Semantically these are the only cases where we would want to force an address to
be merged. Some notes:
1. When we have a box, the project_box is considered to come from the box and is
considered non uniquely identified.
2. The only place this was really triggering was when we created temporary
partial applies to pass to a function when using address only types. Since this
temporaries are never reassigned to, there isn't any reason to require them to
be merged.
3. In the case where we have an alloc_stack grabbed by a partial_apply, we still
appropriately merge.
Importantly, we determine at the error stage if a specific value that is
transferred is within the same region of a value that is Actor derived. This
means that we can in a flow insensitive manner determine the values that are
actor derived and then via propagating those values into various regions
determine the issue... using our region analysis to handle the flow sensitivity.
One important case to reason about here is that since we are relying on the
region propagation for flow sensitivity is that this solves the var case for
us. A var when declared is never marked as actor derived. Var uses only become
actor derived if the var was merged into a region that contain is actor
derived. That means that re-assigning to a non-actor derived value, eliminates
the actor derived bit.
As part of this, I also discovered I could just get rid of the captured uniquely
identified array in favor of just passing in an actor derived flag.
rdar://115656589
In a future commit, I think I am going to change this to use a
SmallFrozenMultiMap so we can avoid the heap cost in most cases. For now though
I am just changing it to a std::multimap to make it cleaner and avoid having to
reason about when to freeze the SmallFrozenMultiMap.
Resolves numerous regressions when enabling AddressLowering early in the
pipeline.
Previously, if a value incoming into a phi had storage which itself was
a use-projection out of some other storage, PhiStorageOptimizer bailed
out. The result was unnecessary "moves" (i.e. `copy_addr [take] [init]`
instructions).
Here, this bailout is removed. In order to do this, it is necessary to
find (1) all values whose storage recursively project out of an incoming
value (such a value may have storage which is either a use _or_ a def
projection) and (2) the block which dominates the defs of all these
values.
Together, these values are used to compute liveness to determine
interference. Previously, the live region was that between the uses of
an incoming value and its defining block. Now, it is that between the
uses of any of the values found in (1) and the dominating block found in
(2).
This indirection is premature abstraction since the only two places we actually
use these callbacks is to print the accumulated output and to emit our
errors. With this change, I was able to simplify how print works and inline in
the actual diagnostic emission making it easier to understand the code.
Additionally, in a subsequent commit I am going to need to ensure that we do not
emit an error here if the source cause of our error is due to an actor. To
implement that I would need to change tryDiagnoseAsCallsite to signal to the
machinery that it needs to not emit requires and then fail further up as
well. Given that there really wasn't a need for this abstraction in the first
place and the amount of munging needed to express this, I decided to just make
this change and make it easier. If we truly need this flexibility, we can always
add it back later.
Conflicts:
- `lib/AST/TypeCheckRequests.cpp` renamed `isMoveOnly` which requires
a static_cast on rebranch because `Optional` is now a `std::optional`.
If a value's storage is a use projection out of some use,
AddressLowering correctly does not move into that storage when
initializing the composing use of the operand for the user into whose
storage it projects.
Previously, however, it was only checked that the value's storage was a
use projection at all. When initializing the composing use of the
operand of some _other_ user of the value (i.e. a user into whose
storage it does _not_ project), the result was a missing move.
Here, this is fixed by only skipping the move when the value's storage
is a projection _and_ it projects into the storage of the user of the
operand at hand.
Deserialization is calling AccessMarkerElimination repeatedly on the
same function.
The bug was introduced here:
commit 872bf40e17
Date: Mon Aug 13 10:24:20 2018
[sil-optimizer] Centralize how we send out serialization notifications.
Where the code that uniques the deserialization callbacks was simply
removed!
As a result, this pass was being invoked a number of times equal to
the number of functions in the module *multiplied* by the number of
functions being deserialized.
Fixes rdar://117141871 (Building spends most of its time in
AccessMarkerElimination)
When rewriting uses of a noncopyable value, the move-only checker failed to take into account
the scope of borrowing uses when establishing the final lifetimes of values. One way this
manifested was when borrowed values get reabstracted from value to in-memory representations,
using a store_borrow instruction, the lifetime of the original borrow would be ended immediately
after the store_borrow begins rather than after the matching end_borrow. Fix this by, first,
changing `store_borrow` to be treated as a borrowing use of its source rather than an
interior-pointer use; this should be more accurate overall since `store_borrow` borrows the
entire source value for a well-scoped duration balanced by `end_borrow` instructions. That done,
change MoveOnlyBorrowToDestructureUtils so that when it sees a borrow use, it ends the borrow
at the end(s) of the use's borrow scope, instead of immediately after the beginning of the use.
When deciding whether to clean up copies of noncopyable captures, I got
the parameter indexing wrong when the closure has non-capture arguments.
Fixing this allows noncopyable captures to work in more general
circumstances.
Function call arguments were not being treated as liveness uses.
Unblocks SIL: Treat store_borrow as borrowing its source, and have the
move-only checker account for borrow scopes. #69169https://github.com/apple/swift/pull/69169
* Don't exclude code which end up in an infinite loop. rdar://116705459
* Don't exclude error handling code (throw, catch). Errors are existentials and will always allocate. Once we have typed throws it will be possible to do error handling without allocations.
This instruction was given forwarding ownership in the original OSSA
implementation. That will obviously lead to memory leaks. Remove
ownership from this instruction and verify that it is never used for
non-trivial types.
Add `Differentiable` requirements to pattern substitutions / pattern generic signature when calculating constrained function type. Also, add requirements for differentiable results as well.
Fixes#65487
For cases where init accessor field has a nonmutating set we need
ignore copies and borrows associated with load of "self" because
they are going to be erased together with the setter application
by DI.