diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/brillig_acir_as_brillig/Nargo.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/brillig_acir_as_brillig/Nargo.toml new file mode 100644 index 00000000000..e0b467ce5da --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/brillig_acir_as_brillig/Nargo.toml @@ -0,0 +1,5 @@ +[package] +authors = [""] +compiler_version = "0.1" + +[dependencies] \ No newline at end of file diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/brillig_acir_as_brillig/Prover.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/brillig_acir_as_brillig/Prover.toml new file mode 100644 index 00000000000..11497a473bc --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/brillig_acir_as_brillig/Prover.toml @@ -0,0 +1 @@ +x = "0" diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/brillig_acir_as_brillig/src/main.nr b/crates/nargo_cli/tests/test_data_ssa_refactor/brillig_acir_as_brillig/src/main.nr new file mode 100644 index 00000000000..9d4c5da9dc4 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/brillig_acir_as_brillig/src/main.nr @@ -0,0 +1,43 @@ + +fn main(x: u32) { + assert(entry_point(x) == 2); + swap_entry_point(x, x + 1); + assert(deep_entry_point(x) == 4); +} + +fn inner(x : u32) -> u32 { + x + 1 +} + +unconstrained fn entry_point(x : u32) -> u32 { + inner(x + 1) +} + +fn swap(x: u32, y:u32) -> (u32, u32) { + (y, x) +} + +unconstrained fn swap_entry_point(x: u32, y: u32) { + let swapped = swap(x, y); + assert(swapped.0 == y); + assert(swapped.1 == x); + let swapped_twice = swap(swapped.0, swapped.1); + assert(swapped_twice.0 == x); + assert(swapped_twice.1 == y); +} + +fn level_3(x : u32) -> u32 { + x + 1 +} + +fn level_2(x : u32) -> u32 { + level_3(x + 1) +} + +fn level_1(x : u32) -> u32 { + level_2(x + 1) +} + +unconstrained fn deep_entry_point(x : u32) -> u32 { + level_1(x + 1) +} diff --git a/crates/noirc_evaluator/src/brillig/brillig_gen.rs b/crates/noirc_evaluator/src/brillig/brillig_gen.rs index 2cc0c03544e..32c98cb86ff 100644 --- a/crates/noirc_evaluator/src/brillig/brillig_gen.rs +++ b/crates/noirc_evaluator/src/brillig/brillig_gen.rs @@ -12,10 +12,6 @@ use self::{brillig_block::BrilligBlock, brillig_fn::FunctionContext}; use super::brillig_ir::{artifact::BrilligArtifact, BrilligContext}; /// Converting an SSA function into Brillig bytecode. -/// -/// TODO: Change this to use `dfg.basic_blocks_iter` which will return an -/// TODO iterator of all of the basic blocks. -/// TODO(Jake): what order is this ^ pub(crate) fn convert_ssa_function(func: &Function) -> BrilligArtifact { let mut reverse_post_order = Vec::new(); reverse_post_order.extend_from_slice(PostOrder::with_function(func).as_slice()); diff --git a/crates/noirc_evaluator/src/brillig/mod.rs b/crates/noirc_evaluator/src/brillig/mod.rs index 4ff657435db..c5ae0a514ed 100644 --- a/crates/noirc_evaluator/src/brillig/mod.rs +++ b/crates/noirc_evaluator/src/brillig/mod.rs @@ -6,10 +6,13 @@ use self::{ brillig_ir::artifact::{BrilligArtifact, Label}, }; use crate::ssa_refactor::{ - ir::function::{Function, FunctionId, RuntimeType}, + ir::{ + function::{Function, FunctionId, RuntimeType}, + value::Value, + }, ssa_gen::Ssa, }; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; /// Context structure for the brillig pass. /// It stores brillig-related data required for brillig generation. @@ -46,15 +49,54 @@ impl std::ops::Index for Brillig { } impl Ssa { - /// Generate compilation artifacts for brillig functions + /// Compile to brillig brillig functions and ACIR functions reachable from them pub(crate) fn to_brillig(&self) -> Brillig { - // Collect all of the brillig functions - let brillig_functions = - self.functions.values().filter(|func| func.runtime() == RuntimeType::Brillig); + // Collect all the function ids that are reachable from brillig + // That means all the functions marked as brillig and ACIR functions called by them + let mut brillig_reachable_function_ids: HashSet = HashSet::new(); + + // Initialize the queue with all the functions marked as brillig + let mut reachability_queue: Vec = self + .functions + .iter() + .filter_map( + |(id, func)| { + if func.runtime() == RuntimeType::Brillig { + Some(*id) + } else { + None + } + }, + ) + .collect(); + + while let Some(func_id) = reachability_queue.pop() { + let func = &self.functions[&func_id]; + brillig_reachable_function_ids.insert(func.id()); + + // Explore all functions that are reachable from this function + for (_, value) in func.dfg.values_iter() { + // All reachable functions appear as literals after defunctionalization of the SSA + let reachable_function = match value { + Value::Function(function_id) => function_id, + _ => continue, + }; + + // If the function is already reachable by brillig or enqueued, skip it. + if brillig_reachable_function_ids.contains(reachable_function) + || reachability_queue.contains(reachable_function) + { + continue; + } + + reachability_queue.push(*reachable_function); + } + } let mut brillig = Brillig::default(); - for brillig_function in brillig_functions { - brillig.compile(brillig_function); + for brillig_function_id in brillig_reachable_function_ids { + let func = &self.functions[&brillig_function_id]; + brillig.compile(func); } brillig diff --git a/crates/noirc_evaluator/src/ssa_refactor/acir_gen/mod.rs b/crates/noirc_evaluator/src/ssa_refactor/acir_gen/mod.rs index f743d975f91..3c365e68e71 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/acir_gen/mod.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/acir_gen/mod.rs @@ -357,7 +357,7 @@ impl Context { while let Some(unresolved_fn_label) = entry_point.first_unresolved_function_call() { let artifact = &brillig .find_by_function_label(unresolved_fn_label.clone()) - .expect("Cannot find linked fn {unresolved_fn_label}"); + .unwrap_or_else(|| panic!("Cannot find linked fn {unresolved_fn_label}")); entry_point.link_with(artifact); } // Generate the final bytecode