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.
Moves from limited use values are redundant. When a move separates a
non-escaping lifetime from an escaping lifetime, it is still redundant
if the original lifetime couldn't be optimized because it's already as
small as possible.
There is a preexisting function with this name that takes a
BorrowedValue. The new function calls that preexisting function if a
BorrowedValue can be constructed from the SILValue. Otherwise, it looks
for direct uses of the value which qualify as "pointer escapes".
Although nonescaping closures are representationally trivial pointers to their
on-stack context, it is useful to model them as borrowing their captures, which
allows for checking correct use of move-only values across the closure, and
lets us model the lifetime dependence between a closure and its captures without
an ad-hoc web of `mark_dependence` instructions.
During ownership elimination, We eliminate copy/destroy_value instructions and
end the partial_apply's lifetime with an explicit dealloc_stack as before,
for compatibility with existing IRGen and non-OSSA aware passes.
Some guaranteed forwarding instructions have multiple operands:
mark_dependence, ref_to_bridge_object.
The corresponding instruction types checked here already have
documentation that the forwarded operand is the first operand. The
assert is overly cautious, and checking for indiviudal opcodes would be
tedious maintenance.
This API is the inverse of visitEnclosingDefs when called on a phi.
This replaces the visitAdjacentReborrowsOfPhi algorithm with a small
loop that simply checks all the phis in the current block.
This should all be fairly efficient once SILArgument has a "reborrow"
flag.
Recognize lexical borrows as nested when their borrowee's guaranteed
reference roots are all lexical borrows.
Addresses the following regressions
Breadcrumbs.MutatedUTF16ToIdx.Mixed 188 882 +369.1% **0.21x**
Breadcrumbs.MutatedIdxToUTF16.Mixed 230 926 +302.6% **0.25x**
seen when enabling lexical lifetimes in the standard library.
In preparation for adding OwnershipLiveness.
Rename Simple LiveRangeSummary to LiveRangeSummary.
Add initializeDefNode helpers to avoid confusion about the argument
type.
Add defBegin/defEnd iterators in MultiDefPrunedLiveness.
These APIs are essential for complete OSSA liveness analysis. The
existing ad-hoc OSSA logic always misses some of the cases handled by
these new utilities. We need to start replacing that ad-hoc logic with
new utilities built on top of these APIs to define away potential
latent bugs.
Add FIXMEs to the inverse API: visitAdjacentBorrowsOfPhi. It should
probably be redesigned in terms of these new APIs.
Factors a mess of code in MemAccessUtils to handle forwarding
instruction types into a simpler utility. This utility is also needed
for ownership APIs, which need to be extended to handle these cases.
Add TermInst::forwardedOperand.
Add SILArgument::forwardedTerminatorResultOperand. This API will be
moved into a proper TerminatorResult abstraction.
Remove getSingleTerminatorOperand, which could be misused because it's
not necessarilly forwarding ownership.
Remove the isTransformationTerminator API, which is not useful or well
defined.
Rewrite several instances of complex logic to handle block arguments
with the simple terminator result API. This defines away potential
bugs where we don't detect casts that perform implicit conversion.
Replace uses of the SILPhiArgument type and code that explicitly
handle block arguments. Control flow is irrelevant in these
situations. SILPhiArgument needs to be deleted ASAP. Instead, use
simple APIs like SILArgument::isTerminatorResult(). Eventually this
will be replaced by a TerminatorResult type.
Computing simple liveness is distinct from computing transitive
liveness. But for safety and consistency, always handle the first
level of liveness transitively. This way, computeSimple can be used on
guaranteed values that need OSSA lifetime fixup.
Simple liveness just means that *inner* borrow and address scopes are
assumed to be complete.
This utility is still only used conservatively because OSSA lifetime
completion is not yet enabled. But, in the future, computeSimple can
be used in the common case.
Start using consistent terminolfy in ownership utils.
A transitive use set follows transitive uses within an ownership
lifetime. It does not rely on complete inner scopes. An extended use
set is not necessarilly transitive but does look across
lifetime-ending uses: copies of owned values and/or reborrows of
guaranteed values. Whether lifetime extension refers to copies or
reborrow is context dependent.
The API for computing simple liveness now returns a
SimpleLiveRangeSummary. Callers need to decide how to handle reborrows
and pointer escapes. If either condition exists then the resulting
liveness does not necessarily encapsulate the definition's ownership.
Fixes some number of latent bugs w.r.t. liveness clients.
This fixes ScopedAddressValue::computeLiveness in unreachable code scenarios.
For example:
%storeBorrow = store_borrow %_ to %adr
%loadBorrow = load_borrow %storeBorrow
apply %f(%loadBorrow) : $@convention(thin) (...) -> Never
Now recursively process uses of load_borrow as if they are address
uses.
Ultimately, this would be more efficiently handled by a recursive
lifetime completion utility which would fixup the load_borrow scope
before computing the store_borrow liveness.
Fixes rdar://99874173: unreachable assert "No user in LiveWithin block"
First restore the basic PrunedLiveness abstraction to its original
intention. Move code outside of the basic abstraction that polutes the
abstraction and is fundamentally wrong from the perspective of the
liveness abstraction.
Most clients need to reason about live ranges, including the def
points, not just liveness based on use points. Add a PrunedLiveRange
layer of types that understand where the live range is
defined. Knowing where the live range is defined (the kill set) helps
reliably check that arbitrary points are within the boundary. This
way, the client doesn't need to be manage this on its own. We can also
support holes in the live range for non-SSA liveness. This makes it
safe and correct for the way liveness is now being used. This layer
safety handles:
- multiple defs
- instructions that are both uses and defs
- dead values
- unreachable code
- self-loops
So it's no longer the client's responsibility to check these things!
Add SSAPrunedLiveness and MultiDefPrunedLiveness to safely handle each
situation.
Split code that I can't figure out into
DiagnosticPrunedLiveness. Hopefully it will be deleted soon.
Fix the utilities used by LexicalDestroyHoisting that finds all uses
to report a "PointerEscape". We can't rely on lifetime analysis when
such a use is present.
Add ScopedAddressOperand and ScopedAddressValue abstraction utilities
Introduce verification for store_borrow to validate its uses are correctly enclosed in their scope.
Include end_borrow/end_access as implicit uses while validating a borrow introducer
Add flow sensitive verifier rule for store_borrow/end_borrow pair
Make sure store_borrow is always to an alloc_stack
Make sure uses to store borrow location are via its return address only
Andy some time ago already created the new API but didn't go through and update
the old occurences. I did that in this PR and then deprecated the old API. The
tree is clean, so I could just remove it, but I decided to be nicer to
downstream people by deprecating it first.
The new utility, given an phi, visits all adjacent phis (i.e. arguments
to the same block) which are (potentially iterated) reborrows of a value
reaching the given phi.