A debug_value with a large undef operand should not be rewritten to use
an alloc_stack with no stores.
Debug values should have no impact on allocations, and the undef operand
has a special meaning, especially when combined with debug
reconstruction blocks, where the undef value is normally unused.
Replace uses of createDebugValueAddr in passes, that were used to
rewrite debug value instructions with a prepended deref, to use the
prependDeref function to prepend it in place.
The previous implementation did not work in all CFG configurations, and would
take some effort to do so. We don't have an immediate need to support OSSA
form with this pass, so we don't need to precisely place `store_borrow` and
`end_borrow` scopes, and `alloc_stack`/`dealloc_stack` can be placed with
less precision so long as they balance, and type-dependent stack allocations
are dominated by the def for the type.
When an argument is made indirect by the pass, and the argument value was the base
of a `make_borrow` in the original function, then we must ensure the `make_addr_borrow`
in the transformed function uses the lowered address of the argument as its base,
in order to ensure that the lifetime of the borrow matches the lifetime of the argument
in the caller. Also, LoadableByAddress does not always lower local values that do not
interact with arguments or returns of the function to addresses, but IRGen expects
all `make_borrow`s of large loadable types to be transformed into `make_borrow_addr`,
so form a local `alloc_stack` and storage when necessary in these cases.
Fixes rdar://175799037.
We cannot use spare bits or other overlapping storage layout tricks with fundamentally
address-only enums, and we can take advantage of this to do borrowing switches or other
in-place projections without copying the value. However, for resilient enums, the
implementation may use spare bit packing, but the type must be handled address-only
outside of its defining module, and we didn't have a way to express that with
borrowing switch. Optimization passes have also been running into problems with the
complexity that we were using `unchecked_take_enum_data_addr` sometimes as a pure
operation. This patch splits the instruction into three:
- `unchecked_inplace_enum_data_addr` represents a nondestructive in-place enum
projection. It is only allowed for enums whose projection operation is
nondestructive.
- `unchecked_take_enum_data_addr` represents a destructive enum projection,
invalidating the enum and leaving the payload to be further consumed.
This matches the current instruction's semantics.
- `unchecked_borrow_enum_data_addr` represents a borrowing enum projection.
The instruction takes a second operand for "scratch" space, which the
enum representation may be copied into in order to avoid invalidating the
enum value, so the result is dependent on the lifetime of both the
original enum and the scratch buffer. This allows for borrowing switches
over resilient enums.
`unchecked_borrow_enum_data_addr` is implemented by taking advantage of the
"address-only enums can't do spare bit optimization" property at runtime.
We inspect the operand type's bitwise-borrowability from its metadata. If
the type is bitwise-borrowable, then we are allowed to bitwise-copy the
enum to the scratch space and apply the projection to the scratch space,
preserving the original value. If the type is not bitwise-borrowable, then
we cannot use spare bit optimization in its layout, so we apply the
projection in-place.
Fixes rdar://174952822.
The LoadableByAddress pass rewrites alloc_stack instructions when their element
type changes (e.g., a function parameter convention changes from @guaranteed to
@in_guaranteed for large/opaque types). However, it was passing the original
SILDebugVariable info through unchanged. When the VarInfo has an explicit Type
field set this creates a mismatch between the SSA type and the debug type,
causing a SIL verifier failure.
In this patch, I just change the pass to update the alloc_stack as
appropriate. I verified that this cannot happen with debug_value since we do not
store the extra type info in it if we have an object typed thing. Since
loadable_by_address only changes objects -> addresses, it can never happen.
rdar://164268891
rdar://167713693
The LoadableByAddress pass recognizes large loadable types in borrow accessors and returns them by @guaranteed_address.
This prevents stack allocations and unnecessary copies.
Co-authored-by: Meghana Gupta <meghana_gupta@apple.com>
Computing the explosion schema for large types can be expensive.
E.g the following example would spend multiple seconds to compute the
explosion scheme for the array type. It is not worth adding the
complexity to have a special case explosion schema that handles types
like that since exploding a value like that is going to be detrimental.
```
struct Test {
private var values: [0xfffffff of [UInt32]] =
InlineArray(repeating: [])
}
```
rdar://165202495
For example the pattern:
```
%e = load %1 : SomeEnum
switch_enum %e
```
The switch_enum_addr should reuse the load's address operand instead of
creating a new location for the SSA value of %e.
While we are there also don't create a new stack location for extracting payload
in a switch_enum_addr case target basic block if that extracted payload is not
used. That is if the basic block arguments in all switch target blocks are
unused in the switch_enum version.
```
switch_enum %enum, case #Optional.some!enumelt: bb1,
case #Optional.none!enumelt: bb2
bb2(%payload : $Payload):
// unused %payload value
```
rdar://156602951
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.
This is a value operation that can work just fine on lowered types,
so there's no need to carry along a formal type. Make the value/address
duality clearer, and enforce it in the verifier.
Create two versions of the following functions:
isConsumedParameter
isGuaranteedParameter
SILParameterInfo::isConsumed
SILParameterInfo::isGuaranteed
SILArgumentConvention::isOwnedConvention
SILArgumentConvention::isGuaranteedConvention
These changes will be needed when we add a new convention for
non-trivial C++ types as the functions will return different answers
depending on whether they are called for the caller or the callee. This
commit doesn't change any functionality.
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)
It needs to match with the (large loadable) lowered closure type in the rest of
the program: Large types in the signature need to be passed indirectly.
rdar://127367321
An unchecked_trivial_bit_cast can go from a bigger type to a smaller
type. Therefore we must allocate stack storage for the operand type
rather than the result type. Otherwise, we can end up storing bigger
values into smaller storage -- not good.
rdar://128086028
LoadableByAddress was losing debug info, including at -Onone.
When converting a load-store pair to a copy_addr, the debug info
attached to the load was not salvaged.
Additionally, the wrong scope was being attached to other debug
values.