LLVM 20.0.0git
GCNSchedStrategy.cpp
Go to the documentation of this file.
1//===-- GCNSchedStrategy.cpp - GCN Scheduler Strategy ---------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8//
9/// \file
10/// This contains a MachineSchedStrategy implementation for maximizing wave
11/// occupancy on GCN hardware.
12///
13/// This pass will apply multiple scheduling stages to the same function.
14/// Regions are first recorded in GCNScheduleDAGMILive::schedule. The actual
15/// entry point for the scheduling of those regions is
16/// GCNScheduleDAGMILive::runSchedStages.
17
18/// Generally, the reason for having multiple scheduling stages is to account
19/// for the kernel-wide effect of register usage on occupancy. Usually, only a
20/// few scheduling regions will have register pressure high enough to limit
21/// occupancy for the kernel, so constraints can be relaxed to improve ILP in
22/// other regions.
23///
24//===----------------------------------------------------------------------===//
25
26#include "GCNSchedStrategy.h"
27#include "AMDGPUIGroupLP.h"
30
31#define DEBUG_TYPE "machine-scheduler"
32
33using namespace llvm;
34
36 "amdgpu-disable-unclustered-high-rp-reschedule", cl::Hidden,
37 cl::desc("Disable unclustered high register pressure "
38 "reduction scheduling stage."),
39 cl::init(false));
40
42 "amdgpu-disable-clustered-low-occupancy-reschedule", cl::Hidden,
43 cl::desc("Disable clustered low occupancy "
44 "rescheduling for ILP scheduling stage."),
45 cl::init(false));
46
48 "amdgpu-schedule-metric-bias", cl::Hidden,
50 "Sets the bias which adds weight to occupancy vs latency. Set it to "
51 "100 to chase the occupancy only."),
52 cl::init(10));
53
54static cl::opt<bool>
55 RelaxedOcc("amdgpu-schedule-relaxed-occupancy", cl::Hidden,
56 cl::desc("Relax occupancy targets for kernels which are memory "
57 "bound (amdgpu-membound-threshold), or "
58 "Wave Limited (amdgpu-limit-wave-threshold)."),
59 cl::init(false));
60
62 "amdgpu-use-amdgpu-trackers", cl::Hidden,
63 cl::desc("Use the AMDGPU specific RPTrackers during scheduling"),
64 cl::init(false));
65
66const unsigned ScheduleMetrics::ScaleFactor = 100;
67
69 : GenericScheduler(C), TargetOccupancy(0), MF(nullptr),
70 DownwardTracker(*C->LIS), UpwardTracker(*C->LIS), HasHighPressure(false) {
71}
72
75
76 MF = &DAG->MF;
77
79
81 Context->RegClassInfo->getNumAllocatableRegs(&AMDGPU::SGPR_32RegClass);
83 Context->RegClassInfo->getNumAllocatableRegs(&AMDGPU::VGPR_32RegClass);
84
86 // Set the initial TargetOccupnacy to the maximum occupancy that we can
87 // achieve for this function. This effectively sets a lower bound on the
88 // 'Critical' register limits in the scheduler.
89 // Allow for lower occupancy targets if kernel is wave limited or memory
90 // bound, and using the relaxed occupancy feature.
94 std::min(ST.getMaxNumSGPRs(TargetOccupancy, true), SGPRExcessLimit);
95
96 if (!KnownExcessRP) {
98 std::min(ST.getMaxNumVGPRs(TargetOccupancy), VGPRExcessLimit);
99 } else {
100 // This is similar to ST.getMaxNumVGPRs(TargetOccupancy) result except
101 // returns a reasonably small number for targets with lots of VGPRs, such
102 // as GFX10 and GFX11.
103 LLVM_DEBUG(dbgs() << "Region is known to spill, use alternative "
104 "VGPRCriticalLimit calculation method.\n");
105
106 unsigned Granule = AMDGPU::IsaInfo::getVGPRAllocGranule(&ST);
107 unsigned Addressable = AMDGPU::IsaInfo::getAddressableNumVGPRs(&ST);
108 unsigned VGPRBudget = alignDown(Addressable / TargetOccupancy, Granule);
109 VGPRBudget = std::max(VGPRBudget, Granule);
110 VGPRCriticalLimit = std::min(VGPRBudget, VGPRExcessLimit);
111 }
112
113 // Subtract error margin and bias from register limits and avoid overflow.
118
119 LLVM_DEBUG(dbgs() << "VGPRCriticalLimit = " << VGPRCriticalLimit
120 << ", VGPRExcessLimit = " << VGPRExcessLimit
121 << ", SGPRCriticalLimit = " << SGPRCriticalLimit
122 << ", SGPRExcessLimit = " << SGPRExcessLimit << "\n\n");
123}
124
125/// Checks whether \p SU can use the cached DAG pressure diffs to compute the
126/// current register pressure.
127///
128/// This works for the common case, but it has a few exceptions that have been
129/// observed through trial and error:
130/// - Explicit physical register operands
131/// - Subregister definitions
132///
133/// In both of those cases, PressureDiff doesn't represent the actual pressure,
134/// and querying LiveIntervals through the RegPressureTracker is needed to get
135/// an accurate value.
136///
137/// We should eventually only use PressureDiff for maximum performance, but this
138/// already allows 80% of SUs to take the fast path without changing scheduling
139/// at all. Further changes would either change scheduling, or require a lot
140/// more logic to recover an accurate pressure estimate from the PressureDiffs.
141static bool canUsePressureDiffs(const SUnit &SU) {
142 if (!SU.isInstr())
143 return false;
144
145 // Cannot use pressure diffs for subregister defs or with physregs, it's
146 // imprecise in both cases.
147 for (const auto &Op : SU.getInstr()->operands()) {
148 if (!Op.isReg() || Op.isImplicit())
149 continue;
150 if (Op.getReg().isPhysical() ||
151 (Op.isDef() && Op.getSubReg() != AMDGPU::NoSubRegister))
152 return false;
153 }
154 return true;
155}
156
158 bool AtTop, const RegPressureTracker &RPTracker, SUnit *SU,
159 std::vector<unsigned> &Pressure, std::vector<unsigned> &MaxPressure,
160 GCNDownwardRPTracker &DownwardTracker, GCNUpwardRPTracker &UpwardTracker,
161 ScheduleDAGMI *DAG, const SIRegisterInfo *SRI) {
162 // getDownwardPressure() and getUpwardPressure() make temporary changes to
163 // the tracker, so we need to pass those function a non-const copy.
164 RegPressureTracker &TempTracker = const_cast<RegPressureTracker &>(RPTracker);
165 if (!GCNTrackers) {
166 AtTop
167 ? TempTracker.getDownwardPressure(SU->getInstr(), Pressure, MaxPressure)
168 : TempTracker.getUpwardPressure(SU->getInstr(), Pressure, MaxPressure);
169
170 return;
171 }
172
173 // GCNTrackers
174 Pressure.resize(4, 0);
175 MachineInstr *MI = SU->getInstr();
176 GCNRegPressure NewPressure;
177 if (AtTop) {
178 GCNDownwardRPTracker TempDownwardTracker(DownwardTracker);
179 NewPressure = TempDownwardTracker.bumpDownwardPressure(MI, SRI);
180 } else {
181 GCNUpwardRPTracker TempUpwardTracker(UpwardTracker);
182 TempUpwardTracker.recede(*MI);
183 NewPressure = TempUpwardTracker.getPressure();
184 }
185 Pressure[AMDGPU::RegisterPressureSets::SReg_32] = NewPressure.getSGPRNum();
186 Pressure[AMDGPU::RegisterPressureSets::VGPR_32] =
187 NewPressure.getArchVGPRNum();
188 Pressure[AMDGPU::RegisterPressureSets::AGPR_32] = NewPressure.getAGPRNum();
189}
190
191// Return true if the instruction is mutually exclusive with all non-IGLP DAG
192// mutations, requiring all other mutations to be disabled.
193static bool isIGLPMutationOnly(unsigned Opcode) {
194 return Opcode == AMDGPU::SCHED_GROUP_BARRIER || Opcode == AMDGPU::IGLP_OPT;
195}
196
198 bool AtTop,
199 const RegPressureTracker &RPTracker,
200 const SIRegisterInfo *SRI,
201 unsigned SGPRPressure,
202 unsigned VGPRPressure, bool IsBottomUp) {
203 Cand.SU = SU;
204 Cand.AtTop = AtTop;
205
206 if (!DAG->isTrackingPressure())
207 return;
208
209 Pressure.clear();
210 MaxPressure.clear();
211
212 // We try to use the cached PressureDiffs in the ScheduleDAG whenever
213 // possible over querying the RegPressureTracker.
214 //
215 // RegPressureTracker will make a lot of LIS queries which are very
216 // expensive, it is considered a slow function in this context.
217 //
218 // PressureDiffs are precomputed and cached, and getPressureDiff is just a
219 // trivial lookup into an array. It is pretty much free.
220 //
221 // In EXPENSIVE_CHECKS, we always query RPTracker to verify the results of
222 // PressureDiffs.
223 if (AtTop || !canUsePressureDiffs(*SU) || GCNTrackers) {
224 getRegisterPressures(AtTop, RPTracker, SU, Pressure, MaxPressure,
226 } else {
227 // Reserve 4 slots.
228 Pressure.resize(4, 0);
229 Pressure[AMDGPU::RegisterPressureSets::SReg_32] = SGPRPressure;
230 Pressure[AMDGPU::RegisterPressureSets::VGPR_32] = VGPRPressure;
231
232 for (const auto &Diff : DAG->getPressureDiff(SU)) {
233 if (!Diff.isValid())
234 continue;
235 // PressureDiffs is always bottom-up so if we're working top-down we need
236 // to invert its sign.
237 Pressure[Diff.getPSet()] +=
238 (IsBottomUp ? Diff.getUnitInc() : -Diff.getUnitInc());
239 }
240
241#ifdef EXPENSIVE_CHECKS
242 std::vector<unsigned> CheckPressure, CheckMaxPressure;
243 getRegisterPressures(AtTop, RPTracker, SU, CheckPressure, CheckMaxPressure,
245 if (Pressure[AMDGPU::RegisterPressureSets::SReg_32] !=
246 CheckPressure[AMDGPU::RegisterPressureSets::SReg_32] ||
247 Pressure[AMDGPU::RegisterPressureSets::VGPR_32] !=
248 CheckPressure[AMDGPU::RegisterPressureSets::VGPR_32]) {
249 errs() << "Register Pressure is inaccurate when calculated through "
250 "PressureDiff\n"
251 << "SGPR got " << Pressure[AMDGPU::RegisterPressureSets::SReg_32]
252 << ", expected "
253 << CheckPressure[AMDGPU::RegisterPressureSets::SReg_32] << "\n"
254 << "VGPR got " << Pressure[AMDGPU::RegisterPressureSets::VGPR_32]
255 << ", expected "
256 << CheckPressure[AMDGPU::RegisterPressureSets::VGPR_32] << "\n";
257 report_fatal_error("inaccurate register pressure calculation");
258 }
259#endif
260 }
261
262 unsigned NewSGPRPressure = Pressure[AMDGPU::RegisterPressureSets::SReg_32];
263 unsigned NewVGPRPressure = Pressure[AMDGPU::RegisterPressureSets::VGPR_32];
264
265 // If two instructions increase the pressure of different register sets
266 // by the same amount, the generic scheduler will prefer to schedule the
267 // instruction that increases the set with the least amount of registers,
268 // which in our case would be SGPRs. This is rarely what we want, so
269 // when we report excess/critical register pressure, we do it either
270 // only for VGPRs or only for SGPRs.
271
272 // FIXME: Better heuristics to determine whether to prefer SGPRs or VGPRs.
273 const unsigned MaxVGPRPressureInc = 16;
274 bool ShouldTrackVGPRs = VGPRPressure + MaxVGPRPressureInc >= VGPRExcessLimit;
275 bool ShouldTrackSGPRs = !ShouldTrackVGPRs && SGPRPressure >= SGPRExcessLimit;
276
277 // FIXME: We have to enter REG-EXCESS before we reach the actual threshold
278 // to increase the likelihood we don't go over the limits. We should improve
279 // the analysis to look through dependencies to find the path with the least
280 // register pressure.
281
282 // We only need to update the RPDelta for instructions that increase register
283 // pressure. Instructions that decrease or keep reg pressure the same will be
284 // marked as RegExcess in tryCandidate() when they are compared with
285 // instructions that increase the register pressure.
286 if (ShouldTrackVGPRs && NewVGPRPressure >= VGPRExcessLimit) {
287 HasHighPressure = true;
288 Cand.RPDelta.Excess = PressureChange(AMDGPU::RegisterPressureSets::VGPR_32);
289 Cand.RPDelta.Excess.setUnitInc(NewVGPRPressure - VGPRExcessLimit);
290 }
291
292 if (ShouldTrackSGPRs && NewSGPRPressure >= SGPRExcessLimit) {
293 HasHighPressure = true;
294 Cand.RPDelta.Excess = PressureChange(AMDGPU::RegisterPressureSets::SReg_32);
295 Cand.RPDelta.Excess.setUnitInc(NewSGPRPressure - SGPRExcessLimit);
296 }
297
298 // Register pressure is considered 'CRITICAL' if it is approaching a value
299 // that would reduce the wave occupancy for the execution unit. When
300 // register pressure is 'CRITICAL', increasing SGPR and VGPR pressure both
301 // has the same cost, so we don't need to prefer one over the other.
302
303 int SGPRDelta = NewSGPRPressure - SGPRCriticalLimit;
304 int VGPRDelta = NewVGPRPressure - VGPRCriticalLimit;
305
306 if (SGPRDelta >= 0 || VGPRDelta >= 0) {
307 HasHighPressure = true;
308 if (SGPRDelta > VGPRDelta) {
309 Cand.RPDelta.CriticalMax =
310 PressureChange(AMDGPU::RegisterPressureSets::SReg_32);
311 Cand.RPDelta.CriticalMax.setUnitInc(SGPRDelta);
312 } else {
313 Cand.RPDelta.CriticalMax =
314 PressureChange(AMDGPU::RegisterPressureSets::VGPR_32);
315 Cand.RPDelta.CriticalMax.setUnitInc(VGPRDelta);
316 }
317 }
318}
319
320// This function is mostly cut and pasted from
321// GenericScheduler::pickNodeFromQueue()
323 const CandPolicy &ZonePolicy,
324 const RegPressureTracker &RPTracker,
325 SchedCandidate &Cand,
326 bool IsBottomUp) {
327 const SIRegisterInfo *SRI = static_cast<const SIRegisterInfo*>(TRI);
329 unsigned SGPRPressure = 0;
330 unsigned VGPRPressure = 0;
331 if (DAG->isTrackingPressure()) {
332 if (!GCNTrackers) {
333 SGPRPressure = Pressure[AMDGPU::RegisterPressureSets::SReg_32];
334 VGPRPressure = Pressure[AMDGPU::RegisterPressureSets::VGPR_32];
335 } else {
336 GCNRPTracker *T = IsBottomUp
337 ? static_cast<GCNRPTracker *>(&UpwardTracker)
338 : static_cast<GCNRPTracker *>(&DownwardTracker);
339 SGPRPressure = T->getPressure().getSGPRNum();
340 VGPRPressure = T->getPressure().getArchVGPRNum();
341 }
342 }
343 ReadyQueue &Q = Zone.Available;
344 for (SUnit *SU : Q) {
345
346 SchedCandidate TryCand(ZonePolicy);
347 initCandidate(TryCand, SU, Zone.isTop(), RPTracker, SRI, SGPRPressure,
348 VGPRPressure, IsBottomUp);
349 // Pass SchedBoundary only when comparing nodes from the same boundary.
350 SchedBoundary *ZoneArg = Cand.AtTop == TryCand.AtTop ? &Zone : nullptr;
351 tryCandidate(Cand, TryCand, ZoneArg);
352 if (TryCand.Reason != NoCand) {
353 // Initialize resource delta if needed in case future heuristics query it.
354 if (TryCand.ResDelta == SchedResourceDelta())
355 TryCand.initResourceDelta(Zone.DAG, SchedModel);
356 Cand.setBest(TryCand);
358 }
359 }
360}
361
362// This function is mostly cut and pasted from
363// GenericScheduler::pickNodeBidirectional()
365 // Schedule as far as possible in the direction of no choice. This is most
366 // efficient, but also provides the best heuristics for CriticalPSets.
367 if (SUnit *SU = Bot.pickOnlyChoice()) {
368 IsTopNode = false;
369 return SU;
370 }
371 if (SUnit *SU = Top.pickOnlyChoice()) {
372 IsTopNode = true;
373 return SU;
374 }
375 // Set the bottom-up policy based on the state of the current bottom zone and
376 // the instructions outside the zone, including the top zone.
377 CandPolicy BotPolicy;
378 setPolicy(BotPolicy, /*IsPostRA=*/false, Bot, &Top);
379 // Set the top-down policy based on the state of the current top zone and
380 // the instructions outside the zone, including the bottom zone.
381 CandPolicy TopPolicy;
382 setPolicy(TopPolicy, /*IsPostRA=*/false, Top, &Bot);
383
384 // See if BotCand is still valid (because we previously scheduled from Top).
385 LLVM_DEBUG(dbgs() << "Picking from Bot:\n");
386 if (!BotCand.isValid() || BotCand.SU->isScheduled ||
387 BotCand.Policy != BotPolicy) {
390 /*IsBottomUp=*/true);
391 assert(BotCand.Reason != NoCand && "failed to find the first candidate");
392 } else {
394#ifndef NDEBUG
395 if (VerifyScheduling) {
396 SchedCandidate TCand;
397 TCand.reset(CandPolicy());
398 pickNodeFromQueue(Bot, BotPolicy, DAG->getBotRPTracker(), TCand,
399 /*IsBottomUp=*/true);
400 assert(TCand.SU == BotCand.SU &&
401 "Last pick result should correspond to re-picking right now");
402 }
403#endif
404 }
405
406 // Check if the top Q has a better candidate.
407 LLVM_DEBUG(dbgs() << "Picking from Top:\n");
408 if (!TopCand.isValid() || TopCand.SU->isScheduled ||
409 TopCand.Policy != TopPolicy) {
412 /*IsBottomUp=*/false);
413 assert(TopCand.Reason != NoCand && "failed to find the first candidate");
414 } else {
416#ifndef NDEBUG
417 if (VerifyScheduling) {
418 SchedCandidate TCand;
419 TCand.reset(CandPolicy());
420 pickNodeFromQueue(Top, TopPolicy, DAG->getTopRPTracker(), TCand,
421 /*IsBottomUp=*/false);
422 assert(TCand.SU == TopCand.SU &&
423 "Last pick result should correspond to re-picking right now");
424 }
425#endif
426 }
427
428 // Pick best from BotCand and TopCand.
429 LLVM_DEBUG(dbgs() << "Top Cand: "; traceCandidate(TopCand);
430 dbgs() << "Bot Cand: "; traceCandidate(BotCand););
431 SchedCandidate Cand = BotCand;
433 tryCandidate(Cand, TopCand, nullptr);
434 if (TopCand.Reason != NoCand) {
435 Cand.setBest(TopCand);
436 }
437 LLVM_DEBUG(dbgs() << "Picking: "; traceCandidate(Cand););
438
439 IsTopNode = Cand.AtTop;
440 return Cand.SU;
441}
442
443// This function is mostly cut and pasted from
444// GenericScheduler::pickNode()
446 if (DAG->top() == DAG->bottom()) {
448 Bot.Available.empty() && Bot.Pending.empty() && "ReadyQ garbage");
449 return nullptr;
450 }
451 SUnit *SU;
452 do {
454 SU = Top.pickOnlyChoice();
455 if (!SU) {
456 CandPolicy NoPolicy;
457 TopCand.reset(NoPolicy);
459 /*IsBottomUp=*/false);
460 assert(TopCand.Reason != NoCand && "failed to find a candidate");
461 SU = TopCand.SU;
462 }
463 IsTopNode = true;
464 } else if (RegionPolicy.OnlyBottomUp) {
465 SU = Bot.pickOnlyChoice();
466 if (!SU) {
467 CandPolicy NoPolicy;
468 BotCand.reset(NoPolicy);
470 /*IsBottomUp=*/true);
471 assert(BotCand.Reason != NoCand && "failed to find a candidate");
472 SU = BotCand.SU;
473 }
474 IsTopNode = false;
475 } else {
476 SU = pickNodeBidirectional(IsTopNode);
477 }
478 } while (SU->isScheduled);
479
480 if (SU->isTopReady())
481 Top.removeReady(SU);
482 if (SU->isBottomReady())
483 Bot.removeReady(SU);
484
485 LLVM_DEBUG(dbgs() << "Scheduling SU(" << SU->NodeNum << ") "
486 << *SU->getInstr());
487 return SU;
488}
489
490void GCNSchedStrategy::schedNode(SUnit *SU, bool IsTopNode) {
491 if (GCNTrackers) {
492 MachineInstr *MI = SU->getInstr();
493 IsTopNode ? (void)DownwardTracker.advance(MI, false)
495 }
496
497 return GenericScheduler::schedNode(SU, IsTopNode);
498}
499
502 return *CurrentStage;
503}
504
507 if (!CurrentStage)
509 else
510 CurrentStage++;
511
512 return CurrentStage != SchedStages.end();
513}
514
517 return std::next(CurrentStage) != SchedStages.end();
518}
519
521 assert(CurrentStage && std::next(CurrentStage) != SchedStages.end());
522 return *std::next(CurrentStage);
523}
524
526 const MachineSchedContext *C, bool IsLegacyScheduler)
532 GCNTrackers = GCNTrackers & !IsLegacyScheduler;
533}
534
538}
539
541 SchedCandidate &TryCand,
542 SchedBoundary *Zone) const {
543 // Initialize the candidate if needed.
544 if (!Cand.isValid()) {
545 TryCand.Reason = NodeOrder;
546 return true;
547 }
548
549 // Avoid spilling by exceeding the register limit.
550 if (DAG->isTrackingPressure() &&
551 tryPressure(TryCand.RPDelta.Excess, Cand.RPDelta.Excess, TryCand, Cand,
552 RegExcess, TRI, DAG->MF))
553 return TryCand.Reason != NoCand;
554
555 // Bias PhysReg Defs and copies to their uses and defined respectively.
556 if (tryGreater(biasPhysReg(TryCand.SU, TryCand.AtTop),
557 biasPhysReg(Cand.SU, Cand.AtTop), TryCand, Cand, PhysReg))
558 return TryCand.Reason != NoCand;
559
560 bool SameBoundary = Zone != nullptr;
561 if (SameBoundary) {
562 // Prioritize instructions that read unbuffered resources by stall cycles.
563 if (tryLess(Zone->getLatencyStallCycles(TryCand.SU),
564 Zone->getLatencyStallCycles(Cand.SU), TryCand, Cand, Stall))
565 return TryCand.Reason != NoCand;
566
567 // Avoid critical resource consumption and balance the schedule.
570 TryCand, Cand, ResourceReduce))
571 return TryCand.Reason != NoCand;
573 Cand.ResDelta.DemandedResources, TryCand, Cand,
575 return TryCand.Reason != NoCand;
576
577 // Unconditionally try to reduce latency.
578 if (tryLatency(TryCand, Cand, *Zone))
579 return TryCand.Reason != NoCand;
580
581 // Weak edges are for clustering and other constraints.
582 if (tryLess(getWeakLeft(TryCand.SU, TryCand.AtTop),
583 getWeakLeft(Cand.SU, Cand.AtTop), TryCand, Cand, Weak))
584 return TryCand.Reason != NoCand;
585 }
586
587 // Keep clustered nodes together to encourage downstream peephole
588 // optimizations which may reduce resource requirements.
589 //
590 // This is a best effort to set things up for a post-RA pass. Optimizations
591 // like generating loads of multiple registers should ideally be done within
592 // the scheduler pass by combining the loads during DAG postprocessing.
593 const SUnit *CandNextClusterSU =
595 const SUnit *TryCandNextClusterSU =
597 if (tryGreater(TryCand.SU == TryCandNextClusterSU,
598 Cand.SU == CandNextClusterSU, TryCand, Cand, Cluster))
599 return TryCand.Reason != NoCand;
600
601 // Avoid increasing the max critical pressure in the scheduled region.
602 if (DAG->isTrackingPressure() &&
604 TryCand, Cand, RegCritical, TRI, DAG->MF))
605 return TryCand.Reason != NoCand;
606
607 // Avoid increasing the max pressure of the entire region.
608 if (DAG->isTrackingPressure() &&
609 tryPressure(TryCand.RPDelta.CurrentMax, Cand.RPDelta.CurrentMax, TryCand,
610 Cand, RegMax, TRI, DAG->MF))
611 return TryCand.Reason != NoCand;
612
613 if (SameBoundary) {
614 // Fall through to original instruction order.
615 if ((Zone->isTop() && TryCand.SU->NodeNum < Cand.SU->NodeNum) ||
616 (!Zone->isTop() && TryCand.SU->NodeNum > Cand.SU->NodeNum)) {
617 TryCand.Reason = NodeOrder;
618 return true;
619 }
620 }
621 return false;
622}
623
625 const MachineSchedContext *C)
628}
629
630/// GCNMaxMemoryClauseSchedStrategy tries best to clause memory instructions as
631/// much as possible. This is achieved by:
632// 1. Prioritize clustered operations before stall latency heuristic.
633// 2. Prioritize long-latency-load before stall latency heuristic.
634///
635/// \param Cand provides the policy and current best candidate.
636/// \param TryCand refers to the next SUnit candidate, otherwise uninitialized.
637/// \param Zone describes the scheduled zone that we are extending, or nullptr
638/// if Cand is from a different zone than TryCand.
639/// \return \c true if TryCand is better than Cand (Reason is NOT NoCand)
641 SchedCandidate &TryCand,
642 SchedBoundary *Zone) const {
643 // Initialize the candidate if needed.
644 if (!Cand.isValid()) {
645 TryCand.Reason = NodeOrder;
646 return true;
647 }
648
649 // Bias PhysReg Defs and copies to their uses and defined respectively.
650 if (tryGreater(biasPhysReg(TryCand.SU, TryCand.AtTop),
651 biasPhysReg(Cand.SU, Cand.AtTop), TryCand, Cand, PhysReg))
652 return TryCand.Reason != NoCand;
653
654 if (DAG->isTrackingPressure()) {
655 // Avoid exceeding the target's limit.
656 if (tryPressure(TryCand.RPDelta.Excess, Cand.RPDelta.Excess, TryCand, Cand,
657 RegExcess, TRI, DAG->MF))
658 return TryCand.Reason != NoCand;
659
660 // Avoid increasing the max critical pressure in the scheduled region.
662 TryCand, Cand, RegCritical, TRI, DAG->MF))
663 return TryCand.Reason != NoCand;
664 }
665
666 // MaxMemoryClause-specific: We prioritize clustered instructions as we would
667 // get more benefit from clausing these memory instructions.
668 const SUnit *CandNextClusterSU =
670 const SUnit *TryCandNextClusterSU =
672 if (tryGreater(TryCand.SU == TryCandNextClusterSU,
673 Cand.SU == CandNextClusterSU, TryCand, Cand, Cluster))
674 return TryCand.Reason != NoCand;
675
676 // We only compare a subset of features when comparing nodes between
677 // Top and Bottom boundary. Some properties are simply incomparable, in many
678 // other instances we should only override the other boundary if something
679 // is a clear good pick on one boundary. Skip heuristics that are more
680 // "tie-breaking" in nature.
681 bool SameBoundary = Zone != nullptr;
682 if (SameBoundary) {
683 // For loops that are acyclic path limited, aggressively schedule for
684 // latency. Within an single cycle, whenever CurrMOps > 0, allow normal
685 // heuristics to take precedence.
686 if (Rem.IsAcyclicLatencyLimited && !Zone->getCurrMOps() &&
687 tryLatency(TryCand, Cand, *Zone))
688 return TryCand.Reason != NoCand;
689
690 // MaxMemoryClause-specific: Prioritize long latency memory load
691 // instructions in top-bottom order to hide more latency. The mayLoad check
692 // is used to exclude store-like instructions, which we do not want to
693 // scheduler them too early.
694 bool TryMayLoad =
695 TryCand.SU->isInstr() && TryCand.SU->getInstr()->mayLoad();
696 bool CandMayLoad = Cand.SU->isInstr() && Cand.SU->getInstr()->mayLoad();
697
698 if (TryMayLoad || CandMayLoad) {
699 bool TryLongLatency =
700 TryCand.SU->Latency > 10 * Cand.SU->Latency && TryMayLoad;
701 bool CandLongLatency =
702 10 * TryCand.SU->Latency < Cand.SU->Latency && CandMayLoad;
703
704 if (tryGreater(Zone->isTop() ? TryLongLatency : CandLongLatency,
705 Zone->isTop() ? CandLongLatency : TryLongLatency, TryCand,
706 Cand, Stall))
707 return TryCand.Reason != NoCand;
708 }
709 // Prioritize instructions that read unbuffered resources by stall cycles.
710 if (tryLess(Zone->getLatencyStallCycles(TryCand.SU),
711 Zone->getLatencyStallCycles(Cand.SU), TryCand, Cand, Stall))
712 return TryCand.Reason != NoCand;
713 }
714
715 if (SameBoundary) {
716 // Weak edges are for clustering and other constraints.
717 if (tryLess(getWeakLeft(TryCand.SU, TryCand.AtTop),
718 getWeakLeft(Cand.SU, Cand.AtTop), TryCand, Cand, Weak))
719 return TryCand.Reason != NoCand;
720 }
721
722 // Avoid increasing the max pressure of the entire region.
723 if (DAG->isTrackingPressure() &&
724 tryPressure(TryCand.RPDelta.CurrentMax, Cand.RPDelta.CurrentMax, TryCand,
725 Cand, RegMax, TRI, DAG->MF))
726 return TryCand.Reason != NoCand;
727
728 if (SameBoundary) {
729 // Avoid critical resource consumption and balance the schedule.
732 TryCand, Cand, ResourceReduce))
733 return TryCand.Reason != NoCand;
735 Cand.ResDelta.DemandedResources, TryCand, Cand,
737 return TryCand.Reason != NoCand;
738
739 // Avoid serializing long latency dependence chains.
740 // For acyclic path limited loops, latency was already checked above.
742 !Rem.IsAcyclicLatencyLimited && tryLatency(TryCand, Cand, *Zone))
743 return TryCand.Reason != NoCand;
744
745 // Fall through to original instruction order.
746 if (Zone->isTop() == (TryCand.SU->NodeNum < Cand.SU->NodeNum)) {
747 assert(TryCand.SU->NodeNum != Cand.SU->NodeNum);
748 TryCand.Reason = NodeOrder;
749 return true;
750 }
751 }
752
753 return false;
754}
755
757 MachineSchedContext *C, std::unique_ptr<MachineSchedStrategy> S)
758 : ScheduleDAGMILive(C, std::move(S)), ST(MF.getSubtarget<GCNSubtarget>()),
759 MFI(*MF.getInfo<SIMachineFunctionInfo>()),
760 StartingOccupancy(MFI.getOccupancy()), MinOccupancy(StartingOccupancy),
761 RegionLiveOuts(this, /*IsLiveOut=*/true) {
762
763 LLVM_DEBUG(dbgs() << "Starting occupancy is " << StartingOccupancy << ".\n");
764 if (RelaxedOcc) {
765 MinOccupancy = std::min(MFI.getMinAllowedOccupancy(), StartingOccupancy);
766 if (MinOccupancy != StartingOccupancy)
767 LLVM_DEBUG(dbgs() << "Allowing Occupancy drops to " << MinOccupancy
768 << ".\n");
769 }
770}
771
772std::unique_ptr<GCNSchedStage>
773GCNScheduleDAGMILive::createSchedStage(GCNSchedStageID SchedStageID) {
774 switch (SchedStageID) {
776 return std::make_unique<OccInitialScheduleStage>(SchedStageID, *this);
778 return std::make_unique<UnclusteredHighRPStage>(SchedStageID, *this);
780 return std::make_unique<ClusteredLowOccStage>(SchedStageID, *this);
782 return std::make_unique<PreRARematStage>(SchedStageID, *this);
784 return std::make_unique<ILPInitialScheduleStage>(SchedStageID, *this);
786 return std::make_unique<MemoryClauseInitialScheduleStage>(SchedStageID,
787 *this);
788 }
789
790 llvm_unreachable("Unknown SchedStageID.");
791}
792
794 // Collect all scheduling regions. The actual scheduling is performed in
795 // GCNScheduleDAGMILive::finalizeSchedule.
796 Regions.push_back(std::pair(RegionBegin, RegionEnd));
797}
798
800GCNScheduleDAGMILive::getRealRegPressure(unsigned RegionIdx) const {
802 RPTracker.advance(begin(), end(), &LiveIns[RegionIdx]);
803 return RPTracker.moveMaxPressure();
804}
805
807 MachineBasicBlock::iterator RegionEnd) {
808 auto REnd = RegionEnd == RegionBegin->getParent()->end()
809 ? std::prev(RegionEnd)
810 : RegionEnd;
811 return &*skipDebugInstructionsBackward(REnd, RegionBegin);
812}
813
814void GCNScheduleDAGMILive::computeBlockPressure(unsigned RegionIdx,
815 const MachineBasicBlock *MBB) {
817
818 // If the block has the only successor then live-ins of that successor are
819 // live-outs of the current block. We can reuse calculated live set if the
820 // successor will be sent to scheduling past current block.
821
822 // However, due to the bug in LiveInterval analysis it may happen that two
823 // predecessors of the same successor block have different lane bitmasks for
824 // a live-out register. Workaround that by sticking to one-to-one relationship
825 // i.e. one predecessor with one successor block.
826 const MachineBasicBlock *OnlySucc = nullptr;
827 if (MBB->succ_size() == 1) {
828 auto *Candidate = *MBB->succ_begin();
829 if (!Candidate->empty() && Candidate->pred_size() == 1) {
831 if (Ind->getMBBStartIdx(MBB) < Ind->getMBBStartIdx(Candidate))
832 OnlySucc = Candidate;
833 }
834 }
835
836 // Scheduler sends regions from the end of the block upwards.
837 size_t CurRegion = RegionIdx;
838 for (size_t E = Regions.size(); CurRegion != E; ++CurRegion)
839 if (Regions[CurRegion].first->getParent() != MBB)
840 break;
841 --CurRegion;
842
843 auto I = MBB->begin();
844 auto LiveInIt = MBBLiveIns.find(MBB);
845 auto &Rgn = Regions[CurRegion];
846 auto *NonDbgMI = &*skipDebugInstructionsForward(Rgn.first, Rgn.second);
847 if (LiveInIt != MBBLiveIns.end()) {
848 auto LiveIn = std::move(LiveInIt->second);
849 RPTracker.reset(*MBB->begin(), &LiveIn);
850 MBBLiveIns.erase(LiveInIt);
851 } else {
852 I = Rgn.first;
853 auto LRS = BBLiveInMap.lookup(NonDbgMI);
854#ifdef EXPENSIVE_CHECKS
855 assert(isEqual(getLiveRegsBefore(*NonDbgMI, *LIS), LRS));
856#endif
857 RPTracker.reset(*I, &LRS);
858 }
859
860 for (;;) {
861 I = RPTracker.getNext();
862
863 if (Regions[CurRegion].first == I || NonDbgMI == I) {
864 LiveIns[CurRegion] = RPTracker.getLiveRegs();
865 RPTracker.clearMaxPressure();
866 }
867
868 if (Regions[CurRegion].second == I) {
869 Pressure[CurRegion] = RPTracker.moveMaxPressure();
870 if (CurRegion-- == RegionIdx)
871 break;
872 }
873 RPTracker.advanceToNext();
874 RPTracker.advanceBeforeNext();
875 }
876
877 if (OnlySucc) {
878 if (I != MBB->end()) {
879 RPTracker.advanceToNext();
881 }
882 RPTracker.advanceBeforeNext();
883 MBBLiveIns[OnlySucc] = RPTracker.moveLiveRegs();
884 }
885}
886
888GCNScheduleDAGMILive::getRegionLiveInMap() const {
889 assert(!Regions.empty());
890 std::vector<MachineInstr *> RegionFirstMIs;
891 RegionFirstMIs.reserve(Regions.size());
892 auto I = Regions.rbegin(), E = Regions.rend();
893 auto *BB = I->first->getParent();
894 do {
895 auto *MI = &*skipDebugInstructionsForward(I->first, I->second);
896 RegionFirstMIs.push_back(MI);
897 do {
898 ++I;
899 } while (I != E && I->first->getParent() == BB);
900 } while (I != E);
901 return getLiveRegMap(RegionFirstMIs, /*After=*/false, *LIS);
902}
903
905GCNScheduleDAGMILive::getRegionLiveOutMap() const {
906 assert(!Regions.empty());
907 std::vector<MachineInstr *> RegionLastMIs;
908 RegionLastMIs.reserve(Regions.size());
909 for (auto &[RegionBegin, RegionEnd] : reverse(Regions))
910 RegionLastMIs.push_back(getLastMIForRegion(RegionBegin, RegionEnd));
911
912 return getLiveRegMap(RegionLastMIs, /*After=*/true, *LIS);
913}
914
916 IdxToInstruction.clear();
917
918 RegionLiveRegMap =
919 IsLiveOut ? DAG->getRegionLiveOutMap() : DAG->getRegionLiveInMap();
920 for (unsigned I = 0; I < DAG->Regions.size(); I++) {
921 MachineInstr *RegionKey =
922 IsLiveOut
923 ? getLastMIForRegion(DAG->Regions[I].first, DAG->Regions[I].second)
924 : &*DAG->Regions[I].first;
925 IdxToInstruction[I] = RegionKey;
926 }
927}
928
930 // Start actual scheduling here. This function is called by the base
931 // MachineScheduler after all regions have been recorded by
932 // GCNScheduleDAGMILive::schedule().
933 LiveIns.resize(Regions.size());
934 Pressure.resize(Regions.size());
935 RescheduleRegions.resize(Regions.size());
936 RegionsWithHighRP.resize(Regions.size());
937 RegionsWithExcessRP.resize(Regions.size());
938 RegionsWithMinOcc.resize(Regions.size());
939 RegionsWithIGLPInstrs.resize(Regions.size());
940 RescheduleRegions.set();
941 RegionsWithHighRP.reset();
942 RegionsWithExcessRP.reset();
943 RegionsWithMinOcc.reset();
944 RegionsWithIGLPInstrs.reset();
945
946 runSchedStages();
947}
948
949void GCNScheduleDAGMILive::runSchedStages() {
950 LLVM_DEBUG(dbgs() << "All regions recorded, starting actual scheduling.\n");
951
952 if (!Regions.empty()) {
953 BBLiveInMap = getRegionLiveInMap();
954 if (GCNTrackers)
955 RegionLiveOuts.buildLiveRegMap();
956 }
957
958 GCNSchedStrategy &S = static_cast<GCNSchedStrategy &>(*SchedImpl);
959 while (S.advanceStage()) {
960 auto Stage = createSchedStage(S.getCurrentStage());
961 if (!Stage->initGCNSchedStage())
962 continue;
963
964 for (auto Region : Regions) {
965 RegionBegin = Region.first;
966 RegionEnd = Region.second;
967 // Setup for scheduling the region and check whether it should be skipped.
968 if (!Stage->initGCNRegion()) {
969 Stage->advanceRegion();
970 exitRegion();
971 continue;
972 }
973
974 if (GCNTrackers) {
975 GCNDownwardRPTracker *DownwardTracker = S.getDownwardTracker();
976 GCNUpwardRPTracker *UpwardTracker = S.getUpwardTracker();
977 GCNRPTracker::LiveRegSet *RegionLiveIns =
978 &LiveIns[Stage->getRegionIdx()];
979
980 reinterpret_cast<GCNRPTracker *>(DownwardTracker)
981 ->reset(MRI, *RegionLiveIns);
982 reinterpret_cast<GCNRPTracker *>(UpwardTracker)
983 ->reset(MRI, RegionLiveOuts.getLiveRegsForRegionIdx(
984 Stage->getRegionIdx()));
985 }
986
988 Stage->finalizeGCNRegion();
989 }
990
991 Stage->finalizeGCNSchedStage();
992 }
993}
994
995#ifndef NDEBUG
997 switch (StageID) {
999 OS << "Max Occupancy Initial Schedule";
1000 break;
1002 OS << "Unclustered High Register Pressure Reschedule";
1003 break;
1005 OS << "Clustered Low Occupancy Reschedule";
1006 break;
1008 OS << "Pre-RA Rematerialize";
1009 break;
1011 OS << "Max ILP Initial Schedule";
1012 break;
1014 OS << "Max memory clause Initial Schedule";
1015 break;
1016 }
1017
1018 return OS;
1019}
1020#endif
1021
1023 : DAG(DAG), S(static_cast<GCNSchedStrategy &>(*DAG.SchedImpl)), MF(DAG.MF),
1024 MFI(DAG.MFI), ST(DAG.ST), StageID(StageID) {}
1025
1027 if (!DAG.LIS)
1028 return false;
1029
1030 LLVM_DEBUG(dbgs() << "Starting scheduling stage: " << StageID << "\n");
1031 return true;
1032}
1033
1036 return false;
1037
1039 return false;
1040
1041 if (DAG.RegionsWithHighRP.none() && DAG.RegionsWithExcessRP.none())
1042 return false;
1043
1047
1048 InitialOccupancy = DAG.MinOccupancy;
1049 // Aggressivly try to reduce register pressure in the unclustered high RP
1050 // stage. Temporarily increase occupancy target in the region.
1053 if (MFI.getMaxWavesPerEU() > DAG.MinOccupancy)
1054 MFI.increaseOccupancy(MF, ++DAG.MinOccupancy);
1055
1056 LLVM_DEBUG(
1057 dbgs()
1058 << "Retrying function scheduling without clustering. "
1059 "Aggressivly try to reduce register pressure to achieve occupancy "
1060 << DAG.MinOccupancy << ".\n");
1061
1062 return true;
1063}
1064
1067 return false;
1068
1070 return false;
1071
1072 // Don't bother trying to improve ILP in lower RP regions if occupancy has not
1073 // been dropped. All regions will have already been scheduled with the ideal
1074 // occupancy targets.
1075 if (DAG.StartingOccupancy <= DAG.MinOccupancy)
1076 return false;
1077
1078 LLVM_DEBUG(
1079 dbgs() << "Retrying function scheduling with lowest recorded occupancy "
1080 << DAG.MinOccupancy << ".\n");
1081 return true;
1082}
1083
1086 return false;
1087
1088 if (DAG.RegionsWithMinOcc.none() || DAG.Regions.size() == 1)
1089 return false;
1090
1092 // Check maximum occupancy
1094 DAG.MinOccupancy)
1095 return false;
1096
1097 // FIXME: This pass will invalidate cached MBBLiveIns for regions
1098 // inbetween the defs and region we sinked the def to. Cached pressure
1099 // for regions where a def is sinked from will also be invalidated. Will
1100 // need to be fixed if there is another pass after this pass.
1101 assert(!S.hasNextStage());
1102
1103 collectRematerializableInstructions();
1104 if (RematerializableInsts.empty() || !sinkTriviallyRematInsts(ST, TII))
1105 return false;
1106
1107 LLVM_DEBUG(
1108 dbgs() << "Retrying function scheduling with improved occupancy of "
1109 << DAG.MinOccupancy << " from rematerializing\n");
1110 return true;
1111}
1112
1114 DAG.finishBlock();
1115 LLVM_DEBUG(dbgs() << "Ending scheduling stage: " << StageID << "\n");
1116}
1117
1121 if (DAG.MinOccupancy > InitialOccupancy) {
1122 for (unsigned IDX = 0; IDX < DAG.Pressure.size(); ++IDX)
1123 DAG.RegionsWithMinOcc[IDX] =
1124 DAG.Pressure[IDX].getOccupancy(DAG.ST) == DAG.MinOccupancy;
1125
1127 << " stage successfully increased occupancy to "
1128 << DAG.MinOccupancy << '\n');
1129 }
1130
1132}
1133
1135 // Check whether this new region is also a new block.
1136 if (DAG.RegionBegin->getParent() != CurrentMBB)
1137 setupNewBlock();
1138
1139 unsigned NumRegionInstrs = std::distance(DAG.begin(), DAG.end());
1140 DAG.enterRegion(CurrentMBB, DAG.begin(), DAG.end(), NumRegionInstrs);
1141
1142 // Skip empty scheduling regions (0 or 1 schedulable instructions).
1143 if (DAG.begin() == DAG.end() || DAG.begin() == std::prev(DAG.end()))
1144 return false;
1145
1146 LLVM_DEBUG(dbgs() << "********** MI Scheduling **********\n");
1148 << " " << CurrentMBB->getName()
1149 << "\n From: " << *DAG.begin() << " To: ";
1151 else dbgs() << "End";
1152 dbgs() << " RegionInstrs: " << NumRegionInstrs << '\n');
1153
1154 // Save original instruction order before scheduling for possible revert.
1155 Unsched.clear();
1156 Unsched.reserve(DAG.NumRegionInstrs);
1159 for (auto &I : DAG) {
1160 Unsched.push_back(&I);
1161 if (isIGLPMutationOnly(I.getOpcode()))
1162 DAG.RegionsWithIGLPInstrs[RegionIdx] = true;
1163 }
1164 } else {
1165 for (auto &I : DAG)
1166 Unsched.push_back(&I);
1167 }
1168
1169 PressureBefore = DAG.Pressure[RegionIdx];
1170
1171 LLVM_DEBUG(
1172 dbgs() << "Pressure before scheduling:\nRegion live-ins:"
1173 << print(DAG.LiveIns[RegionIdx], DAG.MRI)
1174 << "Region live-in pressure: "
1176 << "Region register pressure: " << print(PressureBefore));
1177
1178 S.HasHighPressure = false;
1180
1181 if (DAG.RegionsWithIGLPInstrs[RegionIdx] &&
1183 SavedMutations.clear();
1185 bool IsInitialStage = StageID == GCNSchedStageID::OccInitialSchedule ||
1188 IsInitialStage ? AMDGPU::SchedulingPhase::Initial
1190 }
1191
1192 return true;
1193}
1194
1196 // Only reschedule regions with the minimum occupancy or regions that may have
1197 // spilling (excess register pressure).
1198 if ((!DAG.RegionsWithMinOcc[RegionIdx] ||
1199 DAG.MinOccupancy <= InitialOccupancy) &&
1200 !DAG.RegionsWithExcessRP[RegionIdx])
1201 return false;
1202
1204}
1205
1207 // We may need to reschedule this region if it wasn't rescheduled in the last
1208 // stage, or if we found it was testing critical register pressure limits in
1209 // the unclustered reschedule stage. The later is because we may not have been
1210 // able to raise the min occupancy in the previous stage so the region may be
1211 // overly constrained even if it was already rescheduled.
1212 if (!DAG.RegionsWithHighRP[RegionIdx])
1213 return false;
1214
1216}
1217
1219 if (!DAG.RescheduleRegions[RegionIdx])
1220 return false;
1221
1223}
1224
1226 if (CurrentMBB)
1227 DAG.finishBlock();
1228
1229 CurrentMBB = DAG.RegionBegin->getParent();
1231 // Get real RP for the region if it hasn't be calculated before. After the
1232 // initial schedule stage real RP will be collected after scheduling.
1236 DAG.computeBlockPressure(RegionIdx, CurrentMBB);
1237}
1238
1240 DAG.Regions[RegionIdx] = std::pair(DAG.RegionBegin, DAG.RegionEnd);
1241 DAG.RescheduleRegions[RegionIdx] = false;
1242 if (S.HasHighPressure)
1243 DAG.RegionsWithHighRP[RegionIdx] = true;
1244
1245 // Revert scheduling if we have dropped occupancy or there is some other
1246 // reason that the original schedule is better.
1248
1249 if (DAG.RegionsWithIGLPInstrs[RegionIdx] &&
1252
1253 DAG.exitRegion();
1254 RegionIdx++;
1255}
1256
1258 // Check the results of scheduling.
1259 PressureAfter = DAG.getRealRegPressure(RegionIdx);
1260
1261 LLVM_DEBUG(dbgs() << "Pressure after scheduling: " << print(PressureAfter));
1262 LLVM_DEBUG(dbgs() << "Region: " << RegionIdx << ".\n");
1263
1266 DAG.Pressure[RegionIdx] = PressureAfter;
1267 DAG.RegionsWithMinOcc[RegionIdx] =
1268 PressureAfter.getOccupancy(ST) == DAG.MinOccupancy;
1269
1270 // Early out if we have achieved the occupancy target.
1271 LLVM_DEBUG(dbgs() << "Pressure in desired limits, done.\n");
1272 return;
1273 }
1274
1275 unsigned TargetOccupancy =
1277 unsigned WavesAfter =
1278 std::min(TargetOccupancy, PressureAfter.getOccupancy(ST));
1279 unsigned WavesBefore =
1280 std::min(TargetOccupancy, PressureBefore.getOccupancy(ST));
1281 LLVM_DEBUG(dbgs() << "Occupancy before scheduling: " << WavesBefore
1282 << ", after " << WavesAfter << ".\n");
1283
1284 // We may not be able to keep the current target occupancy because of the just
1285 // scheduled region. We might still be able to revert scheduling if the
1286 // occupancy before was higher, or if the current schedule has register
1287 // pressure higher than the excess limits which could lead to more spilling.
1288 unsigned NewOccupancy = std::max(WavesAfter, WavesBefore);
1289
1290 // Allow memory bound functions to drop to 4 waves if not limited by an
1291 // attribute.
1292 if (WavesAfter < WavesBefore && WavesAfter < DAG.MinOccupancy &&
1293 WavesAfter >= MFI.getMinAllowedOccupancy()) {
1294 LLVM_DEBUG(dbgs() << "Function is memory bound, allow occupancy drop up to "
1295 << MFI.getMinAllowedOccupancy() << " waves\n");
1296 NewOccupancy = WavesAfter;
1297 }
1298
1299 if (NewOccupancy < DAG.MinOccupancy) {
1300 DAG.MinOccupancy = NewOccupancy;
1301 MFI.limitOccupancy(DAG.MinOccupancy);
1302 DAG.RegionsWithMinOcc.reset();
1303 LLVM_DEBUG(dbgs() << "Occupancy lowered for the function to "
1304 << DAG.MinOccupancy << ".\n");
1305 }
1306 // The maximum number of arch VGPR on non-unified register file, or the
1307 // maximum VGPR + AGPR in the unified register file case.
1308 unsigned MaxVGPRs = ST.getMaxNumVGPRs(MF);
1309 // The maximum number of arch VGPR for both unified and non-unified register
1310 // file.
1311 unsigned MaxArchVGPRs = std::min(MaxVGPRs, ST.getAddressableNumArchVGPRs());
1312 unsigned MaxSGPRs = ST.getMaxNumSGPRs(MF);
1313
1314 if (PressureAfter.getVGPRNum(ST.hasGFX90AInsts()) > MaxVGPRs ||
1315 PressureAfter.getVGPRNum(false) > MaxArchVGPRs ||
1316 PressureAfter.getAGPRNum() > MaxArchVGPRs ||
1317 PressureAfter.getSGPRNum() > MaxSGPRs) {
1318 DAG.RescheduleRegions[RegionIdx] = true;
1319 DAG.RegionsWithHighRP[RegionIdx] = true;
1320 DAG.RegionsWithExcessRP[RegionIdx] = true;
1321 }
1322
1323 // Revert if this region's schedule would cause a drop in occupancy or
1324 // spilling.
1325 if (shouldRevertScheduling(WavesAfter)) {
1327 } else {
1328 DAG.Pressure[RegionIdx] = PressureAfter;
1329 DAG.RegionsWithMinOcc[RegionIdx] =
1330 PressureAfter.getOccupancy(ST) == DAG.MinOccupancy;
1331 }
1332}
1333
1334unsigned
1335GCNSchedStage::computeSUnitReadyCycle(const SUnit &SU, unsigned CurrCycle,
1336 DenseMap<unsigned, unsigned> &ReadyCycles,
1337 const TargetSchedModel &SM) {
1338 unsigned ReadyCycle = CurrCycle;
1339 for (auto &D : SU.Preds) {
1340 if (D.isAssignedRegDep()) {
1341 MachineInstr *DefMI = D.getSUnit()->getInstr();
1342 unsigned Latency = SM.computeInstrLatency(DefMI);
1343 unsigned DefReady = ReadyCycles[DAG.getSUnit(DefMI)->NodeNum];
1344 ReadyCycle = std::max(ReadyCycle, DefReady + Latency);
1345 }
1346 }
1347 ReadyCycles[SU.NodeNum] = ReadyCycle;
1348 return ReadyCycle;
1349}
1350
1351#ifndef NDEBUG
1353 bool operator()(std::pair<MachineInstr *, unsigned> A,
1354 std::pair<MachineInstr *, unsigned> B) const {
1355 return A.second < B.second;
1356 }
1357};
1358
1359static void printScheduleModel(std::set<std::pair<MachineInstr *, unsigned>,
1360 EarlierIssuingCycle> &ReadyCycles) {
1361 if (ReadyCycles.empty())
1362 return;
1363 unsigned BBNum = ReadyCycles.begin()->first->getParent()->getNumber();
1364 dbgs() << "\n################## Schedule time ReadyCycles for MBB : " << BBNum
1365 << " ##################\n# Cycle #\t\t\tInstruction "
1366 " "
1367 " \n";
1368 unsigned IPrev = 1;
1369 for (auto &I : ReadyCycles) {
1370 if (I.second > IPrev + 1)
1371 dbgs() << "****************************** BUBBLE OF " << I.second - IPrev
1372 << " CYCLES DETECTED ******************************\n\n";
1373 dbgs() << "[ " << I.second << " ] : " << *I.first << "\n";
1374 IPrev = I.second;
1375 }
1376}
1377#endif
1378
1380GCNSchedStage::getScheduleMetrics(const std::vector<SUnit> &InputSchedule) {
1381#ifndef NDEBUG
1382 std::set<std::pair<MachineInstr *, unsigned>, EarlierIssuingCycle>
1383 ReadyCyclesSorted;
1384#endif
1386 unsigned SumBubbles = 0;
1387 DenseMap<unsigned, unsigned> ReadyCycles;
1388 unsigned CurrCycle = 0;
1389 for (auto &SU : InputSchedule) {
1390 unsigned ReadyCycle =
1391 computeSUnitReadyCycle(SU, CurrCycle, ReadyCycles, SM);
1392 SumBubbles += ReadyCycle - CurrCycle;
1393#ifndef NDEBUG
1394 ReadyCyclesSorted.insert(std::make_pair(SU.getInstr(), ReadyCycle));
1395#endif
1396 CurrCycle = ++ReadyCycle;
1397 }
1398#ifndef NDEBUG
1399 LLVM_DEBUG(
1400 printScheduleModel(ReadyCyclesSorted);
1401 dbgs() << "\n\t"
1402 << "Metric: "
1403 << (SumBubbles
1404 ? (SumBubbles * ScheduleMetrics::ScaleFactor) / CurrCycle
1405 : 1)
1406 << "\n\n");
1407#endif
1408
1409 return ScheduleMetrics(CurrCycle, SumBubbles);
1410}
1411
1414#ifndef NDEBUG
1415 std::set<std::pair<MachineInstr *, unsigned>, EarlierIssuingCycle>
1416 ReadyCyclesSorted;
1417#endif
1419 unsigned SumBubbles = 0;
1420 DenseMap<unsigned, unsigned> ReadyCycles;
1421 unsigned CurrCycle = 0;
1422 for (auto &MI : DAG) {
1423 SUnit *SU = DAG.getSUnit(&MI);
1424 if (!SU)
1425 continue;
1426 unsigned ReadyCycle =
1427 computeSUnitReadyCycle(*SU, CurrCycle, ReadyCycles, SM);
1428 SumBubbles += ReadyCycle - CurrCycle;
1429#ifndef NDEBUG
1430 ReadyCyclesSorted.insert(std::make_pair(SU->getInstr(), ReadyCycle));
1431#endif
1432 CurrCycle = ++ReadyCycle;
1433 }
1434#ifndef NDEBUG
1435 LLVM_DEBUG(
1436 printScheduleModel(ReadyCyclesSorted);
1437 dbgs() << "\n\t"
1438 << "Metric: "
1439 << (SumBubbles
1440 ? (SumBubbles * ScheduleMetrics::ScaleFactor) / CurrCycle
1441 : 1)
1442 << "\n\n");
1443#endif
1444
1445 return ScheduleMetrics(CurrCycle, SumBubbles);
1446}
1447
1448bool GCNSchedStage::shouldRevertScheduling(unsigned WavesAfter) {
1449 if (WavesAfter < DAG.MinOccupancy)
1450 return true;
1451
1452 return false;
1453}
1454
1457 return false;
1458
1460 return true;
1461
1462 if (mayCauseSpilling(WavesAfter))
1463 return true;
1464
1465 return false;
1466}
1467
1469 // If RP is not reduced in the unclustered reschedule stage, revert to the
1470 // old schedule.
1471 if ((WavesAfter <= PressureBefore.getOccupancy(ST) &&
1472 mayCauseSpilling(WavesAfter)) ||
1474 LLVM_DEBUG(dbgs() << "Unclustered reschedule did not help.\n");
1475 return true;
1476 }
1477
1478 // Do not attempt to relax schedule even more if we are already spilling.
1480 return false;
1481
1482 LLVM_DEBUG(
1483 dbgs()
1484 << "\n\t *** In shouldRevertScheduling ***\n"
1485 << " *********** BEFORE UnclusteredHighRPStage ***********\n");
1486 ScheduleMetrics MBefore =
1488 LLVM_DEBUG(
1489 dbgs()
1490 << "\n *********** AFTER UnclusteredHighRPStage ***********\n");
1492 unsigned OldMetric = MBefore.getMetric();
1493 unsigned NewMetric = MAfter.getMetric();
1494 unsigned WavesBefore =
1496 unsigned Profit =
1497 ((WavesAfter * ScheduleMetrics::ScaleFactor) / WavesBefore *
1499 NewMetric) /
1501 LLVM_DEBUG(dbgs() << "\tMetric before " << MBefore << "\tMetric after "
1502 << MAfter << "Profit: " << Profit << "\n");
1503 return Profit < ScheduleMetrics::ScaleFactor;
1504}
1505
1508 return false;
1509
1511 return true;
1512
1513 if (mayCauseSpilling(WavesAfter))
1514 return true;
1515
1516 return false;
1517}
1518
1521 return true;
1522
1523 if (mayCauseSpilling(WavesAfter))
1524 return true;
1525
1526 return false;
1527}
1528
1530 if (mayCauseSpilling(WavesAfter))
1531 return true;
1532
1533 return false;
1534}
1535
1537 unsigned WavesAfter) {
1538 return mayCauseSpilling(WavesAfter);
1539}
1540
1541bool GCNSchedStage::mayCauseSpilling(unsigned WavesAfter) {
1542 if (WavesAfter <= MFI.getMinWavesPerEU() && isRegionWithExcessRP() &&
1544 LLVM_DEBUG(dbgs() << "New pressure will result in more spilling.\n");
1545 return true;
1546 }
1547
1548 return false;
1549}
1550
1552 DAG.RegionsWithMinOcc[RegionIdx] =
1553 PressureBefore.getOccupancy(ST) == DAG.MinOccupancy;
1554 LLVM_DEBUG(dbgs() << "Attempting to revert scheduling.\n");
1555 DAG.RescheduleRegions[RegionIdx] =
1556 S.hasNextStage() &&
1559 int SkippedDebugInstr = 0;
1560 for (MachineInstr *MI : Unsched) {
1561 if (MI->isDebugInstr()) {
1562 ++SkippedDebugInstr;
1563 continue;
1564 }
1565
1566 if (MI->getIterator() != DAG.RegionEnd) {
1567 DAG.BB->remove(MI);
1569 if (!MI->isDebugInstr())
1570 DAG.LIS->handleMove(*MI, true);
1571 }
1572
1573 // Reset read-undef flags and update them later.
1574 for (auto &Op : MI->all_defs())
1575 Op.setIsUndef(false);
1576 RegisterOperands RegOpers;
1577 RegOpers.collect(*MI, *DAG.TRI, DAG.MRI, DAG.ShouldTrackLaneMasks, false);
1578 if (!MI->isDebugInstr()) {
1580 // Adjust liveness and add missing dead+read-undef flags.
1582 RegOpers.adjustLaneLiveness(*DAG.LIS, DAG.MRI, SlotIdx, MI);
1583 } else {
1584 // Adjust for missing dead-def flags.
1585 RegOpers.detectDeadDefs(*MI, *DAG.LIS);
1586 }
1587 }
1588 DAG.RegionEnd = MI->getIterator();
1589 ++DAG.RegionEnd;
1590 LLVM_DEBUG(dbgs() << "Scheduling " << *MI);
1591 }
1592
1593 // After reverting schedule, debug instrs will now be at the end of the block
1594 // and RegionEnd will point to the first debug instr. Increment RegionEnd
1595 // pass debug instrs to the actual end of the scheduling region.
1596 while (SkippedDebugInstr-- > 0)
1597 ++DAG.RegionEnd;
1598
1599 // If Unsched.front() instruction is a debug instruction, this will actually
1600 // shrink the region since we moved all debug instructions to the end of the
1601 // block. Find the first instruction that is not a debug instruction.
1602 DAG.RegionBegin = Unsched.front()->getIterator();
1603 if (DAG.RegionBegin->isDebugInstr()) {
1604 for (MachineInstr *MI : Unsched) {
1605 if (MI->isDebugInstr())
1606 continue;
1607 DAG.RegionBegin = MI->getIterator();
1608 break;
1609 }
1610 }
1611
1612 // Then move the debug instructions back into their correct place and set
1613 // RegionBegin and RegionEnd if needed.
1615
1616 DAG.Regions[RegionIdx] = std::pair(DAG.RegionBegin, DAG.RegionEnd);
1617}
1618
1619void PreRARematStage::collectRematerializableInstructions() {
1620 const SIRegisterInfo *SRI = static_cast<const SIRegisterInfo *>(DAG.TRI);
1621 for (unsigned I = 0, E = DAG.MRI.getNumVirtRegs(); I != E; ++I) {
1623 if (!DAG.LIS->hasInterval(Reg))
1624 continue;
1625
1626 // TODO: Handle AGPR and SGPR rematerialization
1627 if (!SRI->isVGPRClass(DAG.MRI.getRegClass(Reg)) ||
1628 !DAG.MRI.hasOneDef(Reg) || !DAG.MRI.hasOneNonDBGUse(Reg))
1629 continue;
1630
1632 MachineInstr *Def = Op->getParent();
1633 if (Op->getSubReg() != 0 || !isTriviallyReMaterializable(*Def))
1634 continue;
1635
1637 if (Def->getParent() == UseI->getParent())
1638 continue;
1639
1640 // We are only collecting defs that are defined in another block and are
1641 // live-through or used inside regions at MinOccupancy. This means that the
1642 // register must be in the live-in set for the region.
1643 bool AddedToRematList = false;
1644 for (unsigned I = 0, E = DAG.Regions.size(); I != E; ++I) {
1645 auto It = DAG.LiveIns[I].find(Reg);
1646 if (It != DAG.LiveIns[I].end() && !It->second.none()) {
1647 if (DAG.RegionsWithMinOcc[I]) {
1648 RematerializableInsts[I][Def] = UseI;
1649 AddedToRematList = true;
1650 }
1651
1652 // Collect regions with rematerializable reg as live-in to avoid
1653 // searching later when updating RP.
1654 RematDefToLiveInRegions[Def].push_back(I);
1655 }
1656 }
1657 if (!AddedToRematList)
1658 RematDefToLiveInRegions.erase(Def);
1659 }
1660}
1661
1662bool PreRARematStage::sinkTriviallyRematInsts(const GCNSubtarget &ST,
1663 const TargetInstrInfo *TII) {
1664 // Temporary copies of cached variables we will be modifying and replacing if
1665 // sinking succeeds.
1667 std::pair<MachineBasicBlock::iterator, MachineBasicBlock::iterator>, 32>
1668 NewRegions;
1671 BitVector NewRescheduleRegions;
1672 LiveIntervals *LIS = DAG.LIS;
1673
1674 NewRegions.resize(DAG.Regions.size());
1675 NewRescheduleRegions.resize(DAG.Regions.size());
1676
1677 // Collect only regions that has a rematerializable def as a live-in.
1678 SmallSet<unsigned, 16> ImpactedRegions;
1679 for (const auto &It : RematDefToLiveInRegions)
1680 ImpactedRegions.insert(It.second.begin(), It.second.end());
1681
1682 // Make copies of register pressure and live-ins cache that will be updated
1683 // as we rematerialize.
1684 for (auto Idx : ImpactedRegions) {
1685 NewPressure[Idx] = DAG.Pressure[Idx];
1686 NewLiveIns[Idx] = DAG.LiveIns[Idx];
1687 }
1688 NewRegions = DAG.Regions;
1689 NewRescheduleRegions.reset();
1690
1692 bool Improved = false;
1693 for (auto I : ImpactedRegions) {
1694 if (!DAG.RegionsWithMinOcc[I])
1695 continue;
1696
1697 Improved = false;
1698 int VGPRUsage = NewPressure[I].getVGPRNum(ST.hasGFX90AInsts());
1699 int SGPRUsage = NewPressure[I].getSGPRNum();
1700
1701 // TODO: Handle occupancy drop due to AGPR and SGPR.
1702 // Check if cause of occupancy drop is due to VGPR usage and not SGPR.
1703 if (ST.getOccupancyWithNumSGPRs(SGPRUsage) == DAG.MinOccupancy)
1704 break;
1705
1706 // The occupancy of this region could have been improved by a previous
1707 // iteration's sinking of defs.
1708 if (NewPressure[I].getOccupancy(ST) > DAG.MinOccupancy) {
1709 NewRescheduleRegions[I] = true;
1710 Improved = true;
1711 continue;
1712 }
1713
1714 // First check if we have enough trivially rematerializable instructions to
1715 // improve occupancy. Optimistically assume all instructions we are able to
1716 // sink decreased RP.
1717 int TotalSinkableRegs = 0;
1718 for (const auto &It : RematerializableInsts[I]) {
1719 MachineInstr *Def = It.first;
1720 Register DefReg = Def->getOperand(0).getReg();
1721 TotalSinkableRegs +=
1722 SIRegisterInfo::getNumCoveredRegs(NewLiveIns[I][DefReg]);
1723 }
1724 int VGPRsAfterSink = VGPRUsage - TotalSinkableRegs;
1725 unsigned OptimisticOccupancy = ST.getOccupancyWithNumVGPRs(VGPRsAfterSink);
1726 // If in the most optimistic scenario, we cannot improve occupancy, then do
1727 // not attempt to sink any instructions.
1728 if (OptimisticOccupancy <= DAG.MinOccupancy)
1729 break;
1730
1731 unsigned ImproveOccupancy = 0;
1733 for (auto &It : RematerializableInsts[I]) {
1734 MachineInstr *Def = It.first;
1735 MachineBasicBlock::iterator InsertPos =
1736 MachineBasicBlock::iterator(It.second);
1737 Register Reg = Def->getOperand(0).getReg();
1738 // Rematerialize MI to its use block. Since we are only rematerializing
1739 // instructions that do not have any virtual reg uses, we do not need to
1740 // call LiveRangeEdit::allUsesAvailableAt() and
1741 // LiveRangeEdit::canRematerializeAt().
1742 TII->reMaterialize(*InsertPos->getParent(), InsertPos, Reg,
1743 Def->getOperand(0).getSubReg(), *Def, *DAG.TRI);
1744 MachineInstr *NewMI = &*std::prev(InsertPos);
1745 LIS->InsertMachineInstrInMaps(*NewMI);
1746 LIS->removeInterval(Reg);
1748 InsertedMIToOldDef[NewMI] = Def;
1749
1750 // Update region boundaries in scheduling region we sinked from since we
1751 // may sink an instruction that was at the beginning or end of its region
1752 DAG.updateRegionBoundaries(NewRegions, Def, /*NewMI =*/nullptr,
1753 /*Removing =*/true);
1754
1755 // Update region boundaries in region we sinked to.
1756 DAG.updateRegionBoundaries(NewRegions, InsertPos, NewMI);
1757
1758 LaneBitmask PrevMask = NewLiveIns[I][Reg];
1759 // FIXME: Also update cached pressure for where the def was sinked from.
1760 // Update RP for all regions that has this reg as a live-in and remove
1761 // the reg from all regions as a live-in.
1762 for (auto Idx : RematDefToLiveInRegions[Def]) {
1763 NewLiveIns[Idx].erase(Reg);
1764 if (InsertPos->getParent() != DAG.Regions[Idx].first->getParent()) {
1765 // Def is live-through and not used in this block.
1766 NewPressure[Idx].inc(Reg, PrevMask, LaneBitmask::getNone(), DAG.MRI);
1767 } else {
1768 // Def is used and rematerialized into this block.
1769 GCNDownwardRPTracker RPT(*LIS);
1770 auto *NonDbgMI = &*skipDebugInstructionsForward(
1771 NewRegions[Idx].first, NewRegions[Idx].second);
1772 RPT.reset(*NonDbgMI, &NewLiveIns[Idx]);
1773 RPT.advance(NewRegions[Idx].second);
1774 NewPressure[Idx] = RPT.moveMaxPressure();
1775 }
1776 }
1777
1778 SinkedDefs.push_back(Def);
1779 ImproveOccupancy = NewPressure[I].getOccupancy(ST);
1780 if (ImproveOccupancy > DAG.MinOccupancy)
1781 break;
1782 }
1783
1784 // Remove defs we just sinked from all regions' list of sinkable defs
1785 for (auto &Def : SinkedDefs)
1786 for (auto TrackedIdx : RematDefToLiveInRegions[Def])
1787 RematerializableInsts[TrackedIdx].erase(Def);
1788
1789 if (ImproveOccupancy <= DAG.MinOccupancy)
1790 break;
1791
1792 NewRescheduleRegions[I] = true;
1793 Improved = true;
1794 }
1795
1796 if (!Improved) {
1797 // Occupancy was not improved for all regions that were at MinOccupancy.
1798 // Undo sinking and remove newly rematerialized instructions.
1799 for (auto &Entry : InsertedMIToOldDef) {
1800 MachineInstr *MI = Entry.first;
1801 MachineInstr *OldMI = Entry.second;
1802 Register Reg = MI->getOperand(0).getReg();
1804 MI->eraseFromParent();
1805 OldMI->clearRegisterDeads(Reg);
1806 LIS->removeInterval(Reg);
1808 }
1809 return false;
1810 }
1811
1812 // Occupancy was improved for all regions.
1813 for (auto &Entry : InsertedMIToOldDef) {
1814 MachineInstr *MI = Entry.first;
1815 MachineInstr *OldMI = Entry.second;
1816
1817 // Remove OldMI from BBLiveInMap since we are sinking it from its MBB.
1818 DAG.BBLiveInMap.erase(OldMI);
1819
1820 // Remove OldMI and update LIS
1821 Register Reg = MI->getOperand(0).getReg();
1822 LIS->RemoveMachineInstrFromMaps(*OldMI);
1823 OldMI->eraseFromParent();
1824 LIS->removeInterval(Reg);
1826 }
1827
1828 // Update live-ins, register pressure, and regions caches.
1829 for (auto Idx : ImpactedRegions) {
1830 DAG.LiveIns[Idx] = NewLiveIns[Idx];
1831 DAG.Pressure[Idx] = NewPressure[Idx];
1832 DAG.MBBLiveIns.erase(DAG.Regions[Idx].first->getParent());
1833 }
1834 DAG.Regions = NewRegions;
1835 DAG.RescheduleRegions = NewRescheduleRegions;
1836
1837 if (GCNTrackers)
1838 DAG.RegionLiveOuts.buildLiveRegMap();
1839
1841 MFI.increaseOccupancy(MF, ++DAG.MinOccupancy);
1842
1843 return true;
1844}
1845
1846// Copied from MachineLICM
1847bool PreRARematStage::isTriviallyReMaterializable(const MachineInstr &MI) {
1849 return false;
1850
1851 for (const MachineOperand &MO : MI.all_uses())
1852 if (MO.getReg().isVirtual())
1853 return false;
1854
1855 return true;
1856}
1857
1858// When removing, we will have to check both beginning and ending of the region.
1859// When inserting, we will only have to check if we are inserting NewMI in front
1860// of a scheduling region and do not need to check the ending since we will only
1861// ever be inserting before an already existing MI.
1862void GCNScheduleDAGMILive::updateRegionBoundaries(
1864 MachineBasicBlock::iterator>> &RegionBoundaries,
1865 MachineBasicBlock::iterator MI, MachineInstr *NewMI, bool Removing) {
1866 unsigned I = 0, E = RegionBoundaries.size();
1867 // Search for first region of the block where MI is located
1868 while (I != E && MI->getParent() != RegionBoundaries[I].first->getParent())
1869 ++I;
1870
1871 for (; I != E; ++I) {
1872 if (MI->getParent() != RegionBoundaries[I].first->getParent())
1873 return;
1874
1875 if (Removing && MI == RegionBoundaries[I].first &&
1876 MI == RegionBoundaries[I].second) {
1877 // MI is in a region with size 1, after removing, the region will be
1878 // size 0, set RegionBegin and RegionEnd to pass end of block iterator.
1879 RegionBoundaries[I] =
1880 std::pair(MI->getParent()->end(), MI->getParent()->end());
1881 return;
1882 }
1883 if (MI == RegionBoundaries[I].first) {
1884 if (Removing)
1885 RegionBoundaries[I] =
1886 std::pair(std::next(MI), RegionBoundaries[I].second);
1887 else
1888 // Inserted NewMI in front of region, set new RegionBegin to NewMI
1889 RegionBoundaries[I] = std::pair(MachineBasicBlock::iterator(NewMI),
1890 RegionBoundaries[I].second);
1891 return;
1892 }
1893 if (Removing && MI == RegionBoundaries[I].second) {
1894 RegionBoundaries[I] = std::pair(RegionBoundaries[I].first, std::prev(MI));
1895 return;
1896 }
1897 }
1898}
1899
1901 return any_of(*DAG, [](MachineBasicBlock::iterator MI) {
1902 return isIGLPMutationOnly(MI->getOpcode());
1903 });
1904}
1905
1907 MachineSchedContext *C, std::unique_ptr<MachineSchedStrategy> S,
1908 bool RemoveKillFlags)
1909 : ScheduleDAGMI(C, std::move(S), RemoveKillFlags) {}
1910
1912 HasIGLPInstrs = hasIGLPInstrs(this);
1913 if (HasIGLPInstrs) {
1914 SavedMutations.clear();
1915 SavedMutations.swap(Mutations);
1917 }
1918
1920}
1921
1923 if (HasIGLPInstrs)
1924 SavedMutations.swap(Mutations);
1925
1927}
MachineInstrBuilder MachineInstrBuilder & DefMI
MachineBasicBlock & MBB
basic Basic Alias true
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
#define LLVM_DEBUG(...)
Definition: Debug.h:106
static cl::opt< bool > GCNTrackers("amdgpu-use-amdgpu-trackers", cl::Hidden, cl::desc("Use the AMDGPU specific RPTrackers during scheduling"), cl::init(false))
static cl::opt< bool > DisableClusteredLowOccupancy("amdgpu-disable-clustered-low-occupancy-reschedule", cl::Hidden, cl::desc("Disable clustered low occupancy " "rescheduling for ILP scheduling stage."), cl::init(false))
static MachineInstr * getLastMIForRegion(MachineBasicBlock::iterator RegionBegin, MachineBasicBlock::iterator RegionEnd)
static bool isIGLPMutationOnly(unsigned Opcode)
static cl::opt< bool > RelaxedOcc("amdgpu-schedule-relaxed-occupancy", cl::Hidden, cl::desc("Relax occupancy targets for kernels which are memory " "bound (amdgpu-membound-threshold), or " "Wave Limited (amdgpu-limit-wave-threshold)."), cl::init(false))
static cl::opt< bool > DisableUnclusterHighRP("amdgpu-disable-unclustered-high-rp-reschedule", cl::Hidden, cl::desc("Disable unclustered high register pressure " "reduction scheduling stage."), cl::init(false))
static void printScheduleModel(std::set< std::pair< MachineInstr *, unsigned >, EarlierIssuingCycle > &ReadyCycles)
static bool hasIGLPInstrs(ScheduleDAGInstrs *DAG)
static bool canUsePressureDiffs(const SUnit &SU)
Checks whether SU can use the cached DAG pressure diffs to compute the current register pressure.
static void getRegisterPressures(bool AtTop, const RegPressureTracker &RPTracker, SUnit *SU, std::vector< unsigned > &Pressure, std::vector< unsigned > &MaxPressure, GCNDownwardRPTracker &DownwardTracker, GCNUpwardRPTracker &UpwardTracker, ScheduleDAGMI *DAG, const SIRegisterInfo *SRI)
static cl::opt< unsigned > ScheduleMetricBias("amdgpu-schedule-metric-bias", cl::Hidden, cl::desc("Sets the bias which adds weight to occupancy vs latency. Set it to " "100 to chase the occupancy only."), cl::init(10))
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
#define I(x, y, z)
Definition: MD5.cpp:58
if(PassOpts->AAPipeline)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
raw_pwrite_stream & OS
unsigned getOccupancyWithLocalMemSize(uint32_t Bytes, const Function &) const
Inverse of getMaxLocalMemWithWaveCount.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
BitVector & reset()
Definition: BitVector.h:392
void resize(unsigned N, bool t=false)
resize - Grow or shrink the bitvector.
Definition: BitVector.h:341
BitVector & set()
Definition: BitVector.h:351
bool none() const
none - Returns true if none of the bits are set.
Definition: BitVector.h:188
bool shouldRevertScheduling(unsigned WavesAfter) override
This class represents an Operation in the Expression.
bool erase(const KeyT &Val)
Definition: DenseMap.h:321
bool advance(MachineInstr *MI=nullptr, bool UseInternalIterator=true)
Move to the state at the next MI.
GCNRegPressure bumpDownwardPressure(const MachineInstr *MI, const SIRegisterInfo *TRI) const
Mostly copy/paste from CodeGen/RegisterPressure.cpp Calculate the impact MI will have on CurPressure ...
GCNMaxILPSchedStrategy(const MachineSchedContext *C)
bool tryCandidate(SchedCandidate &Cand, SchedCandidate &TryCand, SchedBoundary *Zone) const override
Apply a set of heuristics to a new candidate.
bool tryCandidate(SchedCandidate &Cand, SchedCandidate &TryCand, SchedBoundary *Zone) const override
GCNMaxMemoryClauseSchedStrategy tries best to clause memory instructions as much as possible.
GCNMaxMemoryClauseSchedStrategy(const MachineSchedContext *C)
GCNMaxOccupancySchedStrategy(const MachineSchedContext *C, bool IsLegacyScheduler=false)
void finalizeSchedule() override
Allow targets to perform final scheduling actions at the level of the whole MachineFunction.
void schedule() override
Implement ScheduleDAGInstrs interface for scheduling a sequence of reorderable instructions.
GCNPostScheduleDAGMILive(MachineSchedContext *C, std::unique_ptr< MachineSchedStrategy > S, bool RemoveKillFlags)
GCNRegPressure getPressure() const
virtual bool initGCNRegion()
GCNSchedStrategy & S
GCNRegPressure PressureBefore
bool isRegionWithExcessRP() const
bool mayCauseSpilling(unsigned WavesAfter)
ScheduleMetrics getScheduleMetrics(const std::vector< SUnit > &InputSchedule)
GCNScheduleDAGMILive & DAG
const GCNSchedStageID StageID
std::vector< MachineInstr * > Unsched
GCNRegPressure PressureAfter
MachineFunction & MF
SIMachineFunctionInfo & MFI
unsigned computeSUnitReadyCycle(const SUnit &SU, unsigned CurrCycle, DenseMap< unsigned, unsigned > &ReadyCycles, const TargetSchedModel &SM)
virtual void finalizeGCNSchedStage()
virtual bool initGCNSchedStage()
virtual bool shouldRevertScheduling(unsigned WavesAfter)
std::vector< std::unique_ptr< ScheduleDAGMutation > > SavedMutations
GCNSchedStage(GCNSchedStageID StageID, GCNScheduleDAGMILive &DAG)
MachineBasicBlock * CurrentMBB
const GCNSubtarget & ST
This is a minimal scheduler strategy.
const unsigned HighRPSGPRBias
GCNDownwardRPTracker DownwardTracker
GCNSchedStrategy(const MachineSchedContext *C)
SmallVector< GCNSchedStageID, 4 > SchedStages
SUnit * pickNodeBidirectional(bool &IsTopNode)
void pickNodeFromQueue(SchedBoundary &Zone, const CandPolicy &ZonePolicy, const RegPressureTracker &RPTracker, SchedCandidate &Cand, bool IsBottomUp)
std::vector< unsigned > MaxPressure
GCNSchedStageID getCurrentStage()
MachineFunction * MF
SmallVectorImpl< GCNSchedStageID >::iterator CurrentStage
void schedNode(SUnit *SU, bool IsTopNode) override
Update the scheduler's state after scheduling a node.
GCNDownwardRPTracker * getDownwardTracker()
std::vector< unsigned > Pressure
void initialize(ScheduleDAGMI *DAG) override
Initialize the strategy after building the DAG for a new region.
GCNUpwardRPTracker UpwardTracker
const unsigned HighRPVGPRBias
void initCandidate(SchedCandidate &Cand, SUnit *SU, bool AtTop, const RegPressureTracker &RPTracker, const SIRegisterInfo *SRI, unsigned SGPRPressure, unsigned VGPRPressure, bool IsBottomUp)
SUnit * pickNode(bool &IsTopNode) override
Pick the best node to balance the schedule. Implements MachineSchedStrategy.
GCNUpwardRPTracker * getUpwardTracker()
GCNSchedStageID getNextStage() const
void finalizeSchedule() override
Allow targets to perform final scheduling actions at the level of the whole MachineFunction.
void schedule() override
Implement ScheduleDAGInstrs interface for scheduling a sequence of reorderable instructions.
GCNScheduleDAGMILive(MachineSchedContext *C, std::unique_ptr< MachineSchedStrategy > S)
unsigned getAddressableNumArchVGPRs() const
bool hasGFX90AInsts() const
unsigned computeOccupancy(const Function &F, unsigned LDSSize=0, unsigned NumSGPRs=0, unsigned NumVGPRs=0) const
Return occupancy for the given function.
const SIInstrInfo * getInstrInfo() const override
Definition: GCNSubtarget.h:279
unsigned getMaxNumVGPRs(unsigned WavesPerEU) const
unsigned getOccupancyWithNumVGPRs(unsigned VGPRs) const
Return the maximum number of waves per SIMD for kernels using VGPRs VGPRs.
unsigned getOccupancyWithNumSGPRs(unsigned SGPRs) const
Return the maximum number of waves per SIMD for kernels using SGPRs SGPRs.
unsigned getMaxNumSGPRs(unsigned WavesPerEU, bool Addressable) const
void recede(const MachineInstr &MI)
Move to the state of RP just before the MI .
void traceCandidate(const SchedCandidate &Cand)
void setPolicy(CandPolicy &Policy, bool IsPostRA, SchedBoundary &CurrZone, SchedBoundary *OtherZone)
Set the CandPolicy given a scheduling zone given the current resources and latencies inside and outsi...
MachineSchedPolicy RegionPolicy
const TargetSchedModel * SchedModel
const MachineSchedContext * Context
const TargetRegisterInfo * TRI
GenericScheduler shrinks the unscheduled zone using heuristics to balance the schedule.
SchedCandidate BotCand
Candidate last picked from Bot boundary.
SchedCandidate TopCand
Candidate last picked from Top boundary.
virtual bool tryCandidate(SchedCandidate &Cand, SchedCandidate &TryCand, SchedBoundary *Zone) const
Apply a set of heuristics to a new candidate.
ScheduleDAGMILive * DAG
void initialize(ScheduleDAGMI *dag) override
Initialize the strategy after building the DAG for a new region.
void schedNode(SUnit *SU, bool IsTopNode) override
Update the scheduler's state after scheduling a node.
bool shouldRevertScheduling(unsigned WavesAfter) override
bool hasInterval(Register Reg) const
SlotIndex InsertMachineInstrInMaps(MachineInstr &MI)
void handleMove(MachineInstr &MI, bool UpdateFlags=false)
Call this method to notify LiveIntervals that instruction MI has been moved within a basic block.
SlotIndexes * getSlotIndexes() const
SlotIndex getInstructionIndex(const MachineInstr &Instr) const
Returns the base index of the given instruction.
void RemoveMachineInstrFromMaps(MachineInstr &MI)
void removeInterval(Register Reg)
Interval removal.
LiveInterval & createAndComputeVirtRegInterval(Register Reg)
instr_iterator insert(instr_iterator I, MachineInstr *M)
Insert MI into the instruction list before I, possibly inside a bundle.
MachineInstr * remove(MachineInstr *I)
Remove the unbundled instruction from the instruction list without deleting it.
unsigned succ_size() const
MachineInstrBundleIterator< MachineInstr > iterator
StringRef getName() const
Return the name of the corresponding LLVM basic block, or an empty string.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
Function & getFunction()
Return the LLVM function that this machine code represents.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
Representation of each machine instruction.
Definition: MachineInstr.h:69
const MachineBasicBlock * getParent() const
Definition: MachineInstr.h:347
bool mayLoad(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly read memory.
iterator_range< mop_iterator > operands()
Definition: MachineInstr.h:691
void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
void clearRegisterDeads(Register Reg)
Clear all dead flags on operands defining register Reg.
MachineOperand class - Representation of each machine instruction operand.
bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
MachineOperand * getOneDef(Register Reg) const
Returns the defining operand if there is exactly one operand defining the specified register,...
use_instr_nodbg_iterator use_instr_nodbg_begin(Register RegNo) const
bool hasOneDef(Register RegNo) const
Return true if there is exactly one operand defining the specified register.
unsigned getNumVirtRegs() const
getNumVirtRegs - Return the number of virtual registers created.
bool shouldRevertScheduling(unsigned WavesAfter) override
bool shouldRevertScheduling(unsigned WavesAfter) override
bool shouldRevertScheduling(unsigned WavesAfter) override
bool initGCNRegion() override
bool initGCNSchedStage() override
Capture a change in pressure for a single pressure set.
void setUnitInc(int Inc)
Helpers for implementing custom MachineSchedStrategy classes.
bool empty() const
Track the current register pressure at some position in the instruction stream, and remember the high...
void advance()
Advance across the current instruction.
void getDownwardPressure(const MachineInstr *MI, std::vector< unsigned > &PressureResult, std::vector< unsigned > &MaxPressureResult)
Get the pressure of each PSet after traversing this instruction top-down.
const std::vector< unsigned > & getRegSetPressureAtPos() const
Get the register set pressure at the current position, which may be less than the pressure across the...
void getUpwardPressure(const MachineInstr *MI, std::vector< unsigned > &PressureResult, std::vector< unsigned > &MaxPressureResult)
Get the pressure of each PSet after traversing this instruction bottom-up.
GCNRPTracker::LiveRegSet & getLiveRegsForRegionIdx(unsigned RegionIdx)
unsigned getNumAllocatableRegs(const TargetRegisterClass *RC) const
getNumAllocatableRegs - Returns the number of actually allocatable registers in RC in the current fun...
List of registers defined and used by a machine instruction.
void collect(const MachineInstr &MI, const TargetRegisterInfo &TRI, const MachineRegisterInfo &MRI, bool TrackLaneMasks, bool IgnoreDead)
Analyze the given instruction MI and fill in the Uses, Defs and DeadDefs list based on the MachineOpe...
void adjustLaneLiveness(const LiveIntervals &LIS, const MachineRegisterInfo &MRI, SlotIndex Pos, MachineInstr *AddFlagsMI=nullptr)
Use liveness information to find out which uses/defs are partially undefined/dead and adjust the Regi...
void detectDeadDefs(const MachineInstr &MI, const LiveIntervals &LIS)
Use liveness information to find dead defs not marked with a dead flag and move them to the DeadDefs ...
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
static Register index2VirtReg(unsigned Index)
Convert a 0-based index to a virtual register number.
Definition: Register.h:84
const TargetSchedModel & getSchedModel() const
Definition: SIInstrInfo.h:1456
This class keeps track of the SPI_SP_INPUT_ADDR config register, which tells the hardware which inter...
void increaseOccupancy(const MachineFunction &MF, unsigned Limit)
void limitOccupancy(const MachineFunction &MF)
static unsigned getNumCoveredRegs(LaneBitmask LM)
static bool isVGPRClass(const TargetRegisterClass *RC)
Scheduling unit. This is a node in the scheduling DAG.
Definition: ScheduleDAG.h:242
bool isInstr() const
Returns true if this SUnit refers to a machine instruction as opposed to an SDNode.
Definition: ScheduleDAG.h:378
unsigned NodeNum
Entry # of node in the node vector.
Definition: ScheduleDAG.h:270
unsigned short Latency
Node latency.
Definition: ScheduleDAG.h:303
bool isScheduled
True once scheduled.
Definition: ScheduleDAG.h:296
bool isBottomReady() const
Definition: ScheduleDAG.h:467
bool isTopReady() const
Definition: ScheduleDAG.h:464
SmallVector< SDep, 4 > Preds
All sunit predecessors.
Definition: ScheduleDAG.h:262
MachineInstr * getInstr() const
Returns the representative MachineInstr for this SUnit.
Definition: ScheduleDAG.h:390
Each Scheduling boundary is associated with ready queues.
unsigned getLatencyStallCycles(SUnit *SU)
Get the difference between the given SUnit's ready time and the current cycle.
ScheduleDAGMI * DAG
SUnit * pickOnlyChoice()
Call this before applying any other heuristics to the Available queue.
unsigned getCurrMOps() const
Micro-ops issued in the current cycle.
void removeReady(SUnit *SU)
Remove SU from the ready set for this boundary.
A ScheduleDAG for scheduling lists of MachineInstr.
MachineBasicBlock::iterator end() const
Returns an iterator to the bottom of the current scheduling region.
MachineBasicBlock * BB
The block in which to insert instructions.
MachineBasicBlock::iterator RegionEnd
The end of the range to be scheduled.
virtual void finalizeSchedule()
Allow targets to perform final scheduling actions at the level of the whole MachineFunction.
MachineBasicBlock::iterator begin() const
Returns an iterator to the top of the current scheduling region.
SUnit * getSUnit(MachineInstr *MI) const
Returns an existing SUnit for this MI, or nullptr.
virtual void exitRegion()
Called when the scheduler has finished scheduling the current region.
MachineBasicBlock::iterator RegionBegin
The beginning of the range to be scheduled.
unsigned NumRegionInstrs
Instructions in this region (distance(RegionBegin, RegionEnd)).
ScheduleDAGMILive is an implementation of ScheduleDAGInstrs that schedules machine instructions while...
void schedule() override
Implement ScheduleDAGInstrs interface for scheduling a sequence of reorderable instructions.
PressureDiff & getPressureDiff(const SUnit *SU)
void enterRegion(MachineBasicBlock *bb, MachineBasicBlock::iterator begin, MachineBasicBlock::iterator end, unsigned regioninstrs) override
Implement the ScheduleDAGInstrs interface for handling the next scheduling region.
const RegPressureTracker & getBotRPTracker() const
bool isTrackingPressure() const
Return true if register pressure tracking is enabled.
const RegPressureTracker & getTopRPTracker() const
RegPressureTracker RPTracker
ScheduleDAGMI is an implementation of ScheduleDAGInstrs that simply schedules machine instructions ac...
void startBlock(MachineBasicBlock *bb) override
Prepares to perform scheduling in the given block.
void addMutation(std::unique_ptr< ScheduleDAGMutation > Mutation)
Add a postprocessing step to the DAG builder.
MachineBasicBlock::iterator top() const
void schedule() override
Implement ScheduleDAGInstrs interface for scheduling a sequence of reorderable instructions.
MachineBasicBlock::iterator bottom() const
void finishBlock() override
Cleans up after scheduling in the given block.
LiveIntervals * LIS
const SUnit * getNextClusterPred() const
void placeDebugValues()
Reinsert debug_values recorded in ScheduleDAGInstrs::DbgValues.
const SUnit * getNextClusterSucc() const
std::vector< std::unique_ptr< ScheduleDAGMutation > > Mutations
Ordered list of DAG postprocessing steps.
MachineRegisterInfo & MRI
Virtual/real register map.
Definition: ScheduleDAG.h:578
const TargetInstrInfo * TII
Target instruction information.
Definition: ScheduleDAG.h:575
std::vector< SUnit > SUnits
The scheduling units.
Definition: ScheduleDAG.h:579
const TargetRegisterInfo * TRI
Target processor register info.
Definition: ScheduleDAG.h:576
MachineFunction & MF
Machine function.
Definition: ScheduleDAG.h:577
static const unsigned ScaleFactor
unsigned getMetric() const
SlotIndex - An opaque wrapper around machine indexes.
Definition: SlotIndexes.h:65
SlotIndex getRegSlot(bool EC=false) const
Returns the register use/def slot in the current instruction for a normal or early-clobber def.
Definition: SlotIndexes.h:237
SlotIndexes pass.
Definition: SlotIndexes.h:297
SlotIndex getMBBStartIdx(unsigned Num) const
Returns the first index in the given basic block number.
Definition: SlotIndexes.h:460
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
Definition: SmallSet.h:132
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
Definition: SmallSet.h:181
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: SmallVector.h:573
void resize(size_type N)
Definition: SmallVector.h:638
void push_back(const T &Elt)
Definition: SmallVector.h:413
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1196
TargetInstrInfo - Interface to description of machine instruction set.
bool isTriviallyReMaterializable(const MachineInstr &MI) const
Return true if the instruction is trivially rematerializable, meaning it has no side effects and requ...
Provide an instruction scheduling machine model to CodeGen passes.
virtual const TargetInstrInfo * getInstrInfo() const
bool shouldRevertScheduling(unsigned WavesAfter) override
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned getAddressableNumVGPRs(const MCSubtargetInfo *STI)
unsigned getVGPRAllocGranule(const MCSubtargetInfo *STI, std::optional< bool > EnableWavefrontSize32)
@ Entry
Definition: COFF.h:844
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
Reg
All possible values of the reg field in the ModR/M byte.
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:443
NodeAddr< DefNode * > Def
Definition: RDFGraph.h:384
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
bool isEqual(const GCNRPTracker::LiveRegSet &S1, const GCNRPTracker::LiveRegSet &S2)
unsigned getWeakLeft(const SUnit *SU, bool isTop)
GCNRegPressure getRegPressure(const MachineRegisterInfo &MRI, Range &&LiveRegs)
std::unique_ptr< ScheduleDAGMutation > createIGroupLPDAGMutation(AMDGPU::SchedulingPhase Phase)
Phase specifes whether or not this is a reentry into the IGroupLPDAGMutation.
constexpr T alignDown(U Value, V Align, W Skew=0)
Returns the largest unsigned integer less than or equal to Value and is Skew mod Align.
Definition: MathExtras.h:555
cl::opt< bool > VerifyScheduling
Printable print(const GCNRegPressure &RP, const GCNSubtarget *ST=nullptr)
IterT skipDebugInstructionsForward(IterT It, IterT End, bool SkipPseudoOp=true)
Increment It until it points to a non-debug instruction or to End and return the resulting iterator.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1746
bool tryPressure(const PressureChange &TryP, const PressureChange &CandP, GenericSchedulerBase::SchedCandidate &TryCand, GenericSchedulerBase::SchedCandidate &Cand, GenericSchedulerBase::CandReason Reason, const TargetRegisterInfo *TRI, const MachineFunction &MF)
auto reverse(ContainerTy &&C)
Definition: STLExtras.h:420
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:167
bool tryLatency(GenericSchedulerBase::SchedCandidate &TryCand, GenericSchedulerBase::SchedCandidate &Cand, SchedBoundary &Zone)
IterT skipDebugInstructionsBackward(IterT It, IterT Begin, bool SkipPseudoOp=true)
Decrement It until it points to a non-debug instruction or to Begin and return the resulting iterator...
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
bool tryGreater(int TryVal, int CandVal, GenericSchedulerBase::SchedCandidate &TryCand, GenericSchedulerBase::SchedCandidate &Cand, GenericSchedulerBase::CandReason Reason)
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
Definition: APFixedPoint.h:303
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1873
DenseMap< MachineInstr *, GCNRPTracker::LiveRegSet > getLiveRegMap(Range &&R, bool After, LiveIntervals &LIS)
creates a map MachineInstr -> LiveRegSet R - range of iterators on instructions After - upon entry or...
GCNRPTracker::LiveRegSet getLiveRegsBefore(const MachineInstr &MI, const LiveIntervals &LIS)
bool tryLess(int TryVal, int CandVal, GenericSchedulerBase::SchedCandidate &TryCand, GenericSchedulerBase::SchedCandidate &Cand, GenericSchedulerBase::CandReason Reason)
Return true if this heuristic determines order.
Printable printMBBReference(const MachineBasicBlock &MBB)
Prints a machine basic block reference.
int biasPhysReg(const SUnit *SU, bool isTop)
Minimize physical register live ranges.
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:858
bool operator()(std::pair< MachineInstr *, unsigned > A, std::pair< MachineInstr *, unsigned > B) const
unsigned getOccupancy(const GCNSubtarget &ST) const
unsigned getVGPRNum(bool UnifiedVGPRFile) const
unsigned getArchVGPRNum() const
unsigned getAGPRNum() const
unsigned getSGPRNum() const
bool less(const MachineFunction &MF, const GCNRegPressure &O, unsigned MaxOccupancy=std::numeric_limits< unsigned >::max()) const
Compares this GCNRegpressure to O, returning true if this is less.
Policy for scheduling the next instruction in the candidate's zone.
Store the state used by GenericScheduler heuristics, required for the lifetime of one invocation of p...
void reset(const CandPolicy &NewPolicy)
void initResourceDelta(const ScheduleDAGMI *DAG, const TargetSchedModel *SchedModel)
Status of an instruction's critical resource consumption.
static constexpr LaneBitmask getNone()
Definition: LaneBitmask.h:81
MachineSchedContext provides enough context from the MachineScheduler pass for the target to instanti...
RegisterClassInfo * RegClassInfo
PressureChange CriticalMax