diff options
| author | Evan Phoenix <evan@fallingsnow.net> | 2009-10-05 22:53:52 +0000 | 
|---|---|---|
| committer | Evan Phoenix <evan@fallingsnow.net> | 2009-10-05 22:53:52 +0000 | 
| commit | 44e5dbcaf035aa04f000505b39be657b26b10754 (patch) | |
| tree | 99f15c1e74d813c2b3eed34fcfee994e77e6f6b0 | |
| parent | 3472ae5bac95965083490b746c7da045054658f8 (diff) | |
| download | bcm5719-llvm-44e5dbcaf035aa04f000505b39be657b26b10754.tar.gz bcm5719-llvm-44e5dbcaf035aa04f000505b39be657b26b10754.zip  | |
Extend ConstantFolding to understand signed overflow variants
llvm-svn: 83338
| -rw-r--r-- | llvm/lib/Analysis/ConstantFolding.cpp | 24 | ||||
| -rw-r--r-- | llvm/test/Transforms/ConstProp/overflow-ops.ll | 121 | 
2 files changed, 144 insertions, 1 deletions
diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp index 1ca7cb05b41..0ce1c24bed6 100644 --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -678,6 +678,8 @@ llvm::canConstantFoldCallTo(const Function *F) {    case Intrinsic::cttz:    case Intrinsic::uadd_with_overflow:    case Intrinsic::usub_with_overflow: +  case Intrinsic::sadd_with_overflow: +  case Intrinsic::ssub_with_overflow:      return true;    default:      return false; @@ -902,6 +904,28 @@ llvm::ConstantFoldCall(Function *F,            };            return ConstantStruct::get(F->getContext(), Ops, 2, false);          } +        case Intrinsic::sadd_with_overflow: { +          Constant *Res = ConstantExpr::getAdd(Op1, Op2);           // result. +          Constant *Overflow = ConstantExpr::getSelect( +              ConstantExpr::getICmp(CmpInst::ICMP_SGT, +                ConstantInt::get(Op1->getType(), 0), Op1), +              ConstantExpr::getICmp(CmpInst::ICMP_SGT, Res, Op2),  +              ConstantExpr::getICmp(CmpInst::ICMP_SLT, Res, Op2)); // overflow. + +          Constant *Ops[] = { Res, Overflow }; +          return ConstantStruct::get(F->getContext(), Ops, 2, false); +        } +        case Intrinsic::ssub_with_overflow: { +          Constant *Res = ConstantExpr::getSub(Op1, Op2);           // result. +          Constant *Overflow = ConstantExpr::getSelect( +              ConstantExpr::getICmp(CmpInst::ICMP_SGT, +                ConstantInt::get(Op2->getType(), 0), Op2), +              ConstantExpr::getICmp(CmpInst::ICMP_SLT, Res, Op1),  +              ConstantExpr::getICmp(CmpInst::ICMP_SGT, Res, Op1)); // overflow. + +          Constant *Ops[] = { Res, Overflow }; +          return ConstantStruct::get(F->getContext(), Ops, 2, false); +        }          }        } diff --git a/llvm/test/Transforms/ConstProp/overflow-ops.ll b/llvm/test/Transforms/ConstProp/overflow-ops.ll index 52d59217b49..1547a4d0f5b 100644 --- a/llvm/test/Transforms/ConstProp/overflow-ops.ll +++ b/llvm/test/Transforms/ConstProp/overflow-ops.ll @@ -24,7 +24,6 @@ entry:  ; CHECK: ret %i8i1 { i8 6, i1 true }  } -  ;;-----------------------------  ;; usub  ;;----------------------------- @@ -47,7 +46,127 @@ entry:  ; CHECK: ret %i8i1 { i8 -2, i1 true }  } +;;----------------------------- +;; sadd +;;----------------------------- + +define {i8, i1} @sadd_1() nounwind { +entry: +  %t = call {i8, i1} @llvm.sadd.with.overflow.i8(i8 42, i8 2) +  ret {i8, i1} %t + +; CHECK: @sadd_1 +; CHECK: ret %i8i1 { i8 44, i1 false } +} + +define {i8, i1} @sadd_2() nounwind { +entry: +  %t = call {i8, i1} @llvm.sadd.with.overflow.i8(i8 120, i8 10) +  ret {i8, i1} %t + +; CHECK: @sadd_2 +; CHECK: ret %i8i1 { i8 -126, i1 true } +} + +define {i8, i1} @sadd_3() nounwind { +entry: +  %t = call {i8, i1} @llvm.sadd.with.overflow.i8(i8 -120, i8 10) +  ret {i8, i1} %t + +; CHECK: @sadd_3 +; CHECK: ret %i8i1 { i8 -110, i1 false } +} + +define {i8, i1} @sadd_4() nounwind { +entry: +  %t = call {i8, i1} @llvm.sadd.with.overflow.i8(i8 -120, i8 -10) +  ret {i8, i1} %t + +; CHECK: @sadd_4 +; CHECK: ret %i8i1 { i8 126, i1 true } +} + +define {i8, i1} @sadd_5() nounwind { +entry: +  %t = call {i8, i1} @llvm.sadd.with.overflow.i8(i8 2, i8 -10) +  ret {i8, i1} %t + +; CHECK: @sadd_5 +; CHECK: ret %i8i1 { i8 -8, i1 false } +} + + +;;----------------------------- +;; ssub +;;----------------------------- + +define {i8, i1} @ssub_1() nounwind { +entry: +  %t = call {i8, i1} @llvm.ssub.with.overflow.i8(i8 4, i8 2) +  ret {i8, i1} %t + +; CHECK: @ssub_1 +; CHECK: ret %i8i1 { i8 2, i1 false } +} + +define {i8, i1} @ssub_2() nounwind { +entry: +  %t = call {i8, i1} @llvm.ssub.with.overflow.i8(i8 4, i8 6) +  ret {i8, i1} %t + +; CHECK: @ssub_2 +; CHECK: ret %i8i1 { i8 -2, i1 false } +} + +define {i8, i1} @ssub_3() nounwind { +entry: +  %t = call {i8, i1} @llvm.ssub.with.overflow.i8(i8 -10, i8 120) +  ret {i8, i1} %t + +; CHECK: @ssub_3 +; CHECK: ret %i8i1 { i8 126, i1 true } +} + +define {i8, i1} @ssub_3b() nounwind { +entry: +  %t = call {i8, i1} @llvm.ssub.with.overflow.i8(i8 -10, i8 10) +  ret {i8, i1} %t + +; CHECK: @ssub_3b +; CHECK: ret %i8i1 { i8 -20, i1 false } +} + +define {i8, i1} @ssub_4() nounwind { +entry: +  %t = call {i8, i1} @llvm.ssub.with.overflow.i8(i8 120, i8 -10) +  ret {i8, i1} %t + +; CHECK: @ssub_4 +; CHECK: ret %i8i1 { i8 -126, i1 true } +} + +define {i8, i1} @ssub_4b() nounwind { +entry: +  %t = call {i8, i1} @llvm.ssub.with.overflow.i8(i8 20, i8 -10) +  ret {i8, i1} %t + +; CHECK: @ssub_4b +; CHECK: ret %i8i1 { i8 30, i1 false } +} + +define {i8, i1} @ssub_5() nounwind { +entry: +  %t = call {i8, i1} @llvm.ssub.with.overflow.i8(i8 -20, i8 -10) +  ret {i8, i1} %t + +; CHECK: @ssub_5 +; CHECK: ret %i8i1 { i8 -10, i1 false } +} +  declare {i8, i1} @llvm.uadd.with.overflow.i8(i8, i8)  declare {i8, i1} @llvm.usub.with.overflow.i8(i8, i8) + +declare {i8, i1} @llvm.sadd.with.overflow.i8(i8, i8) +declare {i8, i1} @llvm.ssub.with.overflow.i8(i8, i8)  | 

