Split AccessedStorage functionality in two pieces. This doesn't add
any new logic, it just allows utilities to make queries on the access
base. This is important for OSSA where we often need to find the
borrow scope or ownership root that contains an access.
Handle SSA update (phi creation) when extending an owned lifetime over
a borrowed lifetime.
This is a layer of logic above BorrowedValue but below
OwnershipLifetimeExtender and other higher-level utilities.
Rewrite ownership forwarding through switch_enums. It's unclear what
the original code was doing, but enabling OSSA verification for
terminators revealed the issue.
Add OwnershipForwardingTermInst::createResult(SILBasicBlock, SILType)
Add SwitchEnumInst::createDefaultResult()
Add SwitchEnumInst::createOptionalSomeResult(), which handles most
compiler-generated switches.
Basic API for creating terminator results with consistent
ownership. This allows enabling OSSA verification on terminator
results. It fixes current issues, but is also a prerequisite for OSSA
simplify-cfg.
For switch_enum, this ensures that the default argument consistently
either forwards the original value, or handles the payload of the
unique case (the unique payload was already being inferred for
ownership, but the block argument was inconsistent with that fact).
switch_enum and checked_cast_br specify their forwarding
ownership. This can differ from their operand ownership.
For example:
%e = enum $Optional<AnyObject>, #Optional.none!enumelt
switch_enum %e : $Optional<AnyObject>,
case #Optional.some!enumelt: bb2...
bb2(%arg : @owned T):
Independent forwarding ownership is only supported with terminators in this
change, but in the near term it will be used for all forwarding
operations to support implicit borrow scopes.
Mangling can fail, usually because the Node structure has been built
incorrectly or because something isn't supported with the old remangler.
We shouldn't just terminate the program when that happens, particularly
if it happens because someone has passed bad data to the demangler.
rdar://79725187
This patch replace all in-memory objects of DebugValueAddrInst with
DebugValueInst + op_deref, and duplicates logics that handles
DebugValueAddrInst with the latter. All related check in the tests
have been updated as well.
Note that this patch neither remove the DebugValueAddrInst class nor
remove `debug_value_addr` syntax in the test inputs.
This pattern was really error-prone. I've fixed multiple bugs related
to CurGenericSignature not being set correctly at the right time, and
found another latent bug by inspection while doing this cleanup.
* unify FunctionPassContext and InstructionPassContext
* add a modification API: PassContext.setOperand
* automatic invalidation notifications when the SIL is modified
OSSA rauw cleans up end of scope markers before rauw'ing.
This can lead to inadvertant deleting of end_lifetime, later
resulting in an ownership verifier error indicating a leak.
This PR stops treating end_lifetime scope ending like end_borrow/end_access.
Determines whether an address might be inside a borrowed scope. If so,
then any address substitution needs to find that scope boundary to
avoid violating its basic guarantee that all uses are within scope.
It was originally convenient for exclusivity optimization to treat
boxes specially. We wanted to know that the 'Box' kind was always
uniquely identified. But that's not really important. And now that
AccessedStorage is being used more generally, the inconsistency is
problematic.
A consistent model is also must easier to understand and explain.
This also make the implementation of the utility simpler and more powerful.
Functional changes:
isRCIdentical will look through mark_dependence and mark_uninitialized.
findReferenceRoot is used consistently everywhere increasing analysis precision.
AccessPathWithBase::compute can return a valid access path with unidentified base.
In such cases, we cannot LICM stores, because there is no base address to check if it is invariant
AccessPathDefUseTraversal accumulates the offsets that it has seen on
the def-use walk while visiting index_addr and casts.
This is quite tricky because either the AccessPath being matched or
the def-use chain could contain unknown offsets. We need to correctly
classify all cases as either an exact, inner, or overlapping match.
For SIL like this
%91 = integer_literal $Builtin.Int64, 0
%113 = builtin "truncOrBitCast_Int64_Word"(%91 : $Builtin.Int64) : $Builtin.Word
%115 = index_addr %114 : $*MyStruct, %113 : $Builtin.Word
%119 = struct_element_addr %115 : $*MyStruct, #MyStruct.klass
We have Path: (@Unknown,#0)
There are two issues
(1) When AccessPathDefUseTraversal::checkAndUpdateOffset visits the
struct_element_addr, it fails to pop the unknown offset from the
expected path but continues trying to handle the struct_element_addr
and hits an assert. This PR fixes this.
(2) If the builtin "truncOrBitCast_Int64_Word" comes from a literal,
we should not treat it as an unknown offset (given that the literal is
within the size of a word). Added a test for this case, we should be able
to identify the access path accurately in this.