-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Centralize KeyPath accessor calling convention logic to IRGen #66273
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
Centralize KeyPath accessor calling convention logic to IRGen #66273
Conversation
902c9c4
to
0d76818
Compare
KeyPathAccessorGetter, | ||
KeyPathAccessorSetter, | ||
KeyPathAccessorEquals, | ||
KeyPathAccessorHash, |
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 think it's the ideal design to have conventions for each signature, but I couldn't come up with better ideas...
Currently, accessors are represented by the following in SIL:
sil hidden @testGetter : $@convention(keypath_accessor_getter) (@in_guaranteed S, @in_guaranteed (S, C)) -> @out Int
sil hidden @testSetter : $@convention(keypath_accessor_setter) (@in_guaranteed Int, @in_guaranteed S, @in_guaranteed (S, C)) -> ()
sil hidden @testEq : $@convention(keypath_accessor_equals) (@in_guaranteed (S, C), @in_guaranteed (S, C)) -> Bool
sil hidden @testHash : $@convention(keypath_accessor_hash) (@in_guaranteed (S, C)) -> Int
As a possible idea, if having a single @convention(keypath_accessor)
and put new ParameterConvention attributes like @keypath_argument_buffer
:
sil hidden @testGetter : $@convention(keypath_accessor) (@in_guaranteed S, @keypath_argument_buffer (S, C)) -> @out Int
sil hidden @testSetter : $@convention(keypath_accessor) (@in_guaranteed Int, @in_guaranteed S, @keypath_argument_buffer (S, C)) -> ()
sil hidden @testEq : $@convention(keypath_accessor) (@keypath_argument_buffer (S, C), @keypath_argument_buffer (S, C)) -> Bool
sil hidden @testHash : $@convention(keypath_accessor) (@keypath_argument_buffer (S, C)) -> Int
But unlike other ParameterConventions, @keypath_argument_buffer
is not only how the parameter should be passed but also a marker to determine where generic parameters should be retrieved from. So I'm unsure whether this new @keypath_argument_buffer
matches the ParameterConvention's concept or not.
What do you think about this, and do you have any other ideas? It would be much appreciated if I can have any comment from @jckarter 🙏
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 think it's better to have one convention if possible. The argument buffer from which we bind generic parameters is always the last argument, so we could have that be an implicit property of the convention, just like how the self
or context
argument for @convention(method)
is always the final argument.
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.
Thank you for your comment 🙏
Oh, I overlooked @convention(method)
! It makes sense to me to have such implicit property. I'll update the patch.
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.
Looking a bit longer term, for partial apply elimination, I want to extend SILBoxType
to have a "nonescaping" flavor to explicitl represent the context parameter for nonescaping closures. These have the same need to capture and rebind the generic environment from a parameter (as represented by the @capturesGenericEnvironment
attribute), so maybe once that is implemented we could also use it for keypath accessors with the normal thin
convention. That's a ways away, though, so I think introducing a new convention is fine for 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.
@jckarter While updating the patch to have one unified convention, I found we can't have an implicit property that takes generic parameters from the last argument because getter and setter accessors don't always have indices.
IRGen needs to know whether a keypath getter/setter accessor function has indices or not because:
- IRGen needs to add dummy keypath argument buffer pointer to IR-level parameters to have a stable signature
- If the accessor doesn't have indices but has generic parameters, it can omit a GEP to offset the argument buffer pointer to retrieve generic parameters at runtime.
SILGen of course knows hasIndices
info but IRGen doesn't if we use one unified convention and no explicit marker.
For example, Getter with indices ((base: Foo, indices: (Int, String))
) and setter without indices ((value: Bar, base: (Int, String))
) have the same number of parameters and both can have trailing tuple parameter.
The former doesn't need dummy keypath argument buffer pointer to IR-level parameters, but the latter needs it. However, they cannot be distinguished during IRGen as far as I know.
I also tried to put a trailing empty tuple parameter even though the accessor doesn't have indices during SILGen, but we still need hasIndices
info at IRGen to avoid extra GEP.
So I think we need something marker to propagate hasIndices
info. I'd like to hear your thoughts and which direction we should go (four conventions or parameter attribute or other) 🙏
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.
@jckarter gentle ping :)
0d76818
to
563aba2
Compare
563aba2
to
3fb1ca7
Compare
|
Thinking about this more, using a function attribute would be kinda unfortunate -- the signature of a function should be all that is needed to determine its ABI. Using a function attribute would require to look at the function declaration to get the final ABI that would be very unfortunate. Ignore my above suggestion. |
0eda21a
to
8cd672b
Compare
@swift-ci Please smoke test |
… and caller signature This is a legacy solution for the KeyPath calling convention problem described in https://forums.swift.org/t/wasm-support/16087/21. This patch will be replaced by swiftlang#66273
8cd672b
to
53a2c3f
Compare
@swift-ci Please smoke test |
@swift-ci build toolchain |
preset=buildbot_incremental_linux_crosscompile_wasm |
@swift-ci Please smoke test Windows platform |
@swift-ci build toolchain Windows platform |
The preset CI job is failing due to completely unrelated issue (will be fixed by #68527), so it's now ready for review! |
preset=buildbot_incremental_linux_crosscompile_wasm |
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.
Looks good to me
53a2c3f
to
55e63d7
Compare
@swift-ci Please smoke test and merge |
KeyPath's getter/setter/hash/equals functions have their own calling convention, which receives generic arguments and embedded indices from a given KeyPath argument buffer. The convention was previously implemented by: 1. Accepting an argument buffer as an UnsafeRawPointer and casting it to indices tuple pointer in SIL. 2. Bind generic arguments info from the given argument buffer while emitting prologue in IRGen by creating a new forwarding thunk. This 2-phase lowering approach was not ideal, as it blocked KeyPath projection optimization [^1], and also required having a target arch specific signature lowering logic in SIL-level [^2]. This patch centralizes the KeyPath accessor calling convention logic to IRGen, by introducing `@convention(keypath_accessor_XXX)` convention in SIL and lowering it in IRGen. This change unblocks the KeyPath projection optimization while capturing subscript indices, and also makes it easier to support WebAssembly target. [^1]: swiftlang#28799 [^2]: https://forums.swift.org/t/wasm-support/16087/21
55e63d7
to
c5314bd
Compare
@swift-ci Please smoke test and merge |
Motivation
Resolves rdar://113910207.
KeyPath's getter/setter/hash/equals functions have their own calling convention, which receives generic arguments and embedded indices from a given KeyPath argument buffer.
The convention was previously implemented by:
This 2-phase lowering approach was not ideal, as it blocked KeyPath projection optimization 1, and also required having a target arch specific signature lowering logic in SIL-level 2.
Description
This patch centralizes the KeyPath accessor calling convention logic to IRGen, by introducing
@convention(keypath_accessor_XXX)
convention in SIL and lowering it in IRGen. The accessor functions now accept indices as tuple instead of UnsafeRawPointer in SIL level.This change unblocks the KeyPath projection optimization while capturing subscript indices, and also makes it easier to support WebAssembly target.
ABI concerns
Merge plan
TBD
Footnotes
https://github.com/apple/swift/pull/28799 ↩
https://forums.swift.org/t/wasm-support/16087/21 ↩