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.
Needed to diagnose MutableSpan and OutputSpan.
For now, simply remove the bailout and TODO. The next change will introduce more
logic to force a diagnostic error in rare cases that can't be handled completely.
Fixes rdar://143584461 (Extended exclusive borrow issues with
MutableSpan and OutputSpan)
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)
If the base value of a mark_dependence is an address, that memory location must be initialized at the mark_dependence.
This requires that the mark_dependence is considered to read from the base address.
If the memory location depends on something, insert a dependency for the loaded value:
```
%2 = mark_dependence %1 on %0
%3 = load %2
```
->
```
%2 = mark_dependence %1 on %0 // not needed anymore, can be removed eventually
%3 = load %2
%4 = mark_dependence %3 on %0
// replace %3 with %4
```
Memory effects of begin_access are only defined to prevent the optimizer moving loads and stores across a begin_access.
But those memory effects are not relevant for RedundantLoadElimination
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.
We use the formal source type do decide whether a checked_cast_br is
known to succeed/fail. If we don't update it we loose that optimization
That is:
```
checked_cast_br AnyObject in %2 : X to X, bb1, bb2
```
Will not be simplified even though the operand and the destintation type
matches.
The problem with `is_escaping_closure` was that it didn't consume its operand and therefore reference count checks were unreliable.
For example, copy-propagation could break it.
As this instruction was always used together with an immediately following `destroy_value` of the closure, it makes sense to combine both into a `destroy_not_escaped_closure`.
It
1. checks the reference count and returns true if it is 1
2. consumes and destroys the operand