Support for addresses with arbitrary alignment as opposed to their
element type's natural in-memory alignment.
Required for bytestream encoding/decoding without resorting to memcpy.
SIL instruction flag, documentation, printing, parsing, serialization,
and IRGen.
This is a new instruction that can be used by SILGen to perform a semantic move
in between two entities that are considered separate variables at the AST
level. I am going to use it to implement an experimental borrow checker.
This PR contains the following:
1. I define move_value, setup parsing, printing, serializing, deserializing,
cloning, and filled in all of the visitors as appropriate.
2. I added createMoveValue and emitMoveValueOperation SILBuilder
APIs. createMoveValue always creates a move and asserts is passed a trivial
type. emitMoveValueOperation in contrast, will short circuit if passed a
trivial value and just return the trivial value.
3. I added IRGen tests to show that we can push this through the entire system.
This is all just scaffolding for the instruction to live in SIL land and as of
this PR doesn't actually do anything.
It's not sufficient to first serialize all functions and then serialize all globals, because a function can be referenced from the initializer expression of a global.
Therefore the worklist processing must include both, functions and globals.
This fixes a crash in the serializer, which is exposed through cross-module-optimization.
https://bugs.swift.org/browse/SR-15162
rdar://82827256
The new flag will be used to track whether a borrow scope corresponds to
a source-level lexical scope. Here, the flag is just added to the
instruction and represented in textual and serialized SIL.
While the comment is correct to state that this won't enable any
new optimizations with -Onone, it does enable IRGen's lazy
function emission, which is important for 'reasync' functions,
which we don't want to emit at all even at -Onone.
This fixes debug stdlib builds with the new reasync versions
of the &&, || and ?? operators.
Refactor SILGen's ApplyOptions into an OptionSet, add a
DoesNotAwait flag to go with DoesNotThrow, and sink it
all down into SILInstruction.h.
Then, replace the isNonThrowing() flag in ApplyInst and
BeginApplyInst with getApplyOptions(), and plumb it
through to TryApplyInst as well.
Set the flag when SILGen emits a sync call to a reasync
function.
When set, this disables the SIL verifier check against
calling async functions from sync functions.
Finally, this allows us to add end-to-end tests for
rdar://problem/71098795.
There is some sort of ASAN issue that this exposes on Linux, so I am going to do
this on Darwin and then debug the Linux issue using ASAN over the weekend/next
week.
`get_async_continuation[_addr]` begins a suspend operation by accessing the continuation value that can resume
the task, which can then be used in a callback or event handler before executing `await_async_continuation` to
suspend the task.
Previously we were linking in all SIL entities
if the input was a serialized non-SIB AST, and
`-disable-sil-linking` wasn't specified. However
none of the tests appear to want this behaviour.
Stop calling `SerializedSILLoader::getAll`, and
remove the `-disable-sil-linking` option, as this
is now the default behaviour.
Failing tests that do not test mandatory combine are updated to skip
the mandatory combine pass. Othere tests are updated to use otherwise
removed values.
CocoaError.Code.fileReadUnknown conflicts with the CHECK-NOT line here.
We should be checking more specifically for UnknownBlock and UnknownCode
anyways.
rdar://53284293
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.
This patch implements movable guaranteed scopes in ossa. This pattern is
currently not generated anywhere in the compiler, but my hope is to begin
emitting these in SemanticARCOpts. The idea is that these model true phi nodes
and thus can be used to fuse multiple guaranteed scopes into one using br
instructions. This is treated similarly to how owned instructions are forwarded
through /all/ terminators. This will enable us to use the SILSSAUpdater with
guaranteed arguments as well as enable the expression of sets of borrow scopes
that minimally jointly-dominate a guaranteed argument. This will enable us to
express +0 merge points like the following:
```
bb1:
%0a = begin_borrow %0 : $Klass
br bb3(%0a : $Klass)
bb2:
%1a = load_borrow %1 : $*Klass
br bb3(%1a : $Klass)
bb3(%2 : @guaranteed $Klass)
...
end_borrow %2 : $Klass
```
I describe below what the semantics of guaranteed block arguments were
previously, what they are now, and a little bit of interesting things from a
semantic perspective around implicit sub-scope users.
Before this patch in ossa, guaranteed block arguments had two different sets of
semantics:
1. Given a checked_cast_br or a switch_enum, the guaranteed block argument was
treated like a forwarding instruction. As such, the guaranteed argument's did
not require an end_borrow and its uses were validated as part of the use list
of the switch_enum/checked_cast_br operand's borrow introducer. It also was
not classified as a BorrowScopeValueIntroducer since it was not introducing a
new scope.
2. Given any other predecessor terminator, we treated the guaranteed argument as
a complete sub-scope of its incoming values. Thus we required the guaranteed
argument to have its lifetime eneded by an end_borrow and that all incoming
values of the guaranteed argument to come from a borrow introducer whose set
of jointly post-dominating end_borrows also jointly post-dominates the set of
end_borrows associated with the guaranteed argument itself. Consider the
following example:
```
bb0:
%1 = begin_borrow %foo : $Foo // (1)
%2 = begin_borrow %foo2 : $Foo2 // (2)
cond_br ..., bb1, bb2
bb1:
br bb3(%1 : $Foo)
bb2:
br bb3(%2 : $Foo)
bb3(%3 : @guaranteed $Foo)
...
end_borrow %3 : $Foo // (3)
end_borrow %2 : $Foo // (4)
end_borrow %1 : $Foo // (5)
...
```
Notice how due to SSA, (1) and (2) must dominate (4) and (5) and thus must
dominate bb3, preventing the borrows from existing within bb1, bb2.
This dominance property is actively harmful to expressivity in SIL since it
means that guaranteed arguments can not be used to express (without contortion)
sil code patterns where an argument is jointly-dominated by a minimal set of
guaranteed incoming values. For instance, consider the following SIL example:
```
bb0:
cond_br ..., bb1, bb2
bb1:
%0 = load [copy] %globalAddr : $Foo
br bb3(%0 : $Foo)
bb2:
%1 = copy_value %guaranteedFunctionArg : $Foo
br bb3(%1 : $Foo):
bb3(%2 : @owned $Foo):
apply %useFoo(%2)
destroy_value %2 : $Foo
```
As a quick proof: Assume the previous rules for guaranteed arguments. Then to
promote the load [copy] -> load_borrow and the copy_value to a begin_borrow, we
would need to place an end_borrow in bb3. But neither bb1 or bb2 dominates bb3,
so we would violate SSA dominance rules.
To enable SIL to express this pattern, we introduce a third rule for terminator
in ossa that applies only to branch insts. All other branches that obeyed the
previous rules (cond_br), still follow the old rule. This is not on purpose, I
am just being incremental and changing things as I need to. Specifically,
guaranteed arguments whose incoming values are defined by branch instructions
now act as a move on guaranteed values. The intuition here is that these
arguments are acting as true phis in an SSA sense and thus are just new names
for the incoming values. This implies since it is just a new name (not a
semantic change) that the guaranteed incoming value's guaranteed scopes should
be fused into one scope. The natural way to model this is by treating branch
insts as consuming guaranteed values. This then lets us express the example
above without using copies as follows:
```
bb0:
cond_br ..., bb1, bb2
bb1:
%0 = load_borrow %globalAddr : $Foo
br bb3(%0 : $Foo) // consumes %0 and acts as %0's end_borrow.
bb2:
// We need to introduce a new begin_borrow here since function
// arguments are required to never be consumed.
%1 = begin_borrow %guaranteedFunctionArg : $Foo
br bb3(%1 : $Foo) // consumes %1 and acts as %1's end_borrow
// %2 continues the guaranteed scope of %0, %1. This time fused with one name.
bb3(%2 : @guaranteed $Foo):
apply %useFoo(%2)
// End the lifetime of %2 (which implicitly ends the lifetime of %0, %1).
end_borrow %2 : $Foo
...
```
The main complication for users is that now when attempting to discover the set
of implicit users on an owned or guaranteed value caused by their usage as an
argument of a borrow introducer like begin_borrow. For those who are unaware, a
begin_borrow places an implicit requirement on its parent value that the parent
value is alive for the entire part of the CFG where this begin_borrow is
live. Previously, one could just look for the end_borrows of the
begin_borrow. Now one must additionally look for consuming branch insts. This is
because the original value that is being borrowed from must be alive over the
entire web of guaranteed values. That is the entire web of guaranteed values act
as a liveness requirement on the begin_borrow's operand.
The way this is implemented is given a use that we are validating, if the use is
a BorrowScopeOperand (1), we see if the borrow scope operand consumes the given
guaranteed scope and forwards it into a borrow scope introducer. If so, we add
the list of consuming uses of the borrow scope introducer to the worklist to
visit and then iterate.
In order to avoid working with cycles, for now, the ownership verifier bans
liveness requiring uses that have cycles in them. This still allows us to have
loop carried guaranteed values.
(1) A BorrowScopeOperand is a concept that represents an operand to a SIL
instruction that begins a guaranteed scope of some sort. All BorrowScopeOperand
are thus at a minimum able to compute a compile time the static region in which
they implicitly use their operands. NOTE: We do not require the scope to be
represented as a SILValue in the same function.
We achieve some nice benefit by introducing this. Specifically:
1. We can optimize the pattern I mentioned above. This is a common pattern in
many frameworks that want to return a default object if a computation fails
(with the default object usually being some sort of global or static
var). This will let us optimize that case when the global is a let global.
2. The SSA Updater can now be used with guaranteed values without needing to
introduce extra copies. This will enable predictable mem opts to introduce
less copies and for semantic arc opts to optimize the remaining copies that
PMO exposes but does not insert itself.
rdar://56720519
... including all SIL functions with are transitively referenced from such witness tables.
After the last devirtualizer run witness tables are not needed in the optimizer anymore.
We can delete witness tables with an available-externally linkage. IRGen does not emit such witness tables anyway.
This can save a little bit of compile time, because it reduces the amount of SIL at the end of the optimizer pipeline.
It also reduces the size of the SIL output after the optimizer, which makes debugging the SIL output easier.
SIL type lowering erases DynamicSelfType, so we generate
incorrect code when casting to DynamicSelfType. Fixing this
requires a fair amount of plumbing, but most of the
changes are mechanical.
Note that the textual SIL syntax for casts has changed
slightly; the target type is now a formal type without a '$',
not a SIL type.
Also, the unconditional_checked_cast_value and
checked_cast_value_br instructions now take the _source_
formal type as well, just like the *_addr forms they are
intended to replace.
The weak imported flag is now only set if the attribute is unconditionally
weak linked, which is the case when it or one of its parent contexts has a
@_weakLinked attribute.
To correctly handle weak linking based availability with serialized SIL
functions, we need to serialize the actual version tuple when the SIL function
was introduced. This is because the deployment target of the client app can
be older than the deployment target that the original module was built with.
Fixes <rdar://problem/52783668>.
...fulfilling the promised audit from 0747d9a339. No intended
functionality change /other/ than the order of already-unsorted lists.
This affected a number of SIL tests that relied on deserialization
order matching the original source order; I have no idea why the old
hash logic would make that the case. If we think that's a valuable
property, we should serialize a list of functions in addition to the
iterable table. (Maybe just in SIB mode?)
Specifically, we were preferring the always correct ownership kind specified by
the FunctionType and ignoring what we parsed from the argument. This PR changes
ossa to give a nice error when this is detected and fixes the places where this
tests were written incorrectly.
This provides a singular instruction for convert an unmanaged value to a ref,
then strong_retain it. I expanded the definition of UNCHECKED_REF_STORAGE to
include these copy like instructions. This instruction is valid in all SIL.
The reason why I am adding this instruction is that currently when we emit an
access to an unowned (unsafe) ivar, we use an unmanaged_to_ref and a strong
retain. This can look to the optimizer like a strong retain that can potentially
be optimized. By combining the two together into a new instruction, we can avoid
this potential problem since the pattern matching will break.
When deserializing an opaque type xref inside an extension context, we were looking
incorrectly in the base module of the type being extended, rather than in the module
of the extension, where the opaque type would really be. Fixes rdar://problem/51775500.
This includes a small refactoring of OpaqueTypeDecl deserialization to break the inevitable
cycle between deserializing the namingDecl, and the namingDecl turning around and re-
deserializing its opaque return type. This is NFC but avoids some unnecessary work.