diff options
-rw-r--r-- | llvm/lib/Analysis/ConstantFolding.cpp | 29 | ||||
-rw-r--r-- | llvm/test/Transforms/ConstProp/overflow-ops.ll | 13 |
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 |