[llvm-commits] CVS: llvm/lib/Transforms/Scalar/InstructionCombining.cpp
Chris Lattner
sabre at nondot.org
Thu Jun 21 11:11:42 PDT 2007
Changes in directory llvm/lib/Transforms/Scalar:
InstructionCombining.cpp updated: 1.774 -> 1.775
---
Log message:
Significantly improve the documentation of the instcombine divide/compare
transformation. Also, keep track of which end of the integer interval overflows
occur on. This fixes Transforms/InstCombine/2007-06-21-DivCompareMiscomp.ll
and rdar://5278853, a miscompilation of perl.
---
Diffs of the changes: (+50 -34)
InstructionCombining.cpp | 84 +++++++++++++++++++++++++++--------------------
1 files changed, 50 insertions(+), 34 deletions(-)
Index: llvm/lib/Transforms/Scalar/InstructionCombining.cpp
diff -u llvm/lib/Transforms/Scalar/InstructionCombining.cpp:1.774 llvm/lib/Transforms/Scalar/InstructionCombining.cpp:1.775
--- llvm/lib/Transforms/Scalar/InstructionCombining.cpp:1.774 Wed Jun 20 18:46:26 2007
+++ llvm/lib/Transforms/Scalar/InstructionCombining.cpp Thu Jun 21 13:11:19 2007
@@ -5131,12 +5131,7 @@
if (!ICI.isEquality() && DivIsSigned != ICI.isSignedPredicate())
return 0;
if (DivRHS->isZero())
- return 0; // Don't hack on div by zero
-
- // Initialize the variables that will indicate the nature of the
- // range check.
- bool LoOverflow = false, HiOverflow = false;
- ConstantInt *LoBound = 0, *HiBound = 0;
+ return 0; // The ProdOV computation fails on divide by zero.
// Compute Prod = CI * DivRHS. We are essentially solving an equation
// of form X/C1=C2. We solve for X by multiplying C1 (DivRHS) and
@@ -5151,87 +5146,108 @@
ConstantExpr::getUDiv(Prod, DivRHS)) != CmpRHS;
// Get the ICmp opcode
- ICmpInst::Predicate predicate = ICI.getPredicate();
+ ICmpInst::Predicate Pred = ICI.getPredicate();
+ // Figure out the interval that is being checked. For example, a comparison
+ // like "X /u 5 == 0" is really checking that X is in the interval [0, 5).
+ // Compute this interval based on the constants involved and the signedness of
+ // the compare/divide. This computes a half-open interval, keeping track of
+ // whether either value in the interval overflows. After analysis each
+ // overflow variable is set to 0 if it's corresponding bound variable is valid
+ // -1 if overflowed off the bottom end, or +1 if overflowed off the top end.
+ int LoOverflow = 0, HiOverflow = 0;
+ ConstantInt *LoBound = 0, *HiBound = 0;
+
+
if (!DivIsSigned) { // udiv
+ // e.g. X/5 op 3 --> [15, 20)
LoBound = Prod;
- LoOverflow = ProdOV;
- HiOverflow = ProdOV || AddWithOverflow(HiBound, LoBound, DivRHS, false);
+ HiOverflow = LoOverflow = ProdOV;
+ if (!HiOverflow)
+ HiOverflow = AddWithOverflow(HiBound, LoBound, DivRHS, false);
} else if (DivRHS->getValue().isPositive()) { // Divisor is > 0.
if (CmpRHSV == 0) { // (X / pos) op 0
- // Can't overflow.
+ // Can't overflow. e.g. X/2 op 0 --> [-1, 2)
LoBound = cast<ConstantInt>(ConstantExpr::getNeg(SubOne(DivRHS)));
HiBound = DivRHS;
} else if (CmpRHSV.isPositive()) { // (X / pos) op pos
- LoBound = Prod;
- LoOverflow = ProdOV;
- HiOverflow = ProdOV || AddWithOverflow(HiBound, Prod, DivRHS, true);
+ LoBound = Prod; // e.g. X/5 op 3 --> [15, 20)
+ HiOverflow = LoOverflow = ProdOV;
+ if (!HiOverflow)
+ HiOverflow = AddWithOverflow(HiBound, Prod, DivRHS, true);
} else { // (X / pos) op neg
+ // e.g. X/5 op -3 --> [-15-4, -15+1) --> [-19, -14)
Constant *DivRHSH = ConstantExpr::getNeg(SubOne(DivRHS));
LoOverflow = AddWithOverflow(LoBound, Prod,
- cast<ConstantInt>(DivRHSH), true);
+ cast<ConstantInt>(DivRHSH), true) ? -1 : 0;
HiBound = AddOne(Prod);
- HiOverflow = ProdOV;
+ HiOverflow = ProdOV ? -1 : 0;
}
} else { // Divisor is < 0.
if (CmpRHSV == 0) { // (X / neg) op 0
+ // e.g. X/-5 op 0 --> [-4, 5)
LoBound = AddOne(DivRHS);
HiBound = cast<ConstantInt>(ConstantExpr::getNeg(DivRHS));
- if (HiBound == DivRHS)
- return 0; // - INTMIN = INTMIN
+ if (HiBound == DivRHS) { // -INTMIN = INTMIN
+ HiOverflow = 1; // [INTMIN+1, overflow)
+ HiBound = 0; // e.g. X/INTMIN = 0 --> X > INTMIN
+ }
} else if (CmpRHSV.isPositive()) { // (X / neg) op pos
- HiOverflow = LoOverflow = ProdOV;
+ // e.g. X/-5 op 3 --> [-19, -14)
+ HiOverflow = LoOverflow = ProdOV ? -1 : 0;
if (!LoOverflow)
- LoOverflow = AddWithOverflow(LoBound, Prod, AddOne(DivRHS),
- true);
+ LoOverflow = AddWithOverflow(LoBound, Prod, AddOne(DivRHS), true) ?-1:0;
HiBound = AddOne(Prod);
} else { // (X / neg) op neg
+ // e.g. X/-5 op -3 --> [15, 20)
LoBound = Prod;
- LoOverflow = HiOverflow = ProdOV;
+ LoOverflow = HiOverflow = ProdOV ? 1 : 0;
HiBound = Subtract(Prod, DivRHS);
}
- // Dividing by a negate swaps the condition.
- predicate = ICmpInst::getSwappedPredicate(predicate);
+ // Dividing by a negative swaps the condition. LT <-> GT
+ Pred = ICmpInst::getSwappedPredicate(Pred);
}
Value *X = DivI->getOperand(0);
- switch (predicate) {
+ switch (Pred) {
default: assert(0 && "Unhandled icmp opcode!");
case ICmpInst::ICMP_EQ:
if (LoOverflow && HiOverflow)
return ReplaceInstUsesWith(ICI, ConstantInt::getFalse());
else if (HiOverflow)
- return new ICmpInst(DivIsSigned ? ICmpInst::ICMP_SGE :
+ return new ICmpInst(DivIsSigned ? ICmpInst::ICMP_SGE :
ICmpInst::ICMP_UGE, X, LoBound);
else if (LoOverflow)
return new ICmpInst(DivIsSigned ? ICmpInst::ICMP_SLT :
ICmpInst::ICMP_ULT, X, HiBound);
else
- return InsertRangeTest(X, LoBound, HiBound, DivIsSigned,
- true, ICI);
+ return InsertRangeTest(X, LoBound, HiBound, DivIsSigned, true, ICI);
case ICmpInst::ICMP_NE:
if (LoOverflow && HiOverflow)
return ReplaceInstUsesWith(ICI, ConstantInt::getTrue());
else if (HiOverflow)
- return new ICmpInst(DivIsSigned ? ICmpInst::ICMP_SLT :
+ return new ICmpInst(DivIsSigned ? ICmpInst::ICMP_SLT :
ICmpInst::ICMP_ULT, X, LoBound);
else if (LoOverflow)
return new ICmpInst(DivIsSigned ? ICmpInst::ICMP_SGE :
ICmpInst::ICMP_UGE, X, HiBound);
else
- return InsertRangeTest(X, LoBound, HiBound, DivIsSigned,
- false, ICI);
+ return InsertRangeTest(X, LoBound, HiBound, DivIsSigned, false, ICI);
case ICmpInst::ICMP_ULT:
case ICmpInst::ICMP_SLT:
- if (LoOverflow)
+ if (LoOverflow == +1) // Low bound is greater than input range.
+ return ReplaceInstUsesWith(ICI, ConstantInt::getTrue());
+ if (LoOverflow == -1) // Low bound is less than input range.
return ReplaceInstUsesWith(ICI, ConstantInt::getFalse());
- return new ICmpInst(predicate, X, LoBound);
+ return new ICmpInst(Pred, X, LoBound);
case ICmpInst::ICMP_UGT:
case ICmpInst::ICMP_SGT:
- if (HiOverflow)
+ if (HiOverflow == +1) // High bound greater than input range.
return ReplaceInstUsesWith(ICI, ConstantInt::getFalse());
- if (predicate == ICmpInst::ICMP_UGT)
+ else if (HiOverflow == -1) // High bound less than input range.
+ return ReplaceInstUsesWith(ICI, ConstantInt::getTrue());
+ if (Pred == ICmpInst::ICMP_UGT)
return new ICmpInst(ICmpInst::ICMP_UGE, X, HiBound);
else
return new ICmpInst(ICmpInst::ICMP_SGE, X, HiBound);
More information about the llvm-commits
mailing list