diff --git a/compiler/noirc_evaluator/src/ssa/opt/loop_invariant.rs b/compiler/noirc_evaluator/src/ssa/opt/loop_invariant.rs index e8e53ad4832..66c5bfeabe8 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/loop_invariant.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/loop_invariant.rs @@ -40,7 +40,7 @@ //! ``` //! Reversing this for post-dominance we can see that the conditions for control dependence //! are the same as those for post-dominance frontiers. -//! Thus, we rewrite our control dependence condition as Y is control dependent on X iff Y is in PDF(Y). +//! Thus, we rewrite our control dependence condition as Y is control dependent on X iff X is in PDF(Y). //! //! We then can store the PDFs for every block as part of the context of this pass, and use it for checking control dependence. //! Using PDFs gets us from a worst case n^2 complexity to a worst case n. @@ -101,7 +101,7 @@ impl Loops { }; context.current_pre_header = Some(pre_header); - context.hoist_loop_invariants(&loop_); + context.hoist_loop_invariants(&loop_, &self.yet_to_unroll); } context.map_dependent_instructions(); @@ -166,6 +166,13 @@ struct LoopInvariantContext<'f> { // Stores whether the current block being processed is control dependent current_block_control_dependent: bool, + /// Caches all blocks that belong to nested loops determined to be control dependent + /// on blocks in an outer loop. This allows short circuiting future control dependence + /// checks during loop invariant analysis, as these blocks are guaranteed to be + /// control dependent due to the entire nested loop being control dependent. + /// + /// Reset for each new loop as the set should not be shared across different outer loops. + nested_loop_control_dependent_blocks: HashSet, // Maps a block to its post-dominance frontiers // This map should be precomputed a single time and used for checking control dependence. @@ -198,6 +205,7 @@ impl<'f> LoopInvariantContext<'f> { current_pre_header: None, cfg, current_block_control_dependent: false, + nested_loop_control_dependent_blocks: HashSet::default(), post_dom_frontiers, true_value, false_value, @@ -209,11 +217,11 @@ impl<'f> LoopInvariantContext<'f> { self.current_pre_header.expect("ICE: Pre-header block should have been set") } - fn hoist_loop_invariants(&mut self, loop_: &Loop) { + fn hoist_loop_invariants(&mut self, loop_: &Loop, all_loops: &[Loop]) { self.set_values_defined_in_loop(loop_); for block in loop_.blocks.iter() { - self.is_control_dependent_post_pre_header(loop_, *block); + self.is_control_dependent_post_pre_header(loop_, *block, all_loops); for instruction_id in self.inserter.function.dfg[*block].take_instructions() { if self.simplify_from_loop_bounds(instruction_id, loop_, block) { @@ -257,30 +265,91 @@ impl<'f> LoopInvariantContext<'f> { /// Checks whether a `block` is control dependent on any blocks after /// the given loop's header. - fn is_control_dependent_post_pre_header(&mut self, loop_: &Loop, block: BasicBlockId) { + fn is_control_dependent_post_pre_header( + &mut self, + loop_: &Loop, + block: BasicBlockId, + all_loops: &[Loop], + ) { + // The block is already known to be in a control dependent nested loop + // Thus, we can avoid checking for control dependence again. + if self.nested_loop_control_dependent_blocks.contains(&block) { + self.current_block_control_dependent = true; + return; + } + + // Find all blocks between the current block and the loop header, exclusive of the current block and loop header themselves. let all_predecessors = Loop::find_blocks_in_loop(loop_.header, block, &self.cfg).blocks; + let all_predecessors = all_predecessors + .into_iter() + .filter(|&predecessor| predecessor != block && predecessor != loop_.header) + .collect::>(); // Reset the current block control dependent flag, the check will set it to true if needed. // If we fail to reset it, a block may be inadvertently labelled // as control dependent thus preventing optimizations. self.current_block_control_dependent = false; - // Need to accurately determine whether the current block is dependent on any blocks between + // Now check whether the current block is dependent on any blocks between // the current block and the loop header, exclusive of the current block and loop header themselves - if all_predecessors - .into_iter() - .filter(|&predecessor| predecessor != block && predecessor != loop_.header) - .any(|predecessor| self.is_control_dependent(predecessor, block)) + if all_predecessors.iter().any(|predecessor| self.is_control_dependent(*predecessor, block)) { self.current_block_control_dependent = true; + return; + } + + self.is_nested_loop_control_dependent(loop_, block, all_loops, all_predecessors); + } + + /// Determines if the `block` is in a nested loop that is control dependent + /// on a block in the outer loop. + /// If this is the case, we block hoisting as control is not guaranteed. + /// If the block is not control dependent on the inner loop itself, it will be marked appropriately + /// when the inner loop is processed later. + /// + /// Control dependence on a nested loop is determined by checking whether the nested loop's header + /// is control dependent on any blocks between itself and the outer loop's header. + /// It is expected that `all_predecessors` contains at least all of these blocks. + fn is_nested_loop_control_dependent( + &mut self, + loop_: &Loop, + block: BasicBlockId, + all_loops: &[Loop], + all_predecessors: Vec, + ) { + // Now check for nested loops within the current loop + for nested in all_loops.iter() { + if !nested.blocks.contains(&block) { + // Skip unrelated loops + continue; + } + + // We have found a nested loop if an inner loop shares blocks with the current loop + // and they do not share a loop header. + // `all_loops` should not contain the current loop but this extra check provides a sanity + // check in case that ever changes. + let nested_loop_is_control_dep = nested.header != loop_.header + && all_predecessors + .iter() + // Check whether the nested loop's header is control dependent on any of its predecessors + .any(|predecessor| self.is_control_dependent(*predecessor, nested.header)); + if nested_loop_is_control_dep { + self.current_block_control_dependent = true; + // Mark all blocks in the nested loop as control dependent to avoid redundant checks + // for each of these blocks when they are later visited during hoisting. + // This is valid because control dependence of the loop header implies dependence + // for the entire loop body. + self.nested_loop_control_dependent_blocks.extend(nested.blocks.iter()); + return; + } } } - /// Checks whether a `block` is control dependent on a `parent_block` + /// Checks whether a `block` is control dependent on a `parent_block`. /// Uses post-dominance frontiers to determine control dependence. /// Reference the doc comments at the top of the this module for more information /// regarding post-dominance frontiers and control dependence. - fn is_control_dependent(&mut self, parent_block: BasicBlockId, block: BasicBlockId) -> bool { + fn is_control_dependent(&self, parent_block: BasicBlockId, block: BasicBlockId) -> bool { match self.post_dom_frontiers.get(&block) { Some(dependent_blocks) => dependent_blocks.contains(&parent_block), None => false, @@ -300,6 +369,11 @@ impl<'f> LoopInvariantContext<'f> { self.current_induction_variables.clear(); self.set_induction_var_bounds(loop_, true); self.no_break = loop_.is_fully_executed(&self.cfg); + // Clear any cached control dependent nested loop blocks from the previous loop. + // This set is only relevant within the scope of a single loop. + // Keeping previous data would incorrectly classify blocks as control dependent, + // leading to missed hoisting opportunities. + self.nested_loop_control_dependent_blocks.clear(); for block in loop_.blocks.iter() { let params = self.inserter.function.dfg.block_parameters(*block); @@ -2265,4 +2339,86 @@ mod control_dependence { // We expect the SSA to be unchanged assert_normalized_ssa_equals(ssa, src); } + + #[test] + fn do_not_hoist_from_outer_loop_when_inner_loop_is_control_dependent() { + // We want to check the case when an entire inner loop is under a predicate + // that we do not still hoist with respect to control dependence on the outer + // loop's block header. + // This is the SSA for the following program: + // ```noir + // fn main(a: pub bool) { + // for _ in 0..1 { + // if a { + // for _ in 0..1 { + // let _ = (1 / (a as Field)); + // } + // }; + // } + // } + // ``` + let src = r" + acir(inline) predicate_pure fn main f0 { + b0(v0: u1): + jmp b1(u32 0) + b1(v1: u32): + v4 = eq v1, u32 0 + jmpif v4 then: b2, else: b3 + b2(): + jmpif v0 then: b4, else: b5 + b3(): + return + b4(): + jmp b6(u32 0) + b5(): + v7 = unchecked_add v1, u32 1 + jmp b1(v7) + b6(v2: u32): + v5 = eq v2, u32 0 + jmpif v5 then: b7, else: b8 + b7(): + v8 = cast v0 as Field + v10 = div Field 1, v8 + v11 = unchecked_add v2, u32 1 + jmp b6(v11) + b8(): + jmp b5() + } + "; + + let ssa = Ssa::from_str(src).unwrap(); + let ssa = ssa.loop_invariant_code_motion(); + + // We expect `v10 = div Field 1, v8` to be hoisted, but only to the inner loop's header. + // If we were to hoist that div to the outer loop's header, we will fail inadvertently + // if `v0 == false`. + assert_ssa_snapshot!(ssa, @r" + acir(inline) predicate_pure fn main f0 { + b0(v0: u1): + v3 = cast v0 as Field + jmp b1(u32 0) + b1(v1: u32): + v5 = eq v1, u32 0 + jmpif v5 then: b2, else: b3 + b2(): + jmpif v0 then: b4, else: b5 + b3(): + return + b4(): + v7 = div Field 1, v3 + jmp b6(u32 0) + b5(): + v10 = unchecked_add v1, u32 1 + jmp b1(v10) + b6(v2: u32): + v8 = eq v2, u32 0 + jmpif v8 then: b7, else: b8 + b7(): + v11 = unchecked_add v2, u32 1 + jmp b6(v11) + b8(): + jmp b5() + } + "); + } } diff --git a/test_programs/execution_success/loop_invariant_nested_deep/Nargo.toml b/test_programs/execution_success/loop_invariant_nested_deep/Nargo.toml new file mode 100644 index 00000000000..e9d98a8eaba --- /dev/null +++ b/test_programs/execution_success/loop_invariant_nested_deep/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "loop_invariant_nested_deep" +type = "bin" +authors = [""] + +[dependencies] \ No newline at end of file diff --git a/test_programs/execution_success/loop_invariant_nested_deep/Prover.toml b/test_programs/execution_success/loop_invariant_nested_deep/Prover.toml new file mode 100644 index 00000000000..f25ab1e5abe --- /dev/null +++ b/test_programs/execution_success/loop_invariant_nested_deep/Prover.toml @@ -0,0 +1 @@ +a = false diff --git a/test_programs/execution_success/loop_invariant_nested_deep/src/main.nr b/test_programs/execution_success/loop_invariant_nested_deep/src/main.nr new file mode 100644 index 00000000000..1049bde0b5c --- /dev/null +++ b/test_programs/execution_success/loop_invariant_nested_deep/src/main.nr @@ -0,0 +1,50 @@ +// We expect this program to fail if we incorrectly hoist the division. +// This is an expansion of the `loop_invariant_regression_8586` test. +// a = false +fn main(a: pub bool) { + for _ in 0..1 { + for _ in 0..1 { + for _ in 0..1 { + for _ in 0..1 { + if a { + for _ in 0..1 { + let _ = (1 / (a as Field)); + } + }; + } + } + } + } + + for _ in 0..1 { + if a { + for _ in 0..1 { + let _ = (1 / (a as Field)); + + for _ in 0..1 { + for _ in 0..1 { + for _ in 0..1 { + let _ = (1 / (a as Field)); + } + } + } + } + } + } + + for _ in 0..1 { + for _ in 0..1 { + for _ in 0..1 { + if a { + for _ in 0..1 { + let _ = (1 / (a as Field)); + + for _ in 0..1 { + let _ = (1 / (a as Field)); + } + } + } + } + } + } +} diff --git a/test_programs/execution_success/loop_invariant_regression_8586/Nargo.toml b/test_programs/execution_success/loop_invariant_regression_8586/Nargo.toml new file mode 100644 index 00000000000..60b2d49d088 --- /dev/null +++ b/test_programs/execution_success/loop_invariant_regression_8586/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "loop_invariant_regression_8586" +type = "bin" +authors = [""] + +[dependencies] \ No newline at end of file diff --git a/test_programs/execution_success/loop_invariant_regression_8586/Prover.toml b/test_programs/execution_success/loop_invariant_regression_8586/Prover.toml new file mode 100644 index 00000000000..f25ab1e5abe --- /dev/null +++ b/test_programs/execution_success/loop_invariant_regression_8586/Prover.toml @@ -0,0 +1 @@ +a = false diff --git a/test_programs/execution_success/loop_invariant_regression_8586/src/main.nr b/test_programs/execution_success/loop_invariant_regression_8586/src/main.nr new file mode 100644 index 00000000000..1652a7b4b53 --- /dev/null +++ b/test_programs/execution_success/loop_invariant_regression_8586/src/main.nr @@ -0,0 +1,10 @@ +// Regression for issue #8586 (https://github.com/noir-lang/noir/issues/8586) +fn main(a: pub bool) { + for _ in 0..1 { + if a { + for _ in 0..1 { + let _ = (1 / (a as Field)); + } + }; + } +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_nested_deep/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_nested_deep/execute__tests__expanded.snap new file mode 100644 index 00000000000..a0975da5a00 --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_nested_deep/execute__tests__expanded.snap @@ -0,0 +1,47 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: expanded_code +--- +fn main(a: pub bool) { + for _ in 0..1 { + for _ in 0..1 { + for _ in 0..1 { + for _ in 0..1 { + if a { + for _ in 0..1 { + let _: Field = 1 / (a as Field); + } + }; + } + } + } + } + for _ in 0..1 { + if a { + for _ in 0..1 { + let _: Field = 1 / (a as Field); + for _ in 0..1 { + for _ in 0..1 { + for _ in 0..1 { + let _: Field = 1 / (a as Field); + } + } + } + } + } + } + for _ in 0..1 { + for _ in 0..1 { + for _ in 0..1 { + if a { + for _ in 0..1 { + let _: Field = 1 / (a as Field); + for _ in 0..1 { + let _: Field = 1 / (a as Field); + } + } + } + } + } + } +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_nested_deep/execute__tests__force_brillig_false_inliner_-9223372036854775808.snap b/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_nested_deep/execute__tests__force_brillig_false_inliner_-9223372036854775808.snap new file mode 100644 index 00000000000..257d0265404 --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_nested_deep/execute__tests__force_brillig_false_inliner_-9223372036854775808.snap @@ -0,0 +1,48 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: artifact +--- +{ + "noir_version": "[noir_version]", + "hash": "[hash]", + "abi": { + "parameters": [ + { + "name": "a", + "type": { + "kind": "boolean" + }, + "visibility": "public" + } + ], + "return_type": null, + "error_types": {} + }, + "bytecode": [ + "func 0", + "current witness index : _2", + "private parameters indices : []", + "public parameters indices : [_0]", + "return value indices : []", + "BLACKBOX::RANGE [(_0, 1)] []", + "BRILLIG CALL func 0: PREDICATE = EXPR [ (1, _0) 0 ]", + "inputs: [Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(0))], q_c: 0 })], outputs: [Simple(Witness(1))]", + "EXPR [ (1, _0, _1) (-1, _2) 0 ]", + "EXPR [ (1, _0, _2) (-1, _0) 0 ]", + "unconstrained func 0", + "[Const { destination: Direct(21), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(20), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(0), size_address: Direct(21), offset_address: Direct(20) }, Const { destination: Direct(2), bit_size: Field, value: 0 }, BinaryFieldOp { destination: Direct(3), op: Equals, lhs: Direct(0), rhs: Direct(2) }, JumpIf { condition: Direct(3), location: 8 }, Const { destination: Direct(1), bit_size: Field, value: 1 }, BinaryFieldOp { destination: Direct(0), op: Div, lhs: Direct(1), rhs: Direct(0) }, Stop { return_data: HeapVector { pointer: Direct(20), size: Direct(21) } }]" + ], + "debug_symbols": "jZDdCoMwDIXfJde9UPfD5quMIVWjFEJbYjsY4rsvFnV6MdhN0uT0O6VnhBbr2FfGdm6A8jFCzYbI9BW5RgfjrGzHScE6VoERZQU7XSivGW2A0kYiBS9NMV0avLapB82iZgrQttLFsDOE82lSXzr7jZ7u+QKfs3zDL//zt+vGFwf+KZNuDB9+DDmUhYIi1ZPUabZmo2vCJZEu2mYXUHj7VVkj9OwabCPjbJ00eewD", + "file_map": { + "50": { + "source": "// We expect this program to fail if we incorrectly hoist the division.\n// This is an expansion of the `loop_invariant_regression_8586` test.\n// a = false\nfn main(a: pub bool) {\n for _ in 0..1 {\n for _ in 0..1 {\n for _ in 0..1 {\n for _ in 0..1 {\n if a {\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n }\n };\n }\n }\n }\n }\n\n for _ in 0..1 {\n if a {\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n\n for _ in 0..1 {\n for _ in 0..1 {\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n }\n }\n }\n }\n }\n }\n\n for _ in 0..1 {\n for _ in 0..1 {\n for _ in 0..1 {\n if a {\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n }\n }\n }\n }\n }\n }\n}\n", + "path": "" + } + }, + "names": [ + "main" + ], + "brillig_names": [ + "directive_invert" + ] +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_nested_deep/execute__tests__force_brillig_false_inliner_0.snap b/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_nested_deep/execute__tests__force_brillig_false_inliner_0.snap new file mode 100644 index 00000000000..257d0265404 --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_nested_deep/execute__tests__force_brillig_false_inliner_0.snap @@ -0,0 +1,48 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: artifact +--- +{ + "noir_version": "[noir_version]", + "hash": "[hash]", + "abi": { + "parameters": [ + { + "name": "a", + "type": { + "kind": "boolean" + }, + "visibility": "public" + } + ], + "return_type": null, + "error_types": {} + }, + "bytecode": [ + "func 0", + "current witness index : _2", + "private parameters indices : []", + "public parameters indices : [_0]", + "return value indices : []", + "BLACKBOX::RANGE [(_0, 1)] []", + "BRILLIG CALL func 0: PREDICATE = EXPR [ (1, _0) 0 ]", + "inputs: [Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(0))], q_c: 0 })], outputs: [Simple(Witness(1))]", + "EXPR [ (1, _0, _1) (-1, _2) 0 ]", + "EXPR [ (1, _0, _2) (-1, _0) 0 ]", + "unconstrained func 0", + "[Const { destination: Direct(21), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(20), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(0), size_address: Direct(21), offset_address: Direct(20) }, Const { destination: Direct(2), bit_size: Field, value: 0 }, BinaryFieldOp { destination: Direct(3), op: Equals, lhs: Direct(0), rhs: Direct(2) }, JumpIf { condition: Direct(3), location: 8 }, Const { destination: Direct(1), bit_size: Field, value: 1 }, BinaryFieldOp { destination: Direct(0), op: Div, lhs: Direct(1), rhs: Direct(0) }, Stop { return_data: HeapVector { pointer: Direct(20), size: Direct(21) } }]" + ], + "debug_symbols": "jZDdCoMwDIXfJde9UPfD5quMIVWjFEJbYjsY4rsvFnV6MdhN0uT0O6VnhBbr2FfGdm6A8jFCzYbI9BW5RgfjrGzHScE6VoERZQU7XSivGW2A0kYiBS9NMV0avLapB82iZgrQttLFsDOE82lSXzr7jZ7u+QKfs3zDL//zt+vGFwf+KZNuDB9+DDmUhYIi1ZPUabZmo2vCJZEu2mYXUHj7VVkj9OwabCPjbJ00eewD", + "file_map": { + "50": { + "source": "// We expect this program to fail if we incorrectly hoist the division.\n// This is an expansion of the `loop_invariant_regression_8586` test.\n// a = false\nfn main(a: pub bool) {\n for _ in 0..1 {\n for _ in 0..1 {\n for _ in 0..1 {\n for _ in 0..1 {\n if a {\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n }\n };\n }\n }\n }\n }\n\n for _ in 0..1 {\n if a {\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n\n for _ in 0..1 {\n for _ in 0..1 {\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n }\n }\n }\n }\n }\n }\n\n for _ in 0..1 {\n for _ in 0..1 {\n for _ in 0..1 {\n if a {\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n }\n }\n }\n }\n }\n }\n}\n", + "path": "" + } + }, + "names": [ + "main" + ], + "brillig_names": [ + "directive_invert" + ] +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_nested_deep/execute__tests__force_brillig_false_inliner_9223372036854775807.snap b/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_nested_deep/execute__tests__force_brillig_false_inliner_9223372036854775807.snap new file mode 100644 index 00000000000..257d0265404 --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_nested_deep/execute__tests__force_brillig_false_inliner_9223372036854775807.snap @@ -0,0 +1,48 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: artifact +--- +{ + "noir_version": "[noir_version]", + "hash": "[hash]", + "abi": { + "parameters": [ + { + "name": "a", + "type": { + "kind": "boolean" + }, + "visibility": "public" + } + ], + "return_type": null, + "error_types": {} + }, + "bytecode": [ + "func 0", + "current witness index : _2", + "private parameters indices : []", + "public parameters indices : [_0]", + "return value indices : []", + "BLACKBOX::RANGE [(_0, 1)] []", + "BRILLIG CALL func 0: PREDICATE = EXPR [ (1, _0) 0 ]", + "inputs: [Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(0))], q_c: 0 })], outputs: [Simple(Witness(1))]", + "EXPR [ (1, _0, _1) (-1, _2) 0 ]", + "EXPR [ (1, _0, _2) (-1, _0) 0 ]", + "unconstrained func 0", + "[Const { destination: Direct(21), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(20), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(0), size_address: Direct(21), offset_address: Direct(20) }, Const { destination: Direct(2), bit_size: Field, value: 0 }, BinaryFieldOp { destination: Direct(3), op: Equals, lhs: Direct(0), rhs: Direct(2) }, JumpIf { condition: Direct(3), location: 8 }, Const { destination: Direct(1), bit_size: Field, value: 1 }, BinaryFieldOp { destination: Direct(0), op: Div, lhs: Direct(1), rhs: Direct(0) }, Stop { return_data: HeapVector { pointer: Direct(20), size: Direct(21) } }]" + ], + "debug_symbols": "jZDdCoMwDIXfJde9UPfD5quMIVWjFEJbYjsY4rsvFnV6MdhN0uT0O6VnhBbr2FfGdm6A8jFCzYbI9BW5RgfjrGzHScE6VoERZQU7XSivGW2A0kYiBS9NMV0avLapB82iZgrQttLFsDOE82lSXzr7jZ7u+QKfs3zDL//zt+vGFwf+KZNuDB9+DDmUhYIi1ZPUabZmo2vCJZEu2mYXUHj7VVkj9OwabCPjbJ00eewD", + "file_map": { + "50": { + "source": "// We expect this program to fail if we incorrectly hoist the division.\n// This is an expansion of the `loop_invariant_regression_8586` test.\n// a = false\nfn main(a: pub bool) {\n for _ in 0..1 {\n for _ in 0..1 {\n for _ in 0..1 {\n for _ in 0..1 {\n if a {\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n }\n };\n }\n }\n }\n }\n\n for _ in 0..1 {\n if a {\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n\n for _ in 0..1 {\n for _ in 0..1 {\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n }\n }\n }\n }\n }\n }\n\n for _ in 0..1 {\n for _ in 0..1 {\n for _ in 0..1 {\n if a {\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n }\n }\n }\n }\n }\n }\n}\n", + "path": "" + } + }, + "names": [ + "main" + ], + "brillig_names": [ + "directive_invert" + ] +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_nested_deep/execute__tests__force_brillig_true_inliner_-9223372036854775808.snap b/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_nested_deep/execute__tests__force_brillig_true_inliner_-9223372036854775808.snap new file mode 100644 index 00000000000..4e5173f825f --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_nested_deep/execute__tests__force_brillig_true_inliner_-9223372036854775808.snap @@ -0,0 +1,49 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: artifact +--- +{ + "noir_version": "[noir_version]", + "hash": "[hash]", + "abi": { + "parameters": [ + { + "name": "a", + "type": { + "kind": "boolean" + }, + "visibility": "public" + } + ], + "return_type": null, + "error_types": { + "17843811134343075018": { + "error_kind": "string", + "string": "Stack too deep" + } + } + }, + "bytecode": [ + "func 0", + "current witness index : _0", + "private parameters indices : []", + "public parameters indices : [_0]", + "return value indices : []", + "BRILLIG CALL func 0: inputs: [Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(0))], q_c: 0 })], outputs: []", + "unconstrained func 0", + "[Const { destination: Direct(2), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(1), bit_size: Integer(U32), value: 32837 }, Const { destination: Direct(0), bit_size: Integer(U32), value: 3 }, Const { destination: Relative(2), bit_size: Integer(U32), value: 1 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(32836), size_address: Relative(2), offset_address: Relative(3) }, Cast { destination: Direct(32836), source: Direct(32836), bit_size: Integer(U1) }, Mov { destination: Relative(1), source: Direct(32836) }, Call { location: 13 }, Call { location: 14 }, Const { destination: Relative(1), bit_size: Integer(U32), value: 32837 }, Const { destination: Relative(2), bit_size: Integer(U32), value: 0 }, Stop { return_data: HeapVector { pointer: Relative(1), size: Relative(2) } }, Return, Call { location: 32 }, Cast { destination: Relative(2), source: Relative(1), bit_size: Field }, Const { destination: Relative(3), bit_size: Field, value: 1 }, JumpIf { condition: Relative(1), location: 19 }, Jump { location: 21 }, BinaryFieldOp { destination: Relative(4), op: Div, lhs: Relative(3), rhs: Relative(2) }, Jump { location: 21 }, JumpIf { condition: Relative(1), location: 23 }, Jump { location: 26 }, BinaryFieldOp { destination: Relative(4), op: Div, lhs: Relative(3), rhs: Relative(2) }, BinaryFieldOp { destination: Relative(5), op: Div, lhs: Relative(3), rhs: Relative(2) }, Jump { location: 26 }, JumpIf { condition: Relative(1), location: 28 }, Jump { location: 31 }, BinaryFieldOp { destination: Relative(1), op: Div, lhs: Relative(3), rhs: Relative(2) }, BinaryFieldOp { destination: Relative(4), op: Div, lhs: Relative(3), rhs: Relative(2) }, Jump { location: 31 }, Return, Const { destination: Direct(32772), bit_size: Integer(U32), value: 30720 }, BinaryIntOp { destination: Direct(32771), op: LessThan, bit_size: U32, lhs: Direct(0), rhs: Direct(32772) }, JumpIf { condition: Direct(32771), location: 37 }, IndirectConst { destination_pointer: Direct(1), bit_size: Integer(U64), value: 17843811134343075018 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Direct(2) } }, Return]" + ], + "debug_symbols": "nZLBjoMgFEX/5a1ZgIhWfqVpDCo2JAQNhUkmhn+fR1Mcu2jSuOHyuJx7N2+DSQ/x3hs3Lw+Q1w0Gb6w1994uowpmcfi6Ac0HEyAZAdaBrAhUHCRHqUHWKBeQAgW9JiUChe6D1zrDhzgsWZXXLoB00VoCP8rG56fHqtxTg/LoUgLaTagYOBur8y2Rf5p+RnnHXnBN2Y6L7/lLs/PVCV7s/Q1tT/CtKP1te6afUV4CGBWnEhjnJYHV3VvCDSc1Gv+2JClneaMGq1/jHN14cMPvWpyyZKtfRj1Fr3PSYdPwvPKK8PaWctsf", + "file_map": { + "50": { + "source": "// We expect this program to fail if we incorrectly hoist the division.\n// This is an expansion of the `loop_invariant_regression_8586` test.\n// a = false\nfn main(a: pub bool) {\n for _ in 0..1 {\n for _ in 0..1 {\n for _ in 0..1 {\n for _ in 0..1 {\n if a {\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n }\n };\n }\n }\n }\n }\n\n for _ in 0..1 {\n if a {\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n\n for _ in 0..1 {\n for _ in 0..1 {\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n }\n }\n }\n }\n }\n }\n\n for _ in 0..1 {\n for _ in 0..1 {\n for _ in 0..1 {\n if a {\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n }\n }\n }\n }\n }\n }\n}\n", + "path": "" + } + }, + "names": [ + "main" + ], + "brillig_names": [ + "main" + ] +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_nested_deep/execute__tests__force_brillig_true_inliner_0.snap b/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_nested_deep/execute__tests__force_brillig_true_inliner_0.snap new file mode 100644 index 00000000000..4e5173f825f --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_nested_deep/execute__tests__force_brillig_true_inliner_0.snap @@ -0,0 +1,49 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: artifact +--- +{ + "noir_version": "[noir_version]", + "hash": "[hash]", + "abi": { + "parameters": [ + { + "name": "a", + "type": { + "kind": "boolean" + }, + "visibility": "public" + } + ], + "return_type": null, + "error_types": { + "17843811134343075018": { + "error_kind": "string", + "string": "Stack too deep" + } + } + }, + "bytecode": [ + "func 0", + "current witness index : _0", + "private parameters indices : []", + "public parameters indices : [_0]", + "return value indices : []", + "BRILLIG CALL func 0: inputs: [Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(0))], q_c: 0 })], outputs: []", + "unconstrained func 0", + "[Const { destination: Direct(2), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(1), bit_size: Integer(U32), value: 32837 }, Const { destination: Direct(0), bit_size: Integer(U32), value: 3 }, Const { destination: Relative(2), bit_size: Integer(U32), value: 1 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(32836), size_address: Relative(2), offset_address: Relative(3) }, Cast { destination: Direct(32836), source: Direct(32836), bit_size: Integer(U1) }, Mov { destination: Relative(1), source: Direct(32836) }, Call { location: 13 }, Call { location: 14 }, Const { destination: Relative(1), bit_size: Integer(U32), value: 32837 }, Const { destination: Relative(2), bit_size: Integer(U32), value: 0 }, Stop { return_data: HeapVector { pointer: Relative(1), size: Relative(2) } }, Return, Call { location: 32 }, Cast { destination: Relative(2), source: Relative(1), bit_size: Field }, Const { destination: Relative(3), bit_size: Field, value: 1 }, JumpIf { condition: Relative(1), location: 19 }, Jump { location: 21 }, BinaryFieldOp { destination: Relative(4), op: Div, lhs: Relative(3), rhs: Relative(2) }, Jump { location: 21 }, JumpIf { condition: Relative(1), location: 23 }, Jump { location: 26 }, BinaryFieldOp { destination: Relative(4), op: Div, lhs: Relative(3), rhs: Relative(2) }, BinaryFieldOp { destination: Relative(5), op: Div, lhs: Relative(3), rhs: Relative(2) }, Jump { location: 26 }, JumpIf { condition: Relative(1), location: 28 }, Jump { location: 31 }, BinaryFieldOp { destination: Relative(1), op: Div, lhs: Relative(3), rhs: Relative(2) }, BinaryFieldOp { destination: Relative(4), op: Div, lhs: Relative(3), rhs: Relative(2) }, Jump { location: 31 }, Return, Const { destination: Direct(32772), bit_size: Integer(U32), value: 30720 }, BinaryIntOp { destination: Direct(32771), op: LessThan, bit_size: U32, lhs: Direct(0), rhs: Direct(32772) }, JumpIf { condition: Direct(32771), location: 37 }, IndirectConst { destination_pointer: Direct(1), bit_size: Integer(U64), value: 17843811134343075018 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Direct(2) } }, Return]" + ], + "debug_symbols": "nZLBjoMgFEX/5a1ZgIhWfqVpDCo2JAQNhUkmhn+fR1Mcu2jSuOHyuJx7N2+DSQ/x3hs3Lw+Q1w0Gb6w1994uowpmcfi6Ac0HEyAZAdaBrAhUHCRHqUHWKBeQAgW9JiUChe6D1zrDhzgsWZXXLoB00VoCP8rG56fHqtxTg/LoUgLaTagYOBur8y2Rf5p+RnnHXnBN2Y6L7/lLs/PVCV7s/Q1tT/CtKP1te6afUV4CGBWnEhjnJYHV3VvCDSc1Gv+2JClneaMGq1/jHN14cMPvWpyyZKtfRj1Fr3PSYdPwvPKK8PaWctsf", + "file_map": { + "50": { + "source": "// We expect this program to fail if we incorrectly hoist the division.\n// This is an expansion of the `loop_invariant_regression_8586` test.\n// a = false\nfn main(a: pub bool) {\n for _ in 0..1 {\n for _ in 0..1 {\n for _ in 0..1 {\n for _ in 0..1 {\n if a {\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n }\n };\n }\n }\n }\n }\n\n for _ in 0..1 {\n if a {\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n\n for _ in 0..1 {\n for _ in 0..1 {\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n }\n }\n }\n }\n }\n }\n\n for _ in 0..1 {\n for _ in 0..1 {\n for _ in 0..1 {\n if a {\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n }\n }\n }\n }\n }\n }\n}\n", + "path": "" + } + }, + "names": [ + "main" + ], + "brillig_names": [ + "main" + ] +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_nested_deep/execute__tests__force_brillig_true_inliner_9223372036854775807.snap b/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_nested_deep/execute__tests__force_brillig_true_inliner_9223372036854775807.snap new file mode 100644 index 00000000000..4e5173f825f --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_nested_deep/execute__tests__force_brillig_true_inliner_9223372036854775807.snap @@ -0,0 +1,49 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: artifact +--- +{ + "noir_version": "[noir_version]", + "hash": "[hash]", + "abi": { + "parameters": [ + { + "name": "a", + "type": { + "kind": "boolean" + }, + "visibility": "public" + } + ], + "return_type": null, + "error_types": { + "17843811134343075018": { + "error_kind": "string", + "string": "Stack too deep" + } + } + }, + "bytecode": [ + "func 0", + "current witness index : _0", + "private parameters indices : []", + "public parameters indices : [_0]", + "return value indices : []", + "BRILLIG CALL func 0: inputs: [Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(0))], q_c: 0 })], outputs: []", + "unconstrained func 0", + "[Const { destination: Direct(2), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(1), bit_size: Integer(U32), value: 32837 }, Const { destination: Direct(0), bit_size: Integer(U32), value: 3 }, Const { destination: Relative(2), bit_size: Integer(U32), value: 1 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(32836), size_address: Relative(2), offset_address: Relative(3) }, Cast { destination: Direct(32836), source: Direct(32836), bit_size: Integer(U1) }, Mov { destination: Relative(1), source: Direct(32836) }, Call { location: 13 }, Call { location: 14 }, Const { destination: Relative(1), bit_size: Integer(U32), value: 32837 }, Const { destination: Relative(2), bit_size: Integer(U32), value: 0 }, Stop { return_data: HeapVector { pointer: Relative(1), size: Relative(2) } }, Return, Call { location: 32 }, Cast { destination: Relative(2), source: Relative(1), bit_size: Field }, Const { destination: Relative(3), bit_size: Field, value: 1 }, JumpIf { condition: Relative(1), location: 19 }, Jump { location: 21 }, BinaryFieldOp { destination: Relative(4), op: Div, lhs: Relative(3), rhs: Relative(2) }, Jump { location: 21 }, JumpIf { condition: Relative(1), location: 23 }, Jump { location: 26 }, BinaryFieldOp { destination: Relative(4), op: Div, lhs: Relative(3), rhs: Relative(2) }, BinaryFieldOp { destination: Relative(5), op: Div, lhs: Relative(3), rhs: Relative(2) }, Jump { location: 26 }, JumpIf { condition: Relative(1), location: 28 }, Jump { location: 31 }, BinaryFieldOp { destination: Relative(1), op: Div, lhs: Relative(3), rhs: Relative(2) }, BinaryFieldOp { destination: Relative(4), op: Div, lhs: Relative(3), rhs: Relative(2) }, Jump { location: 31 }, Return, Const { destination: Direct(32772), bit_size: Integer(U32), value: 30720 }, BinaryIntOp { destination: Direct(32771), op: LessThan, bit_size: U32, lhs: Direct(0), rhs: Direct(32772) }, JumpIf { condition: Direct(32771), location: 37 }, IndirectConst { destination_pointer: Direct(1), bit_size: Integer(U64), value: 17843811134343075018 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Direct(2) } }, Return]" + ], + "debug_symbols": "nZLBjoMgFEX/5a1ZgIhWfqVpDCo2JAQNhUkmhn+fR1Mcu2jSuOHyuJx7N2+DSQ/x3hs3Lw+Q1w0Gb6w1994uowpmcfi6Ac0HEyAZAdaBrAhUHCRHqUHWKBeQAgW9JiUChe6D1zrDhzgsWZXXLoB00VoCP8rG56fHqtxTg/LoUgLaTagYOBur8y2Rf5p+RnnHXnBN2Y6L7/lLs/PVCV7s/Q1tT/CtKP1te6afUV4CGBWnEhjnJYHV3VvCDSc1Gv+2JClneaMGq1/jHN14cMPvWpyyZKtfRj1Fr3PSYdPwvPKK8PaWctsf", + "file_map": { + "50": { + "source": "// We expect this program to fail if we incorrectly hoist the division.\n// This is an expansion of the `loop_invariant_regression_8586` test.\n// a = false\nfn main(a: pub bool) {\n for _ in 0..1 {\n for _ in 0..1 {\n for _ in 0..1 {\n for _ in 0..1 {\n if a {\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n }\n };\n }\n }\n }\n }\n\n for _ in 0..1 {\n if a {\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n\n for _ in 0..1 {\n for _ in 0..1 {\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n }\n }\n }\n }\n }\n }\n\n for _ in 0..1 {\n for _ in 0..1 {\n for _ in 0..1 {\n if a {\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n }\n }\n }\n }\n }\n }\n}\n", + "path": "" + } + }, + "names": [ + "main" + ], + "brillig_names": [ + "main" + ] +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_nested_deep/execute__tests__stdout.snap b/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_nested_deep/execute__tests__stdout.snap new file mode 100644 index 00000000000..e86e3de90e1 --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_nested_deep/execute__tests__stdout.snap @@ -0,0 +1,5 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: stdout +--- + diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_regression_8586/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_regression_8586/execute__tests__expanded.snap new file mode 100644 index 00000000000..428945187f1 --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_regression_8586/execute__tests__expanded.snap @@ -0,0 +1,13 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: expanded_code +--- +fn main(a: pub bool) { + for _ in 0..1 { + if a { + for _ in 0..1 { + let _: Field = 1 / (a as Field); + } + }; + } +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_regression_8586/execute__tests__force_brillig_false_inliner_-9223372036854775808.snap b/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_regression_8586/execute__tests__force_brillig_false_inliner_-9223372036854775808.snap new file mode 100644 index 00000000000..d9979d599b6 --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_regression_8586/execute__tests__force_brillig_false_inliner_-9223372036854775808.snap @@ -0,0 +1,48 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: artifact +--- +{ + "noir_version": "[noir_version]", + "hash": "[hash]", + "abi": { + "parameters": [ + { + "name": "a", + "type": { + "kind": "boolean" + }, + "visibility": "public" + } + ], + "return_type": null, + "error_types": {} + }, + "bytecode": [ + "func 0", + "current witness index : _2", + "private parameters indices : []", + "public parameters indices : [_0]", + "return value indices : []", + "BLACKBOX::RANGE [(_0, 1)] []", + "BRILLIG CALL func 0: PREDICATE = EXPR [ (1, _0) 0 ]", + "inputs: [Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(0))], q_c: 0 })], outputs: [Simple(Witness(1))]", + "EXPR [ (1, _0, _1) (-1, _2) 0 ]", + "EXPR [ (1, _0, _2) (-1, _0) 0 ]", + "unconstrained func 0", + "[Const { destination: Direct(21), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(20), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(0), size_address: Direct(21), offset_address: Direct(20) }, Const { destination: Direct(2), bit_size: Field, value: 0 }, BinaryFieldOp { destination: Direct(3), op: Equals, lhs: Direct(0), rhs: Direct(2) }, JumpIf { condition: Direct(3), location: 8 }, Const { destination: Direct(1), bit_size: Field, value: 1 }, BinaryFieldOp { destination: Direct(0), op: Div, lhs: Direct(1), rhs: Direct(0) }, Stop { return_data: HeapVector { pointer: Direct(20), size: Direct(21) } }]" + ], + "debug_symbols": "jZDBCoMwDIbfJece1ClMX2UMqTVKobQltoMhvvtiUaeHwS5Jkz9fSv4Zeuzi2Go7uAmaxwwdaWP02BqnZNDOcndeBOxlGwiRW3DSmfKS0AZobDRGwEuamIYmL23KQRKrmQC0PWdeOGiD62sRXzr7jeZ1ucFFVh549T9/rw++uvBPrqTSdLkYch4UUKR447isq0nLzuDmyBCtOhkU3n5Xdgs9OYV9JFxXJ40/+wA=", + "file_map": { + "50": { + "source": "// Regression for issue #8586 (https://github.com/noir-lang/noir/issues/8586)\nfn main(a: pub bool) {\n for _ in 0..1 {\n if a {\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n }\n };\n }\n}\n", + "path": "" + } + }, + "names": [ + "main" + ], + "brillig_names": [ + "directive_invert" + ] +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_regression_8586/execute__tests__force_brillig_false_inliner_0.snap b/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_regression_8586/execute__tests__force_brillig_false_inliner_0.snap new file mode 100644 index 00000000000..d9979d599b6 --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_regression_8586/execute__tests__force_brillig_false_inliner_0.snap @@ -0,0 +1,48 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: artifact +--- +{ + "noir_version": "[noir_version]", + "hash": "[hash]", + "abi": { + "parameters": [ + { + "name": "a", + "type": { + "kind": "boolean" + }, + "visibility": "public" + } + ], + "return_type": null, + "error_types": {} + }, + "bytecode": [ + "func 0", + "current witness index : _2", + "private parameters indices : []", + "public parameters indices : [_0]", + "return value indices : []", + "BLACKBOX::RANGE [(_0, 1)] []", + "BRILLIG CALL func 0: PREDICATE = EXPR [ (1, _0) 0 ]", + "inputs: [Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(0))], q_c: 0 })], outputs: [Simple(Witness(1))]", + "EXPR [ (1, _0, _1) (-1, _2) 0 ]", + "EXPR [ (1, _0, _2) (-1, _0) 0 ]", + "unconstrained func 0", + "[Const { destination: Direct(21), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(20), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(0), size_address: Direct(21), offset_address: Direct(20) }, Const { destination: Direct(2), bit_size: Field, value: 0 }, BinaryFieldOp { destination: Direct(3), op: Equals, lhs: Direct(0), rhs: Direct(2) }, JumpIf { condition: Direct(3), location: 8 }, Const { destination: Direct(1), bit_size: Field, value: 1 }, BinaryFieldOp { destination: Direct(0), op: Div, lhs: Direct(1), rhs: Direct(0) }, Stop { return_data: HeapVector { pointer: Direct(20), size: Direct(21) } }]" + ], + "debug_symbols": "jZDBCoMwDIbfJece1ClMX2UMqTVKobQltoMhvvtiUaeHwS5Jkz9fSv4Zeuzi2Go7uAmaxwwdaWP02BqnZNDOcndeBOxlGwiRW3DSmfKS0AZobDRGwEuamIYmL23KQRKrmQC0PWdeOGiD62sRXzr7jeZ1ucFFVh549T9/rw++uvBPrqTSdLkYch4UUKR447isq0nLzuDmyBCtOhkU3n5Xdgs9OYV9JFxXJ40/+wA=", + "file_map": { + "50": { + "source": "// Regression for issue #8586 (https://github.com/noir-lang/noir/issues/8586)\nfn main(a: pub bool) {\n for _ in 0..1 {\n if a {\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n }\n };\n }\n}\n", + "path": "" + } + }, + "names": [ + "main" + ], + "brillig_names": [ + "directive_invert" + ] +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_regression_8586/execute__tests__force_brillig_false_inliner_9223372036854775807.snap b/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_regression_8586/execute__tests__force_brillig_false_inliner_9223372036854775807.snap new file mode 100644 index 00000000000..d9979d599b6 --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_regression_8586/execute__tests__force_brillig_false_inliner_9223372036854775807.snap @@ -0,0 +1,48 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: artifact +--- +{ + "noir_version": "[noir_version]", + "hash": "[hash]", + "abi": { + "parameters": [ + { + "name": "a", + "type": { + "kind": "boolean" + }, + "visibility": "public" + } + ], + "return_type": null, + "error_types": {} + }, + "bytecode": [ + "func 0", + "current witness index : _2", + "private parameters indices : []", + "public parameters indices : [_0]", + "return value indices : []", + "BLACKBOX::RANGE [(_0, 1)] []", + "BRILLIG CALL func 0: PREDICATE = EXPR [ (1, _0) 0 ]", + "inputs: [Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(0))], q_c: 0 })], outputs: [Simple(Witness(1))]", + "EXPR [ (1, _0, _1) (-1, _2) 0 ]", + "EXPR [ (1, _0, _2) (-1, _0) 0 ]", + "unconstrained func 0", + "[Const { destination: Direct(21), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(20), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(0), size_address: Direct(21), offset_address: Direct(20) }, Const { destination: Direct(2), bit_size: Field, value: 0 }, BinaryFieldOp { destination: Direct(3), op: Equals, lhs: Direct(0), rhs: Direct(2) }, JumpIf { condition: Direct(3), location: 8 }, Const { destination: Direct(1), bit_size: Field, value: 1 }, BinaryFieldOp { destination: Direct(0), op: Div, lhs: Direct(1), rhs: Direct(0) }, Stop { return_data: HeapVector { pointer: Direct(20), size: Direct(21) } }]" + ], + "debug_symbols": "jZDBCoMwDIbfJece1ClMX2UMqTVKobQltoMhvvtiUaeHwS5Jkz9fSv4Zeuzi2Go7uAmaxwwdaWP02BqnZNDOcndeBOxlGwiRW3DSmfKS0AZobDRGwEuamIYmL23KQRKrmQC0PWdeOGiD62sRXzr7jeZ1ucFFVh549T9/rw++uvBPrqTSdLkYch4UUKR447isq0nLzuDmyBCtOhkU3n5Xdgs9OYV9JFxXJ40/+wA=", + "file_map": { + "50": { + "source": "// Regression for issue #8586 (https://github.com/noir-lang/noir/issues/8586)\nfn main(a: pub bool) {\n for _ in 0..1 {\n if a {\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n }\n };\n }\n}\n", + "path": "" + } + }, + "names": [ + "main" + ], + "brillig_names": [ + "directive_invert" + ] +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_regression_8586/execute__tests__force_brillig_true_inliner_-9223372036854775808.snap b/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_regression_8586/execute__tests__force_brillig_true_inliner_-9223372036854775808.snap new file mode 100644 index 00000000000..f83ce881d64 --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_regression_8586/execute__tests__force_brillig_true_inliner_-9223372036854775808.snap @@ -0,0 +1,49 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: artifact +--- +{ + "noir_version": "[noir_version]", + "hash": "[hash]", + "abi": { + "parameters": [ + { + "name": "a", + "type": { + "kind": "boolean" + }, + "visibility": "public" + } + ], + "return_type": null, + "error_types": { + "17843811134343075018": { + "error_kind": "string", + "string": "Stack too deep" + } + } + }, + "bytecode": [ + "func 0", + "current witness index : _0", + "private parameters indices : []", + "public parameters indices : [_0]", + "return value indices : []", + "BRILLIG CALL func 0: inputs: [Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(0))], q_c: 0 })], outputs: []", + "unconstrained func 0", + "[Const { destination: Direct(2), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(1), bit_size: Integer(U32), value: 32837 }, Const { destination: Direct(0), bit_size: Integer(U32), value: 3 }, Const { destination: Relative(2), bit_size: Integer(U32), value: 1 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(32836), size_address: Relative(2), offset_address: Relative(3) }, Cast { destination: Direct(32836), source: Direct(32836), bit_size: Integer(U1) }, Mov { destination: Relative(1), source: Direct(32836) }, Call { location: 13 }, Call { location: 14 }, Const { destination: Relative(1), bit_size: Integer(U32), value: 32837 }, Const { destination: Relative(2), bit_size: Integer(U32), value: 0 }, Stop { return_data: HeapVector { pointer: Relative(1), size: Relative(2) } }, Return, Call { location: 22 }, Cast { destination: Relative(2), source: Relative(1), bit_size: Field }, JumpIf { condition: Relative(1), location: 18 }, Jump { location: 21 }, Const { destination: Relative(1), bit_size: Field, value: 1 }, BinaryFieldOp { destination: Relative(3), op: Div, lhs: Relative(1), rhs: Relative(2) }, Jump { location: 21 }, Return, Const { destination: Direct(32772), bit_size: Integer(U32), value: 30720 }, BinaryIntOp { destination: Direct(32771), op: LessThan, bit_size: U32, lhs: Direct(0), rhs: Direct(32772) }, JumpIf { condition: Direct(32771), location: 27 }, IndirectConst { destination_pointer: Direct(1), bit_size: Integer(U64), value: 17843811134343075018 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Direct(2) } }, Return]" + ], + "debug_symbols": "jZDRCoMwDEX/Jc990DKZ+isiUjVKobSltoMh/felok4fBnvJbZqcG7grjNiHuZN6MgvUzQq9k0rJuVNmEF4aTb8rZKnkBdQ5g7yEmpNUJDEyOBY77xDT3oUkPyscag+1DkoxeAkVtqXFCr2pF46mGQPUIykZTlJhekX2pbPfaF49dphnjxMv/ufL6uSLG99SJwbpblnE5OSk6BXu7RT0cJn6tz0mR5bWmQHH4DA5XQKl2nDO+LON6doH", + "file_map": { + "50": { + "source": "// Regression for issue #8586 (https://github.com/noir-lang/noir/issues/8586)\nfn main(a: pub bool) {\n for _ in 0..1 {\n if a {\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n }\n };\n }\n}\n", + "path": "" + } + }, + "names": [ + "main" + ], + "brillig_names": [ + "main" + ] +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_regression_8586/execute__tests__force_brillig_true_inliner_0.snap b/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_regression_8586/execute__tests__force_brillig_true_inliner_0.snap new file mode 100644 index 00000000000..f83ce881d64 --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_regression_8586/execute__tests__force_brillig_true_inliner_0.snap @@ -0,0 +1,49 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: artifact +--- +{ + "noir_version": "[noir_version]", + "hash": "[hash]", + "abi": { + "parameters": [ + { + "name": "a", + "type": { + "kind": "boolean" + }, + "visibility": "public" + } + ], + "return_type": null, + "error_types": { + "17843811134343075018": { + "error_kind": "string", + "string": "Stack too deep" + } + } + }, + "bytecode": [ + "func 0", + "current witness index : _0", + "private parameters indices : []", + "public parameters indices : [_0]", + "return value indices : []", + "BRILLIG CALL func 0: inputs: [Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(0))], q_c: 0 })], outputs: []", + "unconstrained func 0", + "[Const { destination: Direct(2), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(1), bit_size: Integer(U32), value: 32837 }, Const { destination: Direct(0), bit_size: Integer(U32), value: 3 }, Const { destination: Relative(2), bit_size: Integer(U32), value: 1 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(32836), size_address: Relative(2), offset_address: Relative(3) }, Cast { destination: Direct(32836), source: Direct(32836), bit_size: Integer(U1) }, Mov { destination: Relative(1), source: Direct(32836) }, Call { location: 13 }, Call { location: 14 }, Const { destination: Relative(1), bit_size: Integer(U32), value: 32837 }, Const { destination: Relative(2), bit_size: Integer(U32), value: 0 }, Stop { return_data: HeapVector { pointer: Relative(1), size: Relative(2) } }, Return, Call { location: 22 }, Cast { destination: Relative(2), source: Relative(1), bit_size: Field }, JumpIf { condition: Relative(1), location: 18 }, Jump { location: 21 }, Const { destination: Relative(1), bit_size: Field, value: 1 }, BinaryFieldOp { destination: Relative(3), op: Div, lhs: Relative(1), rhs: Relative(2) }, Jump { location: 21 }, Return, Const { destination: Direct(32772), bit_size: Integer(U32), value: 30720 }, BinaryIntOp { destination: Direct(32771), op: LessThan, bit_size: U32, lhs: Direct(0), rhs: Direct(32772) }, JumpIf { condition: Direct(32771), location: 27 }, IndirectConst { destination_pointer: Direct(1), bit_size: Integer(U64), value: 17843811134343075018 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Direct(2) } }, Return]" + ], + "debug_symbols": "jZDRCoMwDEX/Jc990DKZ+isiUjVKobSltoMh/felok4fBnvJbZqcG7grjNiHuZN6MgvUzQq9k0rJuVNmEF4aTb8rZKnkBdQ5g7yEmpNUJDEyOBY77xDT3oUkPyscag+1DkoxeAkVtqXFCr2pF46mGQPUIykZTlJhekX2pbPfaF49dphnjxMv/ufL6uSLG99SJwbpblnE5OSk6BXu7RT0cJn6tz0mR5bWmQHH4DA5XQKl2nDO+LON6doH", + "file_map": { + "50": { + "source": "// Regression for issue #8586 (https://github.com/noir-lang/noir/issues/8586)\nfn main(a: pub bool) {\n for _ in 0..1 {\n if a {\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n }\n };\n }\n}\n", + "path": "" + } + }, + "names": [ + "main" + ], + "brillig_names": [ + "main" + ] +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_regression_8586/execute__tests__force_brillig_true_inliner_9223372036854775807.snap b/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_regression_8586/execute__tests__force_brillig_true_inliner_9223372036854775807.snap new file mode 100644 index 00000000000..f83ce881d64 --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_regression_8586/execute__tests__force_brillig_true_inliner_9223372036854775807.snap @@ -0,0 +1,49 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: artifact +--- +{ + "noir_version": "[noir_version]", + "hash": "[hash]", + "abi": { + "parameters": [ + { + "name": "a", + "type": { + "kind": "boolean" + }, + "visibility": "public" + } + ], + "return_type": null, + "error_types": { + "17843811134343075018": { + "error_kind": "string", + "string": "Stack too deep" + } + } + }, + "bytecode": [ + "func 0", + "current witness index : _0", + "private parameters indices : []", + "public parameters indices : [_0]", + "return value indices : []", + "BRILLIG CALL func 0: inputs: [Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(0))], q_c: 0 })], outputs: []", + "unconstrained func 0", + "[Const { destination: Direct(2), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(1), bit_size: Integer(U32), value: 32837 }, Const { destination: Direct(0), bit_size: Integer(U32), value: 3 }, Const { destination: Relative(2), bit_size: Integer(U32), value: 1 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(32836), size_address: Relative(2), offset_address: Relative(3) }, Cast { destination: Direct(32836), source: Direct(32836), bit_size: Integer(U1) }, Mov { destination: Relative(1), source: Direct(32836) }, Call { location: 13 }, Call { location: 14 }, Const { destination: Relative(1), bit_size: Integer(U32), value: 32837 }, Const { destination: Relative(2), bit_size: Integer(U32), value: 0 }, Stop { return_data: HeapVector { pointer: Relative(1), size: Relative(2) } }, Return, Call { location: 22 }, Cast { destination: Relative(2), source: Relative(1), bit_size: Field }, JumpIf { condition: Relative(1), location: 18 }, Jump { location: 21 }, Const { destination: Relative(1), bit_size: Field, value: 1 }, BinaryFieldOp { destination: Relative(3), op: Div, lhs: Relative(1), rhs: Relative(2) }, Jump { location: 21 }, Return, Const { destination: Direct(32772), bit_size: Integer(U32), value: 30720 }, BinaryIntOp { destination: Direct(32771), op: LessThan, bit_size: U32, lhs: Direct(0), rhs: Direct(32772) }, JumpIf { condition: Direct(32771), location: 27 }, IndirectConst { destination_pointer: Direct(1), bit_size: Integer(U64), value: 17843811134343075018 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Direct(2) } }, Return]" + ], + "debug_symbols": "jZDRCoMwDEX/Jc990DKZ+isiUjVKobSltoMh/felok4fBnvJbZqcG7grjNiHuZN6MgvUzQq9k0rJuVNmEF4aTb8rZKnkBdQ5g7yEmpNUJDEyOBY77xDT3oUkPyscag+1DkoxeAkVtqXFCr2pF46mGQPUIykZTlJhekX2pbPfaF49dphnjxMv/ufL6uSLG99SJwbpblnE5OSk6BXu7RT0cJn6tz0mR5bWmQHH4DA5XQKl2nDO+LON6doH", + "file_map": { + "50": { + "source": "// Regression for issue #8586 (https://github.com/noir-lang/noir/issues/8586)\nfn main(a: pub bool) {\n for _ in 0..1 {\n if a {\n for _ in 0..1 {\n let _ = (1 / (a as Field));\n }\n };\n }\n}\n", + "path": "" + } + }, + "names": [ + "main" + ], + "brillig_names": [ + "main" + ] +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_regression_8586/execute__tests__stdout.snap b/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_regression_8586/execute__tests__stdout.snap new file mode 100644 index 00000000000..e86e3de90e1 --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/loop_invariant_regression_8586/execute__tests__stdout.snap @@ -0,0 +1,5 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: stdout +--- +