fix: Defunctionalize foreign functions in pre-SSA pass over mAST#10160
fix: Defunctionalize foreign functions in pre-SSA pass over mAST#10160
Conversation
There was a problem hiding this comment.
⚠️ 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: eb39da3 | Previous: 9b08130 | Ratio |
|---|---|---|---|
sha512-100-bytes |
0.072 s |
0.053 s |
1.36 |
This comment was automatically generated by workflow using github-action-benchmark.
CC: @TomAFrench
There was a problem hiding this comment.
⚠️ 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: eb39da3 | Previous: 9b08130 | 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
#[oracle] functions#[oracle] functions
#[oracle] functions#[oracle] functions in pre-SSA pass over mAST
Can you elaborate on this? I'm not sure why we'd need a new pass for this versus adding a |
|
When the monomorphizer encounters a call, it looks up the definition of the called function, and if it hasn't existed yet, it enqueues it, knowing that its ID will be the same. Then, we pick an ID from the queue and elaborate it by looking up the definition of it in the interner. To change this, what I thought I'd have to do is check that the call I'm making to is an oracle, and then come up with some ID I can call instead of the oracle, and enqueue that ID for monomorphization, but when we get that ID from the queue, there is no regular definition for it in the interner like there is for local functions, and instead it needs to rely on other information to synthesise a function. I'm sure this is all doable, but I thought it would be much easier to write it as a separate pass, which I was already familiar with, then for me add this aspect to the monomorphizer itself. |
I'm not sure where this check would be added to be honest. As I understood we only monomorphized user-defined functions, while oracle and intrinsics did not need to be enqueued for monomorphization, they were functions identified by "name". That's why I didn't want to go into this: the queue does not expect a foreign function in it, and then I don't know what definition to look up for them in the thing that processes the queue, so I would have had to add more context data captured during the enqueueing of the foreign function. I thought encapsulating all this into a separate pass that doesn't need to touch anything in the elaborator is cleaner. I wasn't sure if it somehow makes the elaborator "incomplete" that it produces code that isn't meant to be final, but since ownership analysis also modifies the AST, and there is no way to skip this, we can consider it part of the elaboration, even if the means to achieve it lay outside the purview of the queue processing logic. |
|
I see that the looking up the definition itself is the same What I wasn't sure about is that the Altogether, yes, this seems doable, but I found it more straight forward to recognise when a function is a value in the mAST, and knew how to generate a body for it. Since the machinery in the For example it didn't look like I can call |
jfecher
left a comment
There was a problem hiding this comment.
I'm going to try some alternate methods of this PR to see if they pan out or if they're worse than expected. This has been up for a little while already so if they don't pan out I'll approve and we can get this merged to solve the issue now.
There was a problem hiding this comment.
⚠️ Performance Alert ⚠️
Possible performance regression was detected for benchmark 'Compilation Time'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.20.
| Benchmark suite | Current: eac13e1 | Previous: 9b08130 | Ratio |
|---|---|---|---|
private-kernel-inner |
2.068 s |
1.702 s |
1.22 |
private-kernel-tail |
1.706 s |
1.35 s |
1.26 |
This comment was automatically generated by workflow using github-action-benchmark.
CC: @TomAFrench
#[oracle] functions in pre-SSA pass over mAST
vezenovm
left a comment
There was a problem hiding this comment.
@jfecher I will leave final approval to you. As mentioned in #10160 (comment) I would still like to follow-up with always wrapping intrinsics/oracles in the elaborator.
jfecher
left a comment
There was a problem hiding this comment.
Agreed that we can merge this now and focus on a follow-up later if needed
Automated pull of nightly from the [noir](https://github.com/noir-lang/noir) programming language, a dependency of Aztec. BEGIN_COMMIT_OVERRIDE fix(brillig_gen): Switch to iterative variable liveness (noir-lang/noir#10460) feat: remove unnecessary mutation of blackbox functions during flattening (noir-lang/noir#10182) chore: revert "fix: revert "feat(ACIR): reuse element_type_sizes blocks with… (noir-lang/noir#10461) chore: green light for acir (native_types) audit (noir-lang/noir#10381) chore: lock Cargo.lock in cargo-binstall (noir-lang/noir#10459) fix(acir-gen): Use the side effect variable in `slice_pop_back` (noir-lang/noir#10455) fix: correct location for out of bounds match case integer (noir-lang/noir#10454) fix: Defunctionalize foreign functions in pre-SSA pass over mAST (noir-lang/noir#10160) fix: use unit for fmtstr without variables (noir-lang/noir#10456) chore(docs): Update tinyjs app tutorial for versioned docs (noir-lang/noir#10453) fix(frontend): Resolve to correct type on fmtstr interpolation error (noir-lang/noir#10450) fix: avoid producing duplicate private error messages (noir-lang/noir#10449) chore(docs): update dependencies and installation instructions in NoirJS tutorial and examples (noir-lang/noir#10400) fix(compiler): Improve error message for impl on primitive types (noir-lang/noir#10430) (noir-lang/noir#10442) chore: get trait as non-mut (noir-lang/noir#10447) chore(frontend): Tuple dereference chain unit test and minor method reorg (noir-lang/noir#10410) fix(doc): analyze sub-modules imports before self (noir-lang/noir#10390) chore: green light for blackbox_solver audit (noir-lang/noir#10372) chore: use `get_last_condition` in `link_condition` (noir-lang/noir#10424) chore: bump external pinned commits (noir-lang/noir#10443) feat: primitive types doc comments (noir-lang/noir#10432) chore(frontend): Trait impl Self path unit tests (noir-lang/noir#10437) END_COMMIT_OVERRIDE
Automated pull of nightly from the [noir](https://github.com/noir-lang/noir) programming language, a dependency of Aztec. BEGIN_COMMIT_OVERRIDE fix(brillig_gen): Switch to iterative variable liveness (noir-lang/noir#10460) feat: remove unnecessary mutation of blackbox functions during flattening (noir-lang/noir#10182) chore: revert "fix: revert "feat(ACIR): reuse element_type_sizes blocks with… (noir-lang/noir#10461) chore: green light for acir (native_types) audit (noir-lang/noir#10381) chore: lock Cargo.lock in cargo-binstall (noir-lang/noir#10459) fix(acir-gen): Use the side effect variable in `slice_pop_back` (noir-lang/noir#10455) fix: correct location for out of bounds match case integer (noir-lang/noir#10454) fix: Defunctionalize foreign functions in pre-SSA pass over mAST (noir-lang/noir#10160) fix: use unit for fmtstr without variables (noir-lang/noir#10456) chore(docs): Update tinyjs app tutorial for versioned docs (noir-lang/noir#10453) fix(frontend): Resolve to correct type on fmtstr interpolation error (noir-lang/noir#10450) fix: avoid producing duplicate private error messages (noir-lang/noir#10449) chore(docs): update dependencies and installation instructions in NoirJS tutorial and examples (noir-lang/noir#10400) fix(compiler): Improve error message for impl on primitive types (noir-lang/noir#10430) (noir-lang/noir#10442) chore: get trait as non-mut (noir-lang/noir#10447) chore(frontend): Tuple dereference chain unit test and minor method reorg (noir-lang/noir#10410) fix(doc): analyze sub-modules imports before self (noir-lang/noir#10390) chore: green light for blackbox_solver audit (noir-lang/noir#10372) chore: use `get_last_condition` in `link_condition` (noir-lang/noir#10424) chore: bump external pinned commits (noir-lang/noir#10443) feat: primitive types doc comments (noir-lang/noir#10432) chore(frontend): Trait impl Self path unit tests (noir-lang/noir#10437) END_COMMIT_OVERRIDE
Automated pull of nightly from the [noir](https://github.com/noir-lang/noir) programming language, a dependency of Aztec. BEGIN_COMMIT_OVERRIDE fix(brillig_gen): Switch to iterative variable liveness (noir-lang/noir#10460) feat: remove unnecessary mutation of blackbox functions during flattening (noir-lang/noir#10182) chore: revert "fix: revert "feat(ACIR): reuse element_type_sizes blocks with… (noir-lang/noir#10461) chore: green light for acir (native_types) audit (noir-lang/noir#10381) chore: lock Cargo.lock in cargo-binstall (noir-lang/noir#10459) fix(acir-gen): Use the side effect variable in `slice_pop_back` (noir-lang/noir#10455) fix: correct location for out of bounds match case integer (noir-lang/noir#10454) fix: Defunctionalize foreign functions in pre-SSA pass over mAST (noir-lang/noir#10160) fix: use unit for fmtstr without variables (noir-lang/noir#10456) chore(docs): Update tinyjs app tutorial for versioned docs (noir-lang/noir#10453) fix(frontend): Resolve to correct type on fmtstr interpolation error (noir-lang/noir#10450) fix: avoid producing duplicate private error messages (noir-lang/noir#10449) chore(docs): update dependencies and installation instructions in NoirJS tutorial and examples (noir-lang/noir#10400) fix(compiler): Improve error message for impl on primitive types (noir-lang/noir#10430) (noir-lang/noir#10442) chore: get trait as non-mut (noir-lang/noir#10447) chore(frontend): Tuple dereference chain unit test and minor method reorg (noir-lang/noir#10410) fix(doc): analyze sub-modules imports before self (noir-lang/noir#10390) chore: green light for blackbox_solver audit (noir-lang/noir#10372) chore: use `get_last_condition` in `link_condition` (noir-lang/noir#10424) chore: bump external pinned commits (noir-lang/noir#10443) feat: primitive types doc comments (noir-lang/noir#10432) chore(frontend): Trait impl Self path unit tests (noir-lang/noir#10437) END_COMMIT_OVERRIDE
Description
Problem*
Resolves #10156
Resolves #10154
Summary*
Adds a new
create_foreign_proxiesmethod to the monomorphizedProgram, similar tohandle_ownership, which is executed inmonomorphize_debug, as a pass on the AST before SSA generation.The pass finds all instances where we use a "foreign" function as a value - where "foreign" can be intrinsic, oracle or built-in function identifier -, creates proxy functions to call them, and replaces the definition in the identifiers with the ID of the new global function. After this pass we should only ever see function values refer to global functions, and only direct calls refer to intrinsic/builtin/oracle functions.
Further changes:
defuncitonalize_pre_checkto ascertain that we no longer have non-global functions as values.visitormodule from the AST fuzzer to the monomorphization module.to_hir_typefunction in the AST fuzzer, to handle function types and convert them back to non-tuple HIR type. Made theMonomorphizerpublic so that I can add a property based test thatMonomorphizer::convert_typeandType::to_hir_typeare on the same page. (We already agreed that theMonomorphizercan be public in chore: monomorphizer public fields #9979).IntrinsicorOraclehas to be printed, but use the hash instead, although now this shouldn't come up, since there will always be a wrapper with a global ID.Additional Context
Started by handling oracle and intrinsic functions in the SSA interpreter printing so that Initial SSA can be processed, thinking I'd be replacing these values during the
defuncitonalizepass with wrapper functions, but then realised the wrapping will have to happen in the monomorphizer, which will solve it even for the Initial SSA.I looked at the monomorphizer queue, and thought that while it would be possible to extend the queue mechanism to non-global functions, it would go against the grain of it more than adding a post-processing pass to create new function. The current queue processing logic expects to be able to find the definition of a function in the NodeInterner, whereas these new ones would not exists, and would have to be projected based on the definition of something else.
I thought this can be achieved without making the monomorphizer more complicated by traversing the AST.
I found it a little surprising that an identifier for a function looks something like this:
This is true in both of these cases:
The first one will appear in the AST as
Callwith anargumentsofvec![Tuple(vec![Ident, Ident])], where both idents are the same, carrying both constrained and unconstrained in their type:while the second has just 1
IdentinCall::func, but its type is again a tuple of functions:I initially thought there would be two idents with the same definition (e.g.
Intrinsic), and theIdent::typwould beType::Function.The fact at there is a
Expression::Tuplemakes it easy to detect when we are dealing with a function value, and then seek confirmation from theIdent::typwhich should also be a tuple ofType::Functionwithfalseandtrueforunconstrained.Example
Documentation*
Check one:
PR Checklist*
cargo fmton default settings.