From 665c2d0137d45ce4ecaec092ae31dfb7eb6b31c9 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Thu, 16 Oct 2025 15:30:18 -0300 Subject: [PATCH 1/3] chore: simplify `x > 0` to `x != 0` for unsigned types in ACIR --- .../src/ssa/ir/dfg/simplify.rs | 4 +- .../src/ssa/ir/dfg/simplify/binary.rs | 50 ++++++++++++++++++- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/compiler/noirc_evaluator/src/ssa/ir/dfg/simplify.rs b/compiler/noirc_evaluator/src/ssa/ir/dfg/simplify.rs index 50b386c1734..1b45d96f53d 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/dfg/simplify.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/dfg/simplify.rs @@ -76,7 +76,9 @@ pub(crate) fn simplify( use SimplifyResult::*; match instruction { - Instruction::Binary(binary) => simplify_binary(binary, dfg), + Instruction::Binary(binary) => { + simplify_binary(binary, dfg, block, ctrl_typevars, call_stack) + } Instruction::Cast(value, typ) => simplify_cast(*value, *typ, dfg), Instruction::Not(value) => { match &dfg[*value] { diff --git a/compiler/noirc_evaluator/src/ssa/ir/dfg/simplify/binary.rs b/compiler/noirc_evaluator/src/ssa/ir/dfg/simplify/binary.rs index 0519554c877..80df9838302 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/dfg/simplify/binary.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/dfg/simplify/binary.rs @@ -1,18 +1,26 @@ use acvm::{AcirField as _, FieldElement}; use crate::ssa::ir::{ + basic_block::BasicBlockId, dfg::DataFlowGraph, instruction::{ Binary, BinaryOp, Instruction, binary::{BinaryEvaluationResult, eval_constant_binary_op}, }, - types::NumericType, + types::{NumericType, Type}, }; +use noirc_errors::call_stack::CallStackId; use super::SimplifyResult; /// Try to simplify this binary instruction, returning the new value if possible. -pub(super) fn simplify_binary(binary: &Binary, dfg: &mut DataFlowGraph) -> SimplifyResult { +pub(super) fn simplify_binary( + binary: &Binary, + dfg: &mut DataFlowGraph, + block: BasicBlockId, + ctrl_typevars: Option>, + call_stack: CallStackId, +) -> SimplifyResult { let lhs = binary.lhs; let rhs = binary.rhs; @@ -211,6 +219,22 @@ pub(super) fn simplify_binary(binary: &Binary, dfg: &mut DataFlowGraph) -> Simpl lhs, zero, )); + } else if lhs_is_zero && dfg.runtime.is_acir() { + // `0 < rhs` for unsigned values is the same as `rhs != 0`, + // which is slightly more performant in ACIR + let zero = dfg.make_constant(FieldElement::zero(), lhs_type); + let instruction = + Instruction::Binary(Binary { lhs: rhs, rhs: zero, operator: BinaryOp::Eq }); + let eq = dfg.insert_instruction_and_results( + instruction, + block, + ctrl_typevars, + call_stack, + ); + let eq = eq.results(); + let eq = eq.first().unwrap(); + let neq = Instruction::Not(*eq); + return SimplifyResult::SimplifiedToInstruction(neq); } } } @@ -341,4 +365,26 @@ mod tests { } "); } + + #[test] + fn simplifies_zero_less_than_unsigned_value_to_not_equals_in_acir() { + let src = " + acir(inline) fn main f0 { + b0(v0: u8): + v1 = lt u8 0, v0 + return v1 + } + "; + + let ssa = Ssa::from_str_simplifying(src).unwrap(); + + assert_ssa_snapshot!(ssa, @r" + acir(inline) fn main f0 { + b0(v0: u8): + v2 = eq v0, u8 0 + v3 = not v2 + return v3 + } + "); + } } From 1f2c0ef0e3d132b4860fd3535c6cfadf6b8523c3 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Thu, 16 Oct 2025 17:13:51 -0300 Subject: [PATCH 2/3] Binary instructions don't take control type vars --- compiler/noirc_evaluator/src/ssa/ir/dfg/simplify.rs | 4 +--- .../noirc_evaluator/src/ssa/ir/dfg/simplify/binary.rs | 11 +++-------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/compiler/noirc_evaluator/src/ssa/ir/dfg/simplify.rs b/compiler/noirc_evaluator/src/ssa/ir/dfg/simplify.rs index 1b45d96f53d..b7a4c9a9e70 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/dfg/simplify.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/dfg/simplify.rs @@ -76,9 +76,7 @@ pub(crate) fn simplify( use SimplifyResult::*; match instruction { - Instruction::Binary(binary) => { - simplify_binary(binary, dfg, block, ctrl_typevars, call_stack) - } + Instruction::Binary(binary) => simplify_binary(binary, dfg, block, call_stack), Instruction::Cast(value, typ) => simplify_cast(*value, *typ, dfg), Instruction::Not(value) => { match &dfg[*value] { diff --git a/compiler/noirc_evaluator/src/ssa/ir/dfg/simplify/binary.rs b/compiler/noirc_evaluator/src/ssa/ir/dfg/simplify/binary.rs index 80df9838302..614f618931c 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/dfg/simplify/binary.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/dfg/simplify/binary.rs @@ -7,7 +7,7 @@ use crate::ssa::ir::{ Binary, BinaryOp, Instruction, binary::{BinaryEvaluationResult, eval_constant_binary_op}, }, - types::{NumericType, Type}, + types::NumericType, }; use noirc_errors::call_stack::CallStackId; @@ -18,7 +18,6 @@ pub(super) fn simplify_binary( binary: &Binary, dfg: &mut DataFlowGraph, block: BasicBlockId, - ctrl_typevars: Option>, call_stack: CallStackId, ) -> SimplifyResult { let lhs = binary.lhs; @@ -225,12 +224,8 @@ pub(super) fn simplify_binary( let zero = dfg.make_constant(FieldElement::zero(), lhs_type); let instruction = Instruction::Binary(Binary { lhs: rhs, rhs: zero, operator: BinaryOp::Eq }); - let eq = dfg.insert_instruction_and_results( - instruction, - block, - ctrl_typevars, - call_stack, - ); + let eq = + dfg.insert_instruction_and_results(instruction, block, None, call_stack); let eq = eq.results(); let eq = eq.first().unwrap(); let neq = Instruction::Not(*eq); From 9cf3130a893b4a2b4132f8dc29d79a3efd45cead Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Fri, 17 Oct 2025 09:18:30 -0300 Subject: [PATCH 3/3] Refactor --- .../noirc_evaluator/src/ssa/ir/dfg/simplify/binary.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/noirc_evaluator/src/ssa/ir/dfg/simplify/binary.rs b/compiler/noirc_evaluator/src/ssa/ir/dfg/simplify/binary.rs index 614f618931c..c15a0e1f243 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/dfg/simplify/binary.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/dfg/simplify/binary.rs @@ -224,11 +224,10 @@ pub(super) fn simplify_binary( let zero = dfg.make_constant(FieldElement::zero(), lhs_type); let instruction = Instruction::Binary(Binary { lhs: rhs, rhs: zero, operator: BinaryOp::Eq }); - let eq = - dfg.insert_instruction_and_results(instruction, block, None, call_stack); - let eq = eq.results(); - let eq = eq.first().unwrap(); - let neq = Instruction::Not(*eq); + let eq = dfg + .insert_instruction_and_results(instruction, block, None, call_stack) + .first(); + let neq = Instruction::Not(eq); return SimplifyResult::SimplifiedToInstruction(neq); } }