-
Notifications
You must be signed in to change notification settings - Fork 10.5k
SwiftCompilerSources support for OSSA and lifetime dependence #70460
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
Conversation
SwiftCompilerSources/Sources/Optimizer/Utilities/BorrowUtils.swift
Outdated
Show resolved
Hide resolved
SwiftCompilerSources/Sources/Optimizer/Utilities/BorrowUtils.swift
Outdated
Show resolved
Hide resolved
SwiftCompilerSources/Sources/Optimizer/Utilities/BorrowUtils.swift
Outdated
Show resolved
Hide resolved
SwiftCompilerSources/Sources/Optimizer/Utilities/OwnershipLiveness.swift
Outdated
Show resolved
Hide resolved
SwiftCompilerSources/Sources/Optimizer/Utilities/LifetimeDependenceUtils.swift
Outdated
Show resolved
Hide resolved
SwiftCompilerSources/Sources/Optimizer/Utilities/LifetimeDependenceUtils.swift
Outdated
Show resolved
Hide resolved
SwiftCompilerSources/Sources/Optimizer/Utilities/LifetimeDependenceUtils.swift
Show resolved
Hide resolved
return .abortWalk | ||
} | ||
default: | ||
fatalError("unknown borrow scope end") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Worth encoding these two possibilities as an enum which scopeEndingOperands
is a sequence of?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I encoded EndBorrowOperand as an enum. But there are always unreachable cases here because borrow scopes can now counterintuitively be owned values in the case of partial_apply.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice! I didn't look into all details, yet, but basically it looks good to me.
SwiftCompilerSources/Sources/Optimizer/Utilities/BorrowUtils.swift
Outdated
Show resolved
Hide resolved
/// terminated by end_borrow instructions that directly use this | ||
/// value. Function arguments do not introduce a local scope because | ||
/// the caller owns the scope. | ||
struct BeginBorrowValue { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here: should this be an enum?
Bonus: the phi argument case could be a struct Phi
instead of an Argument
SwiftCompilerSources/Sources/Optimizer/Utilities/BorrowUtils.swift
Outdated
Show resolved
Hide resolved
SwiftCompilerSources/Sources/Optimizer/Utilities/BorrowUtils.swift
Outdated
Show resolved
Hide resolved
SwiftCompilerSources/Sources/Optimizer/DataStructures/InstructionRange.swift
Outdated
Show resolved
Hide resolved
SwiftCompilerSources/Sources/Optimizer/Utilities/OwnershipLiveness.swift
Outdated
Show resolved
Hide resolved
SwiftCompilerSources/Sources/Optimizer/Utilities/OwnershipLiveness.swift
Outdated
Show resolved
Hide resolved
SwiftCompilerSources/Sources/Optimizer/Utilities/OwnershipLiveness.swift
Show resolved
Hide resolved
@meg-gupta I'll move InteriorLiveness into its own PR now and work on test cases, so if you have already made fixes then I can cherry pick them into that PR. |
And rename `uses.lifetimeEndingUses` to `uses.endingLifetime`
Also fix the memory binding within stack access.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The first batch of comments: BorrowUtils.
Basically it looks good. Most comments are about documentation, API ergonomics and suggestions for coding style.
Something to consider for future work: My gut feeling tells me that it would be better to represent the borrow-introducer relationship of re-borrows with an explicit instruction in SIL. For example:
bb3(%outer_adjacent_phi : @owned, %inner_adjacent_phi : @guaranteed):
%v = borrowed %inner_adjacent_phi from %outer_adjacent_phi, %some_dominating_value
use %v // %v replaces %inner_adjacent_phi in the following SIL
This ensures the dominance relationship of borrow-introducers and makes it easier for passes to obtain this information. The gather-utilities would then be something like SSAUpdater, which can be run by a pass if it changes the SIL.
The borrowed-from
instruction is the "moral" OSSA equivalent of a phi-term in plain SSA. Like a phi-term it makes dominance relation a structural property and avoids that passes need to recursively walk the predecessor blocks to gather defs/introducers.
SwiftCompilerSources/Sources/Optimizer/Utilities/BorrowUtils.swift
Outdated
Show resolved
Hide resolved
SwiftCompilerSources/Sources/Optimizer/Utilities/BorrowUtils.swift
Outdated
Show resolved
Hide resolved
SwiftCompilerSources/Sources/Optimizer/Utilities/BorrowUtils.swift
Outdated
Show resolved
Hide resolved
SwiftCompilerSources/Sources/Optimizer/Utilities/BorrowUtils.swift
Outdated
Show resolved
Hide resolved
SwiftCompilerSources/Sources/Optimizer/Utilities/BorrowUtils.swift
Outdated
Show resolved
Hide resolved
SwiftCompilerSources/Sources/Optimizer/Utilities/BorrowUtils.swift
Outdated
Show resolved
Hide resolved
SwiftCompilerSources/Sources/Optimizer/Utilities/BorrowUtils.swift
Outdated
Show resolved
Hide resolved
SwiftCompilerSources/Sources/Optimizer/Utilities/BorrowUtils.swift
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some comments on utilities
/// Mark a stack location for future iteration. | ||
/// | ||
/// TODO: Marker should be ~Escapable. | ||
struct Marker { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is effectively an index. So let's call it Index
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok. but I was avoiding introducing the concept of an Index which would be totally unsafe. The point was that the marker has a scope.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The point was that the marker has a scope.
That makes sense. I still would rename it to Index
. But make endIndex
a private property (and add a comment why it's unsafe when used directly).
I kept this draft open for review comments. It is in sync with the current PR: |
Format comments so they are readable on github and 80-col tools.
Key APIs necessary for using OSSA. - BorrowingInstruction - BeginBorrowValue - scopeEndingOperands - BorrowIntroducers - EnclosingValues - innerAdjacentPhis These need to be complete to be correct.
This is what you need to correctly analyze OSSA. - computeLinearLiveness - computeInteriorLiveness - InteriorUseVisitor - OwnershipUseVisitor - LivenessBoundary Along with BorrowUtils.swift, all of our OSSA transformations are built on top of these fundamentals. With these APIs, we can build anything OSSA-related in SwiftCompilerSources. These utilities are immediately needed for borrowed arguments and lifetime dependence. In the near future, we can also use them to complete OSSA lifetimes and *correctly* fixup OSSA after transformation without introducing lots of copies and creating lots of incorrect corner cases.
We've had ongoing discussions about doing this ever since OSSA was introduced. It would obviously simplify OSSA liveness and dead code elimination (although we've finally solved those problems). There are serious tradeoffs though. One is making all passes aware of the borrowed phi dependence. Another problem is figuring out how to guarantee that the dependence always stays valid. Keeping the borrowed phi dependence valid and verifying it requires that same logic we have here, so getting the utilities in this PR right is a good start. I'm generally in favor of augmenting the SSAUpdater to do more things as an OSSAUpdater. Most importantly, we need to flag phis with lexical lifetimes and pointer escapes because without that, our OSSA utilities all have serious time-complexity problems. If we can also teach OSSAUpdater to update borrowed phi dependencies, that would be reasonable. Then the only question is whether other optimizations might invalidate the borrowed phis in a way the the OSSAUpdater does not catch. |
- LifetimeDependence - VariableIntroducerUseDefWalker - LifetimeDependenceUseDefWalker - LifetimeDependenceDefUseWalker
That should be encapsulated in the
That's what I mean with providing a utility for it (similar to SSAUpdated) which passes can use when they modify the SIL.
Right 👍 |
Once #70887 is merged, the LifetimeDependence utils will be introduced in a separate PR. |
Fundamental APIs for working with OSSA in swift.
These are both simpler and more complete than the C++ counterpart. I'm adding support for the new on-stack closure representation and handling mark_dependence.