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 //===----------------------------------------------------------------------===//
12 //===----------------------------------------------------------------------===//
14 #include "llvm/CodeGen/ScheduleDAG.h"
18 #define DEBUG_TYPE "misched"
20 class GCNMinRegScheduler {
21 struct Candidate : ilist_node<Candidate> {
25 Candidate(const SUnit *SU_, int Priority_ = 0)
26 : SU(SU_), Priority(Priority_) {}
29 SpecificBumpPtrAllocator<Candidate> Alloc;
30 typedef simple_ilist<Candidate> Queue;
31 Queue RQ; // Ready queue
33 std::vector<unsigned> NumPreds;
35 bool isScheduled(const SUnit *SU) const {
36 assert(!SU->isBoundaryNode());
37 return NumPreds[SU->NodeNum] == std::numeric_limits<unsigned>::max();
40 void setIsScheduled(const SUnit *SU) {
41 assert(!SU->isBoundaryNode());
42 NumPreds[SU->NodeNum] = std::numeric_limits<unsigned>::max();
45 unsigned getNumPreds(const SUnit *SU) const {
46 assert(!SU->isBoundaryNode());
47 assert(NumPreds[SU->NodeNum] != std::numeric_limits<unsigned>::max());
48 return NumPreds[SU->NodeNum];
51 unsigned decNumPreds(const SUnit *SU) {
52 assert(!SU->isBoundaryNode());
53 assert(NumPreds[SU->NodeNum] != std::numeric_limits<unsigned>::max());
54 return --NumPreds[SU->NodeNum];
57 void initNumPreds(const decltype(ScheduleDAG::SUnits) &SUnits);
59 int getReadySuccessors(const SUnit *SU) const;
60 int getNotReadySuccessors(const SUnit *SU) const;
62 template <typename Calc>
63 unsigned findMax(unsigned Num, Calc C);
65 Candidate* pickCandidate();
67 void bumpPredsPriority(const SUnit *SchedSU, int Priority);
68 void releaseSuccessors(const SUnit* SU, int Priority);
71 std::vector<const SUnit*> schedule(ArrayRef<const SUnit*> TopRoots,
72 const ScheduleDAG &DAG);
75 void GCNMinRegScheduler::initNumPreds(const decltype(ScheduleDAG::SUnits) &SUnits) {
76 NumPreds.resize(SUnits.size());
77 for (unsigned I = 0; I < SUnits.size(); ++I)
78 NumPreds[I] = SUnits[I].NumPredsLeft;
81 int GCNMinRegScheduler::getReadySuccessors(const SUnit *SU) const {
82 unsigned NumSchedSuccs = 0;
83 for (auto SDep : SU->Succs) {
84 bool wouldBeScheduled = true;
85 for (auto PDep : SDep.getSUnit()->Preds) {
86 auto PSU = PDep.getSUnit();
87 assert(!PSU->isBoundaryNode());
88 if (PSU != SU && !isScheduled(PSU)) {
89 wouldBeScheduled = false;
93 NumSchedSuccs += wouldBeScheduled ? 1 : 0;
98 int GCNMinRegScheduler::getNotReadySuccessors(const SUnit *SU) const {
99 return SU->Succs.size() - getReadySuccessors(SU);
102 template <typename Calc>
103 unsigned GCNMinRegScheduler::findMax(unsigned Num, Calc C) {
104 assert(!RQ.empty() && Num <= RQ.size());
105 typedef decltype(C(*RQ.begin())) T;
106 T Max = std::numeric_limits<T>::min();
108 for (auto I = RQ.begin(); Num; --Num) {
126 GCNMinRegScheduler::Candidate* GCNMinRegScheduler::pickCandidate() {
128 unsigned Num = RQ.size();
131 DEBUG(dbgs() << "\nSelecting max priority candidates among " << Num << '\n');
132 Num = findMax(Num, [=](const Candidate &C) { return C.Priority; });
135 DEBUG(dbgs() << "\nSelecting min non-ready producing candidate among "
137 Num = findMax(Num, [=](const Candidate &C) {
139 int Res = getNotReadySuccessors(SU);
140 DEBUG(dbgs() << "SU(" << SU->NodeNum << ") would left non-ready "
141 << Res << " successors, metric = " << -Res << '\n');
146 DEBUG(dbgs() << "\nSelecting most producing candidate among "
148 Num = findMax(Num, [=](const Candidate &C) {
150 auto Res = getReadySuccessors(SU);
151 DEBUG(dbgs() << "SU(" << SU->NodeNum << ") would make ready "
152 << Res << " successors, metric = " << Res << '\n');
157 Num = Num ? Num : RQ.size();
158 DEBUG(dbgs() << "\nCan't find best candidate, selecting in program order among "
160 Num = findMax(Num, [=](const Candidate &C) { return -(int64_t)C.SU->NodeNum; });
167 void GCNMinRegScheduler::bumpPredsPriority(const SUnit *SchedSU, int Priority) {
168 SmallPtrSet<const SUnit*, 32> Set;
169 for (const auto &S : SchedSU->Succs) {
170 if (S.getSUnit()->isBoundaryNode() || isScheduled(S.getSUnit()) ||
171 S.getKind() != SDep::Data)
173 for (const auto &P : S.getSUnit()->Preds) {
174 auto PSU = P.getSUnit();
175 assert(!PSU->isBoundaryNode());
176 if (PSU != SchedSU && !isScheduled(PSU)) {
181 SmallVector<const SUnit*, 32> Worklist(Set.begin(), Set.end());
182 while (!Worklist.empty()) {
183 auto SU = Worklist.pop_back_val();
184 assert(!SU->isBoundaryNode());
185 for (const auto &P : SU->Preds) {
186 if (!P.getSUnit()->isBoundaryNode() && !isScheduled(P.getSUnit()) &&
187 Set.insert(P.getSUnit()).second)
188 Worklist.push_back(P.getSUnit());
191 DEBUG(dbgs() << "Make the predecessors of SU(" << SchedSU->NodeNum
192 << ")'s non-ready successors of " << Priority
193 << " priority in ready queue: ");
194 const auto SetEnd = Set.end();
196 if (Set.find(C.SU) != SetEnd) {
197 C.Priority = Priority;
198 DEBUG(dbgs() << " SU(" << C.SU->NodeNum << ')');
201 DEBUG(dbgs() << '\n');
204 void GCNMinRegScheduler::releaseSuccessors(const SUnit* SU, int Priority) {
205 for (const auto &S : SU->Succs) {
206 auto SuccSU = S.getSUnit();
209 assert(SuccSU->isBoundaryNode() || getNumPreds(SuccSU) > 0);
210 if (!SuccSU->isBoundaryNode() && decNumPreds(SuccSU) == 0)
211 RQ.push_front(*new (Alloc.Allocate()) Candidate(SuccSU, Priority));
215 std::vector<const SUnit*>
216 GCNMinRegScheduler::schedule(ArrayRef<const SUnit*> TopRoots,
217 const ScheduleDAG &DAG) {
218 const auto &SUnits = DAG.SUnits;
219 std::vector<const SUnit*> Schedule;
220 Schedule.reserve(SUnits.size());
222 initNumPreds(SUnits);
226 for (auto SU : TopRoots) {
227 RQ.push_back(*new (Alloc.Allocate()) Candidate(SU, StepNo));
229 releaseSuccessors(&DAG.EntrySU, StepNo);
231 while (!RQ.empty()) {
233 dbgs() << "\n=== Picking candidate, Step = " << StepNo << "\n"
236 dbgs() << ' ' << C.SU->NodeNum << "(P" << C.Priority << ')';
240 auto C = pickCandidate();
244 DEBUG(dbgs() << "Selected "; SU->dump(&DAG));
246 releaseSuccessors(SU, StepNo);
247 Schedule.push_back(SU);
250 if (getReadySuccessors(SU) == 0)
251 bumpPredsPriority(SU, StepNo);
255 assert(SUnits.size() == Schedule.size());
261 std::vector<const SUnit*> makeMinRegSchedule(ArrayRef<const SUnit*> TopRoots,
262 const ScheduleDAG &DAG) {
263 GCNMinRegScheduler S;
264 return S.schedule(TopRoots, DAG);