Skip to content

Commit 32bc07f

Browse files
authored
Merge branch 'mv/fix-signed-cast-simplification' into mv/promote-ConstantDoesNotFitInType-err
2 parents 6646624 + 0b9c3f3 commit 32bc07f

20 files changed

Lines changed: 510 additions & 226 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

compiler/noirc_evaluator/src/errors.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ pub enum RuntimeError {
7474
"Cannot return a function from an if or match expression, or assignment within these expressions"
7575
)]
7676
ReturnedFunctionFromDynamicIf { call_stack: CallStack },
77+
/// This case is not an error. It's used during codegen to prevent inserting instructions after
78+
/// code when a break or continue is generated.
79+
#[error("Break or continue")]
80+
BreakOrContinue { call_stack: CallStack },
7781
}
7882

7983
#[derive(Debug, Clone, Serialize, Deserialize, Hash)]
@@ -186,6 +190,7 @@ impl RuntimeError {
186190
| RuntimeError::UnknownReference { call_stack } => call_stack,
187191
RuntimeError::ReturnedReferenceFromDynamicIf { call_stack } => call_stack,
188192
RuntimeError::ReturnedFunctionFromDynamicIf { call_stack } => call_stack,
193+
RuntimeError::BreakOrContinue { call_stack } => call_stack,
189194
}
190195
}
191196
}

compiler/noirc_evaluator/src/ssa/function_builder/mod.rs

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ pub mod data_bus;
33
use std::{borrow::Cow, collections::BTreeMap, sync::Arc};
44

