Skip to content

feat(SSA): replace slice intrinsics returned length with constant#10301

Closed
asterite wants to merge 2 commits intomasterfrom
ab/ssa-slice-intrinsics-length-optimization
Closed

feat(SSA): replace slice intrinsics returned length with constant#10301
asterite wants to merge 2 commits intomasterfrom
ab/ssa-slice-intrinsics-length-optimization

Conversation

@asterite
Copy link
Collaborator

Description

Problem

Resolves #9917

Summary

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.

@github-actions
Copy link
Contributor

github-actions bot commented Oct 27, 2025

Changes to number of Brillig opcodes executed

Generated at commit: 562fe7bb964b6f74de31237c53b5b9978bb3d1ba, compared to commit: b43153bd34f52ea835f6b7715bcf2c1f931a0fc8

🧾 Summary (10% most significant diffs)

Program Brillig opcodes (+/-) %
slice_dynamic_insert_inliner_min -4 ✅ -0.38%
array_to_slice_inliner_max -6 ✅ -0.63%

Full diff report 👇
Program Brillig opcodes (+/-) %
slice_dynamic_insert_inliner_max 951 (-2) -0.21%
slice_dynamic_insert_inliner_zero 951 (-2) -0.21%
regression_capacity_tracker_inliner_max 566 (-2) -0.35%
regression_capacity_tracker_inliner_min 566 (-2) -0.35%
regression_capacity_tracker_inliner_zero 566 (-2) -0.35%
slice_dynamic_insert_inliner_min 1,061 (-4) -0.38%
array_to_slice_inliner_max 942 (-6) -0.63%

@github-actions
Copy link
Contributor

github-actions bot commented Oct 27, 2025

Changes to Brillig bytecode sizes

Generated at commit: 562fe7bb964b6f74de31237c53b5b9978bb3d1ba, compared to commit: b43153bd34f52ea835f6b7715bcf2c1f931a0fc8

🧾 Summary (10% most significant diffs)

Program Brillig opcodes (+/-) %
array_to_slice_inliner_max -9 ✅ -1.83%
slice_dynamic_insert_inliner_min -8 ✅ -1.85%

Full diff report 👇
Program Brillig opcodes (+/-) %
slice_dynamic_insert_inliner_max 378 (-4) -1.05%
slice_dynamic_insert_inliner_zero 378 (-4) -1.05%
regression_capacity_tracker_inliner_max 212 (-3) -1.40%
regression_capacity_tracker_inliner_min 212 (-3) -1.40%
regression_capacity_tracker_inliner_zero 212 (-3) -1.40%
array_to_slice_inliner_max 482 (-9) -1.83%
slice_dynamic_insert_inliner_min 425 (-8) -1.85%

@asterite
Copy link
Collaborator Author

The optimizations here aren't that big. However, if we implement #10296 then it will happen that intrinsics that were optimized out will now be fully optimized (as the slice contents won't be needed, and neither the length) so DIE will remove them, resulting in (I think) less ACIR/Brillig.

But, in any case, this is a relatively simple optimization that we could merge as-is.

Copy link
Contributor

@jfecher jfecher left a comment

Choose a reason for hiding this comment

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

I'm thinking some larger changes to the slice methods may actually be better than a new pass

Comment on lines +22 to +23
/// where `v1` is the returned length, we can replace `v1` with `u32 11` since we know
/// the returned length will be one more than the input length `u32 10`.
Copy link
Contributor

Choose a reason for hiding this comment

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

The fact this is always known makes me question whether we should have slice_insert return two values at all.

Perhaps slice_insert, slice_push_front, and friends should instead return just the array, and when handling them we should insert a separate add 1 instruction for the length. That way we need less special handling. The only time insert/remove wont change the length is if the index is OOB, in which case we should halt anyway. The only case the length doesn't change on a non-error is when we call pop on an empty array. We could still do a new_len = if len == 0 { 0 } else { len - 1 } though.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Ah, it's not always known. For example in slice_dynamic_index I can see this:

v812, v813, v814 = call slice_pop_back(v789, v811) -> (u32, [Field], Field)

That said, I agree that maybe the length doesn't need to be returned and it can be computed from the input. I think in ACIR that's what we do (I didn't check Brillig). But I don't know how this can be changed if the Noir function does return the length (in the slice return type).

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

On the other hand, if we replace v812 above with v812 = add v789, u32 1 then it's one more operation that needs to be done in ACIR/Brillig for dynamic indexes, so maybe it'll add some overhead.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, it's not always known. For example in slice_dynamic_index I can see this:

Not sure what you mean - looks like the length would still be known to be 1 more than the previous. By unknown I meant unknown whether it'd increment at all or not, not whether the result is unknown.

Would add/sub be one more operation that need to be handled for dynamic indices? I would think we'd need to already handle that case since indices can come from addition/subtraction already. If the analysis only handles slice_ functions then we could even change it not to handle them at all anymore since now the lengths wouldn't be coming from those operations but from separate add/subs.

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: ade36c5 Previous: b43153b Ratio
test_report_zkpassport_noir-ecdsa_ 3 s 2 s 1.50

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

CC: @TomAFrench

@asterite
Copy link
Collaborator Author

Closing until #10206 is merged.

@asterite asterite closed this Oct 28, 2025
@asterite asterite deleted the ab/ssa-slice-intrinsics-length-optimization branch October 28, 2025 12:40
@asterite asterite restored the ab/ssa-slice-intrinsics-length-optimization branch October 28, 2025 12:41
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.

More slice SSA optimizations similar to as_slice_optimization

2 participants