Commit Graph

34 Commits

Author SHA1 Message Date
Meghana Gupta
6c2d3eb27d Bailout of CopyValueOpts when there is a pointer escape
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.
2025-03-07 10:40:37 -08:00
Meghana Gupta
24aa3296dc [NFC] Add debug msgs in copy value opts 2023-12-13 10:38:12 -08:00
Meghana Gupta
28df449d38 Merge pull request #66723 from meg-gupta/improvefindpointerescape
Refactor swift::findPointerEscape and handle additional cases
2023-06-21 21:04:21 -07:00
Meghana Gupta
031255c2d8 Rename hasPointerEscape -> findPointerEscape 2023-06-20 21:13:55 -07:00
Meghana Gupta
7cb3733e29 Rename OwnershipForwardingMixin -> ForwardingInstruction 2023-06-14 10:40:32 -07:00
Nate Chandler
a4ac481ecb [SemanticARCOpts] Keep owned lexical lifetimes.
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
2023-04-13 14:36:37 -07:00
Andrew Trick
26a62645b4 Fix MandatoryARCOpts tryJoiningCopyValueLiveRangeWithOperand.
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)
2023-03-31 20:33:53 -07: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
Andrew Trick
103a6fefb8 LinearLifetimeChecker - make DeadEndBlocks optional 2023-03-01 21:41:46 -08:00
Andrew Trick
6346bf55c5 Rename areUsesWithinTransitiveScope to ...ExtendedScope
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.
2022-10-04 13:27:48 -07:00
Nate Chandler
46fe0f7128 [Gardening] Tweaked comment grammar. 2022-08-21 21:44:31 -07:00
Nate Chandler
b467319cce [NFC] Removed unused variable. 2022-08-21 21:44:30 -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
Meghana Gupta
dc9308e13b Rename areUsesWithinLocalScope -> areUsesWithinTransitiveScope 2022-06-24 21:32:04 -07:00
Andrew Trick
febde3da2f SemanticARCOpts fix - remove deadEndBlocks checks
SemanticARCOptVisitor::performGuaranteedCopyValueOptimization was
converting this SIL

    %borrow = begin_borrow %copiedValue
    %copy = copy_value %borrow
    %borrowCopy = begin_borrow %copy
    end_borrow %borrow
    end_borrow %borrowCopy
    destroy_value %copy
    // something something
    unreachable

into

    %borrow = begin_borrow %copiedValue
    %innerBorrow = begin_borrow %borrow
    end_borrow %borrow
    end_borrow %innerBorrow
    // something something
    unreachable

Dead-end blocks are simply irrelevant for this
optimization. Unfortunately, there were multiple layers of attempted
workarounds that were hiding the real problem, except in rare cases.

Thanks Nate Chandler for reducing the test.
2021-12-09 20:23:17 -08:00
Andrew Trick
8996fb8af2 Add functionality to the OSSA BorrowedValue utility.
This abstraction is heavily used to ask about the current borrow scope
enclosing some uses. Give it the functionality it needs.

Add BorrowedValue::computeLiveness(PrunedLiveness). Get the borrow
scope's live range. A trivial 4-line implementation.

Cleanup BorrowedValue::areUsesWithinScope(). Quick check to see if a set
of uses known to be dominated by the borrow are within the borrow scope.

Add BorrowedValue::hasReborrow(). Is this local borrow scope
reborrowed? If not, then it's local scope-ending operations are the
end of its required lifetime.

Simplify BorrowedValue::gatherReborrows() to use OperandOwnership::Reborrow.
2021-10-06 15:48:08 -07:00
Andrew Trick
573df892e7 Fix BorrowingOperand more.
Don't allow an owned call argument to be considered a valid BorrowingOperand.

More generally, make sure there is a perfect equivalence between valid
BorrowingOperand and the corresponding OperandOwnership kind.
2021-06-30 15:20:19 -07:00
Andrew Trick
b689b1dabe Rename GuaranteedARCOpts to MandatoryARCOpts.
This bleeds into the implementation where "guaranteed" is used
everywhere to talk about optimization of guaranteed values. We need to
use mandatory to indicate we're talking about the pass pipeline.
2021-03-02 22:20:13 -08:00
Andrew Trick
caefb9afaa Centralize and document low-level OSSA utilities
...for handling borrow scopes:

- find[Extended]TransitiveGuaranteedUses

- BorrowingOperand::visit[Extended]ScopeEndingUses

- BorrowedValue BorrowingOperand::getBorrowIntroducingUserResult()

And document the logic.

Mostly NFC in this commit, but more RAUW cases should be correctly
handled now.

Particularly, ensure that we can cleanly handle all manner of
reborrows. This is necessary to ensure both CanonicalizeOSSA and
replace-all-uses higher-level utilities handle all cases.

This generalizes some of the logic in CanonicalizeOSSA so it can be
shared by other high-level OSSA utilities.

These utilities extend the fundamental BorrowingOperand and
BorrowedValue functionality that has been designed recently. It builds
on and replaces a mix of piece-meal functionality that was needed
during bootstrapping. These APIs are now consistent with the more
recently designed code. It should be obvious what they mean and how to
use them, should be very hard to use them incorrectly, and should be
as efficient as possible, since they're fundamental to other
higher-level utilities.

Most importantly, there were several very subtle correctness issues
that were not handled cleanly in a centralized way. There are now a
mix of higher-level utilities trying to use this underlying
functionality, but it was hard to tell if all those higher-level
utilities were covering all the subtle cases:

- checking for PointerEscapes everywhere we need to

- the differences between uses of borrow introducers and other
  guaranteed values

