Skip to content

Commit

Permalink
feat(ssa): Hoist MakeArray instructions during loop invariant code mo…
Browse files Browse the repository at this point in the history
…tion (#6782)

Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com>
  • Loading branch information
vezenovm and TomAFrench authored Dec 12, 2024
1 parent feec2a1 commit b88db67
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 5 deletions.
107 changes: 107 additions & 0 deletions compiler/noirc_evaluator/src/ssa/opt/loop_invariant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,22 @@ impl<'f> LoopInvariantContext<'f> {

if hoist_invariant {
self.inserter.push_instruction(instruction_id, pre_header);

// If we are hoisting a MakeArray instruction,
// we need to issue an extra inc_rc in case they are mutated afterward.
if matches!(
self.inserter.function.dfg[instruction_id],
Instruction::MakeArray { .. }
) {
let result =
self.inserter.function.dfg.instruction_results(instruction_id)[0];
let inc_rc = Instruction::IncrementRc { value: result };
let call_stack = self.inserter.function.dfg.get_call_stack(instruction_id);
self.inserter
.function
.dfg
.insert_instruction_and_results(inc_rc, *block, None, call_stack);
}
} else {
self.inserter.push_instruction(instruction_id, *block);
}
Expand Down Expand Up @@ -186,6 +202,7 @@ impl<'f> LoopInvariantContext<'f> {
});

let can_be_deduplicated = instruction.can_be_deduplicated(self.inserter.function, false)
|| matches!(instruction, Instruction::MakeArray { .. })
|| self.can_be_deduplicated_from_upper_bound(&instruction);

is_loop_invariant && can_be_deduplicated
Expand Down Expand Up @@ -555,4 +572,94 @@ mod test {
let ssa = ssa.loop_invariant_code_motion();
assert_normalized_ssa_equals(ssa, expected);
}

#[test]
fn insert_inc_rc_when_moving_make_array() {
// SSA for the following program:
//
// unconstrained fn main(x: u32, y: u32) {
// let mut a1 = [1, 2, 3, 4, 5];
// a1[x] = 64;
// for i in 0 .. 5 {
// let mut a2 = [1, 2, 3, 4, 5];
// a2[y + i] = 128;
// foo(a2);
// }
// foo(a1);
// }
//
// We want to make sure move a loop invariant make_array instruction,
// to account for whether that array has been marked as mutable.
// To do so, we increment the reference counter on the array we are moving.
// In the SSA below, we want to move `v42` out of the loop.
let src = "
brillig(inline) fn main f0 {
b0(v0: u32, v1: u32):
v8 = make_array [Field 1, Field 2, Field 3, Field 4, Field 5] : [Field; 5]
v9 = allocate -> &mut [Field; 5]
v11 = array_set v8, index v0, value Field 64
v13 = add v0, u32 1
store v11 at v9
jmp b1(u32 0)
b1(v2: u32):
v16 = lt v2, u32 5
jmpif v16 then: b3, else: b2
b2():
v17 = load v9 -> [Field; 5]
call f1(v17)
return
b3():
v19 = make_array [Field 1, Field 2, Field 3, Field 4, Field 5] : [Field; 5]
v20 = allocate -> &mut [Field; 5]
v21 = add v1, v2
v23 = array_set v19, index v21, value Field 128
call f1(v23)
v25 = add v2, u32 1
jmp b1(v25)
}
brillig(inline) fn foo f1 {
b0(v0: [Field; 5]):
return
}
";

let ssa = Ssa::from_str(src).unwrap();

// We expect the `make_array` at the top of `b3` to be replaced with an `inc_rc`
// of the newly hoisted `make_array` at the end of `b0`.
let expected = "
brillig(inline) fn main f0 {
b0(v0: u32, v1: u32):
v8 = make_array [Field 1, Field 2, Field 3, Field 4, Field 5] : [Field; 5]
v9 = allocate -> &mut [Field; 5]
v11 = array_set v8, index v0, value Field 64
v13 = add v0, u32 1
store v11 at v9
v14 = make_array [Field 1, Field 2, Field 3, Field 4, Field 5] : [Field; 5]
jmp b1(u32 0)
b1(v2: u32):
v17 = lt v2, u32 5
jmpif v17 then: b3, else: b2
b2():
v18 = load v9 -> [Field; 5]
call f1(v18)
return
b3():
inc_rc v14
v20 = allocate -> &mut [Field; 5]
v21 = add v1, v2
v23 = array_set v14, index v21, value Field 128
call f1(v23)
v25 = add v2, u32 1
jmp b1(v25)
}
brillig(inline) fn foo f1 {
b0(v0: [Field; 5]):
return
}
";

let ssa = ssa.loop_invariant_code_motion();
assert_normalized_ssa_equals(ssa, expected);
}
}
2 changes: 0 additions & 2 deletions test_programs/gates_report_brillig_execution.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ excluded_dirs=(
"double_verify_nested_proof"
"overlapping_dep_and_mod"
"comptime_println"
# Takes a very long time to execute as large loops do not get simplified.
"regression_4709"
# bit sizes for bigint operation doesn't match up.
"bigint"
# Expected to fail as test asserts on which runtime it is in.
Expand Down
4 changes: 1 addition & 3 deletions tooling/nargo_cli/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,7 @@ fn main() {

/// Some tests are explicitly ignored in brillig due to them failing.
/// These should be fixed and removed from this list.
const IGNORED_BRILLIG_TESTS: [&str; 11] = [
// Takes a very long time to execute as large loops do not get simplified.
"regression_4709",
const IGNORED_BRILLIG_TESTS: [&str; 10] = [
// bit sizes for bigint operation doesn't match up.
"bigint",
// ICE due to looking for function which doesn't exist.
Expand Down

0 comments on commit b88db67

Please sign in to comment.