[llvm-commits] CVS: llvm/lib/CodeGen/SelectionDAG/ScheduleDAG.cpp

Jim Laskey jlaskey at apple.com
Fri Sep 30 12:15:38 PDT 2005



Changes in directory llvm/lib/CodeGen/SelectionDAG:

ScheduleDAG.cpp updated: 1.25 -> 1.26
---
Log message:

1. Made things node-centric (from operand).

2. Added node groups to handle flagged nodes.

3. Started weaning simple scheduling off existing emitter.



---
Diffs of the changes:  (+609 -244)

 ScheduleDAG.cpp |  853 +++++++++++++++++++++++++++++++++++++++-----------------
 1 files changed, 609 insertions(+), 244 deletions(-)


Index: llvm/lib/CodeGen/SelectionDAG/ScheduleDAG.cpp
diff -u llvm/lib/CodeGen/SelectionDAG/ScheduleDAG.cpp:1.25 llvm/lib/CodeGen/SelectionDAG/ScheduleDAG.cpp:1.26
--- llvm/lib/CodeGen/SelectionDAG/ScheduleDAG.cpp:1.25	Wed Sep 28 20:59:49 2005
+++ llvm/lib/CodeGen/SelectionDAG/ScheduleDAG.cpp	Fri Sep 30 14:15:27 2005
@@ -192,25 +192,177 @@
 
 
 //===----------------------------------------------------------------------===//
