We would try to take the `metatype` of the integer value, which doesn't work. If
a specialized parameter is an integer generic parameter, emit a code sequence
that compares the integer value. Fixes rdar://176876134.
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)
This deprecates the use of DIExpr on alloc_stack. When varinfo is present
on an alloc_stack, it represents the whole variable. Otherwise, debug_value
should be used.
usePoints is an artifact of the time when we didn't have guaranteed forwarding phis.
It is no longer used and triggered an unnecessary assert for borrow accessors.
tryToCSEOpenExtCall replaces open_existential_addr operands in apply
instructions, but doesn't remap types of other arguments that depend
on the opened archetype (e.g. init_existential_addr results).
This can create illegal apply with mismatched archetypes.
Add a check that bails out if any apply argument (other than the
open_existential_addr itself) has a type depending on the opened
archetype's generic environment.
Resolves an issue exposed in rdar://100426072
Add a bailout for an unexpected SIL pattern.
Normally, access scopes for dynamic exclusivity enforcement are supposed to be
on the address that is the based of a formal access. When this is true, it's
possible to merge two accesses whenever that have the same base by blindly
replacing all uses. But, in some strange situation that seems to result from
optimization and inlining, we end up with dynamic access on a projection. Simply
recognize that case and bailout.
Fixes rdar://175181392
Prevents situations when actor isolation ends up not being set
un-intentionally i.e. when cloning, specializating, or creating
thunks.
The thunks get `unspecified` isolation at the moment.
SIL functions should always have actor isolation set, otherwise
it could lead to wrong deductions in optimization passes like
`SendNonSendable` or `OptimizeHopToExecutor`.
This is a first step to move isolation assignment into
`SILFunction::create`.
A dead forwarding operation (e.g. `unchecked_enum_data`,
`unchecked_value_cast`, `destructure_struct`) with an owned move-only operand
must not be deleted because it ends the lifetime of its operand.
Previously, only `destructure_struct` was guarded against deletion. This
change uses `ForwardingOperation` and `getSingleForwardingOperand()` to
cover all single-operand forwarding instructions uniformly.
Resolves rdar://175150849
There are passes that rely on the isolation being present after
specialization and other optmizations i.e. `SendNonSendable` which
means the clones need to always preserve the isolation of the
original function.
`LifetimeDependenceScopeFixup` can insert `end_cow_mutation_addr` on a struct address containing multiple COW fields, `SimplifyEndCOWMutationAddr` lowers it to an `end_cow_mutation` on the struct.
`skipStructAndExtract()` in COWOpts was unconditionally looking through `struct_extract` and `destructure_struct` instructions when tracing from `begin_cow_mutation` back to `end_cow_mutation`.
COWOpts would then trace from a `begin_cow_mutation` on one field, through `struct_extract`, to the `end_cow_mutation` on the `struct` that was placed for a different field's mutation. This caused COWOpts to incorrectly conclude the
buffer was uniquely referenced and fold the uniqueness check to true, breaking COW semantics.
The fix restricts `skipStructAndExtract` to only look through `struct_extract` and `destructure_struct` when the struct type has exactly one stored property.
Resolves rdar://172670647
I can't quite enable modeling their stack effects in this patch because
SILGen generates improperly-nested allocations; that'll be fixed in a
follow-up.
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
ConditionForwarding moves a condition terminator down to a switch_enum.
The existing OSSA check only verified if the condition's operand was
directly a BorrowedValue with a local scope, but missed cases where the
operand is a guaranteed forwarding result from a local borrow scope.
This caused the switch_enum to be moved past the
end_borrow, producing an outside-of-lifetime use.
Use getAllBorrowIntroducingValues to walk through forwarding instructions
and find the actual borrow introducers, then bail out if any of them is
a local scope.
Resolves rdar://172697777
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 ).
For very large functions OSSA canonicalization can run into noticeable quadratic behavior.
Don't canonicalize functions with more than 100000 SIL instructions.
This limit is large enough to not affect most of real-world SIL functions.
Such large SIL functions can come up for large string array initializers when building with an assert-enabled stdlib.
ColdBlockInfo previously had to be constructed and run manually for each function.
Turning it into a SILAnalysis makes it lazily computed and cached per-function,
with automatic invalidation whenever the control-flow graph changes.
This is otherwise a non-functional change.
Mainly:
* look through ownership instructions in more places
* support `load_borrow` and `store_borrow` where `load` and `store`s are expected
* support `destructure_struct` where `struct_extract` is expected
* enable inout-keypath optimization for OSSA
* OSSA support in StringOptimization
In the optimizer (= non mandatory) pipeline we don't need to maintain the lexical flags of `begin_borrow`, etc. anymore.
This enables more optimizations to be done.
Such casts could cast from a vector to its first element. Prevent DestroyAddrHoisting from hoisting such `destroy_addr`s because it would also replace the address from the cast result to the cast operand.
Fixes a mis-compile
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 is a follow up from the "async" `deinit` work, which will allow us
to guarantee cleanup code to run in deinitializers, even if they need to
call asynchronous code, and even if they may be run in a task that was
cancelled: by "shielding" it from cancellation.
This is incomplete, the child handling needs some more love.
SE proposal: https://github.com/swiftlang/swift-evolution/pull/3037/
This can happen if the only exit of a loop is the throw-branch of a `try_apply` and the inlined function does not actually throw.
Fixes a SIL verification failure.
rdar://169569071