Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(brillig): Brillig entry point analysis and function specialization through duplication #7277

Merged
merged 39 commits into from
Feb 18, 2025

Conversation

vezenovm
Copy link
Contributor

@vezenovm vezenovm commented Feb 4, 2025

Description

Problem*

Resolves #7306.

The description in this PR repeats a lot of the comments and tests from the new SSA pass, but I have copied things here for visibility.

Take this program:

global ONE: Field = 1;
global TWO: Field = 2;
global THREE: Field = 3;
fn main(x: Field, y: pub Field) {
    /// Safety: testing context
    unsafe {
        entry_point_one(x, y);
        entry_point_two(x, y);
    }
}
unconstrained fn entry_point_one(x: Field, y: Field) {
    let z = ONE + x + y;
    assert(z == 2);
    inner_func(x, y);
}
unconstrained fn entry_point_two(x: Field, y: Field) {
    let z = TWO + x + y;
    assert(z == 3);
    inner_func(x, y);
}
unconstrained fn inner_func(x: Field, y: Field) {
    let z = THREE + x + y;
    assert(z == 4);
}

We have this SSA before Brillig gen:

g0 = Field 1
g1 = Field 2
g2 = Field 3

acir(inline) predicate_pure fn main f0 {
  b0(v3: Field, v4: Field):
    call f1(v3, v4)
    call f2(v3, v4)
    return
}
brillig(inline) predicate_pure fn entry_point_one f1 {
  b0(v3: Field, v4: Field):
    v5 = add Field 1, v3
    v6 = add v5, v4
    constrain v6 == Field 2
    call f3(v3, v4)
    return
}
brillig(inline) predicate_pure fn entry_point_two f2 {
  b0(v3: Field, v4: Field):
    v5 = add Field 2, v3
    v6 = add v5, v4
    constrain v6 == Field 3
    call f3(v3, v4)
    return
}
brillig(inline) predicate_pure fn inner_func f3 {
  b0(v3: Field, v4: Field):
    v5 = add Field 3, v3
    v6 = add v5, v4
    constrain v6 == Field 4
    return
}

For each entry point we will generate the follows artifacts for globals initialization:

GlobalInit(Id(1)):
  CONST M32835 = 1
  CONST M32836 = 2
  CONST M32837 = 3
  RETURN
GlobalInit(Id(2)):
  CONST M32835 = 2
  CONST M32836 = 3
  RETURN

It is then not clear to inner_func which map of SSA value id -> Brillig global initialization we should use.
Without the hack from #7306 we get the following bytecode for f3:

Function(Id(3), Some(Id(0))):
  S3 = M32836 + S1
  S1 = S3 + S2
  CONST S2 = 4
  S3 = S1 == S2
  JUMP_IF S3 TO Function(Id(3), Some(Id(0))) - 1
  CONST S4 = 0
  TRAP FreeMem[0..S4]
  RETURN

This works when f3 is called from the f2 entry point. But it will break when called from the f1 entry point. We need to specialize f3 to account for the potentially conflicting global allocation maps.

Summary*

We now specialize functions per entry point.

A few things were done in this PR:

  1. A new pass the specializes functions per entry point
  2. I run the new pass following DIE as to reduce the amount of code we may have to duplicate. However, this also required re-running DIE following this pass as the used_globals map is set during DIE. Perhaps we do not have to re-run this though as the global value IDs should not change across SSA passes. I could foresee the CFG simplification after DIE leading to some terminators that use globals being removed and needing to recompute the used globals map. Perhaps we could recompute this during CFG simplification. I feel this can be done in a followup PR though.
  3. I have been testing against aztec-packages directly and added a few simplified regression tests to our integration tests as well as some unit tests for the new SSA pass.

Additional Context

This works further re-iterates the need for a debug/release mode as laid out in #2128. This duplication can lead to code bloat. During debug mode we could potentially not perform any entry point analysis and just have the same globals across all functions if this work is shown to seriously degrade compilation. Then during release mode we can perform the full entry point analysis to optimize for runtime.

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 added a commit to AztecProtocol/aztec-packages that referenced this pull request Feb 4, 2025
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: b807d0d Previous: 64890c0 Ratio
noir-lang_noir_bigcurve_ 311 s 250 s 1.24

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

CC: @TomAFrench

Copy link
Contributor

github-actions bot commented Feb 6, 2025

Changes to Brillig bytecode sizes

Generated at commit: 7aa2241f20862db79cc8913c4336c92f9ed18045, compared to commit: 64890c0d7420adb32d3867e51dd194e48b87bb32

🧾 Summary (10% most significant diffs)

Program Brillig opcodes (+/-) %
fold_complex_outputs_inliner_min -21 ✅ -2.97%
brillig_nested_arrays_inliner_zero -8 ✅ -3.32%
regression_6674_2_inliner_zero -6 ✅ -3.75%
nested_arrays_from_brillig_inliner_min -8 ✅ -4.28%
nested_array_in_slice_inliner_max -127 ✅ -11.22%

