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