Commit Graph

1315 Commits

Author SHA1 Message Date
Michael Gottesman
6a24087f90 Merge pull request #59611 from gottesmm/moveonly-rebase
[no-implicit-copy] Update SILGen/move checker to work with new patterns from copyable_to_moveonly and friends.
2022-06-28 13:45:15 -07:00
Erik Eckstein
f420468b27 SILOptimizer: add a pass to perform target specific constant folding.
TargetConstantFolding performs constant folding for target-specific values:

```
  MemoryLayout<S>.size
  MemoryLayout<S>.alignment
  MemoryLayout<S>.stride
```

Constant folding those expressions in the middle of the SIL pipeline enables other optimizations to e.g. allow such expressions in statically allocated global variables (done by the GlobalOpt pass).

The implementation requires to create a temporary IRGenModule, which is used to get actual constant sizes/alignments from IRGen's type lowering.

rdar://94831524
2022-06-23 22:16:42 +02:00
Michael Gottesman
2f9d67de18 [move-only] Add a new pass called MoveOnlyTypeEliminator that runs after move only checking.
This pass lowers moveonly-ness from the IR after we have finished move only
checking. The transform can be configured in two ways: such that it only handles
trivial types and such that it does trivial and non-trivial types. For ease of
use, I created two top level transforms (TrivialMoveOnlyTypeEliminator and
MoveOnlyTypeElimintor) that invoke the two behaviors by configuring the
underlying transform slightly differently.

