diff --git a/compiler/noirc_evaluator/src/ssa/opt/brillig_entry_points.rs b/compiler/noirc_evaluator/src/ssa/opt/brillig_entry_points.rs index 2fe33eef46a..edb90609f24 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/brillig_entry_points.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/brillig_entry_points.rs @@ -67,8 +67,8 @@ use crate::ssa::{ Ssa, ir::{ function::{Function, FunctionId}, - instruction::Instruction, - value::Value, + instruction::{Instruction, InstructionId}, + value::{Value, ValueId}, }, }; @@ -80,33 +80,55 @@ impl Ssa { return self; } + // Build a call graph based upon the Brillig entry points and set up + // the functions needing specialization before performing the actual call site rewrites. let brillig_entry_points = get_brillig_entry_points(&self.functions, self.main_id); - let functions_to_clone_map = build_functions_to_clone(&brillig_entry_points); + let (calls_to_update, mut new_functions_map) = + build_calls_to_update(&mut self, functions_to_clone_map, &brillig_entry_points); - let calls_to_update = build_calls_to_update(&mut self, functions_to_clone_map); - - let mut new_functions_map = HashMap::default(); - for (entry_point, inner_calls) in brillig_entry_points { - let new_entry_point = - new_functions_map.get(&entry_point).copied().unwrap_or(entry_point); - - let function = - self.functions.get_mut(&new_entry_point).expect("ICE: Function does not exist"); - update_function_calls(function, entry_point, &mut new_functions_map, &calls_to_update); + // Now we want to actually rewrite the appropriate call sites + // First pass to rewrite the originally supplied call graph + for CallToUpdate { + entry_point, + function_to_update, + instruction, + new_func_to_call: new_id, + call_args: arguments, + } in calls_to_update + { + // Fetch the caller function whose call site we wish to update + let new_function_to_update = if entry_point == function_to_update { + // Do not fetch entry points from the new functions map. + // We leave resolving duplicated entry points to a later pass + entry_point + } else { + new_functions_map + .entry(entry_point) + .or_default() + .get(&function_to_update) + .copied() + .unwrap_or(function_to_update) + }; - for inner_call in inner_calls { - let new_inner_call = - new_functions_map.get(&inner_call).copied().unwrap_or(inner_call); + let function = self + .functions + .get_mut(&new_function_to_update) + .expect("ICE: Function does not exist"); + let new_function_value_id = function.dfg.import_function(new_id); + function.dfg[instruction] = + Instruction::Call { func: new_function_value_id, arguments }; + } + // Second pass to rewrite the calls sites in the cloned functions + // The list of structs mapping call site updates in `calls_to_update` only includes the original function IDs + // so we risk potentially not rewriting the call sites within the cloned functions themselves. + // The cloned functions we are using are stored within the `new_functions_map`. + for (_, new_functions_per_entry) in new_functions_map { + for new_function in new_functions_per_entry.values() { let function = - self.functions.get_mut(&new_inner_call).expect("ICE: Function does not exist"); - update_function_calls( - function, - entry_point, - &mut new_functions_map, - &calls_to_update, - ); + self.functions.get_mut(new_function).expect("ICE: Function does not exist"); + resolve_cloned_function_call_sites(function, &new_functions_per_entry); } } @@ -114,6 +136,38 @@ impl Ssa { } } +/// Given that we have already rewritten all the call sites among the original SSA, +/// this function provides a helper for resolving the call sites within cloned functions. +/// This function will update a cloned function according to the supplied function mapping. +/// The function assumes that the supplied mapping is per entry point and handled +/// by the caller of this method. +fn resolve_cloned_function_call_sites( + // Function that was cloned earlier in the pass to specialize functions + // in the original SSA + function: &mut Function, + // Per entry point, maps (old function -> new function) + new_functions_map: &HashMap, +) { + for block_id in function.reachable_blocks() { + #[allow(clippy::unnecessary_to_owned)] // clippy is wrong here + for instruction_id in function.dfg[block_id].instructions().to_vec() { + let instruction = function.dfg[instruction_id].clone(); + let Instruction::Call { func: func_value_id, arguments } = instruction else { + continue; + }; + let func_value = &function.dfg[func_value_id]; + let Value::Function(func_id) = func_value else { continue }; + + let Some(new_func_id) = new_functions_map.get(func_id) else { + continue; + }; + let new_function_value_id = function.dfg.import_function(*new_func_id); + function.dfg[instruction_id] = + Instruction::Call { func: new_function_value_id, arguments }; + } + } +} + /// For every call site, we can determine the entry point for a given callee. /// Once we know that we can determine which functions are in need of duplication. /// We duplicate when the following occurs: @@ -139,15 +193,23 @@ fn build_functions_to_clone( functions_to_clone_map } +// Per entry point context, maps the original function to its new specialized function +// (entry_point -> map(old_id, new_id)) +type NewCallSitesMap = HashMap>; + /// Clones new functions and returns a mapping representing the calls to update. /// -/// Returns a map of (entry point, callee function) -> new callee function id. +/// Returns a set of [CallToUpdate] containing all information needed to rewrite +/// a call site and a [NewCallSitesMap] fn build_calls_to_update( ssa: &mut Ssa, functions_to_clone_map: HashMap>, -) -> HashMap<(FunctionId, FunctionId), FunctionId> { + brillig_entry_points: &BTreeMap>, +) -> (HashSet, NewCallSitesMap) { + // Clone new functions + // Map of (entry point, callee function) -> new callee function id. + // This will be used internally for determining whether a call site needs to be rewritten. let mut calls_to_update: HashMap<(FunctionId, FunctionId), FunctionId> = HashMap::default(); - for (entry_point, functions_to_clone) in functions_to_clone_map { for old_id in functions_to_clone { let function = ssa.functions[&old_id].clone(); @@ -158,36 +220,89 @@ fn build_calls_to_update( } } - calls_to_update + // Maps a function to its new specialized function per entry point context + // (entry_point -> map(old_id, new_id)) + let mut new_functions_map: NewCallSitesMap = HashMap::default(); + // Collect extra information about the call sites we want to rewrite. + // We need to do this as the original calls to update were set up based upon + // the original call sites, not the soon-to-be rewritten call sites. + let mut new_calls_to_update = HashSet::default(); + for (entry_point, inner_calls) in brillig_entry_points { + let function = ssa.functions.get(entry_point).expect("ICE: Function does not exist"); + new_calls_to_update.extend(collect_callsites_to_rewrite( + function, + *entry_point, + &mut new_functions_map, + &calls_to_update, + )); + for inner_call in inner_calls { + let function = ssa.functions.get(inner_call).expect("ICE: Function does not exist"); + new_calls_to_update.extend(collect_callsites_to_rewrite( + function, + *entry_point, + &mut new_functions_map, + &calls_to_update, + )); + } + } + + (new_calls_to_update, new_functions_map) } -fn update_function_calls( - function: &mut Function, +/// Stores the information necessary to appropriately update +/// the call sites across the Brillig entry point graph +/// +/// This structure should be built by analyzing the unchanged SSA +/// and later used to perform updates. +#[derive(PartialEq, Eq, Hash)] +struct CallToUpdate { entry_point: FunctionId, - new_functions_map: &mut HashMap, - // Maps (entry point, callee function) -> new callee function id + function_to_update: FunctionId, + instruction: InstructionId, + new_func_to_call: FunctionId, + call_args: Vec, +} + +/// Go through the supplied function and based upon the call sites +/// set in the `calls_to_update` map build the set of call sites +/// that should be rewritten. +/// Upon finding call sites that should be rewritten this method will also +/// update the mapping of old functions to new functions in the supplied [NewCallSitesMap]. +fn collect_callsites_to_rewrite( + function: &Function, + entry_point: FunctionId, + // Maps (entry_point -> map(old_id, new_id)) + function_per_entry: &mut NewCallSitesMap, + // Maps (entry_point, callee function) -> new callee function id calls_to_update: &HashMap<(FunctionId, FunctionId), FunctionId>, -) { +) -> HashSet { + let mut new_calls_to_update = HashSet::default(); for block_id in function.reachable_blocks() { #[allow(clippy::unnecessary_to_owned)] // clippy is wrong here for instruction_id in function.dfg[block_id].instructions().to_vec() { let instruction = function.dfg[instruction_id].clone(); - let Instruction::Call { func: func_id, arguments } = instruction else { + let Instruction::Call { func: func_value_id, arguments } = instruction else { continue; }; - let func_value = &function.dfg[func_id]; + let func_value = &function.dfg[func_value_id]; let Value::Function(func_id) = func_value else { continue }; let Some(new_id) = calls_to_update.get(&(entry_point, *func_id)) else { continue; }; - new_functions_map.insert(*func_id, *new_id); - let new_function_value_id = function.dfg.import_function(*new_id); - function.dfg[instruction_id] = - Instruction::Call { func: new_function_value_id, arguments }; + function_per_entry.entry(entry_point).or_default().insert(*func_id, *new_id); + let new_call = CallToUpdate { + entry_point, + function_to_update: function.id(), + instruction: instruction_id, + new_func_to_call: *new_id, + call_args: arguments, + }; + new_calls_to_update.insert(new_call); } } + new_calls_to_update } /// Returns a map of Brillig entry points to all functions called in that entry point. @@ -605,4 +720,222 @@ mod tests { } "); } + + #[test] + fn duplicate_recursive_shared_entry_points() { + // Check that we appropriately specialize functions when the entry point + // is recursive. + // f1 and f2 in the SSA below are recursive with themselves and another entry point. + let src = " + acir(inline) impure fn main f0 { + b0(): + v3 = call f1(u1 1, u32 5) -> u1 + constrain v3 == u1 0 + v6 = call f2(u1 1, u32 5) -> u1 + constrain v6 == u1 0 + return + } + brillig(inline) impure fn func_1 f1 { + b0(v0: u1, v1: u32): + v4 = eq v1, u32 0 + jmpif v4 then: b1, else: b2 + b1(): + jmp b3(u1 0) + b2(): + v6 = sub v1, u32 1 + v8 = call f2(v0, v6) -> u1 + v10 = call f1(v8, v6) -> u1 + jmp b3(v10) + b3(v2: u1): + return v2 + } + brillig(inline) impure fn func_2 f2 { + b0(v0: u1, v1: u32): + v4 = eq v1, u32 0 + jmpif v4 then: b1, else: b2 + b1(): + jmp b3(u1 0) + b2(): + v6 = sub v1, u32 1 + v8 = call f2(v0, v6) -> u1 + v10 = call f1(v8, v6) -> u1 + jmp b3(v10) + b3(v2: u1): + return v2 + } + "; + let ssa = Ssa::from_str(src).unwrap(); + let ssa = ssa.brillig_entry_point_analysis(); + + // We want no shared callees between entry points. + // Each Brillig entry point (f1 and f2 called from f0) should have its own + // specialized function call graph. + assert_ssa_snapshot!(ssa, @r#" + acir(inline) impure fn main f0 { + b0(): + v3 = call f1(u1 1, u32 5) -> u1 + constrain v3 == u1 0 + v6 = call f2(u1 1, u32 5) -> u1 + constrain v6 == u1 0 + return + } + brillig(inline) impure fn func_1 f1 { + b0(v0: u1, v1: u32): + v4 = eq v1, u32 0 + jmpif v4 then: b1, else: b2 + b1(): + jmp b3(u1 0) + b2(): + v6 = sub v1, u32 1 + v8 = call f4(v0, v6) -> u1 + v10 = call f3(v8, v6) -> u1 + jmp b3(v10) + b3(v2: u1): + return v2 + } + brillig(inline) impure fn func_2 f2 { + b0(v0: u1, v1: u32): + v4 = eq v1, u32 0 + jmpif v4 then: b1, else: b2 + b1(): + jmp b3(u1 0) + b2(): + v6 = sub v1, u32 1 + v8 = call f6(v0, v6) -> u1 + v10 = call f5(v8, v6) -> u1 + jmp b3(v10) + b3(v2: u1): + return v2 + } + brillig(inline) fn func_1 f3 { + b0(v0: u1, v1: u32): + v4 = eq v1, u32 0 + jmpif v4 then: b1, else: b2 + b1(): + jmp b3(u1 0) + b2(): + v6 = sub v1, u32 1 + v8 = call f4(v0, v6) -> u1 + v10 = call f3(v8, v6) -> u1 + jmp b3(v10) + b3(v2: u1): + return v2 + } + brillig(inline) fn func_2 f4 { + b0(v0: u1, v1: u32): + v4 = eq v1, u32 0 + jmpif v4 then: b1, else: b2 + b1(): + jmp b3(u1 0) + b2(): + v6 = sub v1, u32 1 + v8 = call f4(v0, v6) -> u1 + v10 = call f3(v8, v6) -> u1 + jmp b3(v10) + b3(v2: u1): + return v2 + } + brillig(inline) fn func_1 f5 { + b0(v0: u1, v1: u32): + v4 = eq v1, u32 0 + jmpif v4 then: b1, else: b2 + b1(): + jmp b3(u1 0) + b2(): + v6 = sub v1, u32 1 + v8 = call f6(v0, v6) -> u1 + v10 = call f5(v8, v6) -> u1 + jmp b3(v10) + b3(v2: u1): + return v2 + } + brillig(inline) fn func_2 f6 { + b0(v0: u1, v1: u32): + v4 = eq v1, u32 0 + jmpif v4 then: b1, else: b2 + b1(): + jmp b3(u1 0) + b2(): + v6 = sub v1, u32 1 + v8 = call f6(v0, v6) -> u1 + v10 = call f5(v8, v6) -> u1 + jmp b3(v10) + b3(v2: u1): + return v2 + } + "#); + } + + #[test] + fn duplicate_recursive_shared_entry_points_indirect_recursion() { + // This test is essentially identical to `duplicate_recursive_shared_entry_points` + // except that the one recursive entry point does not recurse on itself directly. + // f1 is recursive, but only through calling itself in f2. + let src = " + acir(inline) impure fn main f0 { + b0(): + call f1(Field 1) + call f2(Field 1) + return + } + brillig(inline) impure fn foo f1 { + b0(v0: Field): + call f2(v0) + return + } + brillig(inline) impure fn bar f2 { + b0(v0: Field): + call f1(Field 1) + call f2(Field 1) + return + } + "; + let ssa = Ssa::from_str(src).unwrap(); + let ssa = ssa.brillig_entry_point_analysis(); + + // We want no shared callees between entry points. + // Each Brillig entry point (f1 and f2 called from f0) should have its own + // specialized function call graph. + assert_ssa_snapshot!(ssa, @r#" + acir(inline) impure fn main f0 { + b0(): + call f1(Field 1) + call f2(Field 1) + return + } + brillig(inline) impure fn foo f1 { + b0(v0: Field): + call f4(v0) + return + } + brillig(inline) impure fn bar f2 { + b0(v0: Field): + call f5(Field 1) + call f6(Field 1) + return + } + brillig(inline) fn foo f3 { + b0(v0: Field): + call f4(v0) + return + } + brillig(inline) fn bar f4 { + b0(v0: Field): + call f3(Field 1) + call f4(Field 1) + return + } + brillig(inline) fn foo f5 { + b0(v0: Field): + call f6(v0) + return + } + brillig(inline) fn bar f6 { + b0(v0: Field): + call f5(Field 1) + call f6(Field 1) + return + } + "#); + } } diff --git a/test_programs/execution_failure/brillig_entry_points_shared_recursive/Nargo.toml b/test_programs/execution_failure/brillig_entry_points_shared_recursive/Nargo.toml new file mode 100644 index 00000000000..dd26317ca01 --- /dev/null +++ b/test_programs/execution_failure/brillig_entry_points_shared_recursive/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "brillig_entry_points_shared_recursive" +type = "bin" +authors = [""] + +[dependencies] \ No newline at end of file diff --git a/test_programs/execution_failure/brillig_entry_points_shared_recursive/src/main.nr b/test_programs/execution_failure/brillig_entry_points_shared_recursive/src/main.nr new file mode 100644 index 00000000000..dca0b619333 --- /dev/null +++ b/test_programs/execution_failure/brillig_entry_points_shared_recursive/src/main.nr @@ -0,0 +1,21 @@ +fn main() { + baz(); +} + +unconstrained fn foo(f: fn[Env]()) { + println("foo"); + bar(f); +} + +unconstrained fn bar(f: fn[Env]()) { +println("bar"); + f(); +} + +fn baz() { + // Safety: testing context + unsafe { + foo(baz); + bar(baz); + } +} \ No newline at end of file diff --git a/test_programs/execution_success/brillig_entry_points_regression_8069/Nargo.toml b/test_programs/execution_success/brillig_entry_points_regression_8069/Nargo.toml new file mode 100644 index 00000000000..62eb5600de0 --- /dev/null +++ b/test_programs/execution_success/brillig_entry_points_regression_8069/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "brillig_entry_points_regression_8069" +type = "bin" +authors = [""] + +[dependencies] \ No newline at end of file diff --git a/test_programs/execution_success/brillig_entry_points_regression_8069/Prover.toml b/test_programs/execution_success/brillig_entry_points_regression_8069/Prover.toml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test_programs/execution_success/brillig_entry_points_regression_8069/src/main.nr b/test_programs/execution_success/brillig_entry_points_regression_8069/src/main.nr new file mode 100644 index 00000000000..e76f3903c44 --- /dev/null +++ b/test_programs/execution_success/brillig_entry_points_regression_8069/src/main.nr @@ -0,0 +1,28 @@ +fn main() -> pub bool { + let ctx_depth = 5; + // Safety: testing context + let cond = unsafe { func_1(true, 1, ctx_depth) }; + let _ = if !cond { + // Safety: testing context + unsafe { func_2(1, true, ctx_depth) }[0] + } else { + 0 + }; + false +} +unconstrained fn func_1(a: bool, b: i8, mut ctx_depth: u32) -> bool { + if (ctx_depth == 0) { + false + } else { + ctx_depth = (ctx_depth - 1); + func_1(false, func_2((a as Field), false, ctx_depth)[3], ctx_depth) + } +} +unconstrained fn func_2(mut a: Field, mut b: bool, mut ctx_depth: u32) -> [i8; 4] { + if (ctx_depth == 0) { + [6, 101, 92, 30] + } else { + ctx_depth = (ctx_depth - 1); + func_2(a, func_1(b, 0, ctx_depth), ctx_depth) + } +} diff --git a/test_programs/execution_success/brillig_entry_points_regression_8069/stdout.txt b/test_programs/execution_success/brillig_entry_points_regression_8069/stdout.txt new file mode 100644 index 00000000000..a43c141e9a1 --- /dev/null +++ b/test_programs/execution_success/brillig_entry_points_regression_8069/stdout.txt @@ -0,0 +1 @@ +[brillig_entry_points_regression_8069] Circuit output: Field(0) \ No newline at end of file diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/brillig_entry_points_regression_8069/execute__tests__force_brillig_false_inliner_-9223372036854775808.snap b/tooling/nargo_cli/tests/snapshots/execution_success/brillig_entry_points_regression_8069/execute__tests__force_brillig_false_inliner_-9223372036854775808.snap new file mode 100644 index 00000000000..e01b27a09b5 --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/brillig_entry_points_regression_8069/execute__tests__force_brillig_false_inliner_-9223372036854775808.snap @@ -0,0 +1,25 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: artifact +--- +{ + "noir_version": "[noir_version]", + "hash": "[hash]", + "abi": { + "parameters": [], + "return_type": { + "abi_type": { + "kind": "boolean" + }, + "visibility": "public" + }, + "error_types": {} + }, + "bytecode": "H4sIAAAAAAAA/63OsQkAQAgDwAR+IH+D33+qR1As1EqvCaQIIQKRefcsZeYubol+O6gRvQ9x7LRQ9AAAAA==", + "debug_symbols": "XYxLCoAwDAXvkrUn8Coi0k9aAqEpsRWk9O5+cCFdzhveNPBoa9woBdlhXhqwOFNI0k2tT2CVmCluw3wYJWMZPww1uZ8tZ8bhn1Uc+qr4lF7X134B", + "file_map": {}, + "names": [ + "main" + ], + "brillig_names": [] +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/brillig_entry_points_regression_8069/execute__tests__force_brillig_false_inliner_0.snap b/tooling/nargo_cli/tests/snapshots/execution_success/brillig_entry_points_regression_8069/execute__tests__force_brillig_false_inliner_0.snap new file mode 100644 index 00000000000..e01b27a09b5 --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/brillig_entry_points_regression_8069/execute__tests__force_brillig_false_inliner_0.snap @@ -0,0 +1,25 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: artifact +--- +{ + "noir_version": "[noir_version]", + "hash": "[hash]", + "abi": { + "parameters": [], + "return_type": { + "abi_type": { + "kind": "boolean" + }, + "visibility": "public" + }, + "error_types": {} + }, + "bytecode": "H4sIAAAAAAAA/63OsQkAQAgDwAR+IH+D33+qR1As1EqvCaQIIQKRefcsZeYubol+O6gRvQ9x7LRQ9AAAAA==", + "debug_symbols": "XYxLCoAwDAXvkrUn8Coi0k9aAqEpsRWk9O5+cCFdzhveNPBoa9woBdlhXhqwOFNI0k2tT2CVmCluw3wYJWMZPww1uZ8tZ8bhn1Uc+qr4lF7X134B", + "file_map": {}, + "names": [ + "main" + ], + "brillig_names": [] +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/brillig_entry_points_regression_8069/execute__tests__force_brillig_false_inliner_9223372036854775807.snap b/tooling/nargo_cli/tests/snapshots/execution_success/brillig_entry_points_regression_8069/execute__tests__force_brillig_false_inliner_9223372036854775807.snap new file mode 100644 index 00000000000..e01b27a09b5 --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/brillig_entry_points_regression_8069/execute__tests__force_brillig_false_inliner_9223372036854775807.snap @@ -0,0 +1,25 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: artifact +--- +{ + "noir_version": "[noir_version]", + "hash": "[hash]", + "abi": { + "parameters": [], + "return_type": { + "abi_type": { + "kind": "boolean" + }, + "visibility": "public" + }, + "error_types": {} + }, + "bytecode": "H4sIAAAAAAAA/63OsQkAQAgDwAR+IH+D33+qR1As1EqvCaQIIQKRefcsZeYubol+O6gRvQ9x7LRQ9AAAAA==", + "debug_symbols": "XYxLCoAwDAXvkrUn8Coi0k9aAqEpsRWk9O5+cCFdzhveNPBoa9woBdlhXhqwOFNI0k2tT2CVmCluw3wYJWMZPww1uZ8tZ8bhn1Uc+qr4lF7X134B", + "file_map": {}, + "names": [ + "main" + ], + "brillig_names": [] +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/brillig_entry_points_regression_8069/execute__tests__force_brillig_true_inliner_-9223372036854775808.snap b/tooling/nargo_cli/tests/snapshots/execution_success/brillig_entry_points_regression_8069/execute__tests__force_brillig_true_inliner_-9223372036854775808.snap new file mode 100644 index 00000000000..d29f346cfed --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/brillig_entry_points_regression_8069/execute__tests__force_brillig_true_inliner_-9223372036854775808.snap @@ -0,0 +1,41 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: artifact +--- +{ + "noir_version": "[noir_version]", + "hash": "[hash]", + "abi": { + "parameters": [], + "return_type": { + "abi_type": { + "kind": "boolean" + }, + "visibility": "public" + }, + "error_types": { + "2920182694213909827": { + "error_kind": "string", + "string": "attempt to subtract with overflow" + }, + "17843811134343075018": { + "error_kind": "string", + "string": "Stack too deep" + } + } + }, + "bytecode": "H4sIAAAAAAAA/9VYXY6bQAz2hEBh22j7c4GeoBqSEKjUB6Sy7RWqqg+loTlDH3lfVeqRy6h2Y8zMLhEzq91PQgPY+eyxZ+whCs5QOK5hDAUzoO549wfHDMcVk0fDVeOzXoY8E3Z98ld6X2WW+Xn0f5chpwrDr4k/UPz1M+T53J/5+VzIbjpcL9j9K7zf3PH7kL4PuS0zxumbf0D+xuE/zc3gYz+etyfbmvgbxg8B+G/6ILH7z/8pDH/+HP6twy2415rHeOW2taYC8K8hSLwK4k/C8Jcb5KR6wkGylNleCVkm/OKyKybj8ZGIxDOfr7FdMV6pJ32NmYz8joXsHY7Gxlu8l+vEoMZRL0P+2HIo88RzKPPrK4ffGK/Uk77acqhgmp9I6BtQ3boGdw/YADj7pfFZO/QMqG/cp9egnql3FN91P/alxvd6AcpKa7IbIX8M03xw+7HQL/GZ55rG9QI/T2Wbn3btqS3artsf29eC34DiLvsCxZN8XcM533xuN2xOXP8LjiZPHwSnXBOSk/c+zpkwPdkfbT7UOJp5/cZ7aU+umwyme8BjrTjQWk1gCllHbHsmZfpNP5bZ6sjcWkHzvbRW8LVKfgc+X+7JbiLmJP0h+9cwzWnyML5elG+Dph/LeP2Nxe+W5JveXdrfbfkmGe9PpGfm/dWhZ9D0bj1ZBw1816lfzM/vDs65dSphXHPqFOl3OPI69VTOnQbUk21nFh5DCZ/nTr5/ye/HFkMlZHPP7ktieEkt5zUkFTK+t/lZ7Rbvbf/nmKvGZ70MB9t3qj/+QxH2O7U42s4V/vjzn7Y+o0Ru5LnCj21dKGEPRBxB2L+CoPsyVzDdlxFM4yNrWmrx9SW497ESMm4ntdixca08ckUeueRZg+9/3uduhZ6rZ/v+ttlW1eH99sfwb2Z3PHX73X3fNn8Br6P9SP0XAAA=", + "debug_symbols": "ldjfiuIwFMfxd+m1Fzk5+eurLMtQtQ6FUqXqwiK++9ahHSSGHb43YsQPafs7aZtzbw7d7vb50Y/H06XZ/ro3w2nfXvvTOI/uj02zm/ph6D8/Xn9uzPND0tf/L+d2fA4v13a6NlsxdtN042H+ZtPsj/3QNVtvHr83jWQqrMFCsLBYKBYOC49FwCJigTO3OHOt5mFNXIRVLYVi4bDwWAQsIhYJi0yFM1gIFvU1mNO3KKvEKRW+enXV50VoLI8qVM/cWb8I9zZHECwsFopFtdpdlFUkKUW12l3QRXjzJgIWEYuERaYiGiwEC4uFYuF+Eq4UHouART1zt65BL6EUCYtMRTJYCBYWC8XCYeGpyNWjCrLe24OWlZirVRKyW0Q0sRQRi4RFpkJMtUyiXR850csbEU4sJ8qJ48RzEjiJnCROqulH+SahfBcQMZwIJ5YT5cRx4jkJnERM6lvE4MN6Q/Jv29D6HvH/xHKinDhOPCeBk8hJ4iRjojx95ekrT195+srTV56+wvQf8+hPO/XtbuiWntDxNu5fWkTXv+eu6Badp9O+O9ym7tk3emkZPdPyZuP912KfB+JkI07nWeaZ/gE=", + "file_map": { + "50": { + "source": "fn main() -> pub bool {\n let ctx_depth = 5;\n // Safety: testing context\n let cond = unsafe { func_1(true, 1, ctx_depth) };\n let _ = if !cond {\n // Safety: testing context\n unsafe { func_2(1, true, ctx_depth) }[0]\n } else {\n 0\n };\n false\n}\nunconstrained fn func_1(a: bool, b: i8, mut ctx_depth: u32) -> bool {\n if (ctx_depth == 0) {\n false\n } else {\n ctx_depth = (ctx_depth - 1);\n func_1(false, func_2((a as Field), false, ctx_depth)[3], ctx_depth)\n }\n}\nunconstrained fn func_2(mut a: Field, mut b: bool, mut ctx_depth: u32) -> [i8; 4] {\n if (ctx_depth == 0) {\n [6, 101, 92, 30]\n } else {\n ctx_depth = (ctx_depth - 1);\n func_2(a, func_1(b, 0, ctx_depth), ctx_depth)\n }\n}\n", + "path": "" + } + }, + "names": [ + "main" + ], + "brillig_names": [ + "main" + ] +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/brillig_entry_points_regression_8069/execute__tests__force_brillig_true_inliner_0.snap b/tooling/nargo_cli/tests/snapshots/execution_success/brillig_entry_points_regression_8069/execute__tests__force_brillig_true_inliner_0.snap new file mode 100644 index 00000000000..d29f346cfed --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/brillig_entry_points_regression_8069/execute__tests__force_brillig_true_inliner_0.snap @@ -0,0 +1,41 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: artifact +--- +{ + "noir_version": "[noir_version]", + "hash": "[hash]", + "abi": { + "parameters": [], + "return_type": { + "abi_type": { + "kind": "boolean" + }, + "visibility": "public" + }, + "error_types": { + "2920182694213909827": { + "error_kind": "string", + "string": "attempt to subtract with overflow" + }, + "17843811134343075018": { + "error_kind": "string", + "string": "Stack too deep" + } + } + }, + "bytecode": "H4sIAAAAAAAA/9VYXY6bQAz2hEBh22j7c4GeoBqSEKjUB6Sy7RWqqg+loTlDH3lfVeqRy6h2Y8zMLhEzq91PQgPY+eyxZ+whCs5QOK5hDAUzoO549wfHDMcVk0fDVeOzXoY8E3Z98ld6X2WW+Xn0f5chpwrDr4k/UPz1M+T53J/5+VzIbjpcL9j9K7zf3PH7kL4PuS0zxumbf0D+xuE/zc3gYz+etyfbmvgbxg8B+G/6ILH7z/8pDH/+HP6twy2415rHeOW2taYC8K8hSLwK4k/C8Jcb5KR6wkGylNleCVkm/OKyKybj8ZGIxDOfr7FdMV6pJ32NmYz8joXsHY7Gxlu8l+vEoMZRL0P+2HIo88RzKPPrK4ffGK/Uk77acqhgmp9I6BtQ3boGdw/YADj7pfFZO/QMqG/cp9egnql3FN91P/alxvd6AcpKa7IbIX8M03xw+7HQL/GZ55rG9QI/T2Wbn3btqS3artsf29eC34DiLvsCxZN8XcM533xuN2xOXP8LjiZPHwSnXBOSk/c+zpkwPdkfbT7UOJp5/cZ7aU+umwyme8BjrTjQWk1gCllHbHsmZfpNP5bZ6sjcWkHzvbRW8LVKfgc+X+7JbiLmJP0h+9cwzWnyML5elG+Dph/LeP2Nxe+W5JveXdrfbfkmGe9PpGfm/dWhZ9D0bj1ZBw1816lfzM/vDs65dSphXHPqFOl3OPI69VTOnQbUk21nFh5DCZ/nTr5/ye/HFkMlZHPP7ktieEkt5zUkFTK+t/lZ7Rbvbf/nmKvGZ70MB9t3qj/+QxH2O7U42s4V/vjzn7Y+o0Ru5LnCj21dKGEPRBxB2L+CoPsyVzDdlxFM4yNrWmrx9SW497ESMm4ntdixca08ckUeueRZg+9/3uduhZ6rZ/v+ttlW1eH99sfwb2Z3PHX73X3fNn8Br6P9SP0XAAA=", + "debug_symbols": "ldjfiuIwFMfxd+m1Fzk5+eurLMtQtQ6FUqXqwiK++9ahHSSGHb43YsQPafs7aZtzbw7d7vb50Y/H06XZ/ro3w2nfXvvTOI/uj02zm/ph6D8/Xn9uzPND0tf/L+d2fA4v13a6NlsxdtN042H+ZtPsj/3QNVtvHr83jWQqrMFCsLBYKBYOC49FwCJigTO3OHOt5mFNXIRVLYVi4bDwWAQsIhYJi0yFM1gIFvU1mNO3KKvEKRW+enXV50VoLI8qVM/cWb8I9zZHECwsFopFtdpdlFUkKUW12l3QRXjzJgIWEYuERaYiGiwEC4uFYuF+Eq4UHouART1zt65BL6EUCYtMRTJYCBYWC8XCYeGpyNWjCrLe24OWlZirVRKyW0Q0sRQRi4RFpkJMtUyiXR850csbEU4sJ8qJ48RzEjiJnCROqulH+SahfBcQMZwIJ5YT5cRx4jkJnERM6lvE4MN6Q/Jv29D6HvH/xHKinDhOPCeBk8hJ4iRjojx95ekrT195+srTV56+wvQf8+hPO/XtbuiWntDxNu5fWkTXv+eu6Badp9O+O9ym7tk3emkZPdPyZuP912KfB+JkI07nWeaZ/gE=", + "file_map": { + "50": { + "source": "fn main() -> pub bool {\n let ctx_depth = 5;\n // Safety: testing context\n let cond = unsafe { func_1(true, 1, ctx_depth) };\n let _ = if !cond {\n // Safety: testing context\n unsafe { func_2(1, true, ctx_depth) }[0]\n } else {\n 0\n };\n false\n}\nunconstrained fn func_1(a: bool, b: i8, mut ctx_depth: u32) -> bool {\n if (ctx_depth == 0) {\n false\n } else {\n ctx_depth = (ctx_depth - 1);\n func_1(false, func_2((a as Field), false, ctx_depth)[3], ctx_depth)\n }\n}\nunconstrained fn func_2(mut a: Field, mut b: bool, mut ctx_depth: u32) -> [i8; 4] {\n if (ctx_depth == 0) {\n [6, 101, 92, 30]\n } else {\n ctx_depth = (ctx_depth - 1);\n func_2(a, func_1(b, 0, ctx_depth), ctx_depth)\n }\n}\n", + "path": "" + } + }, + "names": [ + "main" + ], + "brillig_names": [ + "main" + ] +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/brillig_entry_points_regression_8069/execute__tests__force_brillig_true_inliner_9223372036854775807.snap b/tooling/nargo_cli/tests/snapshots/execution_success/brillig_entry_points_regression_8069/execute__tests__force_brillig_true_inliner_9223372036854775807.snap new file mode 100644 index 00000000000..d29f346cfed --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/brillig_entry_points_regression_8069/execute__tests__force_brillig_true_inliner_9223372036854775807.snap @@ -0,0 +1,41 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: artifact +--- +{ + "noir_version": "[noir_version]", + "hash": "[hash]", + "abi": { + "parameters": [], + "return_type": { + "abi_type": { + "kind": "boolean" + }, + "visibility": "public" + }, + "error_types": { + "2920182694213909827": { + "error_kind": "string", + "string": "attempt to subtract with overflow" + }, + "17843811134343075018": { + "error_kind": "string", + "string": "Stack too deep" + } + } + }, + "bytecode": "H4sIAAAAAAAA/9VYXY6bQAz2hEBh22j7c4GeoBqSEKjUB6Sy7RWqqg+loTlDH3lfVeqRy6h2Y8zMLhEzq91PQgPY+eyxZ+whCs5QOK5hDAUzoO549wfHDMcVk0fDVeOzXoY8E3Z98ld6X2WW+Xn0f5chpwrDr4k/UPz1M+T53J/5+VzIbjpcL9j9K7zf3PH7kL4PuS0zxumbf0D+xuE/zc3gYz+etyfbmvgbxg8B+G/6ILH7z/8pDH/+HP6twy2415rHeOW2taYC8K8hSLwK4k/C8Jcb5KR6wkGylNleCVkm/OKyKybj8ZGIxDOfr7FdMV6pJ32NmYz8joXsHY7Gxlu8l+vEoMZRL0P+2HIo88RzKPPrK4ffGK/Uk77acqhgmp9I6BtQ3boGdw/YADj7pfFZO/QMqG/cp9egnql3FN91P/alxvd6AcpKa7IbIX8M03xw+7HQL/GZ55rG9QI/T2Wbn3btqS3artsf29eC34DiLvsCxZN8XcM533xuN2xOXP8LjiZPHwSnXBOSk/c+zpkwPdkfbT7UOJp5/cZ7aU+umwyme8BjrTjQWk1gCllHbHsmZfpNP5bZ6sjcWkHzvbRW8LVKfgc+X+7JbiLmJP0h+9cwzWnyML5elG+Dph/LeP2Nxe+W5JveXdrfbfkmGe9PpGfm/dWhZ9D0bj1ZBw1816lfzM/vDs65dSphXHPqFOl3OPI69VTOnQbUk21nFh5DCZ/nTr5/ye/HFkMlZHPP7ktieEkt5zUkFTK+t/lZ7Rbvbf/nmKvGZ70MB9t3qj/+QxH2O7U42s4V/vjzn7Y+o0Ru5LnCj21dKGEPRBxB2L+CoPsyVzDdlxFM4yNrWmrx9SW497ESMm4ntdixca08ckUeueRZg+9/3uduhZ6rZ/v+ttlW1eH99sfwb2Z3PHX73X3fNn8Br6P9SP0XAAA=", + "debug_symbols": "ldjfiuIwFMfxd+m1Fzk5+eurLMtQtQ6FUqXqwiK++9ahHSSGHb43YsQPafs7aZtzbw7d7vb50Y/H06XZ/ro3w2nfXvvTOI/uj02zm/ph6D8/Xn9uzPND0tf/L+d2fA4v13a6NlsxdtN042H+ZtPsj/3QNVtvHr83jWQqrMFCsLBYKBYOC49FwCJigTO3OHOt5mFNXIRVLYVi4bDwWAQsIhYJi0yFM1gIFvU1mNO3KKvEKRW+enXV50VoLI8qVM/cWb8I9zZHECwsFopFtdpdlFUkKUW12l3QRXjzJgIWEYuERaYiGiwEC4uFYuF+Eq4UHouART1zt65BL6EUCYtMRTJYCBYWC8XCYeGpyNWjCrLe24OWlZirVRKyW0Q0sRQRi4RFpkJMtUyiXR850csbEU4sJ8qJ48RzEjiJnCROqulH+SahfBcQMZwIJ5YT5cRx4jkJnERM6lvE4MN6Q/Jv29D6HvH/xHKinDhOPCeBk8hJ4iRjojx95ekrT195+srTV56+wvQf8+hPO/XtbuiWntDxNu5fWkTXv+eu6Badp9O+O9ym7tk3emkZPdPyZuP912KfB+JkI07nWeaZ/gE=", + "file_map": { + "50": { + "source": "fn main() -> pub bool {\n let ctx_depth = 5;\n // Safety: testing context\n let cond = unsafe { func_1(true, 1, ctx_depth) };\n let _ = if !cond {\n // Safety: testing context\n unsafe { func_2(1, true, ctx_depth) }[0]\n } else {\n 0\n };\n false\n}\nunconstrained fn func_1(a: bool, b: i8, mut ctx_depth: u32) -> bool {\n if (ctx_depth == 0) {\n false\n } else {\n ctx_depth = (ctx_depth - 1);\n func_1(false, func_2((a as Field), false, ctx_depth)[3], ctx_depth)\n }\n}\nunconstrained fn func_2(mut a: Field, mut b: bool, mut ctx_depth: u32) -> [i8; 4] {\n if (ctx_depth == 0) {\n [6, 101, 92, 30]\n } else {\n ctx_depth = (ctx_depth - 1);\n func_2(a, func_1(b, 0, ctx_depth), ctx_depth)\n }\n}\n", + "path": "" + } + }, + "names": [ + "main" + ], + "brillig_names": [ + "main" + ] +}