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