-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
[InstCombine] Miscompile of (x & (~(-1 << x))) << x #49122
Comments
assigned to @LebedevRI |
Does not repro on main: https://godbolt.org/z/zdfbEKns9 |
Looks like the link you sent shows that it does repro? The optimized version is unconditionally zero. It shouldn't be. |
Just to clarify my earlier comment, the posted code snippet can conceivably be simplified to: %x13 = zext i1 %x2 to i32 Which looks like what that instcombine transformation might be trying to accomplish. The truth table for this is: f(0) => 0 However, it is being replaced with zero by the optimizer because of the addition of an AND with zero. |
I think the bug lies here: auto *SumOfShAmts = dyn_cast_or_null(SimplifyAddInst(
It's trying to simplify the sum of the two shift values (MaskShAmt and ShiftShAmt) in the expression: (x & (~(-1 << MaskShAmt))) << ShiftShAmt Where the code again is: %x13 = zext i1 %x2 to i32 In this case both MaskShAmt and ShiftShAmt in the expression above are i1 %x2 (the matching looks through zexts). So, of course, it can simplify i1 %x2 + %x2 to zero, but that is incorrect for the purposes of the transformation because it overflows the type i1 which results in the wrong mask being generated. |
fwiw, a C repro: #include <stdio.h> unsigned int f(bool b) { int main(int argc, char** argv) { $ clang -O2 foo.c && ./a.out https://godbolt.org/z/jT1sKa1rq |
I'm not sure if this would be considered a legitimate/complete fix, but we are missing this simplification: define i32 @src(i1 %b) { define i32 @tgt(i1 %b) { If we had that, it might guarantee that the bug in instcombine is covered up? |
If the only known problem case is with a bool type, there's a 1-line fix? diff --git a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
|
The fix would consist of copypasting 781d077. |
Sorry for the delay, fixed. |
Thanks for the quick fix! |
There are 3 commits listed in the "Fixed By Commits" field. Do these all need to be backported? |
Yep |
Merged: c27ad80 |
Extended Description
This expression is miscompiled in the case where x is zext of a single bit value. Here's before and after from a single instcombine transform extracted using debug_counter and fed to Alive:
define i32 @src(i1 %x2) {
%0:
%x13 = zext i1 %x2 to i32
%_7 = shl i32 4294967295, %x13
%mask = xor i32 %_7, 4294967295
%_8 = and i32 %mask, %x13
%_9 = shl i32 %_8, %x13
ret i32 %_9
}
=>
define i32 @tgt(i1 %x2) {
%0:
%x13 = zext i1 %x2 to i32
%1 = shl i32 %x13, %x13
%_9 = and i32 %1, 0
ret i32 %_9
}
Transformation doesn't verify!
ERROR: Value mismatch
Example:
i1 %x2 = #x1 (1)
Source:
i32 %x13 = #x00000001 (1)
i32 %_7 = #xfffffffe (4294967294, -2)
i32 %mask = #x00000001 (1)
i32 %_8 = #x00000001 (1)
i32 %_9 = #x00000002 (2)
Target:
i32 %x13 = #x00000001 (1)
i32 %1 = #x00000002 (2)
i32 %_9 = #x00000000 (0)
Source value: #x00000002 (2)
Target value: #x00000000 (0)
I suspect the problematic transform is this one:
llvm-project/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
Line 168 in c06a8f9
Looks like maybe(?) NewMask is incorrectly being computed as zero:
llvm-project/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
Line 317 in c06a8f9
The text was updated successfully, but these errors were encountered: