1 //===- GCNMinRegStrategy.cpp ----------------------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "llvm/ADT/ArrayRef.h"
11 #include "llvm/ADT/SmallPtrSet.h"
12 #include "llvm/ADT/SmallVector.h"
13 #include "llvm/ADT/ilist_node.h"
14 #include "llvm/ADT/simple_ilist.h"
15 #include "llvm/CodeGen/ScheduleDAG.h"
16 #include "llvm/Support/Allocator.h"
17 #include "llvm/Support/Debug.h"
18 #include "llvm/Support/raw_ostream.h"
26 #define DEBUG_TYPE "machine-scheduler"
30 class GCNMinRegScheduler {
31 struct Candidate : ilist_node<Candidate> {
35 Candidate(const SUnit *SU_, int Priority_ = 0)
36 : SU(SU_), Priority(Priority_) {}
39 SpecificBumpPtrAllocator<Candidate> Alloc;
40 using Queue = simple_ilist<Candidate>;
41 Queue RQ; // Ready queue
43 std::vector<unsigned> NumPreds;
45 bool isScheduled(const SUnit *SU) const {
46 assert(!SU->isBoundaryNode());
47 return NumPreds[SU->NodeNum] == std::numeric_limits<unsigned>::max();
50 void setIsScheduled(const SUnit *SU) {
51 assert(!SU->isBoundaryNode());
52 NumPreds[SU->NodeNum] = std::numeric_limits<unsigned>::max();
55 unsigned getNumPreds(const SUnit *SU) const {
56 assert(!SU->isBoundaryNode());
57 assert(NumPreds[SU->NodeNum] != std::numeric_limits<unsigned>::max());
58 return NumPreds[SU->NodeNum];
61 unsigned decNumPreds(const SUnit *SU) {
62 assert(!SU->isBoundaryNode());
63 assert(NumPreds[SU->NodeNum] != std::numeric_limits<unsigned>::max());
64 return --NumPreds[SU->NodeNum];
67 void initNumPreds(const decltype(ScheduleDAG::SUnits) &SUnits);
69 int getReadySuccessors(const SUnit *SU) const;
70 int getNotReadySuccessors(const SUnit *SU) const;
72 template <typename Calc>
73 unsigned findMax(unsigned Num, Calc C);
75 Candidate* pickCandidate();
77 void bumpPredsPriority(const SUnit *SchedSU, int Priority);
78 void releaseSuccessors(const SUnit* SU, int Priority);
81 std::vector<const SUnit*> schedule(ArrayRef<const SUnit*> TopRoots,
82 const ScheduleDAG &DAG);
85 } // end anonymous namespace
87 void GCNMinRegScheduler::initNumPreds(const decltype(ScheduleDAG::SUnits) &SUnits) {
88 NumPreds.resize(SUnits.size());
89 for (unsigned I = 0; I < SUnits.size(); ++I)
90 NumPreds[I] = SUnits[I].NumPredsLeft;
93 int GCNMinRegScheduler::getReadySuccessors(const SUnit *SU) const {
94 unsigned NumSchedSuccs = 0;
95 for (auto SDep : SU->Succs) {
96 bool wouldBeScheduled = true;
97 for (auto PDep : SDep.getSUnit()->Preds) {
98 auto PSU = PDep.getSUnit();
99 assert(!PSU->isBoundaryNode());
100 if (PSU != SU && !isScheduled(PSU)) {
101 wouldBeScheduled = false;
105 NumSchedSuccs += wouldBeScheduled ? 1 : 0;
107 return NumSchedSuccs;
110 int GCNMinRegScheduler::getNotReadySuccessors(const SUnit *SU) const {
111 return SU->Succs.size() - getReadySuccessors(SU);
114 template <typename Calc>
115 unsigned GCNMinRegScheduler::findMax(unsigned Num, Calc C) {
116 assert(!RQ.empty() && Num <= RQ.size());
118 using T = decltype(C(*RQ.begin())) ;
120 T Max = std::numeric_limits<T>::min();
122 for (auto I = RQ.begin(); Num; --Num) {
140 GCNMinRegScheduler::Candidate* GCNMinRegScheduler::pickCandidate() {
142 unsigned Num = RQ.size();
145 DEBUG(dbgs() << "\nSelecting max priority candidates among " << Num << '\n');
146 Num = findMax(Num, [=](const Candidate &C) { return C.Priority; });
149 DEBUG(dbgs() << "\nSelecting min non-ready producing candidate among "
151 Num = findMax(Num, [=](const Candidate &C) {
153 int Res = getNotReadySuccessors(SU);
154 DEBUG(dbgs() << "SU(" << SU->NodeNum << ") would left non-ready "
155 << Res << " successors, metric = " << -Res << '\n');
160 DEBUG(dbgs() << "\nSelecting most producing candidate among "
162 Num = findMax(Num, [=](const Candidate &C) {
164 auto Res = getReadySuccessors(SU);
165 DEBUG(dbgs() << "SU(" << SU->NodeNum << ") would make ready "
166 << Res << " successors, metric = " << Res << '\n');
171 Num = Num ? Num : RQ.size();
172 DEBUG(dbgs() << "\nCan't find best candidate, selecting in program order among "
174 Num = findMax(Num, [=](const Candidate &C) { return -(int64_t)C.SU->NodeNum; });
181 void GCNMinRegScheduler::bumpPredsPriority(const SUnit *SchedSU, int Priority) {
182 SmallPtrSet<const SUnit*, 32> Set;
183 for (const auto &S : SchedSU->Succs) {
184 if (S.getSUnit()->isBoundaryNode() || isScheduled(S.getSUnit()) ||
185 S.getKind() != SDep::Data)
187 for (const auto &P : S.getSUnit()->Preds) {
188 auto PSU = P.getSUnit();
189 assert(!PSU->isBoundaryNode());
190 if (PSU != SchedSU && !isScheduled(PSU)) {
195 SmallVector<const SUnit*, 32> Worklist(Set.begin(), Set.end());
196 while (!Worklist.empty()) {
197 auto SU = Worklist.pop_back_val();
198 assert(!SU->isBoundaryNode());
199 for (const auto &P : SU->Preds) {
200 if (!P.getSUnit()->isBoundaryNode() && !isScheduled(P.getSUnit()) &&
201 Set.insert(P.getSUnit()).second)
202 Worklist.push_back(P.getSUnit());
205 DEBUG(dbgs() << "Make the predecessors of SU(" << SchedSU->NodeNum
206 << ")'s non-ready successors of " << Priority
207 << " priority in ready queue: ");
208 const auto SetEnd = Set.end();
210 if (Set.find(C.SU) != SetEnd) {
211 C.Priority = Priority;
212 DEBUG(dbgs() << " SU(" << C.SU->NodeNum << ')');
215 DEBUG(dbgs() << '\n');
218 void GCNMinRegScheduler::releaseSuccessors(const SUnit* SU, int Priority) {
219 for (const auto &S : SU->Succs) {
220 auto SuccSU = S.getSUnit();
223 assert(SuccSU->isBoundaryNode() || getNumPreds(SuccSU) > 0);
224 if (!SuccSU->isBoundaryNode() && decNumPreds(SuccSU) == 0)
225 RQ.push_front(*new (Alloc.Allocate()) Candidate(SuccSU, Priority));
229 std::vector<const SUnit*>
230 GCNMinRegScheduler::schedule(ArrayRef<const SUnit*> TopRoots,
231 const ScheduleDAG &DAG) {
232 const auto &SUnits = DAG.SUnits;
233 std::vector<const SUnit*> Schedule;
234 Schedule.reserve(SUnits.size());
236 initNumPreds(SUnits);
240 for (auto SU : TopRoots) {
241 RQ.push_back(*new (Alloc.Allocate()) Candidate(SU, StepNo));
243 releaseSuccessors(&DAG.EntrySU, StepNo);
245 while (!RQ.empty()) {
247 dbgs() << "\n=== Picking candidate, Step = " << StepNo << "\n"
250 dbgs() << ' ' << C.SU->NodeNum << "(P" << C.Priority << ')';
254 auto C = pickCandidate();
258 DEBUG(dbgs() << "Selected "; SU->dump(&DAG));
260 releaseSuccessors(SU, StepNo);
261 Schedule.push_back(SU);
264 if (getReadySuccessors(SU) == 0)
265 bumpPredsPriority(SU, StepNo);
269 assert(SUnits.size() == Schedule.size());
276 std::vector<const SUnit*> makeMinRegSchedule(ArrayRef<const SUnit*> TopRoots,
277 const ScheduleDAG &DAG) {
278 GCNMinRegScheduler S;
279 return S.schedule(TopRoots, DAG);
282 } // end namespace llvm