Commit Graph

249 Commits

Author SHA1 Message Date
Michael Gottesman
821f1f419a [sil] Fix a thinko in a comment. 2021-01-14 11:45:35 -08:00
Andrew Trick
a11a59b9c7 Minor comment typo 2021-01-13 23:44:28 -08:00
Michael Gottesman
ffa55937c4 Merge pull request #35297 from gottesmm/ossa-sil-combine-2
[sil-combine] Fix for Ownership round 2
2021-01-13 20:22:05 -08:00
Andrew Trick
7c3865c663 Move canAcceptUnownedValue to SILValue.h.
Now all the logic for mapping OperandOwnership to operand constraints
is defined in one place and fits on a single page.
2021-01-13 10:50:51 -08:00
Michael Gottesman
90f3846bb8 [sil] Define ValueBase::getNextInstruction().
Sometimes when you are working with SILValues, you need a "next" insertion
point. This creates a problem with the SILValue API since even though one can
get an instruction or an insertion point for a value, to find the appropriate
next instruction one needs to pierce through the API and see if one has a
SILArgument or SILInstruction breaking the whole point of abstraction. The
specific problem here is that a SILArgument's "next instruction" is the first
element of the block (that is ValueBase::getDefiningInsertionPoint()) and
SILInstruction's "next instruction" is
std::next(ValueBase::getDefiningInsertionPoint()). This new
API (ValueBase::getNextInstruction()) handles this case for the compiler writer
and eliminates unnecessary code contortions.

I also did a little cleanup where I moved a doxygen comment from a near by a
const_casting trampoline method to the method that the trampoline called (see
getDefiningInsertionPoint()).
2021-01-13 10:43:41 -08:00
Andrew Trick
24fa28808e Comment OwnershipConstraints with respect to Unowned values. 2021-01-01 21:20:23 -08:00
Andrew Trick
93c884e6b5 Comment OperandOwnership 2021-01-01 19:22:19 -08:00
Andrew Trick
ab42f753f7 Remove OperandOwnership::NestedBorrow.
Now that OperandOwnership determines the operand constraints, it
doesn't make sense to distinguish between Borrow and NestedBorrow at
this level. We want these uses to automatically convert between the
nested/non-nested state as the operand's ownership changes. The use
does not need to impose any constraint on the ownership of the
incoming value.

For algorithms that need to distinguish nested borrows, it's still
trivial to do so.
2021-01-01 19:22:19 -08:00
Andrew Trick
ce2a7cfe0e Clearly discriminate OperandOwnership::NonUse and TrivialUse.
A NonUse operand does not use the value itself, so it ignores
ownership and does not require liveness. This is for operands that
represent dependence on a type but are not actually passed the value
of that type (e.g. they may refer an open_existential). This could be
used for other dependence-only operands in the future.

