Skip to content

Commit 17bf172

Browse files
authored
fix(ssa): Remove array from cache in constant folding if it's an argument to a Call (#9040)
1 parent 30a491d commit 17bf172

17 files changed

+503
-11
lines changed

compiler/noirc_evaluator/src/ssa.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ pub fn primary_passes(options: &SsaEvaluatorOptions) -> Vec<SsaPass> {
211211
SsaPass::new(Ssa::fold_constants, "Constant Folding"),
212212
SsaPass::new(Ssa::flatten_basic_conditionals, "Simplify conditionals for unconstrained"),
213213
SsaPass::new(Ssa::remove_enable_side_effects, "EnableSideEffectsIf removal"),
214-
SsaPass::new(Ssa::fold_constants_using_constraints, "Constraint Folding"),
214+
SsaPass::new(Ssa::fold_constants_using_constraints, "Constraint Folding using constraints"),
215215
SsaPass::new_try(
216216
move |ssa| ssa.unroll_loops_iteratively(options.max_bytecode_increase_percent),
217217
"Unrolling",

compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -715,15 +715,16 @@ impl<'brillig> Context<'brillig> {
715715
}
716716
}
717717

718+
/// Remove previously cached instructions that created arrays,
719+
/// if the current instruction is such that it could modify that array.
718720
fn remove_possibly_mutated_cached_make_arrays(
719721
&mut self,
720722
instruction: &Instruction,
721723
function: &Function,
722724
) {
723-
use Instruction::{ArraySet, Store};
725+
use Instruction::{ArraySet, Call, MakeArray, Store};
724726

725-
// Should we consider calls to slice_push_back and similar to be mutating operations as well?
726-
if let Store { value, .. } | ArraySet { array: value, .. } = instruction {
727+
let mut remove_if_array = |value: &ValueId| {
727728
if function.dfg.is_global(*value) {
728729
// Early return as we expect globals to be immutable.
729730
return;
@@ -739,9 +740,29 @@ impl<'brillig> Context<'brillig> {
739740
_ => return,
740741
};
741742

742-
if matches!(instruction, Instruction::MakeArray { .. } | Instruction::Call { .. }) {
743+
if matches!(instruction, MakeArray { .. } | Call { .. }) {
743744
self.cached_instruction_results.remove(instruction);
744745
}
746+
};
747+
748+
// Should we consider calls to slice_push_back and similar to be mutating operations as well?
749+
match instruction {
750+
Store { value, .. } | ArraySet { array: value, .. } => {
751+
remove_if_array(value);
752+
}
753+
Call { arguments, func } if function.runtime().is_brillig() => {
754+
let Value::Function(func_id) = &function.dfg[*func] else { return };
755+
if matches!(function.dfg.purity_of(*func_id), None | Some(Purity::Impure)) {
756+
// Arrays passed to functions might be mutated by them if there are no `inc_rc` instructions
757+
// placed *before* the call to protect them. Currently we don't track the ref count in this
758+
// context, so be conservative and do not reuse any array shared with a callee.
759+
// In ACIR we don't track refcounts, so it should be fine.
760+
for arg in arguments {
761+
remove_if_array(arg);
762+
}
763+
}
764+
}
765+
_ => {}
745766
}
746767
}
747768
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[package]
2+
name = "regression_9037"
3+
type = "bin"
4+
authors = [""]
5+
6+
[dependencies]
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
return = [[false]]
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
global G_B: ([bool; 1],) = ([false],);
2+
unconstrained fn main() -> pub [[bool; 1]; 1] {
3+
let mut ctx_limit: u32 = 25_u32;
4+
let _ = func_3(([true],), [G_B.0], (&mut ctx_limit));
5+
[G_B.0]
6+
}
7+
unconstrained fn func_3(a: ([bool; 1],), mut c: [[bool; 1]; 1], ctx_limit: &mut u32) -> bool {
8+
if ((*ctx_limit) > 0_u32) {
9+
*ctx_limit = ((*ctx_limit) - 1_u32);
10+
if func_3(G_B, [a.0], ctx_limit) {
11+
c[0_u32] = {
12+
{
13+
let mut idx_d: u32 = 0_u32;
14+
loop {
15+
if (idx_d == 3_u32) {
16+
break
17+
} else {
18+
idx_d = (idx_d + 1_u32);
19+
()
20+
}
21+
}
22+
};
23+
a.0
24+
};
25+
}
26+
}
27+
true
28+
}

tooling/ast_fuzzer/src/program/mod.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -572,8 +572,6 @@ impl std::fmt::Display for DisplayAstAsNoir<'_> {
572572
printer.show_type_in_let = true;
573573
// Most of the time it doesn't affect testing, except the comptime tests where
574574
// we parse back the code. For that we use `DisplayAstAsNoirComptime`.
575-
// Using it also inserts an extra `cast` in the SSA,
576-
// which at the moment for example defeats loop unrolling.
577575
printer.show_type_of_int_literal = false;
578576
printer.print_program(self.0, f)
579577
}

tooling/nargo_cli/tests/snapshots/execution_success/fold_2_to_17/execute__tests__force_brillig_true_inliner_-9223372036854775808.snap

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tooling/nargo_cli/tests/snapshots/execution_success/fold_2_to_17/execute__tests__force_brillig_true_inliner_0.snap

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tooling/nargo_cli/tests/snapshots/execution_success/regression_9037/execute__tests__expanded.snap

Lines changed: 34 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)