Commit Graph

694 Commits

Author SHA1 Message Date
Andrew Trick
ae64ff5cb0 Rename PrunedLiveness.clear() to invalidate()
Because SILBitfield cannot be cleared.
2023-03-22 01:36:48 -07:00
Andrew Trick
15796e3ff9 PrunedLiveness: add a SILFunction argument
So that liveness can migrate to using a SILBitfield.
2023-03-22 01:36:48 -07:00
Joe Groff
69e4b95fb8 SIL: Model noescape partial_applys with ownership in OSSA.
Although nonescaping closures are representationally trivial pointers to their
on-stack context, it is useful to model them as borrowing their captures, which
allows for checking correct use of move-only values across the closure, and
lets us model the lifetime dependence between a closure and its captures without
an ad-hoc web of `mark_dependence` instructions.

During ownership elimination, We eliminate copy/destroy_value instructions and
end the partial_apply's lifetime with an explicit dealloc_stack as before,
for compatibility with existing IRGen and non-OSSA aware passes.
2023-02-16 21:43:53 -08:00
Andrew Trick
13e1aa4467 Add OwnershipLiveness utilities
Encapsulate all the complexity of reborrows and guaranteed phi in 3
ownership liveness interfaces:

LinerLiveness, InteriorLiveness, and ExtendedLiveness.
2023-02-10 09:39:18 -08:00
Michael Gottesman
9ae7ff30dd [move-only] Wire up emission of the location for non-consuming uses for objects and emit more precise errors for consuming use errors.
Specifically, previously if we emitted an error we just dumped all of the
consuming uses. Now instead for each consuming use that needs a copy, we perform
a search for a specific boundary use (consuming or non-consuming) that is
reachable from the former and emit a specialized error for it. Thus we emit for
the two consuming case the normal consumed twice error, and now for
non-consuming errors we emit the "use after consume" error.
2023-02-04 10:43:13 -08:00
Michael Gottesman
20479c96fb [move-only] Refactor CanonicalizeOSSALifetime::canonicalizeValueLifetime into an API that computes liveness and a second API that rewrites copies/destroys and fix up MoveOnly checkers to use it.
For those who are unaware, CanonicalizeOSSALifetime::canonicalizeValueLifetime()
is really a high level driver routine for the functionality of
CanonicalizeOSSALifetime that computes liveness and then rewrites copies using
boundary information. This change introduces splits the implementation of
canonicalizeValueLifetime into two parts: a first part called computeLiveness
and a second part called rewriteLifetimes. Internally canonicalizeValueLifetime
still just calls these two methods.

The reason why I am doing this is that it lets the move only object checker use
the raw liveness information computed before the rewriting mucks with the
analysis information. This information is used by the checker to compute the raw
liveness boundary of a value and use that information to determine the list of
consuming uses not on the boundary, consuming uses on the boundary, and
non-consuming uses on the boundary. This is then used by later parts of the
checker to emit our errors.

Some additional benefits of doing this are:

1. I was able to eliminate callbacks in the rewriting stage of
CanonicalOSSALifetimes which previously gave the checker this information.

2. Previously the move checker did not have access to the non-consuming boundary
uses causing us to always fail appropriately, but sadly not emit a note showing
the non-consuming use. I am going to wire this up in a subsequent commit.

The other change to the implementation of the move checker that this caused is
that I needed to add an extra diagnostic check for instructions that consume the
value twice or consume the value and use the value. The reason why this must be
done is that liveness does not distinguish in between different operands on the
same instruction meaning such an error would be lost.
2023-02-04 10:43:13 -08:00
Nate Chandler
4f845ccc52 [CanOSSALifetime] Option to shrink to scopes.
For most uses, some access scopes must be "respected"--if an extended
value's original lifetime originally extends beyond an access scope, its
canonicalized lifetime must not end _within_ such scopes (although
ending before them is fine).  Currently, to be conservative, the utility
applies this behavior to all access scopes.

For move-only values, however, lifetimes end at final consumes without
regard to access scopes.

Allow this behavior to be controlled by whether or not a
NonLocalAccessBlockAnalysis is provided to the utility in its
constructor.

