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.
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.
This invalidation kind is used when a compute-effects pass changes function effects.
Also, let optimization passes which don't change effects only invalidate the `FunctionBody` and not `Everything`.
Pass a BasicCalleeAnalysis instance to isDeinitBarrier. This enables
LexicalDestroyHoisting to hoist destroys over applies of functions which
are not deinit barriers.
Pass a BasicCalleeAnalysis instance to isDeinitBarrier. This will allow
ShrinkBorrowScope to hoist end_borrows over applies of functions which
are not deinit barriers.
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.
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.
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
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.
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.
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.
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.
Computes the side effects for a function, which consists of argument- and global effects.
This is similar to the ComputeEscapeEffects pass, just for side-effects.
Dead-end blocks are blocks from which there is no path to the function exit (`return`, `throw` or unwind).
These are blocks which end with an unreachable instruction and blocks from which all paths end in "unreachable" blocks.
Supports unit testing for OSSA lifetime utilities. These utilities are
the basis of maintaining valid OSSA form. They need to handle invalid
SIL (with incomplete OSSA lifetimes) because we rely on them to fixup
SIL after SILGen and after any transformation that may affect
ownership.
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.
NOTE: If one does not define a deinit on a move only type, if a destroy_value
lasts until IRGen time we will assert since I haven't implemented support in
IRGen for the destroy value witness for move only types. That being said, just
creating a deinit by adding to such a type:
```
deinit {}
```
is pretty low overhead for the experiments we want to use this for.
Some notes:
1. I added support for both loadable/address only types.
2. These tests are based off of porting the move only object tests for inout,
vars, mutating self, etc.
3. I did not include already written tests for address only types in this
specific merge since I need to change us to borrow move only var like types.
Without that, we get a lot of spurious error msgs and the burden of writing that
is not worth it. So instead in a forthcoming commit where I fix that issue in
SILGen, I will commit the corresponding address only tests for this work.
4. I did not include support for trivial types in this. I am going to do
object/address for that at the same time.
In theory, the analysis invalidation notifications should assure that every function has a CallerAnalysis::FunctionInfo in `funcInfos`.
But it's not unlikely that we are missing some of those notifications.
We got some not-reproducible crash reports because of missing function infos in CallerAnalysis.
With this change the analysis accepts missing function infos and does the right thing if such an info is missing.
In the long term we should replace CallerAnalysis by FunctionUses, anyway.
rdar://99653954
It decides which functions need stack protection.
It sets the `needStackProtection` flags on all function which contain stack-allocated values for which an buffer overflow could occur.
Within safe swift code there shouldn't be any buffer overflows.
But if the address of a stack variable is converted to an unsafe pointer, it's not in the control of the compiler anymore.
This means, if there is any `address_to_pointer` instruction for an `alloc_stack`, such a function is marked for stack protection.
Another case is `index_addr` for non-tail allocated memory.
This pattern appears if pointer arithmetic is done with unsafe pointers in swift code.
If the origin of an unsafe pointer can only be tracked to a function argument, the pass tries to find the root stack allocation for such an argument by doing an inter-procedural analysis.
If this is not possible, the fallback is to move the argument into a temporary `alloc_stack` and do the unsafe pointer operations on the temporary.
rdar://93677524
By using the keyword instead of the function, we actually get a much simpler
implementation since we avoid all of the machinery of SILGenApply. Given that we
are going down that path, I am removing the old builtin implementation since it
is dead code.
The reason why I am removing this now is that in a subsequent commit, I want to
move all of the ownership checking passes to run /before/ mandatory inlining. I
originally placed the passes after mandatory inlining since the function version
of the move keyword was transparent and needing to be inlined before we could
process it. Since we use the keyword now, that is no longer an issue.