Specifically, improved debug info retention in:
* tryReplaceRedundantInstructionPair,
* splitAggregateLoad,
* TempLValueElimination,
* Mem2Reg,
* ConstantFolding.
The changes to Mem2Reg allow debug info to be retained in the case tested by
self-nostorage.swift in -O builds, so we have just enabled -O in that file
instead of writing a new test for it.
We attempted to add a case to salvageDebugInfo for unchecked_enum_data, but it
caused crashes in Linux CI that we were not able to reproduce.
This is needed in Embedded Swift because the `witness_method` convention requires passing the witness table to the callee.
However, the witness table is not necessarily available.
A witness table is only generated if an existential value of a protocol is created.
This is a rare situation because only witness thunks have `witness_method` convention and those thunks are created as "transparent" functions, which means they are always inlined (after de-virtualization of a witness method call).
However, inlining - even of transparent functions - can fail for some reasons.
This change adds a new EmbeddedWitnessCallSpecialization pass:
If a function with `witness_method` convention is directly called, the function is specialized by changing the convention to `method` and the call is replaced by a call to the specialized function:
```
%1 = function_ref @callee : $@convention(witness_method: P) (@guaranteed C) -> ()
%2 = apply %1(%0) : $@convention(witness_method: P) (@guaranteed C) -> ()
...
sil [ossa] @callee : $@convention(witness_method: P) (@guaranteed C) -> () {
...
}
```
->
```
%1 = function_ref @$e6calleeTfr9 : $@convention(method) (@guaranteed C) -> ()
%2 = apply %1(%0) : $@convention(method) (@guaranteed C) -> ()
...
// specialized callee
sil shared [ossa] @$e6calleeTfr9 : $@convention(method) (@guaranteed C) -> () {
...
}
```
Fixes a compiler crash
rdar://165184147
This peephole optimization didn't consider that an alloc_stack of an enum can be overridden by another value.
The fix is to remove this peephole optimization at all because it is already covered by `optimizeEnum` in alloc_stack simplification.
Fixes a miscompile
https://github.com/swiftlang/swift/issues/85687
rdar://165374568
It eliminates dead access scopes if they are not conflicting with other scopes.
Removes:
```
%2 = begin_access [modify] [dynamic] %1
... // no uses of %2
end_access %2
```
However, dead _conflicting_ access scopes are not removed.
If a conflicting scope becomes dead because an optimization e.g. removed a load, it is still important to get an access violation at runtime.
Even a propagated value of a redundant load from a conflicting scope is undefined.
```
%2 = begin_access [modify] [dynamic] %1
store %x to %2
%3 = begin_access [read] [dynamic] %1 // conflicting with %2!
%y = load %3
end_access %3
end_access %2
use(%y)
```
After redundant-load-elimination:
```
%2 = begin_access [modify] [dynamic] %1
store %x to %2
%3 = begin_access [read] [dynamic] %1 // now dead, but still conflicting with %2
end_access %3
end_access %2
use(%x) // propagated from the store, but undefined here!
```
In this case the scope `%3` is not removed because it's important to get an access violation error at runtime before the undefined value `%x` is used.
This pass considers potential conflicting access scopes in called functions.
But it does not consider potential conflicting access in callers (because it can't!).
However, optimizations, like redundant-load-elimination, can only do such transformations if the outer access scope is within the function, e.g.
```
bb0(%0 : $*T): // an inout from a conflicting scope in the caller
store %x to %0
%3 = begin_access [read] [dynamic] %1
%y = load %3 // cannot be propagated because it cannot be proved that %1 is the same address as %0
end_access %3
```
All those checks are only done for dynamic access scopes, because they matter for runtime exclusivity checking.
Dead static scopes are removed unconditionally.
This also required me to change how we handled which instruction/argument we
emit an error about in the verifier. Previously we were using two global
variables that we made nullptr to control which thing we emitted an error about.
This was unnecessary. Instead I added a little helper struct that internally
controls what we will emit an error about and an external "guard" RAII struct
that makes sure we push/pop the instruction/argument we are erroring upon
correctly.
Although this error can only happen when tinkering with the stdlib's runtime functions, it's nice to get a readable error message. So far, the compiler just crashed later without a hint to the original problem.
We need to serialize the underlying type substitution map for an
inlinable function. However, there is no reason to deserialize it
eagerly, since doing so can lead to cycles. It is better for
correctness and performance to only deserialize it when needed.
Technically this fixes a regression from #84299, but the actual
problem was there all along, it was just exposed by my change
on a specific project.
Fixes rdar://163301203.
This code was not consulting SILFunctionConventions, so it was
passing things indirect when they are not in sil-opaque-values.
This fixes callers as well to ensure they pass arguments and
results correctly in both modes.
This function will give the wrong convention in SILGen when
using -enable-sil-opaque-values. In particular, it will say
arguments are indirect when they are not.
As the above comments imply, when isTypeKind() returns true, then
getType() should return a valid Type. This wasn't true with
DifferentiabilityWitness.