-// This struct tracks information used to schedule the a node.
-struct ScheduleInfo {
-  SDOperand     Op;                     // Operand information
+///
+/// Node group -  This struct is used to manage flagged node groups.
+///
+class NodeInfo;
+class NodeGroup : public std::vector<NodeInfo *> {
+private:
+  int           Pending;                // Number of visits pending before
+                                        //    adding to order  
+
+public:
+  // Ctor.
+  NodeGroup() : Pending(0) {}
+  
+  // Accessors
+  inline NodeInfo *getLeader() { return empty() ? NULL : front(); }
+  inline int getPending() const { return Pending; }
+  inline void setPending(int P)  { Pending = P; }
+  inline int addPending(int I)  { return Pending += I; }
+
+  static void Add(NodeInfo *D, NodeInfo *U);
+  static unsigned CountInternalUses(NodeInfo *D, NodeInfo *U);
+};
+//===----------------------------------------------------------------------===//
+
+
+//===----------------------------------------------------------------------===//
+///
+/// NodeInfo - This struct tracks information used to schedule the a node.
+///
+class NodeInfo {
+private:
+  int           Pending;                // Number of visits pending before
+                                        //    adding to order
+public:
+  SDNode        *Node;                  // DAG node
   unsigned      Latency;                // Cycles to complete instruction
   unsigned      ResourceSet;            // Bit vector of usable resources
-  unsigned      Slot;                   // Operand's time slot
+  unsigned      Slot;                   // Node's time slot
+  NodeGroup     *Group;                 // Grouping information
+  unsigned      VRBase;                 // Virtual register base
   
   // Ctor.
-  ScheduleInfo(SDOperand op)
-  : Op(op)
+  NodeInfo(SDNode *N = NULL)
+  : Pending(0)
+  , Node(N)
   , Latency(0)
   , ResourceSet(0)
   , Slot(0)
+  , Group(NULL)
+  , VRBase(0)
   {}
+  
+  // Accessors
+  inline bool isInGroup() const {
+    assert(!Group || !Group->empty() && "Group with no members");
+    return Group != NULL;
+  }
+  inline bool isGroupLeader() const {
+     return isInGroup() && Group->getLeader() == this;
+  }
+  inline int getPending() const {
+    return Group ? Group->getPending() : Pending;
+  }
+  inline void setPending(int P) {
+    if (Group) Group->setPending(P);
+    else       Pending = P;
+  }
+  inline int addPending(int I) {
+    if (Group) return Group->addPending(I);
+    else       return Pending += I;
+  }
+};
+typedef std::vector<NodeInfo *>::iterator NIIterator;
+//===----------------------------------------------------------------------===//
+
+
+//===----------------------------------------------------------------------===//
+///
+/// NodeGroupIterator - Iterates over all the nodes indicated by the node info.
+/// If the node is in a group then iterate over the members of the group,
+/// otherwise just the node info.
+///
+class NodeGroupIterator {
+private:
+  NodeInfo   *NI;                       // Node info
+  NIIterator NGI;                       // Node group iterator
+  NIIterator NGE;                       // Node group iterator end
+  
+public:
+  // Ctor.
+  NodeGroupIterator(NodeInfo *N) : NI(N) {
+    // If the node is in a group then set up the group iterator.  Otherwise
+    // the group iterators will trip first time out.
+    if (N->isInGroup()) {
+      // get Group
+      NodeGroup *Group = NI->Group;
+      NGI = Group->begin();
+      NGE = Group->end();
+      // Prevent this node from being used (will be in members list
+      NI = NULL;
+    }
+  }
+  
+  /// next - Return the next node info, otherwise NULL.
+  ///
+  NodeInfo *next() {
+    // If members list
+    if (NGI != NGE) return *NGI++;
+    // Use node as the result (may be NULL)
+    NodeInfo *Result = NI;
+    // Only use once
+    NI = NULL;
+    // Return node or NULL
+    return Result;
+  }
+};
+//===----------------------------------------------------------------------===//
+
+
+//===----------------------------------------------------------------------===//
+///
+/// NodeGroupOpIterator - Iterates over all the operands of a node.  If the node
+/// is a member of a group, this iterates over all the operands of all the
+/// members of the group.
+///
+class NodeGroupOpIterator {
+private:
+  NodeInfo            *NI;              // Node containing operands
+  NodeGroupIterator   GI;               // Node group iterator
+  SDNode::op_iterator OI;               // Operand iterator
+  SDNode::op_iterator OE;               // Operand iterator end
+  
+  /// CheckNode - Test if node has more operands.  If not get the next node
+  /// skipping over nodes that have no operands.
+  void CheckNode() {
+    // Only if operands are exhausted first
+    while (OI == OE) {
+      // Get next node info
+      NodeInfo *NI = GI.next();
+      // Exit if nodes are exhausted
+      if (!NI) return;
+      // Get node itself
+      SDNode *Node = NI->Node;
+      // Set up the operand iterators
+      OI = Node->op_begin();
+      OE = Node->op_end();
+    }
+  }
+  
+public:
+  // Ctor.
+  NodeGroupOpIterator(NodeInfo *N) : NI(N), GI(N) {}
+  
+  /// isEnd - Returns true when not more operands are available.
+  ///
+  inline bool isEnd() { CheckNode(); return OI == OE; }
+  
+  /// next - Returns the next available operand.
+  ///
+  inline SDOperand next() {
+    assert(OI != OE && "Not checking for end of NodeGroupOpIterator correctly");
+    return *OI++;
+  }
 };
 //===----------------------------------------------------------------------===//
 
 
 //===----------------------------------------------------------------------===//
+///
+/// SimpleSched - Simple two pass scheduler.
+///
 class SimpleSched {
 private:
   // TODO - get ResourceSet from TII
@@ -228,12 +380,13 @@
   const MRegisterInfo &MRI;             // Target processor register information
   SSARegMap *RegMap;                    // Virtual/real register map
   MachineConstantPool *ConstPool;       // Target constant pool
-  std::vector<ScheduleInfo> Operands;   // All operands to be scheduled
-  std::vector<ScheduleInfo*> Ordering;  // Emit ordering of operands
-  std::map<SDNode *, int> Visited;      // Operands that have been visited
+  unsigned NodeCount;                   // Number of nodes in DAG
+  NodeInfo *Info;                       // Info for nodes being scheduled
+  std::map<SDNode *, NodeInfo *> Map;   // Map nodes to info
+  std::vector<NodeInfo*> Ordering;      // Emit ordering of nodes
   ResourceTally<unsigned> Tally;        // Resource usage tally
   unsigned NSlots;                      // Total latency
-  std::map<SDNode *, unsigned>VRMap;    // Operand to VR map
+  std::map<SDNode *, unsigned> VRMap;   // Node to VR map
   static const unsigned NotFound = ~0U; // Search marker
   
 public:
@@ -255,37 +408,41 @@
   }
   
 private:
-  static bool isFlagDefiner(SDOperand Op) { return isFlagDefiner(Op.Val); }
-  static bool isFlagUser(SDOperand Op) { return isFlagUser(Op.Val); }
+  /// getNI - Returns the node info for the specified node.
+  ///
+  inline NodeInfo *getNI(SDNode *Node) { return Map[Node]; }
+  
+  /// getVR - Returns the virtual register number of the node.
+  ///
+  inline unsigned getVR(SDOperand Op) {
+    NodeInfo *NI = getNI(Op.Val);
+    assert(NI->VRBase != 0 && "Node emitted out of order - late");
+    return NI->VRBase + Op.ResNo;
+  }
+
   static bool isFlagDefiner(SDNode *A);
   static bool isFlagUser(SDNode *A);
-  static bool isDefiner(SDNode *A, SDNode *B);
-  static bool isPassiveOperand(SDOperand Op);
-  void IncludeOperand(SDOperand Op);
+  static bool isDefiner(NodeInfo *A, NodeInfo *B);
+  static bool isPassiveNode(SDNode *Node);
+  void IncludeNode(NodeInfo *NI);
   void VisitAll();
   void Schedule();
-  void GatherOperandInfo();
-  bool isStrongDependency(SDOperand A, SDOperand B) {
-    return isStrongDependency(A.Val, B.Val);
-  }
-  bool isWeakDependency(SDOperand A, SDOperand B) {
-    return isWeakDependency(A.Val, B.Val);
-  }
-  static bool isStrongDependency(SDNode *A, SDNode *B);
-  static bool isWeakDependency(SDNode *A, SDNode *B);
+  void GatherNodeInfo();
+  bool isStrongDependency(NodeInfo *A, NodeInfo *B);
+  bool isWeakDependency(NodeInfo *A, NodeInfo *B);
   void ScheduleBackward();
   void ScheduleForward();
   void EmitAll();
-  void EmitFlagUsers(SDOperand Op);
-  static unsigned CountResults(SDOperand Op);
-  static unsigned CountOperands(SDOperand Op);
-  unsigned CreateVirtualRegisters(SDOperand Op, MachineInstr *MI,
+  void EmitNode(NodeInfo *NI);
+  static unsigned CountResults(SDNode *Node);
+  static unsigned CountOperands(SDNode *Node);
+  unsigned CreateVirtualRegisters(MachineInstr *MI,
                                   unsigned NumResults,
                                   const TargetInstrDescriptor &II);
-  unsigned Emit(SDOperand A);
+  unsigned EmitDAG(SDOperand A);
 
-  void printSI(std::ostream &O, ScheduleInfo *SI) const ;
-  void print(std::ostream &O) const ;
+  void printSI(std::ostream &O, NodeInfo *NI) const;
+  void print(std::ostream &O) const;
   inline void dump(const char *tag) const { std::cerr << tag; dump(); }
   void dump() const;
 };
@@ -341,193 +498,284 @@
 };
 
 } // namespace
+//===----------------------------------------------------------------------===//
 
 
 //===----------------------------------------------------------------------===//
