-
Notifications
You must be signed in to change notification settings - Fork 819
Make imported functions inexact #7993
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
base: main
Are you sure you want to change the base?
Conversation
Update the Literal constructors for funcrefs to take Type instead of HeapType to allow them to be given inexact function references types when the referenced function is an import. Use the new capability to give references to imported functions inexact types in GUFA. Add a test where this change fixes a misoptimization as well as tests where this change simply changes the nature of the misoptimization. Future PRs will fix these tests.
|
Fuzzer noticed that we didn't type imported ref.funcs correctly. Last two (non-merge) commits fix and test that. |
| if (wasm.features.hasCustomDescriptors()) { | ||
| // Add a cast, as the parent may depend on the exactness to validate. | ||
| replaceCurrent(Builder(wasm).makeRefCast(curr, curr->type)); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't have issues about needing this cast even when custom descriptors are disabled?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
None that our tests or the fuzzer can find. What concerns you, the exactness? I think you made the binary writer strip that out as needed for all instructions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For example in the test I commented on here: #7993 (comment). Shouldn't it be an IR validation error that we have an inexact reference being stored in an exact local? The binary writer would strip exactness and make the output valid, but I would have expected our validator to complain about the IR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't follow you. First, the linked comment was resolved. Second, how is an inexact reference stored in an exact local? The cast is ensuring things don't change (keeping the exact type from before, which was presumed valid).
| // This is imported, so it might be anything of the proper type. | ||
| addRoot(curr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't we still want to track that this is a reference to the imported function? It would just have an inexact type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But without knowing the identity, I think we can misoptimize? Imagine we have equality for a second, then ref.func a == ref.func a is definitely 1, but ref.func a == ref.func b is not necessarily 0 (can have duplicate imports).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But functions references cannot be compared for equality, so there is nothing to misoptimize, unless I'm missing something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did say "imagine" 😆
But, while we don't have ref.eq on functions in wasm userspace, we do have optimizations that compare functions in other ways. E.g. folding an if with ref.eq arms, or GUFA inferences. I admit I don't see an actual bug atm in our optimizer, but a future one is conceivable.
| @@ -0,0 +1,36 @@ | |||
| ;; Import a function of type $C as type $A, cast to $A, $B, $C. All those casts | |||
| ;; should succeed. Exact casts, however TODO | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this still TODO?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, just some old text. These casts become exact. Cleaned up now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add some exact casts to the test to show that they work as expected. I don't think the test currently demonstrates that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, added.
| ;; CHECK-NEXT: (ref.test (ref (exact $func)) | ||
| ;; CHECK-NEXT: (ref.func $f) | ||
| ;; CHECK-NEXT: ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment suggests we should have been able to optimize this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, I think we need to look at finality in GUFA somehow. I added a TODO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suspect this will be fixed by using a non-exact Literal for references to function imports.
Co-authored-by: Thomas Lively <[email protected]>
Co-authored-by: Thomas Lively <[email protected]>
Defined functions remain exact, but imported ones are inexact.
This is a step along the recent Custom Descriptors spec changes.
RefFunc::finalizeandLiteral::makeFuncvariants get the module, and look upthe type there.
Builder::makeRefFuncvariant gets a Type and applies it. The HeapTypevariant does a lookup on the module (so the Type one is more efficient/applicable
if the IR is not fully built yet).
look up the type of the import; see changelog, this seems the least-annoying way to
update here, avoiding new APIs, and less breakage for users - hopefully none, all our
tests here pass as is).