[PATCH] PR19958 wrong code at -O1 and above on x86_64-linux-gnu (InstCombine)
Duncan P. N. Exon Smith
dexonsmith at apple.com
Tue Jul 8 13:00:41 PDT 2014
> On 2014-Jul-08, at 10:40, suyog sarda <sardask01 at gmail.com> wrote:
>
>> I'm not convinced about `lshr exact`. Consider:
>>
>> %Shifted = lshr exact i2 2, %A
>> %Compare = icmp eq i2 %Shifted, 1
>>
>> Here, 2 is negative and 1 is positive, but the %Compare should be `i1 1`
>> when %A is 1.
>>
>> If simplify gives `i1 0` for this, it sounds like a bug to me. Can you
>> confirm?
>
> Strangely, the output varies here.
>
> cat test.ll
> define i1 @main(i2 %a) {
> %shr = lshr exact i2 2, %a
> %cmp = icmp eq i2 %shr, 1
> ret i1 %cmp
> }
>
> llvm/llvm/build/bin/opt -S -instcombine test.ll
> ; ModuleID = 'test.ll'
>
> define i1 @main(i2 %a) {
> %shr = lshr exact i2 -2, %a
> %cmp = icmp eq i2 %shr, 1
> ret i1 %cmp
> }
>
> llvm/llvm/build/bin/opt -S -instsimplify test.ll
> ; ModuleID = 'test.ll'
>
> define i1 @main(i2 %a) {
> %shr = lshr exact i2 -2, %a
> %cmp = icmp eq i2 %shr, 1
> ret i1 %cmp
> }
>
> As visible above, the 'Simplify' or 'Combine' doesn't return false.
>
> However,
> Consider following Test case :
>
> cat test.ll
> define i1 @main(i32 %a) {
> %shr = lshr exact i32 -64, %a // One positive one negative
> %cmp = icmp eq i32 %shr, 16
> ret i1 %cmp
> }
>
> llvm/llvm/build/bin/opt -S -instsimplify test.ll
> ; ModuleID = 'test.ll'
>
> define i1 @main(i32 %a) {
> ret i1 false
> }
>
> llvm/llvm/build/bin/opt -S -instcombine test.ll
> ; ModuleID = 'test.ll'
>
> define i1 @main(i32 %a) {
> ret i1 false
> }
>
> It seems, 'Simplify' is behaving differently for 'extreme (MIN/MAX)' values
> and values in 'middle'. Is this logically correct (doesn't seem so)? Or a bug?
The -instsimplify code seems logically correct. These are bitwise operations,
so think about this on the bit level. This is what -64 and 16 look like:
i32 -64 => 0b11111111 11111111 11111111 11000000
i32 16 => 0b00000000 00000000 00000000 00010000
There's no `lshr` operation that can get you from -64 to 16 in an `i32`. For
`exact`, any shift between 0 and 6 will give `i1 0`; other shifts can give
`i1 undef` or `i1 0` or `i1 1` at their leisure.
However, with an `i7`:
i7 -64 => 0b1000000
i7 16 => 0b0010000
This is an `lshr` of 2.
`lshr exact i8 -64, 2` (e.g.) will give 48:
i8 -64 => 0b11000000
i8 48 => 0b00110000
Talking about signs doesn't really make sense with `lshr`.
More information about the llvm-commits
mailing list