LLVM 24.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"
28#include "GCNHazardRecognizer.h"
29#include "GCNRegPressure.h"
32#include "llvm/ADT/BitVector.h"
33#include "llvm/ADT/STLExtras.h"
42#include "llvm/MC/LaneBitmask.h"
43#include "llvm/MC/MCSchedule.h"
46
47#define DEBUG_TYPE "machine-scheduler"
48
49using namespace llvm;
50
52 "amdgpu-disable-unclustered-high-rp-reschedule", cl::Hidden,
53 cl::desc("Disable unclustered high register pressure "
54 "reduction scheduling stage."),
55 cl::init(false));
56
58 "amdgpu-disable-clustered-low-occupancy-reschedule", cl::Hidden,
59 cl::desc("Disable clustered low occupancy "
60 "rescheduling for ILP scheduling stage."),
61 cl::init(false));
62
64 "amdgpu-schedule-metric-bias", cl::Hidden,
66 "Sets the bias which adds weight to occupancy vs latency. Set it to "
67 "100 to chase the occupancy only."),
68 cl::init(10));
69
70static cl::opt<bool>
71 RelaxedOcc("amdgpu-schedule-relaxed-occupancy", cl::Hidden,
72 cl::desc("Relax occupancy targets for kernels which are memory "
73 "bound (amdgpu-membound-threshold), or "
74 "Wave Limited (amdgpu-limit-wave-threshold)."),
75 cl::init(false));
76
78 "amdgpu-use-amdgpu-trackers", cl::Hidden,
79 cl::desc("Use the AMDGPU specific RPTrackers during scheduling"),
80 cl::init(false));
81
83 "amdgpu-scheduler-pending-queue-limit", cl::Hidden,
85 "Max (Available+Pending) size to inspect pending queue (0 disables)"),
86 cl::init(256));
87
88#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
89#define DUMP_MAX_REG_PRESSURE
91 "amdgpu-print-max-reg-pressure-regusage-before-scheduler", cl::Hidden,
92 cl::desc("Print a list of live registers along with their def/uses at the "
93 "point of maximum register pressure before scheduling."),
94 cl::init(false));
95
97 "amdgpu-print-max-reg-pressure-regusage-after-scheduler", cl::Hidden,
98 cl::desc("Print a list of live registers along with their def/uses at the "
99 "point of maximum register pressure after scheduling."),
100 cl::init(false));
101#endif
102
104 "amdgpu-disable-rewrite-mfma-form-sched-stage", cl::Hidden,
105 cl::desc("Disable rewrite mfma rewrite scheduling stage"), cl::init(true));
106
107namespace {
108
109struct VGPRThresholdParser : public cl::parser<unsigned> {
110 VGPRThresholdParser(cl::Option &O) : cl::parser<unsigned>(O) {}
111
112 bool parse(cl::Option &O, StringRef ArgName, StringRef Arg, unsigned &Value) {
113 if (Arg.getAsInteger(0, Value))
114 return O.error("'" + Arg + "' value invalid for uint argument!");
115
116 if (Value > 100)
117 return O.error("'" + Arg + "' value must be in the range [0, 100]!");
118
119 return false;
120 }
121};
122
123} // end anonymous namespace
124
126 "amdgpu-vgpr-threshold-percent", cl::Hidden,
127 cl::desc("Percent of VGPR limits that we should use as RP threshold "
128 "during scheduling. We have two limits relevant to scheduling: "
129 "Critical (avoid decreasing occupancy), Excess (avoid spilling). "
130 "This flag scales both limits back by an equal percent: (0 = use "
131 " default calculation, 1-100 = use percentage), default: 0"),
132 cl::init(0));
133
134const unsigned ScheduleMetrics::ScaleFactor = 100;
135
142
145
146 MF = &DAG->MF;
147
148 const GCNSubtarget &ST = MF->getSubtarget<GCNSubtarget>();
149
151 Context->RegClassInfo->getNumAllocatableRegs(&AMDGPU::SGPR_32RegClass);
153 Context->RegClassInfo->getNumAllocatableRegs(&AMDGPU::VGPR_32RegClass);
154
156 // Set the initial TargetOccupnacy to the maximum occupancy that we can
157 // achieve for this function. This effectively sets a lower bound on the
158 // 'Critical' register limits in the scheduler.
159 // Allow for lower occupancy targets if kernel is wave limited or memory
160 // bound, and using the relaxed occupancy feature.
164 std::min(ST.getMaxNumSGPRs(TargetOccupancy, true), SGPRExcessLimit);
165
166 if (!KnownExcessRP) {
167 VGPRCriticalLimit = std::min(
168 ST.getMaxNumVGPRs(TargetOccupancy, MFI.getDynamicVGPRBlockSize()),
170 } else {
171 // This is similar to ST.getMaxNumVGPRs(TargetOccupancy) result except
172 // returns a reasonably small number for targets with lots of VGPRs, such
173 // as GFX10 and GFX11.
174 LLVM_DEBUG(dbgs() << "Region is known to spill, use alternative "
175 "VGPRCriticalLimit calculation method.\n");
176 unsigned DynamicVGPRBlockSize = MFI.getDynamicVGPRBlockSize();
177 unsigned Granule =
178 AMDGPU::IsaInfo::getVGPRAllocGranule(ST, DynamicVGPRBlockSize);
179 unsigned Addressable =
180 AMDGPU::IsaInfo::getAddressableNumVGPRs(ST, DynamicVGPRBlockSize);
181 unsigned VGPRBudget = alignDown(Addressable / TargetOccupancy, Granule);
182 VGPRBudget = std::max(VGPRBudget, Granule);
183 VGPRCriticalLimit = std::min(VGPRBudget, VGPRExcessLimit);
184 }
185 // Apply VGPR excess threshold percentage if specified.
186 if (VGPRThresholdPercentOpt > 0) {
187 [[maybe_unused]] unsigned OriginalVGPRExcessLimit = VGPRExcessLimit;
188 [[maybe_unused]] unsigned OriginalVGPRCriticalLimit = VGPRCriticalLimit;
192 LLVM_DEBUG(dbgs() << "Applied VGPR excess threshold "
193 << VGPRThresholdPercentOpt << "%, VGPRExcessLimit: "
194 << OriginalVGPRExcessLimit << " -> " << VGPRExcessLimit
195 << ". VGPRCriticalLimit: " << OriginalVGPRCriticalLimit
196 << " -> " << VGPRCriticalLimit << '\n');
197 } else {
201 }
202
203 // Subtract error margin and bias from register limits and avoid overflow.
206 LLVM_DEBUG(dbgs() << "VGPRCriticalLimit = " << VGPRCriticalLimit
207 << ", VGPRExcessLimit = " << VGPRExcessLimit
208 << ", SGPRCriticalLimit = " << SGPRCriticalLimit
209 << ", SGPRExcessLimit = " << SGPRExcessLimit << "\n\n");
210}
211
212/// Checks whether \p SU can use the cached DAG pressure diffs to compute the
213/// current register pressure.
214///
215/// This works for the common case, but it has a few exceptions that have been
216/// observed through trial and error:
217/// - Explicit physical register operands
218/// - Subregister definitions
219///
220/// In both of those cases, PressureDiff doesn't represent the actual pressure,
221/// and querying LiveIntervals through the RegPressureTracker is needed to get
222/// an accurate value.
223///
224/// We should eventually only use PressureDiff for maximum performance, but this
225/// already allows 80% of SUs to take the fast path without changing scheduling
226/// at all. Further changes would either change scheduling, or require a lot
227/// more logic to recover an accurate pressure estimate from the PressureDiffs.
228static bool canUsePressureDiffs(const SUnit &SU) {
229 if (!SU.isInstr())
230 return false;
231
232 // Cannot use pressure diffs for subregister defs or with physregs, it's
233 // imprecise in both cases.
234 for (const auto &Op : SU.getInstr()->operands()) {
235 if (!Op.isReg() || Op.isImplicit())
236 continue;
237 if (Op.getReg().isPhysical() ||
238 (Op.isDef() && Op.getSubReg() != AMDGPU::NoSubRegister))
239 return false;
240 }
241 return true;
242}
243
245 bool AtTop, const RegPressureTracker &RPTracker, SUnit *SU,
246 std::vector<unsigned> &Pressure, std::vector<unsigned> &MaxPressure,
248 ScheduleDAGMI *DAG, const SIRegisterInfo *SRI) {
249 // getDownwardPressure() and getUpwardPressure() make temporary changes to
250 // the tracker, so we need to pass those function a non-const copy.
251 RegPressureTracker &TempTracker = const_cast<RegPressureTracker &>(RPTracker);
252 if (!useGCNTrackers()) {
253 AtTop
254 ? TempTracker.getDownwardPressure(SU->getInstr(), Pressure, MaxPressure)
255 : TempTracker.getUpwardPressure(SU->getInstr(), Pressure, MaxPressure);
256
257 return;
258 }
259
260 // GCNTrackers
261 Pressure.resize(4, 0);
262 MachineInstr *MI = SU->getInstr();
263 GCNRegPressure NewPressure;
264 if (AtTop) {
265 GCNDownwardRPTracker TempDownwardTracker(DownwardTracker);
266 NewPressure = TempDownwardTracker.bumpDownwardPressure(MI, SRI);
267 } else {
268 GCNUpwardRPTracker TempUpwardTracker(UpwardTracker);
269 TempUpwardTracker.recede(*MI);
270 NewPressure = TempUpwardTracker.getPressure();
271 }
272 Pressure[AMDGPU::RegisterPressureSets::SReg_32] = NewPressure.getSGPRNum();
273 Pressure[AMDGPU::RegisterPressureSets::VGPR_32] =
274 NewPressure.getArchVGPRNum();
275 Pressure[AMDGPU::RegisterPressureSets::AGPR_32] = NewPressure.getAGPRNum();
276}
277
279 SUnit *SU) const {
280 // Only implemented for top-down scheduling currently.
281 if (!Zone.isTop() || !SU)
282 return 0;
283
284 MachineInstr *MI = SU->getInstr();
285 unsigned CurrCycle = Zone.getCurrCycle();
286 unsigned Stall = 0;
287
288 // Query SchedModel for resource stalls (unbuffered resources).
289 if (SchedModel->hasInstrSchedModel() && SU->hasReservedResource) {
290 const MCSchedClassDesc *SC = DAG->getSchedClass(SU);
291 for (const MCWriteProcResEntry &PE :
292 make_range(SchedModel->getWriteProcResBegin(SC),
293 SchedModel->getWriteProcResEnd(SC))) {
294 unsigned NextAvail =
295 Zone.getNextResourceCycle(SC, PE.ProcResourceIdx, PE.ReleaseAtCycle,
296 PE.AcquireAtCycle)
297 .first;
298 if (NextAvail > CurrCycle)
299 Stall = std::max(Stall, NextAvail - CurrCycle);
300 }
301 }
302
303 // Query HazardRecognizer for sequence-dependent hazard penalties.
304 // AMDGPUCoExecSchedStrategy installs a GCNHazardRecognizer in both
305 // pre-RA (PreRA mode) and post-RA configurations.
306 if (Zone.HazardRec && Zone.HazardRec->isEnabled()) {
307 auto *HR = static_cast<GCNHazardRecognizer *>(Zone.HazardRec.get());
308 Stall = std::max(Stall, HR->getHazardWaitStates(MI));
309 }
310
311 return Stall;
312}
313
315 bool AtTop,
316 const RegPressureTracker &RPTracker,
317 const SIRegisterInfo *SRI,
318 unsigned SGPRPressure,
319 unsigned VGPRPressure, bool IsBottomUp) {
320 Cand.SU = SU;
321 Cand.AtTop = AtTop;
322
323 if (!DAG->isTrackingPressure())
324 return;
325
326 Pressure.clear();
327 MaxPressure.clear();
328
329 // We try to use the cached PressureDiffs in the ScheduleDAG whenever
330 // possible over querying the RegPressureTracker.
331 //
332 // RegPressureTracker will make a lot of LIS queries which are very
333 // expensive, it is considered a slow function in this context.
334 //
335 // PressureDiffs are precomputed and cached, and getPressureDiff is just a
336 // trivial lookup into an array. It is pretty much free.
337 //
338 // In EXPENSIVE_CHECKS, we always query RPTracker to verify the results of
339 // PressureDiffs.
340 if (AtTop || !canUsePressureDiffs(*SU) || useGCNTrackers()) {
341 getRegisterPressures(AtTop, RPTracker, SU, Pressure, MaxPressure,
343 } else {
344 // Reserve 4 slots.
345 Pressure.resize(4, 0);
346 Pressure[AMDGPU::RegisterPressureSets::SReg_32] = SGPRPressure;
347 Pressure[AMDGPU::RegisterPressureSets::VGPR_32] = VGPRPressure;
348
349 for (const auto &Diff : DAG->getPressureDiff(SU)) {
350 if (!Diff.isValid())
351 continue;
352 // PressureDiffs is always bottom-up so if we're working top-down we need
353 // to invert its sign.
354 Pressure[Diff.getPSet()] +=
355 (IsBottomUp ? Diff.getUnitInc() : -Diff.getUnitInc());
356 }
357
358#ifdef EXPENSIVE_CHECKS
359 std::vector<unsigned> CheckPressure, CheckMaxPressure;
360 getRegisterPressures(AtTop, RPTracker, SU, CheckPressure, CheckMaxPressure,
362 if (Pressure[AMDGPU::RegisterPressureSets::SReg_32] !=
363 CheckPressure[AMDGPU::RegisterPressureSets::SReg_32] ||
364 Pressure[AMDGPU::RegisterPressureSets::VGPR_32] !=
365 CheckPressure[AMDGPU::RegisterPressureSets::VGPR_32]) {
366 errs() << "Register Pressure is inaccurate when calculated through "
367 "PressureDiff\n"
368 << "SGPR got " << Pressure[AMDGPU::RegisterPressureSets::SReg_32]
369 << ", expected "
370 << CheckPressure[AMDGPU::RegisterPressureSets::SReg_32] << "\n"
371 << "VGPR got " << Pressure[AMDGPU::RegisterPressureSets::VGPR_32]
372 << ", expected "
373 << CheckPressure[AMDGPU::RegisterPressureSets::VGPR_32] << "\n";
374 report_fatal_error("inaccurate register pressure calculation");
375 }
376#endif
377 }
378
379 unsigned NewSGPRPressure = Pressure[AMDGPU::RegisterPressureSets::SReg_32];
380 unsigned NewVGPRPressure = Pressure[AMDGPU::RegisterPressureSets::VGPR_32];
381
382 // If two instructions increase the pressure of different register sets
383 // by the same amount, the generic scheduler will prefer to schedule the
384 // instruction that increases the set with the least amount of registers,
385 // which in our case would be SGPRs. This is rarely what we want, so
386 // when we report excess/critical register pressure, we do it either
387 // only for VGPRs or only for SGPRs.
388
389 // FIXME: Better heuristics to determine whether to prefer SGPRs or VGPRs.
390 const unsigned MaxVGPRPressureInc = 16;
391 bool ShouldTrackVGPRs = VGPRPressure + MaxVGPRPressureInc >= VGPRExcessLimit;
392 bool ShouldTrackSGPRs = !ShouldTrackVGPRs && SGPRPressure >= SGPRExcessLimit;
393
394 // FIXME: We have to enter REG-EXCESS before we reach the actual threshold
395 // to increase the likelihood we don't go over the limits. We should improve
396 // the analysis to look through dependencies to find the path with the least
397 // register pressure.
398
399 // We only need to update the RPDelta for instructions that increase register
400 // pressure. Instructions that decrease or keep reg pressure the same will be
401 // marked as RegExcess in tryCandidate() when they are compared with
402 // instructions that increase the register pressure.
403 if (ShouldTrackVGPRs && NewVGPRPressure >= VGPRExcessLimit) {
404 HasHighPressure = true;
405 Cand.RPDelta.Excess = PressureChange(AMDGPU::RegisterPressureSets::VGPR_32);
406 Cand.RPDelta.Excess.setUnitInc(NewVGPRPressure - VGPRExcessLimit);
407 }
408
409 if (ShouldTrackSGPRs && NewSGPRPressure >= SGPRExcessLimit) {
410 HasHighPressure = true;
411 Cand.RPDelta.Excess = PressureChange(AMDGPU::RegisterPressureSets::SReg_32);
412 Cand.RPDelta.Excess.setUnitInc(NewSGPRPressure - SGPRExcessLimit);
413 }
414
415 // Register pressure is considered 'CRITICAL' if it is approaching a value
416 // that would reduce the wave occupancy for the execution unit. When
417 // register pressure is 'CRITICAL', increasing SGPR and VGPR pressure both
418 // has the same cost, so we don't need to prefer one over the other.
419
420 int SGPRDelta = NewSGPRPressure - SGPRCriticalLimit;
421 int VGPRDelta = NewVGPRPressure - VGPRCriticalLimit;
422
423 if (SGPRDelta >= 0 || VGPRDelta >= 0) {
424 HasHighPressure = true;
425 if (SGPRDelta > VGPRDelta) {
426 Cand.RPDelta.CriticalMax =
427 PressureChange(AMDGPU::RegisterPressureSets::SReg_32);
428 Cand.RPDelta.CriticalMax.setUnitInc(SGPRDelta);
429 } else {
430 Cand.RPDelta.CriticalMax =
431 PressureChange(AMDGPU::RegisterPressureSets::VGPR_32);
432 Cand.RPDelta.CriticalMax.setUnitInc(VGPRDelta);
433 }
434 }
435}
436
438 const TargetSchedModel *SchedModel) {
439 bool HasBufferedModel =
440 SchedModel->hasInstrSchedModel() && SchedModel->getMicroOpBufferSize();
441 unsigned Combined = Zone.Available.size() + Zone.Pending.size();
442 return Combined <= PendingQueueLimit && HasBufferedModel;
443}
444
446 const TargetSchedModel *SchedModel) {
447 // pickOnlyChoice() releases pending instructions and checks for new hazards.
448 SUnit *OnlyChoice = Zone.pickOnlyChoice();
449 if (!shouldCheckPending(Zone, SchedModel) || Zone.Pending.empty())
450 return OnlyChoice;
451
452 return nullptr;
453}
454
456 const SchedCandidate &Preferred) {
457 LLVM_DEBUG({
458 dbgs() << "Prefer:\t\t";
459 DAG->dumpNode(*Preferred.SU);
460
461 if (Current.SU) {
462 dbgs() << "Not:\t";
463 DAG->dumpNode(*Current.SU);
464 }
465
466 dbgs() << "Reason:\t\t";
467 traceCandidate(Preferred);
468 });
469}
470
471// This function is mostly cut and pasted from
472// GenericScheduler::pickNodeFromQueue()
474 const CandPolicy &ZonePolicy,
475 const RegPressureTracker &RPTracker,
476 SchedCandidate &Cand, bool &IsPending,
477 bool IsBottomUp) {
478 const SIRegisterInfo *SRI = static_cast<const SIRegisterInfo *>(TRI);
480 unsigned SGPRPressure = 0;
481 unsigned VGPRPressure = 0;
482 IsPending = false;
483 if (DAG->isTrackingPressure()) {
484 if (!useGCNTrackers()) {
485 SGPRPressure = Pressure[AMDGPU::RegisterPressureSets::SReg_32];
486 VGPRPressure = Pressure[AMDGPU::RegisterPressureSets::VGPR_32];
487 } else {
488 GCNRPTracker *T = IsBottomUp
489 ? static_cast<GCNRPTracker *>(&UpwardTracker)
490 : static_cast<GCNRPTracker *>(&DownwardTracker);
491 SGPRPressure = T->getPressure().getSGPRNum();
492 VGPRPressure = T->getPressure().getArchVGPRNum();
493 }
494 }
495 LLVM_DEBUG(dbgs() << "Available Q:\n");
496 ReadyQueue &AQ = Zone.Available;
497 for (SUnit *SU : AQ) {
498
499 SchedCandidate TryCand(ZonePolicy);
500 initCandidate(TryCand, SU, Zone.isTop(), RPTracker, SRI, SGPRPressure,
501 VGPRPressure, IsBottomUp);
502 // Pass SchedBoundary only when comparing nodes from the same boundary.
503 SchedBoundary *ZoneArg = Cand.AtTop == TryCand.AtTop ? &Zone : nullptr;
504 tryCandidate(Cand, TryCand, ZoneArg);
505 if (TryCand.Reason != NoCand) {
506 // Initialize resource delta if needed in case future heuristics query it.
507 if (TryCand.ResDelta == SchedResourceDelta())
508 TryCand.initResourceDelta(Zone.DAG, SchedModel);
509 LLVM_DEBUG(printCandidateDecision(Cand, TryCand));
510 Cand.setBest(TryCand);
511 } else {
512 printCandidateDecision(TryCand, Cand);
513 }
514 }
515
516 if (!shouldCheckPending(Zone, SchedModel))
517 return;
518
519 LLVM_DEBUG(dbgs() << "Pending Q:\n");
520 ReadyQueue &PQ = Zone.Pending;
521 for (SUnit *SU : PQ) {
522
523 SchedCandidate TryCand(ZonePolicy);
524 initCandidate(TryCand, SU, Zone.isTop(), RPTracker, SRI, SGPRPressure,
525 VGPRPressure, IsBottomUp);
526 // Pass SchedBoundary only when comparing nodes from the same boundary.
527 SchedBoundary *ZoneArg = Cand.AtTop == TryCand.AtTop ? &Zone : nullptr;
528 tryPendingCandidate(Cand, TryCand, ZoneArg);
529 if (TryCand.Reason != NoCand) {
530 // Initialize resource delta if needed in case future heuristics query it.
531 if (TryCand.ResDelta == SchedResourceDelta())
532 TryCand.initResourceDelta(Zone.DAG, SchedModel);
533 LLVM_DEBUG(printCandidateDecision(Cand, TryCand));
534 IsPending = true;
535 Cand.setBest(TryCand);
536 } else {
537 printCandidateDecision(TryCand, Cand);
538 }
539 }
540}
541
542// This function is mostly cut and pasted from
543// GenericScheduler::pickNodeBidirectional()
545 bool &PickedPending) {
546 // Schedule as far as possible in the direction of no choice. This is most
547 // efficient, but also provides the best heuristics for CriticalPSets.
548 if (SUnit *SU = pickOnlyChoice(Bot, SchedModel)) {
549 IsTopNode = false;
550 return SU;
551 }
552 if (SUnit *SU = pickOnlyChoice(Top, SchedModel)) {
553 IsTopNode = true;
554 return SU;
555 }
556 // Set the bottom-up policy based on the state of the current bottom zone
557 // and the instructions outside the zone, including the top zone.
558 CandPolicy BotPolicy;
559 setPolicy(BotPolicy, /*IsPostRA=*/false, Bot, &Top);
560 // Set the top-down policy based on the state of the current top zone and
561 // the instructions outside the zone, including the bottom zone.
562 CandPolicy TopPolicy;
563 setPolicy(TopPolicy, /*IsPostRA=*/false, Top, &Bot);
564
565 bool BotPending = false;
566 // See if BotCand is still valid (because we previously scheduled from Top).
567 LLVM_DEBUG(dbgs() << "Picking from Bot:\n");
568 if (!BotCand.isValid() || BotCand.SU->isScheduled ||
569 BotCand.Policy != BotPolicy) {
570 BotCand.reset(CandPolicy());
571 pickNodeFromQueue(Bot, BotPolicy, DAG->getBotRPTracker(), BotCand,
572 BotPending,
573 /*IsBottomUp=*/true);
574 assert(BotCand.Reason != NoCand && "failed to find the first candidate");
575 } else {
577#ifndef NDEBUG
578 if (VerifyScheduling) {
579 SchedCandidate TCand;
580 TCand.reset(CandPolicy());
581 pickNodeFromQueue(Bot, BotPolicy, DAG->getBotRPTracker(), TCand,
582 BotPending,
583 /*IsBottomUp=*/true);
584 assert(TCand.SU == BotCand.SU &&
585 "Last pick result should correspond to re-picking right now");
586 }
587#endif
588 }
589
590 bool TopPending = false;
591 // Check if the top Q has a better candidate.
592 LLVM_DEBUG(dbgs() << "Picking from Top:\n");
593 if (!TopCand.isValid() || TopCand.SU->isScheduled ||
594 TopCand.Policy != TopPolicy) {
595 TopCand.reset(CandPolicy());
596 pickNodeFromQueue(Top, TopPolicy, DAG->getTopRPTracker(), TopCand,
597 TopPending,
598 /*IsBottomUp=*/false);
599 assert(TopCand.Reason != NoCand && "failed to find the first candidate");
600 } else {
602#ifndef NDEBUG
603 if (VerifyScheduling) {
604 SchedCandidate TCand;
605 TCand.reset(CandPolicy());
606 pickNodeFromQueue(Top, TopPolicy, DAG->getTopRPTracker(), TCand,
607 TopPending,
608 /*IsBottomUp=*/false);
609 assert(TCand.SU == TopCand.SU &&
610 "Last pick result should correspond to re-picking right now");
611 }
612#endif
613 }
614
615 // Pick best from BotCand and TopCand.
616 LLVM_DEBUG(dbgs() << "Top Cand: "; traceCandidate(TopCand);
617 dbgs() << "Bot Cand: "; traceCandidate(BotCand););
618 SchedCandidate Cand = BotPending ? TopCand : BotCand;
619 SchedCandidate TryCand = BotPending ? BotCand : TopCand;
620 PickedPending = BotPending && TopPending;
621
622 TryCand.Reason = NoCand;
623 if (BotPending || TopPending) {
624 PickedPending |= tryPendingCandidate(Cand, TopCand, nullptr);
625 } else {
626 tryCandidate(Cand, TryCand, nullptr);
627 }
628
629 if (TryCand.Reason != NoCand) {
630 Cand.setBest(TryCand);
631 }
632
633 LLVM_DEBUG(dbgs() << "Picking: "; traceCandidate(Cand););
634
635 IsTopNode = Cand.AtTop;
636 return Cand.SU;
637}
638
639// This function is mostly cut and pasted from
640// GenericScheduler::pickNode()
642 if (DAG->top() == DAG->bottom()) {
643 assert(Top.Available.empty() && Top.Pending.empty() &&
644 Bot.Available.empty() && Bot.Pending.empty() && "ReadyQ garbage");
645 return nullptr;
646 }
647 bool PickedPending;
648 SUnit *SU;
649 do {
650 PickedPending = false;
651 if (RegionPolicy.OnlyTopDown) {
653 if (!SU) {
654 CandPolicy NoPolicy;
655 TopCand.reset(NoPolicy);
656 pickNodeFromQueue(Top, NoPolicy, DAG->getTopRPTracker(), TopCand,
657 PickedPending,
658 /*IsBottomUp=*/false);
659 assert(TopCand.Reason != NoCand && "failed to find a candidate");
660 SU = TopCand.SU;
661 }
662 IsTopNode = true;
663 } else if (RegionPolicy.OnlyBottomUp) {
665 if (!SU) {
666 CandPolicy NoPolicy;
667 BotCand.reset(NoPolicy);
668 pickNodeFromQueue(Bot, NoPolicy, DAG->getBotRPTracker(), BotCand,
669 PickedPending,
670 /*IsBottomUp=*/true);
671 assert(BotCand.Reason != NoCand && "failed to find a candidate");
672 SU = BotCand.SU;
673 }
674 IsTopNode = false;
675 } else {
676 SU = pickNodeBidirectional(IsTopNode, PickedPending);
677 }
678 } while (SU->isScheduled);
679
680 if (PickedPending) {
681 unsigned ReadyCycle = IsTopNode ? SU->TopReadyCycle : SU->BotReadyCycle;
682 SchedBoundary &Zone = IsTopNode ? Top : Bot;
683 unsigned CurrentCycle = Zone.getCurrCycle();
684 if (ReadyCycle > CurrentCycle)
685 Zone.bumpCycle(ReadyCycle);
686
687 // FIXME: checkHazard() doesn't give information about which cycle the
688 // hazard will resolve so just keep bumping the cycle by 1. This could be
689 // made more efficient if checkHazard() returned more details.
690 while (Zone.checkHazard(SU))
691 Zone.bumpCycle(Zone.getCurrCycle() + 1);
692
693 Zone.releasePending();
694 }
695
696 if (SU->isTopReady())
697 Top.removeReady(SU);
698 if (SU->isBottomReady())
699 Bot.removeReady(SU);
700
701 LLVM_DEBUG(dbgs() << "Scheduling SU(" << SU->NodeNum << ") "
702 << *SU->getInstr());
703 return SU;
704}
705
706void GCNSchedStrategy::schedNode(SUnit *SU, bool IsTopNode) {
707 if (useGCNTrackers()) {
708 MachineInstr *MI = SU->getInstr();
709 IsTopNode ? (void)DownwardTracker.advance(MI, false)
710 : UpwardTracker.recede(*MI);
711 }
712
713 return GenericScheduler::schedNode(SU, IsTopNode);
714}
715
720
723 if (!CurrentStage)
724 CurrentStage = SchedStages.begin();
725 else
726 CurrentStage++;
727
728 return CurrentStage != SchedStages.end();
729}
730
733 return std::next(CurrentStage) != SchedStages.end();
734}
735
737 assert(CurrentStage && std::next(CurrentStage) != SchedStages.end());
738 return *std::next(CurrentStage);
739}
740
742 SchedCandidate &TryCand,
743 SchedBoundary *Zone) const {
744 // Initialize the candidate if needed.
745 if (!Cand.isValid()) {
746 TryCand.Reason = NodeOrder;
747 return true;
748 }
749
750 // Bias PhysReg Defs and copies to their uses and defined respectively.
751 if (tryGreater(biasPhysReg(TryCand.SU, TryCand.AtTop),
752 biasPhysReg(Cand.SU, Cand.AtTop), TryCand, Cand, PhysReg))
753 return TryCand.Reason != NoCand;
754
755 // Avoid exceeding the target's limit.
756 if (DAG->isTrackingPressure() &&
757 tryPressure(TryCand.RPDelta.Excess, Cand.RPDelta.Excess, TryCand, Cand,
758 RegExcess, TRI, DAG->MF))
759 return TryCand.Reason != NoCand;
760
761 // Avoid increasing the max critical pressure in the scheduled region.
762 if (DAG->isTrackingPressure() &&
764 TryCand, Cand, RegCritical, TRI, DAG->MF))
765 return TryCand.Reason != NoCand;
766
767 bool SameBoundary = Zone != nullptr;
768 if (SameBoundary) {
771 TryCand, Cand, ResourceReduce))
772 return TryCand.Reason != NoCand;
774 Cand.ResDelta.DemandedResources, TryCand, Cand,
776 return TryCand.Reason != NoCand;
777 }
778
779 return false;
780}
781
794
799
801 SchedCandidate &TryCand,
802 SchedBoundary *Zone) const {
803 // Initialize the candidate if needed.
804 if (!Cand.isValid()) {
805 TryCand.Reason = NodeOrder;
806 return true;
807 }
808
809 // Avoid spilling by exceeding the register limit.
810 if (DAG->isTrackingPressure() &&
811 tryPressure(TryCand.RPDelta.Excess, Cand.RPDelta.Excess, TryCand, Cand,
812 RegExcess, TRI, DAG->MF))
813 return TryCand.Reason != NoCand;
814
815 // Bias PhysReg Defs and copies to their uses and defined respectively.
816 if (tryGreater(biasPhysReg(TryCand.SU, TryCand.AtTop),
817 biasPhysReg(Cand.SU, Cand.AtTop), TryCand, Cand, PhysReg))
818 return TryCand.Reason != NoCand;
819
820 bool SameBoundary = Zone != nullptr;
821 if (SameBoundary) {
822 // Prioritize instructions that read unbuffered resources by stall cycles.
823 if (tryLess(Zone->getLatencyStallCycles(TryCand.SU),
824 Zone->getLatencyStallCycles(Cand.SU), TryCand, Cand, Stall))
825 return TryCand.Reason != NoCand;
826
827 // Avoid critical resource consumption and balance the schedule.
830 TryCand, Cand, ResourceReduce))
831 return TryCand.Reason != NoCand;
833 Cand.ResDelta.DemandedResources, TryCand, Cand,
835 return TryCand.Reason != NoCand;
836
837 // Unconditionally try to reduce latency.
838 if (tryLatency(TryCand, Cand, *Zone))
839 return TryCand.Reason != NoCand;
840
841 // Weak edges are for clustering and other constraints.
842 if (tryLess(getWeakLeft(TryCand.SU, TryCand.AtTop),
843 getWeakLeft(Cand.SU, Cand.AtTop), TryCand, Cand, Weak))
844 return TryCand.Reason != NoCand;
845 }
846
847 // Keep clustered nodes together to encourage downstream peephole
848 // optimizations which may reduce resource requirements.
849 //
850 // This is a best effort to set things up for a post-RA pass. Optimizations
851 // like generating loads of multiple registers should ideally be done within
852 // the scheduler pass by combining the loads during DAG postprocessing.
853 unsigned CandZoneCluster = Cand.AtTop ? TopClusterID : BotClusterID;
854 unsigned TryCandZoneCluster = TryCand.AtTop ? TopClusterID : BotClusterID;
855 bool CandIsClusterSucc =
856 isTheSameCluster(CandZoneCluster, Cand.SU->ParentClusterIdx);
857 bool TryCandIsClusterSucc =
858 isTheSameCluster(TryCandZoneCluster, TryCand.SU->ParentClusterIdx);
859 if (tryGreater(TryCandIsClusterSucc, CandIsClusterSucc, TryCand, Cand,
860 Cluster))
861 return TryCand.Reason != NoCand;
862
863 // Avoid increasing the max critical pressure in the scheduled region.
864 if (DAG->isTrackingPressure() &&
866 TryCand, Cand, RegCritical, TRI, DAG->MF))
867 return TryCand.Reason != NoCand;
868
869 // Avoid increasing the max pressure of the entire region.
870 if (DAG->isTrackingPressure() &&
871 tryPressure(TryCand.RPDelta.CurrentMax, Cand.RPDelta.CurrentMax, TryCand,
872 Cand, RegMax, TRI, DAG->MF))
873 return TryCand.Reason != NoCand;
874
875 if (SameBoundary) {
876 // Fall through to original instruction order.
877 if ((Zone->isTop() && TryCand.SU->NodeNum < Cand.SU->NodeNum) ||
878 (!Zone->isTop() && TryCand.SU->NodeNum > Cand.SU->NodeNum)) {
879 TryCand.Reason = NodeOrder;
880 return true;
881 }
882 }
883 return false;
884}
885
891
892/// GCNMaxMemoryClauseSchedStrategy tries best to clause memory instructions as
893/// much as possible. This is achieved by:
894// 1. Prioritize clustered operations before stall latency heuristic.
895// 2. Prioritize long-latency-load before stall latency heuristic.
896///
897/// \param Cand provides the policy and current best candidate.
898/// \param TryCand refers to the next SUnit candidate, otherwise uninitialized.
899/// \param Zone describes the scheduled zone that we are extending, or nullptr
900/// if Cand is from a different zone than TryCand.
901/// \return \c true if TryCand is better than Cand (Reason is NOT NoCand)
903 SchedCandidate &TryCand,
904 SchedBoundary *Zone) const {
905 // Initialize the candidate if needed.
906 if (!Cand.isValid()) {
907 TryCand.Reason = NodeOrder;
908 return true;
909 }
910
911 // Bias PhysReg Defs and copies to their uses and defined respectively.
912 if (tryGreater(biasPhysReg(TryCand.SU, TryCand.AtTop),
913 biasPhysReg(Cand.SU, Cand.AtTop), TryCand, Cand, PhysReg))
914 return TryCand.Reason != NoCand;
915
916 if (DAG->isTrackingPressure()) {
917 // Avoid exceeding the target's limit.
918 if (tryPressure(TryCand.RPDelta.Excess, Cand.RPDelta.Excess, TryCand, Cand,
919 RegExcess, TRI, DAG->MF))
920 return TryCand.Reason != NoCand;
921
922 // Avoid increasing the max critical pressure in the scheduled region.
924 TryCand, Cand, RegCritical, TRI, DAG->MF))
925 return TryCand.Reason != NoCand;
926 }
927
928 // MaxMemoryClause-specific: We prioritize clustered instructions as we would
929 // get more benefit from clausing these memory instructions.
930 unsigned CandZoneCluster = Cand.AtTop ? TopClusterID : BotClusterID;
931 unsigned TryCandZoneCluster = TryCand.AtTop ? TopClusterID : BotClusterID;
932 bool CandIsClusterSucc =
933 isTheSameCluster(CandZoneCluster, Cand.SU->ParentClusterIdx);
934 bool TryCandIsClusterSucc =
935 isTheSameCluster(TryCandZoneCluster, TryCand.SU->ParentClusterIdx);
936 if (tryGreater(TryCandIsClusterSucc, CandIsClusterSucc, TryCand, Cand,
937 Cluster))
938 return TryCand.Reason != NoCand;
939
940 // We only compare a subset of features when comparing nodes between
941 // Top and Bottom boundary. Some properties are simply incomparable, in many
942 // other instances we should only override the other boundary if something
943 // is a clear good pick on one boundary. Skip heuristics that are more
944 // "tie-breaking" in nature.
945 bool SameBoundary = Zone != nullptr;
946 if (SameBoundary) {
947 // For loops that are acyclic path limited, aggressively schedule for
948 // latency. Within an single cycle, whenever CurrMOps > 0, allow normal
949 // heuristics to take precedence.
950 if (Rem.IsAcyclicLatencyLimited && !Zone->getCurrMOps() &&
951 tryLatency(TryCand, Cand, *Zone))
952 return TryCand.Reason != NoCand;
953
954 // MaxMemoryClause-specific: Prioritize long latency memory load
955 // instructions in top-bottom order to hide more latency. The mayLoad check
956 // is used to exclude store-like instructions, which we do not want to
957 // scheduler them too early.
958 bool TryMayLoad =
959 TryCand.SU->isInstr() && TryCand.SU->getInstr()->mayLoad();
960 bool CandMayLoad = Cand.SU->isInstr() && Cand.SU->getInstr()->mayLoad();
961
962 if (TryMayLoad || CandMayLoad) {
963 bool TryLongLatency =
964 TryCand.SU->Latency > 10 * Cand.SU->Latency && TryMayLoad;
965 bool CandLongLatency =
966 10 * TryCand.SU->Latency < Cand.SU->Latency && CandMayLoad;
967
968 if (tryGreater(Zone->isTop() ? TryLongLatency : CandLongLatency,
969 Zone->isTop() ? CandLongLatency : TryLongLatency, TryCand,
970 Cand, Stall))
971 return TryCand.Reason != NoCand;
972 }
973 // Prioritize instructions that read unbuffered resources by stall cycles.
974 if (tryLess(Zone->getLatencyStallCycles(TryCand.SU),
975 Zone->getLatencyStallCycles(Cand.SU), TryCand, Cand, Stall))
976 return TryCand.Reason != NoCand;
977 }
978
979 if (SameBoundary) {
980 // Weak edges are for clustering and other constraints.
981 if (tryLess(getWeakLeft(TryCand.SU, TryCand.AtTop),
982 getWeakLeft(Cand.SU, Cand.AtTop), TryCand, Cand, Weak))
983 return TryCand.Reason != NoCand;
984 }
985
986 // Avoid increasing the max pressure of the entire region.
987 if (DAG->isTrackingPressure() &&
988 tryPressure(TryCand.RPDelta.CurrentMax, Cand.RPDelta.CurrentMax, TryCand,
989 Cand, RegMax, TRI, DAG->MF))
990 return TryCand.Reason != NoCand;
991
992 if (SameBoundary) {
993 // Avoid critical resource consumption and balance the schedule.
996 TryCand, Cand, ResourceReduce))
997 return TryCand.Reason != NoCand;
999 Cand.ResDelta.DemandedResources, TryCand, Cand,
1001 return TryCand.Reason != NoCand;
1002
1003 // Avoid serializing long latency dependence chains.
1004 // For acyclic path limited loops, latency was already checked above.
1005 if (!RegionPolicy.DisableLatencyHeuristic && TryCand.Policy.ReduceLatency &&
1006 !Rem.IsAcyclicLatencyLimited && tryLatency(TryCand, Cand, *Zone))
1007 return TryCand.Reason != NoCand;
1008
1009 // Fall through to original instruction order.
1010 if (Zone->isTop() == (TryCand.SU->NodeNum < Cand.SU->NodeNum)) {
1011 assert(TryCand.SU->NodeNum != Cand.SU->NodeNum);
1012 TryCand.Reason = NodeOrder;
1013 return true;
1014 }
1015 }
1016
1017 return false;
1018}
1019
1021 MachineSchedContext *C, std::unique_ptr<MachineSchedStrategy> S)
1022 : ScheduleDAGMILive(C, std::move(S)), ST(MF.getSubtarget<GCNSubtarget>()),
1023 MFI(*MF.getInfo<SIMachineFunctionInfo>()),
1024 StartingOccupancy(MFI.getOccupancy()), MinOccupancy(StartingOccupancy),
1025 RegionLiveOuts(this, /*IsLiveOut=*/true) {
1026
1027 // We want regions with a single MI to be scheduled so that we can reason
1028 // about them correctly during scheduling stages that move MIs between regions
1029 // (e.g., rematerialization).
1031 LLVM_DEBUG(dbgs() << "Starting occupancy is " << StartingOccupancy << ".\n");
1032 if (RelaxedOcc) {
1033 MinOccupancy = std::min(MFI.getMinAllowedOccupancy(), StartingOccupancy);
1034 if (MinOccupancy != StartingOccupancy)
1035 LLVM_DEBUG(dbgs() << "Allowing Occupancy drops to " << MinOccupancy
1036 << ".\n");
1037 }
1038}
1039
1040std::unique_ptr<GCNSchedStage>
1041GCNScheduleDAGMILive::createSchedStage(GCNSchedStageID SchedStageID) {
1042 switch (SchedStageID) {
1044 return std::make_unique<OccInitialScheduleStage>(SchedStageID, *this);
1046 return std::make_unique<RewriteMFMAFormStage>(SchedStageID, *this);
1048 return std::make_unique<UnclusteredHighRPStage>(SchedStageID, *this);
1050 return std::make_unique<ClusteredLowOccStage>(SchedStageID, *this);
1052 return std::make_unique<PreRARematStage>(SchedStageID, *this);
1054 return std::make_unique<ILPInitialScheduleStage>(SchedStageID, *this);
1056 return std::make_unique<MemoryClauseInitialScheduleStage>(SchedStageID,
1057 *this);
1058 }
1059
1060 llvm_unreachable("Unknown SchedStageID.");
1061}
1062
1064 // Collect all scheduling regions. The actual scheduling is performed in
1065 // GCNScheduleDAGMILive::finalizeSchedule.
1066 Regions.push_back(std::pair(RegionBegin, RegionEnd));
1067}
1068
1070GCNScheduleDAGMILive::getRealRegPressure(unsigned RegionIdx) const {
1071 if (Regions[RegionIdx].first == Regions[RegionIdx].second)
1072 return llvm::getRegPressure(MRI, LiveIns[RegionIdx]);
1074 RPTracker.advance(Regions[RegionIdx].first, Regions[RegionIdx].second,
1075 &LiveIns[RegionIdx]);
1076 return RPTracker.moveMaxPressure();
1077}
1078
1080 MachineBasicBlock::iterator RegionEnd) {
1081 assert(RegionBegin != RegionEnd && "Region must not be empty");
1082 return &*skipDebugInstructionsBackward(std::prev(RegionEnd), RegionBegin);
1083}
1084
1085void GCNScheduleDAGMILive::computeBlockPressure(unsigned RegionIdx,
1086 const MachineBasicBlock *MBB) {
1087 GCNDownwardRPTracker RPTracker(*LIS);
1088
1089 // If the block has the only successor then live-ins of that successor are
1090 // live-outs of the current block. We can reuse calculated live set if the
1091 // successor will be sent to scheduling past current block.
1092
1093 // However, due to the bug in LiveInterval analysis it may happen that two
1094 // predecessors of the same successor block have different lane bitmasks for
1095 // a live-out register. Workaround that by sticking to one-to-one relationship
1096 // i.e. one predecessor with one successor block.
1097 const MachineBasicBlock *OnlySucc = nullptr;
1098 if (MBB->succ_size() == 1) {
1099 auto *Candidate = *MBB->succ_begin();
1100 if (!Candidate->empty() && Candidate->pred_size() == 1) {
1101 SlotIndexes *Ind = LIS->getSlotIndexes();
1102 if (Ind->getMBBStartIdx(MBB) < Ind->getMBBStartIdx(Candidate))
1103 OnlySucc = Candidate;
1104 }
1105 }
1106
1107 // Scheduler sends regions from the end of the block upwards.
1108 size_t CurRegion = RegionIdx;
1109 for (size_t E = Regions.size(); CurRegion != E; ++CurRegion)
1110 if (Regions[CurRegion].first->getParent() != MBB)
1111 break;
1112 --CurRegion;
1113
1114 auto I = MBB->begin();
1115 auto LiveInIt = MBBLiveIns.find(MBB);
1116 auto &Rgn = Regions[CurRegion];
1117 auto *NonDbgMI = &*skipDebugInstructionsForward(Rgn.first, Rgn.second);
1118 if (LiveInIt != MBBLiveIns.end()) {
1119 auto LiveIn = std::move(LiveInIt->second);
1120 RPTracker.reset(*MBB->begin(), MBB->end(), &LiveIn);
1121 MBBLiveIns.erase(LiveInIt);
1122 } else {
1123 I = Rgn.first;
1124 auto LRS = BBLiveInMap.lookup(NonDbgMI);
1125#ifdef EXPENSIVE_CHECKS
1126 assert(isEqual(getLiveRegsBefore(*NonDbgMI, *LIS), LRS));
1127#endif
1128 RPTracker.reset(*I, I->getParent()->end(), &LRS);
1129 }
1130
1131 for (;;) {
1132 I = RPTracker.getNext();
1133
1134 if (Regions[CurRegion].first == I || NonDbgMI == I) {
1135 LiveIns[CurRegion] = RPTracker.getLiveRegs();
1136 RPTracker.clearMaxPressure();
1137 }
1138
1139 if (Regions[CurRegion].second == I) {
1140 Pressure[CurRegion] = RPTracker.moveMaxPressure();
1141 if (CurRegion-- == RegionIdx)
1142 break;
1143 auto &Rgn = Regions[CurRegion];
1144 NonDbgMI = &*skipDebugInstructionsForward(Rgn.first, Rgn.second);
1145 }
1146 RPTracker.advanceBeforeNext();
1147 RPTracker.advanceToNext();
1148 }
1149
1150 if (OnlySucc) {
1151 if (I != MBB->end()) {
1152 RPTracker.advanceBeforeNext();
1153 RPTracker.advanceToNext();
1154 RPTracker.advance(MBB->end());
1155 }
1156 MBBLiveIns[OnlySucc] = RPTracker.moveLiveRegs();
1157 }
1158}
1159
1161GCNScheduleDAGMILive::getRegionLiveInMap() const {
1162 assert(!Regions.empty());
1163 std::vector<MachineInstr *> RegionFirstMIs;
1164 RegionFirstMIs.reserve(Regions.size());
1165 for (auto &[RegionBegin, RegionEnd] : reverse(Regions))
1166 RegionFirstMIs.push_back(
1168
1169 return getLiveRegMap(RegionFirstMIs, /*After=*/false, *LIS);
1170}
1171
1173GCNScheduleDAGMILive::getRegionLiveOutMap() const {
1174 assert(!Regions.empty());
1175 std::vector<MachineInstr *> RegionLastMIs;
1176 RegionLastMIs.reserve(Regions.size());
1177 for (auto &[RegionBegin, RegionEnd] : reverse(Regions)) {
1178 // Skip empty regions.
1179 if (RegionBegin == RegionEnd)
1180 continue;
1181 RegionLastMIs.push_back(getLastMIForRegion(RegionBegin, RegionEnd));
1182 }
1183 return getLiveRegMap(RegionLastMIs, /*After=*/true, *LIS);
1184}
1185
1187 IdxToInstruction.clear();
1188
1189 RegionLiveRegMap =
1190 IsLiveOut ? DAG->getRegionLiveOutMap() : DAG->getRegionLiveInMap();
1191 for (unsigned I = 0; I < DAG->Regions.size(); I++) {
1192 auto &[RegionBegin, RegionEnd] = DAG->Regions[I];
1193 // Skip empty regions.
1194 if (RegionBegin == RegionEnd)
1195 continue;
1196 MachineInstr *RegionKey =
1197 IsLiveOut ? getLastMIForRegion(RegionBegin, RegionEnd) : &*RegionBegin;
1198 IdxToInstruction[I] = RegionKey;
1199 }
1200}
1201
1203 // Start actual scheduling here. This function is called by the base
1204 // MachineScheduler after all regions have been recorded by
1205 // GCNScheduleDAGMILive::schedule().
1206 LiveIns.resize(Regions.size());
1207 Pressure.resize(Regions.size());
1208 RegionsWithHighRP.resize(Regions.size());
1209 RegionsWithExcessRP.resize(Regions.size());
1210 RegionsWithIGLPInstrs.resize(Regions.size());
1211 RegionsWithHighRP.reset();
1212 RegionsWithExcessRP.reset();
1213 RegionsWithIGLPInstrs.reset();
1214
1215 runSchedStages();
1216}
1217
1218void GCNScheduleDAGMILive::runSchedStages() {
1219 LLVM_DEBUG(dbgs() << "All regions recorded, starting actual scheduling.\n");
1220
1221 GCNSchedStrategy &S = static_cast<GCNSchedStrategy &>(*SchedImpl);
1222 if (!Regions.empty()) {
1223 BBLiveInMap = getRegionLiveInMap();
1224 if (S.useGCNTrackers())
1225 RegionLiveOuts.buildLiveRegMap();
1226 }
1227
1228#ifdef DUMP_MAX_REG_PRESSURE
1232 LIS->dump();
1233 }
1234#endif
1235
1236 while (S.advanceStage()) {
1237 auto Stage = createSchedStage(S.getCurrentStage());
1238 if (!Stage->initGCNSchedStage())
1239 continue;
1240
1241 for (auto Region : Regions) {
1242 RegionBegin = Region.first;
1243 RegionEnd = Region.second;
1244 // Setup for scheduling the region and check whether it should be skipped.
1245 if (!Stage->initGCNRegion()) {
1246 Stage->advanceRegion();
1247 exitRegion();
1248 continue;
1249 }
1250
1251 if (S.useGCNTrackers()) {
1252 const unsigned RegionIdx = Stage->getRegionIdx();
1253 S.getDownwardTracker()->reset(MRI, LiveIns[RegionIdx]);
1255 MRI, RegionLiveOuts.getLiveRegsForRegionIdx(RegionIdx));
1256 }
1257
1259 Stage->finalizeGCNRegion();
1260 Stage->advanceRegion();
1261 exitRegion();
1262 }
1263
1264 Stage->finalizeGCNSchedStage();
1265 }
1266
1267#ifdef DUMP_MAX_REG_PRESSURE
1271 LIS->dump();
1272 }
1273#endif
1274}
1275
1276#ifndef NDEBUG
1278 switch (StageID) {
1280 OS << "Max Occupancy Initial Schedule";
1281 break;
1283 OS << "Instruction Rewriting Reschedule";
1284 break;
1286 OS << "Unclustered High Register Pressure Reschedule";
1287 break;
1289 OS << "Clustered Low Occupancy Reschedule";
1290 break;
1292 OS << "Pre-RA Rematerialize";
1293 break;
1295 OS << "Max ILP Initial Schedule";
1296 break;
1298 OS << "Max memory clause Initial Schedule";
1299 break;
1300 }
1301
1302 return OS;
1303}
1304#endif
1305
1309
1311 if (!DAG.LIS)
1312 return false;
1313
1314 LLVM_DEBUG(dbgs() << "Starting scheduling stage: " << StageID << "\n");
1315 return true;
1316}
1317
1318void RewriteMFMAFormStage::findReachingDefs(
1319 MachineOperand &UseMO, LiveIntervals *LIS,
1320 SmallVectorImpl<SlotIndex> &DefIdxs) {
1321 MachineInstr *UseMI = UseMO.getParent();
1322 LiveInterval &UseLI = LIS->getInterval(UseMO.getReg());
1323 VNInfo *VNI = UseLI.getVNInfoAt(LIS->getInstructionIndex(*UseMI));
1324
1325 // If the def is not a PHI, then it must be the only reaching def.
1326 if (!VNI->isPHIDef()) {
1327 DefIdxs.push_back(VNI->def);
1328 return;
1329 }
1330
1331 SmallPtrSet<MachineBasicBlock *, 8> Visited = {UseMI->getParent()};
1333
1334 // Mark the predecessor blocks for traversal
1335 for (MachineBasicBlock *PredMBB : UseMI->getParent()->predecessors()) {
1336 Worklist.push_back(PredMBB);
1337 Visited.insert(PredMBB);
1338 }
1339
1340 while (!Worklist.empty()) {
1341 MachineBasicBlock *CurrMBB = Worklist.pop_back_val();
1342
1343 SlotIndex CurrMBBEnd = LIS->getMBBEndIdx(CurrMBB);
1344 VNInfo *VNI = UseLI.getVNInfoAt(CurrMBBEnd.getPrevSlot());
1345
1346 MachineBasicBlock *DefMBB = LIS->getMBBFromIndex(VNI->def);
1347
1348 // If there is a def in this block, then add it to the list. This is the
1349 // reaching def of this path.
1350 if (!VNI->isPHIDef()) {
1351 DefIdxs.push_back(VNI->def);
1352 continue;
1353 }
1354
1355 for (MachineBasicBlock *PredMBB : DefMBB->predecessors()) {
1356 if (Visited.insert(PredMBB).second)
1357 Worklist.push_back(PredMBB);
1358 }
1359 }
1360}
1361
1362void RewriteMFMAFormStage::findReachingUses(
1363 const MachineInstr *DefMI, LiveIntervals *LIS,
1364 SmallVectorImpl<MachineOperand *> &ReachingUses) {
1365 SlotIndex DefIdx = LIS->getInstructionIndex(*DefMI);
1366 for (MachineOperand &UseMO :
1367 DAG.MRI.use_nodbg_operands(DefMI->getOperand(0).getReg())) {
1368 SmallVector<SlotIndex, 8> ReachingDefIndexes;
1369 findReachingDefs(UseMO, LIS, ReachingDefIndexes);
1370
1371 // If we find a use that contains this DefMI in its reachingDefs, then it is
1372 // a reaching use.
1373 if (any_of(ReachingDefIndexes, [DefIdx](SlotIndex RDIdx) {
1374 return SlotIndex::isSameInstr(RDIdx, DefIdx);
1375 }))
1376 ReachingUses.push_back(&UseMO);
1377 }
1378}
1379
1381 // We only need to run this pass if the architecture supports AGPRs.
1382 // Additionally, we don't use AGPRs at occupancy levels above 1 so there
1383 // is no need for this pass in that case, either.
1384 const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
1385 if (!ST.hasGFX90AInsts() || MFI.getMinWavesPerEU() > 1)
1386 return false;
1387
1388 RegionsWithExcessArchVGPR.resize(DAG.Regions.size());
1389 RegionsWithExcessArchVGPR.reset();
1390 for (unsigned Region = 0; Region < DAG.Regions.size(); Region++) {
1392 if (PressureBefore.getArchVGPRNum() > ST.getAddressableNumArchVGPRs())
1393 RegionsWithExcessArchVGPR[Region] = true;
1394 }
1395
1396 if (RegionsWithExcessArchVGPR.none())
1397 return false;
1398
1399 TII = ST.getInstrInfo();
1400 SRI = ST.getRegisterInfo();
1401
1402 std::vector<std::pair<MachineInstr *, unsigned>> RewriteCands;
1405
1406 if (!initHeuristics(RewriteCands, CopyForUse, CopyForDef))
1407 return false;
1408
1409 int64_t Cost = getRewriteCost(RewriteCands, CopyForUse, CopyForDef);
1410
1411 // If we haven't found the beneficial conditions, prefer the VGPR form which
1412 // may result in less cross RC copies.
1413 if (Cost > 0)
1414 return false;
1415
1416 return rewrite(RewriteCands);
1417}
1418
1421 return false;
1422
1424 return false;
1425
1426 if (DAG.RegionsWithHighRP.none() && DAG.RegionsWithExcessRP.none())
1427 return false;
1428
1429 SavedMutations.swap(DAG.Mutations);
1430 DAG.addMutation(
1432
1433 InitialOccupancy = DAG.MinOccupancy;
1434 // Aggressively try to reduce register pressure in the unclustered high RP
1435 // stage. Temporarily increase occupancy target in the region.
1436 TempTargetOccupancy = MFI.getMaxWavesPerEU() > DAG.MinOccupancy
1437 ? InitialOccupancy + 1
1438 : InitialOccupancy;
1439 IsAnyRegionScheduled = false;
1440 S.SGPRLimitBias = S.HighRPSGPRBias;
1441 S.VGPRLimitBias = S.HighRPVGPRBias;
1442
1443 LLVM_DEBUG(
1444 dbgs()
1445 << "Retrying function scheduling without clustering. "
1446 "Aggressively try to reduce register pressure to achieve occupancy "
1447 << TempTargetOccupancy << ".\n");
1448
1449 return true;
1450}
1451
1454 return false;
1455
1457 return false;
1458
1459 // Don't bother trying to improve ILP in lower RP regions if occupancy has not
1460 // been dropped. All regions will have already been scheduled with the ideal
1461 // occupancy targets.
1462 if (DAG.StartingOccupancy <= DAG.MinOccupancy)
1463 return false;
1464
1465 LLVM_DEBUG(
1466 dbgs() << "Retrying function scheduling with lowest recorded occupancy "
1467 << DAG.MinOccupancy << ".\n");
1468 return true;
1469}
1470
1471/// Allows to easily filter for this stage's debug output.
1472#define REMAT_PREFIX "[PreRARemat] "
1473#define REMAT_DEBUG(X) LLVM_DEBUG(dbgs() << REMAT_PREFIX; X;)
1474
1475#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
1476Printable PreRARematStage::ScoredRemat::print() const {
1477 return Printable([&](raw_ostream &OS) {
1478 OS << '(' << MaxFreq << ", " << FreqDiff << ", " << RegionImpact << ')';
1479 });
1480}
1481#endif
1482
1484 // FIXME: This pass will invalidate cached BBLiveInMap and MBBLiveIns for
1485 // regions inbetween the defs and region we sinked the def to. Will need to be
1486 // fixed if there is another pass after this pass.
1487 assert(!S.hasNextStage());
1488
1489 if (!GCNSchedStage::initGCNSchedStage() || DAG.Regions.size() <= 1)
1490 return false;
1491
1492#ifndef NDEBUG
1493 auto PrintTargetRegions = [&]() -> void {
1494 if (TargetRegions.none()) {
1495 dbgs() << REMAT_PREFIX << "No target regions\n";
1496 return;
1497 }
1498 dbgs() << REMAT_PREFIX << "Target regions:\n";
1499 for (unsigned I : TargetRegions.set_bits())
1500 dbgs() << REMAT_PREFIX << " [" << I << "] " << RPTargets[I] << '\n';
1501 };
1502#endif
1503
1504 // Set an objective for the stage based on current RP in each region.
1505 REMAT_DEBUG({
1506 dbgs() << "Analyzing ";
1507 MF.getFunction().printAsOperand(dbgs(), false);
1508 dbgs() << ": ";
1509 });
1510 if (!setObjective()) {
1511 LLVM_DEBUG(dbgs() << "no objective to achieve, occupancy is maximal at "
1512 << MFI.getMaxWavesPerEU() << '\n');
1513 return false;
1514 }
1515 LLVM_DEBUG({
1516 if (TargetOcc) {
1517 dbgs() << "increase occupancy from " << *TargetOcc - 1 << '\n';
1518 } else {
1519 dbgs() << "reduce spilling (minimum target occupancy is "
1520 << MFI.getMinWavesPerEU() << ")\n";
1521 }
1522 PrintTargetRegions();
1523 });
1524
1525 // We need up-to-date live-out info. to query live-out register masks in
1526 // regions containing rematerializable instructions.
1527 DAG.RegionLiveOuts.buildLiveRegMap();
1528
1529 if (!Remater.analyze()) {
1530 REMAT_DEBUG(dbgs() << "No rematerializable registers\n");
1531 return false;
1532 }
1533 const ScoredRemat::FreqInfo FreqInfo(MF, DAG);
1534
1535 // Set of registers already marked for potential remterialization; used to
1536 // avoid rematerialization chains.
1537 SmallSet<Register, 4> MarkedRegs;
1538
1539 // Collect candidates. We have more restrictions on what we can track here
1540 // compared to the rematerializer.
1541 SmallVector<ScoredRemat, 8> Candidates;
1542 SmallVector<unsigned> CandidateOrder;
1543 for (unsigned RegIdx = 0, E = Remater.getNumRegs(); RegIdx < E; ++RegIdx) {
1544 const Rematerializer::Reg &CandReg = Remater.getReg(RegIdx);
1545
1546 // All users must be in a single region.
1547 if (CandReg.Uses.size() != 1)
1548 continue;
1549 const auto [UseRegion, Users] = *CandReg.Uses.begin();
1550
1551 // Rematerialization moves the defining instruction into the region of its
1552 // use, which may sit under different control dependencies (e.g., across a
1553 // change of EXEC). Convergent operations must not be made control-dependent
1554 // on additional values, so they cannot be safely relocated this way. This
1555 // mirrors the check MachineSink performs before sinking an instruction.
1556 if (any_of(CandReg.Defs,
1557 [](const MachineInstr *DefMI) { return DefMI->isConvergent(); }))
1558 continue;
1559
1560 // We further filter the registers that we can rematerialize based on our
1561 // current tracking capabilities in the stage. Users cannot themselves be
1562 // marked rematerializable, and no register operand of the defining MI can
1563 // be marked rematerializable. We also do not rematerialize an instruction
1564 // if it uses registers that aren't available at its use. This ensures that
1565 // we are not extending any live range while rematerializing.
1566 if (llvm::any_of(Users, [&MarkedRegs](const MachineInstr *UserMI) {
1567 assert(UserMI->getNumOperands() > 0 &&
1568 "user must have at least one operand");
1569 const MachineOperand &UseMO = UserMI->getOperand(0);
1570 return UseMO.isReg() && MarkedRegs.contains(UseMO.getReg());
1571 }))
1572 continue;
1573 MachineInstr *FirstUseMI =
1574 CandReg.getRegionUseBounds(UseRegion, *DAG.LIS).first;
1575 assert(FirstUseMI && "there must be a user in the region");
1576 SlotIndex FirstUseIdx =
1577 DAG.LIS->getInstructionIndex(*FirstUseMI).getRegSlot(true);
1578 SlotIndex RefIdx =
1579 DAG.LIS->getInstructionIndex(*CandReg.getLastDef()).getRegSlot(true);
1580 if (llvm::any_of(CandReg.Dependencies, [&](RegisterIdx DepRegIdx) {
1581 const Rematerializer::Reg &DepReg = Remater.getReg(DepRegIdx);
1582 Register DepDefReg = DepReg.getDefReg();
1583 return MarkedRegs.contains(DepDefReg) ||
1584 !Remater.isRegIdenticalAtUses(DepDefReg, DepReg.Mask, RefIdx,
1585 {FirstUseIdx});
1586 }))
1587 continue;
1588 if (llvm::any_of(Remater.getUnrematableDeps(RegIdx),
1589 [&](const std::pair<Register, LaneBitmask> &RegAndMask) {
1590 const auto &[Reg, Mask] = RegAndMask;
1591 return !Remater.isRegIdenticalAtUses(Reg, Mask, RefIdx,
1592 {FirstUseIdx});
1593 }))
1594 continue;
1595
1596 MarkedRegs.insert(CandReg.getDefReg());
1597 ScoredRemat &Cand = Candidates.emplace_back();
1598 Cand.init(RegIdx, FreqInfo, Remater, DAG);
1599 Cand.update(TargetRegions, RPTargets, FreqInfo, !TargetOcc);
1600 if (!Cand.hasNullScore())
1601 CandidateOrder.push_back(Candidates.size() - 1);
1602 }
1603
1604 if (TargetOcc) {
1605 // Every rematerialization we do here is likely to move the instruction
1606 // into a higher frequency region, increasing the total sum latency of the
1607 // instruction itself. This is acceptable if we are eliminating a spill in
1608 // the process, but when the goal is increasing occupancy we get nothing
1609 // out of rematerialization if occupancy is not increased in the end; in
1610 // such cases we want to roll back the rematerialization.
1611 Rollback = std::make_unique<RollbackSupport>(Remater);
1612 }
1613
1614 // Rematerialize registers in successive rounds until all RP targets are
1615 // satisifed or until we run out of rematerialization candidates.
1616 BitVector RecomputeRP(DAG.Regions.size());
1617 for (;;) {
1618 RecomputeRP.reset();
1619
1620 // Sort candidates in increasing score order.
1621 sort(CandidateOrder, [&](unsigned LHSIndex, unsigned RHSIndex) {
1622 return Candidates[LHSIndex] < Candidates[RHSIndex];
1623 });
1624
1625 REMAT_DEBUG({
1626 dbgs() << "==== NEW REMAT ROUND ====\n"
1627 << REMAT_PREFIX
1628 << "Candidates with non-null score, in rematerialization order:\n";
1629 for (const ScoredRemat &Cand : reverse(Candidates)) {
1630 dbgs() << REMAT_PREFIX << " " << Cand.print() << " | "
1631 << Remater.printRematReg(Cand.RegIdx) << '\n';
1632 }
1633 PrintTargetRegions();
1634 });
1635
1636 // Rematerialize registers in decreasing score order until we estimate
1637 // that all RP targets are satisfied or until rematerialization candidates
1638 // are no longer useful to decrease RP.
1639 while (!CandidateOrder.empty()) {
1640 const ScoredRemat &Cand = Candidates[CandidateOrder.back()];
1641 const Rematerializer::Reg &Reg = Remater.getReg(Cand.RegIdx);
1642
1643 // When previous rematerializations in this round have already satisfied
1644 // RP targets in all regions this rematerialization can impact, we have a
1645 // good indication that our scores have diverged significantly from
1646 // reality, in which case we interrupt this round and re-score. This also
1647 // ensures that every rematerialization we perform is possibly impactful
1648 // in at least one target region.
1649 if (!Cand.maybeBeneficial(TargetRegions, RPTargets)) {
1650 REMAT_DEBUG(dbgs() << "Interrupt round on stale score for "
1651 << Cand.print() << " | "
1652 << Remater.printRematReg(Cand.RegIdx));
1653 break;
1654 }
1655 CandidateOrder.pop_back();
1656
1657#ifdef EXPENSIVE_CHECKS
1658 // All uses are known to be available / live at the remat point. Thus,
1659 // the uses should already be live in to the using region.
1660 for (const MachineInstr *DefMI : Reg.Defs) {
1661 for (const MachineOperand &MO : DefMI->operands()) {
1662 // Exclude the defined register. We are rematerializing all
1663 // instructions defining it so we don't care that its value is
1664 // available at the remat point.
1665 if (!MO.isReg() || !MO.getReg() || !MO.readsReg() || MO.isDef())
1666 continue;
1667
1668 Register UseReg = MO.getReg();
1669 if (!UseReg.isVirtual())
1670 continue;
1671
1672 LiveInterval &LI = DAG.LIS->getInterval(UseReg);
1673 LaneBitmask LM = DAG.MRI.getMaxLaneMaskForVReg(MO.getReg());
1674 if (LI.hasSubRanges() && MO.getSubReg())
1675 LM = DAG.TRI->getSubRegIndexLaneMask(MO.getSubReg());
1676
1677 const unsigned UseRegion = Reg.Uses.begin()->first;
1678 LaneBitmask LiveInMask = DAG.LiveIns[UseRegion].at(UseReg);
1679 LaneBitmask UncoveredLanes = LM & ~(LiveInMask & LM);
1680 // If this register has lanes not covered by the LiveIns, be sure they
1681 // do not map to any subrange. ref:
1682 // machine-scheduler-sink-trivial-remats.mir::omitted_subrange
1683 if (UncoveredLanes.any()) {
1684 assert(LI.hasSubRanges());
1685 for (LiveInterval::SubRange &SR : LI.subranges())
1686 assert((SR.LaneMask & UncoveredLanes).none());
1687 }
1688 }
1689 }
1690#endif
1691
1692 // Remove the register from all regions where it is a live-in or live-out,
1693 // then rematerialize the register.
1694 REMAT_DEBUG(dbgs() << "** REMAT " << Remater.printRematReg(Cand.RegIdx)
1695 << '\n');
1696 removeFromLiveMaps(Reg.getDefReg(), Cand.LiveIn, Cand.LiveOut);
1697 if (Rollback) {
1698 Rollback->LiveMapUpdates.emplace_back(Cand.RegIdx, Cand.LiveIn,
1699 Cand.LiveOut);
1700 }
1701 Cand.rematerialize(Remater);
1702
1703 // Adjust RP targets. The save is guaranteed in regions in which the
1704 // register is live-through and unused but optimistic in all other regions
1705 // where the register is live.
1706 updateRPTargets(Cand.Live, Cand.RPSave);
1707 RecomputeRP |= Cand.UnpredictableRPSave;
1708 RescheduleRegions |= Cand.Live;
1709 if (!TargetRegions.any()) {
1710 REMAT_DEBUG(dbgs() << "All targets cleared, verifying...\n");
1711 break;
1712 }
1713 }
1714
1715 if (!updateAndVerifyRPTargets(RecomputeRP) && !TargetRegions.any()) {
1716 REMAT_DEBUG(dbgs() << "Objectives achieved!\n");
1717 break;
1718 }
1719
1720 // Update the score of remaining candidates and filter out those that have
1721 // become useless from the vector. Candidates never become useful after
1722 // having been useless for a round, so we can freely drop them without
1723 // losing any future rematerialization opportunity.
1724 unsigned NumUsefulCandidates = 0;
1725 for (unsigned CandIdx : CandidateOrder) {
1726 ScoredRemat &Candidate = Candidates[CandIdx];
1727 Candidate.update(TargetRegions, RPTargets, FreqInfo, !TargetOcc);
1728 if (!Candidate.hasNullScore())
1729 CandidateOrder[NumUsefulCandidates++] = CandIdx;
1730 }
1731 if (NumUsefulCandidates == 0) {
1732 REMAT_DEBUG(dbgs() << "Stop on exhausted rematerialization candidates\n");
1733 break;
1734 }
1735 CandidateOrder.truncate(NumUsefulCandidates);
1736 }
1737
1738 if (RescheduleRegions.none())
1739 return false;
1740
1741 // Commit all pressure changes to the DAG and compute minimum achieved
1742 // occupancy in impacted regions.
1743 REMAT_DEBUG(dbgs() << "==== REMAT RESULTS ====\n");
1744 unsigned DynamicVGPRBlockSize = MFI.getDynamicVGPRBlockSize();
1745 for (unsigned I : RescheduleRegions.set_bits()) {
1746 DAG.Pressure[I] = RPTargets[I].getCurrentRP();
1747 REMAT_DEBUG(dbgs() << '[' << I << "] Achieved occupancy "
1748 << DAG.Pressure[I].getOccupancy(ST, DynamicVGPRBlockSize)
1749 << " (" << RPTargets[I] << ")\n");
1750 }
1751 AchievedOcc = MFI.getMaxWavesPerEU();
1752 for (const GCNRegPressure &RP : DAG.Pressure) {
1753 AchievedOcc =
1754 std::min(AchievedOcc, RP.getOccupancy(ST, DynamicVGPRBlockSize));
1755 }
1756
1757 REMAT_DEBUG({
1758 dbgs() << "Retrying function scheduling with new min. occupancy of "
1759 << AchievedOcc << " from rematerializing (original was "
1760 << DAG.MinOccupancy;
1761 if (TargetOcc)
1762 dbgs() << ", target was " << *TargetOcc;
1763 dbgs() << ")\n";
1764 });
1765
1766 DAG.setTargetOccupancy(getStageTargetOccupancy());
1767 return true;
1768}
1769
1771 DAG.finishBlock();
1772 LLVM_DEBUG(dbgs() << "Ending scheduling stage: " << StageID << "\n");
1773}
1774
1776 SavedMutations.swap(DAG.Mutations);
1777 S.SGPRLimitBias = S.VGPRLimitBias = 0;
1778 if (DAG.MinOccupancy > InitialOccupancy) {
1779 assert(IsAnyRegionScheduled);
1781 << " stage successfully increased occupancy to "
1782 << DAG.MinOccupancy << '\n');
1783 } else if (!IsAnyRegionScheduled) {
1784 assert(DAG.MinOccupancy == InitialOccupancy);
1786 << ": No regions scheduled, min occupancy stays at "
1787 << DAG.MinOccupancy << ", MFI occupancy stays at "
1788 << MFI.getOccupancy() << ".\n");
1789 }
1790
1792}
1793
1795 // Skip empty scheduling region.
1796 if (DAG.begin() == DAG.end())
1797 return false;
1798
1799 // Check whether this new region is also a new block.
1800 if (DAG.RegionBegin->getParent() != CurrentMBB)
1801 setupNewBlock();
1802
1803 unsigned NumRegionInstrs = std::distance(DAG.begin(), DAG.end());
1804 DAG.enterRegion(CurrentMBB, DAG.begin(), DAG.end(), NumRegionInstrs);
1805
1806 // Skip regions with 1 schedulable instruction.
1807 if (DAG.begin() == std::prev(DAG.end()))
1808 return false;
1809
1810 LLVM_DEBUG(dbgs() << "********** MI Scheduling **********\n");
1811 LLVM_DEBUG(dbgs() << MF.getName() << ":" << printMBBReference(*CurrentMBB)
1812 << " " << CurrentMBB->getName()
1813 << "\n From: " << *DAG.begin() << " To: ";
1814 if (DAG.RegionEnd != CurrentMBB->end()) dbgs() << *DAG.RegionEnd;
1815 else dbgs() << "End";
1816 dbgs() << " RegionInstrs: " << NumRegionInstrs << '\n');
1817
1818 // Save original instruction order before scheduling for possible revert.
1819 Unsched.clear();
1820 Unsched.reserve(DAG.NumRegionInstrs);
1823 const SIInstrInfo *SII = static_cast<const SIInstrInfo *>(DAG.TII);
1824 for (auto &I : DAG) {
1825 Unsched.push_back(&I);
1826 if (SII->isIGLPMutationOnly(I.getOpcode()))
1827 DAG.RegionsWithIGLPInstrs[RegionIdx] = true;
1828 }
1829 } else {
1830 for (auto &I : DAG)
1831 Unsched.push_back(&I);
1832 }
1833
1834 PressureBefore = DAG.Pressure[RegionIdx];
1835
1836 LLVM_DEBUG(
1837 dbgs() << "Pressure before scheduling:\nRegion live-ins:"
1838 << print(DAG.LiveIns[RegionIdx], DAG.MRI)
1839 << "Region live-in pressure: "
1840 << print(llvm::getRegPressure(DAG.MRI, DAG.LiveIns[RegionIdx]))
1841 << "Region register pressure: " << print(PressureBefore));
1842
1843 S.HasHighPressure = false;
1844 S.KnownExcessRP = isRegionWithExcessRP();
1845
1846 if (DAG.RegionsWithIGLPInstrs[RegionIdx] &&
1848 SavedMutations.clear();
1849 SavedMutations.swap(DAG.Mutations);
1850 bool IsInitialStage = StageID == GCNSchedStageID::OccInitialSchedule ||
1852 DAG.addMutation(createIGroupLPDAGMutation(
1853 IsInitialStage ? AMDGPU::SchedulingPhase::Initial
1855 }
1856
1857 return true;
1858}
1859
1861 // Only reschedule regions that have excess register pressure (i.e. spilling)
1862 // or had minimum occupancy at the beginning of the stage (as long as
1863 // rescheduling of previous regions did not make occupancy drop back down to
1864 // the initial minimum).
1865 unsigned DynamicVGPRBlockSize = DAG.MFI.getDynamicVGPRBlockSize();
1866 // If no region has been scheduled yet, the DAG has not yet been updated with
1867 // the occupancy target. So retrieve it from the temporary.
1868 unsigned CurrentTargetOccupancy =
1869 IsAnyRegionScheduled ? DAG.MinOccupancy : TempTargetOccupancy;
1870 if (!DAG.RegionsWithExcessRP[RegionIdx] &&
1871 (CurrentTargetOccupancy <= InitialOccupancy ||
1872 DAG.Pressure[RegionIdx].getOccupancy(ST, DynamicVGPRBlockSize) !=
1873 InitialOccupancy))
1874 return false;
1875
1876 bool IsSchedulingThisRegion = GCNSchedStage::initGCNRegion();
1877 // If this is the first region scheduled during this stage, make the target
1878 // occupancy changes in the DAG and MFI.
1879 if (!IsAnyRegionScheduled && IsSchedulingThisRegion) {
1880 IsAnyRegionScheduled = true;
1881 if (MFI.getMaxWavesPerEU() > DAG.MinOccupancy)
1882 DAG.setTargetOccupancy(TempTargetOccupancy);
1883 }
1884 return IsSchedulingThisRegion;
1885}
1886
1888 // We may need to reschedule this region if it wasn't rescheduled in the last
1889 // stage, or if we found it was testing critical register pressure limits in
1890 // the unclustered reschedule stage. The later is because we may not have been
1891 // able to raise the min occupancy in the previous stage so the region may be
1892 // overly constrained even if it was already rescheduled.
1893 if (!DAG.RegionsWithHighRP[RegionIdx])
1894 return false;
1895
1897}
1898
1900 return !RevertAllRegions && RescheduleRegions[RegionIdx] &&
1902}
1903
1905 if (CurrentMBB)
1906 DAG.finishBlock();
1907
1908 CurrentMBB = DAG.RegionBegin->getParent();
1909 DAG.startBlock(CurrentMBB);
1910 // Get real RP for the region if it hasn't be calculated before. After the
1911 // initial schedule stage real RP will be collected after scheduling.
1915 DAG.computeBlockPressure(RegionIdx, CurrentMBB);
1916}
1917
1919 DAG.Regions[RegionIdx] = std::pair(DAG.RegionBegin, DAG.RegionEnd);
1920 if (S.HasHighPressure)
1921 DAG.RegionsWithHighRP[RegionIdx] = true;
1922
1923 // Revert scheduling if we have dropped occupancy or there is some other
1924 // reason that the original schedule is better.
1926
1927 if (DAG.RegionsWithIGLPInstrs[RegionIdx] &&
1929 SavedMutations.swap(DAG.Mutations);
1930}
1931
1934 // When the goal is to increase occupancy, all regions must reach the target
1935 // occupancy for rematerializations to be possibly useful, otherwise we will
1936 // just hurt latency for no benefit. If minimum occupancy drops below the
1937 // target there is no point in trying to re-schedule further regions.
1938 if (!TargetOcc)
1939 return;
1940 RegionReverts.emplace_back(RegionIdx, Unsched, PressureBefore);
1941 if (DAG.MinOccupancy < *TargetOcc) {
1942 REMAT_DEBUG(dbgs() << "Region " << RegionIdx
1943 << " cannot meet occupancy target, interrupting "
1944 "re-scheduling in all regions\n");
1945 RevertAllRegions = true;
1946 }
1947}
1948
1950 // Check the results of scheduling.
1951 PressureAfter = DAG.getRealRegPressure(RegionIdx);
1952
1953 LLVM_DEBUG(dbgs() << "Pressure after scheduling: " << print(PressureAfter));
1954 LLVM_DEBUG(dbgs() << "Region: " << RegionIdx << ".\n");
1955
1956 unsigned DynamicVGPRBlockSize = DAG.MFI.getDynamicVGPRBlockSize();
1957
1958 if (PressureAfter.getSGPRNum() <= S.SGPRCriticalLimit &&
1959 PressureAfter.getVGPRNum(ST.hasGFX90AInsts()) <= S.VGPRCriticalLimit) {
1960 DAG.Pressure[RegionIdx] = PressureAfter;
1961
1962 // Early out if we have achieved the occupancy target.
1963 LLVM_DEBUG(dbgs() << "Pressure in desired limits, done.\n");
1964 return;
1965 }
1966
1967 unsigned TargetOccupancy = std::min(
1968 S.getTargetOccupancy(), ST.getOccupancyWithWorkGroupSizes(MF).second);
1969 unsigned WavesAfter = std::min(
1970 TargetOccupancy, PressureAfter.getOccupancy(ST, DynamicVGPRBlockSize));
1971 unsigned WavesBefore = std::min(
1972 TargetOccupancy, PressureBefore.getOccupancy(ST, DynamicVGPRBlockSize));
1973 LLVM_DEBUG(dbgs() << "Occupancy before scheduling: " << WavesBefore
1974 << ", after " << WavesAfter << ".\n");
1975
1976 // We may not be able to keep the current target occupancy because of the just
1977 // scheduled region. We might still be able to revert scheduling if the
1978 // occupancy before was higher, or if the current schedule has register
1979 // pressure higher than the excess limits which could lead to more spilling.
1980 unsigned NewOccupancy = std::max(WavesAfter, WavesBefore);
1981
1982 // Allow memory bound functions to drop to 4 waves if not limited by an
1983 // attribute.
1984 if (WavesAfter < WavesBefore && WavesAfter < DAG.MinOccupancy &&
1985 WavesAfter >= MFI.getMinAllowedOccupancy()) {
1986 LLVM_DEBUG(dbgs() << "Function is memory bound, allow occupancy drop up to "
1987 << MFI.getMinAllowedOccupancy() << " waves\n");
1988 NewOccupancy = WavesAfter;
1989 }
1990
1991 if (NewOccupancy < DAG.MinOccupancy) {
1992 DAG.MinOccupancy = NewOccupancy;
1993 MFI.limitOccupancy(DAG.MinOccupancy);
1994 LLVM_DEBUG(dbgs() << "Occupancy lowered for the function to "
1995 << DAG.MinOccupancy << ".\n");
1996 }
1997 // The maximum number of arch VGPR on non-unified register file, or the
1998 // maximum VGPR + AGPR in the unified register file case.
1999 unsigned MaxVGPRs = ST.getMaxNumVGPRs(MF);
2000 // The maximum number of arch VGPR for both unified and non-unified register
2001 // file.
2002 unsigned MaxArchVGPRs = std::min(MaxVGPRs, ST.getAddressableNumArchVGPRs());
2003 unsigned MaxSGPRs = ST.getMaxNumSGPRs(MF);
2004
2005 if (PressureAfter.getVGPRNum(ST.hasGFX90AInsts()) > MaxVGPRs ||
2006 PressureAfter.getArchVGPRNum() > MaxArchVGPRs ||
2007 PressureAfter.getAGPRNum() > MaxArchVGPRs ||
2008 PressureAfter.getSGPRNum() > MaxSGPRs) {
2009 DAG.RegionsWithHighRP[RegionIdx] = true;
2010 DAG.RegionsWithExcessRP[RegionIdx] = true;
2011 }
2012
2013 // Revert if this region's schedule would cause a drop in occupancy or
2014 // spilling.
2015 if (shouldRevertScheduling(WavesAfter)) {
2017 std::tie(DAG.RegionBegin, DAG.RegionEnd) = DAG.Regions[RegionIdx];
2018 } else {
2019 DAG.Pressure[RegionIdx] = PressureAfter;
2020 }
2021}
2022
2023unsigned
2024GCNSchedStage::computeSUnitReadyCycle(const SUnit &SU, unsigned CurrCycle,
2025 DenseMap<unsigned, unsigned> &ReadyCycles,
2026 const TargetSchedModel &SM) {
2027 unsigned ReadyCycle = CurrCycle;
2028 for (auto &D : SU.Preds) {
2029 if (D.isAssignedRegDep()) {
2030 MachineInstr *DefMI = D.getSUnit()->getInstr();
2031 unsigned Latency = SM.computeInstrLatency(DefMI);
2032 unsigned DefReady = ReadyCycles[DAG.getSUnit(DefMI)->NodeNum];
2033 ReadyCycle = std::max(ReadyCycle, DefReady + Latency);
2034 }
2035 }
2036 ReadyCycles[SU.NodeNum] = ReadyCycle;
2037 return ReadyCycle;
2038}
2039
2040#ifndef NDEBUG
2042 bool operator()(std::pair<MachineInstr *, unsigned> A,
2043 std::pair<MachineInstr *, unsigned> B) const {
2044 return A.second < B.second;
2045 }
2046};
2047
2048static void printScheduleModel(std::set<std::pair<MachineInstr *, unsigned>,
2049 EarlierIssuingCycle> &ReadyCycles) {
2050 if (ReadyCycles.empty())
2051 return;
2052 unsigned BBNum = ReadyCycles.begin()->first->getParent()->getNumber();
2053 dbgs() << "\n################## Schedule time ReadyCycles for MBB : " << BBNum
2054 << " ##################\n# Cycle #\t\t\tInstruction "
2055 " "
2056 " \n";
2057 unsigned IPrev = 1;
2058 for (auto &I : ReadyCycles) {
2059 if (I.second > IPrev + 1)
2060 dbgs() << "****************************** BUBBLE OF " << I.second - IPrev
2061 << " CYCLES DETECTED ******************************\n\n";
2062 dbgs() << "[ " << I.second << " ] : " << *I.first << "\n";
2063 IPrev = I.second;
2064 }
2065}
2066#endif
2067
2068ScheduleMetrics
2069GCNSchedStage::getScheduleMetrics(const std::vector<SUnit> &InputSchedule) {
2070#ifndef NDEBUG
2071 std::set<std::pair<MachineInstr *, unsigned>, EarlierIssuingCycle>
2072 ReadyCyclesSorted;
2073#endif
2074 const TargetSchedModel &SM = ST.getInstrInfo()->getSchedModel();
2075 unsigned SumBubbles = 0;
2076 DenseMap<unsigned, unsigned> ReadyCycles;
2077 unsigned CurrCycle = 0;
2078 for (auto &SU : InputSchedule) {
2079 unsigned ReadyCycle =
2080 computeSUnitReadyCycle(SU, CurrCycle, ReadyCycles, SM);
2081 SumBubbles += ReadyCycle - CurrCycle;
2082#ifndef NDEBUG
2083 ReadyCyclesSorted.insert(std::make_pair(SU.getInstr(), ReadyCycle));
2084#endif
2085 CurrCycle = ++ReadyCycle;
2086 }
2087#ifndef NDEBUG
2088 LLVM_DEBUG(
2089 printScheduleModel(ReadyCyclesSorted);
2090 dbgs() << "\n\t"
2091 << "Metric: "
2092 << (SumBubbles
2093 ? (SumBubbles * ScheduleMetrics::ScaleFactor) / CurrCycle
2094 : 1)
2095 << "\n\n");
2096#endif
2097
2098 return ScheduleMetrics(CurrCycle, SumBubbles);
2099}
2100
2103#ifndef NDEBUG
2104 std::set<std::pair<MachineInstr *, unsigned>, EarlierIssuingCycle>
2105 ReadyCyclesSorted;
2106#endif
2107 const TargetSchedModel &SM = ST.getInstrInfo()->getSchedModel();
2108 unsigned SumBubbles = 0;
2109 DenseMap<unsigned, unsigned> ReadyCycles;
2110 unsigned CurrCycle = 0;
2111 for (auto &MI : DAG) {
2112 SUnit *SU = DAG.getSUnit(&MI);
2113 if (!SU)
2114 continue;
2115 unsigned ReadyCycle =
2116 computeSUnitReadyCycle(*SU, CurrCycle, ReadyCycles, SM);
2117 SumBubbles += ReadyCycle - CurrCycle;
2118#ifndef NDEBUG
2119 ReadyCyclesSorted.insert(std::make_pair(SU->getInstr(), ReadyCycle));
2120#endif
2121 CurrCycle = ++ReadyCycle;
2122 }
2123#ifndef NDEBUG
2124 LLVM_DEBUG(
2125 printScheduleModel(ReadyCyclesSorted);
2126 dbgs() << "\n\t"
2127 << "Metric: "
2128 << (SumBubbles
2129 ? (SumBubbles * ScheduleMetrics::ScaleFactor) / CurrCycle
2130 : 1)
2131 << "\n\n");
2132#endif
2133
2134 return ScheduleMetrics(CurrCycle, SumBubbles);
2135}
2136
2137bool GCNSchedStage::shouldRevertScheduling(unsigned WavesAfter) {
2138 if (WavesAfter < DAG.MinOccupancy)
2139 return true;
2140
2141 // For dynamic VGPR mode, we don't want to waste any VGPR blocks.
2142 if (DAG.MFI.isDynamicVGPREnabled()) {
2143 unsigned BlocksBefore = AMDGPU::IsaInfo::getAllocatedNumVGPRBlocks(
2144 ST, PressureBefore.getVGPRNum(false),
2145 DAG.MFI.getDynamicVGPRBlockSize());
2146 unsigned BlocksAfter = AMDGPU::IsaInfo::getAllocatedNumVGPRBlocks(
2147 ST, PressureAfter.getVGPRNum(false), DAG.MFI.getDynamicVGPRBlockSize());
2148 if (BlocksAfter > BlocksBefore)
2149 return true;
2150 }
2151
2152 return false;
2153}
2154
2157 return false;
2158
2160 return true;
2161
2162 if (mayCauseSpilling(WavesAfter))
2163 return true;
2164
2165 return false;
2166}
2167
2169 // If RP is not reduced in the unclustered reschedule stage, revert to the
2170 // old schedule.
2171 if ((WavesAfter <=
2172 PressureBefore.getOccupancy(ST, DAG.MFI.getDynamicVGPRBlockSize()) &&
2173 mayCauseSpilling(WavesAfter)) ||
2175 LLVM_DEBUG(dbgs() << "Unclustered reschedule did not help.\n");
2176 return true;
2177 }
2178
2179 // Do not attempt to relax schedule even more if we are already spilling.
2181 return false;
2182
2183 LLVM_DEBUG(
2184 dbgs()
2185 << "\n\t *** In shouldRevertScheduling ***\n"
2186 << " *********** BEFORE UnclusteredHighRPStage ***********\n");
2187 ScheduleMetrics MBefore = getScheduleMetrics(DAG.SUnits);
2188 LLVM_DEBUG(
2189 dbgs()
2190 << "\n *********** AFTER UnclusteredHighRPStage ***********\n");
2192 unsigned OldMetric = MBefore.getMetric();
2193 unsigned NewMetric = MAfter.getMetric();
2194 unsigned WavesBefore = std::min(
2195 S.getTargetOccupancy(),
2196 PressureBefore.getOccupancy(ST, DAG.MFI.getDynamicVGPRBlockSize()));
2197 unsigned Profit =
2198 ((WavesAfter * ScheduleMetrics::ScaleFactor) / WavesBefore *
2200 NewMetric) /
2202 LLVM_DEBUG(dbgs() << "\tMetric before " << MBefore << "\tMetric after "
2203 << MAfter << "Profit: " << Profit << "\n");
2204 return Profit < ScheduleMetrics::ScaleFactor;
2205}
2206
2209 return false;
2210
2212 return true;
2213
2214 if (mayCauseSpilling(WavesAfter))
2215 return true;
2216
2217 return false;
2218}
2219
2221 // When trying to increase occupancy (TargetOcc == true) the stage manages
2222 // region reverts globally (all or none), so we always return false here.
2223 return !TargetOcc && mayCauseSpilling(WavesAfter);
2224}
2225
2227 if (mayCauseSpilling(WavesAfter))
2228 return true;
2229
2230 return false;
2231}
2232
2234 unsigned WavesAfter) {
2235 return mayCauseSpilling(WavesAfter);
2236}
2237
2238bool GCNSchedStage::mayCauseSpilling(unsigned WavesAfter) {
2239 if (WavesAfter <= MFI.getMinWavesPerEU() && isRegionWithExcessRP() &&
2241 LLVM_DEBUG(dbgs() << "New pressure will result in more spilling.\n");
2242 return true;
2243 }
2244
2245 return false;
2246}
2247
2249 ArrayRef<MachineInstr *> MIOrder) {
2250 assert(static_cast<size_t>(std::distance(DAG.Regions[RegionIdx].first,
2251 DAG.Regions[RegionIdx].second)) ==
2252 MIOrder.size() &&
2253 "instruction number mismatch");
2254 if (MIOrder.empty())
2255 return;
2256
2257 LLVM_DEBUG(dbgs() << "Reverting scheduling for region " << RegionIdx << '\n');
2258
2259 // Reconstruct MI sequence by moving instructions in desired order before
2260 // the current region's start.
2261 MachineBasicBlock::iterator RegionEnd = DAG.Regions[RegionIdx].first;
2262 MachineBasicBlock *MBB = MIOrder.front()->getParent();
2263 for (MachineInstr *MI : MIOrder) {
2264 // Either move the next MI in order before the end of the region or move the
2265 // region end past the MI if it is at the correct position.
2266 MachineBasicBlock::iterator MII = MI->getIterator();
2267 if (MII != RegionEnd) {
2268 // Will subsequent splice move MI up past a non-debug instruction?
2269 bool NonDebugReordered =
2270 !MI->isDebugInstr() &&
2271 skipDebugInstructionsForward(RegionEnd, MII) != MII;
2272 MBB->splice(RegionEnd, MBB, MI);
2273 // Only update LiveIntervals information if non-debug instructions are
2274 // reordered. Otherwise debug instructions could cause code generation to
2275 // change.
2276 if (NonDebugReordered)
2277 DAG.LIS->handleMove(*MI, true);
2278 } else {
2279 // MI is already at the expected position. However, earlier splices in
2280 // this loop may have changed neighboring slot indices, so this MI's
2281 // slot index can become non-monotonic w.r.t. the physical MBB order.
2282 // Only re-seat when monotonicity is actually violated to avoid
2283 // unnecessary LiveInterval changes that could perturb scheduling.
2284 if (!MI->isDebugInstr()) {
2285 SlotIndex MIIdx = DAG.LIS->getInstructionIndex(*MI);
2286 SlotIndex PrevIdx = DAG.LIS->getSlotIndexes()->getIndexBefore(*MI);
2287 if (PrevIdx >= MIIdx)
2288 DAG.LIS->handleMove(*MI, true);
2289 }
2290 ++RegionEnd;
2291 }
2292 if (MI->isDebugInstr()) {
2293 LLVM_DEBUG(dbgs() << "Scheduling " << *MI);
2294 continue;
2295 }
2296
2297 // Reset read-undef flags and update them later.
2298 for (MachineOperand &Op : MI->all_defs())
2299 Op.setIsUndef(false);
2300 RegisterOperands RegOpers;
2301 RegOpers.collect(*MI, *DAG.TRI, DAG.MRI, DAG.ShouldTrackLaneMasks, false);
2302 if (DAG.ShouldTrackLaneMasks) {
2303 // Adjust liveness and add missing dead+read-undef flags.
2304 RegOpers.adjustLaneLiveness(*DAG.LIS, DAG.MRI, *MI);
2305 } else {
2306 // Adjust for missing dead-def flags.
2307 RegOpers.detectDeadDefs(*MI, *DAG.LIS);
2308 }
2309 LLVM_DEBUG(dbgs() << "Scheduling " << *MI);
2310 }
2311
2312 // The region end doesn't change throughout scheduling since it itself is
2313 // outside the region (whether that is a MBB end or a terminator MI).
2314 assert(RegionEnd == DAG.Regions[RegionIdx].second && "region end mismatch");
2315 DAG.Regions[RegionIdx].first = MIOrder.front();
2316}
2317
2318/// Returns true if reaching def \p RD will be in AGPR form after the rewrite
2319/// and so needs no bridge copy: a candidate MFMA in \p RewriteSet, an
2320/// AV_MOV_*_IMM_PSEUDO, or a copy from a candidate src2 reg in \p CandSrc2Regs.
2321/// A non-candidate MFMA stays in VGPR form and still needs a bridge.
2323 MachineInstr *RD, const SmallPtrSetImpl<MachineInstr *> &RewriteSet,
2324 const DenseSet<Register> &CandSrc2Regs, const SIInstrInfo &TII) {
2325 if (TII.isMAI(*RD))
2326 return RewriteSet.contains(RD);
2327 if (RD->getOpcode() == AMDGPU::AV_MOV_B32_IMM_PSEUDO ||
2328 RD->getOpcode() == AMDGPU::AV_MOV_B64_IMM_PSEUDO)
2329 return true;
2330 if (RD->isCopy() && CandSrc2Regs.contains(RD->getOperand(1).getReg()))
2331 return true;
2332 return false;
2333}
2334
2335bool RewriteMFMAFormStage::hasUseRequiringVGPR(
2336 ArrayRef<SlotIndex> Src2ReachingDefs,
2337 const SmallPtrSetImpl<MachineInstr *> &RewriteSet) {
2338 for (SlotIndex RDIdx : Src2ReachingDefs) {
2339 const MachineInstr *RD = DAG.LIS->getInstructionFromIndex(RDIdx);
2341 findReachingUses(RD, DAG.LIS, ReachingUses);
2342 for (const MachineOperand *UseMO : ReachingUses) {
2343 const MachineInstr *UseMI = UseMO->getParent();
2344 if (UseMI->isCopy())
2345 continue;
2346 if (TII->isMAI(*UseMI) && RewriteSet.contains(UseMI))
2347 continue;
2348 return true;
2349 }
2350 }
2351 return false;
2352}
2353
2354void RewriteMFMAFormStage::resetRewriteCandsToVGPR(
2355 ArrayRef<std::pair<MachineInstr *, unsigned>> RewriteCands) {
2356 for (auto [MI, OriginalOpcode] : RewriteCands) {
2357 assert(TII->isMAI(*MI));
2358 const TargetRegisterClass *ADefRC =
2359 DAG.MRI.getRegClass(MI->getOperand(0).getReg());
2360 const TargetRegisterClass *VDefRC = SRI->getEquivalentVGPRClass(ADefRC);
2361 DAG.MRI.setRegClass(MI->getOperand(0).getReg(), VDefRC);
2362 MI->setDesc(TII->get(OriginalOpcode));
2363
2364 MachineOperand *Src2 = TII->getNamedOperand(*MI, AMDGPU::OpName::src2);
2365 if (!Src2->isReg())
2366 continue;
2367
2368 // Have to get src types separately since subregs may cause C and D
2369 // registers to be different types even though the actual operand is
2370 // the same size.
2371 const TargetRegisterClass *AUseRC = DAG.MRI.getRegClass(Src2->getReg());
2372 const TargetRegisterClass *VUseRC = SRI->getEquivalentVGPRClass(AUseRC);
2373 DAG.MRI.setRegClass(Src2->getReg(), VUseRC);
2374 }
2375}
2376
2377bool RewriteMFMAFormStage::isRewriteCandidate(MachineInstr *MI) const {
2378 if (!static_cast<const SIInstrInfo *>(DAG.TII)->isMAI(*MI))
2379 return false;
2380 if (AMDGPU::getAGPRFormOp(MI->getOpcode()) == -1)
2381 return false;
2382 // Reject candidates whose users force an unavoidable bridge copy.
2383 Register DstReg = MI->getOperand(0).getReg();
2384 for (const MachineOperand &Use : DAG.MRI.use_nodbg_operands(DstReg)) {
2385 if (!TII->isMAI(*Use.getParent()) && !Use.getParent()->isCopy())
2386 return false;
2387 }
2388 return true;
2389}
2390
2391bool RewriteMFMAFormStage::initHeuristics(
2392 std::vector<std::pair<MachineInstr *, unsigned>> &RewriteCands,
2393 DenseMap<MachineBasicBlock *, std::set<Register>> &CopyForUse,
2394 SmallPtrSetImpl<MachineInstr *> &CopyForDef) {
2395 bool Changed = false;
2396
2397 // Collect the candidate group, its members share AGPR-form operands
2398 // post-rewrite, so reaching defs feeding any member don't need bridge copy.
2399 SmallPtrSet<MachineInstr *, 16> RewriteSet;
2400 DenseSet<Register> CandSrc2Regs;
2401 for (MachineBasicBlock &MBB : MF) {
2402 for (MachineInstr &MI : MBB) {
2403 if (!isRewriteCandidate(&MI))
2404 continue;
2405 RewriteSet.insert(&MI);
2406 MachineOperand *Src2 = TII->getNamedOperand(MI, AMDGPU::OpName::src2);
2407 if (Src2 && Src2->isReg())
2408 CandSrc2Regs.insert(Src2->getReg());
2409 }
2410 }
2411
2412 // Prepare for the heuristics
2413 for (MachineBasicBlock &MBB : MF) {
2414 for (MachineInstr &MI : MBB) {
2415 if (!isRewriteCandidate(&MI))
2416 continue;
2417
2418 int ReplacementOp = AMDGPU::getAGPRFormOp(MI.getOpcode());
2419 assert(ReplacementOp != -1);
2420
2421 RewriteCands.push_back({&MI, MI.getOpcode()});
2422 MI.setDesc(TII->get(ReplacementOp));
2423
2424 MachineOperand *Src2 = TII->getNamedOperand(MI, AMDGPU::OpName::src2);
2425 if (Src2->isReg()) {
2426 SmallVector<SlotIndex, 8> Src2ReachingDefs;
2427 findReachingDefs(*Src2, DAG.LIS, Src2ReachingDefs);
2428
2429 // If src2 has a use that must remain VGPR, it cannot be reclassified to
2430 // AGPR.
2431 bool Src2NeedsVGPR = hasUseRequiringVGPR(Src2ReachingDefs, RewriteSet);
2432 Src2NeedsVGPRCache[&MI] = Src2NeedsVGPR;
2433
2434 for (SlotIndex RDIdx : Src2ReachingDefs) {
2435 MachineInstr *RD = DAG.LIS->getInstructionFromIndex(RDIdx);
2436 if (!Src2NeedsVGPR &&
2437 isReachingDefAGPRForm(RD, RewriteSet, CandSrc2Regs, *TII))
2438 continue;
2439 CopyForDef.insert(RD);
2440 }
2441 }
2442
2443 MachineOperand &Dst = MI.getOperand(0);
2444 SmallVector<MachineOperand *, 8> DstReachingUses;
2445
2446 findReachingUses(&MI, DAG.LIS, DstReachingUses);
2447
2448 for (MachineOperand *RUOp : DstReachingUses) {
2449 MachineInstr *UserMI = RUOp->getParent();
2450 // Group members read the AGPR result directly.
2451 if (TII->isMAI(*UserMI) && RewriteSet.contains(UserMI))
2452 continue;
2453
2454 // For any user of the result of the MFMA which is not an MFMA, we
2455 // insert a copy. For a given register, we will only insert one copy
2456 // per user block.
2457 CopyForUse[UserMI->getParent()].insert(RUOp->getReg());
2458
2459 if (TII->isMAI(*UserMI))
2460 continue;
2461
2462 SmallVector<SlotIndex, 8> DstUsesReachingDefs;
2463 findReachingDefs(*RUOp, DAG.LIS, DstUsesReachingDefs);
2464
2465 for (SlotIndex RDIndex : DstUsesReachingDefs) {
2466 MachineInstr *RD = DAG.LIS->getInstructionFromIndex(RDIndex);
2467 if (TII->isMAI(*RD))
2468 continue;
2469
2470 // For any definition of the user of the MFMA which is not an MFMA,
2471 // we insert a copy. We do this to transform all the reaching defs
2472 // of this use to AGPR. By doing this, we can insert a copy from
2473 // AGPR to VGPR at the user rather than after the MFMA.
2474 CopyForDef.insert(RD);
2475 }
2476 }
2477
2478 // Do the rewrite to allow for updated RP calculation.
2479 const TargetRegisterClass *VDefRC = DAG.MRI.getRegClass(Dst.getReg());
2480 const TargetRegisterClass *ADefRC = SRI->getEquivalentAGPRClass(VDefRC);
2481 DAG.MRI.setRegClass(Dst.getReg(), ADefRC);
2482 if (Src2->isReg()) {
2483 // Have to get src types separately since subregs may cause C and D
2484 // registers to be different types even though the actual operand is
2485 // the same size.
2486 const TargetRegisterClass *VUseRC = DAG.MRI.getRegClass(Src2->getReg());
2487 const TargetRegisterClass *AUseRC = SRI->getEquivalentAGPRClass(VUseRC);
2488 DAG.MRI.setRegClass(Src2->getReg(), AUseRC);
2489 }
2490 Changed = true;
2491 }
2492 }
2493
2494 return Changed;
2495}
2496
2497int64_t RewriteMFMAFormStage::getRewriteCost(
2498 ArrayRef<std::pair<MachineInstr *, unsigned>> RewriteCands,
2499 const DenseMap<MachineBasicBlock *, std::set<Register>> &CopyForUse,
2500 const SmallPtrSetImpl<MachineInstr *> &CopyForDef) {
2501 MachineBlockFrequencyInfo *MBFI = DAG.MBFI;
2502
2503 int64_t BestSpillCost = 0;
2504 int64_t Cost = 0;
2505 uint64_t EntryFreq = MBFI->getEntryFreq().getFrequency();
2506
2507 std::pair<unsigned, unsigned> MaxVectorRegs =
2508 ST.getMaxNumVectorRegs(MF.getFunction());
2509 unsigned ArchVGPRThreshold = MaxVectorRegs.first;
2510 unsigned AGPRThreshold = MaxVectorRegs.second;
2511 unsigned CombinedThreshold = ST.getMaxNumVGPRs(MF);
2512
2513 for (unsigned Region = 0; Region < DAG.Regions.size(); Region++) {
2514 if (!RegionsWithExcessArchVGPR[Region])
2515 continue;
2516
2517 GCNRegPressure &PressureBefore = DAG.Pressure[Region];
2518 unsigned SpillCostBefore = PressureBefore.getVGPRSpills(
2519 MF, ArchVGPRThreshold, AGPRThreshold, CombinedThreshold);
2520
2521 // For the cases we care about (i.e. ArchVGPR usage is greater than the
2522 // addressable limit), rewriting alone should bring pressure to manageable
2523 // level. If we find any such region, then the rewrite is potentially
2524 // beneficial.
2525 GCNRegPressure PressureAfter = DAG.getRealRegPressure(Region);
2526 unsigned SpillCostAfter = PressureAfter.getVGPRSpills(
2527 MF, ArchVGPRThreshold, AGPRThreshold, CombinedThreshold);
2528
2529 uint64_t BlockFreq =
2530 MBFI->getBlockFreq(DAG.Regions[Region].first->getParent())
2531 .getFrequency();
2532
2533 bool RelativeFreqIsDenom = EntryFreq > BlockFreq;
2534 uint64_t RelativeFreq = EntryFreq && BlockFreq
2535 ? (RelativeFreqIsDenom ? EntryFreq / BlockFreq
2536 : BlockFreq / EntryFreq)
2537 : 1;
2538
2539 // This assumes perfect spilling / splitting -- using one spill / copy
2540 // instruction and one restoreFrom / copy for each excess register,
2541 int64_t SpillCost = ((int)SpillCostAfter - (int)SpillCostBefore) * 2;
2542
2543 // Also account for the block frequency.
2544 if (RelativeFreqIsDenom)
2545 SpillCost /= (int64_t)RelativeFreq;
2546 else
2547 SpillCost *= (int64_t)RelativeFreq;
2548
2549 // If we have increased spilling in any block, just bail.
2550 if (SpillCost > 0) {
2551 resetRewriteCandsToVGPR(RewriteCands);
2552 return SpillCost;
2553 }
2554
2555 if (SpillCost < BestSpillCost)
2556 BestSpillCost = SpillCost;
2557 }
2558
2559 // Set the cost to the largest decrease in spill cost in order to not double
2560 // count spill reductions.
2561 Cost = BestSpillCost;
2562 assert(Cost <= 0);
2563
2564 unsigned CopyCost = 0;
2565
2566 // For each CopyForDef, increase the cost by the register size while
2567 // accounting for block frequency.
2568 for (MachineInstr *DefMI : CopyForDef) {
2569 Register DefReg = DefMI->getOperand(0).getReg();
2570 uint64_t DefFreq =
2571 EntryFreq
2572 ? MBFI->getBlockFreq(DefMI->getParent()).getFrequency() / EntryFreq
2573 : 1;
2574
2575 const TargetRegisterClass *RC = DAG.MRI.getRegClass(DefReg);
2576 CopyCost += RC->getCopyCost() * DefFreq;
2577 }
2578
2579 // Account for CopyForUse copies in each block that the register is used.
2580 for (auto &[UseBlock, UseRegs] : CopyForUse) {
2581 uint64_t UseFreq =
2582 EntryFreq ? MBFI->getBlockFreq(UseBlock).getFrequency() / EntryFreq : 1;
2583
2584 for (Register UseReg : UseRegs) {
2585 const TargetRegisterClass *RC = DAG.MRI.getRegClass(UseReg);
2586 CopyCost += RC->getCopyCost() * UseFreq;
2587 }
2588 }
2589
2590 // Reset the classes that were changed to AGPR for better register bank
2591 // analysis. We must do rewriting after copy-insertion, as some defs of the
2592 // register may require VGPR. Additionally, if we bail out and don't perform
2593 // the rewrite then these need to be restored anyway.
2594 resetRewriteCandsToVGPR(RewriteCands);
2595
2596 return Cost + CopyCost;
2597}
2598
2599bool RewriteMFMAFormStage::rewrite(
2600 ArrayRef<std::pair<MachineInstr *, unsigned>> RewriteCands) {
2601 DenseMap<MachineInstr *, unsigned> FirstMIToRegion;
2602 DenseMap<MachineInstr *, unsigned> LastMIToRegion;
2603
2604 for (unsigned Region = 0; Region < DAG.Regions.size(); Region++) {
2605 RegionBoundaries Entry = DAG.Regions[Region];
2606 if (Entry.first == Entry.second)
2607 continue;
2608
2609 FirstMIToRegion[&*Entry.first] = Region;
2610 if (Entry.second != Entry.first->getParent()->end())
2611 LastMIToRegion[&*Entry.second] = Region;
2612 }
2613
2614 // Rewrite the MFMAs to AGPR, and insert any copies as needed.
2615 // The general assumption of the algorithm (and the previous cost calculation)
2616 // is that it is better to insert the copies in the MBB of the def of the src2
2617 // operands, and in the MBB of the user of the dest operands. This is based on
2618 // the assumption that the MFMAs are likely to appear in loop bodies, while
2619 // the src2 and dest operands are live-in / live-out of the loop. Due to this
2620 // design, the algorithm for finding copy insertion points is more
2621 // complicated.
2622 //
2623 // There are three main cases to handle: 1. the reaching defs of the src2
2624 // operands, 2. the reaching uses of the dst operands, and 3. the reaching
2625 // defs of the reaching uses of the dst operand.
2626 //
2627 // In the first case, we simply insert copies after each of the reaching
2628 // definitions. In the second case, we collect all the uses of a given dest
2629 // and organize them by MBB. Then, we insert 1 copy for each MBB before the
2630 // earliest use. Since the use may have multiple reaching defs, and since we
2631 // want to replace the register it is using with the result of the copy, we
2632 // must handle case 3. In the third case, we simply insert a copy after each
2633 // of the reaching defs to connect to the copy of the reaching uses of the dst
2634 // reg. This allows us to avoid inserting copies next to the MFMAs.
2635 //
2636 // While inserting the copies, we maintain a map of operands which will use
2637 // different regs (i.e. the result of the copies). For example, a case 1 src2
2638 // operand will use the register result of the copies after the reaching defs,
2639 // as opposed to the original register. Now that we have completed our copy
2640 // analysis and placement, we can bulk update the registers. We do this
2641 // separately as to avoid complicating the reachingDef and reachingUse
2642 // queries.
2643 //
2644 // While inserting the copies, we also maintain a list or registers which we
2645 // will want to reclassify as AGPR. After doing the copy insertion and the
2646 // register replacement, we can finally do the reclassification. This uses the
2647 // redef map, as the registers we are interested in reclassifying may be
2648 // replaced by the result of a copy. We must do this after the copy analysis
2649 // and placement as we must have an accurate redef map -- otherwise we may end
2650 // up creating illegal instructions.
2651
2652 // The original registers of the MFMA that need to be reclassified as AGPR.
2653 DenseSet<Register> RewriteRegs;
2654 // The map of an original register in the MFMA to a new register (result of a
2655 // copy) that it should be replaced with.
2656 DenseMap<Register, Register> RedefMap;
2657 // The map of the original MFMA registers to the relevant MFMA operands.
2658 DenseMap<Register, DenseSet<MachineOperand *>> ReplaceMap;
2659 // The map of reaching defs for a given register -- to avoid duplicate copies.
2660 DenseMap<Register, SmallPtrSet<MachineInstr *, 8>> ReachingDefCopyMap;
2661 // The map of reaching uses for a given register by basic block -- to avoid
2662 // duplicate copies and to calculate per MBB insert pts.
2663 DenseMap<unsigned, DenseMap<Register, SmallPtrSet<MachineOperand *, 8>>>
2664 ReachingUseTracker;
2665
2666 // Collect the candidate group; its members share AGPR-form operands
2667 // post-rewrite, so reaching defs feeding any member need no bridge copy.
2668 SmallPtrSet<MachineInstr *, 16> RewriteCandsSet;
2669 DenseSet<Register> RewriteSrc2Regs;
2670 for (auto &[MI, OriginalOpcode] : RewriteCands) {
2671 RewriteCandsSet.insert(MI);
2672 MachineOperand *Src2 = TII->getNamedOperand(*MI, AMDGPU::OpName::src2);
2673 if (Src2 && Src2->isReg())
2674 RewriteSrc2Regs.insert(Src2->getReg());
2675 }
2676
2677 for (auto &[MI, OriginalOpcode] : RewriteCands) {
2678 int ReplacementOp = AMDGPU::getAGPRFormOp(MI->getOpcode());
2679 if (ReplacementOp == -1)
2680 continue;
2681 MI->setDesc(TII->get(ReplacementOp));
2682
2683 // Case 1: insert copies for the reaching defs of the Src2Reg.
2684 MachineOperand *Src2 = TII->getNamedOperand(*MI, AMDGPU::OpName::src2);
2685 if (Src2->isReg()) {
2686 Register Src2Reg = Src2->getReg();
2687 if (!Src2Reg.isVirtual())
2688 return false;
2689
2690 Register MappedReg = Src2->getReg();
2691 SmallVector<SlotIndex, 8> Src2ReachingDefs;
2692 findReachingDefs(*Src2, DAG.LIS, Src2ReachingDefs);
2693 SmallSetVector<MachineInstr *, 8> Src2DefsReplace;
2694
2695 // If src2 has a use that must remain VGPR, it cannot be reclassified to
2696 // AGPR.
2697 bool Src2NeedsVGPR = Src2NeedsVGPRCache.lookup(MI);
2698
2699 for (SlotIndex RDIndex : Src2ReachingDefs) {
2700 MachineInstr *RD = DAG.LIS->getInstructionFromIndex(RDIndex);
2701 if (!Src2NeedsVGPR &&
2702 isReachingDefAGPRForm(RD, RewriteCandsSet, RewriteSrc2Regs, *TII))
2703 continue;
2704
2705 Src2DefsReplace.insert(RD);
2706 }
2707
2708 if (!Src2DefsReplace.empty()) {
2709 auto RI = RedefMap.find(Src2Reg);
2710 if (RI != RedefMap.end()) {
2711 MappedReg = RI->second;
2712 } else {
2713 assert(!ReachingDefCopyMap.contains(Src2Reg));
2714 const TargetRegisterClass *Src2RC = DAG.MRI.getRegClass(Src2Reg);
2715 const TargetRegisterClass *VGPRRC =
2716 SRI->getEquivalentVGPRClass(Src2RC);
2717
2718 // Track the mapping of the original register to the new register.
2719 MappedReg = DAG.MRI.createVirtualRegister(VGPRRC);
2720 RedefMap[Src2Reg] = MappedReg;
2721 }
2722
2723 // If none exists, create a copy from this reaching def.
2724 // We may have inserted a copy already in an earlier iteration.
2725 for (MachineInstr *RD : Src2DefsReplace) {
2726 // Do not create redundant copies.
2727 if (ReachingDefCopyMap[Src2Reg].insert(RD).second) {
2728 MachineInstrBuilder VGPRCopy =
2729 BuildMI(*RD->getParent(), std::next(RD->getIterator()),
2730 RD->getDebugLoc(), TII->get(TargetOpcode::COPY))
2731 .addDef(MappedReg, {}, 0)
2732 .addUse(Src2Reg, {}, 0);
2733 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
2734
2735 // If this reaching def was the last MI in the region, update the
2736 // region boundaries.
2737 if (LastMIToRegion.contains(RD)) {
2738 unsigned UpdateRegion = LastMIToRegion[RD];
2739 DAG.Regions[UpdateRegion].second = VGPRCopy;
2740 LastMIToRegion.erase(RD);
2741 }
2742 }
2743 }
2744 }
2745
2746 // Track the register for reclassification
2747 RewriteRegs.insert(Src2Reg);
2748
2749 // Always insert the operand for replacement. If this corresponds with a
2750 // chain of tied-def we may not see the VGPR requirement until later.
2751 ReplaceMap[Src2Reg].insert(Src2);
2752 }
2753
2754 // Case 2 and Case 3: insert copies before the reaching uses of the dsts,
2755 // and after the reaching defs of the reaching uses of the dsts.
2756
2757 MachineOperand *Dst = &MI->getOperand(0);
2758 Register DstReg = Dst->getReg();
2759 if (!DstReg.isVirtual())
2760 return false;
2761
2762 Register MappedReg = DstReg;
2763 SmallVector<MachineOperand *, 8> DstReachingUses;
2764
2765 SmallVector<MachineOperand *, 8> DstReachingUseCopies;
2766 SmallVector<MachineInstr *, 8> DstUseDefsReplace;
2767
2768 findReachingUses(MI, DAG.LIS, DstReachingUses);
2769
2770 for (MachineOperand *RUOp : DstReachingUses) {
2771 MachineInstr *UserMI = RUOp->getParent();
2772 // Group members read the AGPR result directly.
2773 if (TII->isMAI(*UserMI) && RewriteCandsSet.contains(UserMI))
2774 continue;
2775
2776 // If there is a non mai reaching use, then we need a copy.
2777 if (find(DstReachingUseCopies, RUOp) == DstReachingUseCopies.end())
2778 DstReachingUseCopies.push_back(RUOp);
2779
2780 // Non-rewritten MAI: its defs aren't being reclassified.
2781 if (TII->isMAI(*UserMI))
2782 continue;
2783
2784 SmallVector<SlotIndex, 8> DstUsesReachingDefs;
2785 findReachingDefs(*RUOp, DAG.LIS, DstUsesReachingDefs);
2786
2787 for (SlotIndex RDIndex : DstUsesReachingDefs) {
2788 MachineInstr *RD = DAG.LIS->getInstructionFromIndex(RDIndex);
2789 if (TII->isMAI(*RD))
2790 continue;
2791
2792 // If there is a non mai reaching def of this reaching use, then we will
2793 // need a copy.
2794 if (find(DstUseDefsReplace, RD) == DstUseDefsReplace.end())
2795 DstUseDefsReplace.push_back(RD);
2796 }
2797 }
2798
2799 if (!DstUseDefsReplace.empty()) {
2800 auto RI = RedefMap.find(DstReg);
2801 if (RI != RedefMap.end()) {
2802 MappedReg = RI->second;
2803 } else {
2804 assert(!ReachingDefCopyMap.contains(DstReg));
2805 const TargetRegisterClass *DstRC = DAG.MRI.getRegClass(DstReg);
2806 const TargetRegisterClass *VGPRRC = SRI->getEquivalentVGPRClass(DstRC);
2807
2808 // Track the mapping of the original register to the new register.
2809 MappedReg = DAG.MRI.createVirtualRegister(VGPRRC);
2810 RedefMap[DstReg] = MappedReg;
2811 }
2812
2813 // If none exists, create a copy from this reaching def.
2814 // We may have inserted a copy already in an earlier iteration.
2815 for (MachineInstr *RD : DstUseDefsReplace) {
2816 // Do not create reundant copies.
2817 if (ReachingDefCopyMap[DstReg].insert(RD).second) {
2818 MachineInstrBuilder VGPRCopy =
2819 BuildMI(*RD->getParent(), std::next(RD->getIterator()),
2820 RD->getDebugLoc(), TII->get(TargetOpcode::COPY))
2821 .addDef(MappedReg, {}, 0)
2822 .addUse(DstReg, {}, 0);
2823 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
2824
2825 // If this reaching def was the last MI in the region, update the
2826 // region boundaries.
2827 auto LMI = LastMIToRegion.find(RD);
2828 if (LMI != LastMIToRegion.end()) {
2829 unsigned UpdateRegion = LMI->second;
2830 DAG.Regions[UpdateRegion].second = VGPRCopy;
2831 LastMIToRegion.erase(RD);
2832 }
2833 }
2834 }
2835 }
2836
2837 DenseSet<MachineOperand *> &DstRegSet = ReplaceMap[DstReg];
2838 // One AGPR→VGPR copy per dst register, shared by all same-block uses.
2839 Register SameBlockCopyReg;
2840 MachineInstr *EarliestSameBlockUse = nullptr;
2841 for (MachineOperand *RU : DstReachingUseCopies) {
2842 MachineBasicBlock *RUBlock = RU->getParent()->getParent();
2843 // Just keep track of the reaching use of this register by block. After we
2844 // have scanned all the MFMAs we can find optimal insert pts.
2845 if (RUBlock != MI->getParent()) {
2846 ReachingUseTracker[RUBlock->getNumber()][DstReg].insert(RU);
2847 continue;
2848 }
2849
2850 // Lazily create the copy register on first same-block use.
2851 if (!SameBlockCopyReg.isValid()) {
2852 const TargetRegisterClass *DstRC = DAG.MRI.getRegClass(DstReg);
2853 const TargetRegisterClass *VGPRRC = SRI->getEquivalentVGPRClass(DstRC);
2854 SameBlockCopyReg = DAG.MRI.createVirtualRegister(VGPRRC);
2855 }
2856
2857 // Track the earliest use for copy insertion point.
2858 MachineInstr *UseInst = RU->getParent();
2859 if (!EarliestSameBlockUse ||
2861 DAG.LIS->getInstructionIndex(*UseInst),
2862 DAG.LIS->getInstructionIndex(*EarliestSameBlockUse)))
2863 EarliestSameBlockUse = UseInst;
2864 RU->setReg(SameBlockCopyReg);
2865 }
2866
2867 // Insert the copy before the earliest same-block use.
2868 if (SameBlockCopyReg.isValid()) {
2869 MachineInstrBuilder VGPRCopy =
2870 BuildMI(*EarliestSameBlockUse->getParent(),
2871 EarliestSameBlockUse->getIterator(), DebugLoc(),
2872 TII->get(TargetOpcode::COPY), SameBlockCopyReg)
2873 .addUse(DstReg, {}, 0);
2874 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
2875 DstRegSet.insert(&VGPRCopy->getOperand(1));
2876 }
2877
2878 // Track the register for reclassification
2879 RewriteRegs.insert(DstReg);
2880
2881 // Insert the dst operand for replacement. If this dst is in a chain of
2882 // tied-def MFMAs, and the first src2 needs to be replaced with a new reg,
2883 // all the correspond operands need to be replaced.
2884 DstRegSet.insert(Dst);
2885 }
2886
2887 // Handle the copies for dst uses.
2888 using RUBType =
2889 std::pair<unsigned, DenseMap<Register, SmallPtrSet<MachineOperand *, 8>>>;
2890 for (RUBType RUBlockEntry : ReachingUseTracker) {
2891 using RUDType = std::pair<Register, SmallPtrSet<MachineOperand *, 8>>;
2892 for (RUDType RUDst : RUBlockEntry.second) {
2893 MachineOperand *OpBegin = *RUDst.second.begin();
2894 SlotIndex InstPt = DAG.LIS->getInstructionIndex(*OpBegin->getParent());
2895
2896 // Find the earliest use in this block.
2897 for (MachineOperand *User : RUDst.second) {
2898 SlotIndex NewInstPt = DAG.LIS->getInstructionIndex(*User->getParent());
2899 if (SlotIndex::isEarlierInstr(NewInstPt, InstPt))
2900 InstPt = NewInstPt;
2901 }
2902
2903 const TargetRegisterClass *DstRC = DAG.MRI.getRegClass(RUDst.first);
2904 const TargetRegisterClass *VGPRRC = SRI->getEquivalentVGPRClass(DstRC);
2905 Register NewUseReg = DAG.MRI.createVirtualRegister(VGPRRC);
2906 MachineInstr *UseInst = DAG.LIS->getInstructionFromIndex(InstPt);
2907
2908 MachineInstrBuilder VGPRCopy =
2909 BuildMI(*UseInst->getParent(), UseInst->getIterator(),
2910 UseInst->getDebugLoc(), TII->get(TargetOpcode::COPY))
2911 .addDef(NewUseReg, {}, 0)
2912 .addUse(RUDst.first, {}, 0);
2913 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
2914
2915 // If this UseInst was the first MI in the region, update the region
2916 // boundaries.
2917 auto FI = FirstMIToRegion.find(UseInst);
2918 if (FI != FirstMIToRegion.end()) {
2919 unsigned UpdateRegion = FI->second;
2920 DAG.Regions[UpdateRegion].first = VGPRCopy;
2921 FirstMIToRegion.erase(UseInst);
2922 }
2923
2924 // Replace the operand for all users.
2925 for (MachineOperand *User : RUDst.second) {
2926 User->setReg(NewUseReg);
2927 }
2928
2929 // Track the copy source operand for replacement.
2930 ReplaceMap[RUDst.first].insert(&VGPRCopy->getOperand(1));
2931 }
2932 }
2933
2934 // We may have needed to insert copies after the reaching defs of the MFMAs.
2935 // Replace the original register with the result of the copy for all relevant
2936 // operands.
2937 for (std::pair<Register, Register> NewDef : RedefMap) {
2938 Register OldReg = NewDef.first;
2939 Register NewReg = NewDef.second;
2940
2941 // Replace the register for any associated operand in the MFMA chain.
2942 for (MachineOperand *ReplaceOp : ReplaceMap[OldReg])
2943 ReplaceOp->setReg(NewReg);
2944 }
2945
2946 // Finally, do the reclassification of the MFMA registers.
2947 for (Register RewriteReg : RewriteRegs) {
2948 Register RegToRewrite = RewriteReg;
2949
2950 // Be sure to update the replacement register and not the original.
2951 auto RI = RedefMap.find(RewriteReg);
2952 if (RI != RedefMap.end())
2953 RegToRewrite = RI->second;
2954
2955 const TargetRegisterClass *CurrRC = DAG.MRI.getRegClass(RegToRewrite);
2956 const TargetRegisterClass *AGPRRC = SRI->getEquivalentAGPRClass(CurrRC);
2957
2958 DAG.MRI.setRegClass(RegToRewrite, AGPRRC);
2959 }
2960
2961 // Bulk update the LIS.
2962 DAG.LIS->reanalyze(DAG.MF);
2963 // Liveins may have been modified for cross RC copies
2964 RegionPressureMap LiveInUpdater(&DAG, false);
2965 LiveInUpdater.buildLiveRegMap();
2966
2967 for (unsigned Region = 0; Region < DAG.Regions.size(); Region++)
2968 DAG.LiveIns[Region] = LiveInUpdater.getLiveRegsForRegionIdx(Region);
2969
2970 DAG.Pressure[RegionIdx] = DAG.getRealRegPressure(RegionIdx);
2971
2972 return true;
2973}
2974
2975unsigned PreRARematStage::getStageTargetOccupancy() const {
2976 return TargetOcc ? *TargetOcc : MFI.getMinWavesPerEU();
2977}
2978
2979bool PreRARematStage::setObjective() {
2980 const Function &F = MF.getFunction();
2981
2982 // Set up "spilling targets" for all regions.
2983 unsigned MaxSGPRs = ST.getMaxNumSGPRs(F);
2984 unsigned MaxVGPRs = ST.getMaxNumVGPRs(F);
2985 bool HasVectorRegisterExcess = false;
2986 for (unsigned I = 0, E = DAG.Regions.size(); I != E; ++I) {
2987 const GCNRegPressure &RP = DAG.Pressure[I];
2988 GCNRPTarget &Target = RPTargets.emplace_back(MaxSGPRs, MaxVGPRs, MF, RP);
2989 if (!Target.satisfied())
2990 TargetRegions.set(I);
2991 HasVectorRegisterExcess |= Target.hasVectorRegisterExcess();
2992 }
2993
2994 if (HasVectorRegisterExcess || DAG.MinOccupancy >= MFI.getMaxWavesPerEU()) {
2995 // In addition to register usage being above addressable limits, occupancy
2996 // below the minimum is considered like "spilling" as well.
2997 TargetOcc = std::nullopt;
2998 } else {
2999 // There is no spilling and room to improve occupancy; set up "increased
3000 // occupancy targets" for all regions.
3001 TargetOcc = DAG.MinOccupancy + 1;
3002 const unsigned VGPRBlockSize = MFI.getDynamicVGPRBlockSize();
3003 MaxSGPRs = ST.getMaxNumSGPRs(*TargetOcc, false);
3004 MaxVGPRs = ST.getMaxNumVGPRs(*TargetOcc, VGPRBlockSize);
3005 for (auto [I, Target] : enumerate(RPTargets)) {
3006 Target.setTarget(MaxSGPRs, MaxVGPRs);
3007 if (!Target.satisfied())
3008 TargetRegions.set(I);
3009 }
3010 }
3011
3012 return TargetRegions.any();
3013}
3014
3015bool PreRARematStage::ScoredRemat::maybeBeneficial(
3016 const BitVector &TargetRegions, ArrayRef<GCNRPTarget> RPTargets) const {
3017 for (unsigned I : TargetRegions.set_bits()) {
3018 if (Live[I] && RPTargets[I].isSaveBeneficial(RPSave))
3019 return true;
3020 }
3021 return false;
3022}
3023
3027 MachineCycleInfo MCI;
3028 MCI.compute(MF);
3029 MachineBlockFrequencyInfo MBFI(MF, MBPI, MCI);
3030
3031 const unsigned NumRegions = DAG.Regions.size();
3033 MaxFreq = 0;
3034 Regions.reserve(NumRegions);
3035 for (unsigned I = 0; I < NumRegions; ++I) {
3036 MachineBasicBlock *MBB = DAG.Regions[I].first->getParent();
3037 uint64_t BlockFreq = MBFI.getBlockFreq(MBB).getFrequency();
3038 Regions.push_back(BlockFreq);
3039 if (BlockFreq && BlockFreq < MinFreq)
3040 MinFreq = BlockFreq;
3041 else if (BlockFreq > MaxFreq)
3042 MaxFreq = BlockFreq;
3043 }
3044 if (!MinFreq)
3045 return;
3046
3047 // Scale everything down if frequencies are high.
3048 if (MinFreq >= ScaleFactor * ScaleFactor) {
3049 for (uint64_t &Freq : Regions)
3050 Freq /= ScaleFactor;
3051 MinFreq /= ScaleFactor;
3052 MaxFreq /= ScaleFactor;
3053 }
3054}
3055
3056void PreRARematStage::ScoredRemat::init(RegisterIdx RegIdx,
3057 const FreqInfo &Freq,
3058 const Rematerializer &Remater,
3060 this->RegIdx = RegIdx;
3061 const unsigned NumRegions = DAG.Regions.size();
3062 LiveIn.resize(NumRegions);
3063 LiveOut.resize(NumRegions);
3064 Live.resize(NumRegions);
3065 UnpredictableRPSave.resize(NumRegions);
3066
3067 const Rematerializer::Reg &Reg = Remater.getReg(RegIdx);
3068 Register DefReg = Reg.getDefReg();
3069 assert(Reg.Uses.size() == 1 && "expected users in single region");
3070 const unsigned UseRegion = Reg.Uses.begin()->first;
3071
3072 // Mark regions in which the rematerializable register is live.
3073 for (unsigned I = 0, E = NumRegions; I != E; ++I) {
3074 if (DAG.LiveIns[I].contains(DefReg))
3075 LiveIn.set(I);
3076 if (DAG.RegionLiveOuts.getLiveRegsForRegionIdx(I).contains(DefReg))
3077 LiveOut.set(I);
3078
3079 // If the register is both unused and live-through in the region, the
3080 // latter's RP is guaranteed to decrease.
3081 if (!LiveIn[I] || !LiveOut[I] || I == UseRegion)
3082 UnpredictableRPSave.set(I);
3083 }
3084 Live |= LiveIn;
3085 Live |= LiveOut;
3086 RPSave.inc(DefReg, LaneBitmask::getNone(), Reg.Mask, DAG.MRI);
3087
3088 // Get frequencies of defining and using regions. A rematerialization from the
3089 // least frequent region to the most frequent region will yield the greatest
3090 // in order to penalize rematerializations from or into regions whose
3091 int64_t DefOrMin = std::max(Freq.Regions[Reg.DefRegion], Freq.MinFreq);
3092 int64_t UseOrMax = Freq.Regions[UseRegion];
3093 if (!UseOrMax)
3094 UseOrMax = Freq.MaxFreq;
3095 FreqDiff = DefOrMin - UseOrMax;
3096}
3097
3098void PreRARematStage::ScoredRemat::update(const BitVector &TargetRegions,
3099 ArrayRef<GCNRPTarget> RPTargets,
3100 const FreqInfo &FreqInfo,
3101 bool ReduceSpill) {
3102 MaxFreq = 0;
3103 RegionImpact = 0;
3104 for (unsigned I : TargetRegions.set_bits()) {
3105 if (!Live[I])
3106 continue;
3107
3108 // The rematerialization must contribute positively in at least one
3109 // register class with usage above the RP target for this region to
3110 // contribute to the score.
3111 const GCNRPTarget &RegionTarget = RPTargets[I];
3112 const unsigned NumRegsBenefit = RegionTarget.getNumRegsBenefit(RPSave);
3113 if (!NumRegsBenefit)
3114 continue;
3115
3116 // Regions in which RP is guaranteed to decrease have more weight.
3117 RegionImpact += (UnpredictableRPSave[I] ? 1 : 2) * NumRegsBenefit;
3118
3119 if (ReduceSpill) {
3120 uint64_t Freq = FreqInfo.Regions[I];
3121 if (UnpredictableRPSave[I]) {
3122 // Apply a frequency penalty in regions in which we are not sure that RP
3123 // will decrease.
3124 Freq /= 2;
3125 }
3126 MaxFreq = std::max(MaxFreq, Freq);
3127 }
3128 }
3129}
3130
3131void PreRARematStage::ScoredRemat::rematerialize(
3132 Rematerializer &Remater) const {
3133 const Rematerializer::Reg &Reg = Remater.getReg(RegIdx);
3134 Rematerializer::DependencyReuseInfo DRI;
3135 for (RegisterIdx DepRegIdx : Reg.Dependencies)
3136 DRI.reuse(DepRegIdx);
3137 unsigned UseRegion = Reg.Uses.begin()->first;
3138 Remater.rematerializeToRegion(RegIdx, UseRegion, DRI);
3139}
3140
3141void PreRARematStage::updateRPTargets(const BitVector &Regions,
3142 const GCNRegPressure &RPSave) {
3143 for (unsigned I : Regions.set_bits()) {
3144 RPTargets[I].saveRP(RPSave);
3145 if (TargetRegions[I] && RPTargets[I].satisfied()) {
3146 REMAT_DEBUG(dbgs() << " [" << I << "] Target reached!\n");
3147 TargetRegions.reset(I);
3148 }
3149 }
3150}
3151
3152bool PreRARematStage::updateAndVerifyRPTargets(const BitVector &Regions) {
3153 bool TooOptimistic = false;
3154 for (unsigned I : Regions.set_bits()) {
3155 GCNRPTarget &Target = RPTargets[I];
3156 Target.setRP(DAG.getRealRegPressure(I));
3157
3158 // Since we were optimistic in assessing RP decreases in these regions, we
3159 // may need to remark the target as a target region if RP didn't decrease
3160 // as expected.
3161 if (!TargetRegions[I] && !Target.satisfied()) {
3162 REMAT_DEBUG(dbgs() << " [" << I << "] Incorrect RP estimation\n");
3163 TooOptimistic = true;
3164 TargetRegions.set(I);
3165 }
3166 }
3167 return TooOptimistic;
3168}
3169
3170void PreRARematStage::removeFromLiveMaps(Register Reg, const BitVector &LiveIn,
3171 const BitVector &LiveOut) {
3172 assert(LiveIn.size() == DAG.Regions.size() &&
3173 LiveOut.size() == DAG.Regions.size() && "region num mismatch");
3174 for (unsigned I : LiveIn.set_bits())
3175 DAG.LiveIns[I].erase(Reg);
3176 for (unsigned I : LiveOut.set_bits())
3177 DAG.RegionLiveOuts.getLiveRegsForRegionIdx(I).erase(Reg);
3178}
3179
3180void PreRARematStage::addToLiveMaps(Register Reg, LaneBitmask Mask,
3181 const BitVector &LiveIn,
3182 const BitVector &LiveOut) {
3183 assert(LiveIn.size() == DAG.Regions.size() &&
3184 LiveOut.size() == DAG.Regions.size() && "region num mismatch");
3185 std::pair<Register, LaneBitmask> LiveReg(Reg, Mask);
3186 for (unsigned I : LiveIn.set_bits())
3187 DAG.LiveIns[I].insert(LiveReg);
3188 for (unsigned I : LiveOut.set_bits())
3189 DAG.RegionLiveOuts.getLiveRegsForRegionIdx(I).insert(LiveReg);
3190}
3191
3193 // We consider that reducing spilling is always beneficial so we never
3194 // rollback rematerializations or revert scheduling in such cases.
3195 if (!TargetOcc)
3196 return;
3197
3198 // When increasing occupancy, it is possible that re-scheduling is not able to
3199 // achieve the target occupancy in all regions, in which case re-scheduling in
3200 // all regions should be reverted.
3201 if (DAG.MinOccupancy >= *TargetOcc)
3202 return;
3203
3204 // Revert re-scheduling in all affected regions.
3205 for (const auto &[RegionIdx, OrigMIOrder, MaxPressure] : RegionReverts) {
3206 REMAT_DEBUG(dbgs() << "Reverting re-scheduling in region " << RegionIdx
3207 << '\n');
3208 DAG.Pressure[RegionIdx] = MaxPressure;
3209 modifyRegionSchedule(RegionIdx, OrigMIOrder);
3210 }
3211
3212 // It is possible that re-scheduling lowers occupancy over the one achieved
3213 // just through rematerializations, in which case we revert re-scheduling in
3214 // all regions but do not roll back rematerializations.
3215 if (AchievedOcc >= *TargetOcc) {
3216 DAG.setTargetOccupancy(AchievedOcc);
3217 return;
3218 }
3219
3220 // Reset the target occupancy to what it was pre-rematerialization.
3221 DAG.setTargetOccupancy(*TargetOcc - 1);
3222
3223 // Roll back changes made by the stage, then recompute pressure in all
3224 // affected regions.
3225 REMAT_DEBUG(dbgs() << "==== ROLLBACK ====\n");
3226 assert(Rollback && "rollbacker should be defined");
3227 Rollback->Listener.rollback(Remater);
3228 for (const auto &[RegIdx, LiveIn, LiveOut] : Rollback->LiveMapUpdates) {
3229 const Rematerializer::Reg &Reg = Remater.getReg(RegIdx);
3230 addToLiveMaps(Reg.getDefReg(), Reg.Mask, LiveIn, LiveOut);
3231 }
3232
3233#ifdef EXPENSIVE_CHECKS
3234 // In particular, we want to check for coherent MI/slot order in regions in
3235 // which reverts and/or rollbacks may have happened.
3236 MF.verify();
3237#endif
3238 for (unsigned I : RescheduleRegions.set_bits())
3239 DAG.Pressure[I] = DAG.getRealRegPressure(I);
3240
3242}
3243
3244void GCNScheduleDAGMILive::setTargetOccupancy(unsigned TargetOccupancy) {
3245 MinOccupancy = TargetOccupancy;
3246 if (MFI.getOccupancy() < TargetOccupancy)
3247 MFI.increaseOccupancy(MF, MinOccupancy);
3248 else
3249 MFI.limitOccupancy(MinOccupancy);
3250}
3251
3253 const SIInstrInfo *SII = static_cast<const SIInstrInfo *>(DAG->TII);
3254 return any_of(*DAG, [SII](MachineBasicBlock::iterator MI) {
3255 return SII->isIGLPMutationOnly(MI->getOpcode());
3256 });
3257}
3258
3263
3265 HasIGLPInstrs = hasIGLPInstrs(this);
3266 if (HasIGLPInstrs) {
3267 SavedMutations.clear();
3268 SavedMutations.swap(Mutations);
3270 }
3271
3273}
3274
3276 if (HasIGLPInstrs)
3277 SavedMutations.swap(Mutations);
3278
3280}
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static SUnit * pickOnlyChoice(SchedBoundary &Zone)
unsigned uint64_t
MachineBasicBlock & MBB
This file implements the BitVector class.
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file defines the GCNRegPressure class, which tracks registry pressure by bookkeeping number of S...
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))
#define REMAT_PREFIX
Allows to easily filter for this stage's debug output.
static cl::opt< unsigned, false, VGPRThresholdParser > VGPRThresholdPercentOpt("amdgpu-vgpr-threshold-percent", cl::Hidden, cl::desc("Percent of VGPR limits that we should use as RP threshold " "during scheduling. We have two limits relevant to scheduling: " "Critical (avoid decreasing occupancy), Excess (avoid spilling). " "This flag scales both limits back by an equal percent: (0 = use " " default calculation, 1-100 = use percentage), default: 0"), cl::init(0))
static MachineInstr * getLastMIForRegion(MachineBasicBlock::iterator RegionBegin, MachineBasicBlock::iterator RegionEnd)
static bool shouldCheckPending(SchedBoundary &Zone, const TargetSchedModel *SchedModel)
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))
#define REMAT_DEBUG(X)
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 isReachingDefAGPRForm(MachineInstr *RD, const SmallPtrSetImpl< MachineInstr * > &RewriteSet, const DenseSet< Register > &CandSrc2Regs, const SIInstrInfo &TII)
Returns true if reaching def RD will be in AGPR form after the rewrite and so needs no bridge copy: a...
static cl::opt< bool > PrintMaxRPRegUsageAfterScheduler("amdgpu-print-max-reg-pressure-regusage-after-scheduler", cl::Hidden, cl::desc("Print a list of live registers along with their def/uses at the " "point of maximum register pressure after scheduling."), cl::init(false))
static bool hasIGLPInstrs(ScheduleDAGInstrs *DAG)
static cl::opt< bool > DisableRewriteMFMAFormSchedStage("amdgpu-disable-rewrite-mfma-form-sched-stage", cl::Hidden, cl::desc("Disable rewrite mfma rewrite scheduling stage"), cl::init(true))
static bool canUsePressureDiffs(const SUnit &SU)
Checks whether SU can use the cached DAG pressure diffs to compute the current register pressure.
static cl::opt< unsigned > PendingQueueLimit("amdgpu-scheduler-pending-queue-limit", cl::Hidden, cl::desc("Max (Available+Pending) size to inspect pending queue (0 disables)"), cl::init(256))
static cl::opt< bool > PrintMaxRPRegUsageBeforeScheduler("amdgpu-print-max-reg-pressure-regusage-before-scheduler", cl::Hidden, cl::desc("Print a list of live registers along with their def/uses at the " "point of maximum register pressure before scheduling."), cl::init(false))
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))
static Register UseReg(const MachineOperand &MO)
const HexagonInstrInfo * TII
static constexpr std::pair< StringLiteral, StringLiteral > ReplaceMap[]
IRTranslator LLVM IR MI
iv Induction Variable Users
Definition IVUsers.cpp:48
A common definition of LaneBitmask for use in TableGen and CodeGen.
static llvm::Error parse(GsymDataExtractor &Data, uint64_t BaseAddr, LineEntryCallback const &Callback)
Definition LineTable.cpp:54
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Register Reg
Promote Memory to Register
Definition Mem2Reg.cpp:110
#define T
if(PassOpts->AAPipeline)
MIR-level target-independent rematerialization helpers.
This file contains some templates that are useful if you are working with the STL at all.
#define LLVM_DEBUG(...)
Definition Debug.h:119
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
const T & front() const
Get the first element.
Definition ArrayRef.h:144
size_t size() const
Get the array size.
Definition ArrayRef.h:141
bool empty() const
Check if the array is empty.
Definition ArrayRef.h:136
iterator_range< const_set_bits_iterator > set_bits() const
Definition BitVector.h:159
size_type size() const
Returns the number of bits in this bitvector.
Definition BitVector.h:178
uint64_t getFrequency() const
Returns the frequency as a fixpoint number scaled by the entry frequency.
bool shouldRevertScheduling(unsigned WavesAfter) override
iterator find(const_arg_type_t< KeyT > Val)
Definition DenseMap.h:223
bool erase(const KeyT &Val)
Definition DenseMap.h:377
iterator end()
Definition DenseMap.h:141
bool contains(const_arg_type_t< KeyT > Val) const
Return true if the specified key is in the map, false otherwise.
Definition DenseMap.h:214
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition DenseMap.h:284
Implements a dense probed hash-table based set.
Definition DenseSet.h:281
bool reset(const MachineInstr &MI, MachineBasicBlock::const_iterator End, const LiveRegSet *LiveRegs=nullptr)
Reset tracker to the point before the MI filling LiveRegs upon this point using LIS.
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
Orders nodes according to selected style.
GCNPostScheduleDAGMILive(MachineSchedContext *C, std::unique_ptr< MachineSchedStrategy > S, bool RemoveKillFlags)
Models a register pressure target, allowing to evaluate and track register savings against that targe...
unsigned getNumRegsBenefit(const GCNRegPressure &SaveRP) const
Returns the benefit towards achieving the RP target that saving SaveRP represents,...
GCNRegPressure getPressure() const
GCNSchedStrategy & S
GCNRegPressure PressureBefore
bool isRegionWithExcessRP() const
void modifyRegionSchedule(unsigned RegionIdx, ArrayRef< MachineInstr * > MIOrder)
Sets the schedule of region RegionIdx to MIOrder.
bool mayCauseSpilling(unsigned WavesAfter)
ScheduleMetrics getScheduleMetrics(const std::vector< SUnit > &InputSchedule)
GCNScheduleDAGMILive & DAG
const GCNSchedStageID StageID
std::vector< MachineInstr * > Unsched
GCNRegPressure PressureAfter
MachineFunction & MF
virtual void finalizeGCNRegion()
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.
GCNDownwardRPTracker DownwardTracker
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)
GCNSchedStrategy(const MachineSchedContext *C)
SmallVector< GCNSchedStageID, 4 > SchedStages
std::vector< unsigned > MaxPressure
SUnit * pickNodeBidirectional(bool &IsTopNode, bool &PickedPending)
GCNSchedStageID getCurrentStage()
bool tryPendingCandidate(SchedCandidate &Cand, SchedCandidate &TryCand, SchedBoundary *Zone) const
Evaluates instructions in the pending queue using a subset of scheduling heuristics.
SmallVectorImpl< GCNSchedStageID >::iterator CurrentStage
void schedNode(SUnit *SU, bool IsTopNode) override
Notify MachineSchedStrategy that ScheduleDAGMI has scheduled an instruction and updated scheduled/rem...
std::optional< bool > GCNTrackersOverride
GCNDownwardRPTracker * getDownwardTracker()
std::vector< unsigned > Pressure
void initialize(ScheduleDAGMI *DAG) override
Initialize the strategy after building the DAG for a new region.
GCNUpwardRPTracker UpwardTracker
void printCandidateDecision(const SchedCandidate &Current, const SchedCandidate &Preferred)
void pickNodeFromQueue(SchedBoundary &Zone, const CandPolicy &ZonePolicy, const RegPressureTracker &RPTracker, SchedCandidate &Cand, bool &IsPending, bool IsBottomUp)
unsigned getStructuralStallCycles(SchedBoundary &Zone, SUnit *SU) const
Estimate how many cycles SU must wait due to structural hazards at the current boundary cycle.
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 next node to schedule, or return NULL.
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
Orders nodes according to selected style.
GCNScheduleDAGMILive(MachineSchedContext *C, std::unique_ptr< MachineSchedStrategy > S)
void recede(const MachineInstr &MI)
Move to the state of RP just before the MI .
void reset(const MachineInstr &MI)
Resets tracker to the point just after MI (in program order), which can be a debug instruction.
void compute(FunctionT &F)
Compute the cycle info for a function.
void traceCandidate(const SchedCandidate &Cand)
LLVM_ABI 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
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.
GenericScheduler(const MachineSchedContext *C)
bool shouldRevertScheduling(unsigned WavesAfter) override
LiveInterval - This class represents the liveness of a register, or stack slot.
bool hasSubRanges() const
Returns true if subregister liveness information is available.
iterator_range< subrange_iterator > subranges()
SlotIndex getInstructionIndex(const MachineInstr &Instr) const
Returns the base index of the given instruction.
SlotIndex getMBBEndIdx(const MachineBasicBlock *mbb) const
Return the last index in the given basic block.
LiveInterval & getInterval(Register Reg)
LLVM_ABI void dump() const
MachineBasicBlock * getMBBFromIndex(SlotIndex index) const
VNInfo * getVNInfoAt(SlotIndex Idx) const
getVNInfoAt - Return the VNInfo that is live at Idx, or NULL.
uint8_t getCopyCost() const
getCopyCost - Return the cost of copying a value between two registers in this class.
int getNumber() const
MachineBasicBlocks are uniquely numbered at the function level, unless they're not in a MachineFuncti...
iterator_range< pred_iterator > predecessors()
MachineInstrBundleIterator< MachineInstr > iterator
MachineBlockFrequencyInfo pass uses BlockFrequencyInfoImpl implementation to estimate machine basic b...
LLVM_ABI BlockFrequency getBlockFreq(const MachineBasicBlock *MBB) const
getblockFreq - Return block frequency.
LLVM_ABI BlockFrequency getEntryFreq() const
Divide a block's BlockFrequency::getFrequency() value by this value to obtain the entry block - relat...
const MachineInstrBuilder & addUse(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & addDef(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register definition operand.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
bool isCopy() const
const MachineBasicBlock * getParent() const
unsigned getNumOperands() const
Retuns the total number of operands.
bool mayLoad(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly read memory.
mop_range operands()
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
const MachineOperand & getOperand(unsigned i) const
MachineOperand class - Representation of each machine instruction operand.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
Register getReg() const
getReg - Returns the register number.
bool shouldRevertScheduling(unsigned WavesAfter) override
bool shouldRevertScheduling(unsigned WavesAfter) override
bool shouldRevertScheduling(unsigned WavesAfter) override
void finalizeGCNRegion() override
bool initGCNSchedStage() override
Capture a change in pressure for a single pressure set.
Simple wrapper around std::function<void(raw_ostream&)>.
Definition Printable.h:38
Helpers for implementing custom MachineSchedStrategy classes.
unsigned size() const
Track the current register pressure at some position in the instruction stream, and remember the high...
LLVM_ABI void advance()
Advance across the current instruction.
LLVM_ABI 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...
LLVM_ABI 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.
List of registers defined and used by a machine instruction.
LLVM_ABI void adjustLaneLiveness(const LiveIntervals &LIS, const MachineRegisterInfo &MRI, SlotIndex Pos)
Use liveness information to find out which uses/defs are partially undefined/dead at Pos and adjust t...
LLVM_ABI 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...
LLVM_ABI 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:20
constexpr bool isValid() const
Definition Register.h:112
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
Definition Register.h:79
MIR-level target-independent rematerializer.
bool isIGLPMutationOnly(unsigned Opcode) const
This class keeps track of the SPI_SP_INPUT_ADDR config register, which tells the hardware which inter...
Scheduling unit. This is a node in the scheduling DAG.
bool isInstr() const
Returns true if this SUnit refers to a machine instruction as opposed to an SDNode.
unsigned TopReadyCycle
Cycle relative to start when node is ready.
unsigned NodeNum
Entry # of node in the node vector.
unsigned short Latency
Node latency.
bool isScheduled
True once scheduled.
unsigned ParentClusterIdx
The parent cluster id.
unsigned BotReadyCycle
Cycle relative to end when node is ready.
bool hasReservedResource
Uses a reserved resource.
bool isBottomReady() const
bool isTopReady() const
SmallVector< SDep, 4 > Preds
All sunit predecessors.
MachineInstr * getInstr() const
Returns the representative MachineInstr for this SUnit.
Each Scheduling boundary is associated with ready queues.
LLVM_ABI void releasePending()
Release pending ready nodes in to the available queue.
LLVM_ABI unsigned getLatencyStallCycles(SUnit *SU)
Get the difference between the given SUnit's ready time and the current cycle.
LLVM_ABI SUnit * pickOnlyChoice()
Call this before applying any other heuristics to the Available queue.
LLVM_ABI void bumpCycle(unsigned NextCycle)
Move the boundary of scheduled code by one cycle.
unsigned getCurrMOps() const
Micro-ops issued in the current cycle.
unsigned getCurrCycle() const
Number of cycles to issue the instructions scheduled in this zone.
std::unique_ptr< ScheduleHazardRecognizer > HazardRec
LLVM_ABI bool checkHazard(SUnit *SU)
Does this SU have a hazard within the current instruction group.
LLVM_ABI std::pair< unsigned, unsigned > getNextResourceCycle(const MCSchedClassDesc *SC, unsigned PIdx, unsigned ReleaseAtCycle, unsigned AcquireAtCycle)
Compute the next cycle at which the given processor resource can be scheduled.
A ScheduleDAG for scheduling lists of MachineInstr.
bool ScheduleSingleMIRegions
True if regions with a single MI should be scheduled.
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.
virtual void exitRegion()
Called when the scheduler has finished scheduling the current region.
const MachineLoopInfo * MLI
bool RemoveKillFlags
True if the DAG builder should remove kill flags (in preparation for rescheduling).
MachineBasicBlock::iterator RegionBegin
The beginning of the range to be scheduled.
void schedule() override
Implement ScheduleDAGInstrs interface for scheduling a sequence of reorderable instructions.
ScheduleDAGMILive(MachineSchedContext *C, std::unique_ptr< MachineSchedStrategy > S)
RegPressureTracker RPTracker
ScheduleDAGMI is an implementation of ScheduleDAGInstrs that simply schedules machine instructions ac...
void addMutation(std::unique_ptr< ScheduleDAGMutation > Mutation)
Add a postprocessing step to the DAG builder.
void schedule() override
Implement ScheduleDAGInstrs interface for scheduling a sequence of reorderable instructions.
ScheduleDAGMI(MachineSchedContext *C, std::unique_ptr< MachineSchedStrategy > S, bool RemoveKillFlags)
std::vector< std::unique_ptr< ScheduleDAGMutation > > Mutations
Ordered list of DAG postprocessing steps.
MachineRegisterInfo & MRI
Virtual/real register map.
const TargetInstrInfo * TII
Target instruction information.
MachineFunction & MF
Machine function.
static const unsigned ScaleFactor
unsigned getMetric() const
bool empty() const
Determine if the SetVector is empty or not.
Definition SetVector.h:100
bool insert(const value_type &X)
Insert a new element into the SetVector.
Definition SetVector.h:157
SlotIndex - An opaque wrapper around machine indexes.
Definition SlotIndexes.h:66
static bool isSameInstr(SlotIndex A, SlotIndex B)
isSameInstr - Return true if A and B refer to the same instruction.
static bool isEarlierInstr(SlotIndex A, SlotIndex B)
isEarlierInstr - Return true if A refers to an instruction earlier than B.
SlotIndex getPrevSlot() const
Returns the previous slot in the index list.
SlotIndex getMBBStartIdx(const MachineBasicBlock *mbb) const
Returns the first index in the given basic block.
A templated base class for SmallPtrSet which provides the typesafe interface that is common across al...
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
Definition SmallSet.h:134
bool contains(const T &V) const
Check if the SmallSet contains the given element.
Definition SmallSet.h:229
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:184
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
bool getAsInteger(unsigned Radix, T &Result) const
Parse the current string as an integer of the specified radix.
Definition StringRef.h:490
Provide an instruction scheduling machine model to CodeGen passes.
LLVM_ABI bool hasInstrSchedModel() const
Return true if this machine model includes an instruction-level scheduling model.
unsigned getMicroOpBufferSize() const
Number of micro-ops that may be buffered for OOO execution.
bool shouldRevertScheduling(unsigned WavesAfter) override
VNInfo - Value Number Information.
SlotIndex def
The index of the defining instruction.
bool isPHIDef() const
Returns true if this value is defined by a PHI instruction (or was, PHI instructions may have been el...
std::pair< iterator, bool > insert(const ValueT &V)
Definition DenseSet.h:209
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
Definition DenseSet.h:182
self_iterator getIterator()
Definition ilist_node.h:123
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
Changed
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned getAddressableNumVGPRs(const MCSubtargetInfo &STI, unsigned DynamicVGPRBlockSize)
unsigned getAllocatedNumVGPRBlocks(const MCSubtargetInfo &STI, unsigned NumVGPRs, unsigned DynamicVGPRBlockSize, std::optional< bool > EnableWavefrontSize32)
unsigned getVGPRAllocGranule(const MCSubtargetInfo &STI, unsigned DynamicVGPRBlockSize, std::optional< bool > EnableWavefrontSize32)
LLVM_READONLY int32_t getAGPRFormOp(uint32_t Opcode)
@ Entry
Definition COFF.h:862
This namespace contains all of the command line option processing machinery.
Definition MCSchedule.h:35
initializer< Ty > init(const Ty &Val)
@ User
could "use" a pointer
NodeAddr< UseNode * > Use
Definition RDFGraph.h:385
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI int biasPhysReg(const SUnit *SU, bool isTop, bool BiasPRegsExtra=false)
Minimize physical register live ranges.
auto find(R &&Range, const T &Val)
Provide wrappers to std::find which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1765
bool isEqual(const GCNRPTracker::LiveRegSet &S1, const GCNRPTracker::LiveRegSet &S2)
Printable print(const GCNRegPressure &RP, const GCNSubtarget *ST=nullptr, unsigned DynamicVGPRBlockSize=0)
LLVM_ABI unsigned getWeakLeft(const SUnit *SU, bool isTop)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
InstructionCost Cost
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
Definition STLExtras.h:2554
GCNRegPressure getRegPressure(const MachineRegisterInfo &MRI, Range &&LiveRegs)
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
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:547
std::pair< MachineBasicBlock::iterator, MachineBasicBlock::iterator > RegionBoundaries
A region's boundaries i.e.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
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
LLVM_ABI 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:407
void sort(IteratorTy Start, IteratorTy End)
Definition STLExtras.h:1636
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
LLVM_ABI cl::opt< bool > VerifyScheduling
LLVM_ABI bool tryLatency(GenericSchedulerBase::SchedCandidate &TryCand, GenericSchedulerBase::SchedCandidate &Cand, SchedBoundary &Zone)
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
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...
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
bool isTheSameCluster(unsigned A, unsigned B)
Return whether the input cluster ID's are the same and valid.
DWARFExpression::Operation Op
LLVM_ABI bool tryGreater(int TryVal, int CandVal, GenericSchedulerBase::SchedCandidate &TryCand, GenericSchedulerBase::SchedCandidate &Cand, GenericSchedulerBase::CandReason Reason)
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
ArrayRef(const T &OneElt) -> ArrayRef< T >
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:1917
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)
LLVM_ABI bool tryLess(int TryVal, int CandVal, GenericSchedulerBase::SchedCandidate &TryCand, GenericSchedulerBase::SchedCandidate &Cand, GenericSchedulerBase::CandReason Reason)
Return true if this heuristic determines order.
LLVM_ABI void dumpMaxRegPressure(MachineFunction &MF, GCNRegPressure::RegKind Kind, LiveIntervals &LIS, const MachineLoopInfo *MLI)
LLVM_ABI Printable printMBBReference(const MachineBasicBlock &MBB)
Prints a machine basic block reference.
MCRegisterClass TargetRegisterClass
Definition FastISel.h:58
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:878
bool operator()(std::pair< MachineInstr *, unsigned > A, std::pair< MachineInstr *, unsigned > B) const
unsigned getArchVGPRNum() const
unsigned getAGPRNum() const
unsigned getSGPRNum() const
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)
LLVM_ABI void initResourceDelta(const ScheduleDAGMI *DAG, const TargetSchedModel *SchedModel)
Status of an instruction's critical resource consumption.
constexpr bool any() const
Definition LaneBitmask.h:53
static constexpr LaneBitmask getNone()
Definition LaneBitmask.h:81
Summarize the scheduling resources required for an instruction of a particular scheduling class.
Definition MCSchedule.h:129
Identify one of the processor resource kinds consumed by a particular scheduling class for the specif...
Definition MCSchedule.h:74
MachineSchedContext provides enough context from the MachineScheduler pass for the target to instanti...
Execution frequency information required by scoring heuristics.
SmallVector< uint64_t > Regions
Per-region execution frequencies. 0 when unknown.
uint64_t MinFreq
Minimum and maximum observed frequencies.
FreqInfo(MachineFunction &MF, const GCNScheduleDAGMILive &DAG)
DependencyReuseInfo & reuse(RegisterIdx DepIdx)
A rematerializable register, potentially defined by multiple instructions.
LLVM_ABI std::pair< MachineInstr *, MachineInstr * > getRegionUseBounds(unsigned UseRegion, const LiveIntervals &LIS) const
Returns the first and last user of the register in region UseRegion.
SmallVector< MachineInstr *, 1 > Defs
All instructions that define the register, in program order.
SmallDenseMap< unsigned, RegionUsers, 2 > Uses
Uses of the register, mapped by region.
MachineInstr * getLastDef() const
SmallVector< RegisterIdx, 2 > Dependencies
This register's rematerializable dependencies, one per unique rematerializable register operand over ...