Skip to content

fix(ssa): Do not remove array operations that can be OOB during DIE #9232

Merged
TomAFrench merged 6 commits intotf/optimize-array-access-checksfrom
mv/array-get-side-effects
Jul 22, 2025
Merged

fix(ssa): Do not remove array operations that can be OOB during DIE #9232
TomAFrench merged 6 commits intotf/optimize-array-access-checksfrom
mv/array-get-side-effects

Conversation

@vezenovm
Copy link
Contributor

@vezenovm vezenovm commented Jul 17, 2025

Description

Problem*

Resolves #9223

Summary*

Builds off of #9200

This replaces #9220 which branches off master. The motivation to have these changes branch off one another is that we have several test failures triggerd by #9200 (the original parent PR). We can more easily get a passing CI but having any fixes built off one another.

Additional Context

Documentation*

Check one:

  • No documentation needed.
  • Documentation included in this PR.
  • [For Experimental Features] Documentation to be submitted in a separate PR.

PR Checklist*

  • I have tested the changes locally.
  • I have formatted the changes with Prettier and/or cargo fmt on default settings.

@vezenovm vezenovm changed the title check whether array gets require an acir gen predicate fix(ssa): Do not remove array operations that can be OOB during DIE Jul 17, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Jul 17, 2025

Changes to Brillig bytecode sizes

Generated at commit: b5bc5ca74da769def2e2b0f34cf00e5a50f1c497, compared to commit: c879dcee0e2a1664154f6d9866a6de2ea573073a

🧾 Summary (10% most significant diffs)

Program Brillig opcodes (+/-) %
regression_9206_inliner_max +48 ❌ +154.84%
regression_9206_inliner_min +48 ❌ +154.84%
regression_9206_inliner_zero +48 ❌ +154.84%
a_6_inliner_max +37 ❌ +27.41%
a_6_inliner_zero +37 ❌ +27.41%
a_6_inliner_min +37 ❌ +25.52%
brillig_rc_regression_6123_inliner_min +30 ❌ +20.98%

Full diff report 👇
Program Brillig opcodes (+/-) %
regression_9206_inliner_max 79 (+48) +154.84%
regression_9206_inliner_min 79 (+48) +154.84%
regression_9206_inliner_zero 79 (+48) +154.84%
a_6_inliner_max 172 (+37) +27.41%
a_6_inliner_zero 172 (+37) +27.41%
a_6_inliner_min 182 (+37) +25.52%
brillig_rc_regression_6123_inliner_min 173 (+30) +20.98%
conditional_regression_short_circuit_inliner_max 245 (+37) +17.79%
conditional_regression_short_circuit_inliner_zero 245 (+37) +17.79%
conditional_regression_short_circuit_inliner_min 272 (+37) +15.74%
regression_struct_array_conditional_inliner_max 426 (+42) +10.94%
regression_struct_array_conditional_inliner_min 426 (+42) +10.94%
regression_struct_array_conditional_inliner_zero 426 (+42) +10.94%
nested_array_in_slice_inliner_max 970 (+90) +10.23%
regression_11294_inliner_max 235 (+14) +6.33%
regression_11294_inliner_zero 235 (+14) +6.33%
brillig_nested_arrays_inliner_max 133 (+7) +5.56%
nested_array_dynamic_inliner_max 1,817 (+93) +5.39%
nested_array_dynamic_inliner_min 1,503 (+75) +5.25%
nested_array_dynamic_inliner_zero 1,503 (+75) +5.25%
array_dynamic_nested_blackbox_input_inliner_max 333 (+15) +4.72%
array_dynamic_nested_blackbox_input_inliner_zero 333 (+15) +4.72%
array_dynamic_nested_blackbox_input_inliner_min 343 (+15) +4.57%
nested_array_in_slice_inliner_min 849 (+35) +4.30%
nested_array_in_slice_inliner_zero 849 (+35) +4.30%
brillig_nested_arrays_inliner_min 178 (+7) +4.09%
brillig_nested_arrays_inliner_zero 178 (+7) +4.09%
brillig_constant_reference_regression_inliner_max 82 (+3) +3.80%
brillig_constant_reference_regression_inliner_min 82 (+3) +3.80%
brillig_constant_reference_regression_inliner_zero 82 (+3) +3.80%
wildcard_type_inliner_max 272 (+7) +2.64%
wildcard_type_inliner_zero 272 (+7) +2.64%
wildcard_type_inliner_min 282 (+7) +2.55%
slices_inliner_zero 1,682 (+32) +1.94%
slices_inliner_max 1,723 (+32) +1.89%
poseidonsponge_x5_254_inliner_max 3,747 (+60) +1.63%
regression_5252_inliner_max 4,032 (+60) +1.51%
hashmap_inliner_max 17,573 (+255) +1.47%
slices_inliner_min 2,197 (+29) +1.34%
poseidonsponge_x5_254_inliner_zero 2,928 (+30) +1.04%
lambda_from_array_inliner_max 2,509 (+25) +1.01%
lambda_from_array_inliner_min 2,509 (+25) +1.01%
lambda_from_array_inliner_zero 2,509 (+25) +1.01%
poseidonsponge_x5_254_inliner_min 3,049 (+30) +0.99%
regression_5252_inliner_zero 3,260 (+30) +0.93%
regression_5252_inliner_min 3,414 (+30) +0.89%
poseidon_bn254_hash_width_3_inliner_zero 4,475 (+30) +0.67%
poseidon_bn254_hash_width_3_inliner_min 4,772 (+30) +0.63%
poseidon_bn254_hash_width_3_inliner_max 4,888 (+30) +0.62%
uhashmap_inliner_max 11,684 (+56) +0.48%
hashmap_inliner_zero 7,754 (+30) +0.39%
uhashmap_inliner_zero 6,894 (+25) +0.36%
brillig_cow_regression_inliner_max 1,206 (+4) +0.33%
brillig_cow_regression_inliner_zero 1,206 (+4) +0.33%
brillig_cow_regression_inliner_min 1,216 (+4) +0.33%
hashmap_inliner_min 8,813 (+26) +0.30%
uhashmap_inliner_min 7,304 (+20) +0.27%
slice_regex_inliner_zero 1,600 (-23) -1.42%
slice_regex_inliner_max 1,824 (-168) -8.43%

