Fix SDNode::MorphNodeTo (a function used by by SelectNodeTo) to
authorDan Gohman <gohman@apple.com>
Mon, 7 Jul 2008 20:57:48 +0000 (20:57 +0000)
committerDan Gohman <gohman@apple.com>
Mon, 7 Jul 2008 20:57:48 +0000 (20:57 +0000)
properly track dead nodes that are on the original SDNode's operand
list but not the new one, and have no other uses.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@53201 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/CodeGen/SelectionDAG.h
include/llvm/CodeGen/SelectionDAGNodes.h
lib/CodeGen/SelectionDAG/SelectionDAG.cpp

index 6568d90951db5e2ed1ec1730c093758003e6fb13..56bd40ae5cec34df7bd6ba7c75b6c8fd36ace945 100644 (file)
@@ -537,6 +537,11 @@ public:
   /// for each node deleted.
   void RemoveDeadNode(SDNode *N, DAGUpdateListener *UpdateListener = 0);
   
+  /// RemoveDeadNodes - This method deletes the unreachable nodes in the
+  /// given list, and any nodes that become unreachable as a result.
+  void RemoveDeadNodes(SmallVectorImpl<SDNode *> &DeadNodes,
+                       DAGUpdateListener *UpdateListener = 0);
+
   /// ReplaceAllUsesWith - Modify anything using 'From' to use 'To' instead.
   /// This can cause recursive merging of nodes in the DAG.  Use the first
   /// version if 'From' is known to have a single result, use the second
index f5ab0707c407cd37852a671166d71fb6956968c7..fe1cab6fe6be2c885a4d61e539b7b5149dd8bcfa 100644 (file)
@@ -1315,12 +1315,18 @@ protected:
       ++Ops[i].getVal()->UsesSize;
     }
   }
+
+  /// DropOperands - Release the operands and set this node to have
+  /// zero operands.  This should only be used by HandleSDNode to clear
+  /// its operand list.
+  void DropOperands();
   
   /// MorphNodeTo - This frees the operands of the current node, resets the
   /// opcode, types, and operands to the specified value.  This should only be
   /// used by the SelectionDAG class.
   void MorphNodeTo(unsigned Opc, SDVTList L,
-                   const SDOperand *Ops, unsigned NumOps);
+                   const SDOperand *Ops, unsigned NumOps,
+                   SmallVectorImpl<SDNode *> &DeadNodes);
   
   void addUser(unsigned i, SDNode *User) {
     assert(User->OperandList[i].getUser() && "Node without parent");
index b9f84080ba89c65f806a04e6bb67402e9de920c4..3f262df713fada0eeb35520f61709852dd2382d1 100644 (file)
@@ -486,42 +486,16 @@ void SelectionDAG::RemoveDeadNodes() {
     if (I->use_empty())
       DeadNodes.push_back(I);
 
-  // Process the worklist, deleting the nodes and adding their uses to the
-  // worklist.
-  while (!DeadNodes.empty()) {
-    SDNode *N = DeadNodes.back();
-    DeadNodes.pop_back();
-    
-    // Take the node out of the appropriate CSE map.
-    RemoveNodeFromCSEMaps(N);
-
-    // Next, brutally remove the operand list.  This is safe to do, as there are
-    // no cycles in the graph.
-    for (SDNode::op_iterator I = N->op_begin(), E = N->op_end(); I != E; ++I) {
-      SDNode *Operand = I->getVal();
-      Operand->removeUser(std::distance(N->op_begin(), I), N);
-      
-      // Now that we removed this operand, see if there are no uses of it left.
-      if (Operand->use_empty())
-        DeadNodes.push_back(Operand);
-    }
-    if (N->OperandsNeedDelete) {
-      delete[] N->OperandList;
-    }
-    N->OperandList = 0;
-    N->NumOperands = 0;
-    
-    // Finally, remove N itself.
-    AllNodes.erase(N);
-  }
+  RemoveDeadNodes(DeadNodes);
   
   // If the root changed (e.g. it was a dead load, update the root).
   setRoot(Dummy.getValue());
 }
 
-void SelectionDAG::RemoveDeadNode(SDNode *N, DAGUpdateListener *UpdateListener){
-  SmallVector<SDNode*, 16> DeadNodes;
-  DeadNodes.push_back(N);
+/// RemoveDeadNodes - This method deletes the unreachable nodes in the
+/// given list, and any nodes that become unreachable as a result.
+void SelectionDAG::RemoveDeadNodes(SmallVectorImpl<SDNode *> &DeadNodes,
+                                   DAGUpdateListener *UpdateListener) {
 
   // Process the worklist, deleting the nodes and adding their uses to the
   // worklist.
@@ -537,16 +511,13 @@ void SelectionDAG::RemoveDeadNode(SDNode *N, DAGUpdateListener *UpdateListener){
 
     // Next, brutally remove the operand list.  This is safe to do, as there are
     // no cycles in the graph.
-    unsigned op_num = 0;
     for (SDNode::op_iterator I = N->op_begin(), E = N->op_end(); I != E; ++I) {
       SDNode *Operand = I->getVal();
-      Operand->removeUser(op_num, N);
+      Operand->removeUser(std::distance(N->op_begin(), I), N);
       
       // Now that we removed this operand, see if there are no uses of it left.
       if (Operand->use_empty())
         DeadNodes.push_back(Operand);
-      
-      op_num++;
     }
     if (N->OperandsNeedDelete) {
       delete[] N->OperandList;
@@ -559,6 +530,12 @@ void SelectionDAG::RemoveDeadNode(SDNode *N, DAGUpdateListener *UpdateListener){
   }
 }
 
+void SelectionDAG::RemoveDeadNode(SDNode *N, DAGUpdateListener *UpdateListener){
+  SmallVector<SDNode*, 16> DeadNodes;
+  DeadNodes.push_back(N);
+  RemoveDeadNodes(DeadNodes, UpdateListener);
+}
+
 void SelectionDAG::DeleteNode(SDNode *N) {
   assert(N->use_empty() && "Cannot delete a node that is not dead!");
 
@@ -3681,16 +3658,22 @@ UpdateNodeOperands(SDOperand InN, const SDOperand *Ops, unsigned NumOps) {
 /// opcode, types, and operands to the specified value.  This should only be
 /// used by the SelectionDAG class.
 void SDNode::MorphNodeTo(unsigned Opc, SDVTList L,
-                         const SDOperand *Ops, unsigned NumOps) {
+                         const SDOperand *Ops, unsigned NumOps,
+                         SmallVectorImpl<SDNode *> &DeadNodes) {
   NodeType = Opc;
   ValueList = L.VTs;
   NumValues = L.NumVTs;
   
   // Clear the operands list, updating used nodes to remove this from their
-  // use list.
-  for (op_iterator I = op_begin(), E = op_end(); I != E; ++I)
-    I->getVal()->removeUser(std::distance(op_begin(), I), this);
-  
+  // use list.  Keep track of any operands that become dead as a result.
+  SmallPtrSet<SDNode*, 16> DeadNodeSet;
+  for (op_iterator I = op_begin(), E = op_end(); I != E; ++I) {
+    SDNode *N = I->getVal();
+    N->removeUser(std::distance(op_begin(), I), this);
+    if (N->use_empty())
+      DeadNodeSet.insert(N);
+  }
+
   // If NumOps is larger than the # of operands we currently have, reallocate
   // the operand list.
   if (NumOps > NumOperands) {
@@ -3710,7 +3693,29 @@ void SDNode::MorphNodeTo(unsigned Opc, SDVTList L,
     SDNode *N = OperandList[i].getVal();
     N->addUser(i, this);
     ++N->UsesSize;
+    DeadNodeSet.erase(N);
   }
+
+  // Clean up any nodes that are still dead after adding the uses for the
+  // new operands.
+  for (SmallPtrSet<SDNode *, 16>::iterator I = DeadNodeSet.begin(),
+       E = DeadNodeSet.end(); I != E; ++I)
+    DeadNodes.push_back(*I);
+}
+
+/// DropOperands - Release the operands and set this node to have
+/// zero operands.  This should only be used by HandleSDNode to clear
+/// its operand list.
+void SDNode::DropOperands() {
+  assert(NodeType == ISD::HANDLENODE &&
+         "DropOperands is for HANDLENODE only!");
+
+  // Unlike the code in MorphNodeTo that does this, we don't need to
+  // watch for dead nodes here.
+  for (op_iterator I = op_begin(), E = op_end(); I != E; ++I)
+    I->getVal()->removeUser(std::distance(op_begin(), I), this);
+
+  NumOperands = 0;
 }
 
 /// SelectNodeTo - These are used for target selectors to *mutate* the
@@ -3814,7 +3819,10 @@ SDNode *SelectionDAG::SelectNodeTo(SDNode *N, unsigned TargetOpc,
 
   RemoveNodeFromCSEMaps(N);
 
-  N->MorphNodeTo(ISD::BUILTIN_OP_END+TargetOpc, VTs, Ops, NumOps);
+  SmallVector<SDNode *, 16> DeadNodes;
+  N->MorphNodeTo(ISD::BUILTIN_OP_END+TargetOpc, VTs, Ops, NumOps, DeadNodes);
+  RemoveDeadNodes(DeadNodes);
+
   CSEMap.InsertNode(N, IP);   // Memoize the new node.
   return N;
 }
@@ -4250,8 +4258,7 @@ void StoreSDNode::ANCHOR() {}
 void AtomicSDNode::ANCHOR() {}
 
 HandleSDNode::~HandleSDNode() {
-  SDVTList VTs = { 0, 0 };
-  MorphNodeTo(ISD::HANDLENODE, VTs, 0, 0);  // Drops operand uses.
+  DropOperands();
 }
 
 GlobalAddressSDNode::GlobalAddressSDNode(bool isTarget, const GlobalValue *GA,