Skip to content

Copy propagation redesign and the CanonicalizeBorrowScopes utility #38220

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Jul 12, 2021

Conversation

atrick
Copy link
Contributor

@atrick atrick commented Jul 2, 2021

Think of this as a complete rewrite of functionality that was mostly disabled anyway but is now ready to be enabled.

One incidental functionality change is that more dead code will now be eliminated during the copy propagation pass.

The one big commit is "Copy propagation redesign".

One medium size commit enabled by the big commit is "Simplify lifetime canonicalization in SILCombine".

Both those commits fix the -canonical-ossa-rewrite-borrows mode, which is now ready to be enabled by default.

The big commit is too hard to split into a separate PR, and the small commits are too trivial to be worth a separate PR.

In the big commit, the large amount of code that was deleted from CanonicalOSSALifetime.cpp can just be considered the old implemenation so can be ignored. The implementation in CanonicalizeBorrowScopes.cpp is new. Although it looks like a big diff, it is now much easier to review the source itself. The design changes are described in the commit message.

atrick added 12 commits July 1, 2021 20:04
It's fine to allow some optimization of access markers without
invalidating this simple analysis.
so they don't need to be passed around on the side everywhere.
Explaining a footgun that I've forgotten to check for more than once.
before accessing the instruction's operands, which will crash.
We're getting lucky that this utility isn't breaking people's code.
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)
And fix the way it handles of borrow scopes so we can enable borrow
scope rewiting. Make sure SILCombine only does canonicalization that
operates on a self-contained single-value-lifetime. It's important to
limit SILCombine to transformations where each individual step
converges quickly to a more canonical form. Rewriting borrow scopes
requires the copy propagation pass to coordinate all the individual
transformations.

Make canonicalizeLifetimes a SILCombine utility. This moves complexity
out of the main loop. SILCombine knows which values it wants to
canonicalize and can directly call either canonicalizeValueLifetime or
canonicalizeFunctionArgument for each one.

Respect the -enable/disable-copy-propagation options.
Currently disabled, but now ready to be enabled.
More dead code happens to be eliminated now because of consistent use
of the InstructionDeleter.
@atrick atrick requested review from gottesmm and meg-gupta July 2, 2021 05:00
@atrick
Copy link
Contributor Author

atrick commented Jul 2, 2021

@swift-ci test

@atrick atrick requested a review from nate-chandler July 2, 2021 05:02
@atrick
Copy link
Contributor Author

atrick commented Jul 11, 2021

@swift-ci test

@atrick
Copy link
Contributor Author

atrick commented Jul 12, 2021

@swift-ci test windows

@atrick atrick merged commit cd55abb into swiftlang:main Jul 12, 2021
@atrick atrick deleted the rewrite-borrow-forward branch July 13, 2021 17:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant