xref: /freebsd/contrib/llvm-project/llvm/lib/Target/AMDGPU/GCNILPSched.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===---------------------------- GCNILPSched.cpp - -----------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric /// \file
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "llvm/CodeGen/ScheduleDAG.h"
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric using namespace llvm;
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric #define DEBUG_TYPE "machine-scheduler"
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric namespace {
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric class GCNILPScheduler {
220b57cec5SDimitry Andric   struct Candidate : ilist_node<Candidate> {
230b57cec5SDimitry Andric     SUnit *SU;
240b57cec5SDimitry Andric 
Candidate__anon1a74e9370111::GCNILPScheduler::Candidate250b57cec5SDimitry Andric     Candidate(SUnit *SU_)
260b57cec5SDimitry Andric       : SU(SU_) {}
270b57cec5SDimitry Andric   };
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric   SpecificBumpPtrAllocator<Candidate> Alloc;
30*0fca6ea1SDimitry Andric   using Queue = simple_ilist<Candidate>;
310b57cec5SDimitry Andric   Queue PendingQueue;
320b57cec5SDimitry Andric   Queue AvailQueue;
330b57cec5SDimitry Andric   unsigned CurQueueId = 0;
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric   std::vector<unsigned> SUNumbers;
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric   /// CurCycle - The current scheduler state corresponds to this cycle.
380b57cec5SDimitry Andric   unsigned CurCycle = 0;
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric   unsigned getNodePriority(const SUnit *SU) const;
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric   const SUnit *pickBest(const SUnit *left, const SUnit *right);
430b57cec5SDimitry Andric   Candidate* pickCandidate();
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric   void releasePending();
460b57cec5SDimitry Andric   void advanceToCycle(unsigned NextCycle);
470b57cec5SDimitry Andric   void releasePredecessors(const SUnit* SU);
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric public:
500b57cec5SDimitry Andric   std::vector<const SUnit*> schedule(ArrayRef<const SUnit*> TopRoots,
510b57cec5SDimitry Andric                                      const ScheduleDAG &DAG);
520b57cec5SDimitry Andric };
530b57cec5SDimitry Andric } // namespace
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric /// CalcNodeSethiUllmanNumber - Compute Sethi Ullman number.
560b57cec5SDimitry Andric /// Smaller number is the higher priority.
570b57cec5SDimitry Andric static unsigned
CalcNodeSethiUllmanNumber(const SUnit * SU,std::vector<unsigned> & SUNumbers)580b57cec5SDimitry Andric CalcNodeSethiUllmanNumber(const SUnit *SU, std::vector<unsigned> &SUNumbers) {
590b57cec5SDimitry Andric   unsigned &SethiUllmanNumber = SUNumbers[SU->NodeNum];
600b57cec5SDimitry Andric   if (SethiUllmanNumber != 0)
610b57cec5SDimitry Andric     return SethiUllmanNumber;
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric   unsigned Extra = 0;
640b57cec5SDimitry Andric   for (const SDep &Pred : SU->Preds) {
650b57cec5SDimitry Andric     if (Pred.isCtrl()) continue;  // ignore chain preds
660b57cec5SDimitry Andric     SUnit *PredSU = Pred.getSUnit();
670b57cec5SDimitry Andric     unsigned PredSethiUllman = CalcNodeSethiUllmanNumber(PredSU, SUNumbers);
680b57cec5SDimitry Andric     if (PredSethiUllman > SethiUllmanNumber) {
690b57cec5SDimitry Andric       SethiUllmanNumber = PredSethiUllman;
700b57cec5SDimitry Andric       Extra = 0;
710b57cec5SDimitry Andric     }
720b57cec5SDimitry Andric     else if (PredSethiUllman == SethiUllmanNumber)
730b57cec5SDimitry Andric       ++Extra;
740b57cec5SDimitry Andric   }
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric   SethiUllmanNumber += Extra;
770b57cec5SDimitry Andric 
780b57cec5SDimitry Andric   if (SethiUllmanNumber == 0)
790b57cec5SDimitry Andric     SethiUllmanNumber = 1;
800b57cec5SDimitry Andric 
810b57cec5SDimitry Andric   return SethiUllmanNumber;
820b57cec5SDimitry Andric }
830b57cec5SDimitry Andric 
840b57cec5SDimitry Andric // Lower priority means schedule further down. For bottom-up scheduling, lower
850b57cec5SDimitry Andric // priority SUs are scheduled before higher priority SUs.
getNodePriority(const SUnit * SU) const860b57cec5SDimitry Andric unsigned GCNILPScheduler::getNodePriority(const SUnit *SU) const {
870b57cec5SDimitry Andric   assert(SU->NodeNum < SUNumbers.size());
880b57cec5SDimitry Andric   if (SU->NumSuccs == 0 && SU->NumPreds != 0)
890b57cec5SDimitry Andric     // If SU does not have a register use, i.e. it doesn't produce a value
900b57cec5SDimitry Andric     // that would be consumed (e.g. store), then it terminates a chain of
910b57cec5SDimitry Andric     // computation.  Give it a large SethiUllman number so it will be
920b57cec5SDimitry Andric     // scheduled right before its predecessors that it doesn't lengthen
930b57cec5SDimitry Andric     // their live ranges.
940b57cec5SDimitry Andric     return 0xffff;
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric   if (SU->NumPreds == 0 && SU->NumSuccs != 0)
970b57cec5SDimitry Andric     // If SU does not have a register def, schedule it close to its uses
980b57cec5SDimitry Andric     // because it does not lengthen any live ranges.
990b57cec5SDimitry Andric     return 0;
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric   return SUNumbers[SU->NodeNum];
1020b57cec5SDimitry Andric }
1030b57cec5SDimitry Andric 
1040b57cec5SDimitry Andric /// closestSucc - Returns the scheduled cycle of the successor which is
1050b57cec5SDimitry Andric /// closest to the current cycle.
closestSucc(const SUnit * SU)1060b57cec5SDimitry Andric static unsigned closestSucc(const SUnit *SU) {
1070b57cec5SDimitry Andric   unsigned MaxHeight = 0;
1080b57cec5SDimitry Andric   for (const SDep &Succ : SU->Succs) {
1090b57cec5SDimitry Andric     if (Succ.isCtrl()) continue;  // ignore chain succs
1100b57cec5SDimitry Andric     unsigned Height = Succ.getSUnit()->getHeight();
1110b57cec5SDimitry Andric     // If there are bunch of CopyToRegs stacked up, they should be considered
1120b57cec5SDimitry Andric     // to be at the same position.
1130b57cec5SDimitry Andric     if (Height > MaxHeight)
1140b57cec5SDimitry Andric       MaxHeight = Height;
1150b57cec5SDimitry Andric   }
1160b57cec5SDimitry Andric   return MaxHeight;
1170b57cec5SDimitry Andric }
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric /// calcMaxScratches - Returns an cost estimate of the worse case requirement
1200b57cec5SDimitry Andric /// for scratch registers, i.e. number of data dependencies.
calcMaxScratches(const SUnit * SU)1210b57cec5SDimitry Andric static unsigned calcMaxScratches(const SUnit *SU) {
1220b57cec5SDimitry Andric   unsigned Scratches = 0;
1230b57cec5SDimitry Andric   for (const SDep &Pred : SU->Preds) {
1240b57cec5SDimitry Andric     if (Pred.isCtrl()) continue;  // ignore chain preds
1250b57cec5SDimitry Andric     Scratches++;
1260b57cec5SDimitry Andric   }
1270b57cec5SDimitry Andric   return Scratches;
1280b57cec5SDimitry Andric }
1290b57cec5SDimitry Andric 
1300b57cec5SDimitry Andric // Return -1 if left has higher priority, 1 if right has higher priority.
1310b57cec5SDimitry Andric // Return 0 if latency-based priority is equivalent.
BUCompareLatency(const SUnit * left,const SUnit * right)1320b57cec5SDimitry Andric static int BUCompareLatency(const SUnit *left, const SUnit *right) {
1330b57cec5SDimitry Andric   // Scheduling an instruction that uses a VReg whose postincrement has not yet
1340b57cec5SDimitry Andric   // been scheduled will induce a copy. Model this as an extra cycle of latency.
1350b57cec5SDimitry Andric   int LHeight = (int)left->getHeight();
1360b57cec5SDimitry Andric   int RHeight = (int)right->getHeight();
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric   // If either node is scheduling for latency, sort them by height/depth
1390b57cec5SDimitry Andric   // and latency.
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric   // If neither instruction stalls (!LStall && !RStall) and HazardRecognizer
1420b57cec5SDimitry Andric   // is enabled, grouping instructions by cycle, then its height is already
1430b57cec5SDimitry Andric   // covered so only its depth matters. We also reach this point if both stall
1440b57cec5SDimitry Andric   // but have the same height.
1450b57cec5SDimitry Andric   if (LHeight != RHeight)
1460b57cec5SDimitry Andric     return LHeight > RHeight ? 1 : -1;
1470b57cec5SDimitry Andric 
1480b57cec5SDimitry Andric   int LDepth = left->getDepth();
1490b57cec5SDimitry Andric   int RDepth = right->getDepth();
1500b57cec5SDimitry Andric   if (LDepth != RDepth) {
1510b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "  Comparing latency of SU (" << left->NodeNum
1520b57cec5SDimitry Andric                       << ") depth " << LDepth << " vs SU (" << right->NodeNum
1530b57cec5SDimitry Andric                       << ") depth " << RDepth << "\n");
1540b57cec5SDimitry Andric     return LDepth < RDepth ? 1 : -1;
1550b57cec5SDimitry Andric   }
1560b57cec5SDimitry Andric   if (left->Latency != right->Latency)
1570b57cec5SDimitry Andric     return left->Latency > right->Latency ? 1 : -1;
1580b57cec5SDimitry Andric 
1590b57cec5SDimitry Andric   return 0;
1600b57cec5SDimitry Andric }
1610b57cec5SDimitry Andric 
pickBest(const SUnit * left,const SUnit * right)1620b57cec5SDimitry Andric const SUnit *GCNILPScheduler::pickBest(const SUnit *left, const SUnit *right)
1630b57cec5SDimitry Andric {
1640b57cec5SDimitry Andric   // TODO: add register pressure lowering checks
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric   bool const DisableSchedCriticalPath = false;
1670b57cec5SDimitry Andric   int MaxReorderWindow = 6;
1680b57cec5SDimitry Andric   if (!DisableSchedCriticalPath) {
1690b57cec5SDimitry Andric     int spread = (int)left->getDepth() - (int)right->getDepth();
1700b57cec5SDimitry Andric     if (std::abs(spread) > MaxReorderWindow) {
1710b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "Depth of SU(" << left->NodeNum << "): "
1720b57cec5SDimitry Andric                         << left->getDepth() << " != SU(" << right->NodeNum
1730b57cec5SDimitry Andric                         << "): " << right->getDepth() << "\n");
1740b57cec5SDimitry Andric       return left->getDepth() < right->getDepth() ? right : left;
1750b57cec5SDimitry Andric     }
1760b57cec5SDimitry Andric   }
1770b57cec5SDimitry Andric 
1780b57cec5SDimitry Andric   bool const DisableSchedHeight = false;
1790b57cec5SDimitry Andric   if (!DisableSchedHeight && left->getHeight() != right->getHeight()) {
1800b57cec5SDimitry Andric     int spread = (int)left->getHeight() - (int)right->getHeight();
1810b57cec5SDimitry Andric     if (std::abs(spread) > MaxReorderWindow)
1820b57cec5SDimitry Andric       return left->getHeight() > right->getHeight() ? right : left;
1830b57cec5SDimitry Andric   }
1840b57cec5SDimitry Andric 
1850b57cec5SDimitry Andric   // Prioritize by Sethi-Ulmann number and push CopyToReg nodes down.
1860b57cec5SDimitry Andric   unsigned LPriority = getNodePriority(left);
1870b57cec5SDimitry Andric   unsigned RPriority = getNodePriority(right);
1880b57cec5SDimitry Andric 
1890b57cec5SDimitry Andric   if (LPriority != RPriority)
1900b57cec5SDimitry Andric     return LPriority > RPriority ? right : left;
1910b57cec5SDimitry Andric 
1920b57cec5SDimitry Andric   // Try schedule def + use closer when Sethi-Ullman numbers are the same.
1930b57cec5SDimitry Andric   // e.g.
1940b57cec5SDimitry Andric   // t1 = op t2, c1
1950b57cec5SDimitry Andric   // t3 = op t4, c2
1960b57cec5SDimitry Andric   //
1970b57cec5SDimitry Andric   // and the following instructions are both ready.
1980b57cec5SDimitry Andric   // t2 = op c3
1990b57cec5SDimitry Andric   // t4 = op c4
2000b57cec5SDimitry Andric   //
2010b57cec5SDimitry Andric   // Then schedule t2 = op first.
2020b57cec5SDimitry Andric   // i.e.
2030b57cec5SDimitry Andric   // t4 = op c4
2040b57cec5SDimitry Andric   // t2 = op c3
2050b57cec5SDimitry Andric   // t1 = op t2, c1
2060b57cec5SDimitry Andric   // t3 = op t4, c2
2070b57cec5SDimitry Andric   //
2080b57cec5SDimitry Andric   // This creates more short live intervals.
2090b57cec5SDimitry Andric   unsigned LDist = closestSucc(left);
2100b57cec5SDimitry Andric   unsigned RDist = closestSucc(right);
2110b57cec5SDimitry Andric   if (LDist != RDist)
2120b57cec5SDimitry Andric     return LDist < RDist ? right : left;
2130b57cec5SDimitry Andric 
2140b57cec5SDimitry Andric   // How many registers becomes live when the node is scheduled.
2150b57cec5SDimitry Andric   unsigned LScratch = calcMaxScratches(left);
2160b57cec5SDimitry Andric   unsigned RScratch = calcMaxScratches(right);
2170b57cec5SDimitry Andric   if (LScratch != RScratch)
2180b57cec5SDimitry Andric     return LScratch > RScratch ? right : left;
2190b57cec5SDimitry Andric 
2200b57cec5SDimitry Andric   bool const DisableSchedCycles = false;
2210b57cec5SDimitry Andric   if (!DisableSchedCycles) {
2220b57cec5SDimitry Andric     int result = BUCompareLatency(left, right);
2230b57cec5SDimitry Andric     if (result != 0)
2240b57cec5SDimitry Andric       return result > 0 ? right : left;
2250b57cec5SDimitry Andric     return left;
2260b57cec5SDimitry Andric   }
2270b57cec5SDimitry Andric   if (left->getHeight() != right->getHeight())
2280b57cec5SDimitry Andric     return (left->getHeight() > right->getHeight()) ? right : left;
2290b57cec5SDimitry Andric 
2300b57cec5SDimitry Andric   if (left->getDepth() != right->getDepth())
2310b57cec5SDimitry Andric     return (left->getDepth() < right->getDepth()) ? right : left;
2320b57cec5SDimitry Andric 
2330b57cec5SDimitry Andric   assert(left->NodeQueueId && right->NodeQueueId &&
2340b57cec5SDimitry Andric         "NodeQueueId cannot be zero");
2350b57cec5SDimitry Andric   return (left->NodeQueueId > right->NodeQueueId) ? right : left;
2360b57cec5SDimitry Andric }
2370b57cec5SDimitry Andric 
pickCandidate()2380b57cec5SDimitry Andric GCNILPScheduler::Candidate* GCNILPScheduler::pickCandidate() {
2390b57cec5SDimitry Andric   if (AvailQueue.empty())
2400b57cec5SDimitry Andric     return nullptr;
2410b57cec5SDimitry Andric   auto Best = AvailQueue.begin();
2420b57cec5SDimitry Andric   for (auto I = std::next(AvailQueue.begin()), E = AvailQueue.end(); I != E; ++I) {
2430b57cec5SDimitry Andric     auto NewBestSU = pickBest(Best->SU, I->SU);
2440b57cec5SDimitry Andric     if (NewBestSU != Best->SU) {
2450b57cec5SDimitry Andric       assert(NewBestSU == I->SU);
2460b57cec5SDimitry Andric       Best = I;
2470b57cec5SDimitry Andric     }
2480b57cec5SDimitry Andric   }
2490b57cec5SDimitry Andric   return &*Best;
2500b57cec5SDimitry Andric }
2510b57cec5SDimitry Andric 
releasePending()2520b57cec5SDimitry Andric void GCNILPScheduler::releasePending() {
2530b57cec5SDimitry Andric   // Check to see if any of the pending instructions are ready to issue.  If
2540b57cec5SDimitry Andric   // so, add them to the available queue.
2550b57cec5SDimitry Andric   for(auto I = PendingQueue.begin(), E = PendingQueue.end(); I != E;) {
2560b57cec5SDimitry Andric     auto &C = *I++;
2570b57cec5SDimitry Andric     if (C.SU->getHeight() <= CurCycle) {
2580b57cec5SDimitry Andric       PendingQueue.remove(C);
2590b57cec5SDimitry Andric       AvailQueue.push_back(C);
2600b57cec5SDimitry Andric       C.SU->NodeQueueId = CurQueueId++;
2610b57cec5SDimitry Andric     }
2620b57cec5SDimitry Andric   }
2630b57cec5SDimitry Andric }
2640b57cec5SDimitry Andric 
2650b57cec5SDimitry Andric /// Move the scheduler state forward by the specified number of Cycles.
advanceToCycle(unsigned NextCycle)2660b57cec5SDimitry Andric void GCNILPScheduler::advanceToCycle(unsigned NextCycle) {
2670b57cec5SDimitry Andric   if (NextCycle <= CurCycle)
2680b57cec5SDimitry Andric     return;
2690b57cec5SDimitry Andric   CurCycle = NextCycle;
2700b57cec5SDimitry Andric   releasePending();
2710b57cec5SDimitry Andric }
2720b57cec5SDimitry Andric 
releasePredecessors(const SUnit * SU)2730b57cec5SDimitry Andric void GCNILPScheduler::releasePredecessors(const SUnit* SU) {
2740b57cec5SDimitry Andric   for (const auto &PredEdge : SU->Preds) {
2750b57cec5SDimitry Andric     auto PredSU = PredEdge.getSUnit();
2760b57cec5SDimitry Andric     if (PredEdge.isWeak())
2770b57cec5SDimitry Andric       continue;
2780b57cec5SDimitry Andric     assert(PredSU->isBoundaryNode() || PredSU->NumSuccsLeft > 0);
2790b57cec5SDimitry Andric 
2800b57cec5SDimitry Andric     PredSU->setHeightToAtLeast(SU->getHeight() + PredEdge.getLatency());
2810b57cec5SDimitry Andric 
2820b57cec5SDimitry Andric     if (!PredSU->isBoundaryNode() && --PredSU->NumSuccsLeft == 0)
2830b57cec5SDimitry Andric       PendingQueue.push_front(*new (Alloc.Allocate()) Candidate(PredSU));
2840b57cec5SDimitry Andric   }
2850b57cec5SDimitry Andric }
2860b57cec5SDimitry Andric 
2870b57cec5SDimitry Andric std::vector<const SUnit*>
schedule(ArrayRef<const SUnit * > BotRoots,const ScheduleDAG & DAG)2880b57cec5SDimitry Andric GCNILPScheduler::schedule(ArrayRef<const SUnit*> BotRoots,
2890b57cec5SDimitry Andric                           const ScheduleDAG &DAG) {
2900b57cec5SDimitry Andric   auto &SUnits = const_cast<ScheduleDAG&>(DAG).SUnits;
2910b57cec5SDimitry Andric 
2920b57cec5SDimitry Andric   std::vector<SUnit> SUSavedCopy;
2930b57cec5SDimitry Andric   SUSavedCopy.resize(SUnits.size());
2940b57cec5SDimitry Andric 
2950b57cec5SDimitry Andric   // we cannot save only those fields we touch: some of them are private
2960b57cec5SDimitry Andric   // so save units verbatim: this assumes SUnit should have value semantics
2970b57cec5SDimitry Andric   for (const SUnit &SU : SUnits)
2980b57cec5SDimitry Andric     SUSavedCopy[SU.NodeNum] = SU;
2990b57cec5SDimitry Andric 
3000b57cec5SDimitry Andric   SUNumbers.assign(SUnits.size(), 0);
3010b57cec5SDimitry Andric   for (const SUnit &SU : SUnits)
3020b57cec5SDimitry Andric     CalcNodeSethiUllmanNumber(&SU, SUNumbers);
3030b57cec5SDimitry Andric 
304bdd1243dSDimitry Andric   for (const auto *SU : BotRoots) {
3050b57cec5SDimitry Andric     AvailQueue.push_back(
3060b57cec5SDimitry Andric       *new (Alloc.Allocate()) Candidate(const_cast<SUnit*>(SU)));
3070b57cec5SDimitry Andric   }
3080b57cec5SDimitry Andric   releasePredecessors(&DAG.ExitSU);
3090b57cec5SDimitry Andric 
3100b57cec5SDimitry Andric   std::vector<const SUnit*> Schedule;
3110b57cec5SDimitry Andric   Schedule.reserve(SUnits.size());
3120b57cec5SDimitry Andric   while (true) {
3130b57cec5SDimitry Andric     if (AvailQueue.empty() && !PendingQueue.empty()) {
314*0fca6ea1SDimitry Andric       auto EarliestSU =
315*0fca6ea1SDimitry Andric           llvm::min_element(PendingQueue, [=](const Candidate &C1,
316*0fca6ea1SDimitry Andric                                               const Candidate &C2) {
3170b57cec5SDimitry Andric             return C1.SU->getHeight() < C2.SU->getHeight();
3180b57cec5SDimitry Andric           })->SU;
3190b57cec5SDimitry Andric       advanceToCycle(std::max(CurCycle + 1, EarliestSU->getHeight()));
3200b57cec5SDimitry Andric     }
3210b57cec5SDimitry Andric     if (AvailQueue.empty())
3220b57cec5SDimitry Andric       break;
3230b57cec5SDimitry Andric 
3240b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "\n=== Picking candidate\n"
3250b57cec5SDimitry Andric                          "Ready queue:";
3260b57cec5SDimitry Andric                for (auto &C
3270b57cec5SDimitry Andric                     : AvailQueue) dbgs()
3280b57cec5SDimitry Andric                << ' ' << C.SU->NodeNum;
3290b57cec5SDimitry Andric                dbgs() << '\n';);
3300b57cec5SDimitry Andric 
3310b57cec5SDimitry Andric     auto C = pickCandidate();
3320b57cec5SDimitry Andric     assert(C);
3330b57cec5SDimitry Andric     AvailQueue.remove(*C);
3340b57cec5SDimitry Andric     auto SU = C->SU;
3350b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Selected "; DAG.dumpNode(*SU));
3360b57cec5SDimitry Andric 
3370b57cec5SDimitry Andric     advanceToCycle(SU->getHeight());
3380b57cec5SDimitry Andric 
3390b57cec5SDimitry Andric     releasePredecessors(SU);
3400b57cec5SDimitry Andric     Schedule.push_back(SU);
3410b57cec5SDimitry Andric     SU->isScheduled = true;
3420b57cec5SDimitry Andric   }
3430b57cec5SDimitry Andric   assert(SUnits.size() == Schedule.size());
3440b57cec5SDimitry Andric 
3450b57cec5SDimitry Andric   std::reverse(Schedule.begin(), Schedule.end());
3460b57cec5SDimitry Andric 
3470b57cec5SDimitry Andric   // restore units
3480b57cec5SDimitry Andric   for (auto &SU : SUnits)
3490b57cec5SDimitry Andric     SU = SUSavedCopy[SU.NodeNum];
3500b57cec5SDimitry Andric 
3510b57cec5SDimitry Andric   return Schedule;
3520b57cec5SDimitry Andric }
3530b57cec5SDimitry Andric 
3540b57cec5SDimitry Andric namespace llvm {
makeGCNILPScheduler(ArrayRef<const SUnit * > BotRoots,const ScheduleDAG & DAG)3550b57cec5SDimitry Andric std::vector<const SUnit*> makeGCNILPScheduler(ArrayRef<const SUnit*> BotRoots,
3560b57cec5SDimitry Andric                                               const ScheduleDAG &DAG) {
3570b57cec5SDimitry Andric   GCNILPScheduler S;
3580b57cec5SDimitry Andric   return S.schedule(BotRoots, DAG);
3590b57cec5SDimitry Andric }
360*0fca6ea1SDimitry Andric } // namespace llvm
361