Previously, when determining and completing lifetimes of scoped
addresses, `computeTransitiveLiveness` was used to determine the
liveness used for completing the lifetime.
That approach had two problems:
(1) The function does not find scope-ending uses of `load_borrow`s.
The result was determining that the lifetime of the enclosing
`store_borrow` ended before that of the `load_borrow`.
(2) The function did not complete lifetimes of values defined within the
scoped address whose lifetimes the scoped address had to contain.
This was an inconsistency between the handling of scoped addresses
and that of values.
Here, both are addressed by implementing a `TransitiveAddressWalker` (as
`computeTransitiveLiveness`'s callee does) which not only visits
existing `end_borrow`s of `load_borrows` but completes them (and other
inner guaranteed values or scoped addresses).
rdar://141246601
Complete scopes of scoped addresses (introduced by `store_borrow` and
`begin_access`) in dead end blocks via
`ScopedAddressValue::computeTransitiveLiveness`.
rdar://141037060
A begin_apply token may be used by operands that do not end the coroutine:
mark_dependence.
We need an API that gives us only the coroutine-ending uses. This blocks
~Escapable accessors.
end_borrow is considered coroutine-ending even though it does not actually
terminate the coroutine.
We cannot simply ask isLifetimeEnding, because end_apply and abort_apply do not
end any lifetime.
This API computes the re-borrow flags for guaranteed phis based on the presence of forwarding instructions in the incoming values.
This is not correct in all cases, because optimizations can optimize away forwarding instructions.
Fixes a verifier crash: rdar://139280579
I am adding this instruction to express artificially that two non-Sendable
values should be part of the same region. It is meant to be used in cases where
due to unsafe code using Sendable, we stop propagating a non-Sendable dependency
that needs to be made in the same region of a use of said Sendable value. I
included an example in ./docs/SIL.rst of where this comes up with @out results
of continuations.
In Embedded Swift, witness method lookup is done from specialized witness tables.
For this to work, the type of witness_method must be specialized as well.
Otherwise the method call would be done with wrong parameter conventions (indirect instead of direct).
For now this will only be used for HopToMainActorIfNeeded thunks. I am creating
this now since in the past there has only been one option for creating
thunks... to create the thunk in SILGen using SILGenThunk. This code is hard to
test and there is a lot of it. By using an instruction here we get a few benefits:
1. We decouple SILGen from needing to generate new kinds of thunks. This means
that SILGenThunk does not need to expand to handle more thunks.
2. All thunks implemented via ThunkInst will be easy to test in a decoupled way
with SIL tests.
3. Even though this stabilizes the patient, we still have many thunks in SILGen
and various parts of the compiler. Over time, we can swap to this model,
allowing us to hopefully eventually delete SILGenThunk.
As the optimizer uses more and more AST stuff, it's now time to create an "AST" module.
Initially it defines following AST datastructures:
* declarations: `Decl` + derived classes
* `Conformance`
* `SubstitutionMap`
* `Type` and `CanonicalType`
Some of those were already defined in the SIL module and are now moved to the AST module.
This change also cleans up a few things:
* proper definition of `NominalTypeDecl`-related APIs in `SIL.Type`
* rename `ProtocolConformance` to `Conformance`
* use `AST.Type`/`AST.CanonicalType` instead of `BridgedASTType` in SIL and the Optimizer
The main change here is to associate a witness table with a `ProtocolConformance` instead of a `RootProtocolConformance`.
A `ProtocolConformance` is the base class and can be a `RootProtocolConformance` or a `SpecializedProtocolConformance`.
* add missing APIs
* bridge the entries as values and not as pointers
* add lookup functions in `Context`
* make WitnessTable.Entry.Kind enum cases lower case
Motivated by need for protocol-based dynamic dispatch, which hasn't been possible in Embedded Swift due to a full ban on existentials. This lifts that restriction but only for class-bound existentials: Class-bound existentials are already (even in desktop Swift) much more lightweight than full existentials, as they don't need type metadata, their containers are typically 2 words only (reference + wtable pointer), don't incur copies (only retains+releases).
Included in this PR:
[x] Non-generic class-bound existentials, executable tests for those.
[x] Extension methods on protocols and using those from a class-bound existential.
[x] RuntimeEffects now differentiate between Existential and ExistentialClassBound.
[x] PerformanceDiagnostics don't flag ExistentialClassBound in Embedded Swift.
[x] WTables are generated in IRGen when needed.
Left for follow-up PRs:
[ ] Generic classes support
Some requirement machine work
Rename requirement to Value
Rename more things to Value
Fix integer checking for requirement
some docs and parser changes
Minor fixes
When computing the available region, a forward walk is done from the
non-lifetime-ending boundary of the live region. That boundary consists
of (1) the target blocks of boundary edges, (2) dead defs, and (3) last
users which are non-consuming. This forward walk is done at the block
level, so neither the specific dead def (for (2)) nor specific last
non-consuming user (for (3)) is required to perform the walk; indeed
currently these are computed and then immediately used only to obtain
the blocks in which they appear and then discarded. Avoid computing the
specific dead defs and specific last non-consuming users by switching to
a lower-fidelity liveness boundary computation via
`PrunedLivenessBlockBoundary`.
To enable those clients which care only about _blocks_ whose
instructions or dead-defs make up the liveness boundary to avoid
iterating instruction lists, enhance boundary computation with a second
type (`PrunedLivenessBlockBoundary`) and migrate some methods from
liveness onto the boundary types to enable dispatching on the boundary
type to do only the amount of analysis that's necessary.
Instead of adding a "flag" (`m` in `...Tgm5`) make it more generic to allow to drop any unused argument.
Add all dropped arguments with a `t<n-1>` (where `<n-1>` is empty for n === 0). For example `...Ttt2g5`.
Make SILLInkage available in SIL as `SIL.Linkage`.
Also, rename the misleading Function and GlobalVariable ABI `isAvailableExternally` to `isDefinedExternally`
When checking whether an instruction is contained in a liveness
boundary, a pointer to a DeadEndBlocks instance must always be passed.
When the pointer is null, it is only checked that the instruction occurs
within the direct live region. When the pointer is non-null, it is
checked whether the instruction occurs within the region obtained by
extending the live region up to the availability boundary within
dead-end regions that are adjacent to the non-lifetime-ending portion of
the liveness boundary.
The areUsesWithinBoundary/areUsesOutsideBoundary methods take the
dead-ends because the region that they're checking for containment
within contains more than just (is a (non-strict) superset of) the
pruned live region. On the other hand, the region also contains _less_
than (is a (non-strict) subset of) the available region. Instructions
are in this extended region only if they're in a dead-end block which is
forwards reachable from the non-lifetime-ending liveness boundary.