Full diff report 👇
Program Brillig opcodes (+/-) %
regression_5252_inliner_max 4,441 (-3) -0.07%
slices_inliner_min 2,534 (-3) -0.12%
slice_regex_inliner_min 2,124 (-3) -0.14%
strings_inliner_min 1,135 (-3) -0.26%
conditional_regression_short_circuit_inliner_min 1,101 (-3) -0.27%
6_inliner_min 1,000 (-3) -0.30%
strings_inliner_max 949 (-3) -0.32%
strings_inliner_zero 934 (-3) -0.32%
conditional_regression_short_circuit_inliner_zero 905 (-3) -0.33%
regression_6674_3_inliner_min 867 (-3) -0.34%
6_inliner_zero 823 (-3) -0.36%
hashmap_inliner_zero 7,843 (-45) -0.57%
higher_order_functions_inliner_zero 729 (-6) -0.82%
slice_regex_inliner_max 2,298 (-21) -0.91%
struct_inputs_inliner_min 289 (-3) -1.03%
slice_regex_inliner_zero 1,686 (-18) -1.06%
higher_order_functions_inliner_max 559 (-6) -1.06%
struct_inputs_inliner_max 269 (-3) -1.10%
struct_inputs_inliner_zero 254 (-3) -1.17%
array_dynamic_nested_blackbox_input_inliner_min 1,179 (-14) -1.17%
regression_6674_2_inliner_max 203 (-3) -1.46%
array_dynamic_nested_blackbox_input_inliner_zero 864 (-14) -1.59%
array_dynamic_nested_blackbox_input_inliner_max 837 (-14) -1.65%
nested_array_dynamic_inliner_max 2,382 (-45) -1.85%
regression_6674_1_inliner_zero 157 (-3) -1.88%
wildcard_type_inliner_min 285 (-7) -2.40%
wildcard_type_inliner_max 274 (-7) -2.49%
wildcard_type_inliner_zero 274 (-7) -2.49%
brillig_nested_arrays_inliner_min 267 (-8) -2.91%
fold_complex_outputs_inliner_min 686 (-21) -2.97%
brillig_nested_arrays_inliner_zero 233 (-8) -3.32%
regression_6674_2_inliner_zero 154 (-6) -3.75%
nested_arrays_from_brillig_inliner_min 179 (-8) -4.28%
nested_array_in_slice_inliner_max 1,005 (-127) -11.22%

Copy link
Contributor

github-actions bot commented Feb 6, 2025

Changes to number of Brillig opcodes executed

Generated at commit: 7aa2241f20862db79cc8913c4336c92f9ed18045, compared to commit: 64890c0d7420adb32d3867e51dd194e48b87bb32

🧾 Summary (10% most significant diffs)

Program Brillig opcodes (+/-) %
brillig_nested_arrays_inliner_zero -14 ✅ -4.65%
wildcard_type_inliner_min -24 ✅ -5.22%
wildcard_type_inliner_max -24 ✅ -5.39%
wildcard_type_inliner_zero -24 ✅ -5.39%
nested_array_in_slice_inliner_max -105 ✅ -7.18%

Full diff report 👇
Program Brillig opcodes (+/-) %
regression_5252_inliner_max 864,828 (-3) -0.00%
slice_regex_inliner_min 8,634 (-3) -0.03%
hashmap_inliner_zero 74,631 (-45) -0.06%
conditional_regression_short_circuit_inliner_min 4,958 (-3) -0.06%
6_inliner_min 4,852 (-3) -0.06%
conditional_regression_short_circuit_inliner_zero 4,519 (-3) -0.07%
6_inliner_zero 4,439 (-3) -0.07%
slices_inliner_min 4,289 (-3) -0.07%
strings_inliner_min 2,893 (-3) -0.10%
strings_inliner_zero 2,098 (-3) -0.14%
regression_6674_3_inliner_min 2,005 (-3) -0.15%
strings_inliner_max 1,743 (-3) -0.17%
array_dynamic_nested_blackbox_input_inliner_min 4,914 (-12) -0.24%
array_dynamic_nested_blackbox_input_inliner_zero 4,460 (-12) -0.27%
array_dynamic_nested_blackbox_input_inliner_max 4,208 (-12) -0.28%
slice_regex_inliner_zero 4,041 (-18) -0.44%
higher_order_functions_inliner_zero 1,328 (-6) -0.45%
struct_inputs_inliner_min 659 (-3) -0.45%
regression_6674_1_inliner_zero 619 (-3) -0.48%
regression_6674_2_inliner_max 606 (-3) -0.49%
struct_inputs_inliner_zero 601 (-3) -0.50%
struct_inputs_inliner_max 566 (-3) -0.53%
slice_regex_inliner_max 3,232 (-21) -0.65%
higher_order_functions_inliner_max 901 (-6) -0.66%
regression_6674_2_inliner_zero 616 (-6) -0.96%
nested_array_dynamic_inliner_max 3,366 (-39) -1.15%
fold_complex_outputs_inliner_min 1,067 (-18) -1.66%
nested_arrays_from_brillig_inliner_min 215 (-7) -3.15%
brillig_nested_arrays_inliner_min 468 (-21) -4.29%
brillig_nested_arrays_inliner_zero 287 (-14) -4.65%
wildcard_type_inliner_min 436 (-24) -5.22%
wildcard_type_inliner_max 421 (-24) -5.39%
wildcard_type_inliner_zero 421 (-24) -5.39%
nested_array_in_slice_inliner_max 1,357 (-105) -7.18%

