From b8d333817b1694bc0b07d061c40e303872d9bd3e Mon Sep 17 00:00:00 2001 From: Tom French Date: Sat, 11 Jan 2025 12:11:36 +0000 Subject: [PATCH 1/2] feat: mark division/modulo by constants as not requiring a predicate --- .../noirc_evaluator/src/ssa/ir/instruction.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction.rs index 786c3671d38..67d4132c03c 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction.rs @@ -507,11 +507,10 @@ impl Instruction { match self { Binary(binary) => { if matches!(binary.operator, BinaryOp::Div | BinaryOp::Mod) { - if let Some(rhs) = function.dfg.get_numeric_constant(binary.rhs) { - rhs != FieldElement::zero() - } else { - false - } + function + .dfg + .get_numeric_constant(binary.rhs) + .map_or(false, |rhs| !rhs.is_zero()) } else { true } @@ -571,11 +570,13 @@ impl Instruction { match self { Instruction::Binary(binary) => { match binary.operator { + BinaryOp::Div | BinaryOp::Mod => { + // Division and modulo operations can fail if the RHS is zero but is otherwise safe. + dfg.get_numeric_constant(binary.rhs).map_or(false, |rhs| !rhs.is_zero()) + } BinaryOp::Add { unchecked: false } | BinaryOp::Sub { unchecked: false } - | BinaryOp::Mul { unchecked: false } - | BinaryOp::Div - | BinaryOp::Mod => { + | BinaryOp::Mul { unchecked: false } => { // Some binary math can overflow or underflow, but this is only the case // for unsigned types (here we assume the type of binary.lhs is the same) dfg.type_of_value(binary.rhs).is_unsigned() From f5b1521fb1eff7aa55f0468681baad9e43fe4858 Mon Sep 17 00:00:00 2001 From: Tom French Date: Sat, 11 Jan 2025 12:24:28 +0000 Subject: [PATCH 2/2] feat: discard predicate when inverting constant fields --- compiler/noirc_evaluator/src/acir/acir_variable.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/compiler/noirc_evaluator/src/acir/acir_variable.rs b/compiler/noirc_evaluator/src/acir/acir_variable.rs index cf6b1fcc7f7..773a95a8770 100644 --- a/compiler/noirc_evaluator/src/acir/acir_variable.rs +++ b/compiler/noirc_evaluator/src/acir/acir_variable.rs @@ -327,12 +327,19 @@ impl> AcirContext { let var_data = &self.vars[&var]; if let AcirVarData::Const(constant) = var_data { // Note that this will return a 0 if the inverse is not available - let inverted_var = self.add_data(AcirVarData::Const(constant.inverse())); + let inverted_constant = constant.inverse(); + let inverted_var = self.add_constant(inverted_constant); + + let should_be_one = self.mul_var(inverted_var, var)?; // Check that the inverted var is valid. // This check prevents invalid divisions by zero. - let should_be_one = self.mul_var(inverted_var, var)?; - self.maybe_eq_predicate(should_be_one, predicate)?; + if inverted_constant.is_zero() { + self.maybe_eq_predicate(should_be_one, predicate)?; + } else { + let one = self.add_constant(F::one()); + self.assert_eq_var(should_be_one, one, None)?; + } return Ok(inverted_var); }