diff --git a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs index df351d6c0cd..9487b24935b 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs @@ -117,18 +117,39 @@ impl<'a> ValueMerger<'a> { let then_condition = dfg.insert_instruction_and_results(cast, block, None, call_stack).first(); - let cast = Instruction::Cast(else_condition, else_type); - let else_condition = - dfg.insert_instruction_and_results(cast, block, None, call_stack).first(); - - let mul = Instruction::binary(BinaryOp::Mul, then_condition, then_value); - let then_value = dfg.insert_instruction_and_results(mul, block, None, call_stack).first(); - - let mul = Instruction::binary(BinaryOp::Mul, else_condition, else_value); - let else_value = dfg.insert_instruction_and_results(mul, block, None, call_stack).first(); - - let add = Instruction::binary(BinaryOp::Add, then_value, else_value); - dfg.insert_instruction_and_results(add, block, None, call_stack).first() + if then_type == NumericType::NativeField { + // We're merging two fields so we can do a more efficient value merger as by converting + // the expression `if c { a } else { b }` as `c * (a-b) + b`. + // + // This removes a multiplication compared to the standard `c*a + (!c)*b`. + + let diff = Instruction::binary(BinaryOp::Sub, then_value, else_value); + let diff_value = + dfg.insert_instruction_and_results(diff, block, None, call_stack).first(); + + let conditional_diff = Instruction::binary(BinaryOp::Mul, then_condition, diff_value); + let conditional_diff_value = dfg + .insert_instruction_and_results(conditional_diff, block, None, call_stack) + .first(); + + let merged_field = + Instruction::binary(BinaryOp::Add, else_value, conditional_diff_value); + dfg.insert_instruction_and_results(merged_field, block, None, call_stack) + .first() + } else { + let cast = Instruction::Cast(else_condition, else_type); + let else_condition = + dfg.insert_instruction_and_results(cast, block, None, call_stack).first(); + + let mul = Instruction::binary(BinaryOp::Mul, then_condition, then_value); + let then_value = dfg.insert_instruction_and_results(mul, block, None, call_stack).first(); + + let mul = Instruction::binary(BinaryOp::Mul, else_condition, else_value); + let else_value = dfg.insert_instruction_and_results(mul, block, None, call_stack).first(); + + let add = Instruction::binary(BinaryOp::Add, then_value, else_value); + dfg.insert_instruction_and_results(add, block, None, call_stack).first() + } } /// Given an if expression that returns an array: `if c { array1 } else { array2 }`,