The VarInfo for an alloc_stack will always have an op_deref, so that they can
get copied along when the VarInfo is moved to a debug_value. This op_deref is
not printed by the SILPrinter.
This commit also updates uses of AllocStackInst's getVarInfo to strip this
op_deref at places where it is not needed, and uses of createDebugValueAddr
where the extra op_deref is no longer needed.
The only change at the IR level is for undef values that now have a DW_OP_deref
for move-only values.
This fixes most of the inconsitencies with op_deref at the SIL level. All
debug_values with addresses should always have an op_deref.
Assisted-by: Claude Opus 4.6 (Updated tests)
Commit 0ef2094279 salvages more debug
information in Mem2Reg in several cases. It propagates the information from
the alloc_stack to the replaced load instructions.
However, there are cases where the loads from an alloca are not actually
representing loads from the respective local variable. One such case is
when there is mandatory inlining happening at the start of the pipeline.
For example, consider the example below where an identity function is inlined.
The resulting SIL will contain an alloca from the outer `result` and a load
that is the leftover after the closure (which is just a load of the passed
argument). The load that is created has its debug scope (correctly) in the
closure scope, but the loaded alloc_stack is actually the outer local variable.
The intermediate `result` that is passed to the closure is getting eliminated
by the inliner.
```
let result = try await ... // becomes empty tuple.
return withExtendedLifetime((...)) {
result
}
```
This patch forces that the scope of the debug_value describing result is
actually in the outer function and describes the right `result` local.
Fixes rdar://171023691
This currently exposes invalid debug info generated by a previous pass.
This patch disables this specific transformation until we have a fix for the
other issue (see rdar://171023691 ).
We did check that the alloc_stack must not be in a dead-end block.
However we missed the case that the alloc_stack is not in a dead-end block but a store is in a dead-end block.
Stores in dead-end blocks could result in the stored value to leak. We are not doing lifetime completion for the stored value.
fixes a SIL verification error
rdar://170354335
This new OSSA invariant simplifies many optimizations because they don't have to take care of the corner case of incomplete lifetimes in dead-end blocks.
The implementation basically consists of these changes:
* add the lifetime completion utility
* add a flag in SILFunction which tells optimization that they need to run the lifetime completion utility
* let all optimizations complete lifetimes if necessary
* enable the ownership verifier to check complete lifetimes
This reverts commit b1eb70bf45.
The original PR (#85244) was reverted (#85836) due to rdar://165667449
This version fixes the aforementioned issue, and (potentially) improves overall
debug info retention by salvaging info in erase(instructionIncludingDebugUses:),
rather than inserting many explicit salvageDebugInfo calls throughout the code
to make the test cases pass.
Bridging: Make salvageDebugInfo a method of MutatingContext
This feels more consistent than making it a method of Instruction.
DebugInfo: Salvage from trivially dead instructions
This handles the case we were checking in constantFoldBuiltin, so we do not need to salvage debug info there any more.
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.
Since the time that lifetimes in `alloc_stack [lexical]` began to be
represented after promotion by `move_value [lexical]`s, the
`endOwnedLexicalLifetimeBeforeInst` is just an assertion. In the
future, lifetimes of values never destroyed that leak into dead end
blocks should be completed by OSSACompleteLifetime. For now, just
delete this code.
The lifetimes of the values stored into these locations may need to be
completed: if a trivial case of a non-trivial enum is written to the
location, its lifetime must be completed.
rdar://158139991
Enum types may have incomplete lifetimes in address form for trivial case values. When promoted to value form, they will end up with incomplete ossa lifetimes.
Because we know that the incomplete enum values are trivial enum cases we complete their lifetimes with `end_lifetime` instead of `destroy_value`.
This is especially important for Embedded Swift where we are not allowed to insert destroys which were not there before.
Fixes a compiler crash in Embedded Swift caused by de-virtualizing such an inserted destroy and ending up with a non-specialized generic function.
rdar://158807801
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
StackAllocationPromoter::pruneAllocStackUsage substitutes loads/stores of alloc_stack
with values. For some reason isLoadFromStack was bailing out for load_borrows with
reborrows leaving them to be fixed up by fixBranchesAndUses which uses live in value
from predecessors for substitution which is obviosly incorrect the block containing
the load_borrow has a store before it.
Fixes rdar://145834542
When we have a non trivial enum lexical stack location, and we store a
none value, after mem2reg we can end up with an ownership error
because of the leaking move_value [lexical].
This change avoids creating move_value [lexical] for such stores.
Do the same when we have store_borrow of none values, even though there
is no ownership error in this case, handle it like store for consistency
Although I don't plan to bring over new assertions wholesale
into the current qualification branch, it's entirely possible
that various minor changes in main will use the new assertions;
having this basic support in the release branch will simplify that.
(This is why I'm adding the includes as a separate pass from
rewriting the individual assertions)
For years, optimizer engineers have been hitting a common bug caused by passes
assuming all SILValues have a parent function only to be surprised by SILUndef.
Generally we see SILUndef not that often so we see this come up later in
testing. This patch eliminates that problem by making SILUndef uniqued at the
function level instead of the module level. This ensures that it makes sense for
SILUndef to have a parent function, eliminating this possibility since we can
define an API to get its parent function.
rdar://123484595
Mem2Reg may materialize the unique instance of empty types when
promoting an address of that empty type. Previously, it was required
that the top-most type in the aggregate be empty. This failed to handle
the case where a projection of empty type from a non-empty aggregate was
promoted.
For example:
```
%addr = alloc_stack $((), C)
%empty_addr = tuple_element_addr $addr : $*((), C), 0
%addr = load %empty_addr : $*()
```
where `C` is some non-empty type.
Here, that case is handled by using `undef` for each non-empty field in
the projected-from aggregate.
In the example,
```
%empty = tuple ()
%tuple = tuple (%empty : $(), undef : $C)
%empty_again = tuple_extract %tuple : $((), C), 0
```
rdar://122417297
We allow none values to be stored to a non-trivial enum.
For such store_borrow, `LiveValues::forValues` used
an Owned storage type, but endLexicalLifetime expected Guaranteed
storage type, leading to a compiler crash.
For store_borrow, use the LiveValues::forGuaranteed and for store
use LiveValues::forOwned to avoid this.
Fixes rdar://114390472