Commit Graph

694 Commits

Author SHA1 Message Date
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
93d1524cc0 Merge pull request #34634 from gottesmm/pr-88f0c52a3c1db5fb272598e5c5596ce3594d804c
[ownership] Make checked_cast_br, destructure_struct, and destructure_tuple real forwarding instructions
2020-11-09 15:28:45 -08:00
Michael Gottesman
c2a6f9aa5e [ownership] Fix assert to test the right thing semantically in the linear lifetime checker.
I think this assert was just testing the wrong thing. Specifically, it is trying
to say that either the given value has a consuming use or it is post-dominated
by dead end blocks.

Instead of checking that directly by using DeadEndBlocks::isDeadEnd(), it was
using a different empty check that caused the assert to actually semantically
say that:

A value must have a lifetime ending use *or* the dead end blocks analysis must
have found at least one block at all in the function that is reachable from a
function terminating terminator (e.x.: return).

This is clearly not the former and was causing the linear lifetime error to hit
this assert in certain cases.

<rdar://problem/70690127>
2020-11-09 11:49:53 -08:00
Andrew Trick
c2b13cdd51 Merge pull request #34635 from atrick/verify-critedge
Verify non-critical edges in OSSA
2020-11-09 08:59:08 -08:00
Michael Gottesman
d1b555f59a [ownership] Make destructure_{struct,tuple} true forwarding instructions instead of inferring from results/arguments. 2020-11-08 23:55:10 -08:00
Michael Gottesman
d74dbebf3b [ownership] Make checked_cast_br a true Ownership Forwarding inst instead of always inferring from the SILPhiArguments.
This is an analogous change to the previous change I just made to SwitchEnumInst.
2020-11-08 23:55:10 -08:00
Andrew Trick
0287a3d820 Verify no SIL critical edges.
There are multiple reasons this is needed.

1. Most passes do not perform CFG transformations. However, we often
need to split critical edges and remember to invalidate all SIL
analyses at the end of virtually every pass. This is very innefficient
and highly bug prone.

2. Many SIL analysis algorithms needs to reason about CFG
edges. Avoiding critical edges leads to far simpler and more efficient
designs when edges can be identified by blocks.

3. Handling block arguments on conditional branches create complexity
at the lowest level of the SIL interface. This complexity is difficult
to abstract over and bleeds until any algorithm that needs to reason
about phi operands. It's far easier to work with phis if we can easily
recover the phi operand with only a reference to the predecessor
block.

4. Attempting to preserve critical edges in high and mid level IR
blocks optimizations that otherwise have no business optimizing
branches. Branch optimization should always be defered to machine
level IR where the most relevant heuristics are employed to remove
unconditional branches. If code didn't need to be placed on a critical
edges, then a branch optimization can easily remove that code from the
critical edge.
2020-11-08 21:34:24 -08:00
Michael Gottesman
264955ccb3 [ownership] Convert switch_enum to be an ownership forwarding inst and store the forwarding ownership kind within it.
Previously, we always inferred the ownership of the switch_enum from its phi
operands. This forced us to need to model a failure to find a good
OperandOwnershipKindMap in OperandOwnership.cpp. We want to eliminate such
conditions so that we can use failing to find a constraint to mean that a value
can accept any value rather than showing a failure.
2020-11-08 20:32:20 -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
b785a5f1d4 Merge pull request #34605 from gottesmm/pr-75f04ac2c27715c84382d9a9e4ca7c0337a3ce30
[ownership] Now that we allow reborrows eliminate isForwardingSubValue it is dead.
2020-11-06 15:18:10 -08:00
Michael Gottesman
e5c98ad2c7 [ownership] Now that we allow reborrows eliminate isForwardingSubValue it is dead. 2020-11-05 19:42:10 -08:00
Doug Gregor
9566d2e665 [Concurrency] Add a builtin to get the current task in an async function.
This introduces a new builtin, `getCurrentAsyncTask()`, that produces a
reference to the current task. This builtin can only be used within
`async` functions, and IR generation merely grabs the task argument
and packages it up.