-/// isFlagDefiner - Returns true if the operand defines a flag result.
+/// Add - Adds a definer and user pair to a node group.
+///
+void NodeGroup::Add(NodeInfo *D, NodeInfo *U) {
+  // Get current groups
+  NodeGroup *DGroup = D->Group;
+  NodeGroup *UGroup = U->Group;
+  // If both are members of groups
+  if (DGroup && UGroup) {
+    // There may have been another edge connecting 
+    if (DGroup == UGroup) return;
+    // Add the pending users count
+    DGroup->addPending(UGroup->getPending());
+    // For each member of the users group
+    NodeGroupIterator UNGI(U);
+    while (NodeInfo *UNI = UNGI.next() ) {
+      // Change the group
+      UNI->Group = DGroup;
+      // For each member of the definers group
+      NodeGroupIterator DNGI(D);
+      while (NodeInfo *DNI = DNGI.next() ) {
+        // Remove internal edges
+        DGroup->addPending(-CountInternalUses(DNI, UNI));
+      }
+    }
+    // Merge the two lists
+    DGroup->insert(DGroup->end(), UGroup->begin(), UGroup->end());
+  } else if (DGroup) {
+    // Make user member of definers group
+    U->Group = DGroup;
+    // Add users uses to definers group pending
+    DGroup->addPending(U->Node->use_size());
+    // For each member of the definers group
+    NodeGroupIterator DNGI(D);
+    while (NodeInfo *DNI = DNGI.next() ) {
+      // Remove internal edges
+      DGroup->addPending(-CountInternalUses(DNI, U));
+    }
+    DGroup->push_back(U);
+  } else if (UGroup) {
+    // Make definer member of users group
+    D->Group = UGroup;
+    // Add definers uses to users group pending
+    UGroup->addPending(D->Node->use_size());
+    // For each member of the users group
+    NodeGroupIterator UNGI(U);
+    while (NodeInfo *UNI = UNGI.next() ) {
+      // Remove internal edges
+      UGroup->addPending(-CountInternalUses(D, UNI));
+    }
+    UGroup->insert(UGroup->begin(), D);
+  } else {
+    D->Group = U->Group = DGroup = new NodeGroup();
+    DGroup->addPending(D->Node->use_size() + U->Node->use_size() -
+                       CountInternalUses(D, U));
+    DGroup->push_back(D);
+    DGroup->push_back(U);
+  }
+}
+
+/// CountInternalUses - Returns the number of edges between the two nodes.
+///
+unsigned NodeGroup::CountInternalUses(NodeInfo *D, NodeInfo *U) {
+  unsigned N = 0;
+  for (SDNode:: use_iterator UI = D->Node->use_begin(),
+                             E = D->Node->use_end(); UI != E; UI++) {
+    if (*UI == U->Node) N++;
+  }
+  return N;
+}
+//===----------------------------------------------------------------------===//
+
+
+//===----------------------------------------------------------------------===//
+/// isFlagDefiner - Returns true if the node defines a flag result.
 bool SimpleSched::isFlagDefiner(SDNode *A) {
   unsigned N = A->getNumValues();
   return N && A->getValueType(N - 1) == MVT::Flag;
 }
 
-/// isFlagUser - Returns true if the operand uses a flag result.
+/// isFlagUser - Returns true if the node uses a flag result.
 ///
 bool SimpleSched::isFlagUser(SDNode *A) {
   unsigned N = A->getNumOperands();
   return N && A->getOperand(N - 1).getValueType() == MVT::Flag;
 }
 
-/// isDefiner - Return true if Node A is a definder for B.
+/// isDefiner - Return true if node A is a definer for B.
 ///
