diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction.rs index 23d8b425349..0c8d8affeb1 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction.rs @@ -22,7 +22,7 @@ use super::{ value::{Value, ValueId}, }; -mod binary; +pub(crate) mod binary; mod call; mod cast; mod constrain; diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction/binary.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction/binary.rs index 81f2f3b1e01..ce65343c7ef 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction/binary.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction/binary.rs @@ -294,7 +294,7 @@ impl Binary { } /// Evaluate a binary operation with constant arguments. -fn eval_constant_binary_op( +pub(crate) fn eval_constant_binary_op( lhs: FieldElement, rhs: FieldElement, operator: BinaryOp, diff --git a/compiler/noirc_evaluator/src/ssa/opt/loop_invariant.rs b/compiler/noirc_evaluator/src/ssa/opt/loop_invariant.rs index c188ed1f80f..0a3c18c1b1e 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/loop_invariant.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/loop_invariant.rs @@ -15,7 +15,7 @@ use crate::ssa::{ basic_block::BasicBlockId, function::Function, function_inserter::FunctionInserter, - instruction::{Instruction, InstructionId}, + instruction::{binary::eval_constant_binary_op, BinaryOp, Instruction, InstructionId}, types::Type, value::ValueId, }, @@ -207,6 +207,7 @@ impl<'f> LoopInvariantContext<'f> { let can_be_deduplicated = instruction.can_be_deduplicated(self.inserter.function, false) || matches!(instruction, Instruction::MakeArray { .. }) + || matches!(instruction, Instruction::Binary(_)) || self.can_be_deduplicated_from_upper_bound(&instruction); is_loop_invariant && can_be_deduplicated @@ -231,6 +232,31 @@ impl<'f> LoopInvariantContext<'f> { false } } + Instruction::Binary(binary) => { + if !matches!(binary.operator, BinaryOp::Add | BinaryOp::Mul) { + return false; + } + + let operand_type = + self.inserter.function.dfg.type_of_value(binary.lhs).unwrap_numeric(); + + let lhs_const = + self.inserter.function.dfg.get_numeric_constant_with_type(binary.lhs); + let rhs_const = + self.inserter.function.dfg.get_numeric_constant_with_type(binary.rhs); + let (lhs, rhs) = match ( + lhs_const, + rhs_const, + self.outer_induction_variables.get(&binary.lhs), + self.outer_induction_variables.get(&binary.rhs), + ) { + (Some((lhs, _)), None, None, Some(upper_bound)) => (lhs, *upper_bound), + (None, Some((rhs, _)), Some(upper_bound), None) => (*upper_bound, rhs), + _ => return false, + }; + + eval_constant_binary_op(lhs, rhs, binary.operator, operand_type).is_some() + } _ => false, } }