[llvm-commits] CVS: llvm/lib/Target/X86/X86ISelPattern.cpp

Chris Lattner lattner at cs.uiuc.edu
Sun Jan 16 22:27:11 PST 2005



Changes in directory llvm/lib/Target/X86:

X86ISelPattern.cpp updated: 1.60 -> 1.61
---
Log message:

Fix test/Regression/CodeGen/X86/2005-01-17-CycleInDAG.ll and 132.ijpeg.
Do not fold a load into an operation if it will induce a cycle in the DAG.

Repeat after me: dAg.



---
Diffs of the changes:  (+62 -17)

Index: llvm/lib/Target/X86/X86ISelPattern.cpp
diff -u llvm/lib/Target/X86/X86ISelPattern.cpp:1.60 llvm/lib/Target/X86/X86ISelPattern.cpp:1.61
--- llvm/lib/Target/X86/X86ISelPattern.cpp:1.60	Sun Jan 16 19:34:14 2005
+++ llvm/lib/Target/X86/X86ISelPattern.cpp	Mon Jan 17 00:26:58 2005
@@ -343,7 +343,7 @@
     /// SelectionDAGISel when it has created a SelectionDAG for us to codegen.
     virtual void InstructionSelectBasicBlock(SelectionDAG &DAG);
 
-    bool isFoldableLoad(SDOperand Op);
+    bool isFoldableLoad(SDOperand Op, SDOperand OtherOp);
     void EmitFoldedLoad(SDOperand Op, X86AddressMode &AM);
 
 