For now, I am running first the trivial-only and then the all of the above
lowering. The trivial only pass will remain at this part of the pipeline
forever, but with time we are going to move the lower everything pass later into
the pipeline once I have audited the optimizer pipeline to just not perform any
work on move only types. That being said, currently we do not have this
guarantee and this patch at least improves the world and lets us codegen no
implicit copy code again.
2022-06-22 15:31:57 -07:00
Meghana Gupta
768a82f2cf Handle undefs in a few utilities used in RLE (#59448) 2022-06-15 14:37:46 -07:00
Erik Eckstein
ec3d9dd9c7 Optimizer: add the ObjCBridgingOptimization to optimize ObjectiveC bridging operations.
Removes redundant ObjectiveC <-> Swift bridging calls.
Basically, if a value is bridged from ObjectiveC to Swift an then back to ObjectiveC again, then just re-use the original ObjectiveC value.

Also in this commit: add an additional DCE pass before ownership elimination. It can cleanup dead code which is left behind by the ObjCBridgingOptimization.

rdar://89987440
2022-06-08 22:51:57 +02:00
Nate Chandler
8775148f7b [SILOpt] Used SetVector for fast contains check.
IterableBackwardReachability just requires an iterable list of gens.
ShrinkBorrowScope, LexicalDestroyHoisting, and SSADestroyHoisting all
need to be able to check whether a given instruction is scope ending
quickly.  Use a SmallSetVector rather than a SmallVector for the gens in
all three.
2022-05-24 14:15:27 -07:00
nate-chandler
2978bf0750 Merge pull request #58791 from nate-chandler/rdar92545900
[SSADestroyHoisting] Handle loops.
2022-05-24 03:17:34 -07:00
Nate Chandler
a6e8277dea [SILOpt] Added VisitBarrierAccessScopes utility.
The new utility finds access scopes which are barriers by finding access
scopes which themselves contain barriers.  This is necessary to (1)
allow hoisting through access scopes when possible (i.e. not simply
treating all end_access instructions as barriers) and (2) not hoist into
access scopes that contain barriers and in so doing introduce
exclusivity violations.
2022-05-21 12:56:51 -07:00
Nate Chandler
11144ec7e2 [Reachability] Added IterativeBackwardReachability.
The new optimistic, iterative backward reachability is optimized to do
as little work as possible.  Only blocks not all of whose successors are
kills participate in the worklist at all.  The blocks within that
discovered set are visited via a worklist which tracks blocks which have
been found to be unreachable at begin and whose
unreachable-at-begin-ness must be propagated into
unreachable-at-end-ness of its predecessors.

rdar://92545900
2022-05-21 12:56:50 -07:00
Nate Chandler
9cc4a97b6b [BackwardReachability] Enforce correct API usage. 2022-05-21 12:56:50 -07:00
Slava Pestov
ac74b845e5 Merge pull request #58513 from AnthonyLatsis/se-309-sil-opt
SE-0309: SILOptimizer fixes & reenable executable tests
2022-05-20 16:38:05 -07:00
Erik Eckstein
3b43da9637 Swift Optimizer: improve ergonomics of Builder and PassContext
* split the PassUtils.swift file into PassContext.swift and Passes.swift
* rework `Builder` bridging allowing more insertion point variations, e.g. inserting at the end of a block.
* add Builder.create functions for more instructions
* add `PassContext.splitBlock`
* move SIL modification functions from PassContext to extensions of the relevant types (e.g. instructions).
* rename `Location.bridgedLocation` -> `Location.bridged`
2022-05-12 21:48:37 +02:00
Michael Gottesman
640d5902e6 [debug-info] Implement a global dataflow that propagates debug info for async vars and clones the dbg info after funclet points.
The overall flow of the pass is:

1. We walk over the blocks summarizing the debug info instruction the blocks gen
as well as whether or not the block had an async funclet edge with in it.

2. We then perform a simple forward iterative optimistic dataflow using
intersection at merge points. At points where we find after merging that we have
a conflict and thus need to stop propagation, we insert a debug_value undef.

3. We then walk the CFG again visiting only blocks that we know had async
funclet edges. We then walk each said block from top to bottom starting with the
propagating gen information and updating as we go, dumping the current set of
debug_info we are tracking after each coroutine funclet boundary.

rdar://85020571
2022-05-05 14:16:51 -07:00
Joe Groff
d2fad71328 Merge pull request #42589 from jckarter/begin-partial-apply-simplification-pass
[SIL] Initial work on PartialApplySimplification pass
2022-05-02 10:20:39 -07:00
Erik Eckstein
cad646b283 re-implement the StackPromotion pass in swift
It uses the new EscapeInfo.
2022-05-02 14:22:27 +02:00
Anthony Latsis
b2a9092ea4 [NFC] SILOptimizer: OpenedArchetypeInfo should use OpenedArchetypeType 2022-04-29 02:42:19 +03:00
Erik Eckstein
5d3339e9a3 Swift SIL: support for sub-pass bisecting: add PassContext.continueWithNextSubpassRun 2022-04-25 11:57:02 +02:00
Erik Eckstein
eea471fe99 add the ComputeEffects pass
The ComputeEffects pass derives escape information for function arguments and adds those effects in the function.
This needs a lot of changes in check-lines in the tests, because the effects are printed in SIL
2022-04-22 09:50:07 +02:00
Erik Eckstein
87ae9e3a73 add passes to dump the results of EscapeInfo
And add test files which uses the passes for verification of EscapeInfo
2022-04-22 09:50:07 +02:00
Saleem Abdulrasool
218ef587e6 Revert "Merge pull request #42242 from eeckstein/escapeinfo"
This reverts commit c05e064cd8, reversing
changes made to c1534d5af9.

This caused a regression on Windows.
2022-04-21 20:33:37 -07:00
Joe Groff
85760d5348 SIL: Add a PartialApplySimplification pass.
This will turn `partial_apply` instructions into explicit box construction and
extraction code sequences. To begin with, recognize when a private function
is only used in partial applications and directly modify the function to be
usable as a closure invocation function. This simplifies the lowering in IRGen
and avoids generating a "partial application forwarder" thunk.
2022-04-21 12:47:44 -07:00
Erik Eckstein
700412b39e add the ComputeEffects pass
The ComputeEffects pass derives escape information for function arguments and adds those effects in the function.
This needs a lot of changes in check-lines in the tests, because the effects are printed in SIL
2022-04-21 08:45:08 +02:00
Erik Eckstein
4d5987c469 add passes to dump the results of EscapeInfo
And add test files which uses the passes for verification of EscapeInfo
2022-04-21 08:45:08 +02:00
Erik Eckstein
d8bf949582 BasicCalleeAnalysis: improve finding the actual called deinits of a destroy/release instruction
* C++: add a function `getDestructors(SILType type, bool isExactType)’: if the type is a final class or `isExactType` is true, then return the one and only destructor of that class.
* swift: add `getDestructor(ofExactType type: Type)` and `getIncompleteCallees`
* swift: remove `getDestructor` from the PassContext. The API of the `calleeAnalysis` can be used instead.
2022-04-05 20:33:23 +02:00
Erik Eckstein
eaeaa02415 PassManager: disable verification of analysis with -sil-verify-none 2022-03-31 10:12:32 +02:00
Erik Eckstein
4824d6d940 Swift SIL: improve BasicBlockRange and InstructionRange and add tests
* add `BasicBlockRange.inclusiveRange`
* add `insert(contentsOf:)`
* add the RangeDumper pass to dump ranges for testing
* and add a test file
2022-03-30 14:45:58 +02:00
Kavon Farvardin
af683dc271 basic implementation of performing an init of the id after an assign of the actorSystem.
The resignID call within the initializer moved into DI, because an assignment to
the actorSystem, and thus initialization of the id, is no longer guaranteed to happen.
Thus, while we previously could model the resignation as a clean-up emitted on all
unwind paths in an initializer, now it's conditional, based on whether the id was
initialized. This is exactly what DI is designed to do, so we inject the resignation
call just before we call the identity's deinit.
2022-03-24 16:20:01 -07:00
Kavon Farvardin
6c0cfac69a remove dependence on system parameter in SILGen/DefiniteInit 2022-03-24 16:18:49 -07:00
Andrew Trick
2fd4de411e [SIL-opaque] Removed [Unconditional]CheckedCastValue 2022-03-22 17:04:13 -07:00
Michael Gottesman
1e2b94ec04 Merge pull request #41944 from gottesmm/add_initial_dominance_impl
[move-function] Add initial support for moved lets over async funclet edges
2022-03-22 09:33:53 -07:00
Michael Gottesman
056132cca0 [move-function] Add a new pass that propagates debug_value [moved] into coroutine func-lets.
NOTE: debug_value [moved] appearing in the source code implies a _move was
used. So this will not effect current stable swift code.

This is just a first version of this that I am using to commit/bring up tests
for IRGen supporting a full dataflow version of this patch.

Big picture is that there is a bunch of work that is done in the LLVM level in
the coroutine splitter to work around communicating live variables in the
various coroutine func-lets. This logic is all done with debug.declare and we
would need to update that logic in the coroutine splitter to handle
debug.addr. Rather than do this, after some conversation, AdrianP and I realized
that we could get the same effect of a debug.declare by just redeclaring the
current live set of debug_value after each possible coroutine funclet start. To
do this in full generality, we need a full dataflow but just to bring this up we
initially perform a dominance propagation algorithm of the following sort:

1. We walk the CFG along successors. By doing this we guarantee that we visit
   blocks after their dominators.

2. When we visit a block, we walk the block from start->end. During this walk:

   a. We grab a new block state from the centralized block->blockState map. This
      state is a [SILDebugVariable : DebugValueInst].

   b. If we see a debug_value, we map blockState[debug_value.getDbgVar()] =
      debug_value. This ensures that when we get to the bottom of the block, we
      have pairs of SILDebugVariable + last debug_value on it.

   c. If we see any coroutine funclet boundaries, we clone the current tracked
      set of our block state and then walk up the dom tree dumping in each block
      any debug_value with a SILDebugVariable that we have not already
      dumped. This is maintained by using a visited set of SILDebugVariable for
      each funclet boundary.

The end result is that at the beginning of each funclet we will basically
declare the debug info for an addr.

This is insufficient of course for moves that are in conditional control flow,
e.x.:

```
let x = Klass()
if boolValue {
  await asyncCall()
  let _ = _move(x)
}
```

but this at least lets me begin to write tests for this in lldb using straight
line code and work out the rest of the issues in CodeGen using those tests.
2022-03-21 14:20:06 -07:00
Andrew Trick
ddf0965d3f Rewrite ClosureScopeAnalysis for generality.
Handle recursive non-escaping local functions.

Previously, it was thought that recursion would force a closure to be
escaping. This is not necessarilly true.

Update AccessEnforcementSelection to conservatively handle closure cycles.

Fixes rdar://88726092 (Compiler hangs when building)
2022-03-18 02:28:53 -07:00
Doug Gregor
9c134263de Collapse the differentiation-specific thunk type generation code into the general version
We had two copies of this code that had drifted apart. Bring them back
together so there is just one place where we compute the type of a
reabstraction thunk.
2022-03-11 16:33:13 -08:00
Michael Gottesman
4a5d7ae63a [move-function] Break blocks right after the non-undef debug info associated with move only values.
The reason why I am doing this is that right now SelectionDAG seems to sink
certain llvm.dbg.addr to the end of block. By breaking the block, we ensure that
we initialize the debug value of values early enough. NOTE: We are relying on
code at -Onone not eliminating control flow which it does not today.

A few additional notes:

1. I also fixed a small issue where I was not setting the proper debug scope for
reinit debug_values. This came up when I was writing test cases for this commit.
So I just fixed it at the same time.

2. Since I am splitting blocks and I don't want to invalidate dominators/etc at
this point in the pipeline, I took advantage of the APIs ability to update
dominators/loopinfo at the same time.

3. I also expanded the tests in tree further by adding debug info tests for the
reinit copyable/addressonly cases in the multi-block case.
2022-02-22 14:06:16 -08:00
nate-chandler
0011b075fa Merge pull request #41387 from nate-chandler/lexical_lifetimes/destroy_hoisting/add
Hoist destroys of owned lexical values.
2022-02-17 11:36:50 -08:00
Andrew Trick
1c8f142a73 OwnershipOptUtils - computeGuaranteedBoundary 2022-02-16 12:23:01 -08:00
Nate Chandler
dd168d837c [LexicalDestroyHoisting] Added.
The new utility, to be run as part of copy propagation, hoists
destroy_values of owned lexical values up to deinit barriers.  It is
heavily based on the rewritten ShrinkBorrowScope.
2022-02-16 10:31:24 -08:00
Nate Chandler
31e072a9bc [LexicalDestroyFolding] Returned move_value inst. 2022-02-15 13:06:45 -08:00
Nate Chandler
41fdbc1285 [ShrinkBorrowScope] Adopt BackwardReachability.
Replaced ShrinkBorrowScope's own data flow with the general
BackwardReachability.

Took this opportunity to refactor and document the utility.

Taken together these changes make ShrinkBorrowScope serve as a template
for a future LexicalDestroyHoisting which will operate on owned lexical
values (rather than guaranteed as here) and hoist destroy_values (rather
than end_borrows as here) but should otherwise be quite similar.
2022-02-14 18:38:31 -08:00
Nate Chandler
94ef0af9ea [SILOpt] Reachability handles phis.
Previously, Reachability assumed that phis were not barriers.  Here,
handling for barrier phis is added.  To that end, a new delegate
callback `checkReachableBarrier(PhiValue)` is added.  Before marking the
beginning of a block as reached (or any of its predecessors), check
whether each argument that is a phi is a barrier.  If any is, then
reachability is done.

Implemented the new method in SSADestroyHoisting by splitting apart the
classification of an instruction and the work to do in response to
visiting an instruction.  Then, when visiting a PhiValue, just check
whether any of the predecessors terminators are classified as barriers.
That way, seeing that they're classified that way doesn't result in
noting down that those terminators had been reached (which indeed they
will not have been if any of the terminators from which the values are
flowing into the phi are barriers).
2022-02-14 17:12:47 -08:00
nate-chandler
63161e6ee5 Merge pull request #41228 from nate-chandler/lexical_lifetimes/owned_function_args_are_lexical
[SIL] Make owned function arguments lexical.
2022-02-11 18:11:59 -08:00
Nate Chandler
f8bcfe2328 [RAUW] Allow RAUWing some lexical values.
RAUWing a lexical value with a non-lexical value is illegal because it
would result in the value's lifetime being shortened without regard to
deinit barriers.  RAUWing _with_ a lexical value is LEGAL so long as
doing so doesn't extend its lifetime.
2022-02-10 16:28:41 -08:00
Erik Eckstein
8fe36eedd8 SILPassManager: improve bisecting for debugging the optimizer
* Add the possibility to bisect the individual transforms of SILCombine and SimplifyCFG.
   To do so, the `-sil-opt-pass-count` option now accepts the format `<n>.<m>`, where `m` is the sub-pass number.
   The sub-pass number limits the number of individual transforms in SILCombine or SimplifyCFG.

* Add an option `-sil-print-last` to print the SIL of the currently optimized function before and after the last pass, which is specified with `-sil-opt-pass-count`.
2022-02-09 13:25:30 +01:00
Erik Eckstein
d418192ceb SIL optimizer: fix a compile time performance problem in UpdatingInstructionIteratorRegistry
C++ closures can implicitly malloc.
Avoid this by just capturing `this` and nothing else.

Reduces the time spent in the SIL pass pipeline by 25% when compiling the stdlib core.

rdar://88567996
2022-02-07 16:19:19 +01:00
nate-chandler
fe74a7dc79 Merge pull request #41113 from nate-chandler/lexical_lifetimes/destroy_folding/add
[CopyPropagation] Added lexical destroy folding.
2022-02-04 22:23:21 -08:00
Nate Chandler
313f0e22a6 [CopyPropagation] Added lexical destroy folding.
The new utility folds patterns like

  TOP:
    // %borrowee is some owned value
    %lifetime = begin_borrow %borrowee

  BOTTOM:
    // %copy is some transitive copy of %borrowee
    apply %f(%copy)
    end_borrow %lifetime
    destroy_value %borrowee

into

  TOP:
    %move = move_value [lexical] %borrowee
    %lifetime begin_borrow [lexical] %move
  BOTTOM:
    end_borrow %lifetime
    apply %f(%move)

It is intended to be run after ShrinkBorrowScope moves the end_borrow up
to just before a relevant apply and after CanonicalizeOSSALifetime moves
destroy_value instructions up to just after their last guaranteed use,
at which point these patterns will exist.
2022-02-04 14:41:33 -08:00
Nate Chandler
5c1a172b37 [CanonicalizeOSSALt] Extracted destroy pred.
Pulled out a simple check--that CanonicalizeOSSALifetime now uses to
determine whether to continue hoisting a destroy_value instruction--into
a predicate that can be used by LexicalDestroyFolding.
2022-02-04 09:10:30 -08:00
Kavon Farvardin
4f28b87de9 basic implementation of flow-isolation for SE-327
Flow-isolation is a diagnostic SIL pass that finds
unsafe accesses to properties in initializers and
deinitializers that cannot gain isolation to otherwise
protect those accesses from concurrent modifications.
See SE-327 for more details about how and why it exists.

This commit includes changes and features like:

- The removal of the escaping-use restriction
- Flow-isolation that works properly with `defer` statements
- Flow-isolation with an emphasis on helpful diagnostics.

It also includes known issues like:

- Local / nonescaping functions are not analyzed by
  flow-isolation, despite it being technically possible.
  The main challenge in supporting it efficiently is that
  such functions do not have a single exit-point, like
  a `defer`. In particular, arbitrary functions can throw
  so there are points where nonisolation should _not_ flow
  out of the function at a call-site in the initializer, etc.

- The implementation of the flow-isolation pass is not
  particularly memory efficient; it relies on BitDataflow
  even though the particular flow problem is simple.
  So, a more efficient implementation would be specialized for
  this particular problem, etc.

There are also some changes to the Swift language itself: defer
will respect its context when deciding its property access kind.

Previously, a defer in an initializer would always access a stored
property through its accessor methods, instead of doing so directly
like its enclosing function might. This inconsistency is unfortunate,
so for Swift 6+ we make this consistent. For Swift 5, only a defer
in a function that is a member of the following kinds of types
will gain this consistency:

- an actor type
- any nominal type that is actor-isolated, excluding UnsafeGlobalActor.

These types are still rather new, so there is much less of a chance of
breaking expected behaviors around defer. In particular, the danger is
that users are relying on the behavior of defer triggering a property
observer within an init or deinit, when it would not be triggering it
without the defer.
2022-02-02 13:31:14 -07:00
eeckstein
00b795fe11 Merge pull request #41120 from eeckstein/capture-propagate-keypaths
CapturePropagation: specialize closures which capture a constant keypath
2022-02-02 07:54:47 +01:00
Erik Eckstein
79e9b9a088 SIL optimizer: add the ability to disable swift instruction passes with the -sil-disable-pass option. 2022-02-01 18:30:05 +01:00