A TrivialUse operand has undefined ownership semantics aside from
requiring liveness. Therefore it is only legal to pass the use a value
with ownership None (a trivial value). Contrast this with things like
InstantaneousUse or BitwiseEscape, which just don't care about
ownership (i.e. they have no ownership semantics.

All of the explicitly listed operations in this category require
trivially typed operands. So the meaning is obvious to anyone
adding SIL operations and updating OperandOwnership.cpp, without
needing to decifer the value ownership kinds.
2021-01-01 19:22:10 -08:00
swift-ci
07dbf4ef57 Merge pull request #35157 from atrick/remove-deadblocks 2020-12-20 17:07:35 -08:00
Andrew Trick
fe6e87913a Remove the default DEBlocks = nullptr argument from verifyOwnership.
Passing nullptr was undefined behavior because ReborrowVerifier takes
a reference to DeadEndBlocks.
2020-12-20 14:46:43 -08:00
Michael Gottesman
368f8acc4b [sil] Eliminate a confusing optional method result by changing type dependent operands to have OwnershipKind::None instead of returning Optional::None from Operand::getOperandOwnership().
This eliminates when talking about this API an ambiguity in between
Optional::None (the C++ ADT) and OwnershipKind::None (the ownership kind).
2020-12-18 19:33:27 -08:00
Andrew Trick
f777e0a70e Convert OperandOwnership from an enum class to a struct enum. 2020-12-17 21:24:41 -08:00
Andrew Trick
84768bcdb3 OSSA: Add requirements on Unowned uses.
Clarify which uses are allowed to take Unowned values. Add enforcement
to ensure that Unowned values are not passed to other uses.

Operations that can take unowned are:

- copy_value
- apply/return @unowned argument
- aggregates (struct, tuple, destructure, phi)
- forwarding operations that are arbitrary type casts

Unowned values are currently borrowed within ObjC deinitializers
materialized by the Swift compiler. This will be banned as soon as
SILGen is fixed.
2020-12-17 21:08:56 -08:00
Andrew Trick
b1dba2554e Introduce OperandOwnership to classify OSSA uses.
Migrating to this classification was made easy by the recent rewrite
of the OSSA constraint model. It's also consistent with
instruction-level abstractions for working with different kinds of
OperandOwnership that are being designed.

This classification vastly simplifies OSSA passes that rewrite OSSA
live ranges, making it straightforward to reason about completeness
and correctness. It will allow a simple utility to canonicalize OSSA
live ranges on-the-fly.

This avoids the need for OSSA-based utilities and passes to hard-code
SIL opcodes. This will allow several of those unmaintainable pieces of
code to be replaced with a trivial OperandOwnership check.

It's extremely important for SIL maintainers to see a list of all SIL
opcodes associated with a simple OSSA classification and set of
well-specified rules for each opcode class, without needing to guess
or reverse-engineer the meaning from the implementation. This
classification does that while eliminating a pile of unreadable
macros.

This classification system is the model that CopyPropagation was
initially designed to use. Now, rather than relying on a separate
pass, a simple, lightweight utility will canonicalize OSSA
live ranges.

The major problem with writing optimizations based on OperandOwnership
is that some operations don't follow structural OSSA requirements,
such as project_box and unchecked_ownership_conversion. Those are
classified as PointerEscape which prevents the compiler from reasoning
about, or rewriting the OSSA live range.

Functional Changes:

As a side effect, this corrects many operand constraints that should
in fact require trivial operand values.
2020-12-16 01:58:53 -08:00
Michael Gottesman
43a89e0c65 [ownership] Some small fixes from Andy's review.
I merged the original PR since it was rather large. These are the remaining
small fixes.
2020-11-10 22:44:13 -08:00
Michael Gottesman
a294ab61ad [ownership] Eliminate OperandOwnershipKindMap in favor of OwnershipConstraint.
I also used this as a moment to clarify the lattice that related
ValueOwnershipKind and OwnershipConstraint.
2020-11-10 19:07:30 -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
f16c4ba203 [ownership] Convert ValueOwnershipKind to have an Invalid state instead of using optional.
At Andy's request. If it creates too much noise in covered switches, we may go
back to the original.
2020-11-10 10:34:44 -08:00
Michael Gottesman
642a993702 [ownership] Rename Operand::isConsumingUse() -> Operand::isLifetimeEnding().
This makes it clearer that isConsumingUse() is not an owned oriented API and
returns also for instructions that end the lifetime of guaranteed values like
end_borrow.
2020-11-08 13:23:17 -08:00
Michael Gottesman
2ef7a212cd [ownership] Rename the cases of UseLifetimeConstraint to use clearer language
Specifically,

* MustBeLive -> NonLifetimeEnding
* MustBeInvalidated -> LifetimeEnding
2020-11-08 13:23:17 -08:00
Michael Gottesman
e5c98ad2c7 [ownership] Now that we allow reborrows eliminate isForwardingSubValue it is dead. 2020-11-05 19:42:10 -08:00
Meghana Gupta
601ea65b5d [ownership] Add a new ReborrowVerifier
This updates how we model reborrow's lifetimes for ownership verification.
Today we follow and combine a borrow's lifetime through phi args as well.
Owned values lifetimes end at a phi arg. This discrepency in modeling
lifetimes leads to the OwnershipVerifier raising errors incorrectly for
cases such as this, where the borrow and the base value do not dominate
the end_borrow:

bb0:
  cond_br undef, bb1, bb2
bb1:
  %copy0 = copy_value %0
  %borrow0 = begin_borrow %copy0
  br bb3(%borrow0, %copy0)
bb2:
  %copy1 = copy_value %1
  %borrow1 = begin_borrow %copy1
  br bb3(%borrow1, %copy1)
bb3(%borrow, %baseVal):
  end_borrow %borrow
  destroy_value %baseVal

This PR adds a new ReborrowVerifier. The ownership verifier collects borrow's
lifetime ending users and populates the worklist of the ReborrowVerifier
with reborrows and the corresponding base value.
ReborrowVerifier then verifies that the lifetime of the reborrow is
within the lifetime of the base value.
2020-10-29 20:46:37 -07:00
Michael Gottesman
50265140aa [sil] Define ValueOwnershipKind::isCompatibleWith(SILValue v).
This just returns isCompatibleWith(v.getOwnershipKind()). Just makes some code
easier to write.
2020-08-04 14:04:08 -07:00
David Zarzycki
fae2c19edb NFC: Make SILType.h and SILDeclRef.h not depend on SIL/*.h
SILType and SILDeclRef do not actually need anything from SIL/*.h. Also,
a few dependencies can be pushed out of the headers into cpp files to
speed up incremental rebuilds.
2020-07-01 08:05:58 -04:00
Michael Gottesman
f373f6ef12 [ownership] Add an exhaustive load borrow invalidation checker.
This verifier validates that while a load_borrow's value is live (that is until
it is invalidated by its end_borrow), the load_borrow's address source is never
written to.

The reason why this verifier is especially important now is that I am adding
many optimizations that convert `load [copy]` -> `load_borrow`. If that
optimization messes up, we break this invariant [in fact, an optimization I am
working on right now violated the invariant =--(]. So by adding this verifier I
am checking that semantic arc opts doesn't break it as well as eliminating any
other such bugs from the compiler (in the future).
2020-04-27 16:07:27 -07:00
Michael Gottesman
fced2398c5 [semantic-arc] Change LiveRange to work with Operand instead of Operand->getUser().
This is just better information to have since one wants to not only know the
instruction, but also the specific value used on the instruction since behavior
can vary depending upon that. The operand is what ties the two together so it is
a natural fit.

Now that this is done, I am going to work on refactoring out converting a
LiveRange from @owned -> @guaranteed. It will be a consuming operation using a
move operator since once the transformation has completed, the LiveRange no
longer exists.

I need this refactored functionality since I am going to need it when
eliminating phi-webs.
2020-03-04 17:07:48 -08:00
Michael Gottesman
bdf6143df5 [ownership] Add simple support for concatenating together simple live ranges that do not need LiveRange analysis.
Specifically, this PR adds support for optimizing simple cases where we do not
need to compute LiveRanges with the idea of first doing simple transforms that
involve small numbers of instructions first. With that in mind, we only optimize
cases where our copy_value has a single consuming user and our owned value has a
single destroy_value. To understand the transform here, consider the following
SIL:

```
  %0 = ...
  %1 = copy_value %0                 (1)
  apply %guaranteedUser(%0)          (2)
  destroy_value %0                   (3)
  apply %cviConsumer(%1)             (4)
```

We want to eliminate (2) and (3), effectively joining the lifetimes of %0 and
%1, transforming the code to:

```
  %0 = ...
  apply %guaranteedUser(%0)          (2)
  apply %cviConsumer(%0)             (4)
```

Easily, we can always do this transform in this case since we know that %0's
lifetime ends strictly before the end of %1's due to (3) being before (4). This
means that any uses that require liveness of %0 must be before (4) and thus no
use-after-frees can result from removing (3) since we are not shrinking the
underlying object's lifetime. Lets consider a different case where (3) and (4)
are swapped.

```
  %0 = ...
  %1 = copy_value %0                 (1)
  apply %guaranteedUser(%0)          (2)
  apply %cviConsumer(%1)             (4)
  destroy_value %0                   (3)
```

In this case, since there aren't any liveness requiring uses of %0 in between
(4) and (3), we can still perform our transform. But what if there was a
liveness requiring user in between (4) and (3). To analyze this, lets swap (2)
and (4), yielding:

```
  %0 = ...
  %1 = copy_value %0                 (1)
  apply %cviConsumer(%1)             (4)
  apply %guaranteedUser(%0)          (2)
  destroy_value %0                   (3)
```

In this case, if we were to perform our transform, we would get a use-after-free
due do the transform shrinking the lifetime of the underlying object here from
ending at (3) to ending at (4):

```
  %0 = ...
  apply %cviConsumer(%1)             (4)
  apply %guaranteedUser(%0)          (2) // *kaboom*
```

So clearly, if (3) is after (4), clearly, we need to know that there aren't any
liveness requiring uses in between them to be able to perform this
optimization. But is this enough? Turns out no. There are two further issues
that we must consider:

1. If (4) is forwards owned ownership, it is not truly "consuming" the
underlying value in the sense of actually destroying the underlying value. This
can be worked with by using the LiveRange abstraction. That being said, this PR
is meant to contain simple transforms that do not need to use LiveRange. So, we
bail if we see a forwarding instruction.

2. At the current time, we may not be able to find all normal uses since all of
the instructions that are interior pointer constructs (e.x.: project_box) have
not been required yet to always be guarded by borrows (the eventual end
state). Thus we can not shrink lifetimes in general safely until that piece of
work is done.

Given all of those constraints, we only handle cases here where (3) is strictly
before (4) so we know 100% we are not shrinking any lifetimes. This effectively
is causing our correctness to rely on SILGen properly scoping lifetimes. Once
all interior pointers are properly guarded, we will be able to be more
aggressive here.

With that in mind, we perform this transform given the following conditions
noting that this pattern often times comes up around return values:

1. If the consuming user is a return inst. In such a case, we know that the
   destroy_value must be before the actual return inst.

2. If the consuming user is in the exit block and the destroy_value is not.

3. If the consuming user and destroy_value are in the same block and the
   consuming user is strictly later in that block than the destroy_value.

In all of these cases, we are able to optimize without the need for LiveRanges.
I am going to add support for this in a subsequent commit.
2020-03-01 19:59:54 -08:00
Michael Gottesman
ae6cd35751 [ownership] Add helper method Operand::isConsumingUse() const.
This just provides a higher level of abstraction around determining if an
operand consumes its associated value needing to touch the ownership kind
map/etc.

I also refactored parts of the code base where it made sense to use this instead
of messing with the ownership kind map itself.
2020-02-13 17:58:03 -08:00
Saleem Abdulrasool
075a93a475 SIL: add an explicit move assignment operation instantiation 2020-01-01 13:16:45 -08:00
Saleem Abdulrasool
86ca0a1747 SIL: explicitly instantiate the Operand move ctor
GCC 7 does not like the missing move constructor and does not implicitly
synthesize one.  Explicitly indicate that this should be synthesized.
2020-01-01 13:15:55 -08:00
Brent Royal-Gordon
99faa033fc [NFC] Standardize dump() methods in frontend
By convention, most structs and classes in the Swift compiler include a `dump()` method which prints debugging information. This method is meant to be called only from the debugger, but this means they’re often unused and may be eliminated from optimized binaries. On the other hand, some parts of the compiler call `dump()` methods directly despite them being intended as a pure debugging aid. clang supports attributes which can be used to avoid these problems, but they’re used very inconsistently across the compiler.

This commit adds `SWIFT_DEBUG_DUMP` and `SWIFT_DEBUG_DUMPER(<name>(<params>))` macros to declare `dump()` methods with the appropriate set of attributes and adopts this macro throughout the frontend. It does not pervasively adopt this macro in SILGen, SILOptimizer, or IRGen; these components use `dump()` methods in a different way where they’re frequently called from debugging code. Nor does it adopt it in runtime components like swiftRuntime and swiftReflection, because I’m a bit worried about size.

Despite the large number of files and lines affected, this change is NFC.
2019-10-31 18:37:42 -07:00
Varun Gandhi
033be473a8 [NFC] Change ValueOwnershipKind::Any to ValueOwnershipKind::None in comments. (#27925)
Follow-up to PR #27879.
2019-10-29 16:50:45 -07:00
Michael Gottesman
26a734e58e [sil] Rename ValueOwnershipKind::{Any,None} 2019-10-25 10:28:25 -07:00
Jordan Rose
a1ea211f22 Add llvm::iterator_range to LLVM.h
If we're going to get rid of swift::IteratorRange, let's make
llvm::iterator_range easy to use.

No functionality change.
2019-10-08 15:24:06 -07:00
Michael Gottesman
d535e3e6cf [ownership] Allow for the ownership verifier to be run in non-asserts builds if -sil-verify-all is set.
This is matching the behavior of the rest of the verifier. NOTE: Both early exit
if said flag is not set, so this should not hit compile time in any way unless
the flag is set (in which case someone is asking for more verification...).

While I was here, I also noticed an ancillary bug where we were not checking if
a value was from in a block that was in a SILGlobalVariable or a SILFunction. We
already had a check that stopped this early when validating ownership of
SILInstructions. I guess we have never had a situation where the verifier was
given values to run on SILGlobalVariable blocks.
2019-10-02 12:36:17 -07:00
Michael Gottesman
7b2fc076f7 [sil] Add new API ValueBase:getUsersOfType<T>().
For some time now we have had the API ValueBase::getSingleUserOfType<T>() but we
never implemented getUsersOfType<T>() using transform/filter iterators.

Since there wasn't a specific API, several incarnations of this API have been
created for BeginBorrow, LoadBorrow, BeginAccess.

In this commit, I introduce the API and use it to excise the redundant code in
those above mentioned 3 instructions.
2019-09-06 16:40:51 -07:00
Michael Gottesman
af565e7cc0 [sil-parser] Fix harmless bug when parsing ossa.
Specifically, we were preferring the always correct ownership kind specified by
the FunctionType and ignoring what we parsed from the argument. This PR changes
ossa to give a nice error when this is detected and fixes the places where this
tests were written incorrectly.
2019-08-27 10:18:49 -07:00
Saleem Abdulrasool
731c31f9a5 MSVC: litter the code with llvm_unreachable (NFC)
Add `llvm_unreachable` to mark covered switches which MSVC does not
analyze correctly and believes that there exists a path through the
function without a return value.
2019-06-01 19:02:46 -07:00
Michael Gottesman
72a093da52 [semantic-arc-opts] Teach the guaranteed copy_value peephole how to handle instructions that can forward either owned or guaranteed ownership.
This fixes issues exposed by my turning off the Nominal Type RValue peephole. It
should give us some nice ARC wins as well potentially.
2019-03-21 13:50:41 -07:00
Slava Pestov
8915f96e3e SIL: Replace SILType::isTrivial(SILModule) with isTrivial(SILFunction) 2019-03-12 01:16:04 -04:00
Michael Gottesman
33e5aba554 Merge pull request #20855 from gottesmm/pr-94ee6e6c6e2d268f47f17dead77e4feb169c24e6
[ownership] Replace ValueOwnershipKind::Trivial with ValueOwnershipKi…
2018-12-05 14:47:04 -08:00
Michael Gottesman
0af0d5fddc [ownership] Replace ValueOwnershipKind::Trivial with ValueOwnershipKind::Any.
In a previous commit, I banned in the verifier any SILValue from producing
ValueOwnershipKind::Any in preparation for this.

This change arises out of discussions in between John, Andy, and I around
ValueOwnershipKind::Trivial. The specific realization was that this ownership
kind was an unnecessary conflation of the a type system idea (triviality) with
an ownership idea (@any, an ownership kind that is compatible with any other
ownership kind at value merge points and can only create). This caused the
ownership model to have to contort to handle the non-payloaded or trivial cases
of non-trivial enums. This is unnecessary if we just eliminate the any case and
in the verifier separately verify that trivial => @any (notice that we do not
verify that @any => trivial).

NOTE: This is technically an NFC intended change since I am just replacing
Trivial with Any. That is why if you look at the tests you will see that I
actually did not need to update anything except removing some @trivial ownership
since @any ownership is represented without writing @any in the parsed sil.

rdar://46294760
2018-12-04 23:01:43 -08:00
Adrian Prantl
ff63eaea6f Remove \brief commands from doxygen comments.
We've been running doxygen with the autobrief option for a couple of
years now. This makes the \brief markers into our comments
redundant. Since they are a visual distraction and we don't want to
encourage more \brief markers in new code either, this patch removes
them all.

Patch produced by

      for i in $(git grep -l '\\brief'); do perl -pi -e 's/\\brief //g' $i & done
2018-12-04 15:45:04 -08:00
Michael Gottesman
71c13b7594 [sil] Rename ValueOwnershipKindClassifier.cpp -> ValueOwnership.cpp and remove ValueOwnershipKindClassifier.h
This matches the name of OperandOwnership.cpp which performs an anologous
function. I also was able to eliminate an unneeded header.  The key thing here
is that the only reason that we had ValueOwnershipKindClassifier.h was because
we needed some defs from it in SILValue.cpp for SILValue::getOwnershipKind()
... which is great except for the fact that ValueOwnershipKindClassifier is
basically the implementation of SILValue::getOwnershipKind().

So what this patch does is moves the implementation of
SILValue::getOwnershipKind() from SILValue.cpp -> ValueOwnership.cpp and then
puts the visitor into an anonymous namespace in that file.

I also added a little comment in SILValue.h that says that
SILValue::getOwnershipKind() is implemented in ValueOwnership.cpp, not
SILValue.cpp.
2018-10-29 23:50:54 -07:00
Erik Eckstein
ac2b5720b0 SILOptimizer: support static large string literal generation for the new UTF8 String implementation
In the new string implementation there is a subtract of a (small) constant from the literal pointer. We convert

((ptr - offset) | bits

to

(ptr + (bits - offset))

which can still be represented as a relocation.
2018-10-25 10:18:23 -07:00
Michael Gottesman
157091d5c6 [ownership] Extract out from SILOwnershipVerifier the OperandOwnershipKindMapClassifier
NOTE: This is not the final form of how operand ownership restraints will be
represented. This patch is instead an incremental change that extracts out this
functionality from the ownership verifier as a pure refactor.

rdar://44667493
2018-10-01 22:14:41 -07:00
Jason Mittertreiner
8ac9a657a8 Fix 'operator ==' is ambiguous with MSVC (#19501)
When compiling with MSVC on Windows, this error among other similar
conflicts with AnyValue occur:

Defined the overloads so it selects the correct one.
2018-09-24 12:39:44 -07:00
Michael Gottesman
af7d301512 [sil] Make ValueOwnershipKind(unsigned) explicit to prevent implicit casts from ints/bools to ValueOwnershipKind.
I hit this problem while splitting classifying operand ownership from the
ownership verifier itself. There is no reason to allow for this implicit
conversion. Just makes updating code more error prone.

rdar://44667493
2018-09-21 09:58:02 -07:00
Sho Ikeda
03fbd4a6de [gardening][SIL] Replace typedef with using 2018-04-05 13:53:20 +09:00