rdar://104635319
2023-01-28 10:23:22 -08:00
Nate Chandler
10e86d6653 [CanonicalizeBorrowScope] Look through moves.
When encountering inside a borrow scope a non-lexical move_value or a
move_value [lexical] where the borrowed value is itself already lexical,
delete the move_value and regard its uses as uses of the moved-from
value.
2023-01-25 16:32:09 -08:00
Nate Chandler
03eb567d74 [Test] Print helpful info on bad unit tests.
If a unit test is miswritten in the sense that the test expects an
instance of one type by an instance of some other type is specified,
print that out.
2023-01-23 13:26:13 -08:00
Erik Eckstein
edce513580 SIL: simplify replaceBranchTarget
Instead of re-creating all kind of terminator instructions, just re-assign the terminator's successor.
2023-01-16 18:55:35 +01:00
Meghana Gupta
3660a1e6a9 Remove borrow scope adjustment for @guaranteed phi args 2023-01-06 23:50:07 -08:00
Michael Gottesman
c33b9ee8e3 [move-only] Refactor both implementations to use the same diagnostic infrastructure.
This let me clean up the parts of the address infrastructure that rely on the
object checker.
2022-12-15 09:59:35 -08:00
Nate Chandler
9ad44a5056 [ClosureLifetimeFixup] Dealloc args on frontier.
Previously, the dealloc_stacks created for the alloc_stacks used to pass
@in_guaranteed arguments to on_stack closures were created after the
users of the closure.  When SILGen created these alloc_stacks in the
same block as the users, this happened to work.  Now that
AddressLowering creates such alloc_stacks elsewhere, this approach
results in invalid SIL.

