LLVM API Documentation

LatencyPriorityQueue.cpp
Go to the documentation of this file.
00001 //===---- LatencyPriorityQueue.cpp - A latency-oriented priority queue ----===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This file implements the LatencyPriorityQueue class, which is a
00011 // SchedulingPriorityQueue that schedules using latency information to
00012 // reduce the length of the critical path through the basic block.
00013 //
00014 //===----------------------------------------------------------------------===//
00015 
00016 #include "llvm/CodeGen/LatencyPriorityQueue.h"
00017 #include "llvm/Support/Debug.h"
00018 #include "llvm/Support/raw_ostream.h"
00019 using namespace llvm;
00020 
00021 #define DEBUG_TYPE "scheduler"
00022 
00023 bool latency_sort::operator()(const SUnit *LHS, const SUnit *RHS) const {
00024   // The isScheduleHigh flag allows nodes with wraparound dependencies that
00025   // cannot easily be modeled as edges with latencies to be scheduled as
00026   // soon as possible in a top-down schedule.
00027   if (LHS->isScheduleHigh && !RHS->isScheduleHigh)
00028     return false;
00029   if (!LHS->isScheduleHigh && RHS->isScheduleHigh)
00030     return true;
00031 
00032   unsigned LHSNum = LHS->NodeNum;
00033   unsigned RHSNum = RHS->NodeNum;
00034 
00035   // The most important heuristic is scheduling the critical path.
00036   unsigned LHSLatency = PQ->getLatency(LHSNum);
00037   unsigned RHSLatency = PQ->getLatency(RHSNum);
00038   if (LHSLatency < RHSLatency) return true;
00039   if (LHSLatency > RHSLatency) return false;
00040 
00041   // After that, if two nodes have identical latencies, look to see if one will
00042   // unblock more other nodes than the other.
00043   unsigned LHSBlocked = PQ->getNumSolelyBlockNodes(LHSNum);
00044   unsigned RHSBlocked = PQ->getNumSolelyBlockNodes(RHSNum);
00045   if (LHSBlocked < RHSBlocked) return true;
00046   if (LHSBlocked > RHSBlocked) return false;
00047 
00048   // Finally, just to provide a stable ordering, use the node number as a
00049   // deciding factor.
00050   return RHSNum < LHSNum;
00051 }
00052 
00053 
00054 /// getSingleUnscheduledPred - If there is exactly one unscheduled predecessor
00055 /// of SU, return it, otherwise return null.
00056 SUnit *LatencyPriorityQueue::getSingleUnscheduledPred(SUnit *SU) {
00057   SUnit *OnlyAvailablePred = nullptr;
00058   for (SUnit::const_pred_iterator I = SU->Preds.begin(), E = SU->Preds.end();
00059        I != E; ++I) {
00060     SUnit &Pred = *I->getSUnit();
00061     if (!Pred.isScheduled) {
00062       // We found an available, but not scheduled, predecessor.  If it's the
00063       // only one we have found, keep track of it... otherwise give up.
00064       if (OnlyAvailablePred && OnlyAvailablePred != &Pred)
00065         return nullptr;
00066       OnlyAvailablePred = &Pred;
00067     }
00068   }
00069 
00070   return OnlyAvailablePred;
00071 }
00072 
00073 void LatencyPriorityQueue::push(SUnit *SU) {
00074   // Look at all of the successors of this node.  Count the number of nodes that
00075   // this node is the sole unscheduled node for.
00076   unsigned NumNodesBlocking = 0;
00077   for (SUnit::const_succ_iterator I = SU->Succs.begin(), E = SU->Succs.end();
00078        I != E; ++I) {
00079     if (getSingleUnscheduledPred(I->getSUnit()) == SU)
00080       ++NumNodesBlocking;
00081   }
00082   NumNodesSolelyBlocking[SU->NodeNum] = NumNodesBlocking;
00083 
00084   Queue.push_back(SU);
00085 }
00086 
00087 
00088 // scheduledNode - As nodes are scheduled, we look to see if there are any
00089 // successor nodes that have a single unscheduled predecessor.  If so, that
00090 // single predecessor has a higher priority, since scheduling it will make
00091 // the node available.
00092 void LatencyPriorityQueue::scheduledNode(SUnit *SU) {
00093   for (SUnit::const_succ_iterator I = SU->Succs.begin(), E = SU->Succs.end();
00094        I != E; ++I) {
00095     AdjustPriorityOfUnscheduledPreds(I->getSUnit());
00096   }
00097 }
00098 
00099 /// AdjustPriorityOfUnscheduledPreds - One of the predecessors of SU was just
00100 /// scheduled.  If SU is not itself available, then there is at least one
00101 /// predecessor node that has not been scheduled yet.  If SU has exactly ONE
00102 /// unscheduled predecessor, we want to increase its priority: it getting
00103 /// scheduled will make this node available, so it is better than some other
00104 /// node of the same priority that will not make a node available.
00105 void LatencyPriorityQueue::AdjustPriorityOfUnscheduledPreds(SUnit *SU) {
00106   if (SU->isAvailable) return;  // All preds scheduled.
00107 
00108   SUnit *OnlyAvailablePred = getSingleUnscheduledPred(SU);
00109   if (!OnlyAvailablePred || !OnlyAvailablePred->isAvailable) return;
00110 
00111   // Okay, we found a single predecessor that is available, but not scheduled.
00112   // Since it is available, it must be in the priority queue.  First remove it.
00113   remove(OnlyAvailablePred);
00114 
00115   // Reinsert the node into the priority queue, which recomputes its
00116   // NumNodesSolelyBlocking value.
00117   push(OnlyAvailablePred);
00118 }
00119 
00120 SUnit *LatencyPriorityQueue::pop() {
00121   if (empty()) return nullptr;
00122   std::vector<SUnit *>::iterator Best = Queue.begin();
00123   for (std::vector<SUnit *>::iterator I = std::next(Queue.begin()),
00124        E = Queue.end(); I != E; ++I)
00125     if (Picker(*Best, *I))
00126       Best = I;
00127   SUnit *V = *Best;
00128   if (Best != std::prev(Queue.end()))
00129     std::swap(*Best, Queue.back());
00130   Queue.pop_back();
00131   return V;
00132 }
00133 
00134 void LatencyPriorityQueue::remove(SUnit *SU) {
00135   assert(!Queue.empty() && "Queue is empty!");
00136   std::vector<SUnit *>::iterator I = std::find(Queue.begin(), Queue.end(), SU);
00137   if (I != std::prev(Queue.end()))
00138     std::swap(*I, Queue.back());
00139   Queue.pop_back();
00140 }
00141 
00142 #ifdef NDEBUG
00143 void LatencyPriorityQueue::dump(ScheduleDAG *DAG) const {}
00144 #else
00145 void LatencyPriorityQueue::dump(ScheduleDAG *DAG) const {
00146   LatencyPriorityQueue q = *this;
00147   while (!q.empty()) {
00148     SUnit *su = q.pop();
00149     dbgs() << "Height " << su->getHeight() << ": ";
00150     su->dump(DAG);
00151   }
00152 }
00153 #endif