From b6fc629942849133eaf5d8c6eb2e130ed780c5ff Mon Sep 17 00:00:00 2001 From: Maxim Vezenov Date: Sat, 21 Dec 2024 00:29:19 +0000 Subject: [PATCH 1/3] hoist binary operations using known induction variables to check for overflow --- .../noirc_evaluator/src/ssa/ir/instruction.rs | 2 +- .../src/ssa/ir/instruction/binary.rs | 2 +- .../src/ssa/opt/loop_invariant.rs | 24 ++++++++++++++++++- 3 files changed, 25 insertions(+), 3 deletions(-) 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..f0f9bacd3ff 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, 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,27 @@ impl<'f> LoopInvariantContext<'f> { false } } + Instruction::Binary(binary) => { + 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, } } From ed1c1d21ea36b67b5b0b7d3b79f4f646cc760f85 Mon Sep 17 00:00:00 2001 From: Maxim Vezenov Date: Sat, 21 Dec 2024 00:38:43 +0000 Subject: [PATCH 2/3] restrict to add and mul --- compiler/noirc_evaluator/src/ssa/opt/loop_invariant.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/noirc_evaluator/src/ssa/opt/loop_invariant.rs b/compiler/noirc_evaluator/src/ssa/opt/loop_invariant.rs index f0f9bacd3ff..4fdd52da871 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::{binary::eval_constant_binary_op, Instruction, InstructionId}, + instruction::{binary::eval_constant_binary_op, BinaryOp, Instruction, InstructionId}, types::Type, value::ValueId, }, @@ -233,6 +233,10 @@ impl<'f> LoopInvariantContext<'f> { } } 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(); From 686506591906e752aa65929d9c5535dab21b7acc Mon Sep 17 00:00:00 2001 From: Maxim Vezenov Date: Sat, 21 Dec 2024 00:40:30 +0000 Subject: [PATCH 3/3] fmt --- compiler/noirc_evaluator/src/ssa/opt/loop_invariant.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/noirc_evaluator/src/ssa/opt/loop_invariant.rs b/compiler/noirc_evaluator/src/ssa/opt/loop_invariant.rs index 4fdd52da871..0a3c18c1b1e 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/loop_invariant.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/loop_invariant.rs @@ -234,9 +234,9 @@ impl<'f> LoopInvariantContext<'f> { } Instruction::Binary(binary) => { if !matches!(binary.operator, BinaryOp::Add | BinaryOp::Mul) { - return false; + return false; } - + let operand_type = self.inserter.function.dfg.type_of_value(binary.lhs).unwrap_numeric();