From: David Majnemer Date: Sat, 11 Oct 2014 10:20:01 +0000 (+0000) Subject: InstCombine, InstSimplify: (%X /s C1) /s C2 isn't always 0 when C1 * C2 overflow X-Git-Tag: android-x86-7.1-r4~56584 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=9043f74acb70f48b6bb7717cf0e1b39ac259ac1b;p=android-x86%2Fexternal-llvm.git InstCombine, InstSimplify: (%X /s C1) /s C2 isn't always 0 when C1 * C2 overflow consider: C1 = INT_MIN C2 = -1 C1 * C2 overflows without a doubt but consider the following: %x = i32 INT_MIN This means that (%X /s C1) is 1 and (%X /s C1) /s C2 is -1. N. B. Move the unsigned version of this transform to InstSimplify, it doesn't create any new instructions. This fixes PR21243. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@219567 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Analysis/InstructionSimplify.cpp b/lib/Analysis/InstructionSimplify.cpp index f2f67067d15..a01bac2077f 100644 --- a/lib/Analysis/InstructionSimplify.cpp +++ b/lib/Analysis/InstructionSimplify.cpp @@ -1057,6 +1057,16 @@ static Value *SimplifyDiv(Instruction::BinaryOps Opcode, Value *Op0, Value *Op1, (!isSigned && match(Op0, m_URem(m_Value(), m_Specific(Op1))))) return Constant::getNullValue(Op0->getType()); + // (X /u C1) /u C2 -> 0 if C1 * C2 overflow + ConstantInt *C1, *C2; + if (!isSigned && match(Op0, m_UDiv(m_Value(X), m_ConstantInt(C1))) && + match(Op1, m_ConstantInt(C2))) { + bool Overflow; + C1->getValue().umul_ov(C2->getValue(), Overflow); + if (Overflow) + return Constant::getNullValue(Op0->getType()); + } + // If the operation is with the result of a select instruction, check whether // operating on either branch of the select always yields the same value. if (isa(Op0) || isa(Op1)) diff --git a/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp index 249456fa6ea..8d004f2a0a2 100644 --- a/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ b/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -727,11 +727,10 @@ Instruction *InstCombiner::commonIDivTransforms(BinaryOperator &I) { // (X / C1) / C2 -> X / (C1*C2) if (Instruction::BinaryOps(LHS->getOpcode()) == I.getOpcode()) if (ConstantInt *LHSRHS = dyn_cast(LHS->getOperand(1))) { - if (MultiplyOverflows(RHS, LHSRHS, - I.getOpcode() == Instruction::SDiv)) - return ReplaceInstUsesWith(I, Constant::getNullValue(I.getType())); - return BinaryOperator::Create(I.getOpcode(), LHS->getOperand(0), - ConstantExpr::getMul(RHS, LHSRHS)); + if (!MultiplyOverflows(RHS, LHSRHS, + I.getOpcode() == Instruction::SDiv)) + return BinaryOperator::Create(I.getOpcode(), LHS->getOperand(0), + ConstantExpr::getMul(RHS, LHSRHS)); } Value *X; diff --git a/test/Transforms/InstCombine/2008-02-16-SDivOverflow.ll b/test/Transforms/InstCombine/2008-02-16-SDivOverflow.ll deleted file mode 100644 index 917d3d9436b..00000000000 --- a/test/Transforms/InstCombine/2008-02-16-SDivOverflow.ll +++ /dev/null @@ -1,14 +0,0 @@ -; RUN: opt < %s -instcombine -S | grep "ret i.* 0" | count 2 -; PR2048 - -define i32 @i(i32 %a) { - %tmp1 = sdiv i32 %a, -1431655765 - %tmp2 = sdiv i32 %tmp1, 3 - ret i32 %tmp2 -} - -define i8 @j(i8 %a) { - %tmp1 = sdiv i8 %a, 64 - %tmp2 = sdiv i8 %tmp1, 3 - ret i8 %tmp2 -} diff --git a/test/Transforms/InstSimplify/exact-nsw-nuw.ll b/test/Transforms/InstSimplify/exact-nsw-nuw.ll index a0e326b13c0..5ccc8083e64 100644 --- a/test/Transforms/InstSimplify/exact-nsw-nuw.ll +++ b/test/Transforms/InstSimplify/exact-nsw-nuw.ll @@ -42,3 +42,19 @@ define i32 @shift5(i32 %A, i32 %B) { %D = ashr i32 %C, %B ret i32 %D } + +; CHECK-LABEL: @div1( +; CHECK: ret i32 0 +define i32 @div1(i32 %V) { + %A = udiv i32 %V, -2147483648 + %B = udiv i32 %A, -2147483648 + ret i32 %B +} + +; CHECK-LABEL: @div2( +; CHECK-NOT: ret i32 0 +define i32 @div2(i32 %V) { + %A = sdiv i32 %V, -1 + %B = sdiv i32 %A, -2147483648 + ret i32 %B +}