Issue 185099
Summary [VectorCombine] Incorrect pointer offset when shrinking `shufflevector` loads of `<N x i1>`
Labels new issue
Assignees
Reporter cardigan1008
    This is a miscompilation case when reviewing https://github.com/llvm/llvm-project/pull/179001:

```llvm
@g = global [2 x i8] [i8 170, i8 0], align 32

define i32 @shuffle_v8_v8i1_cond_r1_2(ptr nocapture readonly %arg0, i1 %cond) local_unnamed_addr {
entry:
  %val0 = load <8 x i1>, ptr %arg0, align 1
  br i1 %cond, label %then, label %else

then:                                             ; preds = %entry
 %val1 = shufflevector <8 x i1> %val0, <8 x i1> poison, <8 x i32> <i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1>
  br label %finally

else: ; preds = %entry
  %val2 = shufflevector <8 x i1> %val0, <8 x i1> poison, <8 x i32> <i32 2, i32 2, i32 2, i32 2, i32 2, i32 2, i32 2, i32 2>
  br label %finally

finally: ; preds = %else, %then
  %val3 = phi <8 x i1> [ %val1, %then ], [ %val2, %else ]
  %res = bitcast <8 x i1> %val3 to i8
  %res32 = zext i8 %res to i32
  ret i32 %res32
}

define i32 @main(i32 %argc, ptr %argv) {
entry:
  %r = call i32 @shuffle_v8_v8i1_cond_r1_2(ptr @g, i1 true)
  ret i32 %r
}
```

**Transformed LLVM IR:**
```llvm

; ModuleID = '/data/tmp/tmpqj2ym6tl/orig.ll'
source_filename = "/data/tmp/tmpqj2ym6tl/orig.ll"

@g = global [2 x i8] c"\AA\00", align 32

define i32 @shuffle_v8_v8i1_cond_r1_2(ptr readonly captures(none) %arg0, i1 %cond) local_unnamed_addr {
entry:
  %0 = getelementptr inbounds i8, ptr %arg0, i64 1
  %1 = load <2 x i1>, ptr %0, align 1
  br i1 %cond, label %then, label %else

then: ; preds = %entry
  %val1 = shufflevector <2 x i1> %1, <2 x i1> poison, <8 x i32> zeroinitializer
  br label %finally

else: ; preds = %entry
  %val2 = shufflevector <2 x i1> %1, <2 x i1> poison, <8 x i32> <i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1>
  br label %finally

finally: ; preds = %else, %then
  %val3 = phi <8 x i1> [ %val1, %then ], [ %val2, %else ]
  %res = bitcast <8 x i1> %val3 to i8
  %res32 = zext i8 %res to i32
  ret i32 %res32
}

define i32 @main(i32 %argc, ptr %argv) {
entry:
  %r = call i32 @shuffle_v8_v8i1_cond_r1_2(ptr @g, i1 true)
  ret i32 %r
}
```

Ran lli on them, we got different results:

```sh
$ lli src.ll
$ echo $?
255
$ lli tgt.ll
$ echo $?
0
```

Alive2 also proved this: https://alive2.llvm.org/ce/z/sNXJtP

> Note: This is a review assisted with a self-built agent. The reproducer was validated manually. Please let me know if anything is wrong.

**Bug Triggering Analysis:**
The provided test case loads an `<8 x i1>` vector from a global variable `@g` which is initialized to `[i8 170, i8 0]`. The first byte is `10101010` in binary. The `shufflevector` extracts the element at index 1, which is `1` (`true`). The result is a vector of all `true`s, which is bitcasted to `i8` resulting in `255`.
The `VectorCombine` pass shrinks the load to `<2 x i1>` starting at index 1. It calculates the pointer offset as `1 * getTypeAllocSize(i1) = 1 * 1 = 1` byte. It adds 1 byte to the pointer, reading from the second byte of `@g`, which is `0`. The result is a vector of all `false`s, which is bitcasted to `i8` resulting in `0`.
This causes a difference in execution, confirming the bug.

**Fix Weakness Analysis:**
The fix uses `DL->getTypeAllocSize(ElemTy)` to compute the element size in bytes. This is incorrect for non-byte-sized elements like `i1` or `i4`, because `getTypeAllocSize` rounds up to the nearest byte. For `i1`, it returns 1 byte. Multiplying `LowOffset` by this rounded-up size results in an incorrect byte offset for the pointer addition. The fix should either check if the element type is byte-sized (`DL->typeSizeEqualsStoreSize(ElemTy)`) or calculate the offset in bits and check if it's a multiple of 8.

cc @Icohedron 
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to