@github-actions
Copy link
Contributor

github-actions bot commented Jul 17, 2025

Changes to number of Brillig opcodes executed

Generated at commit: b5bc5ca74da769def2e2b0f34cf00e5a50f1c497, compared to commit: c879dcee0e2a1664154f6d9866a6de2ea573073a

🧾 Summary (10% most significant diffs)

Program Brillig opcodes (+/-) %
regression_9206_inliner_max +48 ❌ +192.00%
regression_9206_inliner_min +48 ❌ +192.00%
regression_9206_inliner_zero +48 ❌ +192.00%
brillig_rc_regression_6123_inliner_min +108 ❌ +52.94%
regression_struct_array_conditional_inliner_max +97 ❌ +8.58%
regression_struct_array_conditional_inliner_min +97 ❌ +8.58%
regression_struct_array_conditional_inliner_zero +97 ❌ +8.58%

Full diff report 👇
Program Brillig opcodes (+/-) %
regression_9206_inliner_max 73 (+48) +192.00%
regression_9206_inliner_min 73 (+48) +192.00%
regression_9206_inliner_zero 73 (+48) +192.00%
brillig_rc_regression_6123_inliner_min 312 (+108) +52.94%
regression_struct_array_conditional_inliner_max 1,227 (+97) +8.58%
regression_struct_array_conditional_inliner_min 1,227 (+97) +8.58%
regression_struct_array_conditional_inliner_zero 1,227 (+97) +8.58%
nested_array_in_slice_inliner_max 1,150 (+78) +7.28%
wildcard_type_inliner_max 421 (+28) +7.12%
wildcard_type_inliner_zero 421 (+28) +7.12%
wildcard_type_inliner_min 435 (+28) +6.88%
brillig_nested_arrays_inliner_max 123 (+7) +6.03%
brillig_nested_arrays_inliner_min 172 (+7) +4.24%
brillig_nested_arrays_inliner_zero 172 (+7) +4.24%
brillig_constant_reference_regression_inliner_max 82 (+3) +3.80%
brillig_constant_reference_regression_inliner_min 82 (+3) +3.80%
brillig_constant_reference_regression_inliner_zero 82 (+3) +3.80%
nested_array_dynamic_inliner_max 2,718 (+69) +2.60%
a_6_inliner_max 879 (+21) +2.45%
a_6_inliner_zero 879 (+21) +2.45%
a_6_inliner_min 893 (+21) +2.41%
conditional_regression_short_circuit_inliner_max 955 (+21) +2.25%
conditional_regression_short_circuit_inliner_zero 955 (+21) +2.25%
conditional_regression_short_circuit_inliner_min 994 (+21) +2.16%
regression_5252_inliner_max 776,324 (+15,800) +2.08%
poseidonsponge_x5_254_inliner_max 156,158 (+3,160) +2.07%
nested_array_in_slice_inliner_min 1,353 (+27) +2.04%
nested_array_in_slice_inliner_zero 1,353 (+27) +2.04%
nested_array_dynamic_inliner_min 2,931 (+54) +1.88%
nested_array_dynamic_inliner_zero 2,931 (+54) +1.88%
regression_5252_inliner_zero 946,216 (+15,800) +1.70%
poseidonsponge_x5_254_inliner_zero 190,037 (+3,160) +1.69%
regression_5252_inliner_min 958,155 (+15,800) +1.68%
poseidonsponge_x5_254_inliner_min 191,942 (+3,160) +1.67%
lambda_from_array_inliner_max 1,709 (+25) +1.48%
lambda_from_array_inliner_min 1,709 (+25) +1.48%
lambda_from_array_inliner_zero 1,709 (+25) +1.48%
hashmap_inliner_max 52,394 (+743) +1.44%
array_dynamic_nested_blackbox_input_inliner_max 1,196 (+15) +1.27%
array_dynamic_nested_blackbox_input_inliner_zero 1,196 (+15) +1.27%
array_dynamic_nested_blackbox_input_inliner_min 1,210 (+15) +1.26%
regression_11294_inliner_max 1,140 (+14) +1.24%
regression_11294_inliner_zero 1,140 (+14) +1.24%
poseidon_bn254_hash_width_3_inliner_max 138,987 (+1,580) +1.15%
poseidon_bn254_hash_width_3_inliner_zero 169,399 (+1,580) +0.94%
poseidon_bn254_hash_width_3_inliner_min 173,104 (+1,580) +0.92%
slices_inliner_max 2,506 (+16) +0.64%
slices_inliner_zero 2,773 (+16) +0.58%
uhashmap_inliner_max 145,242 (+704) +0.49%
hashmap_inliner_zero 67,043 (+248) +0.37%
slices_inliner_min 3,818 (+13) +0.34%
hashmap_inliner_min 73,580 (+228) +0.31%
uhashmap_inliner_zero 169,044 (+264) +0.16%
uhashmap_inliner_min 176,924 (+230) +0.13%
brillig_cow_regression_inliner_max 194,409 (+64) +0.03%
brillig_cow_regression_inliner_zero 194,409 (+64) +0.03%
brillig_cow_regression_inliner_min 194,644 (+64) +0.03%
slice_regex_inliner_zero 3,859 (-22) -0.57%
slice_regex_inliner_max 2,782 (-98) -3.40%

