summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/lib/Analysis/ConstantFolding.cpp29
-rw-r--r--llvm/test/Transforms/ConstProp/overflow-ops.ll13
2 files changed, 26 insertions, 16 deletions
diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp
index f7cc53b345f..cedd788d226 100644
--- a/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/llvm/lib/Analysis/ConstantFolding.cpp
@@ -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;
diff --git a/llvm/test/Transforms/ConstProp/overflow-ops.ll b/llvm/test/Transforms/ConstProp/overflow-ops.ll
index 303b3b90ab3..1d090d5d0ea 100644
--- a/llvm/test/Transforms/ConstProp/overflow-ops.ll
+++ b/llvm/test/Transforms/ConstProp/overflow-ops.ll
@@ -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
OpenPOWER on IntegriCloud