* remove `filterUsers(ofType:)`, because it's a duplication of `users(ofType:)`
* rename `filterUses(ofType:)` -> `filter(usersOfType:)`
* rename `ignoreUses(ofType:)` -> `ignore(usersOfType:)`
* rename `getSingleUser` -> `singleUser`
* implement `singleUse` with `Sequence.singleElement`
* implement `ignoreDebugUses` with `ignore(usersOfType:)`
This is a follow-up of eb1d5f484c.
It uses a check on conformance to ForwardInstruction for walking down guaranteed forwarding uses.
Since apply of borrow accessors cannot be represented as ForwardingInstruction, handle them separately.
Representing apply of borrow accessors for consistent handling in the optimizer is TBD.
* rename `ScopedInstruction.endOperands` -> `scopeEndingOperands`
* let them behave the same way. For `load_borrow` there was a difference because `endOperands` didn't consider branches to re-borrow phis.
InteriorLiveness has a new "visitInnerUses" mode used by DestroyHoisting. That
mode may visit dependent values, which was not valid for noescape
closures. ClosureLifetimeFixup inserts destroys of noescape closures after the
destroys of the captures. So following such dependent value could result in an
apparent use-after-destroy. This causes DestroyHoisting to insert redundant
destroys.
Fix: InteriorUses will conservatively only follow dependent values if they are
escapable. Non-escapable values, like noescape closures are now considered
escapes of the original value that the non-escapable value depends on. This can
be improved in the future, but we may want to rewrite ClosureLifetimeFixup first.
Fixes the root cause of: rdar://146142041
DestroyHoisting is using this utility. This requires complete liveness. But we
can't rely on complete liveness because complete lifetimes is not
enabled. Instead, we use a visitInnerUses flag to try to ignore borrow
scopes. That flag was never properly implemented. Make an attempt here.
Always visit the use even if it is the beginning of an inner borrow. This
provides a "better" liveness result in the case of dead borrows and gives the
client a chance to see/intercept all uses.
The extra complexity for traversing phis is not needed now that it handles
borrowed-from instructions. Remove the redundant logic because it complicates
the liveness algorithm and generates confusing results.
Inner scopes must all be reported because the walker assumes they are
complete. It is up to the client to either complete them or recursively follow
them.
Check if the forwarded value is trivial, not the base value. Presumably, we
won't call this visitor at all if the base is trivial.
Record a dependent non-Escapable values as a pointer-escape. InteriorUseWalker
does not handle lifetime dependencies. That requires
LifetimeDependenceDefUseWalker.
Only return false if the visitor returns false. Clients were ignoring the
result.
If the BorrowingOperand does not create a borrow scope, call visitUnknownUse
instead.
Until we have complete lifetimes, to avoid breaking code that cannot handle dead
defs, consider a dead borrow scope to be an unknown use.
Functional changes:
Improved modeling of dependence on local variable scopes.
For nested modify->read accesses, only extend the read accesses.
Avoid making a read access dependent on an inout argument.
The following needs to be an error to prevent span storage from being modified:
@lifetime(owner)
foo(owner: inout Owner) -> Span {
owner.span
}
Improve usability of borrowing trivial values (UnsafePointer). Allow:
let span = Span(buffer.baseAddress)
Ignore access scopes for trivial values.
Structural changes:
Delete the LifetimeDependenceUseDefWalker.
Encapsulate all logic for variable introducers within the LifetimeDependenceInsertion pass. Once mark_dependence instructions are inserted, no subsequent pass needs to think about the "root" of a dependence.
Fixes: rdar://142451725 (Escape analysis fails with mutations)
This is necessary to fix a recent OSSA bug that breaks common occurrences on
mark_dependence [nonescaping]. Rather than reverting that change above, we make
forward progress toward implicit borrows scopes, as was the original intention.
In the near future, all InteriorPointer instructions will create an implicit
borrow scope. This means we have the option of not emitting extraneous
begin/end_borrow instructions around intructions like ref_element_addr,
open_existential, and project_box. After that, we can also migrate
GuaranteedForwarding instructions like tuple_extract and struct_extract.
Just don't store the begin instruction.
This led to problem if the "begin" was not actually an instruction but a block argument.
Using the first instruction of that block is not correct in case the range ends immediately at the first instruction, e.g.
```
bb0(%0 : @owned $C):
destroy_value %0
```
When visiting consumes, also visit `extend_lifetime` instructions.
These instructions are not lifetime ending, but together with the
consumes, they enclose the users of a value.
Add a flag to LinearLiveness to control whether these instructions are
added so that the verifier can use verify that all such instructions
appear outside the linear lifetime boundary (not including them).
Compute, update and handle borrowed-from instruction in various utilities and passes.
Also, used borrowed-from to simplify `gatherBorrowIntroducers` and `gatherEnclosingValues`.
Replace those utilities by `Value.getBorrowIntroducers` and `Value.getEnclosingValues`, which return a lazily computed Sequence of borrowed/enclosing values.
Add PartialApplyInst.hasNoescapeCapture
Add PartialApplyInst.mayEscape
Refactor DiagnoseInvalidEscapingCaptures. This may change functionality because tuples containing a noescape closure are now correctly recognized. Although I'm not sure such tupes can ever be captured directly.