The type of this function is `() -> Builtin.NativeObject`, because we
don't currently have a Swift-level representation of tasks, and can
probably handle everything through builtins or runtime calls.
2020-11-05 10:43:33 -08:00
Erik Eckstein
0accc022d5 [concurrency] SILVerifier: don't complain about async function pointers created in non-async functions
It's possible to materialize an async function pointer, e.g. with partial_apply, in a non-async function - as long as no async function is called.
2020-11-05 13:58:40 +01:00
Meghana Gupta
6c46841c26 Merge pull request #34438 from meg-gupta/reborrowverifier
[ownership] Add a new ReborrowVerifier
2020-11-02 19:55:10 -08:00
Meghana Gupta
288ef583e7 SILVerifier: async functions can be called from async functions only 2020-10-30 17:35:18 -07:00
Andrew Trick
fce43daab0 Merge pull request #34502 from atrick/simplifycfg-critedge
Rewrite SimplifyCFG trampoline removal to generalize it (avoid critical edges as a side-effect)
2020-10-30 12:06:25 -07: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
Andrew Trick
7d88d720b9 Add information to SILVerifier stack nesting diagnostic. 2020-10-29 15:25:20 -07:00
Andrew Trick
acc3398fed Add -allow-critical-edges flag.
Provide a mechanism to gradually migrate unit tests away from allowing
critical edges via -allow-critical-edges=false.

This will be the default in OSSA very soon, and will hopefully become
the default eventually for all SIL stages.

Note that not all required optimization pass changes have been
committed yet. I have pending changes in:
- SimplifyCFG
- SILCloner subclasses
- EagerSpecializer
- ArraySpecialization
- LoopUtils
- LoopRotate

There are multiple reasons we need to disallow critical edges:

1. Most passes do not perform CFG transformations. However, we often
need to split critical edges and remember to invalidate all SIL
analyses at the end of virtually every pass. This is very innefficient
and highly bug prone.

2. Many SIL analysis algorithms needs to reason about CFG
edges. Avoiding critical edges leads to far simpler and more efficient
designs when edges can be identified by blocks.

3. Handling block arguments on conditional branches create complexity
at the lowest level of the SIL interface. This complexity is difficult
to abstract over and bleeds until any algorithm that needs to reason
about phi operands. It's far easier to work with phis if we can easily
recover the phi operand with only a reference to the predecessor
block.

4. Attempting to preserve critical edges in high and mid level IR
blocks optimizations that otherwise have no business optimizing
branches. Branch optimization should always be defered to machine
level IR where the most relevant heuristics are employed to remove
unconditional branches. If code didn't need to be placed on a critical
edges, then a branch optimization can easily remove that code from the
critical edge.
2020-10-29 11:51:29 -07:00
Slava Pestov
360e406d3a SIL: Rename SILFunction::hasSelfMetadataParam()/getSelfMetadataArgument()
These are only for class types and are related to the usage of the
DynamicSelfType, so rename them to {has,get}DynamicSelfMetadata().
2020-10-23 21:35:11 -04:00
Andrew Trick
0f1beedfb7 Reenable load-borrow checker. 2020-10-21 15:02:08 -07:00
Andrew Trick
8e3fb44f2d Rewrite LoadBorrowImmutabilityChecker using AccessPath.
The verification will now be as complete as it can be within the
capability of our SIL utilities. It is much more aggressive with
respect to boxes, references, and pointers. It's more efficient in
that it only considers "overlapping" uses.

It is also now wholly consistent with the utilities that it uses, so
can be reenabled.

We could probably go even further and remove the switch statement
entirely, relying on AccessPath to recognize any operations that
propagate addresses, boxes, or pointers. But I didn't want to
potentially weaken enforcement without more careful consideration.
2020-10-21 15:02:08 -07:00
Andrew Trick
4f05d8a857 LoadBorrowImmutabilityChecker renaming.
Limit names to a straightforward and unambiguous statement of
purpose. They should not pose additional questions which can only be
answered by reading the code. Nuanced meaning belongs in descriptions
and code comments.

These are all examples that legitimately made reading the code very
difficult for me:

- LoadBorrowInvalidationChecker: what does "invalidation" mean in this
  context? How does that extend the meaning of "checker"? How can
  something ever pass a checker and not be invalid?

- constructValuesForKey outside of an ADT does not state purpose at all.

- wellBehavedWriteAccumulator: Raises questions about what writes are
  included and the broader semantics of the parent function. It turns
  out that well-behavedness is handled by the function's return value
  and has nothing to do with the accumulator.
2020-10-21 13:09:40 -07:00
Andrew Trick
b0bda13543 LoadBorrowInvalidation: fix mysteriously inverted boolean returns. 2020-10-21 13:09:40 -07:00
Andrew Trick
f31296d63b Fix isRCIdentityPreservingCast to handle trivial-to-reference casts
And add assertions.
2020-10-20 16:57:24 -07:00
Joe Groff
aef8f503d8 Merge pull request #34210 from jckarter/async-await-sil-verifier
SIL: Verify invariants of async_continuation instructions.
2020-10-19 15:06:55 -07:00
Andrew Trick
53eebddbb2 Temporarily disable the load-borrow checker.
A rewrite is ready and will be merged ASAP.
2020-10-16 15:00:10 -07:00
Andrew Trick
f6b32aedcd Add AccessedStorageWithBase to conviently recover the base's VarDecl 2020-10-16 15:00:10 -07:00
Andrew Trick
b272dc5e1a Cache 'isLet' within AccessedStorage.
Compute 'isLet' from the VarDecl that is available when constructing
AccessedStorage so we don't need to recover the VarDecl for the base
later.

