Copy propagation does these optimizations more generally. It should be
able to replace this optimization. Fixing it and not just deleting CopyValueOpts
because it happens to be called in the mandatory pipeline.
This API computes the re-borrow flags for guaranteed phis based on the presence of forwarding instructions in the incoming values.
This is not correct in all cases, because optimizations can optimize away forwarding instructions.
Fixes a verifier crash: rdar://139280579
The optimization replaces a `load [copy]` with a `load_borrow` if possible.
```
%1 = load [copy] %0
// no writes to %0
destroy_value %1
```
->
```
%1 = load_borrow %0
// no writes to %0
end_borrow %1
```
The new implementation uses alias-analysis (instead of a simple def-use walk), which is much more powerful.
rdar://115315849
Although I don't plan to bring over new assertions wholesale
into the current qualification branch, it's entirely possible
that various minor changes in main will use the new assertions;
having this basic support in the release branch will simplify that.
(This is why I'm adding the includes as a separate pass from
rewriting the individual assertions)
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.
For years, optimizer engineers have been hitting a common bug caused by passes
assuming all SILValues have a parent function only to be surprised by SILUndef.
Generally we see SILUndef not that often so we see this come up later in
testing. This patch eliminates that problem by making SILUndef uniqued at the
function level instead of the module level. This ensures that it makes sense for
SILUndef to have a parent function, eliminating this possibility since we can
define an API to get its parent function.
rdar://123484595
This fixes a use-after-free miscompile.
LoadCopyToBorrowOpt alias analysis was wrong in
visitArgumentAccess. inout_aliasable does not give you exclusive
access to an address.
This resulted in removal of a retain before calling an ObjC block
after converting it from a Swift closure.
@_silgen_name("foreign")
func foreign(block: @escaping @convention(block) () -> Void)
public func doit(closure: @escaping () -> ()) {
foreign { [closure] in closure() }
}
Fixes rdar://121268094
Reformatting everything now that we have `llvm` namespaces. I've
separated this from the main commit to help manage merge-conflicts and
for making it a bit easier to read the mega-patch.
This is phase-1 of switching from llvm::Optional to std::optional in the
next rebranch. llvm::Optional was removed from upstream LLVM, so we need
to migrate off rather soon. On Darwin, std::optional, and llvm::Optional
have the same layout, so we don't need to be as concerned about ABI
beyond the name mangling. `llvm::Optional` is only returned from one
function in
```
getStandardTypeSubst(StringRef TypeName,
bool allowConcurrencyManglings);
```
It's the return value, so it should not impact the mangling of the
function, and the layout is the same as `std::optional`, so it should be
mostly okay. This function doesn't appear to have users, and the ABI was
already broken 2 years ago for concurrency and no one seemed to notice
so this should be "okay".
I'm doing the migration incrementally so that folks working on main can
cherry-pick back to the release/5.9 branch. Once 5.9 is done and locked
away, then we can go through and finish the replacement. Since `None`
and `Optional` show up in contexts where they are not `llvm::None` and
`llvm::Optional`, I'm preparing the work now by going through and
removing the namespace unwrapping and making the `llvm` namespace
explicit. This should make it fairly mechanical to go through and
replace llvm::Optional with std::optional, and llvm::None with
std::nullopt. It's also a change that can be brought onto the
release/5.9 with minimal impact. This should be an NFC change.
"reborrow" flag on the SILArgument avoids transitive walk over the phi operandsi
to determine if it is a reborrow in multiple utilities.
SIL transforms must keep the flag up-to-date by calling SILArgument::setReborrow.
SILVerifier checks to ensure the flag is not invalidated.
Currently "escaping" is not used anywhere.
In https://github.com/apple/swift/pull/65417 , support for promoting
moved-from `load [copy]`s was added. At that time, the existing logic
was generalized so that the check for whether writes the loaded-from
address occurred: rather than checking whether the writes occurred in
the live-range of the `load [copy]`, it was generalized to check whether
writes occurred in the live range of the "original" value which was
either the `load [copy]` or the `move_value`. That opened a hole for
writes that occurred between the `load [copy]` and the `move_value`:
```
%v = load [copy] %a
%u = load [take] %a
%m = move_value %v
```
Here, this is fixed by checking both the live-range of the "original"
and also (supposing the original is different from the `load [copy]`)
also the live range of the `load [copy]`.
This required changing the list of consuming uses passed to the
`LinearLifetimeChecker::usesNotContainedWithinLifetime` to include not
just the `destroy_value`s but also the "unknown" consuming uses (i.e.
those that are not forwarding).
This change only affects arguments (and specifically only `@inout`
arguments since promotion for `@in` arguments isn't supported) because a
totally different code path is followed for `alloc_stack`s which regards
`load [take]`s as an "init" of the address (concretely,
`getSingleInitAllocStackUse` returns `truea for the above example if `%a` is
an `alloc_stack`).
rdar://108745323
In the context of promoting a `load [copy]` to a `load_borrow`, allow
the value representing the lifetime of the load to differ from the `load
[copy]` itself--it may either be the load or its only user.
If promoting the `load [copy]` to a `load_borrow` with the load itself
as the lifetime representative fails, look for a single `move_value` use
of the load. If found, attempt the optimization again with the
`move_value` as the lifetime representative.
rdar://108514447
Prevent joining lifetimes of copies with destroyed owned lexical values
if there may be deinit barriers between the final consume of the copy
and the destroy of the lexical value.
rdar://108014714
Fix a miscompile in Debug builds at -Onone.
This optimization ignores uses of owned values that aren't enclosed in
borrow scopes. This is fairly eggregious since project_box
instructions are never borrowed, which means that all local variables
have this problem.
This is a well-known issue that occurs throughout OSSA
optimizations. The reason that we don't see the problem often is that
the optimizations are hidden behind a pile of ad-hoc pattern matching,
so they only kick in for simple cases. This approach to optimization
is great at hiding problems for a long time.
We're attempting to design away this class of problems in the next
release. Until then, it's one miscompile at a time.
Fixes rdar://107420448 (Variable mutation in block isn't reflected
in outer scope: new behavior in swift 5.9)
In the absence of this bailout, reborrows can be introduced while replacing the @owned value with
a local borrow introducer. Since lifetime adjustment for this case was not implemented, disable here.
rdar://106757446
Adds to SemanticARCOpts a new step of removing move_value instructions
if they are redundant. A move_value is redundant if it adds no new
information or optimization opportunities.
An example of adding information: a lifetime becoming lexical. The new
lifetime's destroys cannot be hoisted over deinit barriers.
An example of adding an optimization opportunity: the original value
escapes but the value produced by the move_value does not escape. So
destroys of the new value can be hoisted more aggressively.
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.
`getValue` -> `value`
`getValueOr` -> `value_or`
`hasValue` -> `has_value`
`map` -> `transform`
The old API will be deprecated in the rebranch.
To avoid merge conflicts, use the new API already in the main branch.
rdar://102362022
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.
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.