Commit Graph

17 Commits

Author SHA1 Message Date
Nate Chandler
c893c74bb4 [SemanticARCOpts] Fix miscompile at dead-ends.
With incomplete lifetimes, a value may have an "incomplete lifetime"--it
may not be destroyed on paths into dead-end regions.  When a value lacks
a destroy on a path into a dead-end region, it is effectively destroyed
at its availability boundary (e.g. an `unreachable` instruction).
Indeed, lifetime completion amounts to making such implicit destroys
explicit (with correct nesting).

`SemanticARCOpts`' `performGuaranteedCopyValueOptimization` attempts to
eliminate a `copy_value` of a guaranteed value.  To do so, it computes
the live range (`OwnershipLiveRange`) of the copy_value.  Among other
things, it checks that all destroys of the copy_value are within the
scope of all guaranteed bases of the copied value.  If any destroys are
_not_ within any of those scopes, the copy cannot be eliminated (because
the copy would have been originally live beyond the range which it would
be live in after copy elimination).

A value with an incomplete lifetime is implicitly destroyed at its
availability boundary.  So those implicit destroys along the
availability boundary must _also_ be within the scopes of those
guaranteed bases.

Previously, implicit destroys along availability boundaries were not
considered.  This resulted in invalid shortening of lifetimes--before
the transformation a value would be unconsumed up to its availability
boundary; after the transformation it would be consumed somewhere before
that.  For example:

```
sil [ossa] @f : $@convention(thin) (@owned Outer) -> () {
entry(%o : $*Outer):
  %o_borrow = begin_borrow %o : $Outer
  %i = struct_extract %o_borrow : $Outer, #Outer.inner
  %i_copy = copy_value %i : $Inner
  end_borrow %o_borrow : $Outer
  destroy_value %o : $Outer
  apply @g(%i_copy) : $@convention(thin) (@guaranteed Inner) -> ()
  unreachable // %i_copy implicitly destroyed
}
```

Here, `%i_copy` is implicitly destroyed at `unreachable` but `%i` is
consumed at the scope end of `%o_borrow`.  That means that an attempt to
RAUW `%i_copy` with `%i` would be invalid because uses of `%i_copy` may
be outside the live range of `%i`.

(Note that this happens not to occur in the above example because
there's a bailout in the case that there are no destroys, but perturbing
the example to include a cond_br on one branch of which the value is
destroyed results in the miscompile described above.)

Here, this is fixed by adding the instructions on the availability
boundary at which the value is implicitly destroyed to the live range.
Do this by adding the instructions on the availability boundary of each
def from which the live range is generated to the live range.

One wrinkle is that the OwnershipLiveRange utility is used in one place
by a utility when SIL is in an invalid state (phi uses have been
replaced with undef so values leaks on those paths).  Account for this
by manually fixing up the liveness instance passed to the lifetime
completion utility.

rdar://157291161
2025-08-08 18:06:09 -07:00
Anthony Latsis
fec049e5e4 Address llvm::PointerUnion::{is,get} deprecations
These were deprecated in
https://github.com/llvm/llvm-project/pull/122623.
2025-07-29 18:37:48 +01:00
Erik Eckstein
51e3e5ed80 Optimizer: rename BorrowArgumentsUpdater -> GuaranteedPhiUpdater
NFC
2024-11-12 09:26:59 +01:00
Erik Eckstein
6b8c6a3c3b SIL: rename updateBorrowedFrom to updateBorrowArguments
NFC
2024-11-12 09:26:58 +01:00
Tim Kientzle
1d961ba22d Add #include "swift/Basic/Assertions.h" to a lot of source files
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)
2024-06-05 19:37:30 -07:00
Erik Eckstein
e14c1d1f62 SIL, Optimizer: update and handle borrowed-from instructions
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.
2024-04-10 13:38:10 +02:00
Meghana Gupta
21e829bace Disable owned to guaranteed phi transformation when the borrow introducers have a local scope
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
2023-03-17 09:43:08 -07:00
Meghana Gupta
730b513fad [SemanticARCOpts] Remove unnecessary borrow scope for @guaranteed function arg when used as a phi operand 2022-10-21 22:31:04 -07:00
Meghana Gupta
9b01b87b4b Update SemanticARCOpts for @guaranteed forwarding phi support 2022-10-19 19:54:28 -07:00
Michael Gottesman
1e6187c4f4 [sil] Update all usages of old API SILValue::getOwnershipKind() in favor of new ValueBase::getOwnershipKind().
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.
2022-07-26 11:46:23 -07:00
Michael Gottesman
2ae43f97af [ownership] Eliminate Optional return value APIs from OwnershipUtils in favor of an Invalid enum case.
Should be NFC.
2021-01-14 11:02:10 -08:00
Slava Pestov
e675bee26c AST: Split off DependencyCollector.h from EvaluatorDependencies.h
Also remove some unnecessary #includes from DependencyCollector.h,
which necessitated adding #includes in various other files.
2020-12-23 00:00:25 -05:00
Michael Gottesman
5dbd34d08f [semantic-arc] Prevent future pointer invalidation issues in the OwnedToGuaranteedPhiOp transform.
The specific problem here is that I am going to be adding some code to
SemanticARCOpts that eliminates reborrows and may need to create new phi
arguments and thus add arguments to edges. The weird thing about this is that
doing so actually requires us to create a new terminator!

This means that subtle pointer invalidation issues can occur here. To work
around that we store our terminators as SILBasicBlock, operand number since we
can always immediately find a terminator from its basic block. If we do not have
a terminator, we keep on just storing the SILInstruction itself.

NOTE: This only saves us from additive changes. Deletions are still an issue.
2020-12-04 11:41:43 -08:00
Michael Gottesman
c026e95cce [ownership] Extract out SILOwnershipKind from ValueOwnershipKind into its own type and rename Invalid -> Any.
This makes it easier to understand conceptually why a ValueOwnershipKind with
Any ownership is invalid and also allowed me to explicitly document the lattice
that relates ownership constraints/value ownership kinds.
2020-11-10 14:29:11 -08:00
Michael Gottesman
8d898e5180 [semantic-arc] Extract owned phi to guaranteed phi conversion from the visitor to its own function that works on the SemanticARCContext. 2020-09-17 00:18:26 -05:00
Michael Gottesman
915ccc0854 [semantic-arc] Extract out from the main visitor a context object for individual sub optimizations.
This patch moves state from the main SemanticARCOptVisitor struct to instead be
on a context object. Sub-transformations should not need to know about the
visitor since how it processes things is orthogonal from the transformations
themselves.
2020-09-16 19:11:07 -05:00
Michael Gottesman
04da864090 [semantic-arc] Split out owned -> guaranteed phi opt into its own file. 2020-09-01 12:25:46 -07:00