@github-actions
Copy link
Contributor

github-actions bot commented Jul 17, 2025

Changes to circuit sizes

Generated at commit: b5bc5ca74da769def2e2b0f34cf00e5a50f1c497, compared to commit: c879dcee0e2a1664154f6d9866a6de2ea573073a

🧾 Summary (10% most significant diffs)

Program ACIR opcodes (+/-) % Circuit size (+/-) %
array_oob_regression_7965 +4 ❌ +19.05% +2,745 ❌ +3191.86%
a_6 +1 ❌ +1.43% +2,051 ❌ +94.04%
no_predicates_numeric_generic_poseidon +171 ❌ +322.64% +1,130 ❌ +93.54%

Full diff report 👇
Program ACIR opcodes (+/-) % Circuit size (+/-) %
array_oob_regression_7965 25 (+4) +19.05% 2,831 (+2,745) +3191.86%
a_6 71 (+1) +1.43% 4,232 (+2,051) +94.04%
no_predicates_numeric_generic_poseidon 224 (+171) +322.64% 2,338 (+1,130) +93.54%
bench_2_to_17 22,874 (+16,340) +250.08% 240,203 (+109,470) +83.74%
fold_2_to_17 21,754 (+15,540) +250.08% 228,442 (+104,110) +83.74%
conditional_regression_short_circuit 90 (+1) +1.12% 6,993 (+2,051) +41.50%
slices 741 (+71) +10.60% 4,139 (+370) +9.82%
slice_dynamic_index 969 (+161) +19.93% 5,537 (+464) +9.15%
conditional_1 2,772 (+18) +0.65% 8,625 (+485) +5.96%
regression_capacity_tracker 132 (+79) +149.06% 3,919 (+194) +5.21%
lambda_from_array 808 (+3) +0.37% 592 (+25) +4.41%
nested_array_in_slice 1,052 (+94) +9.81% 5,663 (+201) +3.68%
nested_array_dynamic 3,436 (+206) +6.38% 13,005 (+399) +3.17%
regression_5252 26,724 (+546) +2.09% 82,251 (+2,449) +3.07%
regression_struct_array_conditional 98 (+32) +48.48% 3,244 (+48) +1.50%
array_dynamic_nested_blackbox_input 154 (+24) +18.46% 5,239 (+67) +1.30%
hashmap 32,062 (+512) +1.62% 93,780 (+1,052) +1.13%
regression_7612 17 (+2) +13.33% 2,783 (+3) +0.11%
sha512_100_bytes 13,125 (0) 0.00% 39,409 (-4) -0.01%

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark 'Opcode count'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.10.

Benchmark suite Current: efbe355 Previous: 39a8379 Ratio
private-kernel-reset 83598 opcodes 68865 opcodes 1.21