55
use acvm::{FieldElement, acir::circuit::ErrorSelector};
6-
use fxhash::FxHashSet as HashSet;
76
use noirc_errors::{
87
Location,
98
call_stack::{CallStack, CallStackId},
@@ -42,8 +41,6 @@ use super::{
4241
pub struct FunctionBuilder {
4342
pub current_function: Function,
4443
current_block: BasicBlockId,
45-
current_block_closed: bool,
46-
closed_blocked: HashSet<(FunctionId, BasicBlockId)>,
4744
finished_functions: Vec<Function>,
4845
call_stack: CallStackId,
4946
error_types: BTreeMap<ErrorSelector, HirType>,
@@ -65,8 +62,6 @@ impl FunctionBuilder {
6562
let new_function = Function::new(function_name, function_id);
6663
Self {
6764
current_block: new_function.entry_block(),
68-
current_block_closed: false,
69-
closed_blocked: HashSet::default(),
7065
current_function: new_function,
7166
finished_functions: Vec::new(),
7267
call_stack: CallStackId::root(),
@@ -207,17 +202,6 @@ impl FunctionBuilder {
207202
self.current_function.dfg.make_block()
208203
}
209204

210-
/// Prevents any further instructions from being added to the current block.
211-
/// That is, calls to add instructions can be called, but they will have no effect.
212-
pub fn close_block(&mut self) {
213-
self.closed_blocked.insert((self.current_function.id(), self.current_block));
214-
self.current_block_closed = true;
215-
}
216-
217-
pub fn current_block_is_closed(&self) -> bool {
218-
self.current_block_closed
219-
}
220-
221205
/// Adds a parameter with the given type to the given block.
222206
/// Returns the newly-added parameter.
223207
pub fn add_block_parameter(&mut self, block: BasicBlockId, typ: Type) -> ValueId {
@@ -235,10 +219,6 @@ impl FunctionBuilder {
235219
instruction: Instruction,
236220
ctrl_typevars: Option<Vec<Type>>,
237221
) -> InsertInstructionResult {
238-
if self.current_block_closed {
239-
return InsertInstructionResult::InstructionRemoved;
240-
}
241-
242222
let block = self.current_block();
243223

244224
if self.simplify {
@@ -263,8 +243,6 @@ impl FunctionBuilder {
263243
/// instructions into a new function, call new_function instead.
264244
pub fn switch_to_block(&mut self, block: BasicBlockId) {
265245
self.current_block = block;
266-
self.current_block_closed =
267-
self.closed_blocked.contains(&(self.current_function.id(), block));
268246
}
269247

270248
/// Returns the block currently being inserted into

compiler/noirc_evaluator/src/ssa/interpreter/mod.rs

Lines changed: 83 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,14 @@ struct Interpreter<'ssa> {
3939
/// expected to have no effect if there are no such instructions or if the code
4040
/// being executed is an unconstrained function.
4141
side_effects_enabled: bool,
42+
43+
options: InterpreterOptions,
44+
}
45+
46+
#[derive(Copy, Clone, Default)]
47+
pub struct InterpreterOptions {
48+
/// If true, the interpreter will print each value definition to stdout.
49+
pub print_definitions: bool,
4250
}
4351

4452
struct CallContext {
@@ -66,20 +74,33 @@ type IResults = IResult<Vec<Value>>;
6674
#[allow(unused)]
6775
impl Ssa {
6876
pub fn interpret(&self, args: Vec<Value>) -> IResults {
69-
self.interpret_function(self.main_id, args)
77+
self.interpret_with_options(args, InterpreterOptions::default())
78+
}
79+
80+
pub fn interpret_with_options(
81+
&self,
82+
args: Vec<Value>,
83+
options: InterpreterOptions,
84+
) -> IResults {
85+
self.interpret_function(self.main_id, args, options)
7086
}
7187

72-
pub(crate) fn interpret_function(&self, function: FunctionId, args: Vec<Value>) -> IResults {
73-
let mut interpreter = Interpreter::new(self);
88+
fn interpret_function(
89+
&self,
90+
function: FunctionId,
91+
args: Vec<Value>,
92+
options: InterpreterOptions,
93+
) -> IResults {
94+
let mut interpreter = Interpreter::new(self, options);
7495
interpreter.interpret_globals()?;
7596
interpreter.call_function(function, args)
7697
}
7798
}
7899

79100
impl<'ssa> Interpreter<'ssa> {
80-
fn new(ssa: &'ssa Ssa) -> Self {
101+
fn new(ssa: &'ssa Ssa, options: InterpreterOptions) -> Self {
81102
let call_stack = vec![CallContext::global_context()];
82-
Self { ssa, call_stack, side_effects_enabled: true }
103+
Self { ssa, call_stack, side_effects_enabled: true, options }
83104
}
84105

85106
fn call_context(&self) -> &CallContext {
@@ -94,12 +115,15 @@ impl<'ssa> Interpreter<'ssa> {
94115
&self.call_stack.first().expect("call_stack should always be non-empty").scope
95116
}
96117

97-
fn current_function(&self) -> &'ssa Function {
118+
fn try_current_function(&self) -> Option<&'ssa Function> {
98119
let current_function_id = self.call_context().called_function;
99-
let current_function_id = current_function_id.expect(
120+
current_function_id.map(|current_function_id| &self.ssa.functions[&current_function_id])
121+
}
122+
123+
fn current_function(&self) -> &'ssa Function {
124+
self.try_current_function().expect(
100125
"Tried calling `Interpreter::current_function` while evaluating global instructions",
101-
);
102-
&self.ssa.functions[&current_function_id]
126+
)
103127
}
104128

105129
fn dfg(&self) -> &'ssa DataFlowGraph {
@@ -113,6 +137,9 @@ impl<'ssa> Interpreter<'ssa> {
113137
/// Define or redefine a value.
114138
/// Redefinitions are expected in the case of loops.
115139
fn define(&mut self, id: ValueId, value: Value) {
140+
if self.options.print_definitions {
141+
println!("{id} = {value}");
142+
}
116143
self.call_context_mut().scope.insert(id, value);
117144
}
118145

@@ -376,9 +403,17 @@ impl<'ssa> Interpreter<'ssa> {
376403
try_vecmap(ids, |id| self.lookup(*id))
377404
}
378405

379-
fn side_effects_enabled(&self) -> bool {
380-
match self.current_function().runtime() {
381-
RuntimeType::Acir(_) => self.side_effects_enabled,
406+
fn side_effects_enabled(&self, instruction: &Instruction) -> bool {
407+
let Some(current_function) = self.try_current_function() else {
408+
// If there's no current function it means we are evaluating global instructions
409+
return true;
410+
};
411+
412+
match current_function.runtime() {
413+
RuntimeType::Acir(_) => {
414+
self.side_effects_enabled
415+
|| !instruction.requires_acir_gen_predicate(&current_function.dfg)
416+
}
382417
RuntimeType::Brillig(_) => true,
383418
}
384419
}
@@ -389,9 +424,11 @@ impl<'ssa> Interpreter<'ssa> {
389424
instruction: &Instruction,
390425
results: &[ValueId],
391426
) -> IResult<()> {
427+
let side_effects_enabled = self.side_effects_enabled(instruction);
428+
392429
match instruction {
393430
Instruction::Binary(binary) => {
394-
let result = self.interpret_binary(binary)?;
431+
let result = self.interpret_binary(binary, side_effects_enabled)?;
395432
self.define(results[0], result);
396433
Ok(())
397434
}
@@ -410,7 +447,7 @@ impl<'ssa> Interpreter<'ssa> {
410447
Instruction::Constrain(lhs_id, rhs_id, constrain_error) => {
411448
let lhs = self.lookup(*lhs_id)?;
412449
let rhs = self.lookup(*rhs_id)?;
413-
if self.side_effects_enabled() && lhs != rhs {
450+
if side_effects_enabled && lhs != rhs {
414451
let lhs = lhs.to_string();
415452
let rhs = rhs.to_string();
416453
let lhs_id = *lhs_id;
@@ -433,7 +470,7 @@ impl<'ssa> Interpreter<'ssa> {
433470
Instruction::ConstrainNotEqual(lhs_id, rhs_id, constrain_error) => {
434471
let lhs = self.lookup(*lhs_id)?;
435472
let rhs = self.lookup(*rhs_id)?;
436-
if self.side_effects_enabled() && lhs == rhs {
473+
if side_effects_enabled && lhs == rhs {
437474
let lhs = lhs.to_string();
438475
let rhs = rhs.to_string();
439476
let lhs_id = *lhs_id;
@@ -453,10 +490,16 @@ impl<'ssa> Interpreter<'ssa> {
453490
}
454491
Ok(())
455492
}
456-
Instruction::RangeCheck { value, max_bit_size, assert_message } => {
457-
self.interpret_range_check(*value, *max_bit_size, assert_message.as_ref())
493+
Instruction::RangeCheck { value, max_bit_size, assert_message } => self
494+
.interpret_range_check(
495+
*value,
496+
*max_bit_size,
497+
assert_message.as_ref(),
498+
side_effects_enabled,
499+
),
500+
Instruction::Call { func, arguments } => {
501+
self.interpret_call(*func, arguments, results, side_effects_enabled)
458502
}
459-
Instruction::Call { func, arguments } => self.interpret_call(*func, arguments, results),
460503
Instruction::Allocate => {
461504
self.interpret_allocate(results[0]);
462505
Ok(())
@@ -468,11 +511,18 @@ impl<'ssa> Interpreter<'ssa> {
468511
Ok(())
469512
}
470513
Instruction::ArrayGet { array, index, offset } => {
471-
self.interpret_array_get(*array, *index, *offset, results[0])
472-
}
473-
Instruction::ArraySet { array, index, value, mutable, offset } => {
474-
self.interpret_array_set(*array, *index, *value, *mutable, *offset, results[0])
514+
self.interpret_array_get(*array, *index, *offset, results[0], side_effects_enabled)
475515
}
516+
Instruction::ArraySet { array, index, value, mutable, offset } => self
517+
.interpret_array_set(
518+
*array,
519+
*index,
520+
*value,
521+
*mutable,
522+
*offset,
523+
results[0],
524+
side_effects_enabled,
525+
),
476526
Instruction::IncrementRc { value } => self.interpret_inc_rc(*value),
477527
Instruction::DecrementRc { value } => self.interpret_dec_rc(*value),
478528
Instruction::IfElse { then_condition, then_value, else_condition, else_value } => self
@@ -556,8 +606,9 @@ impl<'ssa> Interpreter<'ssa> {
556606
value_id: ValueId,
557607
max_bit_size: u32,
558608
error_message: Option<&String>,
609+
side_effects_enabled: bool,
559610
) -> IResult<()> {
560-
if !self.side_effects_enabled() {
611+
if !side_effects_enabled {
561612
return Ok(());
562613
}
563614

@@ -628,11 +679,12 @@ impl<'ssa> Interpreter<'ssa> {
628679
function_id: ValueId,
629680
argument_ids: &[ValueId],
630681
results: &[ValueId],
682+
side_effects_enabled: bool,
631683
) -> IResult<()> {
632684
let function = self.lookup(function_id)?;
633685
let mut arguments = try_vecmap(argument_ids, |argument| self.lookup(*argument))?;
634686

635-
let new_results = if self.side_effects_enabled() {
687+
let new_results = if side_effects_enabled {
636688
match function {
637689
Value::Function(id) => {
638690
// If we're crossing a constrained -> unconstrained boundary we have to wipe
@@ -762,8 +814,9 @@ impl<'ssa> Interpreter<'ssa> {
762814
index: ValueId,
763815
offset: ArrayOffset,
764816
result: ValueId,
817+
side_effects_enabled: bool,
765818
) -> IResult<()> {
766-
let element = if self.side_effects_enabled() {
819+
let element = if side_effects_enabled {
767820
let array = self.lookup_array_or_slice(array, "array get")?;
768821
let index = self.lookup_u32(index, "array get index")?;
769822
let index = index - offset.to_u32();
@@ -776,6 +829,7 @@ impl<'ssa> Interpreter<'ssa> {
776829
Ok(())
777830
}
778831

832+
#[allow(clippy::too_many_arguments)]
779833
fn interpret_array_set(
780834
&mut self,
781835
array: ValueId,
@@ -784,10 +838,11 @@ impl<'ssa> Interpreter<'ssa> {
784838
mutable: bool,
785839
offset: ArrayOffset,
786840
result: ValueId,
841+
side_effects_enabled: bool,
787842
) -> IResult<()> {
788843
let array = self.lookup_array_or_slice(array, "array set")?;
789844

790-
let result_array = if self.side_effects_enabled() {
845+
let result_array = if side_effects_enabled {
791846
let index = self.lookup_u32(index, "array set index")?;
792847
let index = index - offset.to_u32();
793848
let value = self.lookup(value)?;
@@ -1047,7 +1102,7 @@ macro_rules! apply_int_comparison_op {
10471102
}
10481103

10491104
impl Interpreter<'_> {
1050-
fn interpret_binary(&mut self, binary: &Binary) -> IResult<Value> {
1105+
fn interpret_binary(&mut self, binary: &Binary, side_effects_enabled: bool) -> IResult<Value> {
10511106
let lhs_id = binary.lhs;
10521107
let rhs_id = binary.rhs;
10531108
let lhs = self.lookup_numeric(lhs_id, "binary op lhs")?;
@@ -1066,7 +1121,7 @@ impl Interpreter<'_> {
10661121
}
10671122

10681123
// Disable this instruction if it is side-effectful and side effects are disabled.
1069-
if !self.side_effects_enabled() && binary.requires_acir_gen_predicate(self.dfg()) {
1124+
if !side_effects_enabled {
10701125
let zero = NumericValue::zero(lhs.get_type());
10711126
return Ok(Value::Numeric(zero));
10721127
}

0 commit comments

Comments
 (0)