Instcombine was illegally transforming -X/C into X/-C when either X or C
overflowed on negation. This commit checks to make sure that neithe C nor X
overflows. This requires that the RHS of X (a subtract instruction) be a
constant integer.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@60275 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Transforms/Scalar/InstructionCombining.cpp b/lib/Transforms/Scalar/InstructionCombining.cpp
index 9214b6b..8461aa7 100644
--- a/lib/Transforms/Scalar/InstructionCombining.cpp
+++ b/lib/Transforms/Scalar/InstructionCombining.cpp
@@ -2956,9 +2956,26 @@
if (RHS->isAllOnesValue())
return BinaryOperator::CreateNeg(Op0);
- // -X/C -> X/-C
- if (Value *LHSNeg = dyn_castNegVal(Op0))
- return BinaryOperator::CreateSDiv(LHSNeg, ConstantExpr::getNeg(RHS));
+ ConstantInt *RHSNeg = cast<ConstantInt>(ConstantExpr::getNeg(RHS));
+
+ // -X/C -> X/-C, if and only if negation doesn't overflow.
+ if ((RHS->getSExtValue() < 0 &&
+ RHS->getSExtValue() < RHSNeg->getSExtValue()) ||
+ (RHS->getSExtValue() > 0 &&
+ RHS->getSExtValue() > RHSNeg->getSExtValue())) {
+ if (Value *LHSNeg = dyn_castNegVal(Op0)) {
+ if (ConstantInt *CI = dyn_cast<ConstantInt>(LHSNeg)) {
+ ConstantInt *CINeg = cast<ConstantInt>(ConstantExpr::getNeg(CI));
+
+ if ((CI->getSExtValue() < 0 &&
+ CI->getSExtValue() < CINeg->getSExtValue()) ||
+ (CI->getSExtValue() > 0 &&
+ CI->getSExtValue() > CINeg->getSExtValue()))
+ return BinaryOperator::CreateSDiv(LHSNeg,
+ ConstantExpr::getNeg(RHS));
+ }
+ }
+ }
}
// If the sign bits of both operands are zero (i.e. we can prove they are