1c8fbf6ffSEugene Zelenko //===- GCNIterativeScheduler.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
101d9e08ecShsmahesha /// This file implements the class GCNIterativeScheduler.
111d9e08ecShsmahesha ///
121d9e08ecShsmahesha //===----------------------------------------------------------------------===//
13fd4c410fSValery Pykhtin 
14fd4c410fSValery Pykhtin #include "GCNIterativeScheduler.h"
15fd4c410fSValery Pykhtin #include "GCNSchedStrategy.h"
1644b30b45STom Stellard #include "SIMachineFunctionInfo.h"
17fd4c410fSValery Pykhtin 
18fd4c410fSValery Pykhtin using namespace llvm;
19fd4c410fSValery Pykhtin 
200cd23f56SEvandro Menezes #define DEBUG_TYPE "machine-scheduler"
21fd4c410fSValery Pykhtin 
22fd4c410fSValery Pykhtin namespace llvm {
23c8fbf6ffSEugene Zelenko 
24fd4c410fSValery Pykhtin std::vector<const SUnit *> makeMinRegSchedule(ArrayRef<const SUnit *> TopRoots,
25fd4c410fSValery Pykhtin                                               const ScheduleDAG &DAG);
26c8fbf6ffSEugene Zelenko 
27f2fe9725SValery Pykhtin   std::vector<const SUnit*> makeGCNILPScheduler(ArrayRef<const SUnit*> BotRoots,
28f2fe9725SValery Pykhtin     const ScheduleDAG &DAG);
29f2fe9725SValery Pykhtin }
30fd4c410fSValery Pykhtin 
31fd4c410fSValery Pykhtin // shim accessors for different order containers
getMachineInstr(MachineInstr * MI)32fd4c410fSValery Pykhtin static inline MachineInstr *getMachineInstr(MachineInstr *MI) {
33fd4c410fSValery Pykhtin   return MI;
34fd4c410fSValery Pykhtin }
getMachineInstr(const SUnit * SU)35fd4c410fSValery Pykhtin static inline MachineInstr *getMachineInstr(const SUnit *SU) {
36fd4c410fSValery Pykhtin   return SU->getInstr();
37fd4c410fSValery Pykhtin }
getMachineInstr(const SUnit & SU)38fd4c410fSValery Pykhtin static inline MachineInstr *getMachineInstr(const SUnit &SU) {
39fd4c410fSValery Pykhtin   return SU.getInstr();
40fd4c410fSValery Pykhtin }
41fd4c410fSValery Pykhtin 
42615eb470SAaron Ballman #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
43fd4c410fSValery Pykhtin LLVM_DUMP_METHOD
printRegion(raw_ostream & OS,MachineBasicBlock::iterator Begin,MachineBasicBlock::iterator End,const LiveIntervals * LIS,unsigned MaxInstNum=std::numeric_limits<unsigned>::max ())44fd4c410fSValery Pykhtin static void printRegion(raw_ostream &OS,
45fd4c410fSValery Pykhtin                         MachineBasicBlock::iterator Begin,
46fd4c410fSValery Pykhtin                         MachineBasicBlock::iterator End,
47fd4c410fSValery Pykhtin                         const LiveIntervals *LIS,
48fd4c410fSValery Pykhtin                         unsigned MaxInstNum =
49fd4c410fSValery Pykhtin                           std::numeric_limits<unsigned>::max()) {
50fd4c410fSValery Pykhtin   auto BB = Begin->getParent();
5125528d6dSFrancis Visoiu Mistrih   OS << BB->getParent()->getName() << ":" << printMBBReference(*BB) << ' '
5225528d6dSFrancis Visoiu Mistrih      << BB->getName() << ":\n";
53fd4c410fSValery Pykhtin   auto I = Begin;
54fd4c410fSValery Pykhtin   MaxInstNum = std::max(MaxInstNum, 1u);
55fd4c410fSValery Pykhtin   for (; I != End && MaxInstNum; ++I, --MaxInstNum) {
56801bf7ebSShiva Chen     if (!I->isDebugInstr() && LIS)
57fd4c410fSValery Pykhtin       OS << LIS->getInstructionIndex(*I);
58fd4c410fSValery Pykhtin     OS << '\t' << *I;
59fd4c410fSValery Pykhtin   }
60fd4c410fSValery Pykhtin   if (I != End) {
61fd4c410fSValery Pykhtin     OS << "\t...\n";
62fd4c410fSValery Pykhtin     I = std::prev(End);
63801bf7ebSShiva Chen     if (!I->isDebugInstr() && LIS)
64fd4c410fSValery Pykhtin       OS << LIS->getInstructionIndex(*I);
65fd4c410fSValery Pykhtin     OS << '\t' << *I;
66fd4c410fSValery Pykhtin   }
67fd4c410fSValery Pykhtin   if (End != BB->end()) { // print boundary inst if present
68fd4c410fSValery Pykhtin     OS << "----\n";
69fd4c410fSValery Pykhtin     if (LIS) OS << LIS->getInstructionIndex(*End) << '\t';
70fd4c410fSValery Pykhtin     OS << *End;
71fd4c410fSValery Pykhtin   }
72fd4c410fSValery Pykhtin }
73fd4c410fSValery Pykhtin 
74fd4c410fSValery Pykhtin LLVM_DUMP_METHOD
printLivenessInfo(raw_ostream & OS,MachineBasicBlock::iterator Begin,MachineBasicBlock::iterator End,const LiveIntervals * LIS)75fd4c410fSValery Pykhtin static void printLivenessInfo(raw_ostream &OS,
76fd4c410fSValery Pykhtin                               MachineBasicBlock::iterator Begin,
77fd4c410fSValery Pykhtin                               MachineBasicBlock::iterator End,
78fd4c410fSValery Pykhtin                               const LiveIntervals *LIS) {
79fd4c410fSValery Pykhtin   const auto BB = Begin->getParent();
80fd4c410fSValery Pykhtin   const auto &MRI = BB->getParent()->getRegInfo();
81fd4c410fSValery Pykhtin 
82fd4c410fSValery Pykhtin   const auto LiveIns = getLiveRegsBefore(*Begin, *LIS);
83fd4c410fSValery Pykhtin   OS << "LIn RP: ";
84fd4c410fSValery Pykhtin   getRegPressure(MRI, LiveIns).print(OS);
85fd4c410fSValery Pykhtin 
86fd4c410fSValery Pykhtin   const auto BottomMI = End == BB->end() ? std::prev(End) : End;
87fd4c410fSValery Pykhtin   const auto LiveOuts = getLiveRegsAfter(*BottomMI, *LIS);
88fd4c410fSValery Pykhtin   OS << "LOt RP: ";
89fd4c410fSValery Pykhtin   getRegPressure(MRI, LiveOuts).print(OS);
90fd4c410fSValery Pykhtin }
91fd4c410fSValery Pykhtin 
92fd4c410fSValery Pykhtin LLVM_DUMP_METHOD
printRegions(raw_ostream & OS) const93fd4c410fSValery Pykhtin void GCNIterativeScheduler::printRegions(raw_ostream &OS) const {
945bfbae5cSTom Stellard   const auto &ST = MF.getSubtarget<GCNSubtarget>();
95fd4c410fSValery Pykhtin   for (const auto R : Regions) {
96fd4c410fSValery Pykhtin     OS << "Region to schedule ";
97fd4c410fSValery Pykhtin     printRegion(OS, R->Begin, R->End, LIS, 1);
98fd4c410fSValery Pykhtin     printLivenessInfo(OS, R->Begin, R->End, LIS);
99fd4c410fSValery Pykhtin     OS << "Max RP: ";
100fd4c410fSValery Pykhtin     R->MaxPressure.print(OS, &ST);
101fd4c410fSValery Pykhtin   }
102fd4c410fSValery Pykhtin }
103fd4c410fSValery Pykhtin 
104fd4c410fSValery Pykhtin LLVM_DUMP_METHOD
printSchedResult(raw_ostream & OS,const Region * R,const GCNRegPressure & RP) const105fd4c410fSValery Pykhtin void GCNIterativeScheduler::printSchedResult(raw_ostream &OS,
106fd4c410fSValery Pykhtin                                              const Region *R,
107fd4c410fSValery Pykhtin                                              const GCNRegPressure &RP) const {
108fd4c410fSValery Pykhtin   OS << "\nAfter scheduling ";
109fd4c410fSValery Pykhtin   printRegion(OS, R->Begin, R->End, LIS);
110fd4c410fSValery Pykhtin   printSchedRP(OS, R->MaxPressure, RP);
111fd4c410fSValery Pykhtin   OS << '\n';
112fd4c410fSValery Pykhtin }
113fd4c410fSValery Pykhtin 
114fd4c410fSValery Pykhtin LLVM_DUMP_METHOD
printSchedRP(raw_ostream & OS,const GCNRegPressure & Before,const GCNRegPressure & After) const115fd4c410fSValery Pykhtin void GCNIterativeScheduler::printSchedRP(raw_ostream &OS,
116fd4c410fSValery Pykhtin                                          const GCNRegPressure &Before,
117fd4c410fSValery Pykhtin                                          const GCNRegPressure &After) const {
1185bfbae5cSTom Stellard   const auto &ST = MF.getSubtarget<GCNSubtarget>();
119fd4c410fSValery Pykhtin   OS << "RP before: ";
120fd4c410fSValery Pykhtin   Before.print(OS, &ST);
121fd4c410fSValery Pykhtin   OS << "RP after:  ";
122fd4c410fSValery Pykhtin   After.print(OS, &ST);
123fd4c410fSValery Pykhtin }
124fd4c410fSValery Pykhtin #endif
125fd4c410fSValery Pykhtin 
126fd4c410fSValery Pykhtin // DAG builder helper
127fd4c410fSValery Pykhtin class GCNIterativeScheduler::BuildDAG {
128fd4c410fSValery Pykhtin   GCNIterativeScheduler &Sch;
129fd4c410fSValery Pykhtin   SmallVector<SUnit *, 8> TopRoots;
130c8fbf6ffSEugene Zelenko 
131f2fe9725SValery Pykhtin   SmallVector<SUnit*, 8> BotRoots;
132fd4c410fSValery Pykhtin public:
BuildDAG(const Region & R,GCNIterativeScheduler & _Sch)133fd4c410fSValery Pykhtin   BuildDAG(const Region &R, GCNIterativeScheduler &_Sch)
134fd4c410fSValery Pykhtin     : Sch(_Sch) {
135fd4c410fSValery Pykhtin     auto BB = R.Begin->getParent();
136fd4c410fSValery Pykhtin     Sch.BaseClass::startBlock(BB);
137fd4c410fSValery Pykhtin     Sch.BaseClass::enterRegion(BB, R.Begin, R.End, R.NumRegionInstrs);
138fd4c410fSValery Pykhtin 
139fd4c410fSValery Pykhtin     Sch.buildSchedGraph(Sch.AA, nullptr, nullptr, nullptr,
140fd4c410fSValery Pykhtin                         /*TrackLaneMask*/true);
141fd4c410fSValery Pykhtin     Sch.Topo.InitDAGTopologicalSorting();
142fd4c410fSValery Pykhtin     Sch.findRootsAndBiasEdges(TopRoots, BotRoots);
143fd4c410fSValery Pykhtin   }
144c8fbf6ffSEugene Zelenko 
~BuildDAG()145fd4c410fSValery Pykhtin   ~BuildDAG() {
146fd4c410fSValery Pykhtin     Sch.BaseClass::exitRegion();
147fd4c410fSValery Pykhtin     Sch.BaseClass::finishBlock();
148fd4c410fSValery Pykhtin   }
149c8fbf6ffSEugene Zelenko 
getTopRoots() const150fd4c410fSValery Pykhtin   ArrayRef<const SUnit *> getTopRoots() const {
151fd4c410fSValery Pykhtin     return TopRoots;
152fd4c410fSValery Pykhtin   }
getBottomRoots() const153f2fe9725SValery Pykhtin   ArrayRef<SUnit*> getBottomRoots() const {
154f2fe9725SValery Pykhtin     return BotRoots;
155f2fe9725SValery Pykhtin   }
156fd4c410fSValery Pykhtin };
157fd4c410fSValery Pykhtin 
158fd4c410fSValery Pykhtin class GCNIterativeScheduler::OverrideLegacyStrategy {
159fd4c410fSValery Pykhtin   GCNIterativeScheduler &Sch;
160fd4c410fSValery Pykhtin   Region &Rgn;
161fd4c410fSValery Pykhtin   std::unique_ptr<MachineSchedStrategy> SaveSchedImpl;
162fd4c410fSValery Pykhtin   GCNRegPressure SaveMaxRP;
163c8fbf6ffSEugene Zelenko 
164fd4c410fSValery Pykhtin public:
OverrideLegacyStrategy(Region & R,MachineSchedStrategy & OverrideStrategy,GCNIterativeScheduler & _Sch)165fd4c410fSValery Pykhtin   OverrideLegacyStrategy(Region &R,
166fd4c410fSValery Pykhtin                          MachineSchedStrategy &OverrideStrategy,
167fd4c410fSValery Pykhtin                          GCNIterativeScheduler &_Sch)
168fd4c410fSValery Pykhtin     : Sch(_Sch)
169fd4c410fSValery Pykhtin     , Rgn(R)
170fd4c410fSValery Pykhtin     , SaveSchedImpl(std::move(_Sch.SchedImpl))
171fd4c410fSValery Pykhtin     , SaveMaxRP(R.MaxPressure) {
172fd4c410fSValery Pykhtin     Sch.SchedImpl.reset(&OverrideStrategy);
173fd4c410fSValery Pykhtin     auto BB = R.Begin->getParent();
174fd4c410fSValery Pykhtin     Sch.BaseClass::startBlock(BB);
175fd4c410fSValery Pykhtin     Sch.BaseClass::enterRegion(BB, R.Begin, R.End, R.NumRegionInstrs);
176fd4c410fSValery Pykhtin   }
177c8fbf6ffSEugene Zelenko 
~OverrideLegacyStrategy()178fd4c410fSValery Pykhtin   ~OverrideLegacyStrategy() {
179fd4c410fSValery Pykhtin     Sch.BaseClass::exitRegion();
180fd4c410fSValery Pykhtin     Sch.BaseClass::finishBlock();
181fd4c410fSValery Pykhtin     Sch.SchedImpl.release();
182fd4c410fSValery Pykhtin     Sch.SchedImpl = std::move(SaveSchedImpl);
183fd4c410fSValery Pykhtin   }
184c8fbf6ffSEugene Zelenko 
schedule()185fd4c410fSValery Pykhtin   void schedule() {
186fd4c410fSValery Pykhtin     assert(Sch.RegionBegin == Rgn.Begin && Sch.RegionEnd == Rgn.End);
187d34e60caSNicola Zaghen     LLVM_DEBUG(dbgs() << "\nScheduling ";
188fd4c410fSValery Pykhtin                printRegion(dbgs(), Rgn.Begin, Rgn.End, Sch.LIS, 2));
189fd4c410fSValery Pykhtin     Sch.BaseClass::schedule();
190fd4c410fSValery Pykhtin 
191*d1f45ed5SNeubauer, Sebastian     // Unfortunately placeDebugValues incorrectly modifies RegionEnd, restore
192fd4c410fSValery Pykhtin     Sch.RegionEnd = Rgn.End;
193fd4c410fSValery Pykhtin     //assert(Rgn.End == Sch.RegionEnd);
194fd4c410fSValery Pykhtin     Rgn.Begin = Sch.RegionBegin;
195fd4c410fSValery Pykhtin     Rgn.MaxPressure.clear();
196fd4c410fSValery Pykhtin   }
197c8fbf6ffSEugene Zelenko 
restoreOrder()198fd4c410fSValery Pykhtin   void restoreOrder() {
199fd4c410fSValery Pykhtin     assert(Sch.RegionBegin == Rgn.Begin && Sch.RegionEnd == Rgn.End);
200fd4c410fSValery Pykhtin     // DAG SUnits are stored using original region's order
201fd4c410fSValery Pykhtin     // so just use SUnits as the restoring schedule
202fd4c410fSValery Pykhtin     Sch.scheduleRegion(Rgn, Sch.SUnits, SaveMaxRP);
203fd4c410fSValery Pykhtin   }
204fd4c410fSValery Pykhtin };
205fd4c410fSValery Pykhtin 
206debb3c35SBenjamin Kramer namespace {
207c8fbf6ffSEugene Zelenko 
208fd4c410fSValery Pykhtin // just a stub to make base class happy
209fd4c410fSValery Pykhtin class SchedStrategyStub : public MachineSchedStrategy {
210fd4c410fSValery Pykhtin public:
shouldTrackPressure() const211fd4c410fSValery Pykhtin   bool shouldTrackPressure() const override { return false; }
shouldTrackLaneMasks() const212fd4c410fSValery Pykhtin   bool shouldTrackLaneMasks() const override { return false; }
initialize(ScheduleDAGMI * DAG)213fd4c410fSValery Pykhtin   void initialize(ScheduleDAGMI *DAG) override {}
pickNode(bool & IsTopNode)214fd4c410fSValery Pykhtin   SUnit *pickNode(bool &IsTopNode) override { return nullptr; }
schedNode(SUnit * SU,bool IsTopNode)215fd4c410fSValery Pykhtin   void schedNode(SUnit *SU, bool IsTopNode) override {}
releaseTopNode(SUnit * SU)216fd4c410fSValery Pykhtin   void releaseTopNode(SUnit *SU) override {}
releaseBottomNode(SUnit * SU)217fd4c410fSValery Pykhtin   void releaseBottomNode(SUnit *SU) override {}
218fd4c410fSValery Pykhtin };
219c8fbf6ffSEugene Zelenko 
220c8fbf6ffSEugene Zelenko } // end anonymous namespace
221fd4c410fSValery Pykhtin 
GCNIterativeScheduler(MachineSchedContext * C,StrategyKind S)222fd4c410fSValery Pykhtin GCNIterativeScheduler::GCNIterativeScheduler(MachineSchedContext *C,
223fd4c410fSValery Pykhtin                                              StrategyKind S)
2240eaee545SJonas Devlieghere   : BaseClass(C, std::make_unique<SchedStrategyStub>())
225fd4c410fSValery Pykhtin   , Context(C)
226fd4c410fSValery Pykhtin   , Strategy(S)
227fd4c410fSValery Pykhtin   , UPTracker(*LIS) {
228fd4c410fSValery Pykhtin }
229fd4c410fSValery Pykhtin 
230fd4c410fSValery Pykhtin // returns max pressure for a region
231fd4c410fSValery Pykhtin GCNRegPressure
getRegionPressure(MachineBasicBlock::iterator Begin,MachineBasicBlock::iterator End) const232fd4c410fSValery Pykhtin GCNIterativeScheduler::getRegionPressure(MachineBasicBlock::iterator Begin,
233fd4c410fSValery Pykhtin                                          MachineBasicBlock::iterator End)
234fd4c410fSValery Pykhtin   const {
235fd4c410fSValery Pykhtin   // For the purpose of pressure tracking bottom inst of the region should
236fd4c410fSValery Pykhtin   // be also processed. End is either BB end, BB terminator inst or sched
237fd4c410fSValery Pykhtin   // boundary inst.
238fd4c410fSValery Pykhtin   auto const BBEnd = Begin->getParent()->end();
239fd4c410fSValery Pykhtin   auto const BottomMI = End == BBEnd ? std::prev(End) : End;
240fd4c410fSValery Pykhtin 
241fd4c410fSValery Pykhtin   // scheduleRegions walks bottom to top, so its likely we just get next
242fd4c410fSValery Pykhtin   // instruction to track
243fd4c410fSValery Pykhtin   auto AfterBottomMI = std::next(BottomMI);
244fd4c410fSValery Pykhtin   if (AfterBottomMI == BBEnd ||
245fd4c410fSValery Pykhtin       &*AfterBottomMI != UPTracker.getLastTrackedMI()) {
246fd4c410fSValery Pykhtin     UPTracker.reset(*BottomMI);
247fd4c410fSValery Pykhtin   } else {
248fd4c410fSValery Pykhtin     assert(UPTracker.isValid());
249fd4c410fSValery Pykhtin   }
250fd4c410fSValery Pykhtin 
251fd4c410fSValery Pykhtin   for (auto I = BottomMI; I != Begin; --I)
252fd4c410fSValery Pykhtin     UPTracker.recede(*I);
253fd4c410fSValery Pykhtin 
254fd4c410fSValery Pykhtin   UPTracker.recede(*Begin);
255fd4c410fSValery Pykhtin 
256fd4c410fSValery Pykhtin   assert(UPTracker.isValid() ||
257fd4c410fSValery Pykhtin          (dbgs() << "Tracked region ",
258fd4c410fSValery Pykhtin           printRegion(dbgs(), Begin, End, LIS), false));
259fd4c410fSValery Pykhtin   return UPTracker.moveMaxPressure();
260fd4c410fSValery Pykhtin }
261fd4c410fSValery Pykhtin 
262fd4c410fSValery Pykhtin // returns max pressure for a tentative schedule
263fd4c410fSValery Pykhtin template <typename Range> GCNRegPressure
getSchedulePressure(const Region & R,Range && Schedule) const264fd4c410fSValery Pykhtin GCNIterativeScheduler::getSchedulePressure(const Region &R,
265fd4c410fSValery Pykhtin                                            Range &&Schedule) const {
266fd4c410fSValery Pykhtin   auto const BBEnd = R.Begin->getParent()->end();
267fd4c410fSValery Pykhtin   GCNUpwardRPTracker RPTracker(*LIS);
268fd4c410fSValery Pykhtin   if (R.End != BBEnd) {
269fd4c410fSValery Pykhtin     // R.End points to the boundary instruction but the
270fd4c410fSValery Pykhtin     // schedule doesn't include it
271fd4c410fSValery Pykhtin     RPTracker.reset(*R.End);
272fd4c410fSValery Pykhtin     RPTracker.recede(*R.End);
273fd4c410fSValery Pykhtin   } else {
274fd4c410fSValery Pykhtin     // R.End doesn't point to the boundary instruction
275fd4c410fSValery Pykhtin     RPTracker.reset(*std::prev(BBEnd));
276fd4c410fSValery Pykhtin   }
277fd4c410fSValery Pykhtin   for (auto I = Schedule.end(), B = Schedule.begin(); I != B;) {
278fd4c410fSValery Pykhtin     RPTracker.recede(*getMachineInstr(*--I));
279fd4c410fSValery Pykhtin   }
280fd4c410fSValery Pykhtin   return RPTracker.moveMaxPressure();
281fd4c410fSValery Pykhtin }
282fd4c410fSValery Pykhtin 
enterRegion(MachineBasicBlock * BB,MachineBasicBlock::iterator Begin,MachineBasicBlock::iterator End,unsigned NumRegionInstrs)283*d1f45ed5SNeubauer, Sebastian void GCNIterativeScheduler::enterRegion(MachineBasicBlock *BB, // overridden
284fd4c410fSValery Pykhtin                                         MachineBasicBlock::iterator Begin,
285fd4c410fSValery Pykhtin                                         MachineBasicBlock::iterator End,
286fd4c410fSValery Pykhtin                                         unsigned NumRegionInstrs) {
287fd4c410fSValery Pykhtin   BaseClass::enterRegion(BB, Begin, End, NumRegionInstrs);
288fd4c410fSValery Pykhtin   if (NumRegionInstrs > 2) {
289fd4c410fSValery Pykhtin     Regions.push_back(
290fd4c410fSValery Pykhtin       new (Alloc.Allocate())
291fd4c410fSValery Pykhtin       Region { Begin, End, NumRegionInstrs,
292fd4c410fSValery Pykhtin                getRegionPressure(Begin, End), nullptr });
293fd4c410fSValery Pykhtin   }
294fd4c410fSValery Pykhtin }
295fd4c410fSValery Pykhtin 
schedule()296*d1f45ed5SNeubauer, Sebastian void GCNIterativeScheduler::schedule() { // overridden
297fd4c410fSValery Pykhtin   // do nothing
298d34e60caSNicola Zaghen   LLVM_DEBUG(printLivenessInfo(dbgs(), RegionBegin, RegionEnd, LIS);
299fd4c410fSValery Pykhtin              if (!Regions.empty() && Regions.back()->Begin == RegionBegin) {
300fd4c410fSValery Pykhtin                dbgs() << "Max RP: ";
301d34e60caSNicola Zaghen                Regions.back()->MaxPressure.print(
3025bfbae5cSTom Stellard                    dbgs(), &MF.getSubtarget<GCNSubtarget>());
303d34e60caSNicola Zaghen              } dbgs()
304d34e60caSNicola Zaghen              << '\n';);
305fd4c410fSValery Pykhtin }
306fd4c410fSValery Pykhtin 
finalizeSchedule()307*d1f45ed5SNeubauer, Sebastian void GCNIterativeScheduler::finalizeSchedule() { // overridden
308fd4c410fSValery Pykhtin   if (Regions.empty())
309fd4c410fSValery Pykhtin     return;
310fd4c410fSValery Pykhtin   switch (Strategy) {
311fd4c410fSValery Pykhtin   case SCHEDULE_MINREGONLY: scheduleMinReg(); break;
312fd4c410fSValery Pykhtin   case SCHEDULE_MINREGFORCED: scheduleMinReg(true); break;
313fd4c410fSValery Pykhtin   case SCHEDULE_LEGACYMAXOCCUPANCY: scheduleLegacyMaxOccupancy(); break;
314f2fe9725SValery Pykhtin   case SCHEDULE_ILP: scheduleILP(false); break;
315fd4c410fSValery Pykhtin   }
316fd4c410fSValery Pykhtin }
317fd4c410fSValery Pykhtin 
318fd4c410fSValery Pykhtin // Detach schedule from SUnits and interleave it with debug values.
319fd4c410fSValery Pykhtin // Returned schedule becomes independent of DAG state.
320fd4c410fSValery Pykhtin std::vector<MachineInstr*>
detachSchedule(ScheduleRef Schedule) const321fd4c410fSValery Pykhtin GCNIterativeScheduler::detachSchedule(ScheduleRef Schedule) const {
322fd4c410fSValery Pykhtin   std::vector<MachineInstr*> Res;
323fd4c410fSValery Pykhtin   Res.reserve(Schedule.size() * 2);
324fd4c410fSValery Pykhtin 
325fd4c410fSValery Pykhtin   if (FirstDbgValue)
326fd4c410fSValery Pykhtin     Res.push_back(FirstDbgValue);
327fd4c410fSValery Pykhtin 
328fd4c410fSValery Pykhtin   const auto DbgB = DbgValues.begin(), DbgE = DbgValues.end();
329fd4c410fSValery Pykhtin   for (auto SU : Schedule) {
330fd4c410fSValery Pykhtin     Res.push_back(SU->getInstr());
331fd4c410fSValery Pykhtin     const auto &D = std::find_if(DbgB, DbgE, [SU](decltype(*DbgB) &P) {
332fd4c410fSValery Pykhtin       return P.second == SU->getInstr();
333fd4c410fSValery Pykhtin     });
334fd4c410fSValery Pykhtin     if (D != DbgE)
335fd4c410fSValery Pykhtin       Res.push_back(D->first);
336fd4c410fSValery Pykhtin   }
337fd4c410fSValery Pykhtin   return Res;
338fd4c410fSValery Pykhtin }
339fd4c410fSValery Pykhtin 
setBestSchedule(Region & R,ScheduleRef Schedule,const GCNRegPressure & MaxRP)340fd4c410fSValery Pykhtin void GCNIterativeScheduler::setBestSchedule(Region &R,
341fd4c410fSValery Pykhtin                                             ScheduleRef Schedule,
342fd4c410fSValery Pykhtin                                             const GCNRegPressure &MaxRP) {
343fd4c410fSValery Pykhtin   R.BestSchedule.reset(
344fd4c410fSValery Pykhtin     new TentativeSchedule{ detachSchedule(Schedule), MaxRP });
345fd4c410fSValery Pykhtin }
346fd4c410fSValery Pykhtin 
scheduleBest(Region & R)347fd4c410fSValery Pykhtin void GCNIterativeScheduler::scheduleBest(Region &R) {
348fd4c410fSValery Pykhtin   assert(R.BestSchedule.get() && "No schedule specified");
349fd4c410fSValery Pykhtin   scheduleRegion(R, R.BestSchedule->Schedule, R.BestSchedule->MaxPressure);
350fd4c410fSValery Pykhtin   R.BestSchedule.reset();
351fd4c410fSValery Pykhtin }
352fd4c410fSValery Pykhtin 
353fd4c410fSValery Pykhtin // minimal required region scheduler, works for ranges of SUnits*,
354fd4c410fSValery Pykhtin // SUnits or MachineIntrs*
355fd4c410fSValery Pykhtin template <typename Range>
scheduleRegion(Region & R,Range && Schedule,const GCNRegPressure & MaxRP)356fd4c410fSValery Pykhtin void GCNIterativeScheduler::scheduleRegion(Region &R, Range &&Schedule,
357fd4c410fSValery Pykhtin                                            const GCNRegPressure &MaxRP) {
358fd4c410fSValery Pykhtin   assert(RegionBegin == R.Begin && RegionEnd == R.End);
359fd4c410fSValery Pykhtin   assert(LIS != nullptr);
360fd4c410fSValery Pykhtin #ifndef NDEBUG
361fd4c410fSValery Pykhtin   const auto SchedMaxRP = getSchedulePressure(R, Schedule);
362fd4c410fSValery Pykhtin #endif
363fd4c410fSValery Pykhtin   auto BB = R.Begin->getParent();
364fd4c410fSValery Pykhtin   auto Top = R.Begin;
365fd4c410fSValery Pykhtin   for (const auto &I : Schedule) {
366fd4c410fSValery Pykhtin     auto MI = getMachineInstr(I);
367fd4c410fSValery Pykhtin     if (MI != &*Top) {
368fd4c410fSValery Pykhtin       BB->remove(MI);
369fd4c410fSValery Pykhtin       BB->insert(Top, MI);
370801bf7ebSShiva Chen       if (!MI->isDebugInstr())
371fd4c410fSValery Pykhtin         LIS->handleMove(*MI, true);
372fd4c410fSValery Pykhtin     }
373801bf7ebSShiva Chen     if (!MI->isDebugInstr()) {
374fd4c410fSValery Pykhtin       // Reset read - undef flags and update them later.
375fd4c410fSValery Pykhtin       for (auto &Op : MI->operands())
376fd4c410fSValery Pykhtin         if (Op.isReg() && Op.isDef())
377fd4c410fSValery Pykhtin           Op.setIsUndef(false);
378fd4c410fSValery Pykhtin 
379fd4c410fSValery Pykhtin       RegisterOperands RegOpers;
380fd4c410fSValery Pykhtin       RegOpers.collect(*MI, *TRI, MRI, /*ShouldTrackLaneMasks*/true,
381fd4c410fSValery Pykhtin                                        /*IgnoreDead*/false);
382fd4c410fSValery Pykhtin       // Adjust liveness and add missing dead+read-undef flags.
383fd4c410fSValery Pykhtin       auto SlotIdx = LIS->getInstructionIndex(*MI).getRegSlot();
384fd4c410fSValery Pykhtin       RegOpers.adjustLaneLiveness(*LIS, MRI, SlotIdx, MI);
385fd4c410fSValery Pykhtin     }
386fd4c410fSValery Pykhtin     Top = std::next(MI->getIterator());
387fd4c410fSValery Pykhtin   }
388fd4c410fSValery Pykhtin   RegionBegin = getMachineInstr(Schedule.front());
389fd4c410fSValery Pykhtin 
390fd4c410fSValery Pykhtin   // Schedule consisting of MachineInstr* is considered 'detached'
391fd4c410fSValery Pykhtin   // and already interleaved with debug values
392fd4c410fSValery Pykhtin   if (!std::is_same<decltype(*Schedule.begin()), MachineInstr*>::value) {
393fd4c410fSValery Pykhtin     placeDebugValues();
394*d1f45ed5SNeubauer, Sebastian     // Unfortunately placeDebugValues incorrectly modifies RegionEnd, restore
395fd4c410fSValery Pykhtin     // assert(R.End == RegionEnd);
396fd4c410fSValery Pykhtin     RegionEnd = R.End;
397fd4c410fSValery Pykhtin   }
398fd4c410fSValery Pykhtin 
399fd4c410fSValery Pykhtin   R.Begin = RegionBegin;
400fd4c410fSValery Pykhtin   R.MaxPressure = MaxRP;
401fd4c410fSValery Pykhtin 
402fd4c410fSValery Pykhtin #ifndef NDEBUG
403fd4c410fSValery Pykhtin   const auto RegionMaxRP = getRegionPressure(R);
4045bfbae5cSTom Stellard   const auto &ST = MF.getSubtarget<GCNSubtarget>();
405fd4c410fSValery Pykhtin #endif
406fd4c410fSValery Pykhtin   assert((SchedMaxRP == RegionMaxRP && (MaxRP.empty() || SchedMaxRP == MaxRP))
407fd4c410fSValery Pykhtin   || (dbgs() << "Max RP mismatch!!!\n"
408fd4c410fSValery Pykhtin                 "RP for schedule (calculated): ",
409fd4c410fSValery Pykhtin       SchedMaxRP.print(dbgs(), &ST),
410fd4c410fSValery Pykhtin       dbgs() << "RP for schedule (reported): ",
411fd4c410fSValery Pykhtin       MaxRP.print(dbgs(), &ST),
412fd4c410fSValery Pykhtin       dbgs() << "RP after scheduling: ",
413fd4c410fSValery Pykhtin       RegionMaxRP.print(dbgs(), &ST),
414fd4c410fSValery Pykhtin       false));
415fd4c410fSValery Pykhtin }
416fd4c410fSValery Pykhtin 
417fd4c410fSValery Pykhtin // Sort recorded regions by pressure - highest at the front
sortRegionsByPressure(unsigned TargetOcc)418fd4c410fSValery Pykhtin void GCNIterativeScheduler::sortRegionsByPressure(unsigned TargetOcc) {
4195bfbae5cSTom Stellard   const auto &ST = MF.getSubtarget<GCNSubtarget>();
4200cac726aSFangrui Song   llvm::sort(Regions, [&ST, TargetOcc](const Region *R1, const Region *R2) {
421fd4c410fSValery Pykhtin     return R2->MaxPressure.less(ST, R1->MaxPressure, TargetOcc);
422fd4c410fSValery Pykhtin   });
423fd4c410fSValery Pykhtin }
424fd4c410fSValery Pykhtin 
425fd4c410fSValery Pykhtin ///////////////////////////////////////////////////////////////////////////////
426fd4c410fSValery Pykhtin // Legacy MaxOccupancy Strategy
427fd4c410fSValery Pykhtin 
428fd4c410fSValery Pykhtin // Tries to increase occupancy applying minreg scheduler for a sequence of
429fd4c410fSValery Pykhtin // most demanding regions. Obtained schedules are saved as BestSchedule for a
430fd4c410fSValery Pykhtin // region.
431fd4c410fSValery Pykhtin // TargetOcc is the best achievable occupancy for a kernel.
432fd4c410fSValery Pykhtin // Returns better occupancy on success or current occupancy on fail.
433fd4c410fSValery Pykhtin // BestSchedules aren't deleted on fail.
tryMaximizeOccupancy(unsigned TargetOcc)434fd4c410fSValery Pykhtin unsigned GCNIterativeScheduler::tryMaximizeOccupancy(unsigned TargetOcc) {
435fd4c410fSValery Pykhtin   // TODO: assert Regions are sorted descending by pressure
4365bfbae5cSTom Stellard   const auto &ST = MF.getSubtarget<GCNSubtarget>();
437fd4c410fSValery Pykhtin   const auto Occ = Regions.front()->MaxPressure.getOccupancy(ST);
438d34e60caSNicola Zaghen   LLVM_DEBUG(dbgs() << "Trying to improve occupancy, target = " << TargetOcc
439fd4c410fSValery Pykhtin                     << ", current = " << Occ << '\n');
440fd4c410fSValery Pykhtin 
441fd4c410fSValery Pykhtin   auto NewOcc = TargetOcc;
442fd4c410fSValery Pykhtin   for (auto R : Regions) {
443fd4c410fSValery Pykhtin     if (R->MaxPressure.getOccupancy(ST) >= NewOcc)
444fd4c410fSValery Pykhtin       break;
445fd4c410fSValery Pykhtin 
446d34e60caSNicola Zaghen     LLVM_DEBUG(printRegion(dbgs(), R->Begin, R->End, LIS, 3);
447fd4c410fSValery Pykhtin                printLivenessInfo(dbgs(), R->Begin, R->End, LIS));
448fd4c410fSValery Pykhtin 
449fd4c410fSValery Pykhtin     BuildDAG DAG(*R, *this);
450fd4c410fSValery Pykhtin     const auto MinSchedule = makeMinRegSchedule(DAG.getTopRoots(), *this);
451fd4c410fSValery Pykhtin     const auto MaxRP = getSchedulePressure(*R, MinSchedule);
452d34e60caSNicola Zaghen     LLVM_DEBUG(dbgs() << "Occupancy improvement attempt:\n";
453fd4c410fSValery Pykhtin                printSchedRP(dbgs(), R->MaxPressure, MaxRP));
454fd4c410fSValery Pykhtin 
455fd4c410fSValery Pykhtin     NewOcc = std::min(NewOcc, MaxRP.getOccupancy(ST));
456fd4c410fSValery Pykhtin     if (NewOcc <= Occ)
457fd4c410fSValery Pykhtin       break;
458fd4c410fSValery Pykhtin 
459fd4c410fSValery Pykhtin     setBestSchedule(*R, MinSchedule, MaxRP);
460fd4c410fSValery Pykhtin   }
461d34e60caSNicola Zaghen   LLVM_DEBUG(dbgs() << "New occupancy = " << NewOcc
462fd4c410fSValery Pykhtin                     << ", prev occupancy = " << Occ << '\n');
463d4b500cbSStanislav Mekhanoshin   if (NewOcc > Occ) {
464d4b500cbSStanislav Mekhanoshin     SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
465d4b500cbSStanislav Mekhanoshin     MFI->increaseOccupancy(MF, NewOcc);
466d4b500cbSStanislav Mekhanoshin   }
467d4b500cbSStanislav Mekhanoshin 
468fd4c410fSValery Pykhtin   return std::max(NewOcc, Occ);
469fd4c410fSValery Pykhtin }
470fd4c410fSValery Pykhtin 
scheduleLegacyMaxOccupancy(bool TryMaximizeOccupancy)471fd4c410fSValery Pykhtin void GCNIterativeScheduler::scheduleLegacyMaxOccupancy(
472fd4c410fSValery Pykhtin   bool TryMaximizeOccupancy) {
4735bfbae5cSTom Stellard   const auto &ST = MF.getSubtarget<GCNSubtarget>();
474d4b500cbSStanislav Mekhanoshin   SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
475d4b500cbSStanislav Mekhanoshin   auto TgtOcc = MFI->getMinAllowedOccupancy();
476fd4c410fSValery Pykhtin 
477fd4c410fSValery Pykhtin   sortRegionsByPressure(TgtOcc);
478fd4c410fSValery Pykhtin   auto Occ = Regions.front()->MaxPressure.getOccupancy(ST);
479fd4c410fSValery Pykhtin 
480fd4c410fSValery Pykhtin   if (TryMaximizeOccupancy && Occ < TgtOcc)
481fd4c410fSValery Pykhtin     Occ = tryMaximizeOccupancy(TgtOcc);
482fd4c410fSValery Pykhtin 
483fd4c410fSValery Pykhtin   // This is really weird but for some magic scheduling regions twice
484fd4c410fSValery Pykhtin   // gives performance improvement
485fd4c410fSValery Pykhtin   const int NumPasses = Occ < TgtOcc ? 2 : 1;
486fd4c410fSValery Pykhtin 
487fd4c410fSValery Pykhtin   TgtOcc = std::min(Occ, TgtOcc);
488d34e60caSNicola Zaghen   LLVM_DEBUG(dbgs() << "Scheduling using default scheduler, "
489d34e60caSNicola Zaghen                        "target occupancy = "
490d34e60caSNicola Zaghen                     << TgtOcc << '\n');
491fd4c410fSValery Pykhtin   GCNMaxOccupancySchedStrategy LStrgy(Context);
492d4b500cbSStanislav Mekhanoshin   unsigned FinalOccupancy = std::min(Occ, MFI->getOccupancy());
493fd4c410fSValery Pykhtin 
494fd4c410fSValery Pykhtin   for (int I = 0; I < NumPasses; ++I) {
495fd4c410fSValery Pykhtin     // running first pass with TargetOccupancy = 0 mimics previous scheduling
496fd4c410fSValery Pykhtin     // approach and is a performance magic
497fd4c410fSValery Pykhtin     LStrgy.setTargetOccupancy(I == 0 ? 0 : TgtOcc);
498fd4c410fSValery Pykhtin     for (auto R : Regions) {
499fd4c410fSValery Pykhtin       OverrideLegacyStrategy Ovr(*R, LStrgy, *this);
500fd4c410fSValery Pykhtin 
501fd4c410fSValery Pykhtin       Ovr.schedule();
502fd4c410fSValery Pykhtin       const auto RP = getRegionPressure(*R);
503d34e60caSNicola Zaghen       LLVM_DEBUG(printSchedRP(dbgs(), R->MaxPressure, RP));
504fd4c410fSValery Pykhtin 
505fd4c410fSValery Pykhtin       if (RP.getOccupancy(ST) < TgtOcc) {
506d34e60caSNicola Zaghen         LLVM_DEBUG(dbgs() << "Didn't fit into target occupancy O" << TgtOcc);
507fd4c410fSValery Pykhtin         if (R->BestSchedule.get() &&
508fd4c410fSValery Pykhtin             R->BestSchedule->MaxPressure.getOccupancy(ST) >= TgtOcc) {
509d34e60caSNicola Zaghen           LLVM_DEBUG(dbgs() << ", scheduling minimal register\n");
510fd4c410fSValery Pykhtin           scheduleBest(*R);
511fd4c410fSValery Pykhtin         } else {
512d34e60caSNicola Zaghen           LLVM_DEBUG(dbgs() << ", restoring\n");
513fd4c410fSValery Pykhtin           Ovr.restoreOrder();
514fd4c410fSValery Pykhtin           assert(R->MaxPressure.getOccupancy(ST) >= TgtOcc);
515fd4c410fSValery Pykhtin         }
516fd4c410fSValery Pykhtin       }
517d4b500cbSStanislav Mekhanoshin       FinalOccupancy = std::min(FinalOccupancy, RP.getOccupancy(ST));
518fd4c410fSValery Pykhtin     }
519fd4c410fSValery Pykhtin   }
520d4b500cbSStanislav Mekhanoshin   MFI->limitOccupancy(FinalOccupancy);
521fd4c410fSValery Pykhtin }
522fd4c410fSValery Pykhtin 
523fd4c410fSValery Pykhtin ///////////////////////////////////////////////////////////////////////////////
524fd4c410fSValery Pykhtin // Minimal Register Strategy
525fd4c410fSValery Pykhtin 
scheduleMinReg(bool force)526fd4c410fSValery Pykhtin void GCNIterativeScheduler::scheduleMinReg(bool force) {
5275bfbae5cSTom Stellard   const auto &ST = MF.getSubtarget<GCNSubtarget>();
528d4b500cbSStanislav Mekhanoshin   const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
529d4b500cbSStanislav Mekhanoshin   const auto TgtOcc = MFI->getOccupancy();
530fd4c410fSValery Pykhtin   sortRegionsByPressure(TgtOcc);
531fd4c410fSValery Pykhtin 
532fd4c410fSValery Pykhtin   auto MaxPressure = Regions.front()->MaxPressure;
533fd4c410fSValery Pykhtin   for (auto R : Regions) {
534fd4c410fSValery Pykhtin     if (!force && R->MaxPressure.less(ST, MaxPressure, TgtOcc))
535fd4c410fSValery Pykhtin       break;
536fd4c410fSValery Pykhtin 
537fd4c410fSValery Pykhtin     BuildDAG DAG(*R, *this);
538fd4c410fSValery Pykhtin     const auto MinSchedule = makeMinRegSchedule(DAG.getTopRoots(), *this);
539fd4c410fSValery Pykhtin 
540fd4c410fSValery Pykhtin     const auto RP = getSchedulePressure(*R, MinSchedule);
541d34e60caSNicola Zaghen     LLVM_DEBUG(if (R->MaxPressure.less(ST, RP, TgtOcc)) {
542fd4c410fSValery Pykhtin       dbgs() << "\nWarning: Pressure becomes worse after minreg!";
543fd4c410fSValery Pykhtin       printSchedRP(dbgs(), R->MaxPressure, RP);
544fd4c410fSValery Pykhtin     });
545fd4c410fSValery Pykhtin 
546fd4c410fSValery Pykhtin     if (!force && MaxPressure.less(ST, RP, TgtOcc))
547fd4c410fSValery Pykhtin       break;
548fd4c410fSValery Pykhtin 
549fd4c410fSValery Pykhtin     scheduleRegion(*R, MinSchedule, RP);
550d34e60caSNicola Zaghen     LLVM_DEBUG(printSchedResult(dbgs(), R, RP));
551fd4c410fSValery Pykhtin 
552fd4c410fSValery Pykhtin     MaxPressure = RP;
553fd4c410fSValery Pykhtin   }
554fd4c410fSValery Pykhtin }
555f2fe9725SValery Pykhtin 
556f2fe9725SValery Pykhtin ///////////////////////////////////////////////////////////////////////////////
557f2fe9725SValery Pykhtin // ILP scheduler port
558f2fe9725SValery Pykhtin 
scheduleILP(bool TryMaximizeOccupancy)559f2fe9725SValery Pykhtin void GCNIterativeScheduler::scheduleILP(
560f2fe9725SValery Pykhtin   bool TryMaximizeOccupancy) {
5615bfbae5cSTom Stellard   const auto &ST = MF.getSubtarget<GCNSubtarget>();
562d4b500cbSStanislav Mekhanoshin   SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
563d4b500cbSStanislav Mekhanoshin   auto TgtOcc = MFI->getMinAllowedOccupancy();
564f2fe9725SValery Pykhtin 
565f2fe9725SValery Pykhtin   sortRegionsByPressure(TgtOcc);
566f2fe9725SValery Pykhtin   auto Occ = Regions.front()->MaxPressure.getOccupancy(ST);
567f2fe9725SValery Pykhtin 
568f2fe9725SValery Pykhtin   if (TryMaximizeOccupancy && Occ < TgtOcc)
569f2fe9725SValery Pykhtin     Occ = tryMaximizeOccupancy(TgtOcc);
570f2fe9725SValery Pykhtin 
571f2fe9725SValery Pykhtin   TgtOcc = std::min(Occ, TgtOcc);
572d34e60caSNicola Zaghen   LLVM_DEBUG(dbgs() << "Scheduling using default scheduler, "
573d34e60caSNicola Zaghen                        "target occupancy = "
574d34e60caSNicola Zaghen                     << TgtOcc << '\n');
575f2fe9725SValery Pykhtin 
576d4b500cbSStanislav Mekhanoshin   unsigned FinalOccupancy = std::min(Occ, MFI->getOccupancy());
577f2fe9725SValery Pykhtin   for (auto R : Regions) {
578f2fe9725SValery Pykhtin     BuildDAG DAG(*R, *this);
579f2fe9725SValery Pykhtin     const auto ILPSchedule = makeGCNILPScheduler(DAG.getBottomRoots(), *this);
580f2fe9725SValery Pykhtin 
581f2fe9725SValery Pykhtin     const auto RP = getSchedulePressure(*R, ILPSchedule);
582d34e60caSNicola Zaghen     LLVM_DEBUG(printSchedRP(dbgs(), R->MaxPressure, RP));
583f2fe9725SValery Pykhtin 
584f2fe9725SValery Pykhtin     if (RP.getOccupancy(ST) < TgtOcc) {
585d34e60caSNicola Zaghen       LLVM_DEBUG(dbgs() << "Didn't fit into target occupancy O" << TgtOcc);
586f2fe9725SValery Pykhtin       if (R->BestSchedule.get() &&
587f2fe9725SValery Pykhtin         R->BestSchedule->MaxPressure.getOccupancy(ST) >= TgtOcc) {
588d34e60caSNicola Zaghen         LLVM_DEBUG(dbgs() << ", scheduling minimal register\n");
589f2fe9725SValery Pykhtin         scheduleBest(*R);
590f2fe9725SValery Pykhtin       }
591f2fe9725SValery Pykhtin     } else {
592f2fe9725SValery Pykhtin       scheduleRegion(*R, ILPSchedule, RP);
593d34e60caSNicola Zaghen       LLVM_DEBUG(printSchedResult(dbgs(), R, RP));
594d4b500cbSStanislav Mekhanoshin       FinalOccupancy = std::min(FinalOccupancy, RP.getOccupancy(ST));
595f2fe9725SValery Pykhtin     }
596f2fe9725SValery Pykhtin   }
597d4b500cbSStanislav Mekhanoshin   MFI->limitOccupancy(FinalOccupancy);
598f2fe9725SValery Pykhtin }
599