Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
6 changes: 3 additions & 3 deletions compiler/noirc_evaluator/src/acir/tests/brillig_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ fn brillig_stdlib_calls_with_multiple_acir_calls() {
BLACKBOX::RANGE [(w7, 32)] []
BRILLIG CALL func 0: inputs: [EXPR [ (1, w0) 0 ], EXPR [ (1, w1) 0 ]], outputs: [w8]
BLACKBOX::RANGE [(w8, 32)] []
CALL func 2: PREDICATE: EXPR [ 1 ]
CALL func 1: PREDICATE: EXPR [ 1 ]
inputs: [w0, w1], outputs: [w9]
BRILLIG CALL func 1: inputs: [EXPR [ (1, w2) 0 ]], outputs: [w10]
EXPR [ (1, w2, w10) -1 ]
Expand All @@ -281,7 +281,7 @@ fn brillig_stdlib_calls_with_multiple_acir_calls() {
BLACKBOX::RANGE [(w13, 32)] []
EXPR [ (-1, w2, w11) (1, w1) (-1, w12) 0 ]
EXPR [ (1, w11) -1 ]

func 1
current witness: w5
private parameters: [w0, w1]
Expand All @@ -295,7 +295,7 @@ fn brillig_stdlib_calls_with_multiple_acir_calls() {
EXPR [ (1, w3, w5) 0 ]
EXPR [ (1, w5) 0 ]
EXPR [ (-1, w0) (1, w2) 0 ]

unconstrained func 0
[Const { destination: Direct(2), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(1), bit_size: Integer(U32), value: 32839 }, Const { destination: Direct(0), bit_size: Integer(U32), value: 3 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 2 }, Const { destination: Relative(4), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(32836), size_address: Relative(3), offset_address: Relative(4) }, Cast { destination: Direct(32836), source: Direct(32836), bit_size: Integer(U32) }, Cast { destination: Direct(32837), source: Direct(32837), bit_size: Integer(U32) }, Mov { destination: Relative(1), source: Direct(32836) }, Mov { destination: Relative(2), source: Direct(32837) }, Call { location: 16 }, Call { location: 17 }, Mov { destination: Direct(32838), source: Relative(1) }, Const { destination: Relative(2), bit_size: Integer(U32), value: 32838 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 1 }, Stop { return_data: HeapVector { pointer: Relative(2), size: Relative(3) } }, Return, Call { location: 25 }, BinaryIntOp { destination: Relative(3), op: Equals, bit_size: U32, lhs: Relative(1), rhs: Relative(2) }, Const { destination: Relative(2), bit_size: Integer(U1), value: 0 }, BinaryIntOp { destination: Relative(4), op: Equals, bit_size: U1, lhs: Relative(3), rhs: Relative(2) }, JumpIf { condition: Relative(4), location: 24 }, Const { destination: Relative(5), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(5) } }, 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: 30 }, IndirectConst { destination_pointer: Direct(1), bit_size: Integer(U64), value: 15764276373176857197 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Direct(2) } }, Return]
unconstrained func 1
Expand Down
10 changes: 8 additions & 2 deletions compiler/noirc_evaluator/src/ssa/ir/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,16 @@ impl RuntimeType {
/// We return `false` for InlineType::Inline on default, which is true
/// in all cases except for main. `main` should be supported with special
/// handling in any places where this function determines logic.
///
/// ## Important
/// If a Brillig function is not main it requires special handling to determine
/// whether it is an entry point. Brillig entry points can also be anywhere we start
/// Brillig execution from an ACIR runtime. This requires analyzing the call sites of the ACIR runtime.
pub(crate) fn is_entry_point(&self) -> bool {
match self {
RuntimeType::Acir(inline_type) => inline_type.is_entry_point(),
RuntimeType::Brillig(_) => true,
RuntimeType::Acir(inline_type) | RuntimeType::Brillig(inline_type) => {
inline_type.is_entry_point()
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,9 @@ impl Function {
let cfg = ControlFlowGraph::with_function(self);
let post_order = PostOrder::with_cfg(&cfg);

let is_acir_entry_point = self.runtime().is_acir() && self.runtime().is_entry_point();
let is_entry_point = self.runtime().is_entry_point();
let is_main = self.id() == main_id;
let can_prune_entry_block = !(is_acir_entry_point || is_main);
let can_prune_entry_block = !(is_entry_point || is_main);

let mut entry_block_keep_list = None;
for &block in post_order.as_slice() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,8 @@ fn remove_unreachable_functions_post_check(ssa: &Ssa) {
/// A sorted set of [`FunctionId`]s that are reachable from the entry points of the SSA.
fn reachable_functions(ssa: &Ssa) -> HashSet<FunctionId> {
// Identify entry points
let entry_points = ssa.functions.iter().filter_map(|(&id, func)| {
// Not using `Ssa::is_entry_point` because it could leave Brillig functions that nobody calls in the SSA,
// because it considers every Brillig function as an entry point.
let is_entry_point =
id == ssa.main_id || func.runtime().is_acir() && func.runtime().is_entry_point();
is_entry_point.then_some(id)
});
let entry_points =
ssa.functions.iter().filter_map(|(&id, _)| ssa.is_entry_point(id).then_some(id));

// Build call graph dependencies using this passes definition of reachability.
let dependencies = ssa.functions.iter().map(|(&id, func)| (id, used_functions(func))).collect();
Expand Down
35 changes: 35 additions & 0 deletions tooling/ssa_executor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,39 @@ mod tests {
_ => {}
}
}

#[test]
fn execute_brillig_stdlib_call_with_multiple_acir_calls() {
let src = "
acir(inline) fn main f0 {
b0(v0: u32, v1: u32, v2: u32):
v5 = div v0, v1
constrain v5 == v2
v6 = call f1(v0, v1) -> u32
v7 = call f1(v0, v1) -> u32
v8 = call f2(v0, v1) -> u32
v9 = div v1, v2
constrain v9 == u32 1
return
}
brillig(inline) fn foo f1 {
b0(v0: u32, v1: u32):
v2 = eq v0, v1
constrain v2 == u1 0
return v0
}
acir(fold) fn foo f2 {
b0(v0: u32, v1: u32):
v2 = eq v0, v1
constrain v2 == u1 0
return v0
}
";
let mut witness_map = WitnessMap::new();
witness_map.insert(Witness(0), FieldElement::from(9_u32));
witness_map.insert(Witness(1), FieldElement::from(3_u32));
witness_map.insert(Witness(2), FieldElement::from(3_u32));
let result = execute_ssa(src.to_string(), witness_map, CompileOptions::default());
assert!(result.is_ok());
}
}
Loading