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]: https://github.com/apple/swift/pull/28799
[^2]: https://forums.swift.org/t/wasm-support/16087/21
When building the label for the IAT synthetic, we need to pre-decorate
the symbol before we apply the synthetic symbol prefix lest we end up
placing the user-label prefix over the synthetic symbol rather than the
actual symbol. This is required to correctly resolve symbols when
building the standard library for x86.
In order to allow this, I've had to rework the syntax of substituted function types; what was previously spelled `<T> in () -> T for <X>` is now spelled `@substituted <T> () -> T for <X>`. I think this is a nice improvement for readability, but it did require me to churn a lot of test cases.
Distinguishing the substitutions has two chief advantages over the existing representation. First, the semantics seem quite a bit clearer at use points; the `implicit` bit was very subtle and not always obvious how to use. More importantly, it allows the expression of generic function types that must satisfy a particular generic abstraction pattern, which was otherwise impossible to express.
As an example of the latter, consider the following protocol conformance:
```
protocol P { func foo() }
struct A<T> : P { func foo() {} }
```
The lowered signature of `P.foo` is `<Self: P> (@in_guaranteed Self) -> ()`. Without this change, the lowered signature of `A.foo`'s witness would be `<T> (@in_guaranteed A<T>) -> ()`, which does not preserve information about the conformance substitution in any useful way. With this change, the lowered signature of this witness could be `<T> @substituted <Self: P> (@in_guaranteed Self) -> () for <A<T>>`, which nicely preserves the exact substitutions which relate the witness to the requirement.
When we adopt this, it will both obviate the need for the special witness-table conformance field in SILFunctionType and make it far simpler for the SILOptimizer to devirtualize witness methods. This patch does not actually take that step, however; it merely makes it possible to do so.
As another piece of unfinished business, while `SILFunctionType::substGenericArgs()` conceptually ought to simply set the given substitutions as the invocation substitutions, that would disturb a number of places that expect that method to produce an unsubstituted type. This patch only set invocation arguments when the generic type is a substituted type, which we currently never produce in type-lowering.
My plan is to start by producing substituted function types for accessors. Accessors are an important case because the coroutine continuation function is essentially an implicit component of the function type which the current substitution rules simply erase the intended abstraction of. They're also used in narrower ways that should exercise less of the optimizer.
The logic here used to consist of a couple of ad-hoc checks,
followed by a general assumption that if something had already
been emitted, it could be referenced directly, whereas everything
else had to go through a GOT entry.
This is way too conservative. Instead, let's try to correctly
calculate what translation unit an entity is going to end up in.
Now that `swift-reflection-dump` correctly handles pointer values and unresolved
cross-image references (for Mach-O, at least), we can safely unconditionally use
symbolic references in runtime mangled names without regressing offline reflection
support.
Asking for the layout of the interface type apparently gives the wrong answer,
causing key paths to access stored properties of generic classes using the wrong
strategy.
Fixes SR-10167 | rdar://problem/49230751.
The IRGen test had wrong offsets for inline String element on tuples kp on 32-bit platforms
The stdlib test had hardcoded offsets (assumed 64-bit host) for tuple kp elements (Memorylayout)
Update the IRGen tests for Windows IRGen. This is an improvement over
what we have currently, but is not sufficient to get all the IRGen tests
passing yet.
In a previous commit, I banned in the verifier any SILValue from producing
ValueOwnershipKind::Any in preparation for this.
This change arises out of discussions in between John, Andy, and I around
ValueOwnershipKind::Trivial. The specific realization was that this ownership
kind was an unnecessary conflation of the a type system idea (triviality) with
an ownership idea (@any, an ownership kind that is compatible with any other
ownership kind at value merge points and can only create). This caused the
ownership model to have to contort to handle the non-payloaded or trivial cases
of non-trivial enums. This is unnecessary if we just eliminate the any case and
in the verifier separately verify that trivial => @any (notice that we do not
verify that @any => trivial).
NOTE: This is technically an NFC intended change since I am just replacing
Trivial with Any. That is why if you look at the tests you will see that I
actually did not need to update anything except removing some @trivial ownership
since @any ownership is represented without writing @any in the parsed sil.
rdar://46294760
This can happen when emitting an inlinable function in a resilient
module, because inlinable functions use the most conservative
access pattern.
This allows some earlier tests for keypaths inside inlinable
functions to pass IR emission, too.
An existing test used an external reference within the same module
to test external references; move this part to a separate test that
builds a separate module to correctly test this functionality.
Always use mangled type names to represent type metadata in keypath patterns.
For generic types, use the generic environment to pull substituted types
from the instantiation arguments.
Finishes the type metadata part of rdar://problem/38038799.
Extend the key-path pattern with a representation of the generic environment
of the key-path, which includes the generic parameters and generic
requirements of the environment.
When a type in keypath metadata is non-dependent, use a mangled type name
rather than a symbolic reference to an accessor function.
Part of rdar://problem/38038799.
Switch key path metadata over to mangled names for each of the places it
refers to either a type metadata accessor or a witness table accessor. For
now, the mangled name is a symbolic reference to the existing accessors.
Part of rdar://problem/38038799.
We were emitting relative references to entities that might be in
another translation unit. Use a GOT entry or thunk where appropriate.
Fixes <rdar://problem/45901706>.
Use relative references instead of pointers so that the pattern can be true-const. Instead of trying
to instantiate a constant key path literal in-place, point to a cache variable that we can store
a pointer to the shared instance into when instantiated. Now that the pattern format has diverged
significantly from the instance format, simplify and refactor the instantiation code using a walker
for the pattern format instead of trying to reuse the code for working with instantiated instances.
rdar://problem/42674576
The constraint solver support for the Swift 3 function type behavior
has been removed, so it's no longer possible to pun the same value as
both a function taking multiple parameters and a function taking a
single tuple argument.
This means the entire parameter list is no longer a target for
substitution as a single value, so the most general form of a function
value passes each parameter indirectly instead of passing a single
tuple parameter indirectly.
Make sure the implementation can handle a key path with zero components by removing inappropriate assumptions that the number of components is always non-empty. Identity key paths also need some special behavior:
- Appending an identity key path should be an identity operation for the other operand
- Identity key paths have a `MemoryLayout.offset(of:)` zero
- Identity key paths interop with KVC as key paths to `@"self"`
To be able to exercise and test this behavior, add a `Builtin.identityKeyPath()` function and `WritableKeyPath._identity` accessor in lieu of finalized syntax.
If we know a key path component can be accessed as a stored property, then we should also know whether it's a `let` or not, so it should be safe to encode this in the key path pattern. Stage this change in by changing the number of bits used to store in-line offsets, fixing up the parts of the key path implementation that assumed that it took up the entire payload bitfield.
This is how we originally controlled whether or not we printed out ownership
annotations when we printed SIL. Since then, I have changed (a few months ago I
believe) the ownership model eliminator to know how to eliminate these
annotations from the SIL itself. So this hack can be removed.
As an additional benefit, this will let me rename -enable-sil-ownership to
-enable-sil-ownership-verifier. This will I hope eliminate confusion around this
option in the short term while I am preparing to work on semantic sil again.
rdar://42509812
The other side of #17404. Since we don't want to generate up front key path metadata for properties/subscripts with no withheld implementation details, the client should generate a key path component that can be used to represent a key path component based on its public interface.
This adds the dllstorage annotations on the tests. This first pass gets
most of the IRGen tests passing on Windows (though has dependencies on
other changes). However, this allows for the changes to be merged more
easily as we cannot regress other platforms here.
Ensure that we use the correct python to run the python based tools.
This also allows these tools to run on Windows which will not
necessarily associate the python script with an interpreter (python).
I am going to leave in the infrastructure around this just in case. But there is
no reason to keep this in the tests themselves. I can always just revert this
and I don't think merge conflicts are likely due to previous work I did around
the tooling for this.