[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