@@ -920,7 +920,7 @@
   unsigned Opc;
   if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(RHS)) {
     Opc = 0;
-    if (HasOneUse && isFoldableLoad(LHS)) {
+    if (HasOneUse && isFoldableLoad(LHS, RHS)) {
       switch (RHS.getValueType()) {
       default: break;
       case MVT::i1:
@@ -959,7 +959,7 @@
   }
 
   Opc = 0;
-  if (HasOneUse && isFoldableLoad(LHS)) {
+  if (HasOneUse && isFoldableLoad(LHS, RHS)) {
     switch (RHS.getValueType()) {
     default: break;
     case MVT::i1:
@@ -996,9 +996,30 @@
   BuildMI(BB, Opc, 2).addReg(Tmp1).addReg(Tmp2);
 }
 
+/// NodeTransitivelyUsesValue - Return true if N or any of its uses uses Op.
+/// The DAG cannot have cycles in it, by definition, so the visited set is not
+/// needed to prevent infinite loops.  The DAG CAN, however, have unbounded
+/// reuse, so it prevents exponential cases.
+///
+static bool NodeTransitivelyUsesValue(SDOperand N, SDOperand Op,
+                                      std::set<SDNode*> &Visited) {
+  if (N == Op) return true;                        // Found it.
+  SDNode *Node = N.Val;
+  if (Node->getNumOperands() == 0) return false;   // Leaf?
+  if (!Visited.insert(Node).second) return false;  // Already visited?
+
+  // Recurse for the first N-1 operands.
+  for (unsigned i = 1, e = Node->getNumOperands(); i != e; ++i)
+    if (NodeTransitivelyUsesValue(Node->getOperand(i), Op, Visited))
+      return true;
+
+  // Tail recurse for the last operand.
+  return NodeTransitivelyUsesValue(Node->getOperand(0), Op, Visited);
+}
+
 /// isFoldableLoad - Return true if this is a load instruction that can safely
 /// be folded into an operation that uses it.
-bool ISel::isFoldableLoad(SDOperand Op) {
+bool ISel::isFoldableLoad(SDOperand Op, SDOperand OtherOp) {
   if (Op.getOpcode() != ISD::LOAD ||
       // FIXME: currently can't fold constant pool indexes.
       isa<ConstantPoolSDNode>(Op.getOperand(1)))
@@ -1011,10 +1032,22 @@
   assert(!LoweredTokens.count(Op.getValue(1)) &&
          "Token lowered but value not in map?");
 
-  // Finally, there can only be one use of its value.
-  return Op.Val->hasNUsesOfValue(1, 0);
+  // If there is not just one use of its value, we cannot fold.
+  if (!Op.Val->hasNUsesOfValue(1, 0)) return false;
+
+  // Finally, we cannot fold the load into the operation if this would induce a
+  // cycle into the resultant dag.  To check for this, see if OtherOp (the other
+  // operand of the operation we are folding the load into) can possible use the
+  // chain node defined by the load.
+  if (OtherOp.Val && !Op.Val->hasNUsesOfValue(0, 1)) { // Has uses of chain?
+    std::set<SDNode*> Visited;
+    if (NodeTransitivelyUsesValue(OtherOp, Op.getValue(1), Visited))
+      return false;
+  }
+  return true;
 }
 
+
 /// EmitFoldedLoad - Ensure that the arguments of the load are code generated,
 /// and compute the address being loaded into AM.
 void ISel::EmitFoldedLoad(SDOperand Op, X86AddressMode &AM) {
@@ -1136,7 +1169,7 @@
       return Result;
     }
 
-    if (isFoldableLoad(N.getOperand(0))) {
+    if (isFoldableLoad(N.getOperand(0), SDOperand())) {
       static const unsigned Opc[3] = {
         X86::MOVZX32rm8, X86::MOVZX32rm16, X86::MOVZX16rm8
       };
@@ -1163,7 +1196,7 @@
     assert(N.getOperand(0).getValueType() != MVT::i1 &&
            "Sign extend from bool not implemented!");
 
-   if (isFoldableLoad(N.getOperand(0))) {
+    if (isFoldableLoad(N.getOperand(0), SDOperand())) {
       static const unsigned Opc[3] = {
         X86::MOVSX32rm8, X86::MOVSX32rm16, X86::MOVSX16rm8
       };
@@ -1183,7 +1216,7 @@
   }
   case ISD::TRUNCATE:
     // Fold TRUNCATE (LOAD P) into a smaller load from P.
-    if (isFoldableLoad(N.getOperand(0))) {
+    if (isFoldableLoad(N.getOperand(0), SDOperand())) {
       switch (N.getValueType()) {
       default: assert(0 && "Unknown truncate!");
       case MVT::i1:
@@ -1442,10 +1475,13 @@
     Op0 = N.getOperand(0);
     Op1 = N.getOperand(1);
 
-    if (isFoldableLoad(Op0))
+    if (isFoldableLoad(Op0, Op1)) {
       std::swap(Op0, Op1);
+      goto FoldAdd;
+    }
 
-    if (isFoldableLoad(Op1)) {
+    if (isFoldableLoad(Op1, Op0)) {
+    FoldAdd:
       switch (N.getValueType()) {
       default: assert(0 && "Cannot add this type!");
       case MVT::i1:
@@ -1622,9 +1658,10 @@
       }
     }
 
-    if (isFoldableLoad(Op0))
+    if (isFoldableLoad(Op0, Op1))
       if (Node->getOpcode() != ISD::SUB) {
         std::swap(Op0, Op1);
+        goto FoldOps;
       } else {
         // Emit 'reverse' subract, with a memory operand.
         switch (N.getValueType()) {
@@ -1641,7 +1678,8 @@
         }
       }
 
-    if (isFoldableLoad(Op1)) {
+    if (isFoldableLoad(Op1, Op0)) {
+    FoldOps:
       switch (N.getValueType()) {
       default: assert(0 && "Cannot operate on this type!");
       case MVT::i1:
@@ -2433,16 +2471,17 @@
 
     // Check to see if this is a load/op/store combination.
     if (N.getOperand(1).Val->hasOneUse() &&
-        isFoldableLoad(N.getOperand(0).getValue(0)) &&
-        !MVT::isFloatingPoint(N.getOperand(0).getValue(0).getValueType())) {
+        N.getOperand(1).Val->getNumOperands() == 2 &&
+        !MVT::isFloatingPoint(N.getOperand(0).getValue(0).getValueType()) &&
+        isFoldableLoad(N.getOperand(0).getValue(0),
+                       N.getOperand(0).getValue(1))) {
       SDOperand TheLoad = N.getOperand(0).getValue(0);
       // Check to see if we are loading the same pointer that we're storing to.
       if (TheLoad.getOperand(1) == N.getOperand(2)) {
         // See if the stored value is a simple binary operator that uses the
         // load as one of its operands.
         SDOperand Op = N.getOperand(1);
-        if (Op.Val->getNumOperands() == 2 &&
-            (Op.getOperand(0) == TheLoad || Op.getOperand(1) == TheLoad)) {
+        if ((Op.getOperand(0) == TheLoad || Op.getOperand(1) == TheLoad)) {
           // Finally, check to see if this is one of the ops we can handle!
           static const unsigned ADDTAB[] = {
             X86::ADD8mi, X86::ADD16mi, X86::ADD32mi,
@@ -2480,6 +2519,12 @@
           const unsigned *TabPtr = 0;
           switch (Op.getOpcode()) {
           default: std::cerr << "CANNOT [mem] op= val: "; Op.Val->dump(); std::cerr << "\n"; break;
+          case ISD::MUL:
+          case ISD::SDIV:
+          case ISD::UDIV:
+          case ISD::SREM:
+          case ISD::UREM: break;
+
           case ISD::ADD: TabPtr = ADDTAB; break;
           case ISD::SUB: TabPtr = SUBTAB; break;
           case ISD::AND: TabPtr = ANDTAB; break;






More information about the llvm-commits mailing list