This generally makes more sense and is more efficient, but it will be
necessary when we look past class casts when finding the reference root.
2020-10-16 15:00:10 -07:00
Andrew Trick
cc0aa2f8b8 Add an AccessPath abstraction and formalize memory access
Things that have come up recently but are somewhat blocked on this:

- Moving AccessMarkerElimination down in the pipeline
- SemanticARCOpts correctness and improvements
- AliasAnalysis improvements
- LICM performance regressions
- RLE/DSE improvements

Begin to formalize the model for valid memory access in SIL. Ignoring
ownership, every access is a def-use chain in three parts:

object root -> formal access base -> memory operation address

AccessPath abstracts over this path and standardizes the identity of a
memory access throughout the optimizer. This abstraction is the basis
for a new AccessPathVerification.

With that verification, we now have all the properties we need for the
type of analysis requires for exclusivity enforcement, but now
generalized for any memory analysis. This is suitable for an extremely
lightweight analysis with no side data structures. We currently have a
massive amount of ad-hoc memory analysis throughout SIL, which is
incredibly unmaintainable, bug-prone, and not performance-robust. We
can begin taking advantage of this verifably complete model to solve
that problem.

The properties this gives us are:

Access analysis must be complete over memory operations: every memory
operation needs a recognizable valid access. An access can be
unidentified only to the extent that it is rooted in some non-address
type and we can prove that it is at least *not* part of an access to a
nominal class or global property. Pointer provenance is also required
for future IRGen-level bitfield optimizations.

Access analysis must be complete over address users: for an identified
object root all memory accesses including subobjects must be
discoverable.

Access analysis must be symmetric: use-def and def-use analysis must
be consistent.

AccessPath is merely a wrapper around the existing accessed-storage
utilities and IndexTrieNode. Existing passes already very succesfully
use this approach, but in an ad-hoc way. With a general utility we
can:

- update passes to use this approach to identify memory access,
  reducing the space and time complexity of those algorithms.

- implement an inexpensive on-the-fly, debug mode address lifetime analysis

- implement a lightweight debug mode alias analysis

- ultimately improve the power, efficiency, and maintainability of
  full alias analysis

- make our type-based alias analysis sensistive to the access path
2020-10-16 15:00:10 -07:00
Slava Pestov
7bc5c5ecb1 SIL: Fix ownership verifier to handle some missing interior pointer projections
My upcoming SILGen change introduces more stores directly into
the result of a ref_element_addr or struct_element_addr in some
cases. Make sure we handle the failing combinations flagged by
the ownership verifier.
2020-10-10 20:04:50 -04:00
Joe Groff
3364c51b1d SIL: Verify invariants of async_continuation instructions.
- Enforce types of continuations and resume/error BBargs for await
- Can't access the continuation again or exit the function mid-suspend
2020-10-09 14:57:38 -07:00
Michael Gottesman
0b3d0aba67 Merge pull request #34090 from gottesmm/pr-eed6b1ec619c4e45094d3a737baacc1c4b6d8303
[ownership] Teach the ownership verifier how to verify that guaranteed yielded values are only used within the coroutine's lifetime.
2020-09-26 09:16:00 -05:00
Michael Gottesman
a1f4a43483 [ownership] Teach the ownership verifier how to verify that guaranteed yielded values are only used within the coroutine's lifetime.
I think validating this was an oversight from the bringup of coroutines. I
discovered this while writing test cases for coroutine lifetime extension. I
realized it was possible to write a test case that should have triggered this
but was not.

I added some tests to make sure that we continue to flag this in the future.

rdar://69597888
2020-09-25 17:38:53 -05:00
Andrew Trick
5ae231eaab Rename getFieldNo() to getFieldIndex().
Do I really need to justify this?
2020-09-24 22:44:13 -07:00
Erik Eckstein
56c857afa9 SIL: Check for leaked instructions in the SILVerifier and in the SILModule destructor. 2020-09-11 11:09:30 +02:00
Erik Eckstein
61f2e7b793 SILVerifier: remove the unused -verify-skip-unreachable-must-be-last option
It had no effect, because such SIL is never generated anyway.
2020-09-11 11:09:29 +02:00
Michael Gottesman
d82470a07d [ownership] Merge regularUsers and implicitRegularUsers into just "regularUsers".
When bringing up ownership I thought that it might be useful to distinguish
"normal users" that just require liveness and are real transitive users vs
implicit users that require liveness (I provide a constrasting example
below). Turns out this distinction did not provide any benefit, so I am ripping
it out so I can refactor this code to be used in other parts of the compiler
where we only want a single array of "normal users".

