From 9d917e46126e3527486bcf24f0d0c4512543ff2b Mon Sep 17 00:00:00 2001 From: Maxim Vezenov <mvezenov@gmail.com> Date: Wed, 26 Feb 2025 00:39:52 +0000 Subject: [PATCH] Do not run opt passes on Brillig functions post Brillig gen --- compiler/noirc_evaluator/src/ssa.rs | 2 +- .../src/ssa/opt/constant_folding.rs | 5 +++++ compiler/noirc_evaluator/src/ssa/opt/die.rs | 21 ++++++++++++++----- .../src/ssa/opt/preprocess_fns.rs | 2 +- 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/compiler/noirc_evaluator/src/ssa.rs b/compiler/noirc_evaluator/src/ssa.rs index fce597d81bd..b3c509dc5cc 100644 --- a/compiler/noirc_evaluator/src/ssa.rs +++ b/compiler/noirc_evaluator/src/ssa.rs @@ -132,7 +132,7 @@ pub(crate) fn optimize_into_acir( // It could happen that we inlined all calls to a given brillig function. // In that case it's unused so we can remove it. This is what we check next. .run_pass(Ssa::remove_unreachable_functions, "Removing Unreachable Functions (4th)") - .run_pass(Ssa::dead_instruction_elimination, "Dead Instruction Elimination (3rd)") + .run_pass(Ssa::dead_instruction_elimination_acir, "Dead Instruction Elimination (3rd)") .finish(); if !options.skip_underconstrained_check { diff --git a/compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs b/compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs index 05bd48b8830..373d99994a1 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs @@ -95,6 +95,11 @@ impl Ssa { let brillig_info = Some(BrilligInfo { brillig, brillig_functions: &brillig_functions }); for function in self.functions.values_mut() { + // We have already performed our final Brillig generation, so constant folding + // Brillig functions is unnecessary work. + if function.dfg.runtime().is_brillig() { + continue; + } function.constant_fold(false, brillig_info); } diff --git a/compiler/noirc_evaluator/src/ssa/opt/die.rs b/compiler/noirc_evaluator/src/ssa/opt/die.rs index d23cfee8a14..c45e1886269 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/die.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/die.rs @@ -26,15 +26,21 @@ impl Ssa { /// This step should come after the flattening of the CFG and mem2reg. #[tracing::instrument(level = "trace", skip(self))] pub(crate) fn dead_instruction_elimination(self) -> Ssa { - self.dead_instruction_elimination_inner(true) + self.dead_instruction_elimination_inner(true, false) } - fn dead_instruction_elimination_inner(mut self, flattened: bool) -> Ssa { + /// Post the Brillig generation we do not need to run this pass on Brillig functions. + #[tracing::instrument(level = "trace", skip(self))] + pub(crate) fn dead_instruction_elimination_acir(self) -> Ssa { + self.dead_instruction_elimination_inner(true, true) + } + + fn dead_instruction_elimination_inner(mut self, flattened: bool, skip_brillig: bool) -> Ssa { let mut used_globals_map: HashMap<_, _> = self .functions .par_iter_mut() .filter_map(|(id, func)| { - let set = func.dead_instruction_elimination(true, flattened); + let set = func.dead_instruction_elimination(true, flattened, skip_brillig); if func.runtime().is_brillig() { Some((*id, set)) } else { @@ -79,7 +85,12 @@ impl Function { &mut self, insert_out_of_bounds_checks: bool, flattened: bool, + skip_brillig: bool, ) -> HashSet<ValueId> { + if skip_brillig && self.dfg.runtime().is_brillig() { + return HashSet::default(); + } + let mut context = Context { flattened, ..Default::default() }; context.mark_function_parameter_arrays_as_used(self); @@ -103,7 +114,7 @@ impl Function { // instructions (we don't want to remove those checks, or instructions that are // dependencies of those checks) if inserted_out_of_bounds_checks { - return self.dead_instruction_elimination(false, flattened); + return self.dead_instruction_elimination(false, flattened, skip_brillig); } context.remove_rc_instructions(&mut self.dfg); @@ -1099,7 +1110,7 @@ mod test { let ssa = Ssa::from_str(src).unwrap(); // Even though these ACIR functions only have 1 block, we have not inlined and flattened anything yet. - let ssa = ssa.dead_instruction_elimination_inner(false); + let ssa = ssa.dead_instruction_elimination_inner(false, false); let expected = " acir(inline) fn main f0 { diff --git a/compiler/noirc_evaluator/src/ssa/opt/preprocess_fns.rs b/compiler/noirc_evaluator/src/ssa/opt/preprocess_fns.rs index 764fb6dd65b..c4f09ac94fe 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/preprocess_fns.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/preprocess_fns.rs @@ -59,7 +59,7 @@ impl Ssa { // Try to reduce the number of blocks. function.simplify_function(); // Remove leftover instructions. - function.dead_instruction_elimination(true, false); + function.dead_instruction_elimination(true, false, false); // Put it back into the SSA, so the next functions can pick it up. self.functions.insert(id, function);