@vezenovm vezenovm changed the title fix(brillig): Duplicate Brillig entry points called by Brillig entry points fix(brillig): Brilig entry point analysis and function specialization through duplication Feb 7, 2025
@vezenovm vezenovm marked this pull request as ready for review February 7, 2025 13:12
@vezenovm vezenovm requested a review from a team February 7, 2025 13:18
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.

Test Suite Duration

Benchmark suite Current: b807d0d Previous: 64890c0 Ratio
AztecProtocol_aztec-packages_noir-projects_aztec-nr 33 s 34 s 0.97
AztecProtocol_aztec-packages_noir-projects_noir-contracts 71 s 73 s 0.97
AztecProtocol_aztec-packages_noir-projects_noir-protocol-circuits_crates_blob 62 s 66 s 0.94
AztecProtocol_aztec-packages_noir-projects_noir-protocol-circuits_crates_private-kernel-lib 167 s 165 s 1.01
AztecProtocol_aztec-packages_noir-projects_noir-protocol-circuits_crates_reset-kernel-lib 11 s 10 s 1.10
AztecProtocol_aztec-packages_noir-projects_noir-protocol-circuits_crates_rollup-lib 180 s 171 s 1.05
AztecProtocol_aztec-packages_noir-projects_noir-protocol-circuits_crates_types 54 s 53 s 1.02
noir-lang_noir-bignum_ 357 s 363 s 0.98
noir-lang_noir_bigcurve_ 311 s 250 s 1.24
noir-lang_noir_json_parser_ 9 s 11 s 0.82

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

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.

Compilation Memory

Benchmark suite Current: b807d0d Previous: 64890c0 Ratio
private-kernel-inner 275.6 MB 275.6 MB 1
private-kernel-reset 586.9 MB 586.93 MB 1.00
private-kernel-tail 199.21 MB 199.2 MB 1.00
rollup-base-private 950.6 MB 950.65 MB 1.00
rollup-base-public 816.14 MB 816.16 MB 1.00
rollup-block-root-empty 326.24 MB 326.23 MB 1.00
rollup-block-root-single-tx 6860 MB 6860 MB 1
rollup-block-root 6870 MB 6870 MB 1
rollup-merge 324.64 MB 324.64 MB 1
rollup-root 372.32 MB 372.3 MB 1.00

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

Copy link
Member

@TomAFrench TomAFrench left a comment

Choose a reason for hiding this comment

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

Looks good, I think we can streamline the logic a little bit before merging however.

@TomAFrench
Copy link
Member

Feel free to bump the execution time limit a little bit here.

@vezenovm vezenovm requested a review from TomAFrench February 18, 2025 16:40
Copy link
Member

@TomAFrench TomAFrench left a comment

Choose a reason for hiding this comment

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

