1d16eff81SEugene Zelenko //===- GCNMinRegStrategy.cpp ----------------------------------------------===//
2fd4c410fSValery Pykhtin //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fd4c410fSValery Pykhtin //
7fd4c410fSValery Pykhtin //===----------------------------------------------------------------------===//
81d9e08ecShsmahesha ///
91d9e08ecShsmahesha /// \file
10*d1f45ed5SNeubauer, Sebastian /// This file defines and implements the class GCNMinRegScheduler, which
111d9e08ecShsmahesha /// implements an experimental, simple scheduler whose main goal is to learn
121d9e08ecShsmahesha /// ways about consuming less possible registers for a region.
131d9e08ecShsmahesha ///
141d9e08ecShsmahesha //===----------------------------------------------------------------------===//
15fd4c410fSValery Pykhtin
16fd4c410fSValery Pykhtin #include "llvm/CodeGen/ScheduleDAG.h"
17fd4c410fSValery Pykhtin using namespace llvm;
18fd4c410fSValery Pykhtin
190cd23f56SEvandro Menezes #define DEBUG_TYPE "machine-scheduler"
20fd4c410fSValery Pykhtin
21debb3c35SBenjamin Kramer namespace {
22d16eff81SEugene Zelenko
23fd4c410fSValery Pykhtin class GCNMinRegScheduler {
24fd4c410fSValery Pykhtin struct Candidate : ilist_node<Candidate> {
25fd4c410fSValery Pykhtin const SUnit *SU;
26fd4c410fSValery Pykhtin int Priority;
27fd4c410fSValery Pykhtin
Candidate__anon7060f7100111::GCNMinRegScheduler::Candidate28fd4c410fSValery Pykhtin Candidate(const SUnit *SU_, int Priority_ = 0)
29fd4c410fSValery Pykhtin : SU(SU_), Priority(Priority_) {}
30fd4c410fSValery Pykhtin };
31fd4c410fSValery Pykhtin
32fd4c410fSValery Pykhtin SpecificBumpPtrAllocator<Candidate> Alloc;
33d16eff81SEugene Zelenko using Queue = simple_ilist<Candidate>;
34fd4c410fSValery Pykhtin Queue RQ; // Ready queue
35fd4c410fSValery Pykhtin
36fd4c410fSValery Pykhtin std::vector<unsigned> NumPreds;
37fd4c410fSValery Pykhtin
isScheduled(const SUnit * SU) const38fd4c410fSValery Pykhtin bool isScheduled(const SUnit *SU) const {
39fd4c410fSValery Pykhtin assert(!SU->isBoundaryNode());
40fd4c410fSValery Pykhtin return NumPreds[SU->NodeNum] == std::numeric_limits<unsigned>::max();
41fd4c410fSValery Pykhtin }
42fd4c410fSValery Pykhtin
setIsScheduled(const SUnit * SU)43fd4c410fSValery Pykhtin void setIsScheduled(const SUnit *SU) {
44fd4c410fSValery Pykhtin assert(!SU->isBoundaryNode());
45fd4c410fSValery Pykhtin NumPreds[SU->NodeNum] = std::numeric_limits<unsigned>::max();
46fd4c410fSValery Pykhtin }
47fd4c410fSValery Pykhtin
getNumPreds(const SUnit * SU) const48fd4c410fSValery Pykhtin unsigned getNumPreds(const SUnit *SU) const {
49fd4c410fSValery Pykhtin assert(!SU->isBoundaryNode());
50fd4c410fSValery Pykhtin assert(NumPreds[SU->NodeNum] != std::numeric_limits<unsigned>::max());
51fd4c410fSValery Pykhtin return NumPreds[SU->NodeNum];
52fd4c410fSValery Pykhtin }
53fd4c410fSValery Pykhtin
decNumPreds(const SUnit * SU)54fd4c410fSValery Pykhtin unsigned decNumPreds(const SUnit *SU) {
55fd4c410fSValery Pykhtin assert(!SU->isBoundaryNode());
56fd4c410fSValery Pykhtin assert(NumPreds[SU->NodeNum] != std::numeric_limits<unsigned>::max());
57fd4c410fSValery Pykhtin return --NumPreds[SU->NodeNum];
58fd4c410fSValery Pykhtin }
59fd4c410fSValery Pykhtin
60fd4c410fSValery Pykhtin void initNumPreds(const decltype(ScheduleDAG::SUnits) &SUnits);
61fd4c410fSValery Pykhtin
62fd4c410fSValery Pykhtin int getReadySuccessors(const SUnit *SU) const;
63fd4c410fSValery Pykhtin int getNotReadySuccessors(const SUnit *SU) const;
64fd4c410fSValery Pykhtin
65fd4c410fSValery Pykhtin template <typename Calc>
66fd4c410fSValery Pykhtin unsigned findMax(unsigned Num, Calc C);
67fd4c410fSValery Pykhtin
68fd4c410fSValery Pykhtin Candidate* pickCandidate();
69fd4c410fSValery Pykhtin
70fd4c410fSValery Pykhtin void bumpPredsPriority(const SUnit *SchedSU, int Priority);
71fd4c410fSValery Pykhtin void releaseSuccessors(const SUnit* SU, int Priority);
72fd4c410fSValery Pykhtin
73fd4c410fSValery Pykhtin public:
74fd4c410fSValery Pykhtin std::vector<const SUnit*> schedule(ArrayRef<const SUnit*> TopRoots,
75fd4c410fSValery Pykhtin const ScheduleDAG &DAG);
76fd4c410fSValery Pykhtin };
77d16eff81SEugene Zelenko
78d16eff81SEugene Zelenko } // end anonymous namespace
79fd4c410fSValery Pykhtin
initNumPreds(const decltype(ScheduleDAG::SUnits) & SUnits)80fd4c410fSValery Pykhtin void GCNMinRegScheduler::initNumPreds(const decltype(ScheduleDAG::SUnits) &SUnits) {
81fd4c410fSValery Pykhtin NumPreds.resize(SUnits.size());
82fd4c410fSValery Pykhtin for (unsigned I = 0; I < SUnits.size(); ++I)
83fd4c410fSValery Pykhtin NumPreds[I] = SUnits[I].NumPredsLeft;
84fd4c410fSValery Pykhtin }
85fd4c410fSValery Pykhtin
getReadySuccessors(const SUnit * SU) const86fd4c410fSValery Pykhtin int GCNMinRegScheduler::getReadySuccessors(const SUnit *SU) const {
87fd4c410fSValery Pykhtin unsigned NumSchedSuccs = 0;
88fd4c410fSValery Pykhtin for (auto SDep : SU->Succs) {
89fd4c410fSValery Pykhtin bool wouldBeScheduled = true;
90fd4c410fSValery Pykhtin for (auto PDep : SDep.getSUnit()->Preds) {
91fd4c410fSValery Pykhtin auto PSU = PDep.getSUnit();
92fd4c410fSValery Pykhtin assert(!PSU->isBoundaryNode());
93fd4c410fSValery Pykhtin if (PSU != SU && !isScheduled(PSU)) {
94fd4c410fSValery Pykhtin wouldBeScheduled = false;
95fd4c410fSValery Pykhtin break;
96fd4c410fSValery Pykhtin }
97fd4c410fSValery Pykhtin }
98fd4c410fSValery Pykhtin NumSchedSuccs += wouldBeScheduled ? 1 : 0;
99fd4c410fSValery Pykhtin }
100fd4c410fSValery Pykhtin return NumSchedSuccs;
101fd4c410fSValery Pykhtin }
102fd4c410fSValery Pykhtin
getNotReadySuccessors(const SUnit * SU) const103fd4c410fSValery Pykhtin int GCNMinRegScheduler::getNotReadySuccessors(const SUnit *SU) const {
104fd4c410fSValery Pykhtin return SU->Succs.size() - getReadySuccessors(SU);
105fd4c410fSValery Pykhtin }
106fd4c410fSValery Pykhtin
107fd4c410fSValery Pykhtin template <typename Calc>
findMax(unsigned Num,Calc C)108fd4c410fSValery Pykhtin unsigned GCNMinRegScheduler::findMax(unsigned Num, Calc C) {
109fd4c410fSValery Pykhtin assert(!RQ.empty() && Num <= RQ.size());
110d16eff81SEugene Zelenko
111d16eff81SEugene Zelenko using T = decltype(C(*RQ.begin())) ;
112d16eff81SEugene Zelenko
113fd4c410fSValery Pykhtin T Max = std::numeric_limits<T>::min();
114fd4c410fSValery Pykhtin unsigned NumMax = 0;
115fd4c410fSValery Pykhtin for (auto I = RQ.begin(); Num; --Num) {
116fd4c410fSValery Pykhtin T Cur = C(*I);
117fd4c410fSValery Pykhtin if (Cur >= Max) {
118fd4c410fSValery Pykhtin if (Cur > Max) {
119fd4c410fSValery Pykhtin Max = Cur;
120fd4c410fSValery Pykhtin NumMax = 1;
121fd4c410fSValery Pykhtin } else
122fd4c410fSValery Pykhtin ++NumMax;
123fd4c410fSValery Pykhtin auto &Cand = *I++;
124fd4c410fSValery Pykhtin RQ.remove(Cand);
125fd4c410fSValery Pykhtin RQ.push_front(Cand);
126fd4c410fSValery Pykhtin continue;
127fd4c410fSValery Pykhtin }
128fd4c410fSValery Pykhtin ++I;
129fd4c410fSValery Pykhtin }
130fd4c410fSValery Pykhtin return NumMax;
131fd4c410fSValery Pykhtin }
132fd4c410fSValery Pykhtin
pickCandidate()133fd4c410fSValery Pykhtin GCNMinRegScheduler::Candidate* GCNMinRegScheduler::pickCandidate() {
134fd4c410fSValery Pykhtin do {
135fd4c410fSValery Pykhtin unsigned Num = RQ.size();
136fd4c410fSValery Pykhtin if (Num == 1) break;
137fd4c410fSValery Pykhtin
138d34e60caSNicola Zaghen LLVM_DEBUG(dbgs() << "\nSelecting max priority candidates among " << Num
139d34e60caSNicola Zaghen << '\n');
140fd4c410fSValery Pykhtin Num = findMax(Num, [=](const Candidate &C) { return C.Priority; });
141fd4c410fSValery Pykhtin if (Num == 1) break;
142fd4c410fSValery Pykhtin
143d34e60caSNicola Zaghen LLVM_DEBUG(dbgs() << "\nSelecting min non-ready producing candidate among "
144fd4c410fSValery Pykhtin << Num << '\n');
145fd4c410fSValery Pykhtin Num = findMax(Num, [=](const Candidate &C) {
146fd4c410fSValery Pykhtin auto SU = C.SU;
147fd4c410fSValery Pykhtin int Res = getNotReadySuccessors(SU);
148d34e60caSNicola Zaghen LLVM_DEBUG(dbgs() << "SU(" << SU->NodeNum << ") would left non-ready "
149fd4c410fSValery Pykhtin << Res << " successors, metric = " << -Res << '\n');
150fd4c410fSValery Pykhtin return -Res;
151fd4c410fSValery Pykhtin });
152fd4c410fSValery Pykhtin if (Num == 1) break;
153fd4c410fSValery Pykhtin
154d34e60caSNicola Zaghen LLVM_DEBUG(dbgs() << "\nSelecting most producing candidate among " << Num
155d34e60caSNicola Zaghen << '\n');
156fd4c410fSValery Pykhtin Num = findMax(Num, [=](const Candidate &C) {
157fd4c410fSValery Pykhtin auto SU = C.SU;
158fd4c410fSValery Pykhtin auto Res = getReadySuccessors(SU);
159d34e60caSNicola Zaghen LLVM_DEBUG(dbgs() << "SU(" << SU->NodeNum << ") would make ready " << Res
160d34e60caSNicola Zaghen << " successors, metric = " << Res << '\n');
161fd4c410fSValery Pykhtin return Res;
162fd4c410fSValery Pykhtin });
163fd4c410fSValery Pykhtin if (Num == 1) break;
164fd4c410fSValery Pykhtin
165fd4c410fSValery Pykhtin Num = Num ? Num : RQ.size();
166d34e60caSNicola Zaghen LLVM_DEBUG(
167d34e60caSNicola Zaghen dbgs()
168d34e60caSNicola Zaghen << "\nCan't find best candidate, selecting in program order among "
169fd4c410fSValery Pykhtin << Num << '\n');
170fd4c410fSValery Pykhtin Num = findMax(Num, [=](const Candidate &C) { return -(int64_t)C.SU->NodeNum; });
171fd4c410fSValery Pykhtin assert(Num == 1);
172fd4c410fSValery Pykhtin } while (false);
173fd4c410fSValery Pykhtin
174fd4c410fSValery Pykhtin return &RQ.front();
175fd4c410fSValery Pykhtin }
176fd4c410fSValery Pykhtin
bumpPredsPriority(const SUnit * SchedSU,int Priority)177fd4c410fSValery Pykhtin void GCNMinRegScheduler::bumpPredsPriority(const SUnit *SchedSU, int Priority) {
178fd4c410fSValery Pykhtin SmallPtrSet<const SUnit*, 32> Set;
179fd4c410fSValery Pykhtin for (const auto &S : SchedSU->Succs) {
180fd4c410fSValery Pykhtin if (S.getSUnit()->isBoundaryNode() || isScheduled(S.getSUnit()) ||
181fd4c410fSValery Pykhtin S.getKind() != SDep::Data)
182fd4c410fSValery Pykhtin continue;
183fd4c410fSValery Pykhtin for (const auto &P : S.getSUnit()->Preds) {
184fd4c410fSValery Pykhtin auto PSU = P.getSUnit();
185fd4c410fSValery Pykhtin assert(!PSU->isBoundaryNode());
186fd4c410fSValery Pykhtin if (PSU != SchedSU && !isScheduled(PSU)) {
187fd4c410fSValery Pykhtin Set.insert(PSU);
188fd4c410fSValery Pykhtin }
189fd4c410fSValery Pykhtin }
190fd4c410fSValery Pykhtin }
191fd4c410fSValery Pykhtin SmallVector<const SUnit*, 32> Worklist(Set.begin(), Set.end());
192fd4c410fSValery Pykhtin while (!Worklist.empty()) {
193fd4c410fSValery Pykhtin auto SU = Worklist.pop_back_val();
194fd4c410fSValery Pykhtin assert(!SU->isBoundaryNode());
195fd4c410fSValery Pykhtin for (const auto &P : SU->Preds) {
196fd4c410fSValery Pykhtin if (!P.getSUnit()->isBoundaryNode() && !isScheduled(P.getSUnit()) &&
197fd4c410fSValery Pykhtin Set.insert(P.getSUnit()).second)
198fd4c410fSValery Pykhtin Worklist.push_back(P.getSUnit());
199fd4c410fSValery Pykhtin }
200fd4c410fSValery Pykhtin }
201d34e60caSNicola Zaghen LLVM_DEBUG(dbgs() << "Make the predecessors of SU(" << SchedSU->NodeNum
202fd4c410fSValery Pykhtin << ")'s non-ready successors of " << Priority
203fd4c410fSValery Pykhtin << " priority in ready queue: ");
204fd4c410fSValery Pykhtin for (auto &C : RQ) {
2053badd17bSBenjamin Kramer if (Set.count(C.SU)) {
206fd4c410fSValery Pykhtin C.Priority = Priority;
207d34e60caSNicola Zaghen LLVM_DEBUG(dbgs() << " SU(" << C.SU->NodeNum << ')');
208fd4c410fSValery Pykhtin }
209fd4c410fSValery Pykhtin }
210d34e60caSNicola Zaghen LLVM_DEBUG(dbgs() << '\n');
211fd4c410fSValery Pykhtin }
212fd4c410fSValery Pykhtin
releaseSuccessors(const SUnit * SU,int Priority)213fd4c410fSValery Pykhtin void GCNMinRegScheduler::releaseSuccessors(const SUnit* SU, int Priority) {
214fd4c410fSValery Pykhtin for (const auto &S : SU->Succs) {
215fd4c410fSValery Pykhtin auto SuccSU = S.getSUnit();
216fd4c410fSValery Pykhtin if (S.isWeak())
217fd4c410fSValery Pykhtin continue;
218fd4c410fSValery Pykhtin assert(SuccSU->isBoundaryNode() || getNumPreds(SuccSU) > 0);
219fd4c410fSValery Pykhtin if (!SuccSU->isBoundaryNode() && decNumPreds(SuccSU) == 0)
220fd4c410fSValery Pykhtin RQ.push_front(*new (Alloc.Allocate()) Candidate(SuccSU, Priority));
221fd4c410fSValery Pykhtin }
222fd4c410fSValery Pykhtin }
223fd4c410fSValery Pykhtin
224fd4c410fSValery Pykhtin std::vector<const SUnit*>
schedule(ArrayRef<const SUnit * > TopRoots,const ScheduleDAG & DAG)225fd4c410fSValery Pykhtin GCNMinRegScheduler::schedule(ArrayRef<const SUnit*> TopRoots,
226fd4c410fSValery Pykhtin const ScheduleDAG &DAG) {
227fd4c410fSValery Pykhtin const auto &SUnits = DAG.SUnits;
228fd4c410fSValery Pykhtin std::vector<const SUnit*> Schedule;
229fd4c410fSValery Pykhtin Schedule.reserve(SUnits.size());
230fd4c410fSValery Pykhtin
231fd4c410fSValery Pykhtin initNumPreds(SUnits);
232fd4c410fSValery Pykhtin
233fd4c410fSValery Pykhtin int StepNo = 0;
234fd4c410fSValery Pykhtin
235fd4c410fSValery Pykhtin for (auto SU : TopRoots) {
236fd4c410fSValery Pykhtin RQ.push_back(*new (Alloc.Allocate()) Candidate(SU, StepNo));
237fd4c410fSValery Pykhtin }
23817dc729bSAlexander Belyaev releaseSuccessors(&DAG.EntrySU, StepNo);
239fd4c410fSValery Pykhtin
240fd4c410fSValery Pykhtin while (!RQ.empty()) {
241d34e60caSNicola Zaghen LLVM_DEBUG(dbgs() << "\n=== Picking candidate, Step = " << StepNo
242d34e60caSNicola Zaghen << "\n"
243fd4c410fSValery Pykhtin "Ready queue:";
244d34e60caSNicola Zaghen for (auto &C
245d34e60caSNicola Zaghen : RQ) dbgs()
246d34e60caSNicola Zaghen << ' ' << C.SU->NodeNum << "(P" << C.Priority << ')';
247d34e60caSNicola Zaghen dbgs() << '\n';);
248fd4c410fSValery Pykhtin
249fd4c410fSValery Pykhtin auto C = pickCandidate();
250fd4c410fSValery Pykhtin assert(C);
251fd4c410fSValery Pykhtin RQ.remove(*C);
252fd4c410fSValery Pykhtin auto SU = C->SU;
253726e12cfSMatthias Braun LLVM_DEBUG(dbgs() << "Selected "; DAG.dumpNode(*SU));
254fd4c410fSValery Pykhtin
255fd4c410fSValery Pykhtin releaseSuccessors(SU, StepNo);
256fd4c410fSValery Pykhtin Schedule.push_back(SU);
257fd4c410fSValery Pykhtin setIsScheduled(SU);
258fd4c410fSValery Pykhtin
259fd4c410fSValery Pykhtin if (getReadySuccessors(SU) == 0)
260fd4c410fSValery Pykhtin bumpPredsPriority(SU, StepNo);
261fd4c410fSValery Pykhtin
262fd4c410fSValery Pykhtin ++StepNo;
263fd4c410fSValery Pykhtin }
264fd4c410fSValery Pykhtin assert(SUnits.size() == Schedule.size());
265fd4c410fSValery Pykhtin
266fd4c410fSValery Pykhtin return Schedule;
267fd4c410fSValery Pykhtin }
268fd4c410fSValery Pykhtin
269fd4c410fSValery Pykhtin namespace llvm {
270d16eff81SEugene Zelenko
makeMinRegSchedule(ArrayRef<const SUnit * > TopRoots,const ScheduleDAG & DAG)271fd4c410fSValery Pykhtin std::vector<const SUnit*> makeMinRegSchedule(ArrayRef<const SUnit*> TopRoots,
272fd4c410fSValery Pykhtin const ScheduleDAG &DAG) {
273fd4c410fSValery Pykhtin GCNMinRegScheduler S;
274fd4c410fSValery Pykhtin return S.schedule(TopRoots, DAG);
275fd4c410fSValery Pykhtin }
276d16eff81SEugene Zelenko
277d16eff81SEugene Zelenko } // end namespace llvm
278