From 0e4fc41b0d952f8185af8c4199efa2a3571f2552 Mon Sep 17 00:00:00 2001 From: David Majnemer Date: Fri, 22 Aug 2014 16:41:23 +0000 Subject: [PATCH] InstCombine: sub nsw %x, C -> add nsw %x, -C if C isn't INT_MIN We can preserve nsw during this transform if -C won't overflow. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@216269 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/IR/Constant.h | 3 +++ lib/IR/Constants.cpp | 23 +++++++++++++++++++ .../InstCombine/InstCombineAddSub.cpp | 5 +++- test/Transforms/InstCombine/sub.ll | 8 +++++++ 4 files changed, 38 insertions(+), 1 deletion(-) diff --git a/include/llvm/IR/Constant.h b/include/llvm/IR/Constant.h index 019e2b93380..d26991eaab7 100644 --- a/include/llvm/IR/Constant.h +++ b/include/llvm/IR/Constant.h @@ -69,6 +69,9 @@ public: /// Return true if the value is negative zero or null value. bool isZeroValue() const; + /// \brief Return true if the value is not the smallest signed value. + bool isNotMinSignedValue() const; + /// \brief Return true if the value is the smallest signed value. bool isMinSignedValue() const; diff --git a/lib/IR/Constants.cpp b/lib/IR/Constants.cpp index b72d850ce25..e2db4fdb291 100644 --- a/lib/IR/Constants.cpp +++ b/lib/IR/Constants.cpp @@ -151,6 +151,29 @@ bool Constant::isMinSignedValue() const { return false; } +bool Constant::isNotMinSignedValue() const { + // Check for INT_MIN integers + if (const ConstantInt *CI = dyn_cast(this)) + return !CI->isMinValue(/*isSigned=*/true); + + // Check for FP which are bitcasted from INT_MIN integers + if (const ConstantFP *CFP = dyn_cast(this)) + return !CFP->getValueAPF().bitcastToAPInt().isMinSignedValue(); + + // Check for constant vectors which are splats of INT_MIN values. + if (const ConstantVector *CV = dyn_cast(this)) + if (Constant *Splat = CV->getSplatValue()) + return Splat->isNotMinSignedValue(); + + // Check for constant vectors which are splats of INT_MIN values. + if (const ConstantDataVector *CV = dyn_cast(this)) + if (Constant *Splat = CV->getSplatValue()) + return Splat->isNotMinSignedValue(); + + // It *may* contain INT_MIN, we can't tell. + return false; +} + // Constructor to create a '0' constant of arbitrary type... Constant *Constant::getNullValue(Type *Ty) { switch (Ty->getTypeID()) { diff --git a/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/lib/Transforms/InstCombine/InstCombineAddSub.cpp index e7e6cdd63d1..600e09433cc 100644 --- a/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ b/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -1539,6 +1539,9 @@ Instruction *InstCombiner::visitSub(BinaryOperator &I) { "Expected a subtraction operator!"); if (BO->hasNoSignedWrap() && I.hasNoSignedWrap()) Res->setHasNoSignedWrap(true); + } else { + if (cast(Op1)->isNotMinSignedValue() && I.hasNoSignedWrap()) + Res->setHasNoSignedWrap(true); } return Res; @@ -1629,7 +1632,7 @@ Instruction *InstCombiner::visitSub(BinaryOperator &I) { // 0 - (X sdiv C) -> (X sdiv -C) provided the negation doesn't overflow. if (match(Op1, m_SDiv(m_Value(X), m_Constant(C))) && match(Op0, m_Zero()) && - !C->isMinSignedValue() && !C->isOneValue()) + C->isNotMinSignedValue() && !C->isOneValue()) return BinaryOperator::CreateSDiv(X, ConstantExpr::getNeg(C)); // 0 - (X << Y) -> (-X << Y) when X is freely negatable. diff --git a/test/Transforms/InstCombine/sub.ll b/test/Transforms/InstCombine/sub.ll index c786ba44ea7..e0b3a07c233 100644 --- a/test/Transforms/InstCombine/sub.ll +++ b/test/Transforms/InstCombine/sub.ll @@ -521,3 +521,11 @@ define i4 @test43(i4 %x, i4 %y) { ; CHECK-NEXT: [[RET:%.*]] = sub nuw i4 [[OR]], [[AND]] ; CHECK: ret i4 [[RET]] } + +define i32 @test44(i32 %x) { + %sub = sub nsw i32 %x, 32768 + ret i32 %sub +; CHECK-LABEL: @test44( +; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 %x, -32768 +; CHECK: ret i32 [[ADD]] +} -- 2.34.1