[llvm-commits] CVS: llvm/lib/Transforms/Scalar/InstructionCombining.cpp

Chris Lattner lattner at cs.uiuc.edu
Wed Sep 29 10:40:23 PDT 2004



Changes in directory llvm/lib/Transforms/Scalar:

InstructionCombining.cpp updated: 1.258 -> 1.259
---
Log message:

* Pull range optimization code out into new InsertRangeTest function.
* SubOne/AddOne functions always return ConstantInt, declare them as such
* Pull code for handling setcc X, cst, where cst is at the end of the range,
  or cc is LE or GE up earlier in visitSetCondInst.  This reduces #iterations
  in some cases.
* Fold: (div X, C1) op C2 -> range check, implementing div.ll:test6 - test9.



---
Diffs of the changes:  (+220 -81)

Index: llvm/lib/Transforms/Scalar/InstructionCombining.cpp
diff -u llvm/lib/Transforms/Scalar/InstructionCombining.cpp:1.258 llvm/lib/Transforms/Scalar/InstructionCombining.cpp:1.259
--- llvm/lib/Transforms/Scalar/InstructionCombining.cpp:1.258	Wed Sep 29 00:07:12 2004
+++ llvm/lib/Transforms/Scalar/InstructionCombining.cpp	Wed Sep 29 12:40:11 2004
@@ -209,6 +209,9 @@
 
     Instruction *OptAndOp(Instruction *Op, ConstantIntegral *OpRHS,
                           ConstantIntegral *AndRHS, BinaryOperator &TheAnd);
+
+    Instruction *InsertRangeTest(Value *V, Constant *Lo, Constant *Hi,
+                                 bool Inside, Instruction &IB);
   };
 
   RegisterOpt<InstCombiner> X("instcombine", "Combine redundant instructions");
@@ -341,11 +344,13 @@
 }
 
 // AddOne, SubOne - Add or subtract a constant one from an integer constant...
-static Constant *AddOne(ConstantInt *C) {
-  return ConstantExpr::getAdd(C, ConstantInt::get(C->getType(), 1));
-}
-static Constant *SubOne(ConstantInt *C) {
-  return ConstantExpr::getSub(C, ConstantInt::get(C->getType(), 1));
+static ConstantInt *AddOne(ConstantInt *C) {
+  return cast<ConstantInt>(ConstantExpr::getAdd(C,
+                                         ConstantInt::get(C->getType(), 1)));
+}
+static ConstantInt *SubOne(ConstantInt *C) {
+  return cast<ConstantInt>(ConstantExpr::getSub(C,
+                                         ConstantInt::get(C->getType(), 1)));
 }
 
 // isTrueWhenEqual - Return true if the specified setcondinst instruction is
@@ -1241,6 +1246,51 @@
 }
 
 