This comment was automatically generated by workflow using github-action-benchmark.

CC: @TomAFrench

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark 'Execution Time'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.20.

Benchmark suite Current: 4a1d68d Previous: 3c18e33 Ratio
sha512-100-bytes 0.115 s 0.056 s 2.05

This comment was automatically generated by workflow using github-action-benchmark.

CC: @TomAFrench

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark 'Test Suite Duration'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.20.

Benchmark suite Current: 4a1d68d Previous: 3c18e33 Ratio
test_report_AztecProtocol_aztec-packages_noir-projects_aztec-nr 132 s 5 s 26.40
test_report_AztecProtocol_aztec-packages_noir-projects_noir-contracts 151 s 42 s 3.60
test_report_AztecProtocol_aztec-packages_noir-projects_noir-protocol-circuits_crates_blob 200 s 3 s 66.67
test_report_AztecProtocol_aztec-packages_noir-projects_noir-protocol-circuits_crates_private-kernel-lib 263 s 1 s 263
test_report_AztecProtocol_aztec-packages_noir-projects_noir-protocol-circuits_crates_reset-kernel-lib 33 s 2 s 16.50
test_report_AztecProtocol_aztec-packages_noir-projects_noir-protocol-circuits_crates_rollup-lib 666 s 3 s 222
test_report_AztecProtocol_aztec-packages_noir-projects_noir-protocol-circuits_crates_types 126 s 1 s 126
test_report_zkpassport_noir-ecdsa_ 112 s 3 s 37.33

This comment was automatically generated by workflow using github-action-benchmark.

CC: @TomAFrench

@TomAFrench TomAFrench self-requested a review July 21, 2025 17:09
@TomAFrench
Copy link
Member

I took a look at the cause of the regressions in this PR and it seems to be down to us now having a lot of instructions would have been removed by die which are sitting under a constant zero predicate.

It's a bit annoying to deal with these in die (as we'd need to do lookahead to determine the predicate). Chucking a simplify_cfg in front of flatten_cfg should either fix it or give us a thread to pull on.

@vezenovm
Copy link
Contributor Author

I took a look at the cause of the regressions in this PR and it seems to be down to us now having a lot of instructions would have been removed by die which are sitting under a constant zero predicate

Which ones do you see are sitting under a constant zero?

Some of the circuit regressions look to be unavoidable without extra handling in DIE. We may have to bring back some form of the OOB checks inserted during DIE that were removed in #7995.

For example this program taken from regression_7612:

pub struct Data {
    fields: [Field; 1],
    counter: u32,
}

fn main(array: [Data; 1], x: bool) {
    let index = if x { 0 } else { 1 };
    if index != 0 {
        assert(array[index - 1].counter < 3);
    }
}

Produces this SSA:

After Dead Instruction Elimination - ACIR (1) (step 43):
acir(inline) predicate_pure fn main f0 {
  b0(v0: [([Field; 1], u32); 1], v1: u1):
    v2 = not v1
    enable_side_effects u1 1
    v4 = cast v2 as u32
    v6 = eq v4, u32 0
    v7 = not v6
    enable_side_effects v7
    v9 = sub v4, u32 1
    v11 = unchecked_mul v9, u32 2
    v12 = array_get v0, index v11 -> [Field; 1]
    v13 = unchecked_add v11, u32 1
    v14 = array_get v0, index v13 -> u32
    v16 = lt v14, u32 3
    v17 = unchecked_mul v16, v7
    constrain v17 == v7
    enable_side_effects u1 1
    return
}

Previously we would remove v12 = array_get v0, index v11 -> [Field; 1] and be confident that the separate OOB kept us safe. However, we can still safely remove this v12 result as it is unused and part of the same array access (if next array get would fail if it was OOB). We would only check this for ACIR. It would complicate DIE again though by bringing back some form of what was removed in #7995.

@TomAFrench
Copy link
Member

TomAFrench commented Jul 22, 2025

I found the regression in no_predicates_numeric_generic_poseidon, I get constant condition jmpifs appearing in the mem2reg just before flattening.

More details in #9275, tl;dr is that this is a no_predicates issue.

@vezenovm
Copy link
Contributor Author

I'm looking at bring back removing unused array get groups during DIE.

@vezenovm
Copy link
Contributor Author

I'm looking at bring back removing unused array get groups during DIE.

This is showing to be promising.

Co-authored-by: Maxim Vezenov <mvezenov@gmail.com>
@TomAFrench
Copy link
Member

huh, sorry I seem to have broken this.

@TomAFrench TomAFrench merged commit 59fcd88 into tf/optimize-array-access-checks Jul 22, 2025
118 checks passed
@TomAFrench TomAFrench deleted the mv/array-get-side-effects branch July 22, 2025 19:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants