diff --git a/crates/nargo/tests/test_data/9_conditional/src/main.nr b/crates/nargo/tests/test_data/9_conditional/src/main.nr index ab4270f1e38..4f2f2089a4d 100644 --- a/crates/nargo/tests/test_data/9_conditional/src/main.nr +++ b/crates/nargo/tests/test_data/9_conditional/src/main.nr @@ -49,6 +49,30 @@ fn main(a: u32, mut c: [u32; 4], x: [u8; 5], result: pub [u8; 32]){ } } + //Regression for to_bits() constant evaluation + let arr : [u8; 2] = [ 1, 2 ]; + // binary array representation of u8 1 + let as_bits_hardcode_1 = [1, 0]; + let mut c1 = 0; + for i in 0..2 { + let mut as_bits = std::to_bits(arr[i] as Field, 2); + c1 = c1 + as_bits[0] as Field; + + if i == 0 { + constrain arr[i] == 1;// 1 + for k in 0..2 { + constrain as_bits_hardcode_1[k] == as_bits[k]; + }; + } + if i == 1 { + constrain arr[i] == 2;//2 + for k in 0..2 { + constrain as_bits_hardcode_1[k] != as_bits[k]; + }; + } + }; + constrain c1==1; + //Test case for short-circuit let mut data = [0 as u32; 32]; let mut ba = a; @@ -68,6 +92,7 @@ fn main(a: u32, mut c: [u32; 4], x: [u8; 5], result: pub [u8; 32]){ }; constrain data[31] == 0; constrain ba != 13; + if a == 3 { c = test4(); } diff --git a/crates/noirc_evaluator/src/ssa/code_gen.rs b/crates/noirc_evaluator/src/ssa/code_gen.rs index 2709a4f1244..b61ed8f48f7 100644 --- a/crates/noirc_evaluator/src/ssa/code_gen.rs +++ b/crates/noirc_evaluator/src/ssa/code_gen.rs @@ -764,8 +764,7 @@ impl IRGenerator { //Exit block let exit_block = block::new_unsealed_block(&mut self.context, block::BlockType::IfJoin, true); - - self.context[entry_block].dominated.push(exit_block); + self.context[exit_block].dominator = Some(entry_block); //Else block self.context.current_block = entry_block; diff --git a/crates/noirc_evaluator/src/ssa/integer.rs b/crates/noirc_evaluator/src/ssa/integer.rs index 2244048f9a2..2cd33a0d4c9 100644 --- a/crates/noirc_evaluator/src/ssa/integer.rs +++ b/crates/noirc_evaluator/src/ssa/integer.rs @@ -391,7 +391,7 @@ fn block_overflow( //we may do that in future when the max_map becomes more used elsewhere (for other optim) } - let old_ins = ctx.try_get_mut_instruction(id).unwrap(); + let old_ins = ctx.try_get_mut_instruction(ins.id).unwrap(); *old_ins = ins; } diff --git a/crates/noirc_evaluator/src/ssa/optim.rs b/crates/noirc_evaluator/src/ssa/optim.rs index 1ffc19050e7..9ecbf1627ce 100644 --- a/crates/noirc_evaluator/src/ssa/optim.rs +++ b/crates/noirc_evaluator/src/ssa/optim.rs @@ -3,7 +3,6 @@ use acvm::FieldElement; use crate::errors::RuntimeError; use super::{ - acir_gen::InternalVar, anchor::{Anchor, CseAction}, block::BlockId, context::SsaContext, @@ -48,25 +47,13 @@ pub fn simplify(ctx: &mut SsaContext, ins: &mut Instruction) -> Result<(), Runti return Ok(()); } - match &mut ins.operation { - Operation::Binary(binary) => { - if let NodeEval::Const(r_const, r_type) = NodeEval::from_id(ctx, binary.rhs) { - if binary.operator == BinaryOp::Div { - binary.rhs = ctx.get_or_create_const(r_const.inverse(), r_type); - binary.operator = BinaryOp::Mul; - } + if let Operation::Binary(binary) = &mut ins.operation { + if let NodeEval::Const(r_const, r_type) = NodeEval::from_id(ctx, binary.rhs) { + if binary.operator == BinaryOp::Div { + binary.rhs = ctx.get_or_create_const(r_const.inverse(), r_type); + binary.operator = BinaryOp::Mul; } } - Operation::Intrinsic(opcode, args) => { - let args = args - .iter() - .map(|arg| NodeEval::from_id(ctx, *arg).into_const_value().map(|f| f.to_u128())); - - if let Some(args) = args.collect() { - ins.mark = Mark::ReplaceWith(evaluate_intrinsic(ctx, *opcode, args, &ins.res_type)); - } - } - _ => (), } Ok(()) @@ -77,30 +64,28 @@ fn evaluate_intrinsic( op: acvm::acir::OPCODE, args: Vec, res_type: &ObjectType, -) -> NodeId { + block_id: BlockId, +) -> Vec { match op { acvm::acir::OPCODE::ToBits => { let bit_count = args[1] as u32; + let mut result = Vec::new(); if let ObjectType::Pointer(a) = res_type { - let new_var = super::node::Variable { - id: NodeId::dummy(), - obj_type: super::node::ObjectType::Pointer(*a), - name: op.to_string(), - root: None, - def: None, - witness: None, - parent_block: ctx.current_block, - }; - for i in 0..bit_count { - if args[0] & (1 << i) != 0 { - ctx.mem[*a].values.push(InternalVar::from(FieldElement::one())); + let index = ctx.get_or_create_const( + FieldElement::from(i as i128), + ObjectType::NativeField, + ); + let op = if args[0] & (1 << i) != 0 { + Operation::Store { array_id: *a, index, value: ctx.one() } } else { - ctx.mem[*a].values.push(InternalVar::from(FieldElement::zero())); - } + Operation::Store { array_id: *a, index, value: ctx.zero() } + }; + let i = Instruction::new(op, ObjectType::NotAnObject, Some(block_id)); + result.push(ctx.add_instruction(i)); } - return ctx.add_variable(new_var, None); + return result; } unreachable!(); } @@ -353,6 +338,23 @@ fn cse_block_with_anchor( let mut update2 = update.clone(); simplify(ctx, &mut update2)?; + //cannot simplify to_bits() in the previous call because it get replaced with multiple instructions + if let Operation::Intrinsic(opcode, args) = &update2.operation { + let args = args.iter().map(|arg| { + NodeEval::from_id(ctx, *arg).into_const_value().map(|f| f.to_u128()) + }); + + if let Some(args) = args.collect() { + update2.mark = Mark::Deleted; + new_list.extend(evaluate_intrinsic( + ctx, + *opcode, + args, + &update2.res_type, + block_id, + )); + } + } let update3 = ctx.get_mut_instruction(*ins_id); *update3 = update2; }