From 5f5939c14c7933d3a5295906a82497f7a14f6dfd Mon Sep 17 00:00:00 2001 From: David Majnemer Date: Wed, 2 Jul 2014 06:07:09 +0000 Subject: [PATCH] InstCombine: Don't turn -(x/INT_MIN) -> x/INT_MIN It is not safe to negate the smallest signed integer, doing so yields the same number back. This fixes PR20186. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@212164 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/IR/Constant.h | 3 +++ lib/IR/Constants.cpp | 22 +++++++++++++++++++ .../InstCombine/InstCombineAddSub.cpp | 6 ++--- test/Transforms/InstCombine/sub.ll | 19 ++++++++++++++++ 4 files changed, 47 insertions(+), 3 deletions(-) diff --git a/include/llvm/IR/Constant.h b/include/llvm/IR/Constant.h index 257bb80f211..82ad9fc2f40 100644 --- a/include/llvm/IR/Constant.h +++ b/include/llvm/IR/Constant.h @@ -64,6 +64,9 @@ public: /// Return true if the value is negative zero or null value. bool isZeroValue() const; + /// \brief Return true if the value is the smallest signed value. + bool isMinSignedValue() const; + /// canTrap - Return true if evaluation of this constant could trap. This is /// true for things like constant expressions that could divide by zero. bool canTrap() const; diff --git a/lib/IR/Constants.cpp b/lib/IR/Constants.cpp index 5851625383b..b815936ac42 100644 --- a/lib/IR/Constants.cpp +++ b/lib/IR/Constants.cpp @@ -107,6 +107,28 @@ bool Constant::isAllOnesValue() const { return false; } +bool Constant::isMinSignedValue() 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->isMinSignedValue(); + + // 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->isMinSignedValue(); + + 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 f8d7e0ecf44..c18ed2df7ad 100644 --- a/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ b/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -1553,9 +1553,9 @@ Instruction *InstCombiner::visitSub(BinaryOperator &I) { return BinaryOperator::CreateAnd(Op0, Builder->CreateNot(Y, Y->getName() + ".not")); - // 0 - (X sdiv C) -> (X sdiv -C) - if (match(Op1, m_SDiv(m_Value(X), m_Constant(C))) && - match(Op0, m_Zero())) + // 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()) 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 41d803c8bdd..a9dffe793a1 100644 --- a/test/Transforms/InstCombine/sub.ll +++ b/test/Transforms/InstCombine/sub.ll @@ -444,3 +444,22 @@ define <2 x i64> @test36(<2 x i64> %A) { ; CHECK-NEXT: %sub = mul <2 x i64> %A, ; CHECK-NEXT: ret <2 x i64> %sub } + +define <2 x i64> @test37(<2 x i64> %A) { + %shl = shl <2 x i64> %A, + %sub = sub <2 x i64> %shl, %A + ret <2 x i64> %sub +; CHECK-LABEL: @test37( +; CHECK-NEXT: %sub = mul <2 x i64> %A, +; CHECK-NEXT: ret <2 x i64> %sub +} + +define i32 @test38(i32 %A) { + %div = sdiv i32 %A, -2147483648 + %sub = sub nsw i32 0, %div + ret i32 %sub +; CHECK-LABEL: @test38( +; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 %A, -2147483648 +; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 0, [[DIV]] +; CHECK-NEXT: ret i32 [[SUB]] +}