This is just a pure refactor. NFCI.

--------------------------------------------------------------------------------

An example of the former would be an apply that uses an owned value as a
guaranteed parameter:

```
bb0(%0 : @owned $Klass):
  apply %func(%0) : $@convention(thin) (@guaranteed $Klass) -> ()
```

while an example of the latter is an end_apply of a coroutine that takes an
owned value as a guaranteed parameter:

```
bb0(%0 : @owned $Klass):
  (%result, %token) = begin_apply %func(%0)
  ...
  end_apply %token
  destroy_value %0
```

In the latter, we can not move the destroy_value past the end_apply.
2020-08-31 14:33:06 -07:00
Michael Gottesman
8b5fb43370 Merge pull request #33714 from gottesmm/pr-328e13b915804e9b08d18a354ef036522340f489
[ownership] Extract out the computation of implicit uses for BorrowingOperands and InteriorPointerOperands into utilities on those classes.
2020-08-31 14:08:20 -07:00
Michael Gottesman
d29bca5a53 [ownership] Extract out the computation of implicit uses for BorrowingOperands and InteriorPointerOperands into utilities on those classes.
I am currently working on updating SimplifyCFG for ownership. One thing that I
am finding that I need is the ability to compute the lifetime of a guaranteed
argument from a checked_cast_br/switch_enum in order to convert said
instructions to a br. The issue comes from br acting as a consuming (lifetime
ending) use of a borrowed value, unlike checked_cast_br/switch_enum (which are
treated like forwarding instructions). This means that during the conversion we
need to insert a begin_borrow on the value before the new br instruction and
then create an end_borrow at the end of the successor block's argument's
lifetime.

By refactoring out this code from the ownership verifier, I can guarantee that
said lifetime computation will always match what the ownership verifier does
internally preventing them from getting out of sync.
2020-08-31 11:54:58 -07:00
Michael Gottesman
9057123739 Merge pull request #33618 from gottesmm/pr-bb7b96b4e43e9b8289ab38ff2613f251e373f0f3
[ownership] When computing usesNotContainedWithinLifetime make sure the error is only a use not in lifetime error.
2020-08-31 11:17:45 -07:00
Nate Chandler
94b5f76654 Revert "[SIL] Add SILFunctionType flag for async."
This reverts commit 9b8828848d.
2020-08-25 13:37:26 -07:00
Michael Gottesman
d9fdce51fc [ownership] When computing usesNotContainedWithinLifetime make sure the error is only a use not in lifetime error.
Otherwise, we can return true in cases where we do not have a proper linear
lifetime which can occur in the presence of destructures.

<rdar://problem/67698939>
2020-08-24 14:21:23 -07:00
Nate Chandler
9b8828848d [SIL] Add SILFunctionType flag for async. 2020-08-19 11:29:58 -07:00
Dan Zheng
bf2ef3934d [AutoDiff] NFC: make LinearFunctionExtractInst inherit UnaryInstructionBase. (#33418)
Remove ad-hoc operand list and operand getters.
2020-08-11 22:20:58 -07:00
Varun Gandhi
29188e3fe7 [AST] Update equality for ExtInfo to take Clang types into account.
In the future, we will remove the UseClangFunctionTypes language option, but we
temporarily need the scaffolding for equality checks to be consistent in all
places.
2020-07-31 13:55:55 -07:00
Varun Gandhi
f219e58ada [NFC] Refactor ExtInfo to use a builder-pattern based API.
Since the two ExtInfos share a common ClangTypeInfo, and C++ doesn't let us
forward declare nested classes, we need to hoist out AnyFunctionType::ExtInfo
and SILFunctionType::ExtInfo to the top-level.

We also add some convenience APIs on (AST|SIL)ExtInfo for frequently used
withXYZ methods. Note that all non-default construction still goes through the
builder's build() method.

We do not add any checks for invariants here; those will be added later.
2020-07-31 13:55:55 -07:00
Joe Groff
90f0f7c627 Merge pull request #32359 from jckarter/enable-prune-vtables
Add PruneVTables to the performance optimizer passes.
2020-07-27 11:10:53 -07:00