Here, the dealloc_stacks are instead at the end of each block in the
dominance frontier of the alloc_stack.
2022-12-13 11:46:47 -08:00
Erik Eckstein
c180d1363e SIL: simplify deleting instruction while iterating over instructions.
Add `deletableInstructions()` and `reverseDeletableInstructions()` in SILBasicBlock.
It allows deleting instructions while iterating over all instructions of the block.
This is a replacement for `InstructionDeleter::updatingRange()`.
It's a simpler implementation than the existing `UpdatingListIterator` and `UpdatingInstructionIteratorRegistry`, because it just needs to keep the prev/next pointers for "deleted" instructions instead of the iterator-registration machinery.
It's also safer, because it doesn't require to delete instructions via a specific instance of an InstructionDeleter (which can be missed easily).
2022-12-12 19:08:54 +01:00
Saleem Abdulrasool
a630fa7a9a SILOptimzer: correct a case of UB
The current `UpdatingInstructionIteratorRegistry` referenced `this` in
the member initializer list.  As per class.cdtor 11.9.5p1, this is UB as
for any class with a non-trivial constructor, referencing the base class
of the object before the constructor begins execution is not permitted.
We attempted to capture `this` in the lambda that was used to initialise
the member.  This was being exploited by the MSVC compiler resulting in
incorrect execution of the instruction deleter.
2022-12-11 19:05:07 -08:00
Erik Eckstein
ab1b343dad use new llvm::Optional API
`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
2022-11-21 19:44:24 +01:00
Erik Eckstein
8ca0143279 Remove uses of std::iterator
It's deprecated in C++17
2022-11-14 09:35:40 +01:00
Erik Eckstein
0403a21d34 use the new side effects in the performance inliner 2022-11-09 08:06:19 +01:00
Allan Shortlidge
cfb5ad8836 Merge pull request #61779 from tshortli/break-cycle-loop-can-duplicate
SILOptimizer: Break circular dependency with SIL library by moving `canDuplicate()`
2022-10-27 22:43:47 -07:00
Allan Shortlidge
0921480486 SILOptimizer: Break circular dependency with SIL library by moving canDuplicate().
Fixes a cycle introduced by https://github.com/apple/swift/pull/61051.
2022-10-27 16:12:05 -07:00
Allan Shortlidge
4f8d33ffb5 SILOptimizer: Break circular dependency with SIL library by moving extendStoreBorrow(). 2022-10-27 15:29:37 -07:00
Andrew Trick
cdbc9170c5 Merge pull request #61648 from atrick/jump-thread
[NFC] OSSA jump-threading support
2022-10-24 21:23:13 -07:00
Nate Chandler
d40500bbca [Gardening] Tweaked doc to avoid warning. 2022-10-24 12:27:05 -07:00
Andrew Trick
04aa16f97d OSSA: CheckedCastBrJumpThreading: support using RAUW utility.
Begin adding support for OSSA to checked-cast jump-threading based on
the new ownership utilities.

TODO:

Finish migrating to the new utilities in OwnershipOptUtils.

Ensure full unit test coverage.
2022-10-22 21:57:47 -07:00
Nate Chandler
2f18af8979 [Test] Allowed referring to block arguments. 2022-10-21 13:58:42 -07:00
Nate Chandler
b9a8334756 [Test] Contextualized bare test_spec refs.
Made bare @instruction and @block more useful.  Rather than referring to
the first instruction and block in the current function, instead, they
now refer to the instruction after the test_specification instruction
(which must always exist) and the block containing the
test_specification instruction.
2022-10-20 13:34:13 -07:00
Nate Chandler
b970e950ed [Test] Allow insts to be taken as values. 2022-10-20 13:34:13 -07:00
Nate Chandler
4b85d0a9ca [DestroyHoisting] Barriers use callee analysis.
Pass a BasicCalleeAnalysis instance to isDeinitBarrier.  This enables
LexicalDestroyHoisting to hoist destroys over applies of functions which
are not deinit barriers.
2022-10-18 21:23:22 -07:00
Nate Chandler
f85074d1ba [ShrinkBorrowScope] Barriers use callee analysis.
Pass a BasicCalleeAnalysis instance to isDeinitBarrier.  This will allow
ShrinkBorrowScope to hoist end_borrows over applies of functions which
are not deinit barriers.
2022-10-18 21:23:22 -07:00
Nate Chandler
7ea336367d [NFC] Port isDeinitBarrier to Swift.
Added new C++-to-Swift callback for isDeinitBarrier.

And pass it CalleeAnalysis so it can depend on function effects.  For
now, the argument is ignored.  And, all callers just pass nullptr.

Promoted to API the mayAccessPointer component predicate of
isDeinitBarrier which needs to remain in C++.  That predicate will also
depends on function effects.  For that reason, it too is now passed a
BasicCalleeAnalysis and is moved into SILOptimizer.

Also, added more conservative versions of isDeinitBarrier and
maySynchronize which will never consider side-effects.
2022-10-18 21:23:22 -07:00
Nate Chandler
ffa0cc423d [Gardening] Doc'd test arg parsing helper. 2022-10-14 07:52:39 -07:00
Nate Chandler
6d62770ffe [SILUnitTests] Added check for remaining args. 2022-10-14 07:47:52 -07:00
Nate Chandler
82cd580145 [SILOptimizer] Add faux unit testing mechanism.
The testing works by way of a new pass "UnitTestRunner" and a new
instruction test_specification.  When a function contains
test_specification instructions, it invokes the UnitTest subclass named
in the test_specification instruction with the arguments specified in
that instruction.

For example, when running the unit-test-runner class, having the
instructions

```
test_specification "my-neato-utility 19 @function[callee].block[2] @trace[2]"
test_specification "my-neato-utility 43 @block @trace"
```

would result in the test associated with "my-neato-utility" in
UnitTestRunner.cpp being invoked twice.  Once with (19, aBlock, aValue),
and once with (43, anotherBlock, someOtherValue).  That UnitTest
subclass class would need to call takeUInt, takeBlock, and takeTrace on
the Arguments struct it is invoked with.  It would then pass those
arguments along to myNeatoUtility and dump out interesting results.  The
results would then be FileChecked.
2022-10-11 17:29:59 -07:00
Nate Chandler
03253dbf48 [CanonicalizeOSSALifetime] Extend Onone lifetimes.
To improve the debugging experience of values whose lifetimes are
canonicalized without compromising the semantics expressed in the source
language, when canonicalizing OSSA lifetimes at Onone, lengthen
lifetimes as much as possible without incurring copies that would be
eliminated at O.

rdar://99618502
2022-10-08 16:08:35 -07:00
Nate Chandler
c1bbfc1f8a [CanonicalizeOSSALifetime] Separated steps.
Rather than having finding the boundary be a single combined step,
separate finding the original boundary from extending that boundary.
This enables inserting an optional step between those steps, namely to
extend unconsumed liveness to its original extent at Onone.
2022-10-08 16:08:35 -07:00
Nate Chandler
8cf65c6c8a [CanonicalizeOSSALifetime] Handle live phis.
It is possible for phis to be marked live.  With guaranteed phis, they
will be the last uses and be non-consuming.  In this case, the
merge block will have multiple predecessors whose terminators are on the
boundary.  When inserting destroys, track whether a merge point has been
visited previously.

To facilitate this, restructure the boundary extension and destroy
insertion code.

Previously, the extender was building up a list of places at which to
insert destroys.  In particular it was using the "boundary edge"
collection for all blocks at the beginning of which a destroy should be
created.  In particular, it would add merge blocks. Such blocks are not
boundary blocks.

Here, the extender produces a PrunedLivenessBoundary which doesn't
violate that invariant.

This required some changes to the destroy insertion code to find where
to insert destroys.  It is now similar to
PrunedLivenessBoundary::visitInsertionPoints and could be used as a
template for a PrunedLivenessBoundary::visitBoundaryPoints through which
::visitInsertionPoints might be factored.
2022-10-08 15:56:23 -07:00
Nate Chandler
65ffed3cf9 [CanonicalizeOSSALifetime] Minor cleanup. 2022-10-08 15:15:03 -07:00
Nate Chandler
2c5ee0f7ad [CanonicalizeOSSALifetime] Fixed caching bug.
Previously, the destroys set (now set vector) wasn't ever being cleared.
The result was that users could get overly pessimistic behavior if they
had previously used the utility with a destroy that came after the
destroys relevant for its current run. Here, it is cleared when the
utility is initialized with a new def.  Addresses a TODO in the
copy_propagation test.
2022-10-06 13:45:54 -07:00
Nate Chandler
9cd4cdb11b [NFC] Removed unused field. 2022-10-05 17:59:08 -07:00
Nate Chandler
4fc42a63a3 [CanonicalizeOSSALifetime] Renamed file.
Matched to the name of the utility.
2022-10-05 17:07:05 -07:00
Nate Chandler
8a3dc109ec [CanonicalizeOSSABoundary] Used ::computeBoundary.
Previously, CanonicalizeOSSALifetime had its own copy of a variation of
the code for computing the liveness boundary that PrunedLiveness has.
Here, it is switched over to using PrunedLiveness' version.

In order to do that without complicating the interface for PrunedLivness
by adding a visitor, the extra bookkeeping that was being done for
destroy_values and debug_values is dropped.  Instead, after getting an
original boundary from PrunedLiveness::computeBoundary, the boundary is
extended out to preexisting destroys which are not separated from the
original boundary by "interesting" instructions.
2022-10-05 17:07:05 -07:00
Nate Chandler
91d530f15e [CanonicalizeOSSALifetime] Ignore debug_values.
Added Kind::DebugValueInst to the list of opcodes that
CanonicalizeOSSALifetime doesn't go out of its way to hoist over.
2022-10-05 13:04:52 -07:00
Nate Chandler
2f36201504 [NFC] Removed unused field.
It should have been removed when poison mode was removed from
CanonicalizeOSSALifetime.
2022-10-05 10:53:18 -07:00
Nate Chandler
9171f77313 [NFC] Removed unused field.
It should have been removed when poison mode was removed from
CanonicalizeOSSALifetime.
2022-10-05 10:53:18 -07:00
Andrew Trick
40e03ef782 Update passes to use SSAPrunedLiveness or MultiDefPrunedLiveness 2022-10-04 13:27:47 -07:00
Andrew Trick
ca503b54b7 Redesign PrunedLiveness APIs, introducing live ranges
First restore the basic PrunedLiveness abstraction to its original
intention. Move code outside of the basic abstraction that polutes the
abstraction and is fundamentally wrong from the perspective of the
liveness abstraction.

Most clients need to reason about live ranges, including the def
points, not just liveness based on use points. Add a PrunedLiveRange
layer of types that understand where the live range is
defined. Knowing where the live range is defined (the kill set) helps
reliably check that arbitrary points are within the boundary. This
way, the client doesn't need to be manage this on its own. We can also
support holes in the live range for non-SSA liveness. This makes it
safe and correct for the way liveness is now being used. This layer
safety handles:

- multiple defs
- instructions that are both uses and defs
- dead values
- unreachable code
- self-loops

So it's no longer the client's responsibility to check these things!

Add SSAPrunedLiveness and MultiDefPrunedLiveness to safely handle each
situation.

Split code that I can't figure out into
DiagnosticPrunedLiveness. Hopefully it will be deleted soon.
2022-10-04 13:27:44 -07:00
Josh Soref
730b16c569 Spelling siloptimizer
* access
* accessed
* accesses
* accessor
* acquiring
* across
* activated
* additive
* address
* addresses'
* aggregated
* analysis
* and
* appropriately
* archetype
* argument
* associated
* availability
* barriers
* because
* been
* beginning
* belongs
* beneficial
* blocks
* borrow
* builtin
* cannot
* canonical
* canonicalize
* clazz
* cleanup
* coalesceable
* coalesced
* comparisons
* completely
* component
* computed
* concrete
* conjunction
* conservatively
* constituent
* construct
* consuming
* containing
* covered
* creates
* critical
* dataflow
* declaration
* defined
* defining
* definition
* deinitialization
* deliberately
* dependencies
* dependent
* deserialized
* destroy
* deterministic
* deterministically
* devirtualizes
* diagnostic
* diagnostics
* differentiation
* disable
* discipline
* dominate
* dominates
* don't
* element
* eliminate
* eliminating
* elimination
* embedded
* encounter
* epilogue
* epsilon
* escape
* escaping
* essential
* evaluating
* evaluation
* evaluator
* executing
* existential
* existentials
* explicit
* expression
* extended
* extension
* extract
* for
* from
* function
* generic
* guarantee
* guaranteed
* happened
* heuristic
* however
* identifiable
* immediately
* implementation
* improper
* include
* infinite
* initialize
* initialized
* initializer
* inside
* instruction
* interference
* interferes
* interleaved
* internal
* intersection
* intractable
* intrinsic
* invalidates
* irreducible
* irrelevant
* language
* lifetime
* literal
* looks
* materialize
* meaning
* mergeable
* might
* mimics
* modification
* modifies
* multiple
* mutating
* necessarily
* necessary
* needsmultiplecopies
* nonetheless
* nothing
* occurred
* occurs
* optimization
* optimizing
* original
* outside
* overflow
* overlapping
* overridden
* owned
* ownership
* parallel
* parameter
* paths
* patterns
* pipeline
* plottable
* possible
* potentially
* practically
* preamble
* precede
* preceding
* predecessor
* preferable
* preparation
* probably
* projection
* properties
* property
* protocol
* reabstraction
* reachable
* recognized
* recursive
* recursively
* redundant
* reentrancy
* referenced
* registry
* reinitialization
* reload
* represent
* requires
* response
* responsible
* retrieving
* returned
* returning
* returns
* rewriting
* rewritten
* sample
* scenarios
* scope
* should
* sideeffects
* similar
* simplify
* simplifycfg
* somewhat
* spaghetti
* specialization
* specializations
* specialized
* specially
* statistically
* substitute
* substitution
* succeeds
* successful
* successfully
* successor
* superfluous
* surprisingly
* suspension
* swift
* targeted
* that
* that our
* the
* therefore
* this
* those
* threshold
* through
* transform
* transformation
* truncated
* ultimate
* unchecked
* uninitialized
* unlikely
* unmanaged
* unoptimized key
* updataflow
* usefulness
* utilities
* villain
* whenever
* writes

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
2022-10-03 18:31:33 -04:00
Nate Chandler
129dadbe70 [CopyPropagation] Removed poison mode.
The Onone strategy will be to shorten lifetimes as little as possible
while eliminating as many copies as are eliminated at -O.
2022-09-28 17:13:24 -07:00
nate-chandler
cd04e9eb3b Merge pull request #60792 from nate-chandler/canonicalize_ossa_lifetime/access_scope_ends
[CopyProp] Don't extend lifetime over end_access.
2022-08-26 15:59:16 -07:00
Nate Chandler
477461b89d [CopyProp] Don't extend lifetime over end_access.
If there is a consuming use of the value inside an access scope, the
lifetime should not be extended over the end_access instruction.
2022-08-26 11:13:37 -07:00