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

Chris Lattner lattner at cs.uiuc.edu
Sat Mar 11 16:39:09 PST 2006



Changes in directory llvm/lib/CodeGen/SelectionDAG:

ScheduleDAGList.cpp updated: 1.45 -> 1.46
---
Log message:

As a pending queue data structure to keep track of instructions whose 
operands have all issued, but whose results are not yet available.  This
allows us to compile:

int G;
int test(int A, int B, int* P) {
   return (G+A)*(B+1);
}

to:

_test:
        lis r2, ha16(L_G$non_lazy_ptr)
        addi r4, r4, 1
        lwz r2, lo16(L_G$non_lazy_ptr)(r2)
        lwz r2, 0(r2)
        add r2, r2, r3
        mullw r3, r2, r4
        blr

instead of this, which has a stall between the lis/lwz:

_test:
        lis r2, ha16(L_G$non_lazy_ptr)
        lwz r2, lo16(L_G$non_lazy_ptr)(r2)
        addi r4, r4, 1
        lwz r2, 0(r2)
        add r2, r2, r3
        mullw r3, r2, r4
        blr



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

 ScheduleDAGList.cpp |   98 ++++++++++++++++++++++++++++++++--------------------
 1 files changed, 62 insertions(+), 36 deletions(-)


Index: llvm/lib/CodeGen/SelectionDAG/ScheduleDAGList.cpp
diff -u llvm/lib/CodeGen/SelectionDAG/ScheduleDAGList.cpp:1.45 llvm/lib/CodeGen/SelectionDAG/ScheduleDAGList.cpp:1.46
--- llvm/lib/CodeGen/SelectionDAG/ScheduleDAGList.cpp:1.45	Sat Mar 11 16:44:37 2006
+++ llvm/lib/CodeGen/SelectionDAG/ScheduleDAGList.cpp	Sat Mar 11 18:38:57 2006
@@ -53,6 +53,7 @@
     short NumChainSuccsLeft;            // # of chain succs not scheduled.
     bool isTwoAddress     : 1;          // Is a two-address instruction.
     bool isDefNUseOperand : 1;          // Is a def&use operand.
+    bool isPending        : 1;          // True once pending.
     bool isAvailable      : 1;          // True once available.
     bool isScheduled      : 1;          // True once scheduled.
     unsigned short Latency;             // Node latency.
@@ -64,7 +65,7 @@
       : Node(node), NumPredsLeft(0), NumSuccsLeft(0),
       NumChainPredsLeft(0), NumChainSuccsLeft(0),
       isTwoAddress(false), isDefNUseOperand(false),
-      isAvailable(false), isScheduled(false), 
+      isPending(false), isAvailable(false), isScheduled(false), 
       Latency(0), CycleBound(0), Cycle(0), NodeNum(nodenum) {}
     
     void dump(const SelectionDAG *G) const;
@@ -173,6 +174,13 @@
   ///
   SchedulingPriorityQueue *AvailableQueue;
   
+  /// PendingQueue - This contains all of the instructions whose operands have
+  /// been issued, but their results are not ready yet (due to the latency of
+  /// the operation).  Once the operands becomes available, the instruction is
+  /// added to the AvailableQueue.  This keeps track of each SUnit and the
+  /// number of cycles left to execute before the operation is available.
+  std::vector<std::pair<unsigned, SUnit*> > PendingQueue;
+  
   /// HazardRec - The hazard recognizer to use.
   HazardRecognizer *HazardRec;
   
@@ -197,7 +205,7 @@
 private:
   SUnit *NewSUnit(SDNode *N);
   void ReleasePred(SUnit *PredSU, bool isChain, unsigned CurCycle);
-  void ReleaseSucc(SUnit *SuccSU, bool isChain, unsigned CurCycle);
+  void ReleaseSucc(SUnit *SuccSU, bool isChain);
   void ScheduleNodeBottomUp(SUnit *SU, unsigned CurCycle);
   void ScheduleNodeTopDown(SUnit *SU, unsigned CurCycle);
   void ListScheduleTopDown();
