No longer needed.
[oota-llvm.git] / lib / CodeGen / SelectionDAG / ScheduleDAGSimple.cpp
index 5497ecf93bf7862cf8d519b06a4cbffa02d8062c..e4133cec6e1f3c1dbcfc0c5d18c6fe8e4e0a6fb2 100644 (file)
 //===----------------------------------------------------------------------===//
 
 #define DEBUG_TYPE "sched"
+#include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/ScheduleDAG.h"
+#include "llvm/CodeGen/SchedulerRegistry.h"
 #include "llvm/CodeGen/SelectionDAG.h"
+#include "llvm/CodeGen/SSARegMap.h"
+#include "llvm/Target/TargetData.h"
 #include "llvm/Target/TargetMachine.h"
 #include "llvm/Target/TargetInstrInfo.h"
 #include "llvm/Support/Debug.h"
+#include "llvm/Support/Compiler.h"
 #include <algorithm>
-#include <iostream>
 using namespace llvm;
 
 namespace {
+
+static RegisterScheduler
+  bfsDAGScheduler("none", "  No scheduling: breadth first sequencing",
+                  createBFS_DAGScheduler);
+static RegisterScheduler
+  simpleDAGScheduler("simple",
+                     "  Simple two pass scheduling: minimize critical path "
+                     "and maximize processor utilization",
+                      createSimpleDAGScheduler);
+static RegisterScheduler
+  noitinDAGScheduler("simple-noitin",
+                     "  Simple two pass scheduling: Same as simple "
+                     "except using generic latency",
+                     createNoItinsDAGScheduler);
+                     
+class NodeInfo;
+typedef NodeInfo *NodeInfoPtr;
+typedef std::vector<NodeInfoPtr>           NIVector;
+typedef std::vector<NodeInfoPtr>::iterator NIIterator;
+
+//===--------------------------------------------------------------------===//
+///
+/// Node group -  This struct is used to manage flagged node groups.
+///
+class NodeGroup {
+public:
+  NodeGroup     *Next;
+private:
+  NIVector      Members;                // Group member nodes
+  NodeInfo      *Dominator;             // Node with highest latency
+  unsigned      Latency;                // Total latency of the group
+  int           Pending;                // Number of visits pending before
+                                        // adding to order  
+
+public:
+  // Ctor.
+  NodeGroup() : Next(NULL), Dominator(NULL), Pending(0) {}
+
+  // Accessors
+  inline void setDominator(NodeInfo *D) { Dominator = D; }
+  inline NodeInfo *getTop() { return Members.front(); }
+  inline NodeInfo *getBottom() { return Members.back(); }
+  inline NodeInfo *getDominator() { return Dominator; }
+  inline void setLatency(unsigned L) { Latency = L; }
+  inline unsigned getLatency() { return Latency; }
+  inline int getPending() const { return Pending; }
+  inline void setPending(int P)  { Pending = P; }
+  inline int addPending(int I)  { return Pending += I; }
+
+  // Pass thru
+  inline bool group_empty() { return Members.empty(); }
+  inline NIIterator group_begin() { return Members.begin(); }
+  inline NIIterator group_end() { return Members.end(); }
+  inline void group_push_back(const NodeInfoPtr &NI) {
+    Members.push_back(NI);
+  }
+  inline NIIterator group_insert(NIIterator Pos, const NodeInfoPtr &NI) {
+    return Members.insert(Pos, NI);
+  }
+  inline void group_insert(NIIterator Pos, NIIterator First,
+                           NIIterator Last) {
+    Members.insert(Pos, First, Last);
+  }
+
+  static void Add(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
+  InstrStage    *StageBegin;            // First stage in itinerary
+  InstrStage    *StageEnd;              // Last+1 stage in itinerary
+  unsigned      Latency;                // Total cycles to complete instr
+  bool          IsCall : 1;             // Is function call
+  bool          IsLoad : 1;             // Is memory load
+  bool          IsStore : 1;            // Is memory store
+  unsigned      Slot;                   // Node's time slot
+  NodeGroup     *Group;                 // Grouping information
+#ifndef NDEBUG
+  unsigned      Preorder;               // Index before scheduling
+#endif
+
+  // Ctor.
+  NodeInfo(SDNode *N = NULL)
+    : Pending(0)
+    , Node(N)
+    , StageBegin(NULL)
+    , StageEnd(NULL)
+    , Latency(0)
+    , IsCall(false)
+    , Slot(0)
+    , Group(NULL)
+#ifndef NDEBUG
+    , Preorder(0)
+#endif
+  {}
+
+  // Accessors
+  inline bool isInGroup() const {
+    assert(!Group || !Group->group_empty() && "Group with no members");
+    return Group != NULL;
+  }
+  inline bool isGroupDominator() const {
+    return isInGroup() && Group->getDominator() == 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;
+  }
+};
+
+//===--------------------------------------------------------------------===//
+///
+/// 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->group_begin();
+      NGE = Group->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), OI(SDNode::op_iterator()), OE(SDNode::op_iterator()) {}
+
+  /// 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++;
+  }
+};
+
+
 //===----------------------------------------------------------------------===//
 ///
 /// BitsIterator - Provides iteration through individual bits in a bit vector.
