[NFC][InstSimplify] Add miscompiled testcase from D87188/D87197
authorRoman Lebedev <lebedev.ri@gmail.com>
Fri, 18 Dec 2020 17:24:25 +0000 (20:24 +0300)
committerRoman Lebedev <lebedev.ri@gmail.com>
Fri, 18 Dec 2020 18:18:13 +0000 (21:18 +0300)
Thanks to Dave Green for producing an actionable reproducer!
It is (obviously) a miscompile:
```
----------------------------------------
define i32 @select_abs_of_abs_eq_wrong(i32 %x, i32 %y) {
%0:
  %abs = abs i32 %x, 0
  %neg = sub i32 0, %abs
  %cmp = icmp eq i32 %y, 0
  %sel = select i1 %cmp, i32 %neg, i32 %abs
  ret i32 %sel
}
=>
define i32 @select_abs_of_abs_eq_wrong(i32 %x, i32 %y) {
%0:
  %abs = abs i32 %x, 0
  ret i32 %abs
}
Transformation doesn't verify!
ERROR: Value mismatch

Example:
i32 %x = #xe0000000 (3758096384, -536870912)
i32 %y = #x00000000 (0)

Source:
i32 %abs = #x20000000 (536870912)
i32 %neg = #xe0000000 (3758096384, -536870912)
i1 %cmp = #x1 (1)
i32 %sel = #xe0000000 (3758096384, -536870912)

Target:
i32 %abs = #x20000000 (536870912)
Source value: #xe0000000 (3758096384, -536870912)
Target value: #x20000000 (536870912)

Alive2: Transform doesn't verify!

```

llvm/test/Transforms/InstSimplify/abs_intrinsic.ll

index 4598c57..e0bb170 100644 (file)
@@ -221,6 +221,19 @@ define i32 @select_abs_of_abs_eq(i32 %x) {
   ret i32 %sel
 }
 
+; The comparison is not with the same value we take abs() of, so this isn't the pattern.
+define i32 @select_abs_of_abs_eq_wrong(i32 %x, i32 %y) {
+; CHECK-LABEL: @select_abs_of_abs_eq_wrong(
+; CHECK-NEXT:    [[ABS:%.*]] = call i32 @llvm.abs.i32(i32 [[X:%.*]], i1 false)
+; CHECK-NEXT:    ret i32 [[ABS]]
+;
+  %abs = call i32 @llvm.abs.i32(i32 %x, i1 false)
+  %neg = sub i32 0, %abs
+  %cmp = icmp eq i32 %y, 0 ; not %x
+  %sel = select i1 %cmp, i32 %neg, i32 %abs
+  ret i32 %sel
+}
+
 define i32 @select_abs_of_abs_ne(i32 %x) {
 ; CHECK-LABEL: @select_abs_of_abs_ne(
 ; CHECK-NEXT:    [[ABS:%.*]] = call i32 @llvm.abs.i32(i32 [[X:%.*]], i1 false)
@@ -246,6 +259,20 @@ define i32 @select_nabs_of_abs_eq(i32 %x) {
   ret i32 %sel
 }
 
+; The comparison is not with the same value we take abs() of, so this isn't the pattern.
+define i32 @select_nabs_of_abs_eq_wrong(i32 %x, i32 %y) {
+; CHECK-LABEL: @select_nabs_of_abs_eq_wrong(
+; CHECK-NEXT:    [[ABS:%.*]] = call i32 @llvm.abs.i32(i32 [[X:%.*]], i1 false)
+; CHECK-NEXT:    [[NEG:%.*]] = sub i32 0, [[ABS]]
+; CHECK-NEXT:    ret i32 [[NEG]]
+;
+  %abs = call i32 @llvm.abs.i32(i32 %x, i1 false)
+  %neg = sub i32 0, %abs
+  %cmp = icmp eq i32 %y, 0
+  %sel = select i1 %cmp, i32 %abs, i32 %neg
+  ret i32 %sel
+}
+
 define i32 @select_nabs_of_abs_ne(i32 %x) {
 ; CHECK-LABEL: @select_nabs_of_abs_ne(
 ; CHECK-NEXT:    [[ABS:%.*]] = call i32 @llvm.abs.i32(i32 [[X:%.*]], i1 false)