From 9dc626d918dc4bb83bb01d60937c0f5b776c1ebd Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Mon, 19 Aug 2024 14:25:39 -0500 Subject: [PATCH 01/22] Add pass to move array gets --- compiler/noirc_evaluator/src/ssa.rs | 1 + compiler/noirc_evaluator/src/ssa/opt/mod.rs | 1 + .../src/ssa/opt/move_array_gets.rs | 155 ++++++++++++++++++ 3 files changed, 157 insertions(+) create mode 100644 compiler/noirc_evaluator/src/ssa/opt/move_array_gets.rs diff --git a/compiler/noirc_evaluator/src/ssa.rs b/compiler/noirc_evaluator/src/ssa.rs index 9daf98e606b..671eddb8778 100644 --- a/compiler/noirc_evaluator/src/ssa.rs +++ b/compiler/noirc_evaluator/src/ssa.rs @@ -114,6 +114,7 @@ pub(crate) fn optimize_into_acir( .run_pass(Ssa::remove_enable_side_effects, "After EnableSideEffects removal:") .run_pass(Ssa::fold_constants_using_constraints, "After Constraint Folding:") .run_pass(Ssa::dead_instruction_elimination, "After Dead Instruction Elimination:") + .run_pass(Ssa::move_array_gets, "After Move Array Gets:") .run_pass(Ssa::array_set_optimization, "After Array Set Optimizations:") .finish(); diff --git a/compiler/noirc_evaluator/src/ssa/opt/mod.rs b/compiler/noirc_evaluator/src/ssa/opt/mod.rs index 4e5fa262696..8ab83510b1c 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/mod.rs @@ -13,6 +13,7 @@ mod die; pub(crate) mod flatten_cfg; mod inlining; mod mem2reg; +mod move_array_gets; mod rc; mod remove_bit_shifts; mod remove_enable_side_effects; diff --git a/compiler/noirc_evaluator/src/ssa/opt/move_array_gets.rs b/compiler/noirc_evaluator/src/ssa/opt/move_array_gets.rs new file mode 100644 index 00000000000..d1bfcb4d85e --- /dev/null +++ b/compiler/noirc_evaluator/src/ssa/opt/move_array_gets.rs @@ -0,0 +1,155 @@ +//! Move Array Gets Pass +//! +//! This is a setup optimization for the mutable array set optimization. +//! Array sets can be made mutable if the array they're setting isn't used +//! again afterward. This pass moves all array gets to their earliest possible +//! location right after their creation. This pass is not expected to yield +//! any runtime difference without the mutable array pass. +//! +//! To move an array get: +//! - We must keep the enable_side_effects variable the same +//! - It cannot move past any instructions it depends on. This includes: +//! - The array itself, the index to set, and the enable_side_effects variable. +//! +//! This optimization has two passes: +//! 1. Traverse the function to find each array_get and remember its dependencies, +//! draining each instruction as we go. +//! 2. Traverse the function re-inserting each instruction. When all dependencies +//! of an array_get have been inserted we can insert the corresponding array_get itself. +//! Since it can be expensive checking this for every instruction, this pass makes +//! the assumption that the last dependency will always have the highest ValueId. +use fxhash::FxHashMap; + +use crate::ssa::ir::basic_block::BasicBlockId; +use crate::ssa::ir::dfg::DataFlowGraph; +use crate::ssa::ir::instruction::InstructionId; +use crate::ssa::ir::types::Type; +use crate::ssa::ir::value::{Value, ValueId}; +use crate::ssa::{ir::instruction::Instruction, ssa_gen::Ssa}; + +impl Ssa { + pub(crate) fn move_array_gets(mut self) -> Self { + for func in self.functions.values_mut() { + if !func.runtime().is_entry_point() { + let mut reachable_blocks = func.reachable_blocks(); + assert_eq!(reachable_blocks.len(), 1, "Expected there to be 1 block remaining in Acir function for array_set optimization"); + + let block = reachable_blocks.pop_first().unwrap(); + let (state, instructions) = find_array_gets(&mut func.dfg, block); + move_array_gets(state, &mut func.dfg, block, instructions); + } + } + self + } +} + +#[derive(Default)] +struct State { + array_gets: FxHashMap>, + + /// These array gets only depend on constant values or function inputs so they'd + /// never be inserted if we're going through each instruction's outputs only. + /// They're separated out here so they can be inserted at the top of the function instead. + independent_array_gets: Vec, +} + +struct ArrayGet { + instruction: InstructionId, + side_effects: ValueId, +} + +fn find_array_gets(dfg: &mut DataFlowGraph, block: BasicBlockId) -> (State, Vec) { + let mut state = State::default(); + let instructions = dfg[block].take_instructions(); + let mut side_effects = dfg.make_constant(1u128.into(), Type::bool()); + + for instruction in &instructions { + match &dfg[*instruction] { + Instruction::ArrayGet { array, index } => { + let dependencies = [*array, *index, side_effects].into_iter(); + let dependencies = dependencies.filter(|value| is_instruction_result(dfg, *value)); + + if let Some(last_dependency) = dependencies.max() { + // Assume largest non-constant ValueId came last in the program + state + .array_gets + .entry(last_dependency) + .or_default() + .push(ArrayGet { instruction: *instruction, side_effects }); + } else { + state.independent_array_gets.push(*instruction); + } + } + Instruction::EnableSideEffects { condition } => { + side_effects = *condition; + } + _ => (), + } + } + + (state, instructions) +} + +fn is_instruction_result(dfg: &DataFlowGraph, value: ValueId) -> bool { + match &dfg[value] { + Value::Instruction { .. } => true, + Value::Param { .. } + | Value::NumericConstant { .. } + | Value::Function(_) + | Value::Intrinsic(_) + | Value::ForeignFunction(_) => false, + Value::Array { array, .. } => array.iter().any(|elem| is_instruction_result(dfg, *elem)), + } +} + +fn move_array_gets( + mut state: State, + dfg: &mut DataFlowGraph, + block: BasicBlockId, + instructions: Vec, +) { + let mut side_effects = dfg.make_constant(1u128.into(), Type::bool()); + + for array_set in state.independent_array_gets { + dfg[block].instructions_mut().push(array_set); + } + + for instruction_id in instructions { + match &dfg[instruction_id] { + // Skip, we'll re-insert these from `state.array_gets` + Instruction::ArrayGet { .. } => (), + Instruction::EnableSideEffects { condition } => { + side_effects = *condition; + dfg[block].instructions_mut().push(instruction_id); + } + _ => { + dfg[block].instructions_mut().push(instruction_id); + } + } + + let results = dfg.instruction_results(instruction_id); + let mut array_gets_to_insert = Vec::new(); + + for result in results { + if let Some(mut array_gets) = state.array_gets.remove(result) { + array_gets_to_insert.append(&mut array_gets); + } + } + + for array_get in array_gets_to_insert { + if array_get.side_effects != side_effects { + insert_side_effects_enabled(dfg, block, array_get.side_effects); + } + dfg[block].instructions_mut().push(array_get.instruction); + if array_get.side_effects != side_effects { + insert_side_effects_enabled(dfg, block, side_effects); + } + } + } +} + +fn insert_side_effects_enabled(dfg: &mut DataFlowGraph, block: BasicBlockId, condition: ValueId) { + let instruction = Instruction::EnableSideEffects { condition }; + let call_stack = dfg.get_value_call_stack(condition); + dfg.insert_instruction_and_results(instruction, block, None, call_stack); +} From 913b629cf89f801047b1610a1358e21987f279bb Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Mon, 19 Aug 2024 14:51:42 -0500 Subject: [PATCH 02/22] Fix tests --- .../src/ssa/opt/move_array_gets.rs | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/compiler/noirc_evaluator/src/ssa/opt/move_array_gets.rs b/compiler/noirc_evaluator/src/ssa/opt/move_array_gets.rs index d1bfcb4d85e..93ef83bd0db 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/move_array_gets.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/move_array_gets.rs @@ -66,10 +66,12 @@ fn find_array_gets(dfg: &mut DataFlowGraph, block: BasicBlockId) -> (State, Vec< for instruction in &instructions { match &dfg[*instruction] { Instruction::ArrayGet { array, index } => { - let dependencies = [*array, *index, side_effects].into_iter(); - let dependencies = dependencies.filter(|value| is_instruction_result(dfg, *value)); + let mut last_dependency = None; + find_last_dependency(dfg, *array, &mut last_dependency); + find_last_dependency(dfg, *index, &mut last_dependency); + find_last_dependency(dfg, side_effects, &mut last_dependency); - if let Some(last_dependency) = dependencies.max() { + if let Some(last_dependency) = last_dependency { // Assume largest non-constant ValueId came last in the program state .array_gets @@ -90,6 +92,30 @@ fn find_array_gets(dfg: &mut DataFlowGraph, block: BasicBlockId) -> (State, Vec< (state, instructions) } +fn find_last_dependency(dfg: &DataFlowGraph, value: ValueId, current_last: &mut Option) { + let value = dfg.resolve(value); + match &dfg[value] { + Value::Instruction { .. } => { + if let Some(last) = *current_last { + *current_last = Some(last.max(value)); + } else { + *current_last = Some(value); + } + } + Value::Param { .. } + | Value::NumericConstant { .. } + | Value::Function(_) + | Value::Intrinsic(_) + | Value::ForeignFunction(_) => (), + // Need to recursively search through arrays since they contain other ValueIds + Value::Array { array, .. } => { + for elem in array { + find_last_dependency(dfg, *elem, current_last); + } + } + } +} + fn is_instruction_result(dfg: &DataFlowGraph, value: ValueId) -> bool { match &dfg[value] { Value::Instruction { .. } => true, From d2a63da52a158d7dac35fd5bfa4595198b6fc2a7 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Mon, 19 Aug 2024 15:02:59 -0500 Subject: [PATCH 03/22] Add test program --- .../array_get_optimization/Nargo.toml | 7 + .../array_get_optimization/Prover.toml | 168 ++++++++++++++++++ .../array_get_optimization/src/main.nr | 11 ++ 3 files changed, 186 insertions(+) create mode 100644 test_programs/execution_success/array_get_optimization/Nargo.toml create mode 100644 test_programs/execution_success/array_get_optimization/Prover.toml create mode 100644 test_programs/execution_success/array_get_optimization/src/main.nr diff --git a/test_programs/execution_success/array_get_optimization/Nargo.toml b/test_programs/execution_success/array_get_optimization/Nargo.toml new file mode 100644 index 00000000000..4c9fb0e036b --- /dev/null +++ b/test_programs/execution_success/array_get_optimization/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "array_get_optimization" +type = "bin" +authors = [""] +compiler_version = ">=0.33.0" + +[dependencies] diff --git a/test_programs/execution_success/array_get_optimization/Prover.toml b/test_programs/execution_success/array_get_optimization/Prover.toml new file mode 100644 index 00000000000..8d1caa8afa6 --- /dev/null +++ b/test_programs/execution_success/array_get_optimization/Prover.toml @@ -0,0 +1,168 @@ +fields = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +] +enables = [ + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, +] +indices = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +] diff --git a/test_programs/execution_success/array_get_optimization/src/main.nr b/test_programs/execution_success/array_get_optimization/src/main.nr new file mode 100644 index 00000000000..244b5d66405 --- /dev/null +++ b/test_programs/execution_success/array_get_optimization/src/main.nr @@ -0,0 +1,11 @@ +global SIZE = 500; + +fn main(mut fields: [Field; SIZE], enables: [bool; SIZE], indices: [u64; SIZE]) -> pub [Field; SIZE] { + for i in 0..SIZE { + if enables[i] { + fields[indices[i]] = i as Field; + } + } + + fields +} From 99d04dbcdf882aa06b5e7cb7231eb5a0b3723775 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Mon, 19 Aug 2024 15:08:24 -0500 Subject: [PATCH 04/22] Add comment --- .../execution_success/array_get_optimization/src/main.nr | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test_programs/execution_success/array_get_optimization/src/main.nr b/test_programs/execution_success/array_get_optimization/src/main.nr index 244b5d66405..943261727a3 100644 --- a/test_programs/execution_success/array_get_optimization/src/main.nr +++ b/test_programs/execution_success/array_get_optimization/src/main.nr @@ -1,3 +1,11 @@ +// ACIR opcodes should now increase linearly per each increase in SIZE: +// | SIZE | ACIR Opcodes | Difference +// | 2 | 45 | +// | 3 | 67 | +22 +// | 4 | 89 | +22 +// | 5 | 111 | +22 +// ... +// | 500 | 11001 | global SIZE = 500; fn main(mut fields: [Field; SIZE], enables: [bool; SIZE], indices: [u64; SIZE]) -> pub [Field; SIZE] { From c94a858bbddb0ceaf91bcb68d6be54718f77e5d5 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Mon, 19 Aug 2024 15:39:20 -0500 Subject: [PATCH 05/22] Try increasing size of value merge optimization --- .../noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs index 90e24a1d5e3..4ac872a4d61 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs @@ -321,7 +321,7 @@ impl<'a> ValueMerger<'a> { // Arbitrarily limit this to looking at most 10 past ArraySet operations. // If there are more than that, we assume 2 completely separate arrays are being merged. - let max_iters = 2; + let max_iters = 10; let mut seen_then = Vec::with_capacity(max_iters); let mut seen_else = Vec::with_capacity(max_iters); From 8e96a559bbabfb5fe736fd87175af16a36aac817 Mon Sep 17 00:00:00 2001 From: jfecher Date: Mon, 19 Aug 2024 15:47:01 -0500 Subject: [PATCH 06/22] Update compiler/noirc_evaluator/src/ssa/opt/move_array_gets.rs Co-authored-by: Maxim Vezenov --- compiler/noirc_evaluator/src/ssa/opt/move_array_gets.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/noirc_evaluator/src/ssa/opt/move_array_gets.rs b/compiler/noirc_evaluator/src/ssa/opt/move_array_gets.rs index 93ef83bd0db..e050d4906c4 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/move_array_gets.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/move_array_gets.rs @@ -18,7 +18,7 @@ //! of an array_get have been inserted we can insert the corresponding array_get itself. //! Since it can be expensive checking this for every instruction, this pass makes //! the assumption that the last dependency will always have the highest ValueId. -use fxhash::FxHashMap; +use fxhash::FxHashMap as HashMap; use crate::ssa::ir::basic_block::BasicBlockId; use crate::ssa::ir::dfg::DataFlowGraph; From 5ead7267f23ac327c6b1647d444e1df612b02578 Mon Sep 17 00:00:00 2001 From: jfecher Date: Mon, 19 Aug 2024 15:47:13 -0500 Subject: [PATCH 07/22] Update compiler/noirc_evaluator/src/ssa/opt/move_array_gets.rs Co-authored-by: Maxim Vezenov --- compiler/noirc_evaluator/src/ssa/opt/move_array_gets.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/noirc_evaluator/src/ssa/opt/move_array_gets.rs b/compiler/noirc_evaluator/src/ssa/opt/move_array_gets.rs index e050d4906c4..3a0cd9caea4 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/move_array_gets.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/move_array_gets.rs @@ -45,7 +45,7 @@ impl Ssa { #[derive(Default)] struct State { - array_gets: FxHashMap>, + array_gets: HashMap>, /// These array gets only depend on constant values or function inputs so they'd /// never be inserted if we're going through each instruction's outputs only. From 91d23120bf72bc3dd0d31860a38cccbbac2082b4 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Mon, 19 Aug 2024 15:50:27 -0500 Subject: [PATCH 08/22] Add comment, tweak constant --- .../noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs | 2 +- compiler/noirc_evaluator/src/ssa/opt/move_array_gets.rs | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs index 4ac872a4d61..fe2fda5e57d 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs @@ -321,7 +321,7 @@ impl<'a> ValueMerger<'a> { // Arbitrarily limit this to looking at most 10 past ArraySet operations. // If there are more than that, we assume 2 completely separate arrays are being merged. - let max_iters = 10; + let max_iters = array_length / 2; let mut seen_then = Vec::with_capacity(max_iters); let mut seen_else = Vec::with_capacity(max_iters); diff --git a/compiler/noirc_evaluator/src/ssa/opt/move_array_gets.rs b/compiler/noirc_evaluator/src/ssa/opt/move_array_gets.rs index 93ef83bd0db..563a7e4fbfd 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/move_array_gets.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/move_array_gets.rs @@ -45,6 +45,9 @@ impl Ssa { #[derive(Default)] struct State { + /// Every array_get in the current function, keyed by its last dependency in terms of + /// which was created latest. We can re-insert the array_get back into the program + /// after this dependency. array_gets: FxHashMap>, /// These array gets only depend on constant values or function inputs so they'd From 63a8ec0dc45d1b252abfaf06589d0792ad74f7cc Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Mon, 19 Aug 2024 15:55:24 -0500 Subject: [PATCH 09/22] Revert constant value --- .../noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs index fe2fda5e57d..e2e98716f5e 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs @@ -321,7 +321,7 @@ impl<'a> ValueMerger<'a> { // Arbitrarily limit this to looking at most 10 past ArraySet operations. // If there are more than that, we assume 2 completely separate arrays are being merged. - let max_iters = array_length / 2; + let max_iters = 10.min(array_length); let mut seen_then = Vec::with_capacity(max_iters); let mut seen_else = Vec::with_capacity(max_iters); From 9268c93b5d447d60ab88e1f6f50180a02fd60b08 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Mon, 19 Aug 2024 16:00:56 -0500 Subject: [PATCH 10/22] Revert constant again --- .../noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs index e2e98716f5e..4ac872a4d61 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs @@ -321,7 +321,7 @@ impl<'a> ValueMerger<'a> { // Arbitrarily limit this to looking at most 10 past ArraySet operations. // If there are more than that, we assume 2 completely separate arrays are being merged. - let max_iters = 10.min(array_length); + let max_iters = 10; let mut seen_then = Vec::with_capacity(max_iters); let mut seen_else = Vec::with_capacity(max_iters); From 244ef0dc0c7e6db2162d87f9f9b873730c8cc032 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Tue, 20 Aug 2024 09:33:37 -0500 Subject: [PATCH 11/22] Try changing value merge optimization --- compiler/noirc_evaluator/src/ssa.rs | 2 +- .../noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/compiler/noirc_evaluator/src/ssa.rs b/compiler/noirc_evaluator/src/ssa.rs index 671eddb8778..7f9f8005ef0 100644 --- a/compiler/noirc_evaluator/src/ssa.rs +++ b/compiler/noirc_evaluator/src/ssa.rs @@ -114,7 +114,7 @@ pub(crate) fn optimize_into_acir( .run_pass(Ssa::remove_enable_side_effects, "After EnableSideEffects removal:") .run_pass(Ssa::fold_constants_using_constraints, "After Constraint Folding:") .run_pass(Ssa::dead_instruction_elimination, "After Dead Instruction Elimination:") - .run_pass(Ssa::move_array_gets, "After Move Array Gets:") + // .run_pass(Ssa::move_array_gets, "After Move Array Gets:") .run_pass(Ssa::array_set_optimization, "After Array Set Optimizations:") .finish(); diff --git a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs index 4ac872a4d61..f9a6b73c74d 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs @@ -370,6 +370,7 @@ impl<'a> ValueMerger<'a> { } let mut array = then_value; + let mut array_sets_to_insert = Vec::new(); for (index, element_type, condition) in changed_indices { let typevars = Some(vec![element_type.clone()]); @@ -395,6 +396,10 @@ impl<'a> ValueMerger<'a> { let value = self.merge_values(then_condition, else_condition, then_element, else_element); + array_sets_to_insert.push((index, value, condition)); + } + + for (index, value, condition) in array_sets_to_insert { array = self.insert_array_set(array, index, value, Some(condition)).first(); } From 41d37878a8ede92e972beddf52695306cec0e7b0 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Tue, 20 Aug 2024 09:50:40 -0500 Subject: [PATCH 12/22] Lower constant; rename test; remove unused code --- compiler/noirc_evaluator/src/ssa.rs | 1 - .../src/ssa/opt/flatten_cfg/value_merger.rs | 8 +- compiler/noirc_evaluator/src/ssa/opt/mod.rs | 1 - .../src/ssa/opt/move_array_gets.rs | 184 ------------------ .../Nargo.toml | 2 +- .../Prover.toml | 0 .../src/main.nr | 3 + 7 files changed, 10 insertions(+), 189 deletions(-) delete mode 100644 compiler/noirc_evaluator/src/ssa/opt/move_array_gets.rs rename test_programs/execution_success/{array_get_optimization => regression_5027}/Nargo.toml (72%) rename test_programs/execution_success/{array_get_optimization => regression_5027}/Prover.toml (100%) rename test_programs/execution_success/{array_get_optimization => regression_5027}/src/main.nr (72%) diff --git a/compiler/noirc_evaluator/src/ssa.rs b/compiler/noirc_evaluator/src/ssa.rs index 7f9f8005ef0..9daf98e606b 100644 --- a/compiler/noirc_evaluator/src/ssa.rs +++ b/compiler/noirc_evaluator/src/ssa.rs @@ -114,7 +114,6 @@ pub(crate) fn optimize_into_acir( .run_pass(Ssa::remove_enable_side_effects, "After EnableSideEffects removal:") .run_pass(Ssa::fold_constants_using_constraints, "After Constraint Folding:") .run_pass(Ssa::dead_instruction_elimination, "After Dead Instruction Elimination:") - // .run_pass(Ssa::move_array_gets, "After Move Array Gets:") .run_pass(Ssa::array_set_optimization, "After Array Set Optimizations:") .finish(); diff --git a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs index f9a6b73c74d..f44b5c9a408 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs @@ -319,9 +319,11 @@ impl<'a> ValueMerger<'a> { let mut current_then = then_value; let mut current_else = else_value; - // Arbitrarily limit this to looking at most 10 past ArraySet operations. + // Arbitrarily limit this to looking at most `max_iters` past ArraySet operations. // If there are more than that, we assume 2 completely separate arrays are being merged. - let max_iters = 10; + // TODO: A value of 5 or higher fails the conditional_1 test. + // See https://github.com/noir-lang/noir/actions/runs/10473667497/job/29006337618?pr=5762 + let max_iters = 4; let mut seen_then = Vec::with_capacity(max_iters); let mut seen_else = Vec::with_capacity(max_iters); @@ -400,6 +402,8 @@ impl<'a> ValueMerger<'a> { } for (index, value, condition) in array_sets_to_insert { + let instruction = Instruction::EnableSideEffects { condition }; + self.insert_instruction(instruction); array = self.insert_array_set(array, index, value, Some(condition)).first(); } diff --git a/compiler/noirc_evaluator/src/ssa/opt/mod.rs b/compiler/noirc_evaluator/src/ssa/opt/mod.rs index 8ab83510b1c..4e5fa262696 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/mod.rs @@ -13,7 +13,6 @@ mod die; pub(crate) mod flatten_cfg; mod inlining; mod mem2reg; -mod move_array_gets; mod rc; mod remove_bit_shifts; mod remove_enable_side_effects; diff --git a/compiler/noirc_evaluator/src/ssa/opt/move_array_gets.rs b/compiler/noirc_evaluator/src/ssa/opt/move_array_gets.rs deleted file mode 100644 index c35e287c530..00000000000 --- a/compiler/noirc_evaluator/src/ssa/opt/move_array_gets.rs +++ /dev/null @@ -1,184 +0,0 @@ -//! Move Array Gets Pass -//! -//! This is a setup optimization for the mutable array set optimization. -//! Array sets can be made mutable if the array they're setting isn't used -//! again afterward. This pass moves all array gets to their earliest possible -//! location right after their creation. This pass is not expected to yield -//! any runtime difference without the mutable array pass. -//! -//! To move an array get: -//! - We must keep the enable_side_effects variable the same -//! - It cannot move past any instructions it depends on. This includes: -//! - The array itself, the index to set, and the enable_side_effects variable. -//! -//! This optimization has two passes: -//! 1. Traverse the function to find each array_get and remember its dependencies, -//! draining each instruction as we go. -//! 2. Traverse the function re-inserting each instruction. When all dependencies -//! of an array_get have been inserted we can insert the corresponding array_get itself. -//! Since it can be expensive checking this for every instruction, this pass makes -//! the assumption that the last dependency will always have the highest ValueId. -use fxhash::FxHashMap as HashMap; - -use crate::ssa::ir::basic_block::BasicBlockId; -use crate::ssa::ir::dfg::DataFlowGraph; -use crate::ssa::ir::instruction::InstructionId; -use crate::ssa::ir::types::Type; -use crate::ssa::ir::value::{Value, ValueId}; -use crate::ssa::{ir::instruction::Instruction, ssa_gen::Ssa}; - -impl Ssa { - pub(crate) fn move_array_gets(mut self) -> Self { - for func in self.functions.values_mut() { - if !func.runtime().is_entry_point() { - let mut reachable_blocks = func.reachable_blocks(); - assert_eq!(reachable_blocks.len(), 1, "Expected there to be 1 block remaining in Acir function for array_set optimization"); - - let block = reachable_blocks.pop_first().unwrap(); - let (state, instructions) = find_array_gets(&mut func.dfg, block); - move_array_gets(state, &mut func.dfg, block, instructions); - } - } - self - } -} - -#[derive(Default)] -struct State { - /// Every array_get in the current function, keyed by its last dependency in terms of - /// which was created latest. We can re-insert the array_get back into the program - /// after this dependency. - array_gets: HashMap>, - - /// These array gets only depend on constant values or function inputs so they'd - /// never be inserted if we're going through each instruction's outputs only. - /// They're separated out here so they can be inserted at the top of the function instead. - independent_array_gets: Vec, -} - -struct ArrayGet { - instruction: InstructionId, - side_effects: ValueId, -} - -fn find_array_gets(dfg: &mut DataFlowGraph, block: BasicBlockId) -> (State, Vec) { - let mut state = State::default(); - let instructions = dfg[block].take_instructions(); - let mut side_effects = dfg.make_constant(1u128.into(), Type::bool()); - - for instruction in &instructions { - match &dfg[*instruction] { - Instruction::ArrayGet { array, index } => { - let mut last_dependency = None; - find_last_dependency(dfg, *array, &mut last_dependency); - find_last_dependency(dfg, *index, &mut last_dependency); - find_last_dependency(dfg, side_effects, &mut last_dependency); - - if let Some(last_dependency) = last_dependency { - // Assume largest non-constant ValueId came last in the program - state - .array_gets - .entry(last_dependency) - .or_default() - .push(ArrayGet { instruction: *instruction, side_effects }); - } else { - state.independent_array_gets.push(*instruction); - } - } - Instruction::EnableSideEffects { condition } => { - side_effects = *condition; - } - _ => (), - } - } - - (state, instructions) -} - -fn find_last_dependency(dfg: &DataFlowGraph, value: ValueId, current_last: &mut Option) { - let value = dfg.resolve(value); - match &dfg[value] { - Value::Instruction { .. } => { - if let Some(last) = *current_last { - *current_last = Some(last.max(value)); - } else { - *current_last = Some(value); - } - } - Value::Param { .. } - | Value::NumericConstant { .. } - | Value::Function(_) - | Value::Intrinsic(_) - | Value::ForeignFunction(_) => (), - // Need to recursively search through arrays since they contain other ValueIds - Value::Array { array, .. } => { - for elem in array { - find_last_dependency(dfg, *elem, current_last); - } - } - } -} - -fn is_instruction_result(dfg: &DataFlowGraph, value: ValueId) -> bool { - match &dfg[value] { - Value::Instruction { .. } => true, - Value::Param { .. } - | Value::NumericConstant { .. } - | Value::Function(_) - | Value::Intrinsic(_) - | Value::ForeignFunction(_) => false, - Value::Array { array, .. } => array.iter().any(|elem| is_instruction_result(dfg, *elem)), - } -} - -fn move_array_gets( - mut state: State, - dfg: &mut DataFlowGraph, - block: BasicBlockId, - instructions: Vec, -) { - let mut side_effects = dfg.make_constant(1u128.into(), Type::bool()); - - for array_set in state.independent_array_gets { - dfg[block].instructions_mut().push(array_set); - } - - for instruction_id in instructions { - match &dfg[instruction_id] { - // Skip, we'll re-insert these from `state.array_gets` - Instruction::ArrayGet { .. } => (), - Instruction::EnableSideEffects { condition } => { - side_effects = *condition; - dfg[block].instructions_mut().push(instruction_id); - } - _ => { - dfg[block].instructions_mut().push(instruction_id); - } - } - - let results = dfg.instruction_results(instruction_id); - let mut array_gets_to_insert = Vec::new(); - - for result in results { - if let Some(mut array_gets) = state.array_gets.remove(result) { - array_gets_to_insert.append(&mut array_gets); - } - } - - for array_get in array_gets_to_insert { - if array_get.side_effects != side_effects { - insert_side_effects_enabled(dfg, block, array_get.side_effects); - } - dfg[block].instructions_mut().push(array_get.instruction); - if array_get.side_effects != side_effects { - insert_side_effects_enabled(dfg, block, side_effects); - } - } - } -} - -fn insert_side_effects_enabled(dfg: &mut DataFlowGraph, block: BasicBlockId, condition: ValueId) { - let instruction = Instruction::EnableSideEffects { condition }; - let call_stack = dfg.get_value_call_stack(condition); - dfg.insert_instruction_and_results(instruction, block, None, call_stack); -} diff --git a/test_programs/execution_success/array_get_optimization/Nargo.toml b/test_programs/execution_success/regression_5027/Nargo.toml similarity index 72% rename from test_programs/execution_success/array_get_optimization/Nargo.toml rename to test_programs/execution_success/regression_5027/Nargo.toml index 4c9fb0e036b..6c38df94169 100644 --- a/test_programs/execution_success/array_get_optimization/Nargo.toml +++ b/test_programs/execution_success/regression_5027/Nargo.toml @@ -1,5 +1,5 @@ [package] -name = "array_get_optimization" +name = "regression_5027" type = "bin" authors = [""] compiler_version = ">=0.33.0" diff --git a/test_programs/execution_success/array_get_optimization/Prover.toml b/test_programs/execution_success/regression_5027/Prover.toml similarity index 100% rename from test_programs/execution_success/array_get_optimization/Prover.toml rename to test_programs/execution_success/regression_5027/Prover.toml diff --git a/test_programs/execution_success/array_get_optimization/src/main.nr b/test_programs/execution_success/regression_5027/src/main.nr similarity index 72% rename from test_programs/execution_success/array_get_optimization/src/main.nr rename to test_programs/execution_success/regression_5027/src/main.nr index 943261727a3..eeae7d61db8 100644 --- a/test_programs/execution_success/array_get_optimization/src/main.nr +++ b/test_programs/execution_success/regression_5027/src/main.nr @@ -11,6 +11,9 @@ global SIZE = 500; fn main(mut fields: [Field; SIZE], enables: [bool; SIZE], indices: [u64; SIZE]) -> pub [Field; SIZE] { for i in 0..SIZE { if enables[i] { + // Expect two optimizations: + // 1: Shortcut array merge to only merge 1 changed index each time + // 2: Each array_set created by the above should be mutable fields[indices[i]] = i as Field; } } From 4005fe919d834ec9cc3e7535455673d355c0e832 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Tue, 20 Aug 2024 09:59:09 -0500 Subject: [PATCH 13/22] Reduce constant to see runtime difference --- .../noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs index f44b5c9a408..374eaea6703 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs @@ -323,7 +323,7 @@ impl<'a> ValueMerger<'a> { // If there are more than that, we assume 2 completely separate arrays are being merged. // TODO: A value of 5 or higher fails the conditional_1 test. // See https://github.com/noir-lang/noir/actions/runs/10473667497/job/29006337618?pr=5762 - let max_iters = 4; + let max_iters = 2; let mut seen_then = Vec::with_capacity(max_iters); let mut seen_else = Vec::with_capacity(max_iters); From 0cede204d21681ac2332fd7a46ebdfe04463b2b3 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Tue, 20 Aug 2024 16:06:29 -0500 Subject: [PATCH 14/22] Actually just don't array_get at all --- .../src/ssa/opt/flatten_cfg/value_merger.rs | 51 +- .../regression_5027/Prover.toml | 165 +---- .../regression_5027/Prover.toml.old | 168 +++++ .../regression_5027/src/main.nr | 2 +- .../execution_success/regression_5027/ssa | 645 ++++++++++++++++++ 5 files changed, 825 insertions(+), 206 deletions(-) create mode 100644 test_programs/execution_success/regression_5027/Prover.toml.old create mode 100644 test_programs/execution_success/regression_5027/ssa diff --git a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs index 374eaea6703..0205139d933 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs @@ -154,13 +154,9 @@ impl<'a> ValueMerger<'a> { let actual_length = len * element_types.len(); - if let Some(result) = self.try_merge_only_changed_indices( - then_condition, - else_condition, - then_value, - else_value, - actual_length, - ) { + if let Some(result) = + self.try_merge_only_changed_indices(then_value, else_value, actual_length) + { return result; } @@ -307,8 +303,6 @@ impl<'a> ValueMerger<'a> { fn try_merge_only_changed_indices( &mut self, - then_condition: ValueId, - else_condition: ValueId, then_value: ValueId, else_value: ValueId, array_length: usize, @@ -323,7 +317,7 @@ impl<'a> ValueMerger<'a> { // If there are more than that, we assume 2 completely separate arrays are being merged. // TODO: A value of 5 or higher fails the conditional_1 test. // See https://github.com/noir-lang/noir/actions/runs/10473667497/job/29006337618?pr=5762 - let max_iters = 2; + let max_iters = 4; let mut seen_then = Vec::with_capacity(max_iters); let mut seen_else = Vec::with_capacity(max_iters); @@ -372,39 +366,11 @@ impl<'a> ValueMerger<'a> { } let mut array = then_value; - let mut array_sets_to_insert = Vec::new(); - - for (index, element_type, condition) in changed_indices { - let typevars = Some(vec![element_type.clone()]); - - let instruction = Instruction::EnableSideEffects { condition }; - self.insert_instruction(instruction); - - let mut get_element = |array, typevars| { - let get = Instruction::ArrayGet { array, index }; - self.dfg - .insert_instruction_and_results( - get, - self.block, - typevars, - self.call_stack.clone(), - ) - .first() - }; - - let then_element = get_element(then_value, typevars.clone()); - let else_element = get_element(else_value, typevars); - - let value = - self.merge_values(then_condition, else_condition, then_element, else_element); - - array_sets_to_insert.push((index, value, condition)); - } - for (index, value, condition) in array_sets_to_insert { + for (index, set_value, condition) in changed_indices { let instruction = Instruction::EnableSideEffects { condition }; self.insert_instruction(instruction); - array = self.insert_array_set(array, index, value, Some(condition)).first(); + array = self.insert_array_set(array, index, set_value, Some(condition)).first(); } let instruction = Instruction::EnableSideEffects { condition: current_condition }; @@ -455,7 +421,7 @@ impl<'a> ValueMerger<'a> { fn find_previous_array_set( &self, result: ValueId, - changed_indices: &mut Vec<(ValueId, ValueId, Type, ValueId)>, + changed_indices: &mut Vec<(ValueId, ValueId, ValueId, ValueId)>, ) -> ValueId { match &self.dfg[result] { Value::Instruction { instruction, .. } => match &self.dfg[*instruction] { @@ -467,8 +433,7 @@ impl<'a> ValueMerger<'a> { self.array_set_conditionals ) }); - let element_type = self.dfg.type_of_value(*value); - changed_indices.push((result, *index, element_type, condition)); + changed_indices.push((result, *index, *value, condition)); *array } _ => result, diff --git a/test_programs/execution_success/regression_5027/Prover.toml b/test_programs/execution_success/regression_5027/Prover.toml index 8d1caa8afa6..31fc8a3ffa5 100644 --- a/test_programs/execution_success/regression_5027/Prover.toml +++ b/test_programs/execution_success/regression_5027/Prover.toml @@ -1,168 +1,9 @@ fields = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, ] enables = [ - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false, true, false, + true, false, ] indices = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0 ] diff --git a/test_programs/execution_success/regression_5027/Prover.toml.old b/test_programs/execution_success/regression_5027/Prover.toml.old new file mode 100644 index 00000000000..8d1caa8afa6 --- /dev/null +++ b/test_programs/execution_success/regression_5027/Prover.toml.old @@ -0,0 +1,168 @@ +fields = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +] +enables = [ + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, + true, false, true, false, true, false, true, false, true, false, +] +indices = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +] diff --git a/test_programs/execution_success/regression_5027/src/main.nr b/test_programs/execution_success/regression_5027/src/main.nr index eeae7d61db8..44d11952aad 100644 --- a/test_programs/execution_success/regression_5027/src/main.nr +++ b/test_programs/execution_success/regression_5027/src/main.nr @@ -6,7 +6,7 @@ // | 5 | 111 | +22 // ... // | 500 | 11001 | -global SIZE = 500; +global SIZE = 2; fn main(mut fields: [Field; SIZE], enables: [bool; SIZE], indices: [u64; SIZE]) -> pub [Field; SIZE] { for i in 0..SIZE { diff --git a/test_programs/execution_success/regression_5027/ssa b/test_programs/execution_success/regression_5027/ssa new file mode 100644 index 00000000000..af79e64ce1c --- /dev/null +++ b/test_programs/execution_success/regression_5027/ssa @@ -0,0 +1,645 @@ +Initial SSA: +acir(inline) fn main f0 { + b0(v0: [Field; 2], v2: [u1; 2], v3: [u64; 2]): + v1 = allocate + store v0 at v1 + inc_rc v0 + inc_rc v2 + inc_rc v3 + jmp b1(u32 0) + b1(v4: u32): + v7 = lt v4, u32 2 + jmpif v7 then: b2, else: b3 + b2(): + v9 = array_get v2, index v4 + jmpif v9 then: b4, else: b5 + b4(): + v10 = load v1 + v11 = array_get v3, index v4 + v12 = cast v4 as Field + v13 = cast v11 as u32 + v14 = array_set v10, index v13, value v12 + v15 = add v13, u32 1 + store v14 at v1 + jmp b5() + b5(): + v16 = add v4, u32 1 + jmp b1(v16) + b3(): + v17 = load v1 + dec_rc v0 + dec_rc v2 + dec_rc v3 + return v17 +} + +After Defunctionalization: +acir(inline) fn main f0 { + b0(v0: [Field; 2], v2: [u1; 2], v3: [u64; 2]): + v1 = allocate + store v0 at v1 + inc_rc v0 + inc_rc v2 + inc_rc v3 + jmp b1(u32 0) + b1(v4: u32): + v7 = lt v4, u32 2 + jmpif v7 then: b2, else: b3 + b2(): + v9 = array_get v2, index v4 + jmpif v9 then: b4, else: b5 + b4(): + v10 = load v1 + v11 = array_get v3, index v4 + v12 = cast v4 as Field + v13 = cast v11 as u32 + v14 = array_set v10, index v13, value v12 + v15 = add v13, u32 1 + store v14 at v1 + jmp b5() + b5(): + v16 = add v4, u32 1 + jmp b1(v16) + b3(): + v17 = load v1 + dec_rc v0 + dec_rc v2 + dec_rc v3 + return v17 +} + +After Removing Paired rc_inc & rc_decs: +acir(inline) fn main f0 { + b0(v0: [Field; 2], v2: [u1; 2], v3: [u64; 2]): + v1 = allocate + store v0 at v1 + inc_rc v0 + jmp b1(u32 0) + b1(v4: u32): + v7 = lt v4, u32 2 + jmpif v7 then: b2, else: b3 + b2(): + v9 = array_get v2, index v4 + jmpif v9 then: b4, else: b5 + b4(): + v10 = load v1 + v11 = array_get v3, index v4 + v12 = cast v4 as Field + v13 = cast v11 as u32 + v14 = array_set v10, index v13, value v12 + v15 = add v13, u32 1 + store v14 at v1 + jmp b5() + b5(): + v16 = add v4, u32 1 + jmp b1(v16) + b3(): + v17 = load v1 + dec_rc v0 + return v17 +} + +After Runtime Separation: +acir(inline) fn main f0 { + b0(v0: [Field; 2], v2: [u1; 2], v3: [u64; 2]): + v1 = allocate + store v0 at v1 + inc_rc v0 + jmp b1(u32 0) + b1(v4: u32): + v7 = lt v4, u32 2 + jmpif v7 then: b2, else: b3 + b2(): + v9 = array_get v2, index v4 + jmpif v9 then: b4, else: b5 + b4(): + v10 = load v1 + v11 = array_get v3, index v4 + v12 = cast v4 as Field + v13 = cast v11 as u32 + v14 = array_set v10, index v13, value v12 + v15 = add v13, u32 1 + store v14 at v1 + jmp b5() + b5(): + v16 = add v4, u32 1 + jmp b1(v16) + b3(): + v17 = load v1 + dec_rc v0 + return v17 +} + +After Resolving IsUnconstrained: +acir(inline) fn main f0 { + b0(v0: [Field; 2], v2: [u1; 2], v3: [u64; 2]): + v1 = allocate + store v0 at v1 + inc_rc v0 + jmp b1(u32 0) + b1(v4: u32): + v7 = lt v4, u32 2 + jmpif v7 then: b2, else: b3 + b2(): + v9 = array_get v2, index v4 + jmpif v9 then: b4, else: b5 + b4(): + v10 = load v1 + v11 = array_get v3, index v4 + v12 = cast v4 as Field + v13 = cast v11 as u32 + v14 = array_set v10, index v13, value v12 + v15 = add v13, u32 1 + store v14 at v1 + jmp b5() + b5(): + v16 = add v4, u32 1 + jmp b1(v16) + b3(): + v17 = load v1 + dec_rc v0 + return v17 +} + +After Inlining: +acir(inline) fn main f0 { + b0(v0: [Field; 2], v1: [u1; 2], v2: [u64; 2]): + v3 = allocate + store v0 at v3 + inc_rc v0 + jmp b1(u32 0) + b1(v4: u32): + v7 = lt v4, u32 2 + jmpif v7 then: b2, else: b3 + b2(): + v9 = array_get v1, index v4 + jmpif v9 then: b4, else: b5 + b4(): + v12 = load v3 + v13 = array_get v2, index v4 + v14 = cast v4 as Field + v15 = cast v13 as u32 + v16 = array_set v12, index v15, value v14 + v17 = add v15, u32 1 + store v16 at v3 + jmp b5() + b5(): + v11 = add v4, u32 1 + jmp b1(v11) + b3(): + v8 = load v3 + dec_rc v0 + return v8 +} + +After Mem2Reg: +acir(inline) fn main f0 { + b0(v0: [Field; 2], v1: [u1; 2], v2: [u64; 2]): + v18 = allocate + store v0 at v18 + inc_rc v0 + jmp b1(u32 0) + b1(v4: u32): + v19 = lt v4, u32 2 + jmpif v19 then: b2, else: b3 + b2(): + v21 = array_get v1, index v4 + jmpif v21 then: b4, else: b5 + b4(): + v22 = load v18 + v23 = array_get v2, index v4 + v24 = cast v4 as Field + v25 = cast v23 as u32 + v26 = array_set v22, index v25, value v24 + v27 = add v25, u32 1 + store v26 at v18 + jmp b5() + b5(): + v28 = add v4, u32 1 + jmp b1(v28) + b3(): + v20 = load v18 + dec_rc v0 + return v20 +} + +After `as_slice` optimization +acir(inline) fn main f0 { + b0(v0: [Field; 2], v1: [u1; 2], v2: [u64; 2]): + v18 = allocate + store v0 at v18 + inc_rc v0 + jmp b1(u32 0) + b1(v4: u32): + v19 = lt v4, u32 2 + jmpif v19 then: b2, else: b3 + b2(): + v21 = array_get v1, index v4 + jmpif v21 then: b4, else: b5 + b4(): + v22 = load v18 + v23 = array_get v2, index v4 + v24 = cast v4 as Field + v25 = cast v23 as u32 + v26 = array_set v22, index v25, value v24 + v27 = add v25, u32 1 + store v26 at v18 + jmp b5() + b5(): + v28 = add v4, u32 1 + jmp b1(v28) + b3(): + v20 = load v18 + dec_rc v0 + return v20 +} + +After `static_assert` and `assert_constant`: +acir(inline) fn main f0 { + b0(v0: [Field; 2], v1: [u1; 2], v2: [u64; 2]): + v18 = allocate + store v0 at v18 + inc_rc v0 + jmp b1(u32 0) + b1(v4: u32): + v19 = lt v4, u32 2 + jmpif v19 then: b2, else: b3 + b2(): + v21 = array_get v1, index v4 + jmpif v21 then: b4, else: b5 + b4(): + v22 = load v18 + v23 = array_get v2, index v4 + v24 = cast v4 as Field + v25 = cast v23 as u32 + v26 = array_set v22, index v25, value v24 + v27 = add v25, u32 1 + store v26 at v18 + jmp b5() + b5(): + v28 = add v4, u32 1 + jmp b1(v28) + b3(): + v20 = load v18 + dec_rc v0 + return v20 +} + +After Unrolling: +acir(inline) fn main f0 { + b0(v0: [Field; 2], v1: [u1; 2], v2: [u64; 2]): + v18 = allocate + store v0 at v18 + inc_rc v0 + v32 = array_get v1, index u32 0 + jmpif v32 then: b8, else: b9 + b8(): + v34 = load v18 + v35 = array_get v2, index u32 0 + v37 = cast v35 as u32 + v38 = array_set v34, index v37, value Field 0 + v39 = add v37, u32 1 + store v38 at v18 + jmp b9() + b9(): + v40 = array_get v1, index u32 1 + jmpif v40 then: b13, else: b14 + b13(): + v42 = load v18 + v43 = array_get v2, index u32 1 + v45 = cast v43 as u32 + v46 = array_set v42, index v45, value Field 1 + v47 = add v45, u32 1 + store v46 at v18 + jmp b14() + b14(): + jmp b3() + b3(): + v20 = load v18 + dec_rc v0 + return v20 +} + +After Simplifying: +acir(inline) fn main f0 { + b0(v0: [Field; 2], v1: [u1; 2], v2: [u64; 2]): + v18 = allocate + store v0 at v18 + inc_rc v0 + v32 = array_get v1, index u32 0 + jmpif v32 then: b8, else: b9 + b8(): + v34 = load v18 + v35 = array_get v2, index u32 0 + v37 = cast v35 as u32 + v38 = array_set v34, index v37, value Field 0 + v39 = add v37, u32 1 + store v38 at v18 + jmp b9() + b9(): + v40 = array_get v1, index u32 1 + jmpif v40 then: b13, else: b14 + b13(): + v42 = load v18 + v43 = array_get v2, index u32 1 + v45 = cast v43 as u32 + v46 = array_set v42, index v45, value Field 1 + v47 = add v45, u32 1 + store v46 at v18 + jmp b14() + b14(): + v20 = load v18 + dec_rc v0 + return v20 +} + +After Flattening: +acir(inline) fn main f0 { + b0(v0: [Field; 2], v1: [u1; 2], v2: [u64; 2]): + v18 = allocate + store v0 at v18 + inc_rc v0 + v32 = array_get v1, index u32 0 + enable_side_effects v32 + v49 = load v18 + v50 = array_get v2, index u32 0 + v51 = cast v50 as u32 + v52 = array_set v49, index v51, value Field 0 + v53 = add v51, u32 1 + v54 = load v18 + store v52 at v18 + v55 = not v32 + store v54 at v18 + enable_side_effects u1 1 + v56 = if v32 then v52 else if v55 then v54 + store v56 at v18 + v57 = array_get v1, index u32 1 + enable_side_effects v57 + v58 = load v18 + v59 = array_get v2, index u32 1 + v60 = cast v59 as u32 + v61 = array_set v58, index v60, value Field 1 + v62 = add v60, u32 1 + v63 = load v18 + store v61 at v18 + v64 = not v57 + store v63 at v18 + enable_side_effects u1 1 + v65 = if v57 then v61 else if v64 then v63 + store v65 at v18 + v66 = load v18 + dec_rc v0 + return v66 +} + +After Removing Bit Shifts: +acir(inline) fn main f0 { + b0(v0: [Field; 2], v1: [u1; 2], v2: [u64; 2]): + v18 = allocate + store v0 at v18 + inc_rc v0 + v32 = array_get v1, index u32 0 + enable_side_effects v32 + v49 = load v18 + v50 = array_get v2, index u32 0 + v51 = cast v50 as u32 + v52 = array_set v49, index v51, value Field 0 + v53 = add v51, u32 1 + v54 = load v18 + store v52 at v18 + v55 = not v32 + store v54 at v18 + enable_side_effects u1 1 + v56 = if v32 then v52 else if v55 then v54 + store v56 at v18 + v57 = array_get v1, index u32 1 + enable_side_effects v57 + v58 = load v18 + v59 = array_get v2, index u32 1 + v60 = cast v59 as u32 + v61 = array_set v58, index v60, value Field 1 + v62 = add v60, u32 1 + v63 = load v18 + store v61 at v18 + v64 = not v57 + store v63 at v18 + enable_side_effects u1 1 + v65 = if v57 then v61 else if v64 then v63 + store v65 at v18 + v66 = load v18 + dec_rc v0 + return v66 +} + +After Mem2Reg: +acir(inline) fn main f0 { + b0(v0: [Field; 2], v1: [u1; 2], v2: [u64; 2]): + v67 = allocate + inc_rc v0 + v68 = array_get v1, index u32 0 + enable_side_effects v68 + v70 = array_get v2, index u32 0 + v71 = cast v70 as u32 + v72 = array_set v0, index v71, value Field 0 + v73 = add v71, u32 1 + v75 = not v68 + enable_side_effects u1 1 + v76 = if v68 then v72 else if v75 then v0 + v77 = array_get v1, index u32 1 + enable_side_effects v77 + v79 = array_get v2, index u32 1 + v80 = cast v79 as u32 + v81 = array_set v76, index v80, value Field 1 + v82 = add v80, u32 1 + v84 = not v77 + enable_side_effects u1 1 + v85 = if v77 then v81 else if v84 then v76 + dec_rc v0 + return v85 +} + +After Inlining: +acir(inline) fn main f0 { + b0(v0: [Field; 2], v1: [u1; 2], v2: [u64; 2]): + v3 = allocate + inc_rc v0 + v5 = array_get v1, index u32 0 + enable_side_effects v5 + v6 = array_get v2, index u32 0 + v7 = cast v6 as u32 + v9 = array_set v0, index v7, value Field 0 + v11 = add v7, u32 1 + v12 = not v5 + enable_side_effects u1 1 + v14 = if v5 then v9 else if v12 then v0 + v15 = array_get v1, index u32 1 + enable_side_effects v15 + v16 = array_get v2, index u32 1 + v17 = cast v16 as u32 + v19 = array_set v14, index v17, value Field 1 + v20 = add v17, u32 1 + v21 = not v15 + enable_side_effects u1 1 + v22 = if v15 then v19 else if v21 then v14 + dec_rc v0 + return v22 +} + +After Remove IfElse: +acir(inline) fn main f0 { + b0(v0: [Field; 2], v1: [u1; 2], v2: [u64; 2]): + v3 = allocate + inc_rc v0 + v5 = array_get v1, index u32 0 + enable_side_effects v5 + v6 = array_get v2, index u32 0 + v7 = cast v6 as u32 + v9 = array_set v0, index v7, value Field 0 + v11 = add v7, u32 1 + v12 = not v5 + enable_side_effects v5 + v23 = array_set v9, index v7, value Field 0 + enable_side_effects u1 1 + v15 = array_get v1, index u32 1 + enable_side_effects v15 + v16 = array_get v2, index u32 1 + v17 = cast v16 as u32 + v19 = array_set v23, index v17, value Field 1 + v20 = add v17, u32 1 + v21 = not v15 + enable_side_effects v15 + v24 = array_set v19, index v17, value Field 1 + enable_side_effects u1 1 + dec_rc v0 + return v24 +} + +After Constant Folding: +acir(inline) fn main f0 { + b0(v0: [Field; 2], v1: [u1; 2], v2: [u64; 2]): + v25 = allocate + inc_rc v0 + v26 = array_get v1, index u32 0 + enable_side_effects v26 + v27 = array_get v2, index u32 0 + v28 = cast v27 as u32 + v29 = array_set v0, index v28, value Field 0 + v30 = add v28, u32 1 + v31 = not v26 + enable_side_effects v26 + v32 = array_set v29, index v28, value Field 0 + enable_side_effects u1 1 + v33 = array_get v1, index u32 1 + enable_side_effects v33 + v34 = array_get v2, index u32 1 + v35 = cast v34 as u32 + v36 = array_set v32, index v35, value Field 1 + v37 = add v35, u32 1 + v38 = not v33 + enable_side_effects v33 + v39 = array_set v36, index v35, value Field 1 + enable_side_effects u1 1 + dec_rc v0 + return v39 +} + +After EnableSideEffects removal: +acir(inline) fn main f0 { + b0(v0: [Field; 2], v1: [u1; 2], v2: [u64; 2]): + v25 = allocate + inc_rc v0 + v26 = array_get v1, index u32 0 + enable_side_effects v26 + v27 = array_get v2, index u32 0 + v28 = cast v27 as u32 + v29 = array_set v0, index v28, value Field 0 + v30 = add v28, u32 1 + v31 = not v26 + v32 = array_set v29, index v28, value Field 0 + enable_side_effects u1 1 + v33 = array_get v1, index u32 1 + enable_side_effects v33 + v34 = array_get v2, index u32 1 + v35 = cast v34 as u32 + v36 = array_set v32, index v35, value Field 1 + v37 = add v35, u32 1 + v38 = not v33 + v39 = array_set v36, index v35, value Field 1 + enable_side_effects u1 1 + dec_rc v0 + return v39 +} + +After Constraint Folding: +acir(inline) fn main f0 { + b0(v0: [Field; 2], v1: [u1; 2], v2: [u64; 2]): + v40 = allocate + inc_rc v0 + v41 = array_get v1, index u32 0 + enable_side_effects v41 + v42 = array_get v2, index u32 0 + v43 = cast v42 as u32 + v44 = array_set v0, index v43, value Field 0 + v45 = add v43, u32 1 + v46 = not v41 + v47 = array_set v44, index v43, value Field 0 + enable_side_effects u1 1 + v48 = array_get v1, index u32 1 + enable_side_effects v48 + v49 = array_get v2, index u32 1 + v50 = cast v49 as u32 + v51 = array_set v47, index v50, value Field 1 + v52 = add v50, u32 1 + v53 = not v48 + v54 = array_set v51, index v50, value Field 1 + enable_side_effects u1 1 + dec_rc v0 + return v54 +} + +After Dead Instruction Elimination: +acir(inline) fn main f0 { + b0(v0: [Field; 2], v1: [u1; 2], v2: [u64; 2]): + inc_rc v0 + v41 = array_get v1, index u32 0 + enable_side_effects v41 + v42 = array_get v2, index u32 0 + v43 = cast v42 as u32 + v44 = array_set v0, index v43, value Field 0 + v47 = array_set v44, index v43, value Field 0 + enable_side_effects u1 1 + v48 = array_get v1, index u32 1 + enable_side_effects v48 + v49 = array_get v2, index u32 1 + v50 = cast v49 as u32 + v51 = array_set v47, index v50, value Field 1 + v54 = array_set v51, index v50, value Field 1 + enable_side_effects u1 1 + dec_rc v0 + return v54 +} + +After Array Set Optimizations: +acir(inline) fn main f0 { + b0(v0: [Field; 2], v1: [u1; 2], v2: [u64; 2]): + inc_rc v0 + v41 = array_get v1, index u32 0 + enable_side_effects v41 + v42 = array_get v2, index u32 0 + v43 = cast v42 as u32 + v44 = array_set mut v0, index v43, value Field 0 + v47 = array_set mut v44, index v43, value Field 0 + enable_side_effects u1 1 + v48 = array_get v1, index u32 1 + enable_side_effects v48 + v49 = array_get v2, index u32 1 + v50 = cast v49 as u32 + v51 = array_set mut v47, index v50, value Field 1 + v54 = array_set mut v51, index v50, value Field 1 + enable_side_effects u1 1 + dec_rc v0 + return v54 +} + +[regression_5027] Circuit witness successfully solved +[regression_5027] Circuit output: Vec([Field(0), Field(0)]) From 459893e328e33531fa538b74136413ee87afce07 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Wed, 21 Aug 2024 10:38:34 -0500 Subject: [PATCH 15/22] Remove ssa file --- .../execution_success/regression_5027/ssa | 645 ------------------ 1 file changed, 645 deletions(-) delete mode 100644 test_programs/execution_success/regression_5027/ssa diff --git a/test_programs/execution_success/regression_5027/ssa b/test_programs/execution_success/regression_5027/ssa deleted file mode 100644 index af79e64ce1c..00000000000 --- a/test_programs/execution_success/regression_5027/ssa +++ /dev/null @@ -1,645 +0,0 @@ -Initial SSA: -acir(inline) fn main f0 { - b0(v0: [Field; 2], v2: [u1; 2], v3: [u64; 2]): - v1 = allocate - store v0 at v1 - inc_rc v0 - inc_rc v2 - inc_rc v3 - jmp b1(u32 0) - b1(v4: u32): - v7 = lt v4, u32 2 - jmpif v7 then: b2, else: b3 - b2(): - v9 = array_get v2, index v4 - jmpif v9 then: b4, else: b5 - b4(): - v10 = load v1 - v11 = array_get v3, index v4 - v12 = cast v4 as Field - v13 = cast v11 as u32 - v14 = array_set v10, index v13, value v12 - v15 = add v13, u32 1 - store v14 at v1 - jmp b5() - b5(): - v16 = add v4, u32 1 - jmp b1(v16) - b3(): - v17 = load v1 - dec_rc v0 - dec_rc v2 - dec_rc v3 - return v17 -} - -After Defunctionalization: -acir(inline) fn main f0 { - b0(v0: [Field; 2], v2: [u1; 2], v3: [u64; 2]): - v1 = allocate - store v0 at v1 - inc_rc v0 - inc_rc v2 - inc_rc v3 - jmp b1(u32 0) - b1(v4: u32): - v7 = lt v4, u32 2 - jmpif v7 then: b2, else: b3 - b2(): - v9 = array_get v2, index v4 - jmpif v9 then: b4, else: b5 - b4(): - v10 = load v1 - v11 = array_get v3, index v4 - v12 = cast v4 as Field - v13 = cast v11 as u32 - v14 = array_set v10, index v13, value v12 - v15 = add v13, u32 1 - store v14 at v1 - jmp b5() - b5(): - v16 = add v4, u32 1 - jmp b1(v16) - b3(): - v17 = load v1 - dec_rc v0 - dec_rc v2 - dec_rc v3 - return v17 -} - -After Removing Paired rc_inc & rc_decs: -acir(inline) fn main f0 { - b0(v0: [Field; 2], v2: [u1; 2], v3: [u64; 2]): - v1 = allocate - store v0 at v1 - inc_rc v0 - jmp b1(u32 0) - b1(v4: u32): - v7 = lt v4, u32 2 - jmpif v7 then: b2, else: b3 - b2(): - v9 = array_get v2, index v4 - jmpif v9 then: b4, else: b5 - b4(): - v10 = load v1 - v11 = array_get v3, index v4 - v12 = cast v4 as Field - v13 = cast v11 as u32 - v14 = array_set v10, index v13, value v12 - v15 = add v13, u32 1 - store v14 at v1 - jmp b5() - b5(): - v16 = add v4, u32 1 - jmp b1(v16) - b3(): - v17 = load v1 - dec_rc v0 - return v17 -} - -After Runtime Separation: -acir(inline) fn main f0 { - b0(v0: [Field; 2], v2: [u1; 2], v3: [u64; 2]): - v1 = allocate - store v0 at v1 - inc_rc v0 - jmp b1(u32 0) - b1(v4: u32): - v7 = lt v4, u32 2 - jmpif v7 then: b2, else: b3 - b2(): - v9 = array_get v2, index v4 - jmpif v9 then: b4, else: b5 - b4(): - v10 = load v1 - v11 = array_get v3, index v4 - v12 = cast v4 as Field - v13 = cast v11 as u32 - v14 = array_set v10, index v13, value v12 - v15 = add v13, u32 1 - store v14 at v1 - jmp b5() - b5(): - v16 = add v4, u32 1 - jmp b1(v16) - b3(): - v17 = load v1 - dec_rc v0 - return v17 -} - -After Resolving IsUnconstrained: -acir(inline) fn main f0 { - b0(v0: [Field; 2], v2: [u1; 2], v3: [u64; 2]): - v1 = allocate - store v0 at v1 - inc_rc v0 - jmp b1(u32 0) - b1(v4: u32): - v7 = lt v4, u32 2 - jmpif v7 then: b2, else: b3 - b2(): - v9 = array_get v2, index v4 - jmpif v9 then: b4, else: b5 - b4(): - v10 = load v1 - v11 = array_get v3, index v4 - v12 = cast v4 as Field - v13 = cast v11 as u32 - v14 = array_set v10, index v13, value v12 - v15 = add v13, u32 1 - store v14 at v1 - jmp b5() - b5(): - v16 = add v4, u32 1 - jmp b1(v16) - b3(): - v17 = load v1 - dec_rc v0 - return v17 -} - -After Inlining: -acir(inline) fn main f0 { - b0(v0: [Field; 2], v1: [u1; 2], v2: [u64; 2]): - v3 = allocate - store v0 at v3 - inc_rc v0 - jmp b1(u32 0) - b1(v4: u32): - v7 = lt v4, u32 2 - jmpif v7 then: b2, else: b3 - b2(): - v9 = array_get v1, index v4 - jmpif v9 then: b4, else: b5 - b4(): - v12 = load v3 - v13 = array_get v2, index v4 - v14 = cast v4 as Field - v15 = cast v13 as u32 - v16 = array_set v12, index v15, value v14 - v17 = add v15, u32 1 - store v16 at v3 - jmp b5() - b5(): - v11 = add v4, u32 1 - jmp b1(v11) - b3(): - v8 = load v3 - dec_rc v0 - return v8 -} - -After Mem2Reg: -acir(inline) fn main f0 { - b0(v0: [Field; 2], v1: [u1; 2], v2: [u64; 2]): - v18 = allocate - store v0 at v18 - inc_rc v0 - jmp b1(u32 0) - b1(v4: u32): - v19 = lt v4, u32 2 - jmpif v19 then: b2, else: b3 - b2(): - v21 = array_get v1, index v4 - jmpif v21 then: b4, else: b5 - b4(): - v22 = load v18 - v23 = array_get v2, index v4 - v24 = cast v4 as Field - v25 = cast v23 as u32 - v26 = array_set v22, index v25, value v24 - v27 = add v25, u32 1 - store v26 at v18 - jmp b5() - b5(): - v28 = add v4, u32 1 - jmp b1(v28) - b3(): - v20 = load v18 - dec_rc v0 - return v20 -} - -After `as_slice` optimization -acir(inline) fn main f0 { - b0(v0: [Field; 2], v1: [u1; 2], v2: [u64; 2]): - v18 = allocate - store v0 at v18 - inc_rc v0 - jmp b1(u32 0) - b1(v4: u32): - v19 = lt v4, u32 2 - jmpif v19 then: b2, else: b3 - b2(): - v21 = array_get v1, index v4 - jmpif v21 then: b4, else: b5 - b4(): - v22 = load v18 - v23 = array_get v2, index v4 - v24 = cast v4 as Field - v25 = cast v23 as u32 - v26 = array_set v22, index v25, value v24 - v27 = add v25, u32 1 - store v26 at v18 - jmp b5() - b5(): - v28 = add v4, u32 1 - jmp b1(v28) - b3(): - v20 = load v18 - dec_rc v0 - return v20 -} - -After `static_assert` and `assert_constant`: -acir(inline) fn main f0 { - b0(v0: [Field; 2], v1: [u1; 2], v2: [u64; 2]): - v18 = allocate - store v0 at v18 - inc_rc v0 - jmp b1(u32 0) - b1(v4: u32): - v19 = lt v4, u32 2 - jmpif v19 then: b2, else: b3 - b2(): - v21 = array_get v1, index v4 - jmpif v21 then: b4, else: b5 - b4(): - v22 = load v18 - v23 = array_get v2, index v4 - v24 = cast v4 as Field - v25 = cast v23 as u32 - v26 = array_set v22, index v25, value v24 - v27 = add v25, u32 1 - store v26 at v18 - jmp b5() - b5(): - v28 = add v4, u32 1 - jmp b1(v28) - b3(): - v20 = load v18 - dec_rc v0 - return v20 -} - -After Unrolling: -acir(inline) fn main f0 { - b0(v0: [Field; 2], v1: [u1; 2], v2: [u64; 2]): - v18 = allocate - store v0 at v18 - inc_rc v0 - v32 = array_get v1, index u32 0 - jmpif v32 then: b8, else: b9 - b8(): - v34 = load v18 - v35 = array_get v2, index u32 0 - v37 = cast v35 as u32 - v38 = array_set v34, index v37, value Field 0 - v39 = add v37, u32 1 - store v38 at v18 - jmp b9() - b9(): - v40 = array_get v1, index u32 1 - jmpif v40 then: b13, else: b14 - b13(): - v42 = load v18 - v43 = array_get v2, index u32 1 - v45 = cast v43 as u32 - v46 = array_set v42, index v45, value Field 1 - v47 = add v45, u32 1 - store v46 at v18 - jmp b14() - b14(): - jmp b3() - b3(): - v20 = load v18 - dec_rc v0 - return v20 -} - -After Simplifying: -acir(inline) fn main f0 { - b0(v0: [Field; 2], v1: [u1; 2], v2: [u64; 2]): - v18 = allocate - store v0 at v18 - inc_rc v0 - v32 = array_get v1, index u32 0 - jmpif v32 then: b8, else: b9 - b8(): - v34 = load v18 - v35 = array_get v2, index u32 0 - v37 = cast v35 as u32 - v38 = array_set v34, index v37, value Field 0 - v39 = add v37, u32 1 - store v38 at v18 - jmp b9() - b9(): - v40 = array_get v1, index u32 1 - jmpif v40 then: b13, else: b14 - b13(): - v42 = load v18 - v43 = array_get v2, index u32 1 - v45 = cast v43 as u32 - v46 = array_set v42, index v45, value Field 1 - v47 = add v45, u32 1 - store v46 at v18 - jmp b14() - b14(): - v20 = load v18 - dec_rc v0 - return v20 -} - -After Flattening: -acir(inline) fn main f0 { - b0(v0: [Field; 2], v1: [u1; 2], v2: [u64; 2]): - v18 = allocate - store v0 at v18 - inc_rc v0 - v32 = array_get v1, index u32 0 - enable_side_effects v32 - v49 = load v18 - v50 = array_get v2, index u32 0 - v51 = cast v50 as u32 - v52 = array_set v49, index v51, value Field 0 - v53 = add v51, u32 1 - v54 = load v18 - store v52 at v18 - v55 = not v32 - store v54 at v18 - enable_side_effects u1 1 - v56 = if v32 then v52 else if v55 then v54 - store v56 at v18 - v57 = array_get v1, index u32 1 - enable_side_effects v57 - v58 = load v18 - v59 = array_get v2, index u32 1 - v60 = cast v59 as u32 - v61 = array_set v58, index v60, value Field 1 - v62 = add v60, u32 1 - v63 = load v18 - store v61 at v18 - v64 = not v57 - store v63 at v18 - enable_side_effects u1 1 - v65 = if v57 then v61 else if v64 then v63 - store v65 at v18 - v66 = load v18 - dec_rc v0 - return v66 -} - -After Removing Bit Shifts: -acir(inline) fn main f0 { - b0(v0: [Field; 2], v1: [u1; 2], v2: [u64; 2]): - v18 = allocate - store v0 at v18 - inc_rc v0 - v32 = array_get v1, index u32 0 - enable_side_effects v32 - v49 = load v18 - v50 = array_get v2, index u32 0 - v51 = cast v50 as u32 - v52 = array_set v49, index v51, value Field 0 - v53 = add v51, u32 1 - v54 = load v18 - store v52 at v18 - v55 = not v32 - store v54 at v18 - enable_side_effects u1 1 - v56 = if v32 then v52 else if v55 then v54 - store v56 at v18 - v57 = array_get v1, index u32 1 - enable_side_effects v57 - v58 = load v18 - v59 = array_get v2, index u32 1 - v60 = cast v59 as u32 - v61 = array_set v58, index v60, value Field 1 - v62 = add v60, u32 1 - v63 = load v18 - store v61 at v18 - v64 = not v57 - store v63 at v18 - enable_side_effects u1 1 - v65 = if v57 then v61 else if v64 then v63 - store v65 at v18 - v66 = load v18 - dec_rc v0 - return v66 -} - -After Mem2Reg: -acir(inline) fn main f0 { - b0(v0: [Field; 2], v1: [u1; 2], v2: [u64; 2]): - v67 = allocate - inc_rc v0 - v68 = array_get v1, index u32 0 - enable_side_effects v68 - v70 = array_get v2, index u32 0 - v71 = cast v70 as u32 - v72 = array_set v0, index v71, value Field 0 - v73 = add v71, u32 1 - v75 = not v68 - enable_side_effects u1 1 - v76 = if v68 then v72 else if v75 then v0 - v77 = array_get v1, index u32 1 - enable_side_effects v77 - v79 = array_get v2, index u32 1 - v80 = cast v79 as u32 - v81 = array_set v76, index v80, value Field 1 - v82 = add v80, u32 1 - v84 = not v77 - enable_side_effects u1 1 - v85 = if v77 then v81 else if v84 then v76 - dec_rc v0 - return v85 -} - -After Inlining: -acir(inline) fn main f0 { - b0(v0: [Field; 2], v1: [u1; 2], v2: [u64; 2]): - v3 = allocate - inc_rc v0 - v5 = array_get v1, index u32 0 - enable_side_effects v5 - v6 = array_get v2, index u32 0 - v7 = cast v6 as u32 - v9 = array_set v0, index v7, value Field 0 - v11 = add v7, u32 1 - v12 = not v5 - enable_side_effects u1 1 - v14 = if v5 then v9 else if v12 then v0 - v15 = array_get v1, index u32 1 - enable_side_effects v15 - v16 = array_get v2, index u32 1 - v17 = cast v16 as u32 - v19 = array_set v14, index v17, value Field 1 - v20 = add v17, u32 1 - v21 = not v15 - enable_side_effects u1 1 - v22 = if v15 then v19 else if v21 then v14 - dec_rc v0 - return v22 -} - -After Remove IfElse: -acir(inline) fn main f0 { - b0(v0: [Field; 2], v1: [u1; 2], v2: [u64; 2]): - v3 = allocate - inc_rc v0 - v5 = array_get v1, index u32 0 - enable_side_effects v5 - v6 = array_get v2, index u32 0 - v7 = cast v6 as u32 - v9 = array_set v0, index v7, value Field 0 - v11 = add v7, u32 1 - v12 = not v5 - enable_side_effects v5 - v23 = array_set v9, index v7, value Field 0 - enable_side_effects u1 1 - v15 = array_get v1, index u32 1 - enable_side_effects v15 - v16 = array_get v2, index u32 1 - v17 = cast v16 as u32 - v19 = array_set v23, index v17, value Field 1 - v20 = add v17, u32 1 - v21 = not v15 - enable_side_effects v15 - v24 = array_set v19, index v17, value Field 1 - enable_side_effects u1 1 - dec_rc v0 - return v24 -} - -After Constant Folding: -acir(inline) fn main f0 { - b0(v0: [Field; 2], v1: [u1; 2], v2: [u64; 2]): - v25 = allocate - inc_rc v0 - v26 = array_get v1, index u32 0 - enable_side_effects v26 - v27 = array_get v2, index u32 0 - v28 = cast v27 as u32 - v29 = array_set v0, index v28, value Field 0 - v30 = add v28, u32 1 - v31 = not v26 - enable_side_effects v26 - v32 = array_set v29, index v28, value Field 0 - enable_side_effects u1 1 - v33 = array_get v1, index u32 1 - enable_side_effects v33 - v34 = array_get v2, index u32 1 - v35 = cast v34 as u32 - v36 = array_set v32, index v35, value Field 1 - v37 = add v35, u32 1 - v38 = not v33 - enable_side_effects v33 - v39 = array_set v36, index v35, value Field 1 - enable_side_effects u1 1 - dec_rc v0 - return v39 -} - -After EnableSideEffects removal: -acir(inline) fn main f0 { - b0(v0: [Field; 2], v1: [u1; 2], v2: [u64; 2]): - v25 = allocate - inc_rc v0 - v26 = array_get v1, index u32 0 - enable_side_effects v26 - v27 = array_get v2, index u32 0 - v28 = cast v27 as u32 - v29 = array_set v0, index v28, value Field 0 - v30 = add v28, u32 1 - v31 = not v26 - v32 = array_set v29, index v28, value Field 0 - enable_side_effects u1 1 - v33 = array_get v1, index u32 1 - enable_side_effects v33 - v34 = array_get v2, index u32 1 - v35 = cast v34 as u32 - v36 = array_set v32, index v35, value Field 1 - v37 = add v35, u32 1 - v38 = not v33 - v39 = array_set v36, index v35, value Field 1 - enable_side_effects u1 1 - dec_rc v0 - return v39 -} - -After Constraint Folding: -acir(inline) fn main f0 { - b0(v0: [Field; 2], v1: [u1; 2], v2: [u64; 2]): - v40 = allocate - inc_rc v0 - v41 = array_get v1, index u32 0 - enable_side_effects v41 - v42 = array_get v2, index u32 0 - v43 = cast v42 as u32 - v44 = array_set v0, index v43, value Field 0 - v45 = add v43, u32 1 - v46 = not v41 - v47 = array_set v44, index v43, value Field 0 - enable_side_effects u1 1 - v48 = array_get v1, index u32 1 - enable_side_effects v48 - v49 = array_get v2, index u32 1 - v50 = cast v49 as u32 - v51 = array_set v47, index v50, value Field 1 - v52 = add v50, u32 1 - v53 = not v48 - v54 = array_set v51, index v50, value Field 1 - enable_side_effects u1 1 - dec_rc v0 - return v54 -} - -After Dead Instruction Elimination: -acir(inline) fn main f0 { - b0(v0: [Field; 2], v1: [u1; 2], v2: [u64; 2]): - inc_rc v0 - v41 = array_get v1, index u32 0 - enable_side_effects v41 - v42 = array_get v2, index u32 0 - v43 = cast v42 as u32 - v44 = array_set v0, index v43, value Field 0 - v47 = array_set v44, index v43, value Field 0 - enable_side_effects u1 1 - v48 = array_get v1, index u32 1 - enable_side_effects v48 - v49 = array_get v2, index u32 1 - v50 = cast v49 as u32 - v51 = array_set v47, index v50, value Field 1 - v54 = array_set v51, index v50, value Field 1 - enable_side_effects u1 1 - dec_rc v0 - return v54 -} - -After Array Set Optimizations: -acir(inline) fn main f0 { - b0(v0: [Field; 2], v1: [u1; 2], v2: [u64; 2]): - inc_rc v0 - v41 = array_get v1, index u32 0 - enable_side_effects v41 - v42 = array_get v2, index u32 0 - v43 = cast v42 as u32 - v44 = array_set mut v0, index v43, value Field 0 - v47 = array_set mut v44, index v43, value Field 0 - enable_side_effects u1 1 - v48 = array_get v1, index u32 1 - enable_side_effects v48 - v49 = array_get v2, index u32 1 - v50 = cast v49 as u32 - v51 = array_set mut v47, index v50, value Field 1 - v54 = array_set mut v51, index v50, value Field 1 - enable_side_effects u1 1 - dec_rc v0 - return v54 -} - -[regression_5027] Circuit witness successfully solved -[regression_5027] Circuit output: Vec([Field(0), Field(0)]) From 107562ee76d7b8e592ac45051db69fa4f1f17227 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Wed, 21 Aug 2024 11:14:02 -0500 Subject: [PATCH 16/22] Fix end condition --- .../src/ssa/opt/flatten_cfg/value_merger.rs | 25 ++++++------------- 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs index 0205139d933..5bd68237cd0 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs @@ -307,7 +307,7 @@ impl<'a> ValueMerger<'a> { else_value: ValueId, array_length: usize, ) -> Option { - let mut found = false; + let mut found_ancestor = None; let current_condition = self.current_condition?; let mut current_then = then_value; @@ -324,30 +324,23 @@ impl<'a> ValueMerger<'a> { // We essentially have a tree of ArraySets and want to find a common // ancestor if it exists, alone with the path to it from each starting node. // This path will be the indices that were changed to create each result array. - for _ in 0..max_iters { - if current_then == else_value { - seen_else.clear(); - found = true; - break; - } - - if current_else == then_value { - seen_then.clear(); - found = true; + for i in 0..max_iters { + if current_then == current_else { + found_ancestor = Some(current_then); break; } if let Some(index) = seen_then.iter().position(|(elem, _, _, _)| *elem == current_else) { seen_else.truncate(index); - found = true; + found_ancestor = Some(current_else); break; } if let Some(index) = seen_else.iter().position(|(elem, _, _, _)| *elem == current_then) { seen_then.truncate(index); - found = true; + found_ancestor = Some(current_then); break; } @@ -361,11 +354,7 @@ impl<'a> ValueMerger<'a> { .chain(seen_else.into_iter().map(|(_, index, typ, condition)| (index, typ, condition))) .collect(); - if !found || changed_indices.len() >= array_length { - return None; - } - - let mut array = then_value; + let mut array = found_ancestor?; for (index, set_value, condition) in changed_indices { let instruction = Instruction::EnableSideEffects { condition }; From 0553153898ed16398b2d600ed642e188f883ecdc Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Wed, 21 Aug 2024 13:31:22 -0500 Subject: [PATCH 17/22] Use a less radical approach instead --- .../src/ssa/opt/flatten_cfg/value_merger.rs | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs index 5bd68237cd0..206d5581a7e 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs @@ -154,9 +154,7 @@ impl<'a> ValueMerger<'a> { let actual_length = len * element_types.len(); - if let Some(result) = - self.try_merge_only_changed_indices(then_value, else_value, actual_length) - { + if let Some(result) = self.try_merge_only_changed_indices(then_value, else_value) { return result; } @@ -305,7 +303,6 @@ impl<'a> ValueMerger<'a> { &mut self, then_value: ValueId, else_value: ValueId, - array_length: usize, ) -> Option { let mut found_ancestor = None; let current_condition = self.current_condition?; @@ -324,7 +321,7 @@ impl<'a> ValueMerger<'a> { // We essentially have a tree of ArraySets and want to find a common // ancestor if it exists, alone with the path to it from each starting node. // This path will be the indices that were changed to create each result array. - for i in 0..max_iters { + for _ in 0..max_iters { if current_then == current_else { found_ancestor = Some(current_then); break; @@ -359,7 +356,27 @@ impl<'a> ValueMerger<'a> { for (index, set_value, condition) in changed_indices { let instruction = Instruction::EnableSideEffects { condition }; self.insert_instruction(instruction); - array = self.insert_array_set(array, index, set_value, Some(condition)).first(); + let element_type = self.dfg.type_of_value(set_value); + + let mut get_element = |array, typevars| { + let get = Instruction::ArrayGet { array, index }; + self.dfg + .insert_instruction_and_results( + get, + self.block, + typevars, + self.call_stack.clone(), + ) + .first() + }; + + let typevars = Some(vec![element_type]); + let old_value = get_element(array, typevars); + + let not_condition = self.insert_instruction(Instruction::Not(condition)).first(); + + let value = self.merge_values(condition, not_condition, set_value, old_value); + array = self.insert_array_set(array, index, value, Some(condition)).first(); } let instruction = Instruction::EnableSideEffects { condition: current_condition }; From aa8cd9088fdaff0b03468d77caaafad5106fa0a2 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Wed, 21 Aug 2024 14:29:13 -0500 Subject: [PATCH 18/22] Fix warning --- .../noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs index 206d5581a7e..f13253c1334 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs @@ -152,8 +152,6 @@ impl<'a> ValueMerger<'a> { _ => panic!("Expected array type"), }; - let actual_length = len * element_types.len(); - if let Some(result) = self.try_merge_only_changed_indices(then_value, else_value) { return result; } From 427e3875cc72db4d31ec9751fdb2234f9bf1c2a7 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Fri, 23 Aug 2024 11:49:22 -0500 Subject: [PATCH 19/22] Try crazy optimization --- .../src/ssa/opt/flatten_cfg/value_merger.rs | 92 +++---------------- 1 file changed, 14 insertions(+), 78 deletions(-) diff --git a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs index f13253c1334..81f23ba9449 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs @@ -1,5 +1,7 @@ +use std::rc::Rc; + use acvm::{acir::AcirField, FieldElement}; -use fxhash::{FxHashMap as HashMap, FxHashSet}; +use fxhash::FxHashMap as HashMap; use crate::ssa::ir::{ basic_block::BasicBlockId, @@ -152,7 +154,7 @@ impl<'a> ValueMerger<'a> { _ => panic!("Expected array type"), }; - if let Some(result) = self.try_merge_only_changed_indices(then_value, else_value) { + if let Some(result) = self.try_merge_only_changed_indices(then_value, else_value, then_condition, typ.clone()) { return result; } @@ -301,85 +303,19 @@ impl<'a> ValueMerger<'a> { &mut self, then_value: ValueId, else_value: ValueId, + then_condition: ValueId, + array_type: Type, ) -> Option { - let mut found_ancestor = None; - let current_condition = self.current_condition?; - - let mut current_then = then_value; - let mut current_else = else_value; - - // Arbitrarily limit this to looking at most `max_iters` past ArraySet operations. - // If there are more than that, we assume 2 completely separate arrays are being merged. - // TODO: A value of 5 or higher fails the conditional_1 test. - // See https://github.com/noir-lang/noir/actions/runs/10473667497/job/29006337618?pr=5762 - let max_iters = 4; - let mut seen_then = Vec::with_capacity(max_iters); - let mut seen_else = Vec::with_capacity(max_iters); - - // We essentially have a tree of ArraySets and want to find a common - // ancestor if it exists, alone with the path to it from each starting node. - // This path will be the indices that were changed to create each result array. - for _ in 0..max_iters { - if current_then == current_else { - found_ancestor = Some(current_then); - break; - } - - if let Some(index) = seen_then.iter().position(|(elem, _, _, _)| *elem == current_else) - { - seen_else.truncate(index); - found_ancestor = Some(current_else); - break; - } - - if let Some(index) = seen_else.iter().position(|(elem, _, _, _)| *elem == current_then) - { - seen_then.truncate(index); - found_ancestor = Some(current_then); - break; - } + let outer_type = Type::Array(Rc::new(vec![array_type.clone()]), 2); + let new_array = self.dfg.make_array(vec![else_value, then_value].into(), outer_type); - current_then = self.find_previous_array_set(current_then, &mut seen_then); - current_else = self.find_previous_array_set(current_else, &mut seen_else); - } - - let changed_indices: FxHashSet<_> = seen_then - .into_iter() - .map(|(_, index, typ, condition)| (index, typ, condition)) - .chain(seen_else.into_iter().map(|(_, index, typ, condition)| (index, typ, condition))) - .collect(); - - let mut array = found_ancestor?; - - for (index, set_value, condition) in changed_indices { - let instruction = Instruction::EnableSideEffects { condition }; - self.insert_instruction(instruction); - let element_type = self.dfg.type_of_value(set_value); - - let mut get_element = |array, typevars| { - let get = Instruction::ArrayGet { array, index }; - self.dfg - .insert_instruction_and_results( - get, - self.block, - typevars, - self.call_stack.clone(), - ) - .first() - }; - - let typevars = Some(vec![element_type]); - let old_value = get_element(array, typevars); - - let not_condition = self.insert_instruction(Instruction::Not(condition)).first(); - - let value = self.merge_values(condition, not_condition, set_value, old_value); - array = self.insert_array_set(array, index, value, Some(condition)).first(); - } + let cast = Instruction::Cast(then_condition, Type::length_type()); + let index = self.insert_instruction(cast).first(); - let instruction = Instruction::EnableSideEffects { condition: current_condition }; - self.insert_instruction(instruction); - Some(array) + let get = Instruction::ArrayGet { array: new_array, index }; + let typevars = Some(vec![array_type]); + Some(self.dfg.insert_instruction_and_results(get, self.block, typevars, self.call_stack.clone()) + .first()) } fn insert_instruction(&mut self, instruction: Instruction) -> InsertInstructionResult { From f771698042c49113d51374272f230070d6ad9473 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Fri, 23 Aug 2024 11:52:24 -0500 Subject: [PATCH 20/22] Fmt --- .../src/ssa/opt/flatten_cfg/value_merger.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs index 81f23ba9449..f4e7d5810ac 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs @@ -154,7 +154,9 @@ impl<'a> ValueMerger<'a> { _ => panic!("Expected array type"), }; - if let Some(result) = self.try_merge_only_changed_indices(then_value, else_value, then_condition, typ.clone()) { + if let Some(result) = + self.try_merge_only_changed_indices(then_value, else_value, then_condition, typ.clone()) + { return result; } @@ -314,8 +316,11 @@ impl<'a> ValueMerger<'a> { let get = Instruction::ArrayGet { array: new_array, index }; let typevars = Some(vec![array_type]); - Some(self.dfg.insert_instruction_and_results(get, self.block, typevars, self.call_stack.clone()) - .first()) + Some( + self.dfg + .insert_instruction_and_results(get, self.block, typevars, self.call_stack.clone()) + .first(), + ) } fn insert_instruction(&mut self, instruction: Instruction) -> InsertInstructionResult { From b5dfcc76a47d4f682917fb441710571c17e7696e Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Fri, 23 Aug 2024 12:29:25 -0500 Subject: [PATCH 21/22] Use odd optimization only on fallback full array merge --- .../src/ssa/opt/flatten_cfg/value_merger.rs | 103 +++++++++--------- 1 file changed, 51 insertions(+), 52 deletions(-) diff --git a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs index f13253c1334..61f85f9c5e1 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs @@ -1,3 +1,5 @@ +use std::rc::Rc; + use acvm::{acir::AcirField, FieldElement}; use fxhash::{FxHashMap as HashMap, FxHashSet}; @@ -145,49 +147,32 @@ impl<'a> ValueMerger<'a> { then_value: ValueId, else_value: ValueId, ) -> ValueId { - let mut merged = im::Vector::new(); - - let (element_types, len) = match &typ { + let (_element_types, len) = match &typ { Type::Array(elements, len) => (elements, *len), _ => panic!("Expected array type"), }; - if let Some(result) = self.try_merge_only_changed_indices(then_value, else_value) { + if let Some(result) = self.try_merge_only_changed_indices( + then_condition, + else_condition, + then_value, + else_value, + len, + ) { return result; } - for i in 0..len { - for (element_index, element_type) in element_types.iter().enumerate() { - let index = ((i * element_types.len() + element_index) as u128).into(); - let index = self.dfg.make_constant(index, Type::field()); - - let typevars = Some(vec![element_type.clone()]); - - let mut get_element = |array, typevars| { - let get = Instruction::ArrayGet { array, index }; - self.dfg - .insert_instruction_and_results( - get, - self.block, - typevars, - self.call_stack.clone(), - ) - .first() - }; + let outer_type = Type::Array(Rc::new(vec![typ.clone()]), 2); + let new_array = self.dfg.make_array(vec![else_value, then_value].into(), outer_type); - let then_element = get_element(then_value, typevars.clone()); - let else_element = get_element(else_value, typevars); + let index = + self.insert_instruction(Instruction::Cast(then_condition, Type::length_type())).first(); - merged.push_back(self.merge_values( - then_condition, - else_condition, - then_element, - else_element, - )); - } - } - - self.dfg.make_array(merged, typ) + let get = Instruction::ArrayGet { array: new_array, index }; + let typevars = Some(vec![typ]); + self.dfg + .insert_instruction_and_results(get, self.block, typevars, self.call_stack.clone()) + .first() } fn merge_slice_values( @@ -299,20 +284,21 @@ impl<'a> ValueMerger<'a> { fn try_merge_only_changed_indices( &mut self, + then_condition: ValueId, + else_condition: ValueId, then_value: ValueId, else_value: ValueId, + array_length: usize, ) -> Option { - let mut found_ancestor = None; + let mut found = false; let current_condition = self.current_condition?; let mut current_then = then_value; let mut current_else = else_value; - // Arbitrarily limit this to looking at most `max_iters` past ArraySet operations. + // Arbitrarily limit this to looking at most 10 past ArraySet operations. // If there are more than that, we assume 2 completely separate arrays are being merged. - // TODO: A value of 5 or higher fails the conditional_1 test. - // See https://github.com/noir-lang/noir/actions/runs/10473667497/job/29006337618?pr=5762 - let max_iters = 4; + let max_iters = 2; let mut seen_then = Vec::with_capacity(max_iters); let mut seen_else = Vec::with_capacity(max_iters); @@ -320,22 +306,29 @@ impl<'a> ValueMerger<'a> { // ancestor if it exists, alone with the path to it from each starting node. // This path will be the indices that were changed to create each result array. for _ in 0..max_iters { - if current_then == current_else { - found_ancestor = Some(current_then); + if current_then == else_value { + seen_else.clear(); + found = true; + break; + } + + if current_else == then_value { + seen_then.clear(); + found = true; break; } if let Some(index) = seen_then.iter().position(|(elem, _, _, _)| *elem == current_else) { seen_else.truncate(index); - found_ancestor = Some(current_else); + found = true; break; } if let Some(index) = seen_else.iter().position(|(elem, _, _, _)| *elem == current_then) { seen_then.truncate(index); - found_ancestor = Some(current_then); + found = true; break; } @@ -349,12 +342,17 @@ impl<'a> ValueMerger<'a> { .chain(seen_else.into_iter().map(|(_, index, typ, condition)| (index, typ, condition))) .collect(); - let mut array = found_ancestor?; + if !found || changed_indices.len() >= array_length { + return None; + } + + let mut array = then_value; + + for (index, element_type, condition) in changed_indices { + let typevars = Some(vec![element_type.clone()]); - for (index, set_value, condition) in changed_indices { let instruction = Instruction::EnableSideEffects { condition }; self.insert_instruction(instruction); - let element_type = self.dfg.type_of_value(set_value); let mut get_element = |array, typevars| { let get = Instruction::ArrayGet { array, index }; @@ -368,12 +366,12 @@ impl<'a> ValueMerger<'a> { .first() }; - let typevars = Some(vec![element_type]); - let old_value = get_element(array, typevars); + let then_element = get_element(then_value, typevars.clone()); + let else_element = get_element(else_value, typevars); - let not_condition = self.insert_instruction(Instruction::Not(condition)).first(); + let value = + self.merge_values(then_condition, else_condition, then_element, else_element); - let value = self.merge_values(condition, not_condition, set_value, old_value); array = self.insert_array_set(array, index, value, Some(condition)).first(); } @@ -425,7 +423,7 @@ impl<'a> ValueMerger<'a> { fn find_previous_array_set( &self, result: ValueId, - changed_indices: &mut Vec<(ValueId, ValueId, ValueId, ValueId)>, + changed_indices: &mut Vec<(ValueId, ValueId, Type, ValueId)>, ) -> ValueId { match &self.dfg[result] { Value::Instruction { instruction, .. } => match &self.dfg[*instruction] { @@ -437,7 +435,8 @@ impl<'a> ValueMerger<'a> { self.array_set_conditionals ) }); - changed_indices.push((result, *index, *value, condition)); + let element_type = self.dfg.type_of_value(*value); + changed_indices.push((result, *index, element_type, condition)); *array } _ => result, From 8c517e961a8baa8273e956ddfd271d28d143c77a Mon Sep 17 00:00:00 2001 From: Tom French Date: Tue, 1 Oct 2024 16:38:00 +0100 Subject: [PATCH 22/22] . --- .../noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs index 2020ea56813..0f64274983b 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs @@ -1,4 +1,4 @@ -use std::rc::Rc; +use std::sync::Arc; use acvm::{acir::AcirField, FieldElement}; use fxhash::{FxHashMap as HashMap, FxHashSet as HashSet}; @@ -169,7 +169,7 @@ impl<'a> ValueMerger<'a> { return result; } - let outer_type = Type::Array(Rc::new(vec![typ.clone()]), 2); + let outer_type = Type::Array(Arc::new(vec![typ.clone()]), 2); let new_array = self.dfg.make_array(vec![else_value, then_value].into(), outer_type); let index =