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