blob: 192d534bb9cfd739c1f91e94f8f5edd6ef66bb0f [file] [log] [blame]
Eugene Zelenkod16eff82017-08-08 23:53:55 +00001//===- GCNMinRegStrategy.cpp ----------------------------------------------===//
Valery Pykhtinfd4c4102017-03-21 13:15:46 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
Valery Pykhtinfd4c4102017-03-21 13:15:46 +00009
Eugene Zelenkod16eff82017-08-08 23:53:55 +000010#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"
Valery Pykhtinfd4c4102017-03-21 13:15:46 +000015#include "llvm/CodeGen/ScheduleDAG.h"
Eugene Zelenkod16eff82017-08-08 23:53:55 +000016#include "llvm/Support/Allocator.h"
17#include "llvm/Support/Debug.h"
18#include "llvm/Support/raw_ostream.h"
19#include <cassert>
20#include <cstdint>
21#include <limits>
22#include <vector>
Valery Pykhtinfd4c4102017-03-21 13:15:46 +000023
24using namespace llvm;
25
Evandro Menezes0cd23f562017-07-11 22:08:28 +000026#define DEBUG_TYPE "machine-scheduler"
Valery Pykhtinfd4c4102017-03-21 13:15:46 +000027
Benjamin Kramerdebb3c32017-05-26 20:09:00 +000028namespace {
Eugene Zelenkod16eff82017-08-08 23:53:55 +000029
Valery Pykhtinfd4c4102017-03-21 13:15:46 +000030class GCNMinRegScheduler {
31 struct Candidate : ilist_node<Candidate> {
32 const SUnit *SU;
33 int Priority;
34
35 Candidate(const SUnit *SU_, int Priority_ = 0)
36 : SU(SU_), Priority(Priority_) {}
37 };
38
39 SpecificBumpPtrAllocator<Candidate> Alloc;
Eugene Zelenkod16eff82017-08-08 23:53:55 +000040 using Queue = simple_ilist<Candidate>;
Valery Pykhtinfd4c4102017-03-21 13:15:46 +000041 Queue RQ; // Ready queue
42
43 std::vector<unsigned> NumPreds;
44
45 bool isScheduled(const SUnit *SU) const {
46 assert(!SU->isBoundaryNode());
47 return NumPreds[SU->NodeNum] == std::numeric_limits<unsigned>::max();
48 }
49
50 void setIsScheduled(const SUnit *SU) {
51 assert(!SU->isBoundaryNode());
52 NumPreds[SU->NodeNum] = std::numeric_limits<unsigned>::max();
53 }
54
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];
59 }
60
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];
65 }
66
67 void initNumPreds(const decltype(ScheduleDAG::SUnits) &SUnits);
68
69 int getReadySuccessors(const SUnit *SU) const;
70 int getNotReadySuccessors(const SUnit *SU) const;
71
72 template <typename Calc>
73 unsigned findMax(unsigned Num, Calc C);
74
75 Candidate* pickCandidate();
76
77 void bumpPredsPriority(const SUnit *SchedSU, int Priority);
78 void releaseSuccessors(const SUnit* SU, int Priority);
79
80public:
81 std::vector<const SUnit*> schedule(ArrayRef<const SUnit*> TopRoots,
82 const ScheduleDAG &DAG);
83};
Eugene Zelenkod16eff82017-08-08 23:53:55 +000084
85} // end anonymous namespace
Valery Pykhtinfd4c4102017-03-21 13:15:46 +000086
87void 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;
91}
92
93int 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;
102 break;
103 }
104 }
105 NumSchedSuccs += wouldBeScheduled ? 1 : 0;
106 }
107 return NumSchedSuccs;
108}
109
110int GCNMinRegScheduler::getNotReadySuccessors(const SUnit *SU) const {
111 return SU->Succs.size() - getReadySuccessors(SU);
112}
113
114template <typename Calc>
115unsigned GCNMinRegScheduler::findMax(unsigned Num, Calc C) {
116 assert(!RQ.empty() && Num <= RQ.size());
Eugene Zelenkod16eff82017-08-08 23:53:55 +0000117
118 using T = decltype(C(*RQ.begin())) ;
119
Valery Pykhtinfd4c4102017-03-21 13:15:46 +0000120 T Max = std::numeric_limits<T>::min();
121 unsigned NumMax = 0;
122 for (auto I = RQ.begin(); Num; --Num) {
123 T Cur = C(*I);
124 if (Cur >= Max) {
125 if (Cur > Max) {
126 Max = Cur;
127 NumMax = 1;
128 } else
129 ++NumMax;
130 auto &Cand = *I++;
131 RQ.remove(Cand);
132 RQ.push_front(Cand);
133 continue;
134 }
135 ++I;
136 }
137 return NumMax;
138}
139
140GCNMinRegScheduler::Candidate* GCNMinRegScheduler::pickCandidate() {
141 do {
142 unsigned Num = RQ.size();
143 if (Num == 1) break;
144
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000145 LLVM_DEBUG(dbgs() << "\nSelecting max priority candidates among " << Num
146 << '\n');
Valery Pykhtinfd4c4102017-03-21 13:15:46 +0000147 Num = findMax(Num, [=](const Candidate &C) { return C.Priority; });
148 if (Num == 1) break;
149
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000150 LLVM_DEBUG(dbgs() << "\nSelecting min non-ready producing candidate among "
151 << Num << '\n');
Valery Pykhtinfd4c4102017-03-21 13:15:46 +0000152 Num = findMax(Num, [=](const Candidate &C) {
153 auto SU = C.SU;
154 int Res = getNotReadySuccessors(SU);
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000155 LLVM_DEBUG(dbgs() << "SU(" << SU->NodeNum << ") would left non-ready "
156 << Res << " successors, metric = " << -Res << '\n');
Valery Pykhtinfd4c4102017-03-21 13:15:46 +0000157 return -Res;
158 });
159 if (Num == 1) break;
160
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000161 LLVM_DEBUG(dbgs() << "\nSelecting most producing candidate among " << Num
162 << '\n');
Valery Pykhtinfd4c4102017-03-21 13:15:46 +0000163 Num = findMax(Num, [=](const Candidate &C) {
164 auto SU = C.SU;
165 auto Res = getReadySuccessors(SU);
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000166 LLVM_DEBUG(dbgs() << "SU(" << SU->NodeNum << ") would make ready " << Res
167 << " successors, metric = " << Res << '\n');
Valery Pykhtinfd4c4102017-03-21 13:15:46 +0000168 return Res;
169 });
170 if (Num == 1) break;
171
172 Num = Num ? Num : RQ.size();
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000173 LLVM_DEBUG(
174 dbgs()
175 << "\nCan't find best candidate, selecting in program order among "
176 << Num << '\n');
Valery Pykhtinfd4c4102017-03-21 13:15:46 +0000177 Num = findMax(Num, [=](const Candidate &C) { return -(int64_t)C.SU->NodeNum; });
178 assert(Num == 1);
179 } while (false);
180
181 return &RQ.front();
182}
183
184void GCNMinRegScheduler::bumpPredsPriority(const SUnit *SchedSU, int Priority) {
185 SmallPtrSet<const SUnit*, 32> Set;
186 for (const auto &S : SchedSU->Succs) {
187 if (S.getSUnit()->isBoundaryNode() || isScheduled(S.getSUnit()) ||
188 S.getKind() != SDep::Data)
189 continue;
190 for (const auto &P : S.getSUnit()->Preds) {
191 auto PSU = P.getSUnit();
192 assert(!PSU->isBoundaryNode());
193 if (PSU != SchedSU && !isScheduled(PSU)) {
194 Set.insert(PSU);
195 }
196 }
197 }
198 SmallVector<const SUnit*, 32> Worklist(Set.begin(), Set.end());
199 while (!Worklist.empty()) {
200 auto SU = Worklist.pop_back_val();
201 assert(!SU->isBoundaryNode());
202 for (const auto &P : SU->Preds) {
203 if (!P.getSUnit()->isBoundaryNode() && !isScheduled(P.getSUnit()) &&
204 Set.insert(P.getSUnit()).second)
205 Worklist.push_back(P.getSUnit());
206 }
207 }
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000208 LLVM_DEBUG(dbgs() << "Make the predecessors of SU(" << SchedSU->NodeNum
209 << ")'s non-ready successors of " << Priority
210 << " priority in ready queue: ");
Valery Pykhtinfd4c4102017-03-21 13:15:46 +0000211 const auto SetEnd = Set.end();
212 for (auto &C : RQ) {
213 if (Set.find(C.SU) != SetEnd) {
214 C.Priority = Priority;
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000215 LLVM_DEBUG(dbgs() << " SU(" << C.SU->NodeNum << ')');
Valery Pykhtinfd4c4102017-03-21 13:15:46 +0000216 }
217 }
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000218 LLVM_DEBUG(dbgs() << '\n');
Valery Pykhtinfd4c4102017-03-21 13:15:46 +0000219}
220
221void GCNMinRegScheduler::releaseSuccessors(const SUnit* SU, int Priority) {
222 for (const auto &S : SU->Succs) {
223 auto SuccSU = S.getSUnit();
224 if (S.isWeak())
225 continue;
226 assert(SuccSU->isBoundaryNode() || getNumPreds(SuccSU) > 0);
227 if (!SuccSU->isBoundaryNode() && decNumPreds(SuccSU) == 0)
228 RQ.push_front(*new (Alloc.Allocate()) Candidate(SuccSU, Priority));
229 }
230}
231
232std::vector<const SUnit*>
233GCNMinRegScheduler::schedule(ArrayRef<const SUnit*> TopRoots,
234 const ScheduleDAG &DAG) {
235 const auto &SUnits = DAG.SUnits;
236 std::vector<const SUnit*> Schedule;
237 Schedule.reserve(SUnits.size());
238
239 initNumPreds(SUnits);
240
241 int StepNo = 0;
242
243 for (auto SU : TopRoots) {
244 RQ.push_back(*new (Alloc.Allocate()) Candidate(SU, StepNo));
245 }
246 releaseSuccessors(&DAG.EntrySU, StepNo);
247
248 while (!RQ.empty()) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000249 LLVM_DEBUG(dbgs() << "\n=== Picking candidate, Step = " << StepNo
250 << "\n"
251 "Ready queue:";
252 for (auto &C
253 : RQ) dbgs()
254 << ' ' << C.SU->NodeNum << "(P" << C.Priority << ')';
255 dbgs() << '\n';);
Valery Pykhtinfd4c4102017-03-21 13:15:46 +0000256
257 auto C = pickCandidate();
258 assert(C);
259 RQ.remove(*C);
260 auto SU = C->SU;
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000261 LLVM_DEBUG(dbgs() << "Selected "; SU->dump(&DAG));
Valery Pykhtinfd4c4102017-03-21 13:15:46 +0000262
263 releaseSuccessors(SU, StepNo);
264 Schedule.push_back(SU);
265 setIsScheduled(SU);
266
267 if (getReadySuccessors(SU) == 0)
268 bumpPredsPriority(SU, StepNo);
269
270 ++StepNo;
271 }
272 assert(SUnits.size() == Schedule.size());
273
274 return Schedule;
275}
276
277namespace llvm {
Eugene Zelenkod16eff82017-08-08 23:53:55 +0000278
Valery Pykhtinfd4c4102017-03-21 13:15:46 +0000279std::vector<const SUnit*> makeMinRegSchedule(ArrayRef<const SUnit*> TopRoots,
280 const ScheduleDAG &DAG) {
281 GCNMinRegScheduler S;
282 return S.schedule(TopRoots, DAG);
283}
Eugene Zelenkod16eff82017-08-08 23:53:55 +0000284
285} // end namespace llvm