@@ -445,7 +453,7 @@
 /// count of its predecessors. If a predecessor pending count is zero, add it to
 /// the Available queue.
 void ScheduleDAGList::ScheduleNodeBottomUp(SUnit *SU, unsigned CurCycle) {
-  DEBUG(std::cerr << "*** Scheduling: ");
+  DEBUG(std::cerr << "*** Scheduling [" << CurCycle << "]: ");
   DEBUG(SU->dump(&DAG));
   SU->Cycle = CurCycle;
 
@@ -527,32 +535,29 @@
 //===----------------------------------------------------------------------===//
 
 /// ReleaseSucc - Decrement the NumPredsLeft count of a successor. Add it to
-/// the Available queue is the count reaches zero. Also update its cycle bound.
-void ScheduleDAGList::ReleaseSucc(SUnit *SuccSU, bool isChain,
-                                  unsigned CurCycle) {
-  // FIXME: the distance between two nodes is not always == the predecessor's
-  // latency. For example, the reader can very well read the register written
-  // by the predecessor later than the issue cycle. It also depends on the
-  // interrupt model (drain vs. freeze).
-  SuccSU->CycleBound = std::max(SuccSU->CycleBound, CurCycle + SuccSU->Latency);
-  
+/// the PendingQueue if the count reaches zero.
+void ScheduleDAGList::ReleaseSucc(SUnit *SuccSU, bool isChain) {
   if (!isChain)
     SuccSU->NumPredsLeft--;
   else
     SuccSU->NumChainPredsLeft--;
   
-#ifndef NDEBUG
-  if (SuccSU->NumPredsLeft < 0 || SuccSU->NumChainPredsLeft < 0) {
-    std::cerr << "*** List scheduling failed! ***\n";
-    SuccSU->dump(&DAG);
-    std::cerr << " has been released too many times!\n";
-    abort();
-  }
-#endif
+  assert(SuccSU->NumPredsLeft >= 0 && SuccSU->NumChainPredsLeft >= 0 &&
+         "List scheduling internal error");
   
   if ((SuccSU->NumPredsLeft + SuccSU->NumChainPredsLeft) == 0) {
-    SuccSU->isAvailable = true;
-    AvailableQueue->push(SuccSU);
+    // Compute how many cycles it will be before this actually becomes
+    // available.  This is the max of the start time of all predecessors plus
+    // their latencies.
+    unsigned AvailableCycle = 0;
+    for (std::set<std::pair<SUnit*, bool> >::iterator I = SuccSU->Preds.begin(),
+         E = SuccSU->Preds.end(); I != E; ++I) {
+      AvailableCycle = std::max(AvailableCycle, 
+                                I->first->Cycle + I->first->Latency);
+    }
+    
+    PendingQueue.push_back(std::make_pair(AvailableCycle, SuccSU));
+    SuccSU->isPending = true;
   }
 }
 
@@ -560,7 +565,7 @@
 /// count of its successors. If a successor pending count is zero, add it to
 /// the Available queue.
 void ScheduleDAGList::ScheduleNodeTopDown(SUnit *SU, unsigned CurCycle) {
-  DEBUG(std::cerr << "*** Scheduling: ");
+  DEBUG(std::cerr << "*** Scheduling [" << CurCycle << "]: ");
   DEBUG(SU->dump(&DAG));
   
   Sequence.push_back(SU);
@@ -569,33 +574,49 @@
   // Bottom up: release successors.
   for (std::set<std::pair<SUnit*, bool> >::iterator I = SU->Succs.begin(),
        E = SU->Succs.end(); I != E; ++I)
-    ReleaseSucc(I->first, I->second, CurCycle);
+    ReleaseSucc(I->first, I->second);
 }
 
 /// ListScheduleTopDown - The main loop of list scheduling for top-down
 /// schedulers.
 void ScheduleDAGList::ListScheduleTopDown() {
-  unsigned CurrCycle = 0;
-  // Emit the entry node first.
+  unsigned CurCycle = 0;
   SUnit *Entry = SUnitMap[DAG.getEntryNode().Val];
-  ScheduleNodeTopDown(Entry, CurrCycle);
-  HazardRec->EmitInstruction(Entry->Node);
-                      
+
   // All leaves to Available queue.
   for (unsigned i = 0, e = SUnits.size(); i != e; ++i) {
     // It is available if it has no predecessors.
-    if (SUnits[i].Preds.size() == 0 && &SUnits[i] != Entry)
+    if (SUnits[i].Preds.size() == 0 && &SUnits[i] != Entry) {
       AvailableQueue->push(&SUnits[i]);
+      SUnits[i].isAvailable = SUnits[i].isPending = true;
+    }
   }
   
+  // Emit the entry node first.
+  ScheduleNodeTopDown(Entry, CurCycle);
+  HazardRec->EmitInstruction(Entry->Node);
+  
   // While Available queue is not empty, grab the node with the highest
   // priority. If it is not ready put it back.  Schedule the node.
   std::vector<SUnit*> NotReady;
-  while (!AvailableQueue->empty()) {
+  while (!AvailableQueue->empty() || !PendingQueue.empty()) {
+    // Check to see if any of the pending instructions are ready to issue.  If
+    // so, add them to the available queue.
+    for (unsigned i = 0, e = PendingQueue.size(); i != e; ++i)
+      if (PendingQueue[i].first == CurCycle) {
+        AvailableQueue->push(PendingQueue[i].second);
+        PendingQueue[i].second->isAvailable = true;
+        PendingQueue[i] = PendingQueue.back();
+        PendingQueue.pop_back();
+        --i; --e;
+      } else {
+        assert(PendingQueue[i].first > CurCycle && "Negative latency?");
+      }
+    
     SUnit *FoundNode = 0;
 
     bool HasNoopHazards = false;
-    do {
+    while (!AvailableQueue->empty()) {
       SUnit *CurNode = AvailableQueue->pop();
       
       // Get the node represented by this SUnit.
@@ -616,7 +637,7 @@
       HasNoopHazards |= HT == HazardRecognizer::NoopHazard;
       
       NotReady.push_back(CurNode);
-    } while (!AvailableQueue->empty());
+    }
     
     // Add the nodes that aren't ready back onto the available list.
     AvailableQueue->push_all(NotReady);
@@ -624,11 +645,15 @@
 
     // If we found a node to schedule, do it now.
     if (FoundNode) {
-      ScheduleNodeTopDown(FoundNode, CurrCycle);
-      CurrCycle++;   // Fixme don't increment for pseudo-ops!
+      ScheduleNodeTopDown(FoundNode, CurCycle);
       HazardRec->EmitInstruction(FoundNode->Node);
       FoundNode->isScheduled = true;
       AvailableQueue->ScheduledNode(FoundNode);
+
+      // If this is a pseudo-op node, we don't want to increment the current
+      // cycle.
+      if (FoundNode->Latency == 0)
+        continue;   // Don't increment for pseudo-ops!
     } else if (!HasNoopHazards) {
       // Otherwise, we have a pipeline stall, but no other problem, just advance
       // the current cycle and try again.
@@ -644,6 +669,7 @@
       Sequence.push_back(0);   // NULL SUnit* -> noop
       ++NumNoops;
     }
+    ++CurCycle;
   }
 
 #ifndef NDEBUG
@@ -1017,7 +1043,7 @@
 /// scheduled will make this node available, so it is better than some other
 /// node of the same priority that will not make a node available.
 void LatencyPriorityQueue::AdjustPriorityOfUnscheduledPreds(SUnit *SU) {
-  if (SU->isAvailable) return;  // All preds scheduled.
+  if (SU->isPending) return;  // All preds scheduled.
   
   SUnit *OnlyAvailablePred = getSingleUnscheduledPred(SU);
   if (OnlyAvailablePred == 0 || !OnlyAvailablePred->isAvailable) return;






More information about the llvm-commits mailing list