blob: 884b2e17289c5a71849eecdea443e498f881ae59 [file] [log] [blame]
Eugene Zelenkod16eff82017-08-08 23:53:55 +00001//===- GCNMinRegStrategy.cpp ----------------------------------------------===//
Valery Pykhtinfd4c4102017-03-21 13:15:46 +00002//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Valery Pykhtinfd4c4102017-03-21 13:15:46 +00006//
7//===----------------------------------------------------------------------===//
hsmahesha1d9e08e2020-01-31 01:03:06 +05308///
9/// \file
10/// This file defines and imlements the class GCNMinRegScheduler, which
11/// implements an experimental, simple scheduler whose main goal is to learn
12/// ways about consuming less possible registers for a region.
13///
14//===----------------------------------------------------------------------===//
Valery Pykhtinfd4c4102017-03-21 13:15:46 +000015
Eugene Zelenkod16eff82017-08-08 23:53:55 +000016#include "llvm/ADT/ArrayRef.h"
17#include "llvm/ADT/SmallPtrSet.h"
18#include "llvm/ADT/SmallVector.h"
19#include "llvm/ADT/ilist_node.h"
20#include "llvm/ADT/simple_ilist.h"
Valery Pykhtinfd4c4102017-03-21 13:15:46 +000021#include "llvm/CodeGen/ScheduleDAG.h"
Eugene Zelenkod16eff82017-08-08 23:53:55 +000022#include "llvm/Support/Allocator.h"
23#include "llvm/Support/Debug.h"
24#include "llvm/Support/raw_ostream.h"
25#include <cassert>
26#include <cstdint>
27#include <limits>
28#include <vector>
Valery Pykhtinfd4c4102017-03-21 13:15:46 +000029
30using namespace llvm;
31
Evandro Menezes0cd23f562017-07-11 22:08:28 +000032#define DEBUG_TYPE "machine-scheduler"
Valery Pykhtinfd4c4102017-03-21 13:15:46 +000033
Benjamin Kramerdebb3c32017-05-26 20:09:00 +000034namespace {
Eugene Zelenkod16eff82017-08-08 23:53:55 +000035
Valery Pykhtinfd4c4102017-03-21 13:15:46 +000036class GCNMinRegScheduler {
37 struct Candidate : ilist_node<Candidate> {
38 const SUnit *SU;
39 int Priority;
40
41 Candidate(const SUnit *SU_, int Priority_ = 0)
42 : SU(SU_), Priority(Priority_) {}
43 };
44
45 SpecificBumpPtrAllocator<Candidate> Alloc;
Eugene Zelenkod16eff82017-08-08 23:53:55 +000046 using Queue = simple_ilist<Candidate>;
Valery Pykhtinfd4c4102017-03-21 13:15:46 +000047 Queue RQ; // Ready queue
48
49 std::vector<unsigned> NumPreds;
50
51 bool isScheduled(const SUnit *SU) const {
52 assert(!SU->isBoundaryNode());
53 return NumPreds[SU->NodeNum] == std::numeric_limits<unsigned>::max();
54 }
55
56 void setIsScheduled(const SUnit *SU) {
57 assert(!SU->isBoundaryNode());
58 NumPreds[SU->NodeNum] = std::numeric_limits<unsigned>::max();
59 }
60
61 unsigned getNumPreds(const SUnit *SU) const {
62 assert(!SU->isBoundaryNode());
63 assert(NumPreds[SU->NodeNum] != std::numeric_limits<unsigned>::max());
64 return NumPreds[SU->NodeNum];
65 }
66
67 unsigned decNumPreds(const SUnit *SU) {
68 assert(!SU->isBoundaryNode());
69 assert(NumPreds[SU->NodeNum] != std::numeric_limits<unsigned>::max());
70 return --NumPreds[SU->NodeNum];
71 }
72
73 void initNumPreds(const decltype(ScheduleDAG::SUnits) &SUnits);
74
75 int getReadySuccessors(const SUnit *SU) const;
76 int getNotReadySuccessors(const SUnit *SU) const;
77
78 template <typename Calc>
79 unsigned findMax(unsigned Num, Calc C);
80
81 Candidate* pickCandidate();
82
83 void bumpPredsPriority(const SUnit *SchedSU, int Priority);
84 void releaseSuccessors(const SUnit* SU, int Priority);
85
86public:
87 std::vector<const SUnit*> schedule(ArrayRef<const SUnit*> TopRoots,
88 const ScheduleDAG &DAG);
89};
Eugene Zelenkod16eff82017-08-08 23:53:55 +000090
91} // end anonymous namespace
Valery Pykhtinfd4c4102017-03-21 13:15:46 +000092
93void GCNMinRegScheduler::initNumPreds(const decltype(ScheduleDAG::SUnits) &SUnits) {
94 NumPreds.resize(SUnits.size());
95 for (unsigned I = 0; I < SUnits.size(); ++I)
96 NumPreds[I] = SUnits[I].NumPredsLeft;
97}
98
99int GCNMinRegScheduler::getReadySuccessors(const SUnit *SU) const {
100 unsigned NumSchedSuccs = 0;
101 for (auto SDep : SU->Succs) {
102 bool wouldBeScheduled = true;
103 for (auto PDep : SDep.getSUnit()->Preds) {
104 auto PSU = PDep.getSUnit();
105 assert(!PSU->isBoundaryNode());
106 if (PSU != SU && !isScheduled(PSU)) {
107 wouldBeScheduled = false;
108 break;
109 }
110 }
111 NumSchedSuccs += wouldBeScheduled ? 1 : 0;
112 }
113 return NumSchedSuccs;
114}
115
116int GCNMinRegScheduler::getNotReadySuccessors(const SUnit *SU) const {
117 return SU->Succs.size() - getReadySuccessors(SU);
118}
119
120template <typename Calc>
121unsigned GCNMinRegScheduler::findMax(unsigned Num, Calc C) {
122 assert(!RQ.empty() && Num <= RQ.size());
Eugene Zelenkod16eff82017-08-08 23:53:55 +0000123
124 using T = decltype(C(*RQ.begin())) ;
125
Valery Pykhtinfd4c4102017-03-21 13:15:46 +0000126 T Max = std::numeric_limits<T>::min();
127 unsigned NumMax = 0;
128 for (auto I = RQ.begin(); Num; --Num) {
129 T Cur = C(*I);
130 if (Cur >= Max) {
131 if (Cur > Max) {
132 Max = Cur;
133 NumMax = 1;
134 } else
135 ++NumMax;
136 auto &Cand = *I++;
137 RQ.remove(Cand);
138 RQ.push_front(Cand);
139 continue;
140 }
141 ++I;
142 }
143 return NumMax;
144}
145
146GCNMinRegScheduler::Candidate* GCNMinRegScheduler::pickCandidate() {
147 do {
148 unsigned Num = RQ.size();
149 if (Num == 1) break;
150
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000151 LLVM_DEBUG(dbgs() << "\nSelecting max priority candidates among " << Num
152 << '\n');
Valery Pykhtinfd4c4102017-03-21 13:15:46 +0000153 Num = findMax(Num, [=](const Candidate &C) { return C.Priority; });
154 if (Num == 1) break;
155
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000156 LLVM_DEBUG(dbgs() << "\nSelecting min non-ready producing candidate among "
157 << Num << '\n');
Valery Pykhtinfd4c4102017-03-21 13:15:46 +0000158 Num = findMax(Num, [=](const Candidate &C) {
159 auto SU = C.SU;
160 int Res = getNotReadySuccessors(SU);
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000161 LLVM_DEBUG(dbgs() << "SU(" << SU->NodeNum << ") would left non-ready "
162 << Res << " successors, metric = " << -Res << '\n');
Valery Pykhtinfd4c4102017-03-21 13:15:46 +0000163 return -Res;
164 });
165 if (Num == 1) break;
166
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000167 LLVM_DEBUG(dbgs() << "\nSelecting most producing candidate among " << Num
168 << '\n');
Valery Pykhtinfd4c4102017-03-21 13:15:46 +0000169 Num = findMax(Num, [=](const Candidate &C) {
170 auto SU = C.SU;
171 auto Res = getReadySuccessors(SU);
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000172 LLVM_DEBUG(dbgs() << "SU(" << SU->NodeNum << ") would make ready " << Res
173 << " successors, metric = " << Res << '\n');
Valery Pykhtinfd4c4102017-03-21 13:15:46 +0000174 return Res;
175 });
176 if (Num == 1) break;
177
178 Num = Num ? Num : RQ.size();
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000179 LLVM_DEBUG(
180 dbgs()
181 << "\nCan't find best candidate, selecting in program order among "
182 << Num << '\n');
Valery Pykhtinfd4c4102017-03-21 13:15:46 +0000183 Num = findMax(Num, [=](const Candidate &C) { return -(int64_t)C.SU->NodeNum; });
184 assert(Num == 1);
185 } while (false);
186
187 return &RQ.front();
188}
189
190void GCNMinRegScheduler::bumpPredsPriority(const SUnit *SchedSU, int Priority) {
191 SmallPtrSet<const SUnit*, 32> Set;
192 for (const auto &S : SchedSU->Succs) {
193 if (S.getSUnit()->isBoundaryNode() || isScheduled(S.getSUnit()) ||
194 S.getKind() != SDep::Data)
195 continue;
196 for (const auto &P : S.getSUnit()->Preds) {
197 auto PSU = P.getSUnit();
198 assert(!PSU->isBoundaryNode());
199 if (PSU != SchedSU && !isScheduled(PSU)) {
200 Set.insert(PSU);
201 }
202 }
203 }
204 SmallVector<const SUnit*, 32> Worklist(Set.begin(), Set.end());
205 while (!Worklist.empty()) {
206 auto SU = Worklist.pop_back_val();
207 assert(!SU->isBoundaryNode());
208 for (const auto &P : SU->Preds) {
209 if (!P.getSUnit()->isBoundaryNode() && !isScheduled(P.getSUnit()) &&
210 Set.insert(P.getSUnit()).second)
211 Worklist.push_back(P.getSUnit());
212 }
213 }
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000214 LLVM_DEBUG(dbgs() << "Make the predecessors of SU(" << SchedSU->NodeNum
215 << ")'s non-ready successors of " << Priority
216 << " priority in ready queue: ");
Valery Pykhtinfd4c4102017-03-21 13:15:46 +0000217 for (auto &C : RQ) {
Benjamin Kramer3badd172020-06-07 22:36:10 +0200218 if (Set.count(C.SU)) {
Valery Pykhtinfd4c4102017-03-21 13:15:46 +0000219 C.Priority = Priority;
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000220 LLVM_DEBUG(dbgs() << " SU(" << C.SU->NodeNum << ')');
Valery Pykhtinfd4c4102017-03-21 13:15:46 +0000221 }
222 }
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000223 LLVM_DEBUG(dbgs() << '\n');
Valery Pykhtinfd4c4102017-03-21 13:15:46 +0000224}
225
226void GCNMinRegScheduler::releaseSuccessors(const SUnit* SU, int Priority) {
227 for (const auto &S : SU->Succs) {
228 auto SuccSU = S.getSUnit();
229 if (S.isWeak())
230 continue;
231 assert(SuccSU->isBoundaryNode() || getNumPreds(SuccSU) > 0);
232 if (!SuccSU->isBoundaryNode() && decNumPreds(SuccSU) == 0)
233 RQ.push_front(*new (Alloc.Allocate()) Candidate(SuccSU, Priority));
234 }
235}
236
237std::vector<const SUnit*>
238GCNMinRegScheduler::schedule(ArrayRef<const SUnit*> TopRoots,
239 const ScheduleDAG &DAG) {
240 const auto &SUnits = DAG.SUnits;
241 std::vector<const SUnit*> Schedule;
242 Schedule.reserve(SUnits.size());
243
244 initNumPreds(SUnits);
245
246 int StepNo = 0;
247
248 for (auto SU : TopRoots) {
249 RQ.push_back(*new (Alloc.Allocate()) Candidate(SU, StepNo));
250 }
Alexander Belyaev17dc7292020-09-21 13:18:39 +0200251 releaseSuccessors(&DAG.EntrySU, StepNo);
Valery Pykhtinfd4c4102017-03-21 13:15:46 +0000252
253 while (!RQ.empty()) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000254 LLVM_DEBUG(dbgs() << "\n=== Picking candidate, Step = " << StepNo
255 << "\n"
256 "Ready queue:";
257 for (auto &C
258 : RQ) dbgs()
259 << ' ' << C.SU->NodeNum << "(P" << C.Priority << ')';
260 dbgs() << '\n';);
Valery Pykhtinfd4c4102017-03-21 13:15:46 +0000261
262 auto C = pickCandidate();
263 assert(C);
264 RQ.remove(*C);
265 auto SU = C->SU;
Matthias Braun726e12c2018-09-19 00:23:35 +0000266 LLVM_DEBUG(dbgs() << "Selected "; DAG.dumpNode(*SU));
Valery Pykhtinfd4c4102017-03-21 13:15:46 +0000267
268 releaseSuccessors(SU, StepNo);
269 Schedule.push_back(SU);
270 setIsScheduled(SU);
271
272 if (getReadySuccessors(SU) == 0)
273 bumpPredsPriority(SU, StepNo);
274
275 ++StepNo;
276 }
277 assert(SUnits.size() == Schedule.size());
278
279 return Schedule;
280}
281
282namespace llvm {
Eugene Zelenkod16eff82017-08-08 23:53:55 +0000283
Valery Pykhtinfd4c4102017-03-21 13:15:46 +0000284std::vector<const SUnit*> makeMinRegSchedule(ArrayRef<const SUnit*> TopRoots,
285 const ScheduleDAG &DAG) {
286 GCNMinRegScheduler S;
287 return S.schedule(TopRoots, DAG);
288}
Eugene Zelenkod16eff82017-08-08 23:53:55 +0000289
290} // end namespace llvm