Commit Graph

65 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
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
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
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
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
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
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
Erik Eckstein
3c3425d098 SILOwnershipVerifier: fix a compiler error in the no-assert build. 2020-05-07 09:25:09 +02:00
Michael Gottesman
820d204285 [ownership] Change the ownership verifier textual error dumper to emit error counts on a per function instead of global basis.
This will just make them easier to update over time since adding a new function
doesn't require one to renumber the /entire/ file... *face-palm*.

Originally the reason why I added this is b/c I need to ensure that we handle
all errors exactly once so making sure we control the exact amount of emitted
errors is important. I can still do this with the new approach by just doing
per-function max error counts. Thus I also in this commit added FileCheck
patterns that implemented this scheme so now we have everything.
2020-05-06 09:39:19 -07:00
Michael Gottesman
82b08c5722 [ownership] Add new pass OwnershipVerifierTextualErrorDumper and use it in ownership verifier FileCheck tests instead of SILVerifier.
This will make it easier for me with a few further refactors to make the
ownership verifier testing mode emit per function error numbers instead of the
global error number that it is emitting now.

The reason why this is necessary is that today, the verification by
-sil-verify-all causes the errors to be emitted. That verification is done on a
per value level, rather than a per function level, so it is hard to get per
function error numbers without doing unprincipled things like propagating around
state saying what the current function being verified is.

This pass instead will let me make the error counter be per ErrorBuilder which
are created per function.

One thing to be aware of is that this /will/ cause SILValue::verifyOwnership to
not emit any output when the testing flag is enabled. This is to ensure I only
do not get duplicate textual error messages from the SILVerifier.
2020-05-04 13:58:56 -07:00
Michael Gottesman
973a82e85d [ownership] Cleanup how we emit filecheck-compatible verification errors for the ownership verifier.
This is doing a few things with a simple change to use a builder:

1. It cleans up how we emit errors so we have a builder object that constructs
errors. The errors then just become dumb POD data that the builder vends to
callers that via the boolean values describe what errors were found.

2. Now that we have one place where we are actually emitting these errors, I
cleaned up how we emit the errors by normalizing the output so function names
are quoted the same.

3. I changed our error emission so that we emit a unique count of the errors as
we emit them. This makes it so that our pattern matching is much more robust
against weird pattern match errors that can be difficult to debug due to the
errors having unrelated test cases/file check patterns bleed
together. Before/end checks eliminate this problem. I updated all of the
relevant test cases.

The reason /why/ I am doing this though is that I am going to be adding support
to the LinearLifetimeChecker for flagging objects that are outside of the
lifetime that we are verifying (meaning either before or after). This is going
to cause me to need to track /all/ non consuming uses when performing linear
lifetime checks and thus most likely emit more errors. I was finding it to be
difficult to update the current tests given the state of the world before this
patch, so I was inspired to clean this up to satisfy practical as well as debt
concerns.
2020-04-28 12:35:02 -07:00
Michael Gottesman
e1a19e4173 [sil] Split library into subfolders, while still building as a single library still.
Specifically, I split it into 3 initial categories: IR, Utils, Verifier. I just
did this quickly, we can always split it more later if we want.

I followed the model that we use in SILOptimizer: ./lib/SIL/CMakeLists.txt vends
 a macro (sil_register_sources) to the sub-folders that register the sources of
 the subdirectory with a global state variable that ./lib/SIL/CMakeLists.txt
 defines. Then after including those subdirs, the parent cmake declares the SIL
 library. So the output is the same, but we have the flexibility of having
 subdirectories to categorize source files.
2020-03-30 11:01:00 -07:00