+/// InsertRangeTest - Emit a computation of: (V >= Lo && V < Hi) if Inside is
+/// true, otherwise (V < Lo || V >= Hi).  In pratice, we emit the more efficient
+/// (V-Lo) <u Hi-Lo.  This method expects that Lo <= Hi.  IB is the location to
+/// insert new instructions.
+Instruction *InstCombiner::InsertRangeTest(Value *V, Constant *Lo, Constant *Hi,
+                                           bool Inside, Instruction &IB) {
+  assert(cast<ConstantBool>(ConstantExpr::getSetLE(Lo, Hi))->getValue() &&
+         "Lo is not <= Hi in range emission code!");
+  if (Inside) {
+    if (Lo == Hi)  // Trivially false.
+      return new SetCondInst(Instruction::SetNE, V, V);
+    if (cast<ConstantIntegral>(Lo)->isMinValue())
+      return new SetCondInst(Instruction::SetLT, V, Hi);
+    
+    Constant *AddCST = ConstantExpr::getNeg(Lo);
+    Instruction *Add = BinaryOperator::createAdd(V, AddCST,V->getName()+".off");
+    InsertNewInstBefore(Add, IB);
+    // Convert to unsigned for the comparison.
+    const Type *UnsType = Add->getType()->getUnsignedVersion();
+    Value *OffsetVal = InsertCastBefore(Add, UnsType, IB);
+    AddCST = ConstantExpr::getAdd(AddCST, Hi);
+    AddCST = ConstantExpr::getCast(AddCST, UnsType);
+    return new SetCondInst(Instruction::SetLT, OffsetVal, AddCST);
+  }
+
+  if (Lo == Hi)  // Trivially true.
+    return new SetCondInst(Instruction::SetEQ, V, V);
+
+  Hi = SubOne(cast<ConstantInt>(Hi));
+  if (cast<ConstantIntegral>(Lo)->isMinValue()) // V < 0 || V >= Hi ->'V > Hi-1'
+    return new SetCondInst(Instruction::SetGT, V, Hi);
+
+  // Emit X-Lo > Hi-Lo-1
+  Constant *AddCST = ConstantExpr::getNeg(Lo);
+  Instruction *Add = BinaryOperator::createAdd(V, AddCST, V->getName()+".off");
+  InsertNewInstBefore(Add, IB);
+  // Convert to unsigned for the comparison.
+  const Type *UnsType = Add->getType()->getUnsignedVersion();
+  Value *OffsetVal = InsertCastBefore(Add, UnsType, IB);
+  AddCST = ConstantExpr::getAdd(AddCST, Hi);
+  AddCST = ConstantExpr::getCast(AddCST, UnsType);
+  return new SetCondInst(Instruction::SetGT, OffsetVal, AddCST);
+}
+
+
 Instruction *InstCombiner::visitAnd(BinaryOperator &I) {
   bool Changed = SimplifyCommutative(I);
   Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
@@ -1375,19 +1425,8 @@
               if (RHSCst == AddOne(LHSCst)) // (X > 13 & X != 14) -> X > 14
                 return new SetCondInst(Instruction::SetGT, LHSVal, RHSCst);
               break;                        // (X > 13 & X != 15) -> no change
-            case Instruction::SetLT: { // (X > 13 & X < 15) -> (X-14) <u 1
-              Constant *AddCST = ConstantExpr::getNeg(AddOne(LHSCst));
-              Instruction *Add = BinaryOperator::createAdd(LHSVal, AddCST,
-                                                      LHSVal->getName()+".off");
-              InsertNewInstBefore(Add, I);
-              // Convert to unsigned for the comparison.
-              const Type *UnsType = Add->getType()->getUnsignedVersion();
-              Value *OffsetVal = InsertCastBefore(Add, UnsType, I);
-              AddCST = ConstantExpr::getAdd(AddCST, RHSCst);
-              AddCST = ConstantExpr::getCast(AddCST, UnsType);
-              return new SetCondInst(Instruction::SetLT, OffsetVal, AddCST);
-            }
-            break;
+            case Instruction::SetLT:   // (X > 13 & X < 15) -> (X-14) <u 1
+              return InsertRangeTest(LHSVal, AddOne(LHSCst), RHSCst, true, I);
             }
           }
         }
@@ -1396,8 +1435,6 @@
   return Changed ? &I : 0;
 }
 
-
-
 Instruction *InstCombiner::visitOr(BinaryOperator &I) {
   bool Changed = SimplifyCommutative(I);
   Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
@@ -1541,18 +1578,8 @@
             default: assert(0 && "Unknown integer condition code!");
             case Instruction::SetEQ:  // (X < 13 | X == 14) -> no change
               break;
-            case Instruction::SetGT: {// (X < 13 | X > 15)  -> (X-13) > 2
-              Constant *AddCST = ConstantExpr::getNeg(LHSCst);
-              Instruction *Add = BinaryOperator::createAdd(LHSVal, AddCST,
-                                                      LHSVal->getName()+".off");
-              InsertNewInstBefore(Add, I);
-              // Convert to unsigned for the comparison.
-              const Type *UnsType = Add->getType()->getUnsignedVersion();
-              Value *OffsetVal = InsertCastBefore(Add, UnsType, I);
-              AddCST = ConstantExpr::getAdd(AddCST, RHSCst);
-              AddCST = ConstantExpr::getCast(AddCST, UnsType);
-              return new SetCondInst(Instruction::SetGT, OffsetVal, AddCST);
-            }
+            case Instruction::SetGT:  // (X < 13 | X > 15)  -> (X-13) > 2
+              return InsertRangeTest(LHSVal, LHSCst, AddOne(RHSCst), false, I);
             case Instruction::SetNE:  // (X < 13 | X != 15) -> X != 15
             case Instruction::SetLT:  // (X < 13 | X < 15) -> X < 15
               return ReplaceInstUsesWith(I, RHS);
@@ -1721,6 +1748,36 @@
   return Changed ? &I : 0;
 }
 