LGTM

Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com>
@vezenovm vezenovm enabled auto-merge February 18, 2025 18:11
@vezenovm vezenovm added this pull request to the merge queue Feb 18, 2025
Merged via the queue into master with commit 119bf62 Feb 18, 2025
101 of 102 checks passed
@vezenovm vezenovm deleted the mv/duplicate-brillig-entry-points-called-from-brillig branch February 18, 2025 18:35
TomAFrench added a commit that referenced this pull request Feb 19, 2025
* master:
  fix(performance): Remove redundant slice access check from brillig (#7434)
  chore(docs): updating tutorials and other nits to beta.2 (#7405)
  feat: LSP hover for integer literals (#7368)
  feat(experimental): Compile match expressions (#7312)
  feat(acir_field): Add little-endian byte serialization for FieldElement (#7258)
  feat: allow unquoting TraitConstraint in trait impl position (#7395)
  feat(brillig): Hoist shared constants across functions to the global space (#7216)
  feat(LSP): auto-import via visible reexport (#7409)
  fix(brillig): Brillig entry point analysis and function specialization through duplication (#7277)
  chore: redo typo PR by maximevtush (#7425)
  fix(ssa): Accurately mark binary ops for hoisting and check Div/Mod against induction variable lower bound (#7396)
  feat!: remove bigint from stdlib (#7411)
AztecBot added a commit to AztecProtocol/aztec-packages that referenced this pull request Feb 19, 2025
…m brillig (noir-lang/noir#7434)

chore(docs): updating tutorials and other nits to beta.2 (noir-lang/noir#7405)
feat: LSP hover for integer literals (noir-lang/noir#7368)
feat(experimental): Compile match expressions (noir-lang/noir#7312)
feat(acir_field): Add little-endian byte serialization for FieldElement (noir-lang/noir#7258)
feat: allow unquoting TraitConstraint in trait impl position (noir-lang/noir#7395)
feat(brillig): Hoist shared constants across functions to the global space (noir-lang/noir#7216)
feat(LSP): auto-import via visible reexport (noir-lang/noir#7409)
fix(brillig): Brillig entry point analysis and function specialization through duplication (noir-lang/noir#7277)
chore: redo typo PR by maximevtush (noir-lang/noir#7425)
fix(ssa): Accurately mark binary ops for hoisting and check Div/Mod against induction variable lower bound (noir-lang/noir#7396)
feat!: remove bigint from stdlib (noir-lang/noir#7411)
chore: bump aztec-packages commit (noir-lang/noir#7415)
chore: deprecate `merkle` module of stdlib (noir-lang/noir#7413)
chore(ci): lock aztec-packages commit in CI (noir-lang/noir#7414)
feat: while statement (noir-lang/noir#7280)
AztecBot added a commit to AztecProtocol/aztec-packages that referenced this pull request Feb 19, 2025
…oir-lang/noir#7434)

chore(docs): updating tutorials and other nits to beta.2 (noir-lang/noir#7405)
feat: LSP hover for integer literals (noir-lang/noir#7368)
feat(experimental): Compile match expressions (noir-lang/noir#7312)
feat(acir_field): Add little-endian byte serialization for FieldElement (noir-lang/noir#7258)
feat: allow unquoting TraitConstraint in trait impl position (noir-lang/noir#7395)
feat(brillig): Hoist shared constants across functions to the global space (noir-lang/noir#7216)
feat(LSP): auto-import via visible reexport (noir-lang/noir#7409)
fix(brillig): Brillig entry point analysis and function specialization through duplication (noir-lang/noir#7277)
chore: redo typo PR by maximevtush (noir-lang/noir#7425)
fix(ssa): Accurately mark binary ops for hoisting and check Div/Mod against induction variable lower bound (noir-lang/noir#7396)
feat!: remove bigint from stdlib (noir-lang/noir#7411)
chore: bump aztec-packages commit (noir-lang/noir#7415)
chore: deprecate `merkle` module of stdlib (noir-lang/noir#7413)
chore(ci): lock aztec-packages commit in CI (noir-lang/noir#7414)
feat: while statement (noir-lang/noir#7280)
TomAFrench added a commit to AztecProtocol/aztec-packages that referenced this pull request Feb 19, 2025
Automated pull of development from the
[noir](https://github.com/noir-lang/noir) programming language, a
dependency of Aztec.
BEGIN_COMMIT_OVERRIDE
fix(performance): Remove redundant slice access check from brillig
(noir-lang/noir#7434)
chore(docs): updating tutorials and other nits to beta.2
(noir-lang/noir#7405)
feat: LSP hover for integer literals
(noir-lang/noir#7368)
feat(experimental): Compile match expressions
(noir-lang/noir#7312)
feat(acir_field): Add little-endian byte serialization for FieldElement
(noir-lang/noir#7258)
feat: allow unquoting TraitConstraint in trait impl position
(noir-lang/noir#7395)
feat(brillig): Hoist shared constants across functions to the global
space (noir-lang/noir#7216)
feat(LSP): auto-import via visible reexport
(noir-lang/noir#7409)
fix(brillig): Brillig entry point analysis and function specialization
through duplication (noir-lang/noir#7277)
chore: redo typo PR by maximevtush
(noir-lang/noir#7425)
fix(ssa): Accurately mark binary ops for hoisting and check Div/Mod
against induction variable lower bound
(noir-lang/noir#7396)
feat!: remove bigint from stdlib
(noir-lang/noir#7411)
chore: bump aztec-packages commit
(noir-lang/noir#7415)
chore: deprecate `merkle` module of stdlib
(noir-lang/noir#7413)
chore(ci): lock aztec-packages commit in CI
(noir-lang/noir#7414)
feat: while statement (noir-lang/noir#7280)
END_COMMIT_OVERRIDE

---------

Co-authored-by: Tom French <tom@tomfren.ch>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bench-show Display benchmark results on PR
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Sync temp fix overriding global reachability analysis
2 participants