xref: /freebsd/contrib/llvm-project/llvm/lib/Target/AMDGPU/GCNILPSched.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===---------------------------- GCNILPSched.cpp - -----------------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric //
9*0b57cec5SDimitry Andric /// \file
10*0b57cec5SDimitry Andric //
11*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
12*0b57cec5SDimitry Andric 
13*0b57cec5SDimitry Andric #include "llvm/CodeGen/ScheduleDAG.h"
14*0b57cec5SDimitry Andric 
15*0b57cec5SDimitry Andric using namespace llvm;
16*0b57cec5SDimitry Andric 
17*0b57cec5SDimitry Andric #define DEBUG_TYPE "machine-scheduler"
18*0b57cec5SDimitry Andric 
19*0b57cec5SDimitry Andric namespace {
20*0b57cec5SDimitry Andric 
21*0b57cec5SDimitry Andric class GCNILPScheduler {
22*0b57cec5SDimitry Andric   struct Candidate : ilist_node<Candidate> {
23*0b57cec5SDimitry Andric     SUnit *SU;
24*0b57cec5SDimitry Andric 
25*0b57cec5SDimitry Andric     Candidate(SUnit *SU_)
26*0b57cec5SDimitry Andric       : SU(SU_) {}
27*0b57cec5SDimitry Andric   };
28*0b57cec5SDimitry Andric 
29*0b57cec5SDimitry Andric   SpecificBumpPtrAllocator<Candidate> Alloc;
30*0b57cec5SDimitry Andric   typedef simple_ilist<Candidate> Queue;
31*0b57cec5SDimitry Andric   Queue PendingQueue;
32*0b57cec5SDimitry Andric   Queue AvailQueue;
33*0b57cec5SDimitry Andric   unsigned CurQueueId = 0;
34*0b57cec5SDimitry Andric 
35*0b57cec5SDimitry Andric   std::vector<unsigned> SUNumbers;
36*0b57cec5SDimitry Andric 
37*0b57cec5SDimitry Andric   /// CurCycle - The current scheduler state corresponds to this cycle.
38*0b57cec5SDimitry Andric   unsigned CurCycle = 0;
39*0b57cec5SDimitry Andric 
40*0b57cec5SDimitry Andric   unsigned getNodePriority(const SUnit *SU) const;
41*0b57cec5SDimitry Andric 
42*0b57cec5SDimitry Andric   const SUnit *pickBest(const SUnit *left, const SUnit *right);
43*0b57cec5SDimitry Andric   Candidate* pickCandidate();
44*0b57cec5SDimitry Andric 
45*0b57cec5SDimitry Andric   void releasePending();
46*0b57cec5SDimitry Andric   void advanceToCycle(unsigned NextCycle);
47*0b57cec5SDimitry Andric   void releasePredecessors(const SUnit* SU);
48*0b57cec5SDimitry Andric 
49*0b57cec5SDimitry Andric public:
50*0b57cec5SDimitry Andric   std::vector<const SUnit*> schedule(ArrayRef<const SUnit*> TopRoots,
51*0b57cec5SDimitry Andric                                      const ScheduleDAG &DAG);
52*0b57cec5SDimitry Andric };
53*0b57cec5SDimitry Andric } // namespace
54*0b57cec5SDimitry Andric 
55*0b57cec5SDimitry Andric /// CalcNodeSethiUllmanNumber - Compute Sethi Ullman number.
56*0b57cec5SDimitry Andric /// Smaller number is the higher priority.
57*0b57cec5SDimitry Andric static unsigned
58*0b57cec5SDimitry Andric CalcNodeSethiUllmanNumber(const SUnit *SU, std::vector<unsigned> &SUNumbers) {
59*0b57cec5SDimitry Andric   unsigned &SethiUllmanNumber = SUNumbers[SU->NodeNum];
60*0b57cec5SDimitry Andric   if (SethiUllmanNumber != 0)
61*0b57cec5SDimitry Andric     return SethiUllmanNumber;
62*0b57cec5SDimitry Andric 
63*0b57cec5SDimitry Andric   unsigned Extra = 0;
64*0b57cec5SDimitry Andric   for (const SDep &Pred : SU->Preds) {
65*0b57cec5SDimitry Andric     if (Pred.isCtrl()) continue;  // ignore chain preds
66*0b57cec5SDimitry Andric     SUnit *PredSU = Pred.getSUnit();
67*0b57cec5SDimitry Andric     unsigned PredSethiUllman = CalcNodeSethiUllmanNumber(PredSU, SUNumbers);
68*0b57cec5SDimitry Andric     if (PredSethiUllman > SethiUllmanNumber) {
69*0b57cec5SDimitry Andric       SethiUllmanNumber = PredSethiUllman;
70*0b57cec5SDimitry Andric       Extra = 0;
71*0b57cec5SDimitry Andric     }
72*0b57cec5SDimitry Andric     else if (PredSethiUllman == SethiUllmanNumber)
73*0b57cec5SDimitry Andric       ++Extra;
74*0b57cec5SDimitry Andric   }
75*0b57cec5SDimitry Andric 
76*0b57cec5SDimitry Andric   SethiUllmanNumber += Extra;
77*0b57cec5SDimitry Andric 
78*0b57cec5SDimitry Andric   if (SethiUllmanNumber == 0)
79*0b57cec5SDimitry Andric     SethiUllmanNumber = 1;
80*0b57cec5SDimitry Andric 
81*0b57cec5SDimitry Andric   return SethiUllmanNumber;
82*0b57cec5SDimitry Andric }
83*0b57cec5SDimitry Andric 
84*0b57cec5SDimitry Andric // Lower priority means schedule further down. For bottom-up scheduling, lower
85*0b57cec5SDimitry Andric // priority SUs are scheduled before higher priority SUs.
86*0b57cec5SDimitry Andric unsigned GCNILPScheduler::getNodePriority(const SUnit *SU) const {
87*0b57cec5SDimitry Andric   assert(SU->NodeNum < SUNumbers.size());
88*0b57cec5SDimitry Andric   if (SU->NumSuccs == 0 && SU->NumPreds != 0)
89*0b57cec5SDimitry Andric     // If SU does not have a register use, i.e. it doesn't produce a value
90*0b57cec5SDimitry Andric     // that would be consumed (e.g. store), then it terminates a chain of
91*0b57cec5SDimitry Andric     // computation.  Give it a large SethiUllman number so it will be
92*0b57cec5SDimitry Andric     // scheduled right before its predecessors that it doesn't lengthen
93*0b57cec5SDimitry Andric     // their live ranges.
94*0b57cec5SDimitry Andric     return 0xffff;
95*0b57cec5SDimitry Andric 
96*0b57cec5SDimitry Andric   if (SU->NumPreds == 0 && SU->NumSuccs != 0)
97*0b57cec5SDimitry Andric     // If SU does not have a register def, schedule it close to its uses
98*0b57cec5SDimitry Andric     // because it does not lengthen any live ranges.
99*0b57cec5SDimitry Andric     return 0;
100*0b57cec5SDimitry Andric 
101*0b57cec5SDimitry Andric   return SUNumbers[SU->NodeNum];
102*0b57cec5SDimitry Andric }
103*0b57cec5SDimitry Andric 
104*0b57cec5SDimitry Andric /// closestSucc - Returns the scheduled cycle of the successor which is
105*0b57cec5SDimitry Andric /// closest to the current cycle.
106*0b57cec5SDimitry Andric static unsigned closestSucc(const SUnit *SU) {
107*0b57cec5SDimitry Andric   unsigned MaxHeight = 0;
108*0b57cec5SDimitry Andric   for (const SDep &Succ : SU->Succs) {
109*0b57cec5SDimitry Andric     if (Succ.isCtrl()) continue;  // ignore chain succs
110*0b57cec5SDimitry Andric     unsigned Height = Succ.getSUnit()->getHeight();
111*0b57cec5SDimitry Andric     // If there are bunch of CopyToRegs stacked up, they should be considered
112*0b57cec5SDimitry Andric     // to be at the same position.
113*0b57cec5SDimitry Andric     if (Height > MaxHeight)
114*0b57cec5SDimitry Andric       MaxHeight = Height;
115*0b57cec5SDimitry Andric   }
116*0b57cec5SDimitry Andric   return MaxHeight;
117*0b57cec5SDimitry Andric }
118*0b57cec5SDimitry Andric 
119*0b57cec5SDimitry Andric /// calcMaxScratches - Returns an cost estimate of the worse case requirement
120*0b57cec5SDimitry Andric /// for scratch registers, i.e. number of data dependencies.
121*0b57cec5SDimitry Andric static unsigned calcMaxScratches(const SUnit *SU) {
122*0b57cec5SDimitry Andric   unsigned Scratches = 0;
123*0b57cec5SDimitry Andric   for (const SDep &Pred : SU->Preds) {
124*0b57cec5SDimitry Andric     if (Pred.isCtrl()) continue;  // ignore chain preds
125*0b57cec5SDimitry Andric     Scratches++;
126*0b57cec5SDimitry Andric   }
127*0b57cec5SDimitry Andric   return Scratches;
128*0b57cec5SDimitry Andric }
129*0b57cec5SDimitry Andric 
130*0b57cec5SDimitry Andric // Return -1 if left has higher priority, 1 if right has higher priority.
131*0b57cec5SDimitry Andric // Return 0 if latency-based priority is equivalent.
132*0b57cec5SDimitry Andric static int BUCompareLatency(const SUnit *left, const SUnit *right) {
133*0b57cec5SDimitry Andric   // Scheduling an instruction that uses a VReg whose postincrement has not yet
134*0b57cec5SDimitry Andric   // been scheduled will induce a copy. Model this as an extra cycle of latency.
135*0b57cec5SDimitry Andric   int LHeight = (int)left->getHeight();
136*0b57cec5SDimitry Andric   int RHeight = (int)right->getHeight();
137*0b57cec5SDimitry Andric 
138*0b57cec5SDimitry Andric   // If either node is scheduling for latency, sort them by height/depth
139*0b57cec5SDimitry Andric   // and latency.
140*0b57cec5SDimitry Andric 
141*0b57cec5SDimitry Andric   // If neither instruction stalls (!LStall && !RStall) and HazardRecognizer
142*0b57cec5SDimitry Andric   // is enabled, grouping instructions by cycle, then its height is already
143*0b57cec5SDimitry Andric   // covered so only its depth matters. We also reach this point if both stall
144*0b57cec5SDimitry Andric   // but have the same height.
145*0b57cec5SDimitry Andric   if (LHeight != RHeight)
146*0b57cec5SDimitry Andric     return LHeight > RHeight ? 1 : -1;
147*0b57cec5SDimitry Andric 
148*0b57cec5SDimitry Andric   int LDepth = left->getDepth();
149*0b57cec5SDimitry Andric   int RDepth = right->getDepth();
150*0b57cec5SDimitry Andric   if (LDepth != RDepth) {
151*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "  Comparing latency of SU (" << left->NodeNum
152*0b57cec5SDimitry Andric                       << ") depth " << LDepth << " vs SU (" << right->NodeNum
153*0b57cec5SDimitry Andric                       << ") depth " << RDepth << "\n");
154*0b57cec5SDimitry Andric     return LDepth < RDepth ? 1 : -1;
155*0b57cec5SDimitry Andric   }
156*0b57cec5SDimitry Andric   if (left->Latency != right->Latency)
157*0b57cec5SDimitry Andric     return left->Latency > right->Latency ? 1 : -1;
158*0b57cec5SDimitry Andric 
159*0b57cec5SDimitry Andric   return 0;
160*0b57cec5SDimitry Andric }
161*0b57cec5SDimitry Andric 
162*0b57cec5SDimitry Andric const SUnit *GCNILPScheduler::pickBest(const SUnit *left, const SUnit *right)
163*0b57cec5SDimitry Andric {
164*0b57cec5SDimitry Andric   // TODO: add register pressure lowering checks
165*0b57cec5SDimitry Andric 
166*0b57cec5SDimitry Andric   bool const DisableSchedCriticalPath = false;
167*0b57cec5SDimitry Andric   int MaxReorderWindow = 6;
168*0b57cec5SDimitry Andric   if (!DisableSchedCriticalPath) {
169*0b57cec5SDimitry Andric     int spread = (int)left->getDepth() - (int)right->getDepth();
170*0b57cec5SDimitry Andric     if (std::abs(spread) > MaxReorderWindow) {
171*0b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "Depth of SU(" << left->NodeNum << "): "
172*0b57cec5SDimitry Andric                         << left->getDepth() << " != SU(" << right->NodeNum
173*0b57cec5SDimitry Andric                         << "): " << right->getDepth() << "\n");
174*0b57cec5SDimitry Andric       return left->getDepth() < right->getDepth() ? right : left;
175*0b57cec5SDimitry Andric     }
176*0b57cec5SDimitry Andric   }
177*0b57cec5SDimitry Andric 
178*0b57cec5SDimitry Andric   bool const DisableSchedHeight = false;
179*0b57cec5SDimitry Andric   if (!DisableSchedHeight && left->getHeight() != right->getHeight()) {
180*0b57cec5SDimitry Andric     int spread = (int)left->getHeight() - (int)right->getHeight();
181*0b57cec5SDimitry Andric     if (std::abs(spread) > MaxReorderWindow)
182*0b57cec5SDimitry Andric       return left->getHeight() > right->getHeight() ? right : left;
183*0b57cec5SDimitry Andric   }
184*0b57cec5SDimitry Andric 
185*0b57cec5SDimitry Andric   // Prioritize by Sethi-Ulmann number and push CopyToReg nodes down.
186*0b57cec5SDimitry Andric   unsigned LPriority = getNodePriority(left);
187*0b57cec5SDimitry Andric   unsigned RPriority = getNodePriority(right);
188*0b57cec5SDimitry Andric 
189*0b57cec5SDimitry Andric   if (LPriority != RPriority)
190*0b57cec5SDimitry Andric     return LPriority > RPriority ? right : left;
191*0b57cec5SDimitry Andric 
192*0b57cec5SDimitry Andric   // Try schedule def + use closer when Sethi-Ullman numbers are the same.
193*0b57cec5SDimitry Andric   // e.g.
194*0b57cec5SDimitry Andric   // t1 = op t2, c1
195*0b57cec5SDimitry Andric   // t3 = op t4, c2
196*0b57cec5SDimitry Andric   //
197*0b57cec5SDimitry Andric   // and the following instructions are both ready.
198*0b57cec5SDimitry Andric   // t2 = op c3
199*0b57cec5SDimitry Andric   // t4 = op c4
200*0b57cec5SDimitry Andric   //
201*0b57cec5SDimitry Andric   // Then schedule t2 = op first.
202*0b57cec5SDimitry Andric   // i.e.
203*0b57cec5SDimitry Andric   // t4 = op c4
204*0b57cec5SDimitry Andric   // t2 = op c3
205*0b57cec5SDimitry Andric   // t1 = op t2, c1
206*0b57cec5SDimitry Andric   // t3 = op t4, c2
207*0b57cec5SDimitry Andric   //
208*0b57cec5SDimitry Andric   // This creates more short live intervals.
209*0b57cec5SDimitry Andric   unsigned LDist = closestSucc(left);
210*0b57cec5SDimitry Andric   unsigned RDist = closestSucc(right);
211*0b57cec5SDimitry Andric   if (LDist != RDist)
212*0b57cec5SDimitry Andric     return LDist < RDist ? right : left;
213*0b57cec5SDimitry Andric 
214*0b57cec5SDimitry Andric   // How many registers becomes live when the node is scheduled.
215*0b57cec5SDimitry Andric   unsigned LScratch = calcMaxScratches(left);
216*0b57cec5SDimitry Andric   unsigned RScratch = calcMaxScratches(right);
217*0b57cec5SDimitry Andric   if (LScratch != RScratch)
218*0b57cec5SDimitry Andric     return LScratch > RScratch ? right : left;
219*0b57cec5SDimitry Andric 
220*0b57cec5SDimitry Andric   bool const DisableSchedCycles = false;
221*0b57cec5SDimitry Andric   if (!DisableSchedCycles) {
222*0b57cec5SDimitry Andric     int result = BUCompareLatency(left, right);
223*0b57cec5SDimitry Andric     if (result != 0)
224*0b57cec5SDimitry Andric       return result > 0 ? right : left;
225*0b57cec5SDimitry Andric     return left;
226*0b57cec5SDimitry Andric   }
227*0b57cec5SDimitry Andric   else {
228*0b57cec5SDimitry Andric     if (left->getHeight() != right->getHeight())
229*0b57cec5SDimitry Andric       return (left->getHeight() > right->getHeight()) ? right : left;
230*0b57cec5SDimitry Andric 
231*0b57cec5SDimitry Andric     if (left->getDepth() != right->getDepth())
232*0b57cec5SDimitry Andric       return (left->getDepth() < right->getDepth()) ? right : left;
233*0b57cec5SDimitry Andric   }
234*0b57cec5SDimitry Andric 
235*0b57cec5SDimitry Andric   assert(left->NodeQueueId && right->NodeQueueId &&
236*0b57cec5SDimitry Andric         "NodeQueueId cannot be zero");
237*0b57cec5SDimitry Andric   return (left->NodeQueueId > right->NodeQueueId) ? right : left;
238*0b57cec5SDimitry Andric }
239*0b57cec5SDimitry Andric 
240*0b57cec5SDimitry Andric GCNILPScheduler::Candidate* GCNILPScheduler::pickCandidate() {
241*0b57cec5SDimitry Andric   if (AvailQueue.empty())
242*0b57cec5SDimitry Andric     return nullptr;
243*0b57cec5SDimitry Andric   auto Best = AvailQueue.begin();
244*0b57cec5SDimitry Andric   for (auto I = std::next(AvailQueue.begin()), E = AvailQueue.end(); I != E; ++I) {
245*0b57cec5SDimitry Andric     auto NewBestSU = pickBest(Best->SU, I->SU);
246*0b57cec5SDimitry Andric     if (NewBestSU != Best->SU) {
247*0b57cec5SDimitry Andric       assert(NewBestSU == I->SU);
248*0b57cec5SDimitry Andric       Best = I;
249*0b57cec5SDimitry Andric     }
250*0b57cec5SDimitry Andric   }
251*0b57cec5SDimitry Andric   return &*Best;
252*0b57cec5SDimitry Andric }
253*0b57cec5SDimitry Andric 
254*0b57cec5SDimitry Andric void GCNILPScheduler::releasePending() {
255*0b57cec5SDimitry Andric   // Check to see if any of the pending instructions are ready to issue.  If
256*0b57cec5SDimitry Andric   // so, add them to the available queue.
257*0b57cec5SDimitry Andric   for(auto I = PendingQueue.begin(), E = PendingQueue.end(); I != E;) {
258*0b57cec5SDimitry Andric     auto &C = *I++;
259*0b57cec5SDimitry Andric     if (C.SU->getHeight() <= CurCycle) {
260*0b57cec5SDimitry Andric       PendingQueue.remove(C);
261*0b57cec5SDimitry Andric       AvailQueue.push_back(C);
262*0b57cec5SDimitry Andric       C.SU->NodeQueueId = CurQueueId++;
263*0b57cec5SDimitry Andric     }
264*0b57cec5SDimitry Andric   }
265*0b57cec5SDimitry Andric }
266*0b57cec5SDimitry Andric 
267*0b57cec5SDimitry Andric /// Move the scheduler state forward by the specified number of Cycles.
268*0b57cec5SDimitry Andric void GCNILPScheduler::advanceToCycle(unsigned NextCycle) {
269*0b57cec5SDimitry Andric   if (NextCycle <= CurCycle)
270*0b57cec5SDimitry Andric     return;
271*0b57cec5SDimitry Andric   CurCycle = NextCycle;
272*0b57cec5SDimitry Andric   releasePending();
273*0b57cec5SDimitry Andric }
274*0b57cec5SDimitry Andric 
275*0b57cec5SDimitry Andric void GCNILPScheduler::releasePredecessors(const SUnit* SU) {
276*0b57cec5SDimitry Andric   for (const auto &PredEdge : SU->Preds) {
277*0b57cec5SDimitry Andric     auto PredSU = PredEdge.getSUnit();
278*0b57cec5SDimitry Andric     if (PredEdge.isWeak())
279*0b57cec5SDimitry Andric       continue;
280*0b57cec5SDimitry Andric     assert(PredSU->isBoundaryNode() || PredSU->NumSuccsLeft > 0);
281*0b57cec5SDimitry Andric 
282*0b57cec5SDimitry Andric     PredSU->setHeightToAtLeast(SU->getHeight() + PredEdge.getLatency());
283*0b57cec5SDimitry Andric 
284*0b57cec5SDimitry Andric     if (!PredSU->isBoundaryNode() && --PredSU->NumSuccsLeft == 0)
285*0b57cec5SDimitry Andric       PendingQueue.push_front(*new (Alloc.Allocate()) Candidate(PredSU));
286*0b57cec5SDimitry Andric   }
287*0b57cec5SDimitry Andric }
288*0b57cec5SDimitry Andric 
289*0b57cec5SDimitry Andric std::vector<const SUnit*>
290*0b57cec5SDimitry Andric GCNILPScheduler::schedule(ArrayRef<const SUnit*> BotRoots,
291*0b57cec5SDimitry Andric                           const ScheduleDAG &DAG) {
292*0b57cec5SDimitry Andric   auto &SUnits = const_cast<ScheduleDAG&>(DAG).SUnits;
293*0b57cec5SDimitry Andric 
294*0b57cec5SDimitry Andric   std::vector<SUnit> SUSavedCopy;
295*0b57cec5SDimitry Andric   SUSavedCopy.resize(SUnits.size());
296*0b57cec5SDimitry Andric 
297*0b57cec5SDimitry Andric   // we cannot save only those fields we touch: some of them are private
298*0b57cec5SDimitry Andric   // so save units verbatim: this assumes SUnit should have value semantics
299*0b57cec5SDimitry Andric   for (const SUnit &SU : SUnits)
300*0b57cec5SDimitry Andric     SUSavedCopy[SU.NodeNum] = SU;
301*0b57cec5SDimitry Andric 
302*0b57cec5SDimitry Andric   SUNumbers.assign(SUnits.size(), 0);
303*0b57cec5SDimitry Andric   for (const SUnit &SU : SUnits)
304*0b57cec5SDimitry Andric     CalcNodeSethiUllmanNumber(&SU, SUNumbers);
305*0b57cec5SDimitry Andric 
306*0b57cec5SDimitry Andric   for (auto SU : BotRoots) {
307*0b57cec5SDimitry Andric     AvailQueue.push_back(
308*0b57cec5SDimitry Andric       *new (Alloc.Allocate()) Candidate(const_cast<SUnit*>(SU)));
309*0b57cec5SDimitry Andric   }
310*0b57cec5SDimitry Andric   releasePredecessors(&DAG.ExitSU);
311*0b57cec5SDimitry Andric 
312*0b57cec5SDimitry Andric   std::vector<const SUnit*> Schedule;
313*0b57cec5SDimitry Andric   Schedule.reserve(SUnits.size());
314*0b57cec5SDimitry Andric   while (true) {
315*0b57cec5SDimitry Andric     if (AvailQueue.empty() && !PendingQueue.empty()) {
316*0b57cec5SDimitry Andric       auto EarliestSU = std::min_element(
317*0b57cec5SDimitry Andric         PendingQueue.begin(), PendingQueue.end(),
318*0b57cec5SDimitry Andric         [=](const Candidate& C1, const Candidate& C2) {
319*0b57cec5SDimitry Andric         return C1.SU->getHeight() < C2.SU->getHeight();
320*0b57cec5SDimitry Andric       })->SU;
321*0b57cec5SDimitry Andric       advanceToCycle(std::max(CurCycle + 1, EarliestSU->getHeight()));
322*0b57cec5SDimitry Andric     }
323*0b57cec5SDimitry Andric     if (AvailQueue.empty())
324*0b57cec5SDimitry Andric       break;
325*0b57cec5SDimitry Andric 
326*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "\n=== Picking candidate\n"
327*0b57cec5SDimitry Andric                          "Ready queue:";
328*0b57cec5SDimitry Andric                for (auto &C
329*0b57cec5SDimitry Andric                     : AvailQueue) dbgs()
330*0b57cec5SDimitry Andric                << ' ' << C.SU->NodeNum;
331*0b57cec5SDimitry Andric                dbgs() << '\n';);
332*0b57cec5SDimitry Andric 
333*0b57cec5SDimitry Andric     auto C = pickCandidate();
334*0b57cec5SDimitry Andric     assert(C);
335*0b57cec5SDimitry Andric     AvailQueue.remove(*C);
336*0b57cec5SDimitry Andric     auto SU = C->SU;
337*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Selected "; DAG.dumpNode(*SU));
338*0b57cec5SDimitry Andric 
339*0b57cec5SDimitry Andric     advanceToCycle(SU->getHeight());
340*0b57cec5SDimitry Andric 
341*0b57cec5SDimitry Andric     releasePredecessors(SU);
342*0b57cec5SDimitry Andric     Schedule.push_back(SU);
343*0b57cec5SDimitry Andric     SU->isScheduled = true;
344*0b57cec5SDimitry Andric   }
345*0b57cec5SDimitry Andric   assert(SUnits.size() == Schedule.size());
346*0b57cec5SDimitry Andric 
347*0b57cec5SDimitry Andric   std::reverse(Schedule.begin(), Schedule.end());
348*0b57cec5SDimitry Andric 
349*0b57cec5SDimitry Andric   // restore units
350*0b57cec5SDimitry Andric   for (auto &SU : SUnits)
351*0b57cec5SDimitry Andric     SU = SUSavedCopy[SU.NodeNum];
352*0b57cec5SDimitry Andric 
353*0b57cec5SDimitry Andric   return Schedule;
354*0b57cec5SDimitry Andric }
355*0b57cec5SDimitry Andric 
356*0b57cec5SDimitry Andric namespace llvm {
357*0b57cec5SDimitry Andric std::vector<const SUnit*> makeGCNILPScheduler(ArrayRef<const SUnit*> BotRoots,
358*0b57cec5SDimitry Andric                                               const ScheduleDAG &DAG) {
359*0b57cec5SDimitry Andric   GCNILPScheduler S;
360*0b57cec5SDimitry Andric   return S.schedule(BotRoots, DAG);
361*0b57cec5SDimitry Andric }
362*0b57cec5SDimitry Andric }
363