+/// MulWithOverflow - Compute Result = In1*In2, returning true if the result
+/// overflowed for this type.
+static bool MulWithOverflow(ConstantInt *&Result, ConstantInt *In1,
+                            ConstantInt *In2) {
+  Result = cast<ConstantInt>(ConstantExpr::getMul(In1, In2));
+  return !In2->isNullValue() && ConstantExpr::getDiv(Result, In2) != In1;
+}
+
+static bool isPositive(ConstantInt *C) {
+  return cast<ConstantSInt>(C)->getValue() >= 0;
+}
+
+/// AddWithOverflow - Compute Result = In1+In2, returning true if the result
+/// overflowed for this type.
+static bool AddWithOverflow(ConstantInt *&Result, ConstantInt *In1,
+                            ConstantInt *In2) {
+  Result = cast<ConstantInt>(ConstantExpr::getAdd(In1, In2));
+
+  if (In1->getType()->isUnsigned())
+    return cast<ConstantUInt>(Result)->getValue() <
+           cast<ConstantUInt>(In1)->getValue();
+  if (isPositive(In1) != isPositive(In2))
+    return false;
+  if (isPositive(In1))
+    return cast<ConstantSInt>(Result)->getValue() <
+           cast<ConstantSInt>(In1)->getValue();
+  return cast<ConstantSInt>(Result)->getValue() >
+         cast<ConstantSInt>(In1)->getValue();
+}
+
 Instruction *InstCombiner::visitSetCondInst(BinaryOperator &I) {
   bool Changed = SimplifyCommutative(I);
   Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
@@ -1770,6 +1827,50 @@
   // See if we are doing a comparison between a constant and an instruction that
   // can be folded into the comparison.
   if (ConstantInt *CI = dyn_cast<ConstantInt>(Op1)) {
+    // Check to see if we are comparing against the minimum or maximum value...
+    if (CI->isMinValue()) {
+      if (I.getOpcode() == Instruction::SetLT)       // A < MIN -> FALSE
+        return ReplaceInstUsesWith(I, ConstantBool::False);
+      if (I.getOpcode() == Instruction::SetGE)       // A >= MIN -> TRUE
+        return ReplaceInstUsesWith(I, ConstantBool::True);
+      if (I.getOpcode() == Instruction::SetLE)       // A <= MIN -> A == MIN
+        return BinaryOperator::createSetEQ(Op0, Op1);
+      if (I.getOpcode() == Instruction::SetGT)       // A > MIN -> A != MIN
+        return BinaryOperator::createSetNE(Op0, Op1);
+
+    } else if (CI->isMaxValue()) {
+      if (I.getOpcode() == Instruction::SetGT)       // A > MAX -> FALSE
+        return ReplaceInstUsesWith(I, ConstantBool::False);
+      if (I.getOpcode() == Instruction::SetLE)       // A <= MAX -> TRUE
+        return ReplaceInstUsesWith(I, ConstantBool::True);
+      if (I.getOpcode() == Instruction::SetGE)       // A >= MAX -> A == MAX
+        return BinaryOperator::createSetEQ(Op0, Op1);
+      if (I.getOpcode() == Instruction::SetLT)       // A < MAX -> A != MAX
+        return BinaryOperator::createSetNE(Op0, Op1);
+
+      // Comparing against a value really close to min or max?
+    } else if (isMinValuePlusOne(CI)) {
+      if (I.getOpcode() == Instruction::SetLT)       // A < MIN+1 -> A == MIN
+        return BinaryOperator::createSetEQ(Op0, SubOne(CI));
+      if (I.getOpcode() == Instruction::SetGE)       // A >= MIN-1 -> A != MIN
+        return BinaryOperator::createSetNE(Op0, SubOne(CI));
+
+    } else if (isMaxValueMinusOne(CI)) {
+      if (I.getOpcode() == Instruction::SetGT)       // A > MAX-1 -> A == MAX
+        return BinaryOperator::createSetEQ(Op0, AddOne(CI));
+      if (I.getOpcode() == Instruction::SetLE)       // A <= MAX-1 -> A != MAX
+        return BinaryOperator::createSetNE(Op0, AddOne(CI));
+    }
+
+    // If we still have a setle or setge instruction, turn it into the
+    // appropriate setlt or setgt instruction.  Since the border cases have
+    // already been handled above, this requires little checking.
+    //
+    if (I.getOpcode() == Instruction::SetLE)
+      return BinaryOperator::createSetLT(Op0, AddOne(CI));
+    if (I.getOpcode() == Instruction::SetGE)
+      return BinaryOperator::createSetGT(Op0, SubOne(CI));
+
     if (Instruction *LHSI = dyn_cast<Instruction>(Op0))
       switch (LHSI->getOpcode()) {
       case Instruction::PHI:
@@ -1864,12 +1965,8 @@
                 return ReplaceInstUsesWith(I, ConstantBool::True);
               case Instruction::SetLT:
                 return ReplaceInstUsesWith(I, ConstantExpr::getSetLT(Max, CI));
-              case Instruction::SetLE:
-                return ReplaceInstUsesWith(I, ConstantExpr::getSetLE(Max, CI));
               case Instruction::SetGT:
                 return ReplaceInstUsesWith(I, ConstantExpr::getSetGT(Min, CI));
-              case Instruction::SetGE:
-                return ReplaceInstUsesWith(I, ConstantExpr::getSetGE(Min, CI));
               }
             }
 
@@ -1968,6 +2065,92 @@
         }
         break;
 
