LLVM: lib/Target/AMDGPU/GCNILPSched.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
14
15using namespace llvm;
16
17#define DEBUG_TYPE "machine-scheduler"
18
19namespace {
20
21class GCNILPScheduler {
22 struct Candidate : ilist_node {
24
25 Candidate(SUnit *SU_)
26 : SU(SU_) {}
27 };
28
31 Queue PendingQueue;
32 Queue AvailQueue;
33 unsigned CurQueueId = 0;
34
35 std::vector SUNumbers;
36
37
38 unsigned CurCycle = 0;
39
40 unsigned getNodePriority(const SUnit *SU) const;
41
42 const SUnit *pickBest(const SUnit *left, const SUnit *right);
43 Candidate* pickCandidate();
44
45 void releasePending();
46 void advanceToCycle(unsigned NextCycle);
47 void releasePredecessors(const SUnit* SU);
48
49public:
52};
53}
54
55
56
57static unsigned
59 unsigned &SethiUllmanNumber = SUNumbers[SU->NodeNum];
60 if (SethiUllmanNumber != 0)
61 return SethiUllmanNumber;
62
63 unsigned Extra = 0;
64 for (const SDep &Pred : SU->Preds) {
65 if (Pred.isCtrl()) continue;
66 SUnit *PredSU = Pred.getSUnit();
68 if (PredSethiUllman > SethiUllmanNumber) {
69 SethiUllmanNumber = PredSethiUllman;
70 Extra = 0;
71 }
72 else if (PredSethiUllman == SethiUllmanNumber)
73 ++Extra;
74 }
75
76 SethiUllmanNumber += Extra;
77
78 if (SethiUllmanNumber == 0)
79 SethiUllmanNumber = 1;
80
81 return SethiUllmanNumber;
82}
83
84
85
86unsigned GCNILPScheduler::getNodePriority(const SUnit *SU) const {
89
90
91
92
93
94 return 0xffff;
95
97
98
99 return 0;
100
101 return SUNumbers[SU->NodeNum];
102}
103
104
105
107 unsigned MaxHeight = 0;
108 for (const SDep &Succ : SU->Succs) {
109 if (Succ.isCtrl()) continue;
111
112
113 if (Height > MaxHeight)
114 MaxHeight = Height;
115 }
116 return MaxHeight;
117}
118
119
120
122 unsigned Scratches = 0;
123 for (const SDep &Pred : SU->Preds) {
124 if (Pred.isCtrl()) continue;
125 Scratches++;
126 }
127 return Scratches;
128}
129
130
131
133
134
135 int LHeight = (int)left->getHeight();
136 int RHeight = (int)right->getHeight();
137
138
139
140
141
142
143
144
145 if (LHeight != RHeight)
146 return LHeight > RHeight ? 1 : -1;
147
148 int LDepth = left->getDepth();
149 int RDepth = right->getDepth();
150 if (LDepth != RDepth) {
152 << ") depth " << LDepth << " vs SU (" << right->NodeNum
153 << ") depth " << RDepth << "\n");
154 return LDepth < RDepth ? 1 : -1;
155 }
158
159 return 0;
160}
161
162const SUnit *GCNILPScheduler::pickBest(const SUnit *left, const SUnit *right)
163{
164
165
173 << "): " << right->getDepth() << "\n");
175 }
176 }
177
183 }
184
185
186 unsigned LPriority = getNodePriority(left);
187 unsigned RPriority = getNodePriority(right);
188
189 if (LPriority != RPriority)
190 return LPriority > RPriority ? right : left;
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
211 if (LDist != RDist)
212 return LDist < RDist ? right : left;
213
214
217 if (LScratch != RScratch)
218 return LScratch > RScratch ? right : left;
219
223 if (result != 0)
224 return result > 0 ? right : left;
225 return left;
226 }
229
231 return (left->getDepth() < right->getDepth()) ? right : left;
232
234 "NodeQueueId cannot be zero");
236}
237
238GCNILPScheduler::Candidate* GCNILPScheduler::pickCandidate() {
239 if (AvailQueue.empty())
240 return nullptr;
241 auto Best = AvailQueue.begin();
242 for (auto I = std::next(AvailQueue.begin()), E = AvailQueue.end(); I != E; ++I) {
243 const auto *NewBestSU = pickBest(Best->SU, I->SU);
244 if (NewBestSU != Best->SU) {
245 assert(NewBestSU == I->SU);
246 Best = I;
247 }
248 }
249 return &*Best;
250}
251
252void GCNILPScheduler::releasePending() {
253
254
255 for(auto I = PendingQueue.begin(), E = PendingQueue.end(); I != E;) {
257 if (C.SU->getHeight() <= CurCycle) {
260 C.SU->NodeQueueId = CurQueueId++;
261 }
262 }
263}
264
265
266void GCNILPScheduler::advanceToCycle(unsigned NextCycle) {
267 if (NextCycle <= CurCycle)
268 return;
269 CurCycle = NextCycle;
270 releasePending();
271}
272
273void GCNILPScheduler::releasePredecessors(const SUnit* SU) {
274 for (const auto &PredEdge : SU->Preds) {
275 auto *PredSU = PredEdge.getSUnit();
276 if (PredEdge.isWeak())
277 continue;
278 assert(PredSU->isBoundaryNode() || PredSU->NumSuccsLeft > 0);
279
280 PredSU->setHeightToAtLeast(SU->getHeight() + PredEdge.getLatency());
281
282 if (!PredSU->isBoundaryNode() && --PredSU->NumSuccsLeft == 0)
283 PendingQueue.push_front(*new (Alloc.Allocate()) Candidate(PredSU));
284 }
285}
286
287std::vector<const SUnit*>
288GCNILPScheduler::schedule(ArrayRef<const SUnit*> BotRoots,
289 const ScheduleDAG &DAG) {
290 auto &SUnits = const_cast<ScheduleDAG&>(DAG).SUnits;
291
292 std::vector SUSavedCopy;
293 SUSavedCopy.resize(SUnits.size());
294
295
296
297 for (const SUnit &SU : SUnits)
298 SUSavedCopy[SU.NodeNum] = SU;
299
300 SUNumbers.assign(SUnits.size(), 0);
301 for (const SUnit &SU : SUnits)
303
304 for (const auto *SU : BotRoots) {
306 *new (Alloc.Allocate()) Candidate(const_cast<SUnit*>(SU)));
307 }
308 releasePredecessors(&DAG.ExitSU);
309
310 std::vector<const SUnit*> Schedule;
311 Schedule.reserve(SUnits.size());
312 while (true) {
313 if (AvailQueue.empty() && !PendingQueue.empty()) {
314 auto *EarliestSU =
316 const Candidate &C2) {
317 return C1.SU->getHeight() < C2.SU->getHeight();
318 })->SU;
319 advanceToCycle(std::max(CurCycle + 1, EarliestSU->getHeight()));
320 }
321 if (AvailQueue.empty())
322 break;
323
325 "Ready queue:";
326 for (auto &C
327 : AvailQueue) dbgs()
328 << ' ' << C.SU->NodeNum;
329 dbgs() << '\n';);
330
331 auto *C = pickCandidate();
333 AvailQueue.remove(*C);
334 auto *SU = C->SU;
336
338
339 releasePredecessors(SU);
340 Schedule.push_back(SU);
342 }
343 assert(SUnits.size() == Schedule.size());
344
345 std::reverse(Schedule.begin(), Schedule.end());
346
347
348 for (auto &SU : SUnits)
349 SU = SUSavedCopy[SU.NodeNum];
350
351 return Schedule;
352}
353
354namespace llvm {
357 GCNILPScheduler S;
358 return S.schedule(BotRoots, DAG);
359}
360}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU Prepare AGPR Alloc
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static unsigned CalcNodeSethiUllmanNumber(const SUnit *SU, std::vector< unsigned > &SUNumbers)
CalcNodeSethiUllmanNumber - Compute Sethi Ullman number.
Definition GCNILPSched.cpp:58
static cl::opt< bool > DisableSchedCycles("disable-sched-cycles", cl::Hidden, cl::init(false), cl::desc("Disable cycle-level precision during preRA scheduling"))
static cl::opt< bool > DisableSchedCriticalPath("disable-sched-critical-path", cl::Hidden, cl::init(false), cl::desc("Disable critical path priority in sched=list-ilp"))
static cl::opt< int > MaxReorderWindow("max-sched-reorder", cl::Hidden, cl::init(6), cl::desc("Number of instructions to allow ahead of the critical path " "in sched=list-ilp"))
static unsigned closestSucc(const SUnit *SU)
closestSucc - Returns the scheduled cycle of the successor which is closest to the current cycle.
static cl::opt< bool > DisableSchedHeight("disable-sched-height", cl::Hidden, cl::init(false), cl::desc("Disable scheduled-height priority in sched=list-ilp"))
static unsigned calcMaxScratches(const SUnit *SU)
calcMaxScratches - Returns an cost estimate of the worse case requirement for scratch registers,...
static unsigned CalcNodeSethiUllmanNumber(const SUnit *SU, std::vector< unsigned > &SUNumbers)
CalcNodeSethiUllmanNumber - Compute Sethi Ullman number.
static int BUCompareLatency(SUnit *left, SUnit *right, bool checkPref, RegReductionPQBase *SPQ)
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
bool isCtrl() const
Shorthand for getKind() != SDep::Data.
Scheduling unit. This is a node in the scheduling DAG.
unsigned NodeQueueId
Queue id of node.
unsigned NodeNum
Entry # of node in the node vector.
unsigned getHeight() const
Returns the height of this node, which is the length of the maximum path down to any node which has n...
unsigned short Latency
Node latency.
unsigned getDepth() const
Returns the depth of this node, which is the length of the maximum path up to any node which has no p...
bool isScheduled
True once scheduled.
SmallVector< SDep, 4 > Succs
All sunit successors.
SmallVector< SDep, 4 > Preds
All sunit predecessors.
virtual void dumpNode(const SUnit &SU) const =0
SUnit ExitSU
Special node for the region exit.
A BumpPtrAllocator that allows only elements of a specific type to be allocated.
A simple intrusive list implementation.
void push_front(reference Node)
Insert a node at the front; never copies.
bool empty() const
Check if the list is empty in constant time.
void push_back(reference Node)
Insert a node at the back; never copies.
void remove(reference N)
Remove a node by reference; never deletes.
@ C
The default llvm calling convention, compatible with C.
This is an optimization pass for GlobalISel generic memory operations.
auto min_element(R &&Range)
Provide wrappers to std::min_element which take ranges instead of having to pass begin/end explicitly...
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
std::vector< const SUnit * > makeGCNILPScheduler(ArrayRef< const SUnit * > BotRoots, const ScheduleDAG &DAG)
Definition GCNILPSched.cpp:355