Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: compile to brillig reachable acir fns #1919

Merged
merged 5 commits into from
Jul 13, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[package]
authors = [""]
compiler_version = "0.1"

[dependencies]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
x = "0"
Original file line number Diff line number Diff line change
@@ -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)
}
4 changes: 0 additions & 4 deletions crates/noirc_evaluator/src/brillig/brillig_gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
kevaundray marked this conversation as resolved.
Show resolved Hide resolved
/// 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());
Expand Down
58 changes: 50 additions & 8 deletions crates/noirc_evaluator/src/brillig/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -46,15 +49,54 @@ impl std::ops::Index<FunctionId> 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 reachable_function_ids: HashSet<FunctionId> = HashSet::new();

// Initialize the queue with all the functions marked as brillig
let mut reachability_queue: Vec<FunctionId> = self
kevaundray marked this conversation as resolved.
Show resolved Hide resolved
.functions
.iter()
.filter_map(
|(id, func)| {
if func.runtime() == RuntimeType::Brillig {
Some(*id)
} else {
None
}
},
)
.collect();

while !reachability_queue.is_empty() {
sirasistant marked this conversation as resolved.
Show resolved Hide resolved
let func = &self.functions[&reachability_queue
.pop()
.expect("Queue should have already been checked for emptiness")];
reachable_function_ids.insert(func.id());
for (_, value) in func.dfg.values_iter() {
// All reachable functions appear as literals after defunctionalization of the SSA
let function_id = match value {
Value::Function(function_id) => function_id,
_ => continue,
};

// If the function is already reachable or enqueued, skip it.
if reachable_function_ids.contains(function_id)
|| reachability_queue.contains(function_id)
{
continue;
}

reachability_queue.push(*function_id);
}
}

let mut brillig = Brillig::default();
for brillig_function in brillig_functions {
brillig.compile(brillig_function);
for brillig_function_id in reachable_function_ids {
let func = &self.functions[&brillig_function_id];
brillig.compile(func);
}

brillig
Expand Down
2 changes: 1 addition & 1 deletion crates/noirc_evaluator/src/ssa_refactor/acir_gen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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}");
kevaundray marked this conversation as resolved.
Show resolved Hide resolved
.unwrap_or_else(|| panic!("Cannot find linked fn {unresolved_fn_label}"));
entry_point.link_with(artifact);
}
// Generate the final bytecode
Expand Down