-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Swift Optimizer: add def-use/use-def walker utilities #59729
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
@swift-ci test |
@swift-ci benchmark |
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!
lgtm
d9b6fd4
to
928d565
Compare
@swift-ci test |
1 similar comment
@swift-ci test |
"Base" valueWe have a specific definition of a base address in SIL. Is there any need to overload the term to mean the initial value for a traversal? Can we just call it an "initial" value? leafUse
I don't follow this logic. (1) Disjoint paths The (2) Incomplete path Here "unmatchedPath" simply means "not fully matched". So it is indistinguishable from any call to index_addrWhy is index_addr treated as a cast? Until SmallProjectionPath supports indices, it needs to be a "leafOrUnmatched" case. Just like tail_addr. switch_enumIt doesn't look like you handle the switch_enum case yet. Bool returnWhen an API performs an action and returns a boolean. The return value should indicate whether the action was succesfull. That way code using the API can be read logically:
(Some parsing APIs reverse this polarity, which is an abhorrent carry-over from C integer error codes. I can't imagine we would carry that practice over to Swift API. Do you know of any Swift APIs where 'false' indicates that the action succeeded?) At any rate, SIL transformations all follow this convention for bailing out. We also have many visitor patterns in the SIL code base. Here, a
Some visitor clients may combine the "unrecognized graph" condition with a "failed check" condition to avoid maintaining extra state. This is fine as long as What is important here is that the sense of the returned boolean cannot change based on the how the client chooses to interpret the result of the traversal. So if the walker is used underneath an API that checks for a negative condition, it would logically invert the result:
Flipping the meaning of a boolean to suit whatever was "convenient" to the API implementer is actually an extraordinarily common source of bugs. reflexivityThis is a silly thing to point out. But would it makes sense to define AddressDefUseWalker.walkDownDefault and |
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.
Thanks, @atrick for reviewing. Here's my feedback on your comments.
SwiftCompilerSources/Sources/Optimizer/Utilities/WalkUtils.swift
Outdated
Show resolved
Hide resolved
SwiftCompilerSources/Sources/Optimizer/Utilities/WalkUtils.swift
Outdated
Show resolved
Hide resolved
SwiftCompilerSources/Sources/Optimizer/Utilities/WalkUtils.swift
Outdated
Show resolved
Hide resolved
SwiftCompilerSources/Sources/Optimizer/Utilities/WalkUtils.swift
Outdated
Show resolved
Hide resolved
return leafOrUnmatched(address: operand, path: path, state: state) | ||
} | ||
case is InitExistentialAddrInst, is OpenExistentialAddrInst, is BeginAccessInst, | ||
is IndexAddrInst: |
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.
Why is index_addr treated as a cast? Until SmallProjectionPath supports indices, it needs to be a "leafOrUnmatched" case. Just like tail_addr.
Well, conceptually SmallProjectionPath already "handles" index_addr
. It just unconditionally matches all indices.
tail_addr
is a leaf node because it is a transition from value to address, while index_addr
is completely within an address chain.
But it's probably a good idea to add a comment here to describe this and add a TODO to better support index_addr
in SmallProjectionPath.
case let arg as BlockArgument: | ||
let block = arg.block | ||
switch block.singlePredecessor!.terminator { | ||
case let se as SwitchEnumInst: |
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.
It doesn't look like you handle the switch_enum case yet.
That's a good point. We could move the handling of switch_enum
into the walkers. And of course also in the down-walk.
/// A `ValueDefUseWalker.walkDownDefault` called on a use of a "value" base which | ||
/// yields an "address" value (such as `ref_element_addr %value_base`) will call `leafUse` | ||
/// since the walk can't proceed. | ||
/// **All functions return a boolean flag which, if true, can stop the walk of the other uses |
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 return value should indicate whether the action was succesfull.
I agree.
It would be even better to return an enum instead of a Bool, e.g.
enum WalkResult {
case continueWalk
case abortWalk
}
Returning a Bool is fine for functions which imply the meaning by it's name, e.g. isEscaping
.
But for functions like walkDown
, it's better to return an enum, which makes the meaning of the returned value immediately clear.
Introduces a set of protocols useful to perform def-use and use-def traversals to find uses and definitions of values. This logic was originally baked into `EscapeInfo` directly. Here we extract it into general utilities, namely: - `ValueDefUseWalker`: visit uses of a value walking down value-value projections/constructions. - `AddressDefUseWalker`: visit uses of an address walking down addr-addr projections/constructions. - `ValueUseDefWalker`: visit definitions of a value walking up value-value projections/constructions. - `AddressUseDefWalker`: visit definitions of an address walking up addr-addr projections/constructions. These utilities can then be used in other passes or to create new utilities by composing them. For example to find a definition passing through both address projections and value extractions, it's enough to implement a visitor conforming to both `AddressUseDefWalker` and `ValueUseDefWalker`.
`EscapeInfo` now conforms to the generic protocols defined in `WalkUtils`. This simplifies the implementation a bit, since trivial instructions are handled by `WalkUtils` and `EscapeInfo` only has to handle a subset of instructions inherent to escape information. Passes using `EscapeInfo` are updated accordingly to become visitors that customize the `EscapeInfo` walk.
928d565
to
c3ccbde
Compare
@swift-ci test |
This PR adds def-use/use-def traversals in
WalkUtils.swift
and updatesEscapeInfo
and related passes to use those.WalkUtils
adds a set of protocols (ValueDefUseWalker
,AddressDefUseWalker
,ValueUseDefWalker
,AddressUseDefWalker
) that perform def-use and use-def traversals guided by a projection path.An implementor of these protocols can collect uses/definitions and track whether
certain instructions have been crossed during the traversal.
Additionally
EscapeInfo
and related passes are updated to use the traversal utilities.