diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction.rs index 3a12d508f95..45b84cc97d9 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction.rs @@ -646,15 +646,11 @@ impl Binary { let operand_type = dfg.type_of_value(self.lhs); if let (Some(lhs), Some(rhs)) = (lhs, rhs) { - // If the rhs of a division is zero, attempting to evaluate the divison will cause a compiler panic. - // Thus, we do not evaluate this divison as we want to avoid triggering a panic, - // and division by zero should be handled by laying down constraints during ACIR generation. - if matches!(self.operator, BinaryOp::Div | BinaryOp::Mod) && rhs == FieldElement::zero() - { - return SimplifyResult::None; - } - return match self.eval_constants(dfg, lhs, rhs, operand_type) { - Some(value) => SimplifyResult::SimplifiedTo(value), + return match eval_constant_binary_op(lhs, rhs, self.operator, operand_type) { + Some((result, result_type)) => { + let value = dfg.make_constant(result, result_type); + SimplifyResult::SimplifiedTo(value) + } None => SimplifyResult::None, }; } @@ -775,47 +771,51 @@ impl Binary { } SimplifyResult::None } +} - /// Evaluate the two constants with the operation specified by self.operator. - /// Pushes the resulting value to the given DataFlowGraph's constants and returns it. - fn eval_constants( - &self, - dfg: &mut DataFlowGraph, - lhs: FieldElement, - rhs: FieldElement, - mut operand_type: Type, - ) -> Option> { - let value = match &operand_type { - Type::Numeric(NumericType::NativeField) => { - self.operator.get_field_function()?(lhs, rhs) - } - Type::Numeric(NumericType::Unsigned { bit_size }) => { - let function = self.operator.get_u128_function(); - - let lhs = truncate(lhs.try_into_u128()?, *bit_size); - let rhs = truncate(rhs.try_into_u128()?, *bit_size); +/// Evaluate a binary operation with constant arguments. +fn eval_constant_binary_op( + lhs: FieldElement, + rhs: FieldElement, + operator: BinaryOp, + mut operand_type: Type, +) -> Option<(FieldElement, Type)> { + let value = match &operand_type { + Type::Numeric(NumericType::NativeField) => { + // If the rhs of a division is zero, attempting to evaluate the division will cause a compiler panic. + // Thus, we do not evaluate the division in this method, as we want to avoid triggering a panic, + // and the operation should be handled by ACIR generation. + if matches!(operator, BinaryOp::Div | BinaryOp::Mod) && rhs == FieldElement::zero() { + return None; + } + operator.get_field_function()?(lhs, rhs) + } + Type::Numeric(NumericType::Unsigned { bit_size }) => { + let function = operator.get_u128_function(); - // The divisor is being truncated into the type of the operand, which can potentially - // lead to the rhs being zero. - // If the rhs of a division is zero, attempting to evaluate the divison will cause a compiler panic. - // Thus, we do not evaluate the division in this method, as we want to avoid triggering a panic, - // and the operation should be handled by ACIR generation. - if matches!(self.operator, BinaryOp::Div) && rhs == 0 { - return None; - } + let lhs = truncate(lhs.try_into_u128()?, *bit_size); + let rhs = truncate(rhs.try_into_u128()?, *bit_size); - let result = function(lhs, rhs); - truncate(result, *bit_size).into() + // The divisor is being truncated into the type of the operand, which can potentially + // lead to the rhs being zero. + // If the rhs of a division is zero, attempting to evaluate the division will cause a compiler panic. + // Thus, we do not evaluate the division in this method, as we want to avoid triggering a panic, + // and the operation should be handled by ACIR generation. + if matches!(operator, BinaryOp::Div | BinaryOp::Mod) && rhs == 0 { + return None; } - _ => return None, - }; - if matches!(self.operator, BinaryOp::Eq | BinaryOp::Lt) { - operand_type = Type::bool(); + let result = function(lhs, rhs); + truncate(result, *bit_size).into() } + _ => return None, + }; - Some(dfg.make_constant(value, operand_type)) + if matches!(operator, BinaryOp::Eq | BinaryOp::Lt) { + operand_type = Type::bool(); } + + Some((value, operand_type)) } fn truncate(int: u128, bit_size: u32) -> u128 {