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