-bool SimpleSched::isDefiner(SDNode *A, SDNode *B) {
-  for (unsigned i = 0, N = B->getNumOperands(); i < N; i++) {
-    if (B->getOperand(i).Val == A) return true;
+bool SimpleSched::isDefiner(NodeInfo *A, NodeInfo *B) {
+  // While there are A nodes
+  NodeGroupIterator NII(A);
+  while (NodeInfo *NI = NII.next()) {
+    // Extract node
+    SDNode *Node = NI->Node;
+    // While there operands in nodes of B
+    NodeGroupOpIterator NGOI(B);
+    while (!NGOI.isEnd()) {
+      SDOperand Op = NGOI.next();
+      // If node from A defines a node in B
+      if (Node == Op.Val) return true;
+    }
   }
   return false;
 }
 
-/// isPassiveOperand - Return true if the operand is a non-scheduled leaf
-/// operand.
-bool SimpleSched::isPassiveOperand(SDOperand Op) {
-  if (isa<ConstantSDNode>(Op))       return true;
-  if (isa<RegisterSDNode>(Op))       return true;
-  if (isa<GlobalAddressSDNode>(Op))  return true;
-  if (isa<BasicBlockSDNode>(Op))     return true;
-  if (isa<FrameIndexSDNode>(Op))     return true;
-  if (isa<ConstantPoolSDNode>(Op))   return true;
-  if (isa<ExternalSymbolSDNode>(Op)) return true;
+/// isPassiveNode - Return true if the node is a non-scheduled leaf.
+///
+bool SimpleSched::isPassiveNode(SDNode *Node) {
+  if (isa<ConstantSDNode>(Node))       return true;
+  if (isa<RegisterSDNode>(Node))       return true;
+  if (isa<GlobalAddressSDNode>(Node))  return true;
+  if (isa<BasicBlockSDNode>(Node))     return true;
+  if (isa<FrameIndexSDNode>(Node))     return true;
+  if (isa<ConstantPoolSDNode>(Node))   return true;
+  if (isa<ExternalSymbolSDNode>(Node)) return true;
   return false;
 }
 
-/// IncludeOperand - Add operand to ScheduleInfo vector.
+/// IncludeNode - Add node to NodeInfo vector.
 ///
-void SimpleSched::IncludeOperand(SDOperand Op) {
+void SimpleSched::IncludeNode(NodeInfo *NI) {
+  // Get node
+  SDNode *Node = NI->Node;
   // Ignore entry node
-  if (Op.getOpcode() == ISD::EntryToken) return;
-  // Check current count for operand
-  int Count = Visited[Op.Val];
-  // If the operand is already in list
+if (Node->getOpcode() == ISD::EntryToken) return;
+  // Check current count for node
+  int Count = NI->getPending();
+  // If the node is already in list
   if (Count < 0) return;
-  // If this the first time then get count 
-  if (!Count) Count = Op.Val->use_size();
   // Decrement count to indicate a visit
   Count--;
-  // If count has gone to zero then add operand to list
+  // If count has gone to zero then add node to list
   if (!Count) {
-    // Add operand
-    Operands.push_back(ScheduleInfo(Op));
-    // indicate operand has been added
+    // Add node
+    if (NI->isInGroup()) {
+      Ordering.push_back(NI->Group->getLeader());
+    } else {
+      Ordering.push_back(NI);
+    }
+    // indicate node has been added
     Count--;
   }
   // Mark as visited with new count 
-  Visited[Op.Val] = Count;
+  NI->setPending(Count);
 }
 
-/// VisitAll - Visit each operand breadth-wise to produce an initial ordering.
-/// Note that the ordering in the Operands vector is reversed.
+/// VisitAll - Visit each node breadth-wise to produce an initial ordering.
+/// Note that the ordering in the Nodes vector is reversed.
 void SimpleSched::VisitAll() {
   // Add first element to list
-  Operands.push_back(DAG.getRoot());
-  for (unsigned i = 0; i < Operands.size(); i++) { // note: size() varies
-    // Get next operand. Need copy because Operands vector is growing and
-    // addresses can be ScheduleInfo changing.
-    SDOperand Op = Operands[i].Op;
-    // Get the number of real operands
-    unsigned NodeOperands = CountOperands(Op);
-    // Get the total number of operands
-    unsigned NumOperands = Op.getNumOperands();
-
-    // Visit all operands skipping the Other operand if present
-    for (unsigned i = NumOperands; 0 < i--;) {
-      SDOperand OpI = Op.getOperand(i);
-      // Ignore passive operands
-      if (isPassiveOperand(OpI)) continue;
-      // Check out operand
-      IncludeOperand(OpI);
+  Ordering.push_back(getNI(DAG.getRoot().Val));
+  
+  // Iterate through all nodes that have been added
+  for (unsigned i = 0; i < Ordering.size(); i++) { // note: size() varies
+    // Visit all operands
+    NodeGroupOpIterator NGI(Ordering[i]);
+    while (!NGI.isEnd()) {
+      // Get next operand
+      SDOperand Op = NGI.next();
+      // Get node
+      SDNode *Node = Op.Val;
+      // Ignore passive nodes
+      if (isPassiveNode(Node)) continue;
+      // Check out node
+      IncludeNode(getNI(Node));
     }
   }
 
-  // Add entry node last (IncludeOperand filters entry nodes)
+  // Add entry node last (IncludeNode filters entry nodes)
   if (DAG.getEntryNode().Val != DAG.getRoot().Val)
-    Operands.push_back(DAG.getEntryNode());
+    Ordering.push_back(getNI(DAG.getEntryNode().Val));
+    
+  // FIXME - Reverse the order
+  for (unsigned i = 0, N = Ordering.size(), Half = N >> 1; i < Half; i++) {
+    unsigned j = N - i - 1;
+    NodeInfo *tmp = Ordering[i];
+    Ordering[i] = Ordering[j];
+    Ordering[j] = tmp;
+  }
 }
 
-/// GatherOperandInfo - Get latency and resource information about each operand.
-///
-void SimpleSched::GatherOperandInfo() {
-  // Add addresses of operand info to ordering vector
-  // Get number of operands
-  unsigned N = Operands.size();
-  // FIXME: This is an ugly (but temporary!) hack to test the scheduler before
-  // we have real target info.
+/// GatherNodeInfo - Get latency and resource information about each node.
+/// 
+void SimpleSched::GatherNodeInfo() {
+  // Allocate node information
+  Info = new NodeInfo[NodeCount];
+  // Get base of all nodes table
+  SelectionDAG::allnodes_iterator AllNodes = DAG.allnodes_begin();
   
-  // For each operand being scheduled
-  for (unsigned i = 0; i < N; i++) {
-    ScheduleInfo* SI = &Operands[N - i - 1];
-    SDOperand Op = SI->Op;
-    MVT::ValueType VT = Op.Val->getValueType(0);
-    if (Op.isTargetOpcode()) {
-      MachineOpCode TOpc = Op.getTargetOpcode();
-      // FIXME SI->Latency = std::max(1, TII.maxLatency(TOpc));
-      // FIXME SI->ResourceSet = TII.resources(TOpc);
+  // For each node being scheduled
+  for (unsigned i = 0, N = NodeCount; i < N; i++) {
+    // Get next node from DAG all nodes table
+    SDNode *Node = AllNodes[i];
+    // Fast reference to node schedule info
+    NodeInfo* NI = &Info[i];
+    // Set up map
+    Map[Node] = NI;
+    // Set node
+    NI->Node = Node;
+    // Set pending visit count
+    NI->setPending(Node->use_size());    
+    
+    MVT::ValueType VT = Node->getValueType(0);
+    if (Node->isTargetOpcode()) {
+      MachineOpCode TOpc = Node->getTargetOpcode();
+      // FIXME: This is an ugly (but temporary!) hack to test the scheduler
+      // before we have real target info.
+      // FIXME NI->Latency = std::max(1, TII.maxLatency(TOpc));
+      // FIXME NI->ResourceSet = TII.resources(TOpc);
       if (TII.isCall(TOpc)) {
-        SI->ResourceSet = RSInteger;
-        SI->Latency = 40;
+        NI->ResourceSet = RSInteger;
+        NI->Latency = 40;
       } else if (TII.isLoad(TOpc)) {
-        SI->ResourceSet = RSLoadStore;
-        SI->Latency = 5;
+        NI->ResourceSet = RSLoadStore;
+        NI->Latency = 5;
       } else if (TII.isStore(TOpc)) {
-        SI->ResourceSet = RSLoadStore;
-        SI->Latency = 2;
+        NI->ResourceSet = RSLoadStore;
+        NI->Latency = 2;
       } else if (MVT::isInteger(VT)) {
-        SI->ResourceSet = RSInteger;
-        SI->Latency = 2;
+        NI->ResourceSet = RSInteger;
+        NI->Latency = 2;
       } else if (MVT::isFloatingPoint(VT)) {
-        SI->ResourceSet = RSFloat;
-        SI->Latency = 3;
+        NI->ResourceSet = RSFloat;
+        NI->Latency = 3;
       } else {
-        SI->ResourceSet = RSOther;
-        SI->Latency = 0;
+        NI->ResourceSet = RSOther;
+        NI->Latency = 0;
       }
     } else {
       if (MVT::isInteger(VT)) {
-        SI->ResourceSet = RSInteger;
-        SI->Latency = 2;
+        NI->ResourceSet = RSInteger;
+        NI->Latency = 2;
       } else if (MVT::isFloatingPoint(VT)) {
-        SI->ResourceSet = RSFloat;
-        SI->Latency = 3;
+        NI->ResourceSet = RSFloat;
+        NI->Latency = 3;
       } else {
-        SI->ResourceSet = RSOther;
-        SI->Latency = 0;
+        NI->ResourceSet = RSOther;
+        NI->Latency = 0;
       }
     }
     
     // Add one slot for the instruction itself
-    SI->Latency++;
+    NI->Latency++;
     
     // Sum up all the latencies for max tally size
-    NSlots += SI->Latency;
-    
-    // Place in initial sorted order
-    // FIXME - PUNT - ignore flag users 
-    if (!isFlagUser(Op)) Ordering.push_back(SI);
+    NSlots += NI->Latency;
+  }
+  
+  // Put flagged nodes into groups
+  for (unsigned i = 0, N = NodeCount; i < N; i++) {
+    NodeInfo* NI = &Info[i];
+    SDNode *Node = NI->Node;
+    if (isFlagDefiner(Node)) {
+      FlagUserIterator FI(Node);
+      while (SDNode *User = FI.next()) NodeGroup::Add(NI, getNI(User));
+    }
   }
 }
 
-/// isStrongDependency - Return true if operand A has results used by operand B. 
+/// isStrongDependency - Return true if node A has results used by node B. 
 /// I.E., B must wait for latency of A.
-bool SimpleSched::isStrongDependency(SDNode *A, SDNode *B) {
+bool SimpleSched::isStrongDependency(NodeInfo *A, NodeInfo *B) {
   // If A defines for B then it's a strong dependency
-  if (isDefiner(A, B)) return true;
-  // If A defines a flag then it's users are part of the dependency
-  if (isFlagDefiner(A)) {
-    // Check each flag user
-    FlagUserIterator FI(A);
-    while (SDNode *User = FI.next()) {
-      // If flag user has strong dependency so does B
-      if (isStrongDependency(User, B)) return true;
-    }
-  }
-  // If B defines a flag then it's users are part of the dependency
-  if (isFlagDefiner(B)) {
-    // Check each flag user
-    FlagUserIterator FI(B);
-    while (SDNode *User = FI.next()) {
-      // If flag user has strong dependency so does B
-      if (isStrongDependency(A, User)) return true;
-    }
-  }
-  return false;
+  return isDefiner(A, B);
 }
 
-/// isWeakDependency Return true if operand A produces a result that will
+/// isWeakDependency Return true if node A produces a result that will
 /// conflict with operands of B.
-bool SimpleSched::isWeakDependency(SDNode *A, SDNode *B) {
+bool SimpleSched::isWeakDependency(NodeInfo *A, NodeInfo *B) {
   // TODO check for conflicting real registers and aliases
-#if 0 // Since we are in SSA form and not checking register aliasing
-  return A->getOpcode() == ISD::EntryToken || isStrongDependency(B, A);
+#if 0 // FIXME - Since we are in SSA form and not checking register aliasing
+  return A->Node->getOpcode() == ISD::EntryToken || isStrongDependency(B, A);
 #else
-  return A->getOpcode() == ISD::EntryToken;
+  return A->Node->getOpcode() == ISD::EntryToken;
 #endif
 }
 
@@ -538,26 +786,26 @@
 void SimpleSched::ScheduleBackward() {
   // Size and clear the resource tally
   Tally.Initialize(NSlots);
-  // Get number of operands to schedule
+  // Get number of nodes to schedule
   unsigned N = Ordering.size();
   
-  // For each operand being scheduled
+  // For each node being scheduled
   for (unsigned i = N; 0 < i--;) {
-    ScheduleInfo *SI = Ordering[i];
+    NodeInfo *NI = Ordering[i];
     // Track insertion
     unsigned Slot = NotFound;
     
-    // Compare against those previously scheduled operands
+    // Compare against those previously scheduled nodes
     unsigned j = i + 1;
     for (; j < N; j++) {
       // Get following instruction
-      ScheduleInfo *Other = Ordering[j];
+      NodeInfo *Other = Ordering[j];
       
-      // Check dependency against previously inserted operands
-      if (isStrongDependency(SI->Op, Other->Op)) {
+      // Check dependency against previously inserted nodes
+      if (isStrongDependency(NI, Other)) {
         Slot = Other->Slot + Other->Latency;
         break;
-      } else if (isWeakDependency(SI->Op, Other->Op)) {
+      } else if (isWeakDependency(NI, Other)) {
         Slot = Other->Slot;
         break;
       }
@@ -567,24 +815,24 @@
     if (Slot == NotFound) Slot = 0;
     
     // Find a slot where the needed resources are available
-    if (SI->ResourceSet)
-      Slot = Tally.FindAndReserve(Slot, SI->Latency, SI->ResourceSet);
+    if (NI->ResourceSet)
+      Slot = Tally.FindAndReserve(Slot, NI->Latency, NI->ResourceSet);
       
-    // Set operand slot
-    SI->Slot = Slot;
+    // Set node slot
+    NI->Slot = Slot;
     
     // Insert sort based on slot
     j = i + 1;
     for (; j < N; j++) {
       // Get following instruction
-      ScheduleInfo *Other = Ordering[j];
+      NodeInfo *Other = Ordering[j];
       // Should we look further
       if (Slot >= Other->Slot) break;
       // Shuffle other into ordering
       Ordering[j - 1] = Other;
     }
-    // Insert operand in proper slot
-    if (j != i + 1) Ordering[j - 1] = SI;
+    // Insert node in proper slot
+    if (j != i + 1) Ordering[j - 1] = NI;
   }
 }
 
@@ -593,26 +841,26 @@
 void SimpleSched::ScheduleForward() {
   // Size and clear the resource tally
   Tally.Initialize(NSlots);
-  // Get number of operands to schedule
+  // Get number of nodes to schedule
   unsigned N = Ordering.size();
   
-  // For each operand being scheduled
+  // For each node being scheduled
   for (unsigned i = 0; i < N; i++) {
-    ScheduleInfo *SI = Ordering[i];
+    NodeInfo *NI = Ordering[i];
     // Track insertion
     unsigned Slot = NotFound;
     
-    // Compare against those previously scheduled operands
+    // Compare against those previously scheduled nodes
     unsigned j = i;
     for (; 0 < j--;) {
       // Get following instruction
-      ScheduleInfo *Other = Ordering[j];
+      NodeInfo *Other = Ordering[j];
       
-      // Check dependency against previously inserted operands
-      if (isStrongDependency(Other->Op, SI->Op)) {
+      // Check dependency against previously inserted nodes
+      if (isStrongDependency(Other, NI)) {
         Slot = Other->Slot + Other->Latency;
         break;
-      } else if (isWeakDependency(Other->Op, SI->Op)) {
+      } else if (isWeakDependency(Other, NI)) {
         Slot = Other->Slot;
         break;
       }
@@ -622,66 +870,59 @@
     if (Slot == NotFound) Slot = 0;
     
     // Find a slot where the needed resources are available
-    if (SI->ResourceSet)
-      Slot = Tally.FindAndReserve(Slot, SI->Latency, SI->ResourceSet);
+    if (NI->ResourceSet)
+      Slot = Tally.FindAndReserve(Slot, NI->Latency, NI->ResourceSet);
       
-    // Set operand slot
-    SI->Slot = Slot;
+    // Set node slot
+    NI->Slot = Slot;
     
     // Insert sort based on slot
     j = i;
     for (; 0 < j--;) {
       // Get following instruction
-      ScheduleInfo *Other = Ordering[j];
+      NodeInfo *Other = Ordering[j];
       // Should we look further
       if (Slot >= Other->Slot) break;
       // Shuffle other into ordering
       Ordering[j + 1] = Other;
     }
-    // Insert operand in proper slot
-    if (j != i) Ordering[j + 1] = SI;
+    // Insert node in proper slot
+    if (j != i) Ordering[j + 1] = NI;
   }
 }
 
-/// EmitAll - Emit all operands in schedule sorted order.
+/// EmitAll - Emit all nodes in schedule sorted order.
 ///
 void SimpleSched::EmitAll() {
-  // For each operand in the ordering
+  // For each node in the ordering
   for (unsigned i = 0, N = Ordering.size(); i < N; i++) {
     // Get the scheduling info
-    ScheduleInfo *SI = Ordering[i];
-    // Get the operand
-    SDOperand Op = SI->Op;
-    // Emit the operand
-    Emit(Op);
-    // FIXME - PUNT - If Op defines a flag then it's users need to be emitted now
-    if (isFlagDefiner(Op)) EmitFlagUsers(Op);
-  }
-}
-
-/// EmitFlagUsers - Emit users of operands flag.
-///
-void SimpleSched::EmitFlagUsers(SDOperand Op) {
-  // Check each flag user
-  FlagUserIterator FI(Op.Val);
-  while (SDNode *User = FI.next()) {
-    // Construct user node as operand
-    SDOperand OpU(User, 0);
-    // Emit  user node
-    Emit(OpU);
-    // If user defines a flag then it's users need to be emitted now
-    if (isFlagDefiner(User)) EmitFlagUsers(OpU);
+    NodeInfo *NI = Ordering[i];
+#if 0
+    // Iterate through nodes
+    NodeGroupIterator NGI(Ordering[i]);
+    while (NodeInfo *NI = NGI.next()) EmitNode(NI);
+#else
+    if (NI->isInGroup()) {
+      if (NI->isGroupLeader()) {
+        NodeGroupIterator NGI(Ordering[i]);
+        while (NodeInfo *NI = NGI.next()) EmitNode(NI);
+      }
+    } else {
+      EmitNode(NI);
+    }
+#endif
   }
 }
 
 /// CountResults - The results of target nodes have register or immediate
 /// operands first, then an optional chain, and optional flag operands (which do
 /// not go into the machine instrs.)
-unsigned SimpleSched::CountResults(SDOperand Op) {
-  unsigned N = Op.Val->getNumValues();
-  while (N && Op.Val->getValueType(N - 1) == MVT::Flag)
+unsigned SimpleSched::CountResults(SDNode *Node) {
+  unsigned N = Node->getNumValues();
+  while (N && Node->getValueType(N - 1) == MVT::Flag)
     --N;
-  if (N && Op.Val->getValueType(N - 1) == MVT::Other)
+  if (N && Node->getValueType(N - 1) == MVT::Other)
     --N;    // Skip over chain result.
   return N;
 }
@@ -689,18 +930,18 @@
 /// CountOperands  The inputs to target nodes have any actual inputs first,
 /// followed by an optional chain operand, then flag operands.  Compute the
 /// number of actual operands that  will go into the machine instr.
-unsigned SimpleSched::CountOperands(SDOperand Op) {
-  unsigned N = Op.getNumOperands();
-  while (N && Op.getOperand(N - 1).getValueType() == MVT::Flag)
+unsigned SimpleSched::CountOperands(SDNode *Node) {
+  unsigned N = Node->getNumOperands();
+  while (N && Node->getOperand(N - 1).getValueType() == MVT::Flag)
     --N;
-  if (N && Op.getOperand(N - 1).getValueType() == MVT::Other)
+  if (N && Node->getOperand(N - 1).getValueType() == MVT::Other)
     --N; // Ignore chain if it exists.
   return N;
 }
 
 /// CreateVirtualRegisters - Add result register values for things that are
 /// defined by this instruction.
-unsigned SimpleSched::CreateVirtualRegisters(SDOperand Op, MachineInstr *MI,
+unsigned SimpleSched::CreateVirtualRegisters(MachineInstr *MI,
                                              unsigned NumResults,
                                              const TargetInstrDescriptor &II) {
   // Create the result registers for this node and add the result regs to
@@ -716,9 +957,131 @@
   return ResultReg;
 }
 
-/// Emit - Generate machine code for an operand and needed dependencies.
+/// EmitNode - Generate machine code for an node and needed dependencies.
+///
+void SimpleSched::EmitNode(NodeInfo *NI) {
+  unsigned VRBase = 0;                 // First virtual register for node
+  SDNode *Node = NI->Node;
+  
+  // If machine instruction
+  if (Node->isTargetOpcode()) {
+    unsigned Opc = Node->getTargetOpcode();
+    const TargetInstrDescriptor &II = TII.get(Opc);
+
+    unsigned NumResults = CountResults(Node);
+    unsigned NodeOperands = CountOperands(Node);
+    unsigned NumMIOperands = NodeOperands + NumResults;
+#ifndef NDEBUG
+    assert((unsigned(II.numOperands) == NumMIOperands || II.numOperands == -1)&&
+           "#operands for dag node doesn't match .td file!"); 
+#endif
+
+    // Create the new machine instruction.
+    MachineInstr *MI = new MachineInstr(Opc, NumMIOperands, true, true);
+    
+    // Add result register values for things that are defined by this
+    // instruction.
+    if (NumResults) VRBase = CreateVirtualRegisters(MI, NumResults, II);
+    
+    // Emit all of the actual operands of this instruction, adding them to the
+    // instruction as appropriate.
+    for (unsigned i = 0; i != NodeOperands; ++i) {
+      if (Node->getOperand(i).isTargetOpcode()) {
+        // Note that this case is redundant with the final else block, but we
+        // include it because it is the most common and it makes the logic
+        // simpler here.
+        assert(Node->getOperand(i).getValueType() != MVT::Other &&
+               Node->getOperand(i).getValueType() != MVT::Flag &&
+               "Chain and flag operands should occur at end of operand list!");
+        
+        MI->addRegOperand(getVR(Node->getOperand(i)), MachineOperand::Use);
+      } else if (ConstantSDNode *C =
+                 dyn_cast<ConstantSDNode>(Node->getOperand(i))) {
+        MI->addZeroExtImm64Operand(C->getValue());
+      } else if (RegisterSDNode*R =
+                 dyn_cast<RegisterSDNode>(Node->getOperand(i))) {
+        MI->addRegOperand(R->getReg(), MachineOperand::Use);
+      } else if (GlobalAddressSDNode *TGA =
+                       dyn_cast<GlobalAddressSDNode>(Node->getOperand(i))) {
+        MI->addGlobalAddressOperand(TGA->getGlobal(), false, 0);
+      } else if (BasicBlockSDNode *BB =
+                       dyn_cast<BasicBlockSDNode>(Node->getOperand(i))) {
+        MI->addMachineBasicBlockOperand(BB->getBasicBlock());
+      } else if (FrameIndexSDNode *FI =
+                       dyn_cast<FrameIndexSDNode>(Node->getOperand(i))) {
+        MI->addFrameIndexOperand(FI->getIndex());
+      } else if (ConstantPoolSDNode *CP = 
+                    dyn_cast<ConstantPoolSDNode>(Node->getOperand(i))) {
+        unsigned Idx = ConstPool->getConstantPoolIndex(CP->get());
+        MI->addConstantPoolIndexOperand(Idx);
+      } else if (ExternalSymbolSDNode *ES = 
+                 dyn_cast<ExternalSymbolSDNode>(Node->getOperand(i))) {
+        MI->addExternalSymbolOperand(ES->getSymbol(), false);
+      } else {
+        assert(Node->getOperand(i).getValueType() != MVT::Other &&
+               Node->getOperand(i).getValueType() != MVT::Flag &&
+               "Chain and flag operands should occur at end of operand list!");
+        MI->addRegOperand(getVR(Node->getOperand(i)), MachineOperand::Use);
+      }
+    }
+    
+    // Now that we have emitted all operands, emit this instruction itself.
+    if ((II.Flags & M_USES_CUSTOM_DAG_SCHED_INSERTION) == 0) {
+      BB->insert(BB->end(), MI);
+    } else {
+      // Insert this instruction into the end of the basic block, potentially
+      // taking some custom action.
+      BB = DAG.getTargetLoweringInfo().InsertAtEndOfBasicBlock(MI, BB);
+    }
+  } else {
+    switch (Node->getOpcode()) {
+    default:
+      Node->dump(); 
+      assert(0 && "This target-independent node should have been selected!");
+    case ISD::EntryToken: // fall thru
+    case ISD::TokenFactor:
+      break;
+    case ISD::CopyToReg: {
+      unsigned Val = getVR(Node->getOperand(2));
+      MRI.copyRegToReg(*BB, BB->end(),
+                       cast<RegisterSDNode>(Node->getOperand(1))->getReg(), Val,
+                       RegMap->getRegClass(Val));
+      break;
+    }
+    case ISD::CopyFromReg: {
+      unsigned SrcReg = cast<RegisterSDNode>(Node->getOperand(1))->getReg();
+      
+      // Figure out the register class to create for the destreg.
+      const TargetRegisterClass *TRC = 0;
+      if (MRegisterInfo::isVirtualRegister(SrcReg)) {
+        TRC = RegMap->getRegClass(SrcReg);
+      } else {
+        // FIXME: we don't know what register class to generate this for.  Do
+        // a brute force search and pick the first match. :(
+        for (MRegisterInfo::regclass_iterator I = MRI.regclass_begin(),
+               E = MRI.regclass_end(); I != E; ++I)
+          if ((*I)->contains(SrcReg)) {
+            TRC = *I;
+            break;
+          }
+        assert(TRC && "Couldn't find register class for reg copy!");
+      }
+      
+      // Create the reg, emit the copy.
+      VRBase = RegMap->createVirtualRegister(TRC);
+      MRI.copyRegToReg(*BB, BB->end(), VRBase, SrcReg, TRC);
+      break;
+    }
+    }
+  }
+
+  assert(NI->VRBase == 0 && "Node emitted out of order - early");
+  NI->VRBase = VRBase;
+}
+
+/// EmitDag - Generate machine code for an operand and needed dependencies.
 ///
-unsigned SimpleSched::Emit(SDOperand Op) {
+unsigned SimpleSched::EmitDAG(SDOperand Op) {
   std::map<SDNode *, unsigned>::iterator OpI = VRMap.lower_bound(Op.Val);
   if (OpI != VRMap.end() && OpI->first == Op.Val)
     return OpI->second + Op.ResNo;
@@ -729,8 +1092,8 @@
     unsigned Opc = Op.getTargetOpcode();
     const TargetInstrDescriptor &II = TII.get(Opc);
 
-    unsigned NumResults = CountResults(Op);
-    unsigned NodeOperands = CountOperands(Op);
+    unsigned NumResults = CountResults(Op.Val);
+    unsigned NodeOperands = CountOperands(Op.Val);
     unsigned NumMIOperands = NodeOperands + NumResults;
 #ifndef NDEBUG
     assert((unsigned(II.numOperands) == NumMIOperands || II.numOperands == -1)&&
@@ -742,13 +1105,13 @@
     
     // Add result register values for things that are defined by this
     // instruction.
-    if (NumResults) ResultReg = CreateVirtualRegisters(Op, MI, NumResults, II);
+    if (NumResults) ResultReg = CreateVirtualRegisters(MI, NumResults, II);
     
     // If there is a token chain operand, emit it first, as a hack to get avoid
     // really bad cases.
     if (Op.getNumOperands() > NodeOperands &&
         Op.getOperand(NodeOperands).getValueType() == MVT::Other) {
-      Emit(Op.getOperand(NodeOperands));
+      EmitDAG(Op.getOperand(NodeOperands));
     }
     
     // Emit all of the actual operands of this instruction, adding them to the
@@ -762,7 +1125,7 @@
                Op.getOperand(i).getValueType() != MVT::Flag &&
                "Chain and flag operands should occur at end of operand list!");
         
-        MI->addRegOperand(Emit(Op.getOperand(i)), MachineOperand::Use);
+        MI->addRegOperand(EmitDAG(Op.getOperand(i)), MachineOperand::Use);
       } else if (ConstantSDNode *C =
                                    dyn_cast<ConstantSDNode>(Op.getOperand(i))) {
         MI->addZeroExtImm64Operand(C->getValue());
@@ -788,7 +1151,7 @@
         assert(Op.getOperand(i).getValueType() != MVT::Other &&
                Op.getOperand(i).getValueType() != MVT::Flag &&
                "Chain and flag operands should occur at end of operand list!");
-        MI->addRegOperand(Emit(Op.getOperand(i)), MachineOperand::Use);
+        MI->addRegOperand(EmitDAG(Op.getOperand(i)), MachineOperand::Use);
       }
     }
 
@@ -801,7 +1164,7 @@
       for (unsigned N = Op.getNumOperands(); i < N; i++) {
         assert(Op.getOperand(i).getValueType() == MVT::Flag &&
                "Must be flag operands!");
-        Emit(Op.getOperand(i));
+        EmitDAG(Op.getOperand(i));
       }
     }
     
@@ -821,7 +1184,7 @@
     case ISD::EntryToken: break;
     case ISD::TokenFactor:
       for (unsigned i = 0, N = Op.getNumOperands(); i < N; i++) {
-        Emit(Op.getOperand(i));
+        EmitDAG(Op.getOperand(i));
       }
       break;
     case ISD::CopyToReg: {
@@ -830,11 +1193,11 @@
         FlagOp = Op.getOperand(3);
       }
       if (Op.getOperand(0).Val != FlagOp.Val) {
-        Emit(Op.getOperand(0));   // Emit the chain.
+        EmitDAG(Op.getOperand(0));   // Emit the chain.
       }
-      unsigned Val = Emit(Op.getOperand(2));
+      unsigned Val = EmitDAG(Op.getOperand(2));
       if (FlagOp.Val) {
-        Emit(FlagOp);
+        EmitDAG(FlagOp);
       }
       MRI.copyRegToReg(*BB, BB->end(),
                        cast<RegisterSDNode>(Op.getOperand(1))->getReg(), Val,
@@ -842,7 +1205,7 @@
       break;
     }
     case ISD::CopyFromReg: {
-      Emit(Op.getOperand(0));   // Emit the chain.
+      EmitDAG(Op.getOperand(0));   // Emit the chain.
       unsigned SrcReg = cast<RegisterSDNode>(Op.getOperand(1))->getReg();
       
       // Figure out the register class to create for the destreg.
@@ -873,17 +1236,19 @@
   return ResultReg+Op.ResNo;
 }
 
-/// Schedule - Order operands according to selected style.
+/// Schedule - Order nodes according to selected style.
 ///
 void SimpleSched::Schedule() {
   switch (ScheduleStyle) {
   case simpleScheduling:
-    // Breadth first walk of DAG
-    VisitAll();
-    // Get latency and resource requirements
-    GatherOperandInfo();
+    // Number the nodes
+    NodeCount = DAG.allnodes_size();
     // Don't waste time if is only entry and return
-    if (Operands.size() > 2) {
+    if (NodeCount > 3) {
+      // Get latency and resource requirements
+      GatherNodeInfo();
+      // Breadth first walk of DAG
+      VisitAll();
       DEBUG(dump("Pre-"));
       // Push back long instructions and critical path
       ScheduleBackward();
@@ -897,27 +1262,27 @@
     } // fall thru
   case noScheduling:
     // Emit instructions in using a DFS from the exit root
-    Emit(DAG.getRoot());
+    EmitDAG(DAG.getRoot());
     break;
   }
 }
 
 /// printSI - Print schedule info.
 ///
-void SimpleSched::printSI(std::ostream &O, ScheduleInfo *SI) const {
+void SimpleSched::printSI(std::ostream &O, NodeInfo *NI) const {
 #ifndef NDEBUG
   using namespace std;
-  SDOperand Op = SI->Op;
+  SDNode *Node = NI->Node;
   O << " "
-    << hex << Op.Val
-    << ", RS=" << SI->ResourceSet
-    << ", Lat=" << SI->Latency
-    << ", Slot=" << SI->Slot
-    << ", ARITY=(" << Op.getNumOperands() << ","
-                   << Op.Val->getNumValues() << ")"
-    << " " << Op.Val->getOperationName(&DAG);
-  if (isFlagDefiner(Op)) O << "<#";
-  if (isFlagUser(Op)) O << ">#";
+    << hex << Node
+    << ", RS=" << NI->ResourceSet
+    << ", Lat=" << NI->Latency
+    << ", Slot=" << NI->Slot
+    << ", ARITY=(" << Node->getNumOperands() << ","
+                   << Node->getNumValues() << ")"
+    << " " << Node->getOperationName(&DAG);
+  if (isFlagDefiner(Node)) O << "<#";
+  if (isFlagUser(Node)) O << ">#";
 #endif
 }
 






More information about the llvm-commits mailing list