Commit Graph

18 Commits

Author SHA1 Message Date
Nate Chandler
e125c5cf64 [NFC] SILOptimizer: Remove LexicalDestroyHoisting.
It has been superseded by OwnedValueCanonicalization's support for
lexical values.
2024-07-22 20:35:30 -07:00
Nate Chandler
5ab9a00e31 [CanonicalizeGuaranteedValue] Cleared everything. 2023-05-04 20:12:16 -07:00
Nate Chandler
3e08f5141b [CanonicalizeBorrowScope] Adopted BitfieldRef. 2023-05-02 11:51:53 -07:00
Andrew Trick
15796e3ff9 PrunedLiveness: add a SILFunction argument
So that liveness can migrate to using a SILBitfield.
2023-03-22 01:36:48 -07:00
Nate Chandler
4b85d0a9ca [DestroyHoisting] Barriers use callee analysis.
Pass a BasicCalleeAnalysis instance to isDeinitBarrier.  This enables
LexicalDestroyHoisting to hoist destroys over applies of functions which
are not deinit barriers.
2022-10-18 21:23:22 -07:00
Nate Chandler
f85074d1ba [ShrinkBorrowScope] Barriers use callee analysis.
Pass a BasicCalleeAnalysis instance to isDeinitBarrier.  This will allow
ShrinkBorrowScope to hoist end_borrows over applies of functions which
are not deinit barriers.
2022-10-18 21:23:22 -07:00
Andrew Trick
ca503b54b7 Redesign PrunedLiveness APIs, introducing live ranges
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.
2022-10-04 13:27:44 -07: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
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
1c106eb6e8 [ShrinkBorrowScope] Return modified copy_values.
So that CopyPropagation and other clients can react accordingly, pass
back a list of copy_value instructions that were rewritten by
ShrinkBorrowScope.  In CopyPropagation, add each modified copy to the
copy worklist.
2021-12-19 08:14:45 -08:00
Nate Chandler
cde250a3e3 [CopyPropagation] Add ShrinkBorrowScope.
During copy propagation (for which -enable-copy-propagation must still
be passed), also try to shrink borrow scopes by hoisting end_borrows
using the newly added ShrinkBorrowScope utility.

Allow end_borrow instructions to be hoisted over instructions that are
not deinit barriers for the value which is borrowed.  Deinit barriers
include uses of the value, loads of memory, loads of weak references
that may be zeroed during deinit, and "synchronization points".

rdar://79149830
2021-12-07 09:43:57 -08:00
Andrew Trick
c86d112891 Update #include for InstructionDeleter.h 2021-11-18 11:38:08 -08:00
Nate Chandler
42f318d9ef [Basic] Renamed GraphNodeWorklist.
Addressed the TODO saying that DAGNodeWorklist should be renamed
GraphNodeWorklist.
2021-10-18 08:55:13 -07:00
Andrew Trick
add3406cfe Move PrunedLiveness so it can be used as a lightweight OSSA helper.
For use in OwnershipUtils.
2021-10-06 09:23:02 -07:00
Meghana Gupta
883d145f06 Handle nil BorrowedValue during canonicalization 2021-08-13 13:06:51 -07:00
Andrew Trick
2c6d5afd28 Copy propagation redesign
This rewrites functionality that was mostly disabled but is now ready
to be enabled.

Allow lifetime canonicalization of owned values and function arguments
as a simple stand-alone utility. This is now being called from within
SILCombine, so we should only do the kind of canonicalization that
makes sense in that context.

Canonicalizing other borrow scopes should *not* be invoked as a
single-value cleanup because it affects other lifetimes outside the
borrow scope boundary. It is a somewhat complicated process that
hoists and sinks forwarding instructions and can generate surrounding
compensation code. The copy propagation pass knows how to post-process
the related lifetimes in just the right order. So borrow scope
rewriting should only be done in the copy propagation pass.

Similarly, only do simple canonicalization of owned values and
function arguments at -Onone.

The feature to canoncalize borrow scopes is now ready to be
enabled (-canonical-ossa-rewrite-borrows), but flipping the switch
should be a separate commit. So most of the functionality that was
affected is not exposed by this PR.

Changes:

Split canonicalization of owned lifetimes vs. borrowed lifetimes into
separate utilities. The owned lifetime utility is now back to being
the simple utility that I originally envisioned. So not much happened
to it other than removing complexity.

We now have a separate entry point for finding the starting point for
rewriting borrow scopes:
CanonicalizeBorrowScope::getCanonicalBorrowedDef.

We now have a utility that defines forwarding instructions that we can
treat consistently as part of a guaranteed lifetime,
CanonicalizeBorrowScope::isRewritableOSSAForward.

We now have a utility that defines the uses of a borrowed value that
are considered part of its lifetime,
CanonicalizeBorrowScope::visitBorrowScopeUses. This single utility is
used to implement three different parts of the alogrithm:

1. Find any uses of the borrowed value that need to be propagated
outside the borrow scope

2. RewriteInnerBorrowUses for SILFunction arguments and borrow scopes
with no outer uses.

3. RewriteOuterBorrowUses for borrow scopes with outer uses. Handling
these involves creating new copies outside the borrow scope and
hoisting forwarding instructions.

The end result is that a lot of borrow scopes can be eliminated and
owned values can be forwarded to destructures, reducing copies and
destroys.

If we stop generating borrow scopes for all interior pointers, then
we'll need to design a comparable optimization that works on
"implicit" borrow scopes:

  %ownedDef = ...
  %element struct_extract %ownedDef
  %copy = copy_value %element
  apply(@guaranteed %element)
  apply(@owned %copy)
  destroy %ownedDef

Should be:

  %ownedDef = ...
  %borrowedElement = destructure_struct @guaranteed %ownedDef
  apply(@guaranteed %borrowedElement)
  %ownedElement = destructure_struct %ownedDef
  apply(@owned %copy)
2021-07-01 21:17:27 -07:00