diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction.rs index 7dcb50762f5..e1ef25b4ae3 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction.rs @@ -32,7 +32,7 @@ mod constrain; pub(crate) use binary::{Binary, BinaryOp}; use call::simplify_call; use cast::simplify_cast; -use constrain::decompose_constrain; +use constrain::{decompose_constrain, simplify_constrain}; /// Reference to an instruction /// @@ -600,7 +600,8 @@ impl Instruction { } } Instruction::Constrain(lhs, rhs, msg) => { - let constraints = decompose_constrain(*lhs, *rhs, msg, dfg); + let (lhs, rhs) = simplify_constrain(*lhs, *rhs, dfg); + let constraints = decompose_constrain(lhs, rhs, msg, dfg); if constraints.is_empty() { Remove } else { diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction/constrain.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction/constrain.rs index 66f50440d64..4d239d32d3a 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction/constrain.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction/constrain.rs @@ -2,6 +2,40 @@ use acvm::{acir::AcirField, FieldElement}; use super::{Binary, BinaryOp, ConstrainError, DataFlowGraph, Instruction, Type, Value, ValueId}; +/// Try to simplify this constrain instruction. This function will inspect the inputs to the constraint such that +/// it acts on variables as early in the DFG as possible. +pub(super) fn simplify_constrain( + lhs: ValueId, + rhs: ValueId, + dfg: &mut DataFlowGraph, +) -> (ValueId, ValueId) { + let lhs = dfg.resolve(lhs); + let rhs = dfg.resolve(rhs); + + match (&dfg[lhs], &dfg[rhs]) { + (Value::Instruction { instruction, .. }, Value::NumericConstant { constant, typ }) => { + let Instruction::Binary(Binary { lhs, rhs, operator: BinaryOp::Add }) = dfg[*instruction].clone() + else { + return (lhs, rhs); + }; + + let Value::NumericConstant { constant: inner_constant, .. } = dfg[rhs].clone() + else { + return (lhs, rhs); + }; + + if *constant > inner_constant { + let new_rhs = dfg.make_constant(*constant - inner_constant, typ.clone()); + (lhs, new_rhs) + } else { + (lhs, rhs) + } + } + + _ => (lhs, rhs), + } +} + /// Try to decompose this constrain instruction. This constraint will be broken down such that it instead constrains /// all the values which are used to compute the values which were being constrained. pub(super) fn decompose_constrain(