-
Notifications
You must be signed in to change notification settings - Fork 10.5k
SILGen: Fix order of operations when a mutating existential method returns Self. #18937
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
SILGen: Fix order of operations when a mutating existential method returns Self. #18937
Conversation
@swift-ci Please test |
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 know this is WIP, just a few minor comments. @rjmccall will hopefully do a more in-depth review because the ResultPlan stuff was his design.
lib/SILGen/ResultPlan.cpp
Outdated
SmallVector<ArchetypeType *, 4> opened; | ||
resultTy->getOpenedExistentials(opened); | ||
|
||
SmallVector<Type, 4> types; |
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 would suggest factoring out the code for building this signature and layout into a new method
// We allocate the buffer as a box because the scope nesting won't clean | ||
// this up with good stack discipline relative to any stack allocations that | ||
// occur during argument emission. Escape analysis during mandatory passes | ||
// ought to clean this up. |
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.
Would be good to add a test for that. However another approach would be to allocate a stack buffer of existential type and then open the existential late, using the same opened type as the result of the call. Would that make sense? Then at least you avoid the heap allocation if the value fits inline.
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.
This is a case where we're always going to erase the existential after the call, right? Can we shift that erasure into the result plan so that we emit into the address produced by init_existential_addr
? That would also let us actually do initialization into the context if possible.
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.
Yeah, that’s basically what I’m suggesting.
@@ -484,6 +484,9 @@ class SILType { | |||
/// Returns the underlying referent SILType of an @sil_unowned or @sil_weak | |||
/// Type. | |||
SILType getReferentType(SILModule &M) const; | |||
|
|||
/// Returns a SILType with any archetypes mapped out of context. | |||
SILType mapTypeOutOfContext() const; |
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.
Do you mind splitting this off into a separate commit and doing a quick pass over mapTypeOutOfContext() calls throughout SIL to see if it can be used anywhere else?
Build failed |
Build failed |
5d115fa
to
7102ef8
Compare
@slavapestov @rjmccall Updated to also form the concrete value buffer for existentials late as well. That doesn't quite cover all the necessary cases, since if the existential is loadable (as when we're calling a method on an opaque protocol from a class-constrained refining existential) we won't pre-allocate the return buffer, and if there's a |
@swift-ci Please test |
Build failed |
Build failed |
@jckarter An optional-of-opened-existential-to-optional-of-existential conversion could also theoretically be done in place -- emit the optional existential, project the optional payload and existential payload, and pass that as the out parameter. However it's understandable if you don't want to keep tweaking this. |
I may be misunderstanding you, but I'm hoping for now to plug enough holes in the regressions here to give us time to figure out how to do the right thing here, opening the type early while still being able to guarantee invariants when the existential is opened for mutation. |
7102ef8
to
78e533c
Compare
This does the same thing as taking the AST type and running it through mapTypeOutOfContext, but saves call sites from having to do the unwrap-rewrap dance.
78e533c
to
4ada498
Compare
@slavapestov This look OK to commit now? How would you feel about bringing this to the 4.2 branch? I'm a bit concerned about introducing new regressions with the changed order of operations in existential codegen; it ought to be benign and doesn't appear to impact any tests, but it's still a change. |
@swift-ci Please test |
@swift-ci Please test source compatibility |
1 similar comment
@swift-ci Please test source compatibility |
@swift-ci Please test |
@swift-ci Please benchmark |
1 similar comment
@swift-ci Please benchmark |
!!! Couldn't read commit file !!! |
@swift-ci Please benchmark |
!!! Couldn't read commit file !!! |
@swift-ci Please benchmark |
Build failed |
4ada498
to
c32f5c8
Compare
@swift-ci Please test |
@swift-ci Please test source compatibility |
1 similar comment
@swift-ci Please test source compatibility |
@swift-ci Please benchmark |
Build failed |
|
||
// FIXME: the dynamic self capture here has to happen after existential | ||
// opening as well. | ||
//_ = y.covariantClosureArgAndReturn({ _ in 0 }) |
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 there a bug for 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.
Yep, I filed rdar://problem/43778354.
Build failed |
Build comment file:Optimized (O)Regression (3)
Improvement (2)
No Changes (469)
Unoptimized (Onone)Regression (12)
Improvement (8)
No Changes (454)
Hardware Overview
|
… existential that returns Self. Delay allocating the result buffer for an opened Self return until right before it's needed. When a mutating method is invoked on an existential, the Self type won't be opened until late, when the formal access to the mutable value begins. Fixes rdar://problem/43507711.
c32f5c8
to
7f14a3b
Compare
@swift-ci Please test |
Build failed |
Build failed |
@swift-ci Please test Linux |
The Self type doesn't get opened until immediately before the function call in a mutating method invocation on an existential, so we have to defer formation of the result buffer to that point. rdar://problem/43507711