]> granicus.if.org Git - llvm/commitdiff
[ConstantFolding] Fix 'undef' folding for @llvm.[us]{add,sub}.with.overflow ops ...
authorRoman Lebedev <lebedev.ri@gmail.com>
Sun, 1 Sep 2019 11:56:52 +0000 (11:56 +0000)
committerRoman Lebedev <lebedev.ri@gmail.com>
Sun, 1 Sep 2019 11:56:52 +0000 (11:56 +0000)
As we have already established/fixed in
  https://bugs.llvm.org/show_bug.cgi?id=42209
  https://reviews.llvm.org/D63065
  https://reviews.llvm.org/rL363522
the InstSimplify handling for @llvm.with.overflow ops with undefs
is correct. Therefore if ConstantFolding produces different results,
then it is wrong.

This duplication of code hints at the need for some refactoring,
but for now address the brokenness of ConstantFolding by
copying the known-good handling from rL363522.

Fixes https://bugs.llvm.org/show_bug.cgi?id=43188

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@370608 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Analysis/ConstantFolding.cpp
test/Transforms/ConstProp/overflow-ops.ll

index f7cc53b345f72ccb5517cd84765f5f5327fe157d..cedd788d2263a417c0591acb51c20cb87fc2b72a 100644 (file)
@@ -2041,20 +2041,27 @@ static Constant *ConstantFoldScalarCall2(StringRef Name,
 
     switch (IntrinsicID) {
     default: break;
+    case Intrinsic::usub_with_overflow:
+    case Intrinsic::ssub_with_overflow:
+    case Intrinsic::uadd_with_overflow:
+    case Intrinsic::sadd_with_overflow:
+      // X - undef -> { undef, false }
+      // undef - X -> { undef, false }
+      // X + undef -> { undef, false }
+      // undef + x -> { undef, false }
+      if (!C0 || !C1) {
+        return ConstantStruct::get(
+            cast<StructType>(Ty),
+            {UndefValue::get(Ty->getStructElementType(0)),
+             Constant::getNullValue(Ty->getStructElementType(1))});
+      }
+      LLVM_FALLTHROUGH;
     case Intrinsic::smul_with_overflow:
-    case Intrinsic::umul_with_overflow:
-      // Even if both operands are undef, we cannot fold muls to undef
-      // in the general case. For example, on i2 there are no inputs
-      // that would produce { i2 -1, i1 true } as the result.
+    case Intrinsic::umul_with_overflow: {
+      // undef * X -> { 0, false }
+      // X * undef -> { 0, false }
       if (!C0 || !C1)
         return Constant::getNullValue(Ty);
-      LLVM_FALLTHROUGH;
-    case Intrinsic::sadd_with_overflow:
-    case Intrinsic::uadd_with_overflow:
-    case Intrinsic::ssub_with_overflow:
-    case Intrinsic::usub_with_overflow: {
-      if (!C0 || !C1)
-        return UndefValue::get(Ty);
 
       APInt Res;
       bool Overflow;
index 303b3b90ab36cd708ee33d9f780d408ac995bfa6..1d090d5d0ea15dba03913b138bb812c495287dc0 100644 (file)
@@ -1,5 +1,8 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -constprop -S | FileCheck %s
+; RUN: opt < %s -constprop -S | FileCheck %s --check-prefixes=CHECK,CONSTPROP
+; RUN: opt < %s -instsimplify -S | FileCheck %s --check-prefixes=CHECK,INSTSIMPLIFY
+; We must *NOT* have any check-lines with prefixes other than CHECK here.
+; If we do, that means the rules are different between the passes.
 
 declare {i8, i1} @llvm.uadd.with.overflow.i8(i8, i8)
 declare {i8, i1} @llvm.usub.with.overflow.i8(i8, i8)
@@ -31,7 +34,7 @@ define {i8, i1} @uadd_2() nounwind {
 
 define {i8, i1} @uadd_undef() nounwind {
 ; CHECK-LABEL: @uadd_undef(
-; CHECK-NEXT:    ret { i8, i1 } undef
+; CHECK-NEXT:    ret { i8, i1 } { i8 undef, i1 false }
 ;
   %t = call {i8, i1} @llvm.uadd.with.overflow.i8(i8 142, i8 undef)
   ret {i8, i1} %t
@@ -59,7 +62,7 @@ define {i8, i1} @usub_2() nounwind {
 
 define {i8, i1} @usub_undef() nounwind {
 ; CHECK-LABEL: @usub_undef(
-; CHECK-NEXT:    ret { i8, i1 } undef
+; CHECK-NEXT:    ret { i8, i1 } { i8 undef, i1 false }
 ;
   %t = call {i8, i1} @llvm.usub.with.overflow.i8(i8 4, i8 undef)
   ret {i8, i1} %t
@@ -147,7 +150,7 @@ define {i8, i1} @sadd_5() nounwind {
 
 define {i8, i1} @sadd_undef() nounwind {
 ; CHECK-LABEL: @sadd_undef(
-; CHECK-NEXT:    ret { i8, i1 } undef
+; CHECK-NEXT:    ret { i8, i1 } { i8 undef, i1 false }
 ;
   %t = call {i8, i1} @llvm.sadd.with.overflow.i8(i8 undef, i8 -10)
   ret {i8, i1} %t
@@ -215,7 +218,7 @@ define {i8, i1} @ssub_5() nounwind {
 
 define {i8, i1} @ssub_undef() nounwind {
 ; CHECK-LABEL: @ssub_undef(
-; CHECK-NEXT:    ret { i8, i1 } undef
+; CHECK-NEXT:    ret { i8, i1 } { i8 undef, i1 false }
 ;
   %t = call {i8, i1} @llvm.ssub.with.overflow.i8(i8 undef, i8 -10)
   ret {i8, i1} %t