- handling the uses of nested borrow scopes

- transitively handling reborrows

- the difference between nested and top-level reborrows

- forwarding destructures (which can cause exponential explosion)

In short, I was fundamentally confused and getting things wrong before
designing these utilities.
2021-02-01 18:03:24 -08:00
Erik Eckstein
ddd0f4d3a9 SIL: replace SmallPtrSet<SILBasicBlock *> with BasicBlockSet in LinearLifetimeChecker
This makes it unnecessary to share a single instance of visited blocks across multiple calls the the checker.
2021-01-27 10:31:17 +01:00
Andrew Trick
a2fac95f9f OSSA ownership optimization RAUW utility fixes.
Verify that the OwnershipRAUWUtility always preserves the original
borrow scope by exhaustively switching over OperandOwnership.

And related cleanup.
2021-01-23 18:15:58 -08: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
Michael Gottesman
ee17f5e8f6 [ownership] Rename OwnershipForwardingInst -> OwnershipForwardingMixin and eliminate support for isa<> and dyn_cast<>.
Instead, I just added some static helper methods that perform the same
operations without needing to deal with generics/etc on OwnershipForwardingMixin
itself. The reason why I did this is that this Mixin is not part of the SILNode
heirarchy so we shouldn't use utilities tied to the SILNode hierarchy.
2021-01-13 10:43:41 -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
Andrew Trick
fc3205739a Add tracing and FIXMEs to CopyValueOpts 2020-12-15 22:06:04 -08: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
85965ed202 [semantic-arc] Optimize more lifetime joining when a copy_value, destroy_value are in the same block.
Specifically the optimization that is being performed here is the elimination of
lifetimes that hand off ownership in between two regions of code. Example:

```
%1 = copy_value %0
...
destroy_value %0
...
apply %consumingUser(%1)
```

We really want to handle this case since it is a natural thing that comes up in
programs and will let me eliminate the *evil* usage of emitDestroyValueOperation
in TypeLowering without needing to modify huge amounts of tests.
2020-11-25 21:57:24 -08:00
Michael Gottesman
56664088ec [semantic-arc] Expand out the infrastructure for disabling/enabling specific opts and use that to add new split up semantic-arc tests.
This split will ensure we are testing only what a specific optimization is doing
rather than all together.

NOTE: The way I split up the tests is I first split up each of the tests by
subject area by hand that I thought were specifically testing one pass. Then any
tests where the FileCheck tests started to fail due to us not running the other
passes, I put back a copy in the original semantic-arc-opts.sil to ensure we do
not regress.

Note, the tests that I copied for each of these passes
are originally from semantic-arc-opts.sil. I left them there as well so we could
see all of the opts together. I also only copied the ones that were testing pass
specific functionality.
2020-11-25 19:32:01 -08:00
Michael Gottesman
1fd400346c [semantic-arc] Eliminate simple recursive copy without borrows involved.
This doesn't happen as much as the guaranteed + owned value optimization but can
occur once we start eliminating borrow scopes. I noticed that I needed this when
looking at the arbitrary RAUW for ownership API.
2020-11-19 22:44:45 -08:00
Michael Gottesman
5a2d63d154 [semantic-arc-opts] Let the simple lifetime join optimization handle certain copies with forwarding insts.
When I originally landed this optimization, I was trying to handle simple cases
without forwarding instructions in my head. In my head, handling this with
forwarding instructions meant using OwnershipLiveRange. Sadly, I didn't realize
at the time that if I didn't use OwnershipLiveRange and just treated forwarding
insts as normal lifetime ending instructions for owned values, everything just
worked (since our check was where %5 in the following was any lifetime ending
instruction for %4c.

```
%4 = copy_value %3 : $Builtin.NativeObject
%4c = copy_value %4 : $Builtin.NativeObject
destroy_value %4 : $Builtin.NativeObject
%5 = enum $FakeOptional<Builtin.NativeObject>, #FakeOptional.some!enumelt, %4c : $Builtin.NativeObject
```

The optimization causes the above to simplified to:

```
%4 = copy_value %3 : $Builtin.NativeObject
%5 = enum $FakeOptional<Builtin.NativeObject>, #FakeOptional.some!enumelt, %4 : $Builtin.NativeObject
```

Notice importantly that we are not shrinking the lifetime of %4, so we can do
this safely without interior pointers being guarded with borrow scopes
everywhere yet.
2020-11-19 13:26:35 -08:00
Michael Gottesman
c35ff33a1f [ownership] Add a subclass for all OwnershipForwarding instructions and fix the classof to the various ownership abstract classes so isa/dyn_cast work.
I think what was happening here was that we were using one of the superclass
classofs and were getting lucky since in the place I was using this I was
guaranteed to have single value instructions and that is what I wrote as my
first case X ).

I also added more robust checks tieing the older isGuaranteed...* APIs to the
ForwardingOperand API. I also eliminated the notion of Branch being an owned
forwarding instruction. We only used this in one place in the compiler (when
finding owned value introducers), yet we treat a phi as an introducer, so we
would never hit a branch in our search since we would stop at the phi argument.
The bigger picture here is that this means that all "forwarding instructions"
either forward ownership for everything or for everything but owned/unowned.

And for those listening in, I did find one instruction that was from an
ownership forwarding subclass but was not marked as forwarding:
DifferentiableFunctionInst. With this change, we can no longer by mistake have
such errors enter the code base.
2020-11-18 12:34:18 -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
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
d26f336b0b [semantic-arc] Split out copy_value optimizations (except phi elimination) into its own file. 2020-08-31 17:57:02 -07:00