Skip to content

chore(opt): Memoize Type::canonicalize#8575

Closed
jfecher wants to merge 15 commits intomasterfrom
jf/optimize-canonicalize
Closed

chore(opt): Memoize Type::canonicalize#8575
jfecher wants to merge 15 commits intomasterfrom
jf/optimize-canonicalize

Conversation

@jfecher
Copy link
Contributor

@jfecher jfecher commented May 19, 2025

Description

Problem*

Resolves #8545

Summary*

Optimizes Type::canonicalize by remembering the returned result which prevents this function from being quadratic in input size since we're no longer re-doing work. This also required a small fix to keep the arithmetic_generics test working: we can't do if let Type::InfixExpr(..) = ... since that doesn't match on Type::CheckedCast variants which are meant to be transparent. With this fix that was previously causing canonicalize to leave some terms unsimplified.

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.

@jfecher jfecher requested a review from a team May 19, 2025 19:25
@jfecher jfecher changed the base branch from master to jf/typebindings May 19, 2025 19:28
Copy link
Collaborator

@asterite asterite left a comment

Choose a reason for hiding this comment

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

Nice!

I thought the solution could be memoizing but I didn't know if it was possible because types don't have IDs, though they do have equality and has so I guess it works.

It might be nice to add bench-show to see if there's any noticeable improvements in existing projects (just out of curiosity).

@asterite
Copy link
Collaborator

Um, I approved but I see there are some regressions, so maybe this broke something. In any case the changes look good.

@jfecher
Copy link
Contributor Author

jfecher commented May 19, 2025

Um, I approved but I see there are some regressions, so maybe this broke something. In any case the changes look good.

Yeah, quite large ones 😅. I'll look into those before merging. Not sure what they are currently. The main difference I can think of is that some Type::CheckedCast may be different but those should be checked at monomorphization time rather than runtime IIRC.

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: d64f0a7 Previous: d3cb2b2 Ratio
test_report_AztecProtocol_aztec-packages_noir-projects_noir-protocol-circuits_crates_blob 2 s 1 s 2
test_report_AztecProtocol_aztec-packages_noir-projects_noir-protocol-circuits_crates_rollup-lib 3 s 1 s 3
test_report_AztecProtocol_aztec-packages_noir-projects_noir-protocol-circuits_crates_types 2 s 1 s 2
test_report_zkpassport_noir_rsa_ 3 s 2 s 1.50

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

CC: @TomAFrench

@github-actions github-actions bot added the documentation Improvements or additions to documentation label May 19, 2025
@jfecher
Copy link
Contributor Author

jfecher commented May 19, 2025

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

This makes me think it is just because I didn't merge master originally.

@jfecher jfecher changed the base branch from jf/typebindings to master May 19, 2025 20:00
@github-actions
Copy link
Contributor

github-actions bot commented May 19, 2025

return None;
};
let lhs = lhs.follow_bindings();
let (l_type, l_op, l_rhs, _) = lhs.as_infix_expr()?;
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it possible that recursing to find an InfixExpr here and/or in try_unify_by_moving_constant_terms ends up removing CheckedCast's?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes - although without doing so we were failing in the arithmetic_generics test from failing to catch this case for results which were now cached to include CheckedCast where they previously dropped it

@TomAFrench
Copy link
Member

simplifying serialize a little bit, if we have the program

fn main() {
    let x = (1, [2, 3, 4]);
    assert_eq(x.serialize().len(), 4);
}

We get the initial SSA

acir(inline) fn main f0 {
  b0():
    v3 = make_array [Field 2, Field 3, Field 4] : [Field; 3]
    v6 = call f1(Field 1, v3) -> [Field; 2]   <---- Note we're expecting an array of size 2
    constrain u1 0 == u1 1
    return
}

If I change the tuple so that both elements are the same size, e.g.

fn main() {
    let x = ([1, 2, 3], [2, 3, 4]);
    assert_eq(x.serialize().len(), 4);
}

We now get the SSA

acir(inline) fn main f0 {
  b0():
    v3 = make_array [Field 1, Field 2, Field 3] : [Field; 3]
    v5 = make_array [Field 2, Field 3, Field 4] : [Field; 3]
    v7 = call f1(v3, v5) -> [Field; 6] <---- Note we're expecting an array of size 6
    constrain u1 0 == u1 1
    return
}

It seems like we're not distinguishing between the associated constants on the various subtypes making up the tuple and instead are applying the Size constant from the first element onto the rest of the tuple's elements.

@github-actions
Copy link
Contributor

github-actions bot commented Jun 4, 2025

FYI @noir-lang/developerrelations on Noir doc changes.

@jfecher
Copy link
Contributor Author

jfecher commented Jun 6, 2025

Closing this - #8826 should be a valid substitute.
The original issue is compiling faster but has errors during compilation (already captured in #8797). We can revisit/close it once the unrelated errors are fixed.

@jfecher jfecher closed this Jun 6, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Type::canonicalize is slow

4 participants