This prevents simplification and SILCombine passes to remove (alive) `mark_dependence_addr`.
The instruction is conceptually equivalent to
```
%v = load %addr
%d = mark_dependence %v on %base
store %d to %addr
```
Therefore the address operand has to be defined as writing to the address.
To determine whether an instruction may require pack metadata, the types
of its operands are examined.
Previously, the top level type was checked for having a pack in its
signature, and the whole type was checked for having a type anywhere in
its layout (via TypeLowering). This didn't account for the case where
the metadata was required for a resilient type which uses a pack in its
signature.
Here, during type lowering, a type having a pack in its signature is
counted towards the type having a pack.
Fixes a compiler crash.
rdar://147207926
It is like `zeroInitializer`, but does not actually initialize the memory.
It only indicates to mandatory passes that the memory is going to be initialized.
This API only makes sense for a scoped borrow-introducer such as:
- reborrow
- owned mark_dependence
Borrowing operands that forward guaranteed values do not have scope-ending uses.
If the base value of a mark_dependence is an address, that memory location must be initialized at the mark_dependence.
This requires that the mark_dependence is considered to read from the base address.
This fixes an OSSA verification bug introduced here:
commit 79b649854b
Author: Meghana Gupta <meghanavgupta@gmail.com>
Date: Wed Jan 22 01:24:49 2025
Fix operand ownership of mark_dependence [nonescaping] of address values
The bug only showed up with mark_dependence [nonescaping], which means mainly
affects `~Escapable` types. Adddressors happened to work because SILGen was
emitting a borrow scope around them.
Rather than reverting the change above, this fix migrates mark_dependence
[nonescaping] to an implicit borrow scope.
Fixes rdar://144199759 (Assert: mark_dependence [nonescaping]:
ownership incompatible with an owned value)
In OSSA, the `partial_apply [on_stack]` instruction produces a value
with odd characteristics that correspond to the fact that it is lowered
to a stack-allocating instruction. Among these characteristics is the
fact that copies of such values aren't load bearing.
When visiting the lifetime-ending uses of a `partial_apply [on_stack]`
the lifetime ending uses of (transitive) copies of the partial_apply
must be considered as well. Otherwise, the borrow scope it defins may be
incorrectly short:
```
%closure = partial_apply %fn(%value) // borrows %value
%closure2 = copy_value %closure
destroy_value %closure // does _not_ end borrow of %value!
...
destroy_value %closure2 // ends borrow of %value
...
destroy_value %value
```
Furthermore, _only_ the final such destroys actually count as the real
lifetime ends. At least one client (OME) relies on
`visitOnStackLifetimeEnds` visiting at most a single lifetime end on any
path.
Rewrite the utility to use PrunedLiveness, tracking only destroys of
copies and forwards. The final destroys are the destroys on the
boundary.
rdar://142636711
The problem with `is_escaping_closure` was that it didn't consume its operand and therefore reference count checks were unreliable.
For example, copy-propagation could break it.
As this instruction was always used together with an immediately following `destroy_value` of the closure, it makes sense to combine both into a `destroy_not_escaped_closure`.
It
1. checks the reference count and returns true if it is 1
2. consumes and destroys the operand
This enables access enforcement analysis to classify a dynamic begin_access in
access patterns (such as the one below) involving a throwing function as not
having nested conflicts.
```
struct Stack {
var items : [UInt8]
mutating func pop() throws -> UInt8 {
guard let item = items.popLast() else { throw SomeErr.err }
return item
}
...
}
class Container {
private var ref : Stack
@inline(never)
internal func someMethod() throws {
try ref.pop()
}
...
}
```
rdar://141182074
In case the control flow ends in a dead-end block there can be begin-borrow instructions which have no corresponding end-borrow uses.
After duplicating such a block, the re-borrow flags cannot be recomputed correctly for inserted phi arguments.
Therefore just disable duplicating such blocks, e.g. in jump-threading.
When its operand has coroutine kind `yield_once_2`, a `begin_apply`
instruction produces an additional value representing the storage
allocated by the callee. This storage must be deallocated by a
`dealloc_stack` on every path out of the function. Like any other stack
allocation, it must obey stack discipline.
SILInstruction::clone doesn't know how to clone instructions that produce
the archetype uuid. SILCloner is equipped to handle such instructions.
Optimizations like LoopRotate use SILInstruction::clone and will be
incorrect for such instructions.
rdar://130047619
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)
drop_deinit forwards ownership while effectively stripping the deinitializer. It is similar to a type cast.
Fixes rdar://125590074 ([NonescapableTypes] Nonescapable types
cannot have deinits)
Even if the final pattern ends up consuming the value, the match itself
must be nondestructive, because any match condition could fail and cause
us to have to go back to the original aggregate. For copyable values,
we can always copy our way out of consuming operations, but we don't
have that luxury for noncopyable types, so the entire match operation
has to be done as a borrow.
For address-only enums, this requires codifying part of our tag layout
algorithm in SIL, namely that an address-only enum will never use
spare bits or other overlapping storage for the enum tag. This allows
us to assume that `unchecked_take_enum_data_addr` is safely non-side-
effecting and match an address-only noncopyable enum as a borrow.
I put TODOs to remove defensive copies from various parts of our
copyable enum codegen, as well as to have the instruction report
its memory behavior as `None` when the projection is nondestructive,
but this disturbs SILGen for existing code in ways SIL passes aren't
yet ready for, so I'll leave those as is for now.
This patch is enough to get simple examples of noncopyable enum switches
to SILGen correctly. Additional work is necessary to stage in the binding
step of the pattern match; for a consuming switch, we'll need to end
the borrow(s) and then reproject the matched components so we can
consume them moving them into the owned bindings. The move-only checker
also needs to be updated because it currently always tries to convert
a switch into a consuming operation.
Previously, mayRequirePackMetadata only considered whether a type
involved a pack. That failed to account for the case of outlined value
functions that require pack metadata when the type involves a pack in
its layout. Here, mayRequirePackMetadata now considers also whether the
layout corresponding to a type involves a pack.
rdar://119829826
partial_apply cannot be cloned, even in OSSA. OSSA lowering does
not know how to allocate for multiple partial applies.
Fixes rdar://119768691 (OwnershipModelEliminator triggers assertion
when lowering certain [on_stack] partial_applys in certain
circumstances)
* `alloc_vector`: allocates an uninitialized vector of elements on the stack or in a statically initialized global
* `vector`: creates an initialized vector in a statically initialized global