Specifically for 6.2, we are making optimize hop to executor more conservative
around caller isolation inheriting functions. This means that we are:
1. No longer treating calls to caller isolation inheriting functions as having a
hop in their prologue. In terms of this pass, it means that when determining
dead hop to executors, we no longer think that a caller isolation inheriting
function means that an earlier hop to executor is not required.
2. Treating returns from caller isolation inheriting callees as requiring a
hop. The reason why we are doing this is that we can no longer assume that our
caller will hop after we return.
Post 6.2, there are three main changes we are going to make:
* Forward Dataflow
Caller isolation inheriting functions will no longer be treated as suspension
points meaning that we will be able to propagate hops over them and can assume
that we know the actor that we are on when we enter the function. Practically
this means that trees of calls that involve just nonisolated(nonsending) async
functions will avoid /all/ hop to executor calls since we will be able to
eliminate all of them since the dataflow will just propagate forward from the
entrance that we are already on the actor.
* Backwards Dataflow
A caller isolation inheriting call site will still cause preceding
hop_to_executor functions to be live. This is because we need to ensure that we
are on the caller isolation inheriting actor before we hit the call site. If we
are already on that actor, the hop will be eliminated by the forward pass. But
if the hop has not been eliminated, then the hop must be needed to return us to
the appropriate actor.
We will also keep the behavior that returns from a caller isolation inheriting
function are considered to keep hop to executors alive. If we were able to
propagate to a hop to executor before the return inst with the forward dataflow,
then we know that we are guaranteed to still be on the relevant actor. If the
hop to executor is still there, then we need it to ensure that our caller can
treat the caller isolation inheriting function as a non-suspension point.
rdar://155905383
tryJoinIfDestroyConsumingUseInSameBlock replaces a copy with its operand
when there is no use of the copy's operand between the copy's forwarded consuming use
and the copy operand's destroy in the same block. It is illegal to do this transformation
when there is a non-consuming use of the copy operand after the forwarded consuming use of the copy.
The code checking this illegal case was not considerin the case where the consuming use of the copy
was in the same instruction as the non-consuming use of the copy operand.
rdar://154712867
We insert end_cow_mutation_addr for lifetime dependent values dependent on mutable addresses.
end_cow_mutation_addr can be simplified to end_cow_mutation after other optimizations like inlining, specialization etc
This PR adds an instruction simplification to transform end_cow_mutation_addr to end_cow_mutation.
This can enable array optimizations which look for end_cow_mutation.
Since LayoutPrespecialization has been enabled by default in all compiler
invocations for quite some time, it doesn't make sense for it to be treated as
experimental feature. Make it a baseline feature and remove all the
checks for it from the compiler.
SILGen already has an exception for this from -enable-actor-data-race-checks,
so there's no need for it, and it causes problems in actor inits.
Fixes rdar://155239032
The move-checker was assuming that any non-Copyable variable in a box must be
captured by a closure. The underlying problem is that the move-checker relies on
the best-effort AllocBoxToStack optimization to be perfect. But when
non-Escapable values depend on the variable, it remains boxed. That's good for
lifetime diagnostics but caused an incorrect move-checker diagnostic.
Fixes rdar://154519148 (Returning non-copyable type after accessing borrowed
field emits incorrect error about escaped closure capturing the noncopyable)
Bypess lifetime dependence diagnostics completely for immortal values. We did
not do this initially because we wanted to potentially consider a value with a missing
dependency to mean that it could not escape the current function. But now we use
`Void` as a stand-in for immortal values.
This is needed for reassigning a Span/MutableSpan to an empty, immortal
Span:
func inoutToImmortal(_ s: inout RawSpan) {
let tmp = RawSpan(_unsafeBytes: UnsafeRawBufferPointer(start: nil, count: 0))
s = _overrideLifetime(tmp, borrowing: ())
}
Fixes rdar://152572002 ([GH:#81976] Cannot reinitialize inout parameter of type
`MutableSpan<T>?`)
This is needed after running the SSAUpdater, because the updater can insert unnecessary phis in the middle of the original liverange of a value.
Fixes an ownership error.
rdar://153229472
Add a fake use for dead-end blocks. This allows gatherKnownLifetimeUses to be
used for local liveness by considering an "unreachable" instruction to generate
liveness. This is important when liveness is used as a boundary within which
access scopes may be extended. Otherwise, we are unable to extend access scopes
into dead-end blocks.
Fixes rdar://154406790 (Lifetime-dependent variable 'X' escapes its
scope but only if actor/class is final)
In OSSA, the result of an `unchecked_bitwise_cast` must immediately be
copied or `unchecked_bitwise_cast`'d again. In particular, it is not
permitted to borrow it. For example, the result can't be borrowed for
the purpose of performinig additional projections (`struct_extract`,
`tuple_extract`) on the borrowed value. Consequently, we cannot promote
an address if such a promotion would result in such a pattern. That
means we can't promote an address `%addr` which is used like
`struct_element_addr(unchecked_addr_cast(%addr))` or
`tuple_element_addr(unchecked_addr_cast(%addr))`. We can still promote
`unchecked_addr_cast(unchecked_addr_cast(%addr))`.
In ownership-lowered SIL, this doesn't apply and we can still promote
address with such projections.
rdar://153693915
Unlike addresses of indirect arguments, a pointer argument (e.g. `UnsafePointer`) can escape a function call.
For example, it can be returned.
Fixes a miscompile
rdar://154124497
To get equivalent test coverage in asserts and noasserts builds, enable
the code that triggers executing only specified subpasses in noasserts
builds.
rdar://154499140
If we have no substitution map, we still substitute types appearing
in the original function, because we need to remap any local
archetypes, which are always cloned.
However, the conformance lookup callback used for this substitution
was wrong. We should only do mapTypeOutOfContext() if we're going
to callSubstitutionMap::lookupConformance(), otherwise we form a
new abstract conformance with an interface type, and not a primary
archetype as expected.
Fix two IRGen tests that are failing on Android armv7 and disable eight ClangImporter, C++ Interop, and SILOptimizer tests, two of which that were already failing on other 32-bit platforms.
switch_enum_addr was being treated like a store instruction, which killed
the local enum's liveness. This could result local variable analysis reporting a
shorter lifetime for the local.
This showed up as a missing exclusivity diagnostic because an access scope was
not fully extended across a dependent local variable of Optional type.
This prevents the following pattern from miscompiling. It should report an exclusivity violation:
var mutableView = getOpaqueOptionalView(holder: &holder)!
mutate(&holder)
mutableView.modify()
Fixes rdar://151231236 ([~Escapable] Missing 'overlapping acceses' error when
called from client code, but exact same code produces error in same module)