1 //===- GCNIterativeScheduler.cpp ------------------------------------------===//
3 // 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
7 //===----------------------------------------------------------------------===//
9 #include "GCNIterativeScheduler.h"
10 #include "AMDGPUSubtarget.h"
11 #include "GCNRegPressure.h"
12 #include "GCNSchedStrategy.h"
13 #include "SIMachineFunctionInfo.h"
14 #include "llvm/ADT/ArrayRef.h"
15 #include "llvm/ADT/STLExtras.h"
16 #include "llvm/ADT/SmallVector.h"
17 #include "llvm/CodeGen/LiveIntervals.h"
18 #include "llvm/CodeGen/MachineBasicBlock.h"
19 #include "llvm/CodeGen/MachineFunction.h"
20 #include "llvm/CodeGen/RegisterPressure.h"
21 #include "llvm/CodeGen/ScheduleDAG.h"
22 #include "llvm/Config/llvm-config.h"
23 #include "llvm/Support/Compiler.h"
24 #include "llvm/Support/Debug.h"
25 #include "llvm/Support/raw_ostream.h"
31 #include <type_traits>
36 #define DEBUG_TYPE "machine-scheduler"
40 std::vector
<const SUnit
*> makeMinRegSchedule(ArrayRef
<const SUnit
*> TopRoots
,
41 const ScheduleDAG
&DAG
);
43 std::vector
<const SUnit
*> makeGCNILPScheduler(ArrayRef
<const SUnit
*> BotRoots
,
44 const ScheduleDAG
&DAG
);
47 // shim accessors for different order containers
48 static inline MachineInstr
*getMachineInstr(MachineInstr
*MI
) {
51 static inline MachineInstr
*getMachineInstr(const SUnit
*SU
) {
52 return SU
->getInstr();
54 static inline MachineInstr
*getMachineInstr(const SUnit
&SU
) {
58 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
60 static void printRegion(raw_ostream
&OS
,
61 MachineBasicBlock::iterator Begin
,
62 MachineBasicBlock::iterator End
,
63 const LiveIntervals
*LIS
,
65 std::numeric_limits
<unsigned>::max()) {
66 auto BB
= Begin
->getParent();
67 OS
<< BB
->getParent()->getName() << ":" << printMBBReference(*BB
) << ' '
68 << BB
->getName() << ":\n";
70 MaxInstNum
= std::max(MaxInstNum
, 1u);
71 for (; I
!= End
&& MaxInstNum
; ++I
, --MaxInstNum
) {
72 if (!I
->isDebugInstr() && LIS
)
73 OS
<< LIS
->getInstructionIndex(*I
);
79 if (!I
->isDebugInstr() && LIS
)
80 OS
<< LIS
->getInstructionIndex(*I
);
83 if (End
!= BB
->end()) { // print boundary inst if present
85 if (LIS
) OS
<< LIS
->getInstructionIndex(*End
) << '\t';
91 static void printLivenessInfo(raw_ostream
&OS
,
92 MachineBasicBlock::iterator Begin
,
93 MachineBasicBlock::iterator End
,
94 const LiveIntervals
*LIS
) {
95 const auto BB
= Begin
->getParent();
96 const auto &MRI
= BB
->getParent()->getRegInfo();
98 const auto LiveIns
= getLiveRegsBefore(*Begin
, *LIS
);
100 getRegPressure(MRI
, LiveIns
).print(OS
);
102 const auto BottomMI
= End
== BB
->end() ? std::prev(End
) : End
;
103 const auto LiveOuts
= getLiveRegsAfter(*BottomMI
, *LIS
);
105 getRegPressure(MRI
, LiveOuts
).print(OS
);
109 void GCNIterativeScheduler::printRegions(raw_ostream
&OS
) const {
110 const auto &ST
= MF
.getSubtarget
<GCNSubtarget
>();
111 for (const auto R
: Regions
) {
112 OS
<< "Region to schedule ";
113 printRegion(OS
, R
->Begin
, R
->End
, LIS
, 1);
114 printLivenessInfo(OS
, R
->Begin
, R
->End
, LIS
);
116 R
->MaxPressure
.print(OS
, &ST
);
121 void GCNIterativeScheduler::printSchedResult(raw_ostream
&OS
,
123 const GCNRegPressure
&RP
) const {
124 OS
<< "\nAfter scheduling ";
125 printRegion(OS
, R
->Begin
, R
->End
, LIS
);
126 printSchedRP(OS
, R
->MaxPressure
, RP
);
131 void GCNIterativeScheduler::printSchedRP(raw_ostream
&OS
,
132 const GCNRegPressure
&Before
,
133 const GCNRegPressure
&After
) const {
134 const auto &ST
= MF
.getSubtarget
<GCNSubtarget
>();
136 Before
.print(OS
, &ST
);
138 After
.print(OS
, &ST
);
142 // DAG builder helper
143 class GCNIterativeScheduler::BuildDAG
{
144 GCNIterativeScheduler
&Sch
;
145 SmallVector
<SUnit
*, 8> TopRoots
;
147 SmallVector
<SUnit
*, 8> BotRoots
;
149 BuildDAG(const Region
&R
, GCNIterativeScheduler
&_Sch
)
151 auto BB
= R
.Begin
->getParent();
152 Sch
.BaseClass::startBlock(BB
);
153 Sch
.BaseClass::enterRegion(BB
, R
.Begin
, R
.End
, R
.NumRegionInstrs
);
155 Sch
.buildSchedGraph(Sch
.AA
, nullptr, nullptr, nullptr,
156 /*TrackLaneMask*/true);
157 Sch
.Topo
.InitDAGTopologicalSorting();
158 Sch
.findRootsAndBiasEdges(TopRoots
, BotRoots
);
162 Sch
.BaseClass::exitRegion();
163 Sch
.BaseClass::finishBlock();
166 ArrayRef
<const SUnit
*> getTopRoots() const {
169 ArrayRef
<SUnit
*> getBottomRoots() const {
174 class GCNIterativeScheduler::OverrideLegacyStrategy
{
175 GCNIterativeScheduler
&Sch
;
177 std::unique_ptr
<MachineSchedStrategy
> SaveSchedImpl
;
178 GCNRegPressure SaveMaxRP
;
181 OverrideLegacyStrategy(Region
&R
,
182 MachineSchedStrategy
&OverrideStrategy
,
183 GCNIterativeScheduler
&_Sch
)
186 , SaveSchedImpl(std::move(_Sch
.SchedImpl
))
187 , SaveMaxRP(R
.MaxPressure
) {
188 Sch
.SchedImpl
.reset(&OverrideStrategy
);
189 auto BB
= R
.Begin
->getParent();
190 Sch
.BaseClass::startBlock(BB
);
191 Sch
.BaseClass::enterRegion(BB
, R
.Begin
, R
.End
, R
.NumRegionInstrs
);
194 ~OverrideLegacyStrategy() {
195 Sch
.BaseClass::exitRegion();
196 Sch
.BaseClass::finishBlock();
197 Sch
.SchedImpl
.release();
198 Sch
.SchedImpl
= std::move(SaveSchedImpl
);
202 assert(Sch
.RegionBegin
== Rgn
.Begin
&& Sch
.RegionEnd
== Rgn
.End
);
203 LLVM_DEBUG(dbgs() << "\nScheduling ";
204 printRegion(dbgs(), Rgn
.Begin
, Rgn
.End
, Sch
.LIS
, 2));
205 Sch
.BaseClass::schedule();
207 // Unfortunatelly placeDebugValues incorrectly modifies RegionEnd, restore
208 Sch
.RegionEnd
= Rgn
.End
;
209 //assert(Rgn.End == Sch.RegionEnd);
210 Rgn
.Begin
= Sch
.RegionBegin
;
211 Rgn
.MaxPressure
.clear();
214 void restoreOrder() {
215 assert(Sch
.RegionBegin
== Rgn
.Begin
&& Sch
.RegionEnd
== Rgn
.End
);
216 // DAG SUnits are stored using original region's order
217 // so just use SUnits as the restoring schedule
218 Sch
.scheduleRegion(Rgn
, Sch
.SUnits
, SaveMaxRP
);
224 // just a stub to make base class happy
225 class SchedStrategyStub
: public MachineSchedStrategy
{
227 bool shouldTrackPressure() const override
{ return false; }
228 bool shouldTrackLaneMasks() const override
{ return false; }
229 void initialize(ScheduleDAGMI
*DAG
) override
{}
230 SUnit
*pickNode(bool &IsTopNode
) override
{ return nullptr; }
231 void schedNode(SUnit
*SU
, bool IsTopNode
) override
{}
232 void releaseTopNode(SUnit
*SU
) override
{}
233 void releaseBottomNode(SUnit
*SU
) override
{}
236 } // end anonymous namespace
238 GCNIterativeScheduler::GCNIterativeScheduler(MachineSchedContext
*C
,
240 : BaseClass(C
, std::make_unique
<SchedStrategyStub
>())
246 // returns max pressure for a region
248 GCNIterativeScheduler::getRegionPressure(MachineBasicBlock::iterator Begin
,
249 MachineBasicBlock::iterator End
)
251 // For the purpose of pressure tracking bottom inst of the region should
252 // be also processed. End is either BB end, BB terminator inst or sched
254 auto const BBEnd
= Begin
->getParent()->end();
255 auto const BottomMI
= End
== BBEnd
? std::prev(End
) : End
;
257 // scheduleRegions walks bottom to top, so its likely we just get next
258 // instruction to track
259 auto AfterBottomMI
= std::next(BottomMI
);
260 if (AfterBottomMI
== BBEnd
||
261 &*AfterBottomMI
!= UPTracker
.getLastTrackedMI()) {
262 UPTracker
.reset(*BottomMI
);
264 assert(UPTracker
.isValid());
267 for (auto I
= BottomMI
; I
!= Begin
; --I
)
268 UPTracker
.recede(*I
);
270 UPTracker
.recede(*Begin
);
272 assert(UPTracker
.isValid() ||
273 (dbgs() << "Tracked region ",
274 printRegion(dbgs(), Begin
, End
, LIS
), false));
275 return UPTracker
.moveMaxPressure();
278 // returns max pressure for a tentative schedule
279 template <typename Range
> GCNRegPressure
280 GCNIterativeScheduler::getSchedulePressure(const Region
&R
,
281 Range
&&Schedule
) const {
282 auto const BBEnd
= R
.Begin
->getParent()->end();
283 GCNUpwardRPTracker
RPTracker(*LIS
);
284 if (R
.End
!= BBEnd
) {
285 // R.End points to the boundary instruction but the
286 // schedule doesn't include it
287 RPTracker
.reset(*R
.End
);
288 RPTracker
.recede(*R
.End
);
290 // R.End doesn't point to the boundary instruction
291 RPTracker
.reset(*std::prev(BBEnd
));
293 for (auto I
= Schedule
.end(), B
= Schedule
.begin(); I
!= B
;) {
294 RPTracker
.recede(*getMachineInstr(*--I
));
296 return RPTracker
.moveMaxPressure();
299 void GCNIterativeScheduler::enterRegion(MachineBasicBlock
*BB
, // overriden
300 MachineBasicBlock::iterator Begin
,
301 MachineBasicBlock::iterator End
,
302 unsigned NumRegionInstrs
) {
303 BaseClass::enterRegion(BB
, Begin
, End
, NumRegionInstrs
);
304 if (NumRegionInstrs
> 2) {
306 new (Alloc
.Allocate())
307 Region
{ Begin
, End
, NumRegionInstrs
,
308 getRegionPressure(Begin
, End
), nullptr });
312 void GCNIterativeScheduler::schedule() { // overriden
314 LLVM_DEBUG(printLivenessInfo(dbgs(), RegionBegin
, RegionEnd
, LIS
);
315 if (!Regions
.empty() && Regions
.back()->Begin
== RegionBegin
) {
316 dbgs() << "Max RP: ";
317 Regions
.back()->MaxPressure
.print(
318 dbgs(), &MF
.getSubtarget
<GCNSubtarget
>());
323 void GCNIterativeScheduler::finalizeSchedule() { // overriden
327 case SCHEDULE_MINREGONLY
: scheduleMinReg(); break;
328 case SCHEDULE_MINREGFORCED
: scheduleMinReg(true); break;
329 case SCHEDULE_LEGACYMAXOCCUPANCY
: scheduleLegacyMaxOccupancy(); break;
330 case SCHEDULE_ILP
: scheduleILP(false); break;
334 // Detach schedule from SUnits and interleave it with debug values.
335 // Returned schedule becomes independent of DAG state.
336 std::vector
<MachineInstr
*>
337 GCNIterativeScheduler::detachSchedule(ScheduleRef Schedule
) const {
338 std::vector
<MachineInstr
*> Res
;
339 Res
.reserve(Schedule
.size() * 2);
342 Res
.push_back(FirstDbgValue
);
344 const auto DbgB
= DbgValues
.begin(), DbgE
= DbgValues
.end();
345 for (auto SU
: Schedule
) {
346 Res
.push_back(SU
->getInstr());
347 const auto &D
= std::find_if(DbgB
, DbgE
, [SU
](decltype(*DbgB
) &P
) {
348 return P
.second
== SU
->getInstr();
351 Res
.push_back(D
->first
);
356 void GCNIterativeScheduler::setBestSchedule(Region
&R
,
357 ScheduleRef Schedule
,
358 const GCNRegPressure
&MaxRP
) {
359 R
.BestSchedule
.reset(
360 new TentativeSchedule
{ detachSchedule(Schedule
), MaxRP
});
363 void GCNIterativeScheduler::scheduleBest(Region
&R
) {
364 assert(R
.BestSchedule
.get() && "No schedule specified");
365 scheduleRegion(R
, R
.BestSchedule
->Schedule
, R
.BestSchedule
->MaxPressure
);
366 R
.BestSchedule
.reset();
369 // minimal required region scheduler, works for ranges of SUnits*,
370 // SUnits or MachineIntrs*
371 template <typename Range
>
372 void GCNIterativeScheduler::scheduleRegion(Region
&R
, Range
&&Schedule
,
373 const GCNRegPressure
&MaxRP
) {
374 assert(RegionBegin
== R
.Begin
&& RegionEnd
== R
.End
);
375 assert(LIS
!= nullptr);
377 const auto SchedMaxRP
= getSchedulePressure(R
, Schedule
);
379 auto BB
= R
.Begin
->getParent();
381 for (const auto &I
: Schedule
) {
382 auto MI
= getMachineInstr(I
);
386 if (!MI
->isDebugInstr())
387 LIS
->handleMove(*MI
, true);
389 if (!MI
->isDebugInstr()) {
390 // Reset read - undef flags and update them later.
391 for (auto &Op
: MI
->operands())
392 if (Op
.isReg() && Op
.isDef())
393 Op
.setIsUndef(false);
395 RegisterOperands RegOpers
;
396 RegOpers
.collect(*MI
, *TRI
, MRI
, /*ShouldTrackLaneMasks*/true,
397 /*IgnoreDead*/false);
398 // Adjust liveness and add missing dead+read-undef flags.
399 auto SlotIdx
= LIS
->getInstructionIndex(*MI
).getRegSlot();
400 RegOpers
.adjustLaneLiveness(*LIS
, MRI
, SlotIdx
, MI
);
402 Top
= std::next(MI
->getIterator());
404 RegionBegin
= getMachineInstr(Schedule
.front());
406 // Schedule consisting of MachineInstr* is considered 'detached'
407 // and already interleaved with debug values
408 if (!std::is_same
<decltype(*Schedule
.begin()), MachineInstr
*>::value
) {
410 // Unfortunatelly placeDebugValues incorrectly modifies RegionEnd, restore
411 //assert(R.End == RegionEnd);
415 R
.Begin
= RegionBegin
;
416 R
.MaxPressure
= MaxRP
;
419 const auto RegionMaxRP
= getRegionPressure(R
);
420 const auto &ST
= MF
.getSubtarget
<GCNSubtarget
>();
422 assert((SchedMaxRP
== RegionMaxRP
&& (MaxRP
.empty() || SchedMaxRP
== MaxRP
))
423 || (dbgs() << "Max RP mismatch!!!\n"
424 "RP for schedule (calculated): ",
425 SchedMaxRP
.print(dbgs(), &ST
),
426 dbgs() << "RP for schedule (reported): ",
427 MaxRP
.print(dbgs(), &ST
),
428 dbgs() << "RP after scheduling: ",
429 RegionMaxRP
.print(dbgs(), &ST
),
433 // Sort recorded regions by pressure - highest at the front
434 void GCNIterativeScheduler::sortRegionsByPressure(unsigned TargetOcc
) {
435 const auto &ST
= MF
.getSubtarget
<GCNSubtarget
>();
436 llvm::sort(Regions
, [&ST
, TargetOcc
](const Region
*R1
, const Region
*R2
) {
437 return R2
->MaxPressure
.less(ST
, R1
->MaxPressure
, TargetOcc
);
441 ///////////////////////////////////////////////////////////////////////////////
442 // Legacy MaxOccupancy Strategy
444 // Tries to increase occupancy applying minreg scheduler for a sequence of
445 // most demanding regions. Obtained schedules are saved as BestSchedule for a
447 // TargetOcc is the best achievable occupancy for a kernel.
448 // Returns better occupancy on success or current occupancy on fail.
449 // BestSchedules aren't deleted on fail.
450 unsigned GCNIterativeScheduler::tryMaximizeOccupancy(unsigned TargetOcc
) {
451 // TODO: assert Regions are sorted descending by pressure
452 const auto &ST
= MF
.getSubtarget
<GCNSubtarget
>();
453 const auto Occ
= Regions
.front()->MaxPressure
.getOccupancy(ST
);
454 LLVM_DEBUG(dbgs() << "Trying to improve occupancy, target = " << TargetOcc
455 << ", current = " << Occ
<< '\n');
457 auto NewOcc
= TargetOcc
;
458 for (auto R
: Regions
) {
459 if (R
->MaxPressure
.getOccupancy(ST
) >= NewOcc
)
462 LLVM_DEBUG(printRegion(dbgs(), R
->Begin
, R
->End
, LIS
, 3);
463 printLivenessInfo(dbgs(), R
->Begin
, R
->End
, LIS
));
465 BuildDAG
DAG(*R
, *this);
466 const auto MinSchedule
= makeMinRegSchedule(DAG
.getTopRoots(), *this);
467 const auto MaxRP
= getSchedulePressure(*R
, MinSchedule
);
468 LLVM_DEBUG(dbgs() << "Occupancy improvement attempt:\n";
469 printSchedRP(dbgs(), R
->MaxPressure
, MaxRP
));
471 NewOcc
= std::min(NewOcc
, MaxRP
.getOccupancy(ST
));
475 setBestSchedule(*R
, MinSchedule
, MaxRP
);
477 LLVM_DEBUG(dbgs() << "New occupancy = " << NewOcc
478 << ", prev occupancy = " << Occ
<< '\n');
480 SIMachineFunctionInfo
*MFI
= MF
.getInfo
<SIMachineFunctionInfo
>();
481 MFI
->increaseOccupancy(MF
, NewOcc
);
484 return std::max(NewOcc
, Occ
);
487 void GCNIterativeScheduler::scheduleLegacyMaxOccupancy(
488 bool TryMaximizeOccupancy
) {
489 const auto &ST
= MF
.getSubtarget
<GCNSubtarget
>();
490 SIMachineFunctionInfo
*MFI
= MF
.getInfo
<SIMachineFunctionInfo
>();
491 auto TgtOcc
= MFI
->getMinAllowedOccupancy();
493 sortRegionsByPressure(TgtOcc
);
494 auto Occ
= Regions
.front()->MaxPressure
.getOccupancy(ST
);
496 if (TryMaximizeOccupancy
&& Occ
< TgtOcc
)
497 Occ
= tryMaximizeOccupancy(TgtOcc
);
499 // This is really weird but for some magic scheduling regions twice
500 // gives performance improvement
501 const int NumPasses
= Occ
< TgtOcc
? 2 : 1;
503 TgtOcc
= std::min(Occ
, TgtOcc
);
504 LLVM_DEBUG(dbgs() << "Scheduling using default scheduler, "
505 "target occupancy = "
507 GCNMaxOccupancySchedStrategy
LStrgy(Context
);
508 unsigned FinalOccupancy
= std::min(Occ
, MFI
->getOccupancy());
510 for (int I
= 0; I
< NumPasses
; ++I
) {
511 // running first pass with TargetOccupancy = 0 mimics previous scheduling
512 // approach and is a performance magic
513 LStrgy
.setTargetOccupancy(I
== 0 ? 0 : TgtOcc
);
514 for (auto R
: Regions
) {
515 OverrideLegacyStrategy
Ovr(*R
, LStrgy
, *this);
518 const auto RP
= getRegionPressure(*R
);
519 LLVM_DEBUG(printSchedRP(dbgs(), R
->MaxPressure
, RP
));
521 if (RP
.getOccupancy(ST
) < TgtOcc
) {
522 LLVM_DEBUG(dbgs() << "Didn't fit into target occupancy O" << TgtOcc
);
523 if (R
->BestSchedule
.get() &&
524 R
->BestSchedule
->MaxPressure
.getOccupancy(ST
) >= TgtOcc
) {
525 LLVM_DEBUG(dbgs() << ", scheduling minimal register\n");
528 LLVM_DEBUG(dbgs() << ", restoring\n");
530 assert(R
->MaxPressure
.getOccupancy(ST
) >= TgtOcc
);
533 FinalOccupancy
= std::min(FinalOccupancy
, RP
.getOccupancy(ST
));
536 MFI
->limitOccupancy(FinalOccupancy
);
539 ///////////////////////////////////////////////////////////////////////////////
540 // Minimal Register Strategy
542 void GCNIterativeScheduler::scheduleMinReg(bool force
) {
543 const auto &ST
= MF
.getSubtarget
<GCNSubtarget
>();
544 const SIMachineFunctionInfo
*MFI
= MF
.getInfo
<SIMachineFunctionInfo
>();
545 const auto TgtOcc
= MFI
->getOccupancy();
546 sortRegionsByPressure(TgtOcc
);
548 auto MaxPressure
= Regions
.front()->MaxPressure
;
549 for (auto R
: Regions
) {
550 if (!force
&& R
->MaxPressure
.less(ST
, MaxPressure
, TgtOcc
))
553 BuildDAG
DAG(*R
, *this);
554 const auto MinSchedule
= makeMinRegSchedule(DAG
.getTopRoots(), *this);
556 const auto RP
= getSchedulePressure(*R
, MinSchedule
);
557 LLVM_DEBUG(if (R
->MaxPressure
.less(ST
, RP
, TgtOcc
)) {
558 dbgs() << "\nWarning: Pressure becomes worse after minreg!";
559 printSchedRP(dbgs(), R
->MaxPressure
, RP
);
562 if (!force
&& MaxPressure
.less(ST
, RP
, TgtOcc
))
565 scheduleRegion(*R
, MinSchedule
, RP
);
566 LLVM_DEBUG(printSchedResult(dbgs(), R
, RP
));
572 ///////////////////////////////////////////////////////////////////////////////
573 // ILP scheduler port
575 void GCNIterativeScheduler::scheduleILP(
576 bool TryMaximizeOccupancy
) {
577 const auto &ST
= MF
.getSubtarget
<GCNSubtarget
>();
578 SIMachineFunctionInfo
*MFI
= MF
.getInfo
<SIMachineFunctionInfo
>();
579 auto TgtOcc
= MFI
->getMinAllowedOccupancy();
581 sortRegionsByPressure(TgtOcc
);
582 auto Occ
= Regions
.front()->MaxPressure
.getOccupancy(ST
);
584 if (TryMaximizeOccupancy
&& Occ
< TgtOcc
)
585 Occ
= tryMaximizeOccupancy(TgtOcc
);
587 TgtOcc
= std::min(Occ
, TgtOcc
);
588 LLVM_DEBUG(dbgs() << "Scheduling using default scheduler, "
589 "target occupancy = "
592 unsigned FinalOccupancy
= std::min(Occ
, MFI
->getOccupancy());
593 for (auto R
: Regions
) {
594 BuildDAG
DAG(*R
, *this);
595 const auto ILPSchedule
= makeGCNILPScheduler(DAG
.getBottomRoots(), *this);
597 const auto RP
= getSchedulePressure(*R
, ILPSchedule
);
598 LLVM_DEBUG(printSchedRP(dbgs(), R
->MaxPressure
, RP
));
600 if (RP
.getOccupancy(ST
) < TgtOcc
) {
601 LLVM_DEBUG(dbgs() << "Didn't fit into target occupancy O" << TgtOcc
);
602 if (R
->BestSchedule
.get() &&
603 R
->BestSchedule
->MaxPressure
.getOccupancy(ST
) >= TgtOcc
) {
604 LLVM_DEBUG(dbgs() << ", scheduling minimal register\n");
608 scheduleRegion(*R
, ILPSchedule
, RP
);
609 LLVM_DEBUG(printSchedResult(dbgs(), R
, RP
));
610 FinalOccupancy
= std::min(FinalOccupancy
, RP
.getOccupancy(ST
));
613 MFI
->limitOccupancy(FinalOccupancy
);