-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Don't perform unsigned comparisons for signed integers #124122
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -368,6 +368,8 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp { | |||||
return None; | ||||||
} | ||||||
|
||||||
// For signed comparisons, we need to consider different bit widths, | ||||||
// so we need to transform to i128 for comparison. | ||||||
fn int_equal(l: ScalarInt, r: impl Into<u128>, size: Size) -> bool { | ||||||
l.try_to_int(l.size()).unwrap() | ||||||
== ScalarInt::try_from_uint(r, size).unwrap().try_to_int(size).unwrap() | ||||||
|
@@ -399,7 +401,10 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp { | |||||
if ((f_c.const_.ty().is_signed() || discr_ty.is_signed()) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Otherwise you're still potentially treating something as signed that is unsigned, or vice versa. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Honestly I think it's best to move this entire thing into a helper, not just And also, why is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah I see, it's about converting the So already further up, you should convert In fact we should probably change SwitchInt to store a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hold on a sec... isn't what you actually want to do here some sort of cast? I don't know the right direction, but -- basically you want to cast the discriminant value to the type of the constant (or the other way around), and then check they are equal, right? The interpreter has the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Everything looks fine here. Any signed integer will be converted to a signed comparison. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I have seen your new issue. :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Perhaps this could be a separate PR? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
You're treating both values as signed if either of them is signed. That means you can be treating unsigned values as signed, which is wrong.
Perhaps, but I don't understand you current PR, so it may also be a way to turn this code into something that makes sense to more than one person. ;) Feel free to pick a different reviewer, but I can't make sense of what this code is trying to achieve. The comments don't explain the high-level picture (what are we even trying to achieve with this complicated series of checks) and the low-level details are clearly still mixing up signedness. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
In the known test cases, it is correct. But I must carefully check the edge cases here. For safety reasons, I will later consider only signed-to-signed conversions in this PR. :) cc @rust-lang/wg-mir-opt Perhaps someone else will directly point out this specific problem? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
That's a very low bar. The comments should give convincing reasons why it is correct for all possible MIR ever. |
||||||
&& int_equal(f, first_val, discr_size) | ||||||
&& int_equal(s, second_val, discr_size)) | ||||||
|| (Some(f) == ScalarInt::try_from_uint(first_val, f.size()) | ||||||
|| (!f_c.const_.ty().is_signed() | ||||||
&& !discr_ty.is_signed() | ||||||
&& Some(f) | ||||||
== ScalarInt::try_from_uint(first_val, f.size()) | ||||||
&& Some(s) | ||||||
== ScalarInt::try_from_uint(second_val, s.size())) => | ||||||
{ | ||||||
|
@@ -449,7 +454,10 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp { | |||||
{ | ||||||
continue; | ||||||
} | ||||||
if Some(f) == ScalarInt::try_from_uint(other_val, f.size()) { | ||||||
if !is_signed | ||||||
&& !s_c.const_.ty().is_signed() | ||||||
&& Some(f) == ScalarInt::try_from_uint(other_val, f.size()) | ||||||
{ | ||||||
continue; | ||||||
} | ||||||
return None; | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
- // MIR for `match_i8_i16_failed_2_a` before MatchBranchSimplification | ||
+ // MIR for `match_i8_i16_failed_2_a` after MatchBranchSimplification | ||
|
||
fn match_i8_i16_failed_2_a(_1: EnumAi8) -> i16 { | ||
debug i => _1; | ||
let mut _0: i16; | ||
let mut _2: i8; | ||
|
||
bb0: { | ||
_2 = discriminant(_1); | ||
switchInt(move _2) -> [255: bb3, 2: bb4, 253: bb2, otherwise: bb1]; | ||
} | ||
|
||
bb1: { | ||
unreachable; | ||
} | ||
|
||
bb2: { | ||
_0 = const -3_i16; | ||
goto -> bb5; | ||
} | ||
|
||
bb3: { | ||
_0 = const 255_i16; | ||
goto -> bb5; | ||
} | ||
|
||
bb4: { | ||
_0 = const 2_i16; | ||
goto -> bb5; | ||
} | ||
|
||
bb5: { | ||
return; | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
- // MIR for `match_i8_i16_failed_2_b` before MatchBranchSimplification | ||
+ // MIR for `match_i8_i16_failed_2_b` after MatchBranchSimplification | ||
|
||
fn match_i8_i16_failed_2_b(_1: EnumAi8) -> i16 { | ||
debug i => _1; | ||
let mut _0: i16; | ||
let mut _2: i8; | ||
|
||
bb0: { | ||
_2 = discriminant(_1); | ||
switchInt(move _2) -> [255: bb3, 2: bb4, 253: bb2, otherwise: bb1]; | ||
} | ||
|
||
bb1: { | ||
unreachable; | ||
} | ||
|
||
bb2: { | ||
_0 = const 253_i16; | ||
goto -> bb5; | ||
} | ||
|
||
bb3: { | ||
_0 = const -1_i16; | ||
goto -> bb5; | ||
} | ||
|
||
bb4: { | ||
_0 = const 2_i16; | ||
goto -> bb5; | ||
} | ||
|
||
bb5: { | ||
return; | ||
} | ||
} | ||
|
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 does it make sense to compare the lengths of the basic blocks...?!?
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.
Because we are currently only merging simple BBs, we have not considered BBs that could potentially be merged even though they have different numbers of instructions.
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.
What's a "simple BB"? If both BBs have 24 instructions, how is that okay but one having 20 and the other 24 is not? The same number of instructions tells you absolutely nothing about what the BBs are doing...
There needs to be a comment here, at first sight this seems entirely nonsensical.
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.
Sorry for the unclear expression. I mean the merging of basic blocks that only consider simple scenarios.
This is just an early bail-out. We assume that BBs with different the lengths of BBs cannot be merged.