+      case Instruction::Div:
+        // Fold: (div X, C1) op C2 -> range check
+        if (ConstantInt *DivRHS = dyn_cast<ConstantInt>(LHSI->getOperand(1))) {
+          // Fold this div into the comparison, producing a range check.
+          // Determine, based on the divide type, what the range is being
+          // checked.  If there is an overflow on the low or high side, remember
+          // it, otherwise compute the range [low, hi) bounding the new value.
+          bool LoOverflow = false, HiOverflow = 0;
+          ConstantInt *LoBound = 0, *HiBound = 0;
+
+          ConstantInt *Prod;
+          bool ProdOV = MulWithOverflow(Prod, CI, DivRHS);
+
+          if (DivRHS->isNullValue()) {  // Don't hack on divide by zeros.
+          } else if (LHSI->getType()->isUnsigned()) {  // udiv
+            LoBound = Prod;
+            LoOverflow = ProdOV;
+            HiOverflow = ProdOV || AddWithOverflow(HiBound, LoBound, DivRHS);
+          } else if (isPositive(DivRHS)) {             // Divisor is > 0.
+            if (CI->isNullValue()) {       // (X / pos) op 0
+              // Can't overflow.
+              LoBound = cast<ConstantInt>(ConstantExpr::getNeg(SubOne(DivRHS)));
+              HiBound = DivRHS;
+            } else if (isPositive(CI)) {   // (X / pos) op pos
+              LoBound = Prod;
+              LoOverflow = ProdOV;
+              HiOverflow = ProdOV || AddWithOverflow(HiBound, Prod, DivRHS);
+            } else {                       // (X / pos) op neg
+              Constant *DivRHSH = ConstantExpr::getNeg(SubOne(DivRHS));
+              LoOverflow = AddWithOverflow(LoBound, Prod,
+                                           cast<ConstantInt>(DivRHSH));
+              HiBound = Prod;
+              HiOverflow = ProdOV;
+            }
+          } else {                                     // Divisor is < 0.
+            if (CI->isNullValue()) {       // (X / neg) op 0
+              LoBound = AddOne(DivRHS);
+              HiBound = cast<ConstantInt>(ConstantExpr::getNeg(DivRHS));
+            } else if (isPositive(CI)) {   // (X / neg) op pos
+              HiOverflow = LoOverflow = ProdOV;
+              if (!LoOverflow)
+                LoOverflow = AddWithOverflow(LoBound, Prod, AddOne(DivRHS));
+              HiBound = AddOne(Prod);
+            } else {                       // (X / neg) op neg
+              LoBound = Prod;
+              LoOverflow = HiOverflow = ProdOV;
+              HiBound = cast<ConstantInt>(ConstantExpr::getSub(Prod, DivRHS));
+            }
+          }
+
+          if (LoBound) {
+            Value *X = LHSI->getOperand(0);
+            std::cerr << "DIV FOLD: " << *LHSI;
+            std::cerr << "DIV FOLD: " << I << "\n";
+            switch (I.getOpcode()) {
+            default: assert(0 && "Unhandled setcc opcode!");
+            case Instruction::SetEQ:
+              if (LoOverflow && HiOverflow)
+                return ReplaceInstUsesWith(I, ConstantBool::False);
+              else if (HiOverflow)
+                return new SetCondInst(Instruction::SetGE, X, LoBound);
+              else if (LoOverflow)
+                return new SetCondInst(Instruction::SetLT, X, HiBound);
+              else
+                return InsertRangeTest(X, LoBound, HiBound, true, I);
+            case Instruction::SetNE:
+              if (LoOverflow && HiOverflow)
+                return ReplaceInstUsesWith(I, ConstantBool::True);
+              else if (HiOverflow)
+                return new SetCondInst(Instruction::SetLT, X, LoBound);
+              else if (LoOverflow)
+                return new SetCondInst(Instruction::SetGE, X, HiBound);
+              else
+                return InsertRangeTest(X, LoBound, HiBound, false, I);
+            case Instruction::SetLT:
+              if (LoOverflow)
+                return ReplaceInstUsesWith(I, ConstantBool::False);
+              return new SetCondInst(Instruction::SetLT, X, LoBound);
+            case Instruction::SetGT:
+              if (HiOverflow)
+                return ReplaceInstUsesWith(I, ConstantBool::False);
+              return new SetCondInst(Instruction::SetGE, X, HiBound);
+            }
+          }
+        }
+        break;
       case Instruction::Select:
         // If either operand of the select is a constant, we can fold the
         // comparison into the select arms, which will cause one to be