@@ -56,7 +277,7 @@ public:
 /// ResourceTally - Manages the use of resources over time intervals.  Each
 /// item (slot) in the tally vector represents the resources used at a given
 /// moment.  A bit set to 1 indicates that a resource is in use, otherwise
-/// available.  An assumption is made that the tally is large enough to schedule 
+/// available.  An assumption is made that the tally is large enough to schedule
 /// all current instructions (asserts otherwise.)
 ///
 template<class T>
@@ -156,7 +377,7 @@ private:
       // Try at cursor, if successful return position.
       if (FindAndReserveStages(Cursor, StageBegin, StageEnd)) return Cursor;
       // Locate a better position
-                       Cursor = RetrySlot(Cursor + 1, StageBegin->Cycles, StageBegin->Units);
+      Cursor = RetrySlot(Cursor + 1, StageBegin->Cycles, StageBegin->Units);
     }
   }
   
@@ -186,26 +407,50 @@ public:
 ///
 /// ScheduleDAGSimple - Simple two pass scheduler.
 ///
-class ScheduleDAGSimple : public ScheduleDAG {
+class VISIBILITY_HIDDEN ScheduleDAGSimple : public ScheduleDAG {
 private:
+  bool NoSched;                         // Just do a BFS schedule, nothing fancy
+  bool NoItins;                         // Don't use itineraries?
   ResourceTally<unsigned> Tally;        // Resource usage tally
   unsigned NSlots;                      // Total latency
   static const unsigned NotFound = ~0U; // Search marker
+
+  unsigned NodeCount;                   // Number of nodes in DAG
+  std::map<SDNode *, NodeInfo *> Map;   // Map nodes to info
+  bool HasGroups;                       // True if there are any groups
+  NodeInfo *Info;                       // Info for nodes being scheduled
+  NIVector Ordering;                    // Emit ordering of nodes
+  NodeGroup *HeadNG, *TailNG;           // Keep track of allocated NodeGroups
   
 public:
 
   // Ctor.
-  ScheduleDAGSimple(SchedHeuristics hstc, SelectionDAG &dag,
+  ScheduleDAGSimple(bool noSched, bool noItins, SelectionDAG &dag,
                     MachineBasicBlock *bb, const TargetMachine &tm)
-    : ScheduleDAG(hstc, dag, bb, tm), Tally(), NSlots(0) {
+    : ScheduleDAG(dag, bb, tm), NoSched(noSched), NoItins(noItins), NSlots(0),
+    NodeCount(0), HasGroups(false), Info(NULL), HeadNG(NULL), TailNG(NULL) {
     assert(&TII && "Target doesn't provide instr info?");
     assert(&MRI && "Target doesn't provide register info?");
   }
 
-  virtual ~ScheduleDAGSimple() {};
+  virtual ~ScheduleDAGSimple() {
+    if (Info)
+      delete[] Info;
+    
+    NodeGroup *NG = HeadNG;
+    while (NG) {
+      NodeGroup *NextSU = NG->Next;
+      delete NG;
+      NG = NextSU;
+    }
+  }
 
   void Schedule();
 
+  /// getNI - Returns the node info for the specified node.
+  ///
+  NodeInfo *getNI(SDNode *Node) { return Map[Node]; }
+  
 private:
   static bool isDefiner(NodeInfo *A, NodeInfo *B);
   void IncludeNode(NodeInfo *NI);
@@ -229,6 +474,7 @@ private:
   /// print - Print ordering to specified output stream.
   ///
   void print(std::ostream &O) const;
+  void print(std::ostream *O) const { if (O) print(*O); }
   
   void dump(const char *tag) const;
   
@@ -241,6 +487,7 @@ private:
   /// printNI - Print node info.
   ///
   void printNI(std::ostream &O, NodeInfo *NI) const;
+  void printNI(std::ostream *O, NodeInfo *NI) const { if (O) printNI(*O, NI); }
   
   /// printChanges - Hilight changes in order caused by scheduling.
   ///
@@ -258,7 +505,6 @@ enum {
   RSLoadStore = 0x0C000000,  // Two load store units
   RSBranch    = 0x02000000   // One branch unit
 };
-static InstrStage CallStage  = { CallLatency, RSBranch };
 static InstrStage LoadStage  = { 5, RSLoadStore };
 static InstrStage StoreStage = { 2, RSLoadStore };
 static InstrStage IntStage   = { 2, RSInteger };
@@ -413,18 +659,30 @@ void ScheduleDAGSimple::print(std::ostream &O) const {
 }
 
 void ScheduleDAGSimple::dump(const char *tag) const {
-  std::cerr << tag; dump();
+  cerr << tag; dump();
 }
 
 void ScheduleDAGSimple::dump() const {
-  print(std::cerr);
+  print(cerr);
 }
 
 
 /// EmitAll - Emit all nodes in schedule sorted order.
 ///
 void ScheduleDAGSimple::EmitAll() {
-  std::map<SDNode*, unsigned> VRBaseMap;
+  // If this is the first basic block in the function, and if it has live ins
+  // that need to be copied into vregs, emit the copies into the top of the
+  // block before emitting the code for the block.
+  MachineFunction &MF = DAG.getMachineFunction();
+  if (&MF.front() == BB && MF.livein_begin() != MF.livein_end()) {
+    for (MachineFunction::livein_iterator LI = MF.livein_begin(),
+         E = MF.livein_end(); LI != E; ++LI)
+      if (LI->second)
+        MRI->copyRegToReg(*MF.begin(), MF.begin()->end(), LI->second,
+                          LI->first, RegMap->getRegClass(LI->second));
+  }
+  
+  DenseMap<SDNode*, unsigned> VRBaseMap;
   
   // For each node in the ordering
   for (unsigned i = 0, N = Ordering.size(); i < N; i++) {
@@ -483,25 +741,25 @@ void ScheduleDAGSimple::printChanges(unsigned Index) const {
   }
   
   if (i < N) {
-    std::cerr << Index << ". New Ordering\n";
+    cerr << Index << ". New Ordering\n";
     
     for (i = 0; i < N; i++) {
       NodeInfo *NI = Ordering[i];
-      std::cerr << "  " << NI->Preorder << ". ";
-      printNI(std::cerr, NI);
-      std::cerr << "\n";
+      cerr << "  " << NI->Preorder << ". ";
+      printNI(cerr, NI);
+      cerr << "\n";
       if (NI->isGroupDominator()) {
         NodeGroup *Group = NI->Group;
         for (NIIterator NII = Group->group_begin(), E = Group->group_end();
              NII != E; NII++) {
-          std::cerr << "          ";
-          printNI(std::cerr, *NII);
-          std::cerr << "\n";
+          cerr << "          ";
+          printNI(cerr, *NII);
+          cerr << "\n";
         }
       }
     }
   } else {
-    std::cerr << Index << ". No Changes\n";
+    cerr << Index << ". No Changes\n";
   }
 #endif
 }
@@ -567,7 +825,7 @@ void ScheduleDAGSimple::GatherSchedulingInfo() {
     SDNode *Node = NI->Node;
     
     // If there are itineraries and it is a machine instruction
-    if (InstrItins.isEmpty() || Heuristic == simpleNoItinScheduling) {
+    if (InstrItins.isEmpty() || NoItins) {
       // If machine opcode
       if (Node->isTargetOpcode()) {
         // Get return type to guess which processing unit 
@@ -826,13 +1084,16 @@ void ScheduleDAGSimple::ScheduleForward() {
 /// Schedule - Order nodes according to selected style.
 ///
 void ScheduleDAGSimple::Schedule() {
+  // Number the nodes
+  NodeCount = std::distance(DAG.allnodes_begin(), DAG.allnodes_end());
+
   // Set up minimum info for scheduling
   PrepareNodeInfo();
   // Construct node groups for flagged nodes
   IdentifyGroups();
   
   // Test to see if scheduling should occur
-  bool ShouldSchedule = NodeCount > 3 && Heuristic != noScheduling;
+  bool ShouldSchedule = NodeCount > 3 && !NoSched;
   // Don't waste time if is only entry and return
   if (ShouldSchedule) {
     // Get latency and resource requirements
@@ -871,9 +1132,25 @@ void ScheduleDAGSimple::Schedule() {
 
 
 /// createSimpleDAGScheduler - This creates a simple two pass instruction
-/// scheduler.
-llvm::ScheduleDAG* llvm::createSimpleDAGScheduler(SchedHeuristics Heuristic,
-                                                  SelectionDAG &DAG,
+/// scheduler using instruction itinerary.
+llvm::ScheduleDAG* llvm::createSimpleDAGScheduler(SelectionDAGISel *IS,
+                                                  SelectionDAG *DAG,
                                                   MachineBasicBlock *BB) {
-  return new ScheduleDAGSimple(Heuristic, DAG, BB,  DAG.getTarget());
+  return new ScheduleDAGSimple(false, false, *DAG, BB, DAG->getTarget());
+}
+
+/// createNoItinsDAGScheduler - This creates a simple two pass instruction
+/// scheduler without using instruction itinerary.
+llvm::ScheduleDAG* llvm::createNoItinsDAGScheduler(SelectionDAGISel *IS,
+                                                   SelectionDAG *DAG,
+                                                   MachineBasicBlock *BB) {
+  return new ScheduleDAGSimple(false, true, *DAG, BB, DAG->getTarget());
+}
+
+/// createBFS_DAGScheduler - This creates a simple breadth first instruction
+/// scheduler.
+llvm::ScheduleDAG* llvm::createBFS_DAGScheduler(SelectionDAGISel *IS,
+                                                SelectionDAG *DAG,
+                                                MachineBasicBlock *BB) {
+  return new ScheduleDAGSimple(true, false, *DAG, BB,  DAG->getTarget());
 }