Track liveness of self so we don't accidentally think that such types
can be memberwise reinitialized.
Fixes rdar://110232973 ([move-only] Checker should distinguish in
between field of single field struct vs parent field itself (was:
mutation of field in noncopyable struct should not trigger deinit))
The address checker records uses in its livenessUses map. Previously,
that map mapped from an instruction to a range of fields of the type.
But an instruction can use multiple discontiguous fields of a single
value. Here, such instructions are properly recorded by fixing the map
to store a bit vector for each instruction.
rdar://110676577
FieldSensitivePrunedLiveness is used as a vectorization of
PrunedLiveness. An instance of FSPL with N elements needs to be able to
represent the same states as N instances of PL.
Previously, it failed to do that in two significant ways:
(1) It attempted to save space for which elements were live by using
a range. This failed to account for instructions which are users of
non-contiguous fields of an aggregate.
apply(
@owned (struct_element_addr %s, #S.f1),
@owned (struct_element_addr %s, #S.f3)
)
(2) It used a single bit to represent whether the instruction was
consuming. This failed to account for instructions which consumed
some fields and borrowed others.
apply(
@owned (struct_element_addr %s, #S.f1),
@guaranteed (struct_element_addr %s, #S.f2)
)
The fix for (1) is to use a bit vector to represent which elements
are used by the instruction. The fix for (2) is to use a second bit
vector to represent which elements are _consumed_ by the instruction.
Adapted the move-checker to use the new representation.
rdar://110909290
And replace them with explicit `metatype` instruction in the entry block.
This allows such metatype instructions to be deleted if they are dead.
This was already done for performance-annotated functions. But now do this for all functions.
It is essential that performance-annotated functions are specialized in the same way as other functions.
Because otherwise it can happen that the same specialization has different performance characteristics in different modules.
And it's up to the linker to select one of those ODR functions when linking.
Also, dropping metatype arguments is good for performance and code size in general.
This change also contains a few bug fixes for dropping metatype arguments.
rdar://110509780
This instruction is similar to AssignByWrapperInst, but instead of having
a destination operand, the initialization is fully factored into the init
function operand. Like AssignByWrapper, AssignOrInit has partial application
operands of both the initializer and the setter, and DI will lower the
instruction to a call based on whether the assignment is initialization or
a setter call.
Just the $*T -> $*@moveOnly T variant for addresses. Unlike the object version
this acts like a cast rather than something that provides semantics from the
frontend to the optimizer.
The reason why I am using a different instruction for addresses and objects here
is that the object checker doesnt have to deal with things like initialization.
drop_deinit only exists in ownership SIL. Remove IRGen support.
A drop_deinit can only ever be destroyed or destructured.
A destructure of a struct-with-deinit requires a drop_deinit operand.
The new alloc_pack_metadata and dealloc_pack_metadata are inserted as
part of IRGen lowering. The former indicates that the next instruction
might result in on-stack pack metadata being emitted. The latter
indicates that this is the position at which metadata emitted on behalf
of its operand should be cleaned up.
The algorithm requires no critical edges, but that doesn't mean
require ownership. Remove the assert to allow the utility to be called
from code where the caller has manually split edges.
In the fullness of time, there should no passes should introduce
critical edges.
I think this was a mistake from when I changed implementations to use pure
scalar bit processing rather than processing all at once. Instead of just
updating the internal found resulting uses array, we were appending to it.
Some notes:
1. This actually did not break anything semantically in the move checker since
we do not use this array in the caller in anyway. We just use it internally in
the routine to first lookup the current state which we then process in the
routine. That being said, this API is written such that a user /could/ do that
and we want to allow for users to be able to do that so that we match what
PrunedLiveness does.
2. This could cause memory corruption due to iterator invalidation if by
appending we caused the SmallVector to reallocate as we iterated over the
array.
So to fix this I did the following:
a. I changed the push_back to be an assignment.
b. I removed llvm::enumerate just out of paranoia if the assignment could
potentially cause iterator invalidation.
The given test exercises this code path and with the old behavior would crash
with asan or guard malloc.
rdar://109673338
After a value is consumed, we emit a `debug_value undef` to indicate that the
variable value is no longer valid to the debugger. However, once a value is
reassigned, it becomes valid again, so emit a `debug_value %original_address` to
reassociate the variable with the valid memory location. rdar://109218404
"reborrow" flag on the SILArgument avoids transitive walk over the phi operandsi
to determine if it is a reborrow in multiple utilities.
SIL transforms must keep the flag up-to-date by calling SILArgument::setReborrow.
SILVerifier checks to ensure the flag is not invalidated.
Currently "escaping" is not used anywhere.
This makes it so that the move address checker is not dependent on starting the
traversal at a base object. I also included verifier checks that the API can
visit all address uses for:
1. project_box.
2. alloc_stack.
3. ref_element_addr.
4. ref_tail_addr.
5. global_addr_inst.
this is because this visitor is now apart of the SIL API definition as being
able to enumerate /all/ addresses derived from a specific chosen address value.
This is a refactoring NFCI change.
rdar://108510644
Previously, calling `visitEnclosingDefs` or `visitBorrowIntroducers`
would crash if the `SILValue` argument were an instance of `SILUndef`
because both instantiate a `::FindEnclosingDefs` with the the result of
of calling `getFunction()` on that argument and `::FindEnclosingDefs` in
turn uses that result to create a `ValueSet`; but
`SILUndef::getFunction` returns `nullptr`, which is illegal to use as
the function for a `ValueSet`(or any other data structure relying on
`NodeBits`).
If the function specified as a separate argument, no values would be
visited and `true` would be returned. Instead of burdening the API with
a separate argument, check for `SILUndef` up front and return `true`.
It's equivalent to getBorrowIntroducingUserResult except that it's less
convenient to use. There's only ever one result, so there's no need for
a visitor. Updated all users to call getBorrowIntroducingUserResult
instead.
Added the assertions from visitBorrowIntroducingUserResults to
getBorrowIntroducingUserResult. In preparation for deleting the former
in favor of the latter.