@@ -2157,50 +2340,6 @@
         }
       }
     }
-
-    // Check to see if we are comparing against the minimum or maximum value...
-    if (CI->isMinValue()) {
-      if (I.getOpcode() == Instruction::SetLT)       // A < MIN -> FALSE
-        return ReplaceInstUsesWith(I, ConstantBool::False);
-      if (I.getOpcode() == Instruction::SetGE)       // A >= MIN -> TRUE
-        return ReplaceInstUsesWith(I, ConstantBool::True);
-      if (I.getOpcode() == Instruction::SetLE)       // A <= MIN -> A == MIN
-        return BinaryOperator::createSetEQ(Op0, Op1);
-      if (I.getOpcode() == Instruction::SetGT)       // A > MIN -> A != MIN
-        return BinaryOperator::createSetNE(Op0, Op1);
-
-    } else if (CI->isMaxValue()) {
-      if (I.getOpcode() == Instruction::SetGT)       // A > MAX -> FALSE
-        return ReplaceInstUsesWith(I, ConstantBool::False);
-      if (I.getOpcode() == Instruction::SetLE)       // A <= MAX -> TRUE
-        return ReplaceInstUsesWith(I, ConstantBool::True);
-      if (I.getOpcode() == Instruction::SetGE)       // A >= MAX -> A == MAX
-        return BinaryOperator::createSetEQ(Op0, Op1);
-      if (I.getOpcode() == Instruction::SetLT)       // A < MAX -> A != MAX
-        return BinaryOperator::createSetNE(Op0, Op1);
-
-      // Comparing against a value really close to min or max?
-    } else if (isMinValuePlusOne(CI)) {
-      if (I.getOpcode() == Instruction::SetLT)       // A < MIN+1 -> A == MIN
-        return BinaryOperator::createSetEQ(Op0, SubOne(CI));
-      if (I.getOpcode() == Instruction::SetGE)       // A >= MIN-1 -> A != MIN
-        return BinaryOperator::createSetNE(Op0, SubOne(CI));
-
-    } else if (isMaxValueMinusOne(CI)) {
-      if (I.getOpcode() == Instruction::SetGT)       // A > MAX-1 -> A == MAX
-        return BinaryOperator::createSetEQ(Op0, AddOne(CI));
-      if (I.getOpcode() == Instruction::SetLE)       // A <= MAX-1 -> A != MAX
-        return BinaryOperator::createSetNE(Op0, AddOne(CI));
-    }
-
-    // If we still have a setle or setge instruction, turn it into the
-    // appropriate setlt or setgt instruction.  Since the border cases have
-    // already been handled above, this requires little checking.
-    //
-    if (I.getOpcode() == Instruction::SetLE)
-      return BinaryOperator::createSetLT(Op0, AddOne(CI));
-    if (I.getOpcode() == Instruction::SetGE)
-      return BinaryOperator::createSetGT(Op0, SubOne(CI));
   }
 
   // Test to see if the operands of the setcc are casted versions of other
@@ -2875,7 +3014,7 @@
             }
           }
         }
-    
+
     if (Instruction *FVI = dyn_cast<Instruction>(FalseVal))
       if (FVI->hasOneUse() && FVI->getNumOperands() == 2 &&
           !isa<Constant>(TrueVal))






More information about the llvm-commits mailing list