-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[clang][dataflow] Model conditional operator correctly. #89213
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
martinboehme
merged 4 commits into
llvm:main
from
martinboehme:piper_export_cl_625978585
Apr 22, 2024
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
e6f729d
[clang][dataflow] Model conditional operator correctly.
martinboehme a7544b6
fixup! [clang][dataflow] Model conditional operator correctly.
martinboehme 86a18d3
fixup! fixup! [clang][dataflow] Model conditional operator correctly.
martinboehme 1a6a463
fixup! fixup! fixup! [clang][dataflow] Model conditional operator cor…
martinboehme File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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 might be worth commenting why we need a join here. IIUC, we lack any concept of a "result expression" of a basic block. So, when the environments were joined in the normal basic-block processing algorithm, these two expressions would have been simply dropped (existing at respectively different locations in LocToVal). Hence, we need to explicitly extract them and join at this point.
Uh oh!
There was an error while loading. Please reload this page.
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.
Just to make sure I understand: The idea of such a concept would be that each of the branches of the conditional operator sets its result expression, and then when we perform the join for those two branches, we join the values of the result expressions?
This would work for the case of the conditional operator -- but it doesn't work for
&&
and||
, where we also have two basic blocks with "result expressions", but at the place where the branches join, we don't want to join the result expressions but rather combine them using logical "and" or "or".So I'm not sure a concept like this would add much of value.
(I think you mean
ExprToVal
?)Yes, in the joined environment these values don't exist -- so we have to extract them from the environments for the two branches (which is exactly what we do for
&&
and||
too). We then combine the values using a join because that's the operation that happens to be appropriate for the conditional operator (whereas for the logical operators we combine them using a logical operation).I've added a short comment that hopefully makes this a bit clearer -- WDYT?
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.
Hmm, I also think join feels a bit out of place here. I wonder if this would belong to
computeBlockInputState
.Uh oh!
There was an error while loading. Please reload this page.
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 understand your reaction; generally, we want to perform joins in
computeBlockInputState()
. But the conditional operator is a special case.Consider: In
computeBlockInputState()
(which calls through toEnvironment::join()
), we join values that are associated with the same expression or the same storage location, and then we associate the joined value with that same expression or storage location in the joined environment.For the conditional operator, we want to join values that are associated with different expressions (the two branches of the conditional operator), and then we associate the joined value with a third expression (the conditional operator itself). This join is what it means to perform transfer on the conditional operator.
Here's a simple example (godbolt) that hopefully clarifies this:
Here's the CFG:
The expressions whose values we are joining are
i
([B2.1]) andj
([B3.1]). The joined value is associated with the conditional operator ([B1.1]).What would it look like if we wanted to do this join within
computeBlockInputState()
?ConditionalOperator
incomputeBlockInputState()
. This would be incongruous, ascomputeBlockInputState()
is otherwise completely general -- it doesn't contain any code that's specific to a particular statement kind.computeBlockInputState()
, what would there be left forTransferVisitor::VisitConditionalOperator()
to do?)I hope this makes sense. If not, maybe it would be easiest to do a quick VC to discuss?
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 for the explanation, now this makes perfect sense. I think this is a sign that our CFGs are not the best abstraction for dataflow analysis in their current form, and we might be able to come up with a better representation for ternaries that would not have this problem (but that representation would probably be a departure from the AST).
That being said, I think this is not too bad to explain. I am happy with the PR now. I wonder if it is worth to extend the comment why the join here is inherently part of the transfer in case it is possible to do it in a couple of concise sentences. If that is not the case, I am ok with merging as is.
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've added my attempt at this, though it ended up being more than two sentences. I'll merge this as-is, as it's just a comment change, but If you think this explanation is too much, happy to remove it in a followup PR.