1f22ef01cSRoman Divacky //===---- LatencyPriorityQueue.cpp - A latency-oriented priority queue ----===//
2f22ef01cSRoman Divacky //
3f22ef01cSRoman Divacky //                     The LLVM Compiler Infrastructure
4f22ef01cSRoman Divacky //
5f22ef01cSRoman Divacky // This file is distributed under the University of Illinois Open Source
6f22ef01cSRoman Divacky // License. See LICENSE.TXT for details.
7f22ef01cSRoman Divacky //
8f22ef01cSRoman Divacky //===----------------------------------------------------------------------===//
9f22ef01cSRoman Divacky //
10f22ef01cSRoman Divacky // This file implements the LatencyPriorityQueue class, which is a
11f22ef01cSRoman Divacky // SchedulingPriorityQueue that schedules using latency information to
12f22ef01cSRoman Divacky // reduce the length of the critical path through the basic block.
13f22ef01cSRoman Divacky //
14f22ef01cSRoman Divacky //===----------------------------------------------------------------------===//
15f22ef01cSRoman Divacky 
16f22ef01cSRoman Divacky #include "llvm/CodeGen/LatencyPriorityQueue.h"
174ba319b5SDimitry Andric #include "llvm/Config/llvm-config.h"
18f22ef01cSRoman Divacky #include "llvm/Support/Debug.h"
192754fe60SDimitry Andric #include "llvm/Support/raw_ostream.h"
20f22ef01cSRoman Divacky using namespace llvm;
21f22ef01cSRoman Divacky 
2291bc56edSDimitry Andric #define DEBUG_TYPE "scheduler"
2391bc56edSDimitry Andric 
operator ()(const SUnit * LHS,const SUnit * RHS) const24f22ef01cSRoman Divacky bool latency_sort::operator()(const SUnit *LHS, const SUnit *RHS) const {
25f22ef01cSRoman Divacky   // The isScheduleHigh flag allows nodes with wraparound dependencies that
26f22ef01cSRoman Divacky   // cannot easily be modeled as edges with latencies to be scheduled as
27f22ef01cSRoman Divacky   // soon as possible in a top-down schedule.
28f22ef01cSRoman Divacky   if (LHS->isScheduleHigh && !RHS->isScheduleHigh)
29f22ef01cSRoman Divacky     return false;
30f22ef01cSRoman Divacky   if (!LHS->isScheduleHigh && RHS->isScheduleHigh)
31f22ef01cSRoman Divacky     return true;
32f22ef01cSRoman Divacky 
33f22ef01cSRoman Divacky   unsigned LHSNum = LHS->NodeNum;
34f22ef01cSRoman Divacky   unsigned RHSNum = RHS->NodeNum;
35f22ef01cSRoman Divacky 
36f22ef01cSRoman Divacky   // The most important heuristic is scheduling the critical path.
37f22ef01cSRoman Divacky   unsigned LHSLatency = PQ->getLatency(LHSNum);
38f22ef01cSRoman Divacky   unsigned RHSLatency = PQ->getLatency(RHSNum);
39f22ef01cSRoman Divacky   if (LHSLatency < RHSLatency) return true;
40f22ef01cSRoman Divacky   if (LHSLatency > RHSLatency) return false;
41f22ef01cSRoman Divacky 
42f22ef01cSRoman Divacky   // After that, if two nodes have identical latencies, look to see if one will
43f22ef01cSRoman Divacky   // unblock more other nodes than the other.
44f22ef01cSRoman Divacky   unsigned LHSBlocked = PQ->getNumSolelyBlockNodes(LHSNum);
45f22ef01cSRoman Divacky   unsigned RHSBlocked = PQ->getNumSolelyBlockNodes(RHSNum);
46f22ef01cSRoman Divacky   if (LHSBlocked < RHSBlocked) return true;
47f22ef01cSRoman Divacky   if (LHSBlocked > RHSBlocked) return false;
48f22ef01cSRoman Divacky 
49f22ef01cSRoman Divacky   // Finally, just to provide a stable ordering, use the node number as a
50f22ef01cSRoman Divacky   // deciding factor.
51dff0c46cSDimitry Andric   return RHSNum < LHSNum;
52f22ef01cSRoman Divacky }
53f22ef01cSRoman Divacky 
54f22ef01cSRoman Divacky 
55f22ef01cSRoman Divacky /// getSingleUnscheduledPred - If there is exactly one unscheduled predecessor
56f22ef01cSRoman Divacky /// of SU, return it, otherwise return null.
getSingleUnscheduledPred(SUnit * SU)57f22ef01cSRoman Divacky SUnit *LatencyPriorityQueue::getSingleUnscheduledPred(SUnit *SU) {
5891bc56edSDimitry Andric   SUnit *OnlyAvailablePred = nullptr;
59f22ef01cSRoman Divacky   for (SUnit::const_pred_iterator I = SU->Preds.begin(), E = SU->Preds.end();
60f22ef01cSRoman Divacky        I != E; ++I) {
61f22ef01cSRoman Divacky     SUnit &Pred = *I->getSUnit();
62f22ef01cSRoman Divacky     if (!Pred.isScheduled) {
63f22ef01cSRoman Divacky       // We found an available, but not scheduled, predecessor.  If it's the
64f22ef01cSRoman Divacky       // only one we have found, keep track of it... otherwise give up.
65f22ef01cSRoman Divacky       if (OnlyAvailablePred && OnlyAvailablePred != &Pred)
6691bc56edSDimitry Andric         return nullptr;
67f22ef01cSRoman Divacky       OnlyAvailablePred = &Pred;
68f22ef01cSRoman Divacky     }
69f22ef01cSRoman Divacky   }
70f22ef01cSRoman Divacky 
71f22ef01cSRoman Divacky   return OnlyAvailablePred;
72f22ef01cSRoman Divacky }
73f22ef01cSRoman Divacky 
push(SUnit * SU)74f22ef01cSRoman Divacky void LatencyPriorityQueue::push(SUnit *SU) {
75f22ef01cSRoman Divacky   // Look at all of the successors of this node.  Count the number of nodes that
76f22ef01cSRoman Divacky   // this node is the sole unscheduled node for.
77f22ef01cSRoman Divacky   unsigned NumNodesBlocking = 0;
78f22ef01cSRoman Divacky   for (SUnit::const_succ_iterator I = SU->Succs.begin(), E = SU->Succs.end();
79f22ef01cSRoman Divacky        I != E; ++I) {
80f22ef01cSRoman Divacky     if (getSingleUnscheduledPred(I->getSUnit()) == SU)
81f22ef01cSRoman Divacky       ++NumNodesBlocking;
82f22ef01cSRoman Divacky   }
83f22ef01cSRoman Divacky   NumNodesSolelyBlocking[SU->NodeNum] = NumNodesBlocking;
84f22ef01cSRoman Divacky 
85f22ef01cSRoman Divacky   Queue.push_back(SU);
86f22ef01cSRoman Divacky }
87f22ef01cSRoman Divacky 
88f22ef01cSRoman Divacky 
89dff0c46cSDimitry Andric // scheduledNode - As nodes are scheduled, we look to see if there are any
90f22ef01cSRoman Divacky // successor nodes that have a single unscheduled predecessor.  If so, that
91f22ef01cSRoman Divacky // single predecessor has a higher priority, since scheduling it will make
92f22ef01cSRoman Divacky // the node available.
scheduledNode(SUnit * SU)93dff0c46cSDimitry Andric void LatencyPriorityQueue::scheduledNode(SUnit *SU) {
94f22ef01cSRoman Divacky   for (SUnit::const_succ_iterator I = SU->Succs.begin(), E = SU->Succs.end();
95f22ef01cSRoman Divacky        I != E; ++I) {
96f22ef01cSRoman Divacky     AdjustPriorityOfUnscheduledPreds(I->getSUnit());
97f22ef01cSRoman Divacky   }
98f22ef01cSRoman Divacky }
99f22ef01cSRoman Divacky 
100f22ef01cSRoman Divacky /// AdjustPriorityOfUnscheduledPreds - One of the predecessors of SU was just
101f22ef01cSRoman Divacky /// scheduled.  If SU is not itself available, then there is at least one
102f22ef01cSRoman Divacky /// predecessor node that has not been scheduled yet.  If SU has exactly ONE
103f22ef01cSRoman Divacky /// unscheduled predecessor, we want to increase its priority: it getting
104f22ef01cSRoman Divacky /// scheduled will make this node available, so it is better than some other
105f22ef01cSRoman Divacky /// node of the same priority that will not make a node available.
AdjustPriorityOfUnscheduledPreds(SUnit * SU)106f22ef01cSRoman Divacky void LatencyPriorityQueue::AdjustPriorityOfUnscheduledPreds(SUnit *SU) {
107f22ef01cSRoman Divacky   if (SU->isAvailable) return;  // All preds scheduled.
108f22ef01cSRoman Divacky 
109f22ef01cSRoman Divacky   SUnit *OnlyAvailablePred = getSingleUnscheduledPred(SU);
11091bc56edSDimitry Andric   if (!OnlyAvailablePred || !OnlyAvailablePred->isAvailable) return;
111f22ef01cSRoman Divacky 
112f22ef01cSRoman Divacky   // Okay, we found a single predecessor that is available, but not scheduled.
113f22ef01cSRoman Divacky   // Since it is available, it must be in the priority queue.  First remove it.
114f22ef01cSRoman Divacky   remove(OnlyAvailablePred);
115f22ef01cSRoman Divacky 
116f22ef01cSRoman Divacky   // Reinsert the node into the priority queue, which recomputes its
117f22ef01cSRoman Divacky   // NumNodesSolelyBlocking value.
118f22ef01cSRoman Divacky   push(OnlyAvailablePred);
119f22ef01cSRoman Divacky }
120f22ef01cSRoman Divacky 
pop()121f22ef01cSRoman Divacky SUnit *LatencyPriorityQueue::pop() {
12291bc56edSDimitry Andric   if (empty()) return nullptr;
123f22ef01cSRoman Divacky   std::vector<SUnit *>::iterator Best = Queue.begin();
12491bc56edSDimitry Andric   for (std::vector<SUnit *>::iterator I = std::next(Queue.begin()),
125f22ef01cSRoman Divacky        E = Queue.end(); I != E; ++I)
126f22ef01cSRoman Divacky     if (Picker(*Best, *I))
127f22ef01cSRoman Divacky       Best = I;
128f22ef01cSRoman Divacky   SUnit *V = *Best;
12991bc56edSDimitry Andric   if (Best != std::prev(Queue.end()))
130f22ef01cSRoman Divacky     std::swap(*Best, Queue.back());
131f22ef01cSRoman Divacky   Queue.pop_back();
132f22ef01cSRoman Divacky   return V;
133f22ef01cSRoman Divacky }
134f22ef01cSRoman Divacky 
remove(SUnit * SU)135f22ef01cSRoman Divacky void LatencyPriorityQueue::remove(SUnit *SU) {
136f22ef01cSRoman Divacky   assert(!Queue.empty() && "Queue is empty!");
137d88c1a5aSDimitry Andric   std::vector<SUnit *>::iterator I = find(Queue, SU);
1382cab237bSDimitry Andric   assert(I != Queue.end() && "Queue doesn't contain the SU being removed!");
13991bc56edSDimitry Andric   if (I != std::prev(Queue.end()))
140f22ef01cSRoman Divacky     std::swap(*I, Queue.back());
141f22ef01cSRoman Divacky   Queue.pop_back();
142f22ef01cSRoman Divacky }
1434ba319b5SDimitry Andric 
1444ba319b5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump(ScheduleDAG * DAG) const1454ba319b5SDimitry Andric LLVM_DUMP_METHOD void LatencyPriorityQueue::dump(ScheduleDAG *DAG) const {
1464ba319b5SDimitry Andric   dbgs() << "Latency Priority Queue\n";
1474ba319b5SDimitry Andric   dbgs() << "  Number of Queue Entries: " << Queue.size() << "\n";
148*b5893f02SDimitry Andric   for (const SUnit *SU : Queue) {
1494ba319b5SDimitry Andric     dbgs() << "    ";
150*b5893f02SDimitry Andric     DAG->dumpNode(*SU);
1514ba319b5SDimitry Andric   }
1524ba319b5SDimitry Andric }
1534ba319b5SDimitry Andric #endif
154