-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
C++: Generate int-to-bool conversions in C code #18490
C++: Generate int-to-bool conversions in C code #18490
Conversation
446f6cb
to
d182a41
Compare
d182a41
to
d204810
Compare
…plicit comparisons against 0 in C code.
d204810
to
5700f46
Compare
5700f46
to
5373e22
Compare
It looks like the changes in 6577161 only affect syntax-zoo, and not the IR tests. I think it would make sense to add an IR test, so we can easily see that the generated IR is actually correct. |
override predicate comparesLt(Expr left, Expr right, int k, boolean isLessThan, boolean testIsTrue) { | ||
exists(Instruction li, Instruction ri | | ||
li.getUnconvertedResultExpression() = left and | ||
ri.getUnconvertedResultExpression() = right and | ||
ir.comparesLt(li.getAUse(), ri.getAUse(), k, isLessThan, testIsTrue.booleanNot()) | ||
) | ||
} |
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 need some more explanation here. Does this predicate (and the ones below) every produce anything sensible given that ir
is a CompareEQ
?
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.
Yeah, I doubt this ever produces anything, really. This was just a result of me copy/pasting the predicate 🙈 I tried to quick-eval this predicate on a couple of local DBs, but nothing came up.
Would you prefer just doing none
here instead?
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.
Does that hold for all the predicates below, or are there exceptions?
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 was about to write this:
All the "less than"-related predicates are probably not relevant, no. But the "equality"-related predicates certainly are. So we could replace all the them all with
none
.
But I then realized that if you write:
if(!(a < b)) { }
in a C file then we'll hit this case since the result of a < b
has an int
type. I've added this as a testcase. A quick MRVA run shows me that we actually hit many GuardCondition
s that fit this. So I'm actually hesitant to delete them.
Now, as I'm looking at what kinds of bounds we actually get from it I realize that this could be improved. However, the results of this predicate are certainly not incorrect. So I'd actually prefer that we keep them if that's okay with you.
Good point. I've added this in 2076c1c. I had to add another file since the existing |
… this class also applies to C++.
Thanks for the chat, @jketema! Some comments on the commits I just pushed:
After I removed the type test requirement I reran MRVA and looked for cases where we had results for unary equality (we had lots), binary equality, unary "less than"s, and binary "less than"s. All of these cases had quite a few results, and I've added an example of each case in d5b31eb. So, unlike what I expressed in our call earlier, I'm not actually sure we should replace the overrides with What do you think? |
// When `!` is applied to an integer (such as `x`) the generated IR looks | ||
// like: | ||
// ``` | ||
// r1(glval<int>) = VariableAddress[myInt] : | ||
// r2(int) = Load[x] : &:r1, m1_6 | ||
// r3(int) = Constant[0] : | ||
// r4(bool) = CompareEQ : r2, r3 | ||
// ``` | ||
// And so the `IRGuardCondition` for an expression such as `if(!x)` is the | ||
// `CompareEQ` instruction. However, users often expect the `x` to also | ||
// be a guard condition. But from the perspective of the IR the `x` is just | ||
// the left-hand side of a comparison against 0 so it's not included as a | ||
// normal `IRGuardCondition`. So to align with user expectations we make | ||
// that `x` a `GuardCondition`. |
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 no longer up-to-date, I think, as you dropped the non-boolean restriction.
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.
Good point. Fixed in b39a932
What about |
We just discussed this offline: There aren't any query result differences. The change is in the number 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.
LGTM
In C++ code we have int-to-bool conversions on
myInt
in examples like:That is, it's not
myInt
that is branched on, but rather the result ofmyInt != 0
. In the IR, this manifests as the IR looking like:(notice the
BranchNE
instruction).This information is important in guard conditions since branching on
myInt
doesn't tell us thatmyInt == 1
, but rather that(myInt != 0) == 1
.This is all well and good in C++. However, in C, there are no int-to-bool conversions. So when compiling the same code with a C compiler the IR looks like:
(notice that we're now branching on the value of
myInt
)Historically, we've worked around this problem in IRGuards specifically (see #16364 and #16533), but upon facing a related problem somewhere else I now feel like we should simply make the IR equivalent in C and C++.
So this PR inserts IR equivalent to what would have been generated for an int-to-bool conversion if it had been present in the database in the places I'm aware of this being a problem. It then removes the workarounds in the guards library that were added to handle these.
Commit-by-commit review recommended (especially for the IR construction related commits).
DCA reveals a few new results and a few lost results:
cpp/overrun-write
andcpp/path-injection
results are because both queries use any guard as a barrier, and we now recognize more barriers.cpp/redundant-null-check-simple
results are new TPs 🎉Commits 6dd1c5e to 0d7adac are IR-construction related changes, and commits 9810a4f to 5373e22 are IRGuards-related changes.