LLVM 24.0.0git
GCNSchedStrategy.cpp
Go to the documentation of this file.
1//===-- GCNSchedStrategy.cpp - GCN Scheduler Strategy ---------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9/// \file
10/// This contains a MachineSchedStrategy implementation for maximizing wave
11/// occupancy on GCN hardware.
12///
13/// This pass will apply multiple scheduling stages to the same function.
14/// Regions are first recorded in GCNScheduleDAGMILive::schedule. The actual
15/// entry point for the scheduling of those regions is
16/// GCNScheduleDAGMILive::runSchedStages.
17
18/// Generally, the reason for having multiple scheduling stages is to account
19/// for the kernel-wide effect of register usage on occupancy. Usually, only a
20/// few scheduling regions will have register pressure high enough to limit
21/// occupancy for the kernel, so constraints can be relaxed to improve ILP in
22/// other regions.
23///
24//===----------------------------------------------------------------------===//
25
26#include "GCNSchedStrategy.h"
27#include "AMDGPUIGroupLP.h"
28#include "GCNHazardRecognizer.h"
29#include "GCNRegPressure.h"
32#include "llvm/ADT/BitVector.h"
33#include "llvm/ADT/STLExtras.h"
42#include "llvm/MC/LaneBitmask.h"
43#include "llvm/MC/MCSchedule.h"
46
47#define DEBUG_TYPE "machine-scheduler"
48
49using namespace llvm;
50
52 "amdgpu-disable-unclustered-high-rp-reschedule", cl::Hidden,
53 cl::desc("Disable unclustered high register pressure "
54 "reduction scheduling stage."),
55 cl::init(false));
56
58 "amdgpu-disable-clustered-low-occupancy-reschedule", cl::Hidden,
59 cl::desc("Disable clustered low occupancy "
60 "rescheduling for ILP scheduling stage."),
61 cl::init(false));
62
64 "amdgpu-schedule-metric-bias", cl::Hidden,
66 "Sets the bias which adds weight to occupancy vs latency. Set it to "
67 "100 to chase the occupancy only."),
68 cl::init(10));
69
70static cl::opt<bool>
71 RelaxedOcc("amdgpu-schedule-relaxed-occupancy", cl::Hidden,
72 cl::desc("Relax occupancy targets for kernels which are memory "
73 "bound (amdgpu-membound-threshold), or "
74 "Wave Limited (amdgpu-limit-wave-threshold)."),
75 cl::init(false));
76
78 "amdgpu-use-amdgpu-trackers", cl::Hidden,
79 cl::desc("Use the AMDGPU specific RPTrackers during scheduling"),
80 cl::init(false));
81
83 "amdgpu-scheduler-pending-queue-limit", cl::Hidden,
85 "Max (Available+Pending) size to inspect pending queue (0 disables)"),
86 cl::init(256));
87
88#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
89#define DUMP_MAX_REG_PRESSURE
91 "amdgpu-print-max-reg-pressure-regusage-before-scheduler", cl::Hidden,
92 cl::desc("Print a list of live registers along with their def/uses at the "
93 "point of maximum register pressure before scheduling."),
94 cl::init(false));
95
97 "amdgpu-print-max-reg-pressure-regusage-after-scheduler", cl::Hidden,
98 cl::desc("Print a list of live registers along with their def/uses at the "
99 "point of maximum register pressure after scheduling."),
100 cl::init(false));
101#endif
102
104 "amdgpu-disable-rewrite-mfma-form-sched-stage", cl::Hidden,
105 cl::desc("Disable rewrite mfma rewrite scheduling stage"), cl::init(true));
106
108 unsigned &Value) {
109 if (Arg.getAsInteger(0, Value))
110 return O.error("'" + Arg + "' value invalid for uint argument!");
111
112 if (Value > 100)
113 return O.error("'" + Arg + "' value must be in the range [0, 100]!");
114
115 return false;
116}
117
119 "amdgpu-vgpr-threshold-percent", cl::Hidden,
120 cl::desc("Percent of VGPR limits that we should use as RP threshold "
121 "during scheduling. We have two limits relevant to scheduling: "
122 "Critical (avoid decreasing occupancy), Excess (avoid spilling). "
123 "This flag scales both limits back by an equal percent: (0 = use "
124 " default calculation, 1-100 = use percentage), default: 0"),
125 cl::init(0));
126
127const unsigned ScheduleMetrics::ScaleFactor = 100;
128
136
139
140 MF = &DAG->MF;
141
142 const GCNSubtarget &ST = MF->getSubtarget<GCNSubtarget>();
143
145 Context->RegClassInfo->getNumAllocatableRegs(&AMDGPU::SGPR_32RegClass);
147 Context->RegClassInfo->getNumAllocatableRegs(&AMDGPU::VGPR_32RegClass);
149 Context->RegClassInfo->getNumAllocatableRegs(&AMDGPU::AGPR_32RegClass);
150
152 // Set the initial TargetOccupnacy to the maximum occupancy that we can
153 // achieve for this function. This effectively sets a lower bound on the
154 // 'Critical' register limits in the scheduler.
155 // Allow for lower occupancy targets if kernel is wave limited or memory
156 // bound, and using the relaxed occupancy feature.
160 std::min(ST.getMaxNumSGPRs(TargetOccupancy, true), SGPRExcessLimit);
161
162 if (!KnownExcessRP) {
163 // Preserve the combined occupancy budget before clamping to one bank.
165 ST.getMaxNumVGPRs(TargetOccupancy, MFI.getDynamicVGPRBlockSize());
167 } else {
168 // This is similar to ST.getMaxNumVGPRs(TargetOccupancy) result except
169 // returns a reasonably small number for targets with lots of VGPRs, such
170 // as GFX10 and GFX11.
171 LLVM_DEBUG(dbgs() << "Region is known to spill, use alternative "
172 "VGPRCriticalLimit calculation method.\n");
173 unsigned DynamicVGPRBlockSize = MFI.getDynamicVGPRBlockSize();
174 unsigned Granule =
175 AMDGPU::IsaInfo::getVGPRAllocGranule(ST, DynamicVGPRBlockSize);
176 unsigned Addressable =
177 AMDGPU::IsaInfo::getAddressableNumVGPRs(ST, DynamicVGPRBlockSize);
178 unsigned VGPRBudget = alignDown(Addressable / TargetOccupancy, Granule);
179 VGPRBudget = std::max(VGPRBudget, Granule);
180 UnifiedVGPRCriticalLimit = VGPRBudget;
181 VGPRCriticalLimit = std::min(VGPRBudget, VGPRExcessLimit);
182 }
183
184 // Reuse VGPR critical limit
186
187 // Apply VGPR excess threshold percentage if specified.
188 if (VGPRThresholdPercent > 0) {
189 [[maybe_unused]] unsigned OriginalVGPRExcessLimit = VGPRExcessLimit;
190 [[maybe_unused]] unsigned OriginalVGPRCriticalLimit = VGPRCriticalLimit;
195 LLVM_DEBUG(dbgs() << "Applied VGPR excess threshold "
196 << VGPRThresholdPercent << "%, VGPRExcessLimit: "
197 << OriginalVGPRExcessLimit << " -> " << VGPRExcessLimit
198 << ". VGPRCriticalLimit: " << OriginalVGPRCriticalLimit
199 << " -> " << VGPRCriticalLimit << '\n');
200 } else {
206 }
207
208 // Subtract error margin and bias from register limits and avoid overflow.
211
214
215 LLVM_DEBUG(dbgs() << "VGPRCriticalLimit = " << VGPRCriticalLimit
216 << ", UnifiedVGPRCriticalLimit = "
218 << ", VGPRExcessLimit = " << VGPRExcessLimit
219 << ", AGPRCriticalLimit = " << AGPRCriticalLimit
220 << ", AGPRExcessLimit = " << AGPRExcessLimit
221 << ", SGPRCriticalLimit = " << SGPRCriticalLimit
222 << ", SGPRExcessLimit = " << SGPRExcessLimit << "\n\n");
223}
224
225/// Checks whether \p SU can use the cached DAG pressure diffs to compute the
226/// current register pressure.
227///
228/// This works for the common case, but it has a few exceptions that have been
229/// observed through trial and error:
230/// - Explicit physical register operands
231/// - Subregister definitions
232///
233/// In both of those cases, PressureDiff doesn't represent the actual pressure,
234/// and querying LiveIntervals through the RegPressureTracker is needed to get
235/// an accurate value.
236///
237/// We should eventually only use PressureDiff for maximum performance, but this
238/// already allows 80% of SUs to take the fast path without changing scheduling
239/// at all. Further changes would either change scheduling, or require a lot
240/// more logic to recover an accurate pressure estimate from the PressureDiffs.
241static bool canUsePressureDiffs(const SUnit &SU) {
242 if (!SU.isInstr())
243 return false;
244
245 // Cannot use pressure diffs for subregister defs or with physregs, it's
246 // imprecise in both cases. For a bundle, check the instructions inside it:
247 // the BUNDLE header only has implicit operands.
248 for (const auto &Op : const_mi_bundle_ops(*SU.getInstr())) {
249 if (!Op.isReg() || Op.isImplicit())
250 continue;
251 if (Op.getReg().isPhysical() ||
252 (Op.isDef() && Op.getSubReg() != AMDGPU::NoSubRegister))
253 return false;
254 }
255 return true;
256}
257
259 bool AtTop, const RegPressureTracker &RPTracker, SUnit *SU,
260 std::vector<unsigned> &Pressure, std::vector<unsigned> &MaxPressure,
263 const SIRegisterInfo *SRI) {
264 // getDownwardPressure() and getUpwardPressure() make temporary changes to
265 // the tracker, so we need to pass those function a non-const copy.
266 RegPressureTracker &TempTracker = const_cast<RegPressureTracker &>(RPTracker);
267 if (!useGCNTrackers()) {
268 AtTop
269 ? TempTracker.getDownwardPressure(SU->getInstr(), Pressure, MaxPressure)
270 : TempTracker.getUpwardPressure(SU->getInstr(), Pressure, MaxPressure);
271
272 return;
273 }
274
275 // GCNTrackers
276 Pressure.resize(4, 0);
277 MachineInstr *MI = SU->getInstr();
278 GCNRegPressure NewPressure;
279 if (AtTop) {
280 NewPressure = DownwardTracker.bumpDownwardPressure(MI, SRI);
281 } else {
282 GCNUpwardRPTracker TempUpwardTracker(UpwardTracker);
283 TempUpwardTracker.recede(*MI);
284 NewPressure = TempUpwardTracker.getPressure();
285 }
286 Pressure[AMDGPU::RegisterPressureSets::SReg_32] = NewPressure.getSGPRNum();
287 Pressure[AMDGPU::RegisterPressureSets::VGPR_32] =
288 NewPressure.getArchVGPRNum();
289 Pressure[AMDGPU::RegisterPressureSets::AGPR_32] = NewPressure.getAGPRNum();
290}
291
293 bool AtTop,
294 const RegPressureTracker &RPTracker,
295 const SIRegisterInfo *SRI,
296 unsigned SGPRPressure,
297 unsigned VGPRPressure,
298 unsigned AGPRPressure, bool IsBottomUp) {
299 Cand.SU = SU;
300 Cand.AtTop = AtTop;
301
302 if (!DAG->isTrackingPressure())
303 return;
304
305 Pressure.clear();
306 MaxPressure.clear();
307
308 // We try to use the cached PressureDiffs in the ScheduleDAG whenever
309 // possible over querying the RegPressureTracker.
310 //
311 // RegPressureTracker will make a lot of LIS queries which are very
312 // expensive, it is considered a slow function in this context.
313 //
314 // PressureDiffs are precomputed and cached, and getPressureDiff is just a
315 // trivial lookup into an array. It is pretty much free.
316 //
317 // In EXPENSIVE_CHECKS, we always query RPTracker to verify the results of
318 // PressureDiffs.
319 if (AtTop || !canUsePressureDiffs(*SU) || useGCNTrackers()) {
320 getRegisterPressures(AtTop, RPTracker, SU, Pressure, MaxPressure,
322 } else {
323 // Reserve 4 slots.
324 Pressure.resize(4, 0);
325 Pressure[AMDGPU::RegisterPressureSets::SReg_32] = SGPRPressure;
326 Pressure[AMDGPU::RegisterPressureSets::VGPR_32] = VGPRPressure;
327 Pressure[AMDGPU::RegisterPressureSets::AGPR_32] = AGPRPressure;
328
329 for (const auto &Diff : DAG->getPressureDiff(SU)) {
330 if (!Diff.isValid())
331 continue;
332 // PressureDiffs is always bottom-up so if we're working top-down we need
333 // to invert its sign.
334 Pressure[Diff.getPSet()] +=
335 (IsBottomUp ? Diff.getUnitInc() : -Diff.getUnitInc());
336 }
337
338#ifdef EXPENSIVE_CHECKS
339 std::vector<unsigned> CheckPressure, CheckMaxPressure;
340 getRegisterPressures(AtTop, RPTracker, SU, CheckPressure, CheckMaxPressure,
342 if (Pressure[AMDGPU::RegisterPressureSets::SReg_32] !=
343 CheckPressure[AMDGPU::RegisterPressureSets::SReg_32] ||
344 Pressure[AMDGPU::RegisterPressureSets::VGPR_32] !=
345 CheckPressure[AMDGPU::RegisterPressureSets::VGPR_32] ||
346 Pressure[AMDGPU::RegisterPressureSets::AGPR_32] !=
347 CheckPressure[AMDGPU::RegisterPressureSets::AGPR_32]) {
348 errs() << "Register Pressure is inaccurate when calculated through "
349 "PressureDiff\n"
350 << "SGPR got " << Pressure[AMDGPU::RegisterPressureSets::SReg_32]
351 << ", expected "
352 << CheckPressure[AMDGPU::RegisterPressureSets::SReg_32] << "\n"
353 << "VGPR got " << Pressure[AMDGPU::RegisterPressureSets::VGPR_32]
354 << ", expected "
355 << CheckPressure[AMDGPU::RegisterPressureSets::VGPR_32] << "\n"
356 << "AGPR got " << Pressure[AMDGPU::RegisterPressureSets::AGPR_32]
357 << ", expected "
358 << CheckPressure[AMDGPU::RegisterPressureSets::AGPR_32] << "\n";
359 report_fatal_error("inaccurate register pressure calculation");
360 }
361#endif
362 }
363
364 unsigned NewAGPRPressure = Pressure[AMDGPU::RegisterPressureSets::AGPR_32];
365 unsigned NewSGPRPressure = Pressure[AMDGPU::RegisterPressureSets::SReg_32];
366 unsigned NewVGPRPressure = Pressure[AMDGPU::RegisterPressureSets::VGPR_32];
367
368 // If two instructions increase the pressure of different register sets
369 // by the same amount, the generic scheduler will prefer to schedule the
370 // instruction that increases the set with the least amount of registers,
371 // which in our case would be SGPRs. This is rarely what we want, so
372 // when we report excess/critical register pressure, we do it either
373 // only for VGPRs, AGPRs or SGPRs. Priority: VGPR > AGPR > SGPR.
374
375 // FIXME: Better heuristics to determine whether to prefer SGPRs or VGPRs.
376 const unsigned MaxVGPRPressureInc = 16;
377 bool ShouldTrackVGPRs = VGPRPressure + MaxVGPRPressureInc >= VGPRExcessLimit;
378 bool ShouldTrackAGPRs = AGPRExcessLimit > 0 && !ShouldTrackVGPRs &&
379 AGPRPressure + MaxVGPRPressureInc >= AGPRExcessLimit;
380 bool ShouldTrackSGPRs =
381 !ShouldTrackVGPRs && !ShouldTrackAGPRs && SGPRPressure >= SGPRExcessLimit;
382 // FIXME: We have to enter REG-EXCESS before we reach the actual threshold
383 // to increase the likelihood we don't go over the limits. We should improve
384 // the analysis to look through dependencies to find the path with the least
385 // register pressure.
386 // We only need to update the RPDelta for instructions that increase register
387 // pressure. Instructions that decrease or keep reg pressure the same will be
388 // marked as RegExcess in tryCandidate() when they are compared with
389 // instructions that increase the register pressure.
390 if (ShouldTrackVGPRs && NewVGPRPressure >= VGPRExcessLimit) {
391 HasHighPressure = true;
392 Cand.RPDelta.Excess = PressureChange(AMDGPU::RegisterPressureSets::VGPR_32);
393 Cand.RPDelta.Excess.setUnitInc(NewVGPRPressure - VGPRExcessLimit);
394 }
395
396 if (ShouldTrackAGPRs && NewAGPRPressure >= AGPRExcessLimit) {
397 HasHighPressure = true;
398 Cand.RPDelta.Excess = PressureChange(AMDGPU::RegisterPressureSets::AGPR_32);
399 Cand.RPDelta.Excess.setUnitInc(NewAGPRPressure - AGPRExcessLimit);
400 }
401
402 if (ShouldTrackSGPRs && NewSGPRPressure >= SGPRExcessLimit) {
403 HasHighPressure = true;
404 Cand.RPDelta.Excess = PressureChange(AMDGPU::RegisterPressureSets::SReg_32);
405 Cand.RPDelta.Excess.setUnitInc(NewSGPRPressure - SGPRExcessLimit);
406 }
407
408 // Register pressure is considered 'CRITICAL' if it is approaching a value
409 // that would reduce the wave occupancy for the execution unit. When
410 // register pressure is 'CRITICAL', increasing SGPR, VGPR, and AGPR
411 // pressure all has the same cost, so we pick the most critical type.
412
413 // Unified targets allocate both vector banks from the same occupancy budget.
414 // Keep the bank pressures above for excess checks, and do not align VGPRs
415 // when there are no AGPRs, matching GCNRegPressure::getVGPRNum().
416 bool UnifiedVGPRFile = MF->getSubtarget<GCNSubtarget>().hasGFX90AInsts();
417 unsigned VectorCriticalLimit = VGPRCriticalLimit;
418 if (UnifiedVGPRFile) {
419 if (NewAGPRPressure)
420 NewVGPRPressure = GCNRegPressure::getUnifiedVGPRNum(NewVGPRPressure,
421 NewAGPRPressure, 0);
422 VectorCriticalLimit = UnifiedVGPRCriticalLimit;
423 }
424
425 int SGPRDelta = NewSGPRPressure - SGPRCriticalLimit;
426 int VGPRDelta = NewVGPRPressure - VectorCriticalLimit;
427 int AGPRDelta = !UnifiedVGPRFile && AGPRExcessLimit > 0
428 ? NewAGPRPressure - AGPRCriticalLimit
429 : std::numeric_limits<int>::min();
430
431 if (SGPRDelta >= 0 || VGPRDelta >= 0 || AGPRDelta >= 0) {
432 HasHighPressure = true;
433 // Pick the most critical type.
434 if (VGPRDelta >= SGPRDelta && VGPRDelta >= AGPRDelta) {
435 Cand.RPDelta.CriticalMax =
436 PressureChange(AMDGPU::RegisterPressureSets::VGPR_32);
437 Cand.RPDelta.CriticalMax.setUnitInc(VGPRDelta);
438 } else if (AGPRDelta >= SGPRDelta) {
439 Cand.RPDelta.CriticalMax =
440 PressureChange(AMDGPU::RegisterPressureSets::AGPR_32);
441 Cand.RPDelta.CriticalMax.setUnitInc(AGPRDelta);
442 } else {
443 Cand.RPDelta.CriticalMax =
444 PressureChange(AMDGPU::RegisterPressureSets::SReg_32);
445 Cand.RPDelta.CriticalMax.setUnitInc(SGPRDelta);
446 }
447 }
448}
449
451 const TargetSchedModel *SchedModel) {
452 bool HasBufferedModel =
453 SchedModel->hasInstrSchedModel() && SchedModel->getMicroOpBufferSize();
454 unsigned Combined = Zone.Available.size() + Zone.Pending.size();
455 return Combined <= PendingQueueLimit && HasBufferedModel;
456}
457
459 const TargetSchedModel *SchedModel) {
460 // pickOnlyChoice() releases pending instructions and checks for new hazards.
461 SUnit *OnlyChoice = Zone.pickOnlyChoice();
462 if (!shouldCheckPending(Zone, SchedModel) || Zone.Pending.empty())
463 return OnlyChoice;
464
465 return nullptr;
466}
467
469 const SchedCandidate &Preferred) {
470 LLVM_DEBUG({
471 dbgs() << "Prefer:\t\t";
472 DAG->dumpNode(*Preferred.SU);
473
474 if (Current.SU) {
475 dbgs() << "Not:\t";
476 DAG->dumpNode(*Current.SU);
477 }
478
479 dbgs() << "Reason:\t\t";
480 traceCandidate(Preferred);
481 });
482}
483
484// This function is mostly cut and pasted from
485// GenericScheduler::pickNodeFromQueue()
487 const CandPolicy &ZonePolicy,
488 const RegPressureTracker &RPTracker,
489 SchedCandidate &Cand, bool &IsPending,
490 bool IsBottomUp) {
491 const SIRegisterInfo *SRI = static_cast<const SIRegisterInfo *>(TRI);
493 unsigned SGPRPressure = 0;
494 unsigned VGPRPressure = 0;
495 unsigned AGPRPressure = 0;
496 IsPending = false;
497 if (DAG->isTrackingPressure()) {
498 if (!useGCNTrackers()) {
499 SGPRPressure = Pressure[AMDGPU::RegisterPressureSets::SReg_32];
500 VGPRPressure = Pressure[AMDGPU::RegisterPressureSets::VGPR_32];
501 AGPRPressure = Pressure[AMDGPU::RegisterPressureSets::AGPR_32];
502 } else {
503 GCNRPTracker *T = IsBottomUp
504 ? static_cast<GCNRPTracker *>(&UpwardTracker)
505 : static_cast<GCNRPTracker *>(&DownwardTracker);
506 SGPRPressure = T->getPressure().getSGPRNum();
507 VGPRPressure = T->getPressure().getArchVGPRNum();
508 AGPRPressure = T->getPressure().getAGPRNum();
509 }
510 }
511 LLVM_DEBUG(dbgs() << "Available Q:\n");
512 ReadyQueue &AQ = Zone.Available;
513 for (SUnit *SU : AQ) {
514
515 SchedCandidate TryCand(ZonePolicy);
516 initCandidate(TryCand, SU, Zone.isTop(), RPTracker, SRI, SGPRPressure,
517 VGPRPressure, AGPRPressure, IsBottomUp);
518 // Pass SchedBoundary only when comparing nodes from the same boundary.
519 SchedBoundary *ZoneArg = Cand.AtTop == TryCand.AtTop ? &Zone : nullptr;
520 tryCandidate(Cand, TryCand, ZoneArg);
521 if (TryCand.Reason != NoCand) {
522 // Initialize resource delta if needed in case future heuristics query it.
523 if (TryCand.ResDelta == SchedResourceDelta())
524 TryCand.initResourceDelta(Zone.DAG, SchedModel);
525 LLVM_DEBUG(printCandidateDecision(Cand, TryCand));
526 Cand.setBest(TryCand);
527 } else {
528 printCandidateDecision(TryCand, Cand);
529 }
530 }
531
532 if (!shouldCheckPending(Zone, SchedModel))
533 return;
534
535 LLVM_DEBUG(dbgs() << "Pending Q:\n");
536 ReadyQueue &PQ = Zone.Pending;
537 for (SUnit *SU : PQ) {
538
539 SchedCandidate TryCand(ZonePolicy);
540 initCandidate(TryCand, SU, Zone.isTop(), RPTracker, SRI, SGPRPressure,
541 VGPRPressure, AGPRPressure, IsBottomUp);
542 // Pass SchedBoundary only when comparing nodes from the same boundary.
543 SchedBoundary *ZoneArg = Cand.AtTop == TryCand.AtTop ? &Zone : nullptr;
544 tryPendingCandidate(Cand, TryCand, ZoneArg);
545 if (TryCand.Reason != NoCand) {
546 // Initialize resource delta if needed in case future heuristics query it.
547 if (TryCand.ResDelta == SchedResourceDelta())
548 TryCand.initResourceDelta(Zone.DAG, SchedModel);
549 LLVM_DEBUG(printCandidateDecision(Cand, TryCand));
550 IsPending = true;
551 Cand.setBest(TryCand);
552 } else {
553 printCandidateDecision(TryCand, Cand);
554 }
555 }
556}
557
558// This function is mostly cut and pasted from
559// GenericScheduler::pickNodeBidirectional()
561 bool &PickedPending) {
562 // Schedule as far as possible in the direction of no choice. This is most
563 // efficient, but also provides the best heuristics for CriticalPSets.
564 if (SUnit *SU = pickOnlyChoice(Bot, SchedModel)) {
565 IsTopNode = false;
566 return SU;
567 }
568 if (SUnit *SU = pickOnlyChoice(Top, SchedModel)) {
569 IsTopNode = true;
570 return SU;
571 }
572 // Set the bottom-up policy based on the state of the current bottom zone
573 // and the instructions outside the zone, including the top zone.
574 CandPolicy BotPolicy;
575 setPolicy(BotPolicy, /*IsPostRA=*/false, Bot, &Top);
576 // Set the top-down policy based on the state of the current top zone and
577 // the instructions outside the zone, including the bottom zone.
578 CandPolicy TopPolicy;
579 setPolicy(TopPolicy, /*IsPostRA=*/false, Top, &Bot);
580
581 bool BotPending = false;
582 // See if BotCand is still valid (because we previously scheduled from Top).
583 LLVM_DEBUG(dbgs() << "Picking from Bot:\n");
584 if (!BotCand.isValid() || BotCand.SU->isScheduled ||
585 BotCand.Policy != BotPolicy) {
586 BotCand.reset(CandPolicy());
587 pickNodeFromQueue(Bot, BotPolicy, DAG->getBotRPTracker(), BotCand,
588 BotPending,
589 /*IsBottomUp=*/true);
590 assert(BotCand.Reason != NoCand && "failed to find the first candidate");
591 } else {
593#ifndef NDEBUG
595 SchedCandidate TCand;
596 TCand.reset(CandPolicy());
597 pickNodeFromQueue(Bot, BotPolicy, DAG->getBotRPTracker(), TCand,
598 BotPending,
599 /*IsBottomUp=*/true);
600 assert(TCand.SU == BotCand.SU &&
601 "Last pick result should correspond to re-picking right now");
602 }
603#endif
604 }
605
606 bool TopPending = false;
607 // Check if the top Q has a better candidate.
608 LLVM_DEBUG(dbgs() << "Picking from Top:\n");
609 if (!TopCand.isValid() || TopCand.SU->isScheduled ||
610 TopCand.Policy != TopPolicy) {
611 TopCand.reset(CandPolicy());
612 pickNodeFromQueue(Top, TopPolicy, DAG->getTopRPTracker(), TopCand,
613 TopPending,
614 /*IsBottomUp=*/false);
615 assert(TopCand.Reason != NoCand && "failed to find the first candidate");
616 } else {
618#ifndef NDEBUG
620 SchedCandidate TCand;
621 TCand.reset(CandPolicy());
622 pickNodeFromQueue(Top, TopPolicy, DAG->getTopRPTracker(), TCand,
623 TopPending,
624 /*IsBottomUp=*/false);
625 assert(TCand.SU == TopCand.SU &&
626 "Last pick result should correspond to re-picking right now");
627 }
628#endif
629 }
630
631 // Pick best from BotCand and TopCand.
632 LLVM_DEBUG(dbgs() << "Top Cand: "; traceCandidate(TopCand);
633 dbgs() << "Bot Cand: "; traceCandidate(BotCand););
634 SchedCandidate Cand = BotPending ? TopCand : BotCand;
635 SchedCandidate TryCand = BotPending ? BotCand : TopCand;
636 PickedPending = BotPending && TopPending;
637
638 TryCand.Reason = NoCand;
639 if (BotPending || TopPending) {
640 PickedPending |= tryPendingCandidate(Cand, TopCand, nullptr);
641 } else {
642 tryCandidate(Cand, TryCand, nullptr);
643 }
644
645 if (TryCand.Reason != NoCand) {
646 Cand.setBest(TryCand);
647 }
648
649 LLVM_DEBUG(dbgs() << "Picking: "; traceCandidate(Cand););
650
651 IsTopNode = Cand.AtTop;
652 return Cand.SU;
653}
654
655// This function is mostly cut and pasted from
656// GenericScheduler::pickNode()
658 if (DAG->top() == DAG->bottom()) {
659 assert(Top.Available.empty() && Top.Pending.empty() &&
660 Bot.Available.empty() && Bot.Pending.empty() && "ReadyQ garbage");
661 return nullptr;
662 }
663 bool PickedPending;
664 SUnit *SU;
665 do {
666 PickedPending = false;
667 if (RegionPolicy.OnlyTopDown) {
669 if (!SU) {
670 CandPolicy NoPolicy;
671 TopCand.reset(NoPolicy);
672 pickNodeFromQueue(Top, NoPolicy, DAG->getTopRPTracker(), TopCand,
673 PickedPending,
674 /*IsBottomUp=*/false);
675 assert(TopCand.Reason != NoCand && "failed to find a candidate");
676 SU = TopCand.SU;
677 }
678 IsTopNode = true;
679 } else if (RegionPolicy.OnlyBottomUp) {
681 if (!SU) {
682 CandPolicy NoPolicy;
683 BotCand.reset(NoPolicy);
684 pickNodeFromQueue(Bot, NoPolicy, DAG->getBotRPTracker(), BotCand,
685 PickedPending,
686 /*IsBottomUp=*/true);
687 assert(BotCand.Reason != NoCand && "failed to find a candidate");
688 SU = BotCand.SU;
689 }
690 IsTopNode = false;
691 } else {
692 SU = pickNodeBidirectional(IsTopNode, PickedPending);
693 }
694 } while (SU->isScheduled);
695
696 if (PickedPending) {
697 unsigned ReadyCycle = IsTopNode ? SU->TopReadyCycle : SU->BotReadyCycle;
698 SchedBoundary &Zone = IsTopNode ? Top : Bot;
699 unsigned CurrentCycle = Zone.getCurrCycle();
700 if (ReadyCycle > CurrentCycle)
701 Zone.bumpCycle(ReadyCycle);
702
703 // FIXME: checkHazard() doesn't give information about which cycle the
704 // hazard will resolve so just keep bumping the cycle by 1. This could be
705 // made more efficient if checkHazard() returned more details.
706 while (Zone.checkHazard(SU))
707 Zone.bumpCycle(Zone.getCurrCycle() + 1);
708
709 Zone.releasePending();
710 }
711
712 if (SU->isTopReady())
713 Top.removeReady(SU);
714 if (SU->isBottomReady())
715 Bot.removeReady(SU);
716
717 LLVM_DEBUG(dbgs() << "Scheduling " << *SU << " " << *SU->getInstr());
718 return SU;
719}
720
721void GCNSchedStrategy::schedNode(SUnit *SU, bool IsTopNode) {
722 if (useGCNTrackers()) {
723 MachineInstr *MI = SU->getInstr();
724 IsTopNode ? DownwardTracker.advance(*MI) : UpwardTracker.recede(*MI);
725 }
726
727 return GenericScheduler::schedNode(SU, IsTopNode);
728}
729
734
737 if (!CurrentStage)
738 CurrentStage = SchedStages.begin();
739 else
740 CurrentStage++;
741
742 return CurrentStage != SchedStages.end();
743}
744
747 return std::next(CurrentStage) != SchedStages.end();
748}
749
751 SchedCandidate &TryCand,
752 SchedBoundary *Zone) const {
753 // Initialize the candidate if needed.
754 if (!Cand.isValid()) {
755 TryCand.Reason = NodeOrder;
756 return true;
757 }
758
759 // Bias PhysReg Defs and copies to their uses and defined respectively.
760 if (tryGreater(biasPhysReg(TryCand.SU, TryCand.AtTop),
761 biasPhysReg(Cand.SU, Cand.AtTop), TryCand, Cand, PhysReg))
762 return TryCand.Reason != NoCand;
763
764 // Avoid exceeding the target's limit.
765 if (DAG->isTrackingPressure() &&
766 tryPressure(TryCand.RPDelta.Excess, Cand.RPDelta.Excess, TryCand, Cand,
767 RegExcess, TRI, DAG->MF))
768 return TryCand.Reason != NoCand;
769
770 // Avoid increasing the max critical pressure in the scheduled region.
771 if (DAG->isTrackingPressure() &&
773 TryCand, Cand, RegCritical, TRI, DAG->MF))
774 return TryCand.Reason != NoCand;
775
776 bool SameBoundary = Zone != nullptr;
777 if (SameBoundary) {
780 TryCand, Cand, ResourceReduce))
781 return TryCand.Reason != NoCand;
783 Cand.ResDelta.DemandedResources, TryCand, Cand,
785 return TryCand.Reason != NoCand;
786 }
787
788 return false;
789}
790
803
808
810 SchedCandidate &TryCand,
811 SchedBoundary *Zone) const {
812 // Initialize the candidate if needed.
813 if (!Cand.isValid()) {
814 TryCand.Reason = NodeOrder;
815 return true;
816 }
817
818 // Avoid spilling by exceeding the register limit.
819 if (DAG->isTrackingPressure() &&
820 tryPressure(TryCand.RPDelta.Excess, Cand.RPDelta.Excess, TryCand, Cand,
821 RegExcess, TRI, DAG->MF))
822 return TryCand.Reason != NoCand;
823
824 // Bias PhysReg Defs and copies to their uses and defined respectively.
825 if (tryGreater(biasPhysReg(TryCand.SU, TryCand.AtTop),
826 biasPhysReg(Cand.SU, Cand.AtTop), TryCand, Cand, PhysReg))
827 return TryCand.Reason != NoCand;
828
829 bool SameBoundary = Zone != nullptr;
830 if (SameBoundary) {
831 // Prioritize instructions that read unbuffered resources by stall cycles.
832 if (tryLess(Zone->getLatencyStallCycles(TryCand.SU),
833 Zone->getLatencyStallCycles(Cand.SU), TryCand, Cand, Stall))
834 return TryCand.Reason != NoCand;
835
836 // Avoid critical resource consumption and balance the schedule.
839 TryCand, Cand, ResourceReduce))
840 return TryCand.Reason != NoCand;
842 Cand.ResDelta.DemandedResources, TryCand, Cand,
844 return TryCand.Reason != NoCand;
845
846 // Unconditionally try to reduce latency.
847 if (tryLatency(TryCand, Cand, *Zone))
848 return TryCand.Reason != NoCand;
849
850 // Weak edges are for clustering and other constraints.
851 if (tryLess(getWeakLeft(TryCand.SU, TryCand.AtTop),
852 getWeakLeft(Cand.SU, Cand.AtTop), TryCand, Cand, Weak))
853 return TryCand.Reason != NoCand;
854 }
855
856 // Keep clustered nodes together to encourage downstream peephole
857 // optimizations which may reduce resource requirements.
858 //
859 // This is a best effort to set things up for a post-RA pass. Optimizations
860 // like generating loads of multiple registers should ideally be done within
861 // the scheduler pass by combining the loads during DAG postprocessing.
862 unsigned CandZoneCluster = Cand.AtTop ? TopClusterID : BotClusterID;
863 unsigned TryCandZoneCluster = TryCand.AtTop ? TopClusterID : BotClusterID;
864 bool CandIsClusterSucc =
865 isTheSameCluster(CandZoneCluster, Cand.SU->ParentClusterIdx);
866 bool TryCandIsClusterSucc =
867 isTheSameCluster(TryCandZoneCluster, TryCand.SU->ParentClusterIdx);
868 if (tryGreater(TryCandIsClusterSucc, CandIsClusterSucc, TryCand, Cand,
869 Cluster))
870 return TryCand.Reason != NoCand;
871
872 // Avoid increasing the max critical pressure in the scheduled region.
873 if (DAG->isTrackingPressure() &&
875 TryCand, Cand, RegCritical, TRI, DAG->MF))
876 return TryCand.Reason != NoCand;
877
878 // Avoid increasing the max pressure of the entire region.
879 if (DAG->isTrackingPressure() &&
880 tryPressure(TryCand.RPDelta.CurrentMax, Cand.RPDelta.CurrentMax, TryCand,
881 Cand, RegMax, TRI, DAG->MF))
882 return TryCand.Reason != NoCand;
883
884 if (SameBoundary) {
885 // Fall through to original instruction order.
886 if ((Zone->isTop() && TryCand.SU->NodeNum < Cand.SU->NodeNum) ||
887 (!Zone->isTop() && TryCand.SU->NodeNum > Cand.SU->NodeNum)) {
888 TryCand.Reason = NodeOrder;
889 return true;
890 }
891 }
892 return false;
893}
894
900
901/// GCNMaxMemoryClauseSchedStrategy tries best to clause memory instructions as
902/// much as possible. This is achieved by:
903// 1. Prioritize clustered operations before stall latency heuristic.
904// 2. Prioritize long-latency-load before stall latency heuristic.
905///
906/// \param Cand provides the policy and current best candidate.
907/// \param TryCand refers to the next SUnit candidate, otherwise uninitialized.
908/// \param Zone describes the scheduled zone that we are extending, or nullptr
909/// if Cand is from a different zone than TryCand.
910/// \return \c true if TryCand is better than Cand (Reason is NOT NoCand)
912 SchedCandidate &TryCand,
913 SchedBoundary *Zone) const {
914 // Initialize the candidate if needed.
915 if (!Cand.isValid()) {
916 TryCand.Reason = NodeOrder;
917 return true;
918 }
919
920 // Bias PhysReg Defs and copies to their uses and defined respectively.
921 if (tryGreater(biasPhysReg(TryCand.SU, TryCand.AtTop),
922 biasPhysReg(Cand.SU, Cand.AtTop), TryCand, Cand, PhysReg))
923 return TryCand.Reason != NoCand;
924
925 if (DAG->isTrackingPressure()) {
926 // Avoid exceeding the target's limit.
927 if (tryPressure(TryCand.RPDelta.Excess, Cand.RPDelta.Excess, TryCand, Cand,
928 RegExcess, TRI, DAG->MF))
929 return TryCand.Reason != NoCand;
930
931 // Avoid increasing the max critical pressure in the scheduled region.
933 TryCand, Cand, RegCritical, TRI, DAG->MF))
934 return TryCand.Reason != NoCand;
935 }
936
937 // MaxMemoryClause-specific: We prioritize clustered instructions as we would
938 // get more benefit from clausing these memory instructions.
939 unsigned CandZoneCluster = Cand.AtTop ? TopClusterID : BotClusterID;
940 unsigned TryCandZoneCluster = TryCand.AtTop ? TopClusterID : BotClusterID;
941 bool CandIsClusterSucc =
942 isTheSameCluster(CandZoneCluster, Cand.SU->ParentClusterIdx);
943 bool TryCandIsClusterSucc =
944 isTheSameCluster(TryCandZoneCluster, TryCand.SU->ParentClusterIdx);
945 if (tryGreater(TryCandIsClusterSucc, CandIsClusterSucc, TryCand, Cand,
946 Cluster))
947 return TryCand.Reason != NoCand;
948
949 // We only compare a subset of features when comparing nodes between
950 // Top and Bottom boundary. Some properties are simply incomparable, in many
951 // other instances we should only override the other boundary if something
952 // is a clear good pick on one boundary. Skip heuristics that are more
953 // "tie-breaking" in nature.
954 bool SameBoundary = Zone != nullptr;
955 if (SameBoundary) {
956 // For loops that are acyclic path limited, aggressively schedule for
957 // latency. Within an single cycle, whenever CurrMOps > 0, allow normal
958 // heuristics to take precedence.
959 if (Rem.IsAcyclicLatencyLimited && !Zone->getCurrMOps() &&
960 tryLatency(TryCand, Cand, *Zone))
961 return TryCand.Reason != NoCand;
962
963 // MaxMemoryClause-specific: Prioritize long latency memory load
964 // instructions in top-bottom order to hide more latency. The mayLoad check
965 // is used to exclude store-like instructions, which we do not want to
966 // scheduler them too early.
967 bool TryMayLoad =
968 TryCand.SU->isInstr() && TryCand.SU->getInstr()->mayLoad();
969 bool CandMayLoad = Cand.SU->isInstr() && Cand.SU->getInstr()->mayLoad();
970
971 if (TryMayLoad || CandMayLoad) {
972 bool TryLongLatency =
973 TryCand.SU->Latency > 10 * Cand.SU->Latency && TryMayLoad;
974 bool CandLongLatency =
975 10 * TryCand.SU->Latency < Cand.SU->Latency && CandMayLoad;
976
977 if (tryGreater(Zone->isTop() ? TryLongLatency : CandLongLatency,
978 Zone->isTop() ? CandLongLatency : TryLongLatency, TryCand,
979 Cand, Stall))
980 return TryCand.Reason != NoCand;
981 }
982 // Prioritize instructions that read unbuffered resources by stall cycles.
983 if (tryLess(Zone->getLatencyStallCycles(TryCand.SU),
984 Zone->getLatencyStallCycles(Cand.SU), TryCand, Cand, Stall))
985 return TryCand.Reason != NoCand;
986 }
987
988 if (SameBoundary) {
989 // Weak edges are for clustering and other constraints.
990 if (tryLess(getWeakLeft(TryCand.SU, TryCand.AtTop),
991 getWeakLeft(Cand.SU, Cand.AtTop), TryCand, Cand, Weak))
992 return TryCand.Reason != NoCand;
993 }
994
995 // Avoid increasing the max pressure of the entire region.
996 if (DAG->isTrackingPressure() &&
997 tryPressure(TryCand.RPDelta.CurrentMax, Cand.RPDelta.CurrentMax, TryCand,
998 Cand, RegMax, TRI, DAG->MF))
999 return TryCand.Reason != NoCand;
1000
1001 if (SameBoundary) {
1002 // Avoid critical resource consumption and balance the schedule.
1005 TryCand, Cand, ResourceReduce))
1006 return TryCand.Reason != NoCand;
1008 Cand.ResDelta.DemandedResources, TryCand, Cand,
1010 return TryCand.Reason != NoCand;
1011
1012 // Avoid serializing long latency dependence chains.
1013 // For acyclic path limited loops, latency was already checked above.
1014 if (!RegionPolicy.DisableLatencyHeuristic && TryCand.Policy.ReduceLatency &&
1015 !Rem.IsAcyclicLatencyLimited && tryLatency(TryCand, Cand, *Zone))
1016 return TryCand.Reason != NoCand;
1017
1018 // Fall through to original instruction order.
1019 if (Zone->isTop() == (TryCand.SU->NodeNum < Cand.SU->NodeNum)) {
1020 assert(TryCand.SU->NodeNum != Cand.SU->NodeNum);
1021 TryCand.Reason = NodeOrder;
1022 return true;
1023 }
1024 }
1025
1026 return false;
1027}
1028
1030 MachineSchedContext *C, std::unique_ptr<MachineSchedStrategy> S)
1031 : ScheduleDAGMILive(C, std::move(S)), ST(MF.getSubtarget<GCNSubtarget>()),
1032 MFI(*MF.getInfo<SIMachineFunctionInfo>()),
1033 StartingOccupancy(MFI.getOccupancy()), MinOccupancy(StartingOccupancy),
1034 RegionLiveOuts(this, /*IsLiveOut=*/true) {
1035
1036 // We want regions with a single MI to be scheduled so that we can reason
1037 // about them correctly during scheduling stages that move MIs between regions
1038 // (e.g., rematerialization).
1040 LLVM_DEBUG(dbgs() << "Starting occupancy is " << StartingOccupancy << ".\n");
1041 if (RelaxedOcc) {
1042 MinOccupancy = std::min(MFI.getMinAllowedOccupancy(), StartingOccupancy);
1043 if (MinOccupancy != StartingOccupancy)
1044 LLVM_DEBUG(dbgs() << "Allowing Occupancy drops to " << MinOccupancy
1045 << ".\n");
1046 }
1047}
1048
1049std::unique_ptr<GCNSchedStage>
1050GCNScheduleDAGMILive::createSchedStage(GCNSchedStageID SchedStageID) {
1051 switch (SchedStageID) {
1053 return std::make_unique<OccInitialScheduleStage>(SchedStageID, *this);
1055 return std::make_unique<RewriteMFMAFormStage>(SchedStageID, *this);
1057 return std::make_unique<UnclusteredHighRPStage>(SchedStageID, *this);
1059 return std::make_unique<ClusteredLowOccStage>(SchedStageID, *this);
1061 return std::make_unique<PreRARematStage>(SchedStageID, *this);
1063 return std::make_unique<ILPInitialScheduleStage>(SchedStageID, *this);
1065 return std::make_unique<MemoryClauseInitialScheduleStage>(SchedStageID,
1066 *this);
1068 return std::make_unique<LiveIntervalRPStage>(SchedStageID, *this);
1069 }
1070
1071 llvm_unreachable("Unknown SchedStageID.");
1072}
1073
1075 // Collect all scheduling regions. The actual scheduling is performed in
1076 // GCNScheduleDAGMILive::finalizeSchedule.
1077 Regions.push_back(std::pair(RegionBegin, RegionEnd));
1078}
1079
1081GCNScheduleDAGMILive::getRealRegPressure(unsigned RegionIdx) const {
1082 if (Regions[RegionIdx].first == Regions[RegionIdx].second)
1083 return llvm::getRegPressure(MRI, LiveIns[RegionIdx]);
1085 RPTracker.advance(Regions[RegionIdx].first, Regions[RegionIdx].second,
1086 &LiveIns[RegionIdx]);
1087 return RPTracker.moveMaxPressure();
1088}
1089
1091 MachineBasicBlock::iterator RegionEnd) {
1092 assert(RegionBegin != RegionEnd && "Region must not be empty");
1093 return &*skipDebugInstructionsBackward(std::prev(RegionEnd), RegionBegin);
1094}
1095
1096void GCNScheduleDAGMILive::computeBlockPressure(unsigned RegionIdx,
1097 const MachineBasicBlock *MBB) {
1098 GCNDownwardRPTracker RPTracker(*LIS);
1099
1100 // If the block has the only successor then live-ins of that successor are
1101 // live-outs of the current block. We can reuse calculated live set if the
1102 // successor will be sent to scheduling past current block.
1103
1104 // However, due to the bug in LiveInterval analysis it may happen that two
1105 // predecessors of the same successor block have different lane bitmasks for
1106 // a live-out register. Workaround that by sticking to one-to-one relationship
1107 // i.e. one predecessor with one successor block.
1108 const MachineBasicBlock *OnlySucc = nullptr;
1109 if (MBB->succ_size() == 1) {
1110 auto *Candidate = *MBB->succ_begin();
1111 if (!Candidate->empty() && Candidate->pred_size() == 1) {
1112 SlotIndexes *Ind = LIS->getSlotIndexes();
1113 if (Ind->getMBBStartIdx(MBB) < Ind->getMBBStartIdx(Candidate))
1114 OnlySucc = Candidate;
1115 }
1116 }
1117
1118 // Scheduler sends regions from the end of the block upwards.
1119 size_t CurRegion = RegionIdx;
1120 for (size_t E = Regions.size(); CurRegion != E; ++CurRegion)
1121 if (Regions[CurRegion].first->getParent() != MBB)
1122 break;
1123 --CurRegion;
1124
1125 auto I = MBB->begin();
1126 auto LiveInIt = MBBLiveIns.find(MBB);
1127 auto &Rgn = Regions[CurRegion];
1128 auto *NonDbgMI = &*skipDebugInstructionsForward(Rgn.first, Rgn.second);
1129 if (LiveInIt != MBBLiveIns.end()) {
1130 auto LiveIn = std::move(LiveInIt->second);
1131 RPTracker.reset(*MBB->begin(), MBB->end(), &LiveIn);
1132 MBBLiveIns.erase(LiveInIt);
1133 } else {
1134 I = Rgn.first;
1135 auto LRS = BBLiveInMap.lookup(NonDbgMI);
1136#ifdef EXPENSIVE_CHECKS
1137 assert(isEqual(getLiveRegsBefore(*NonDbgMI, *LIS), LRS));
1138#endif
1139 RPTracker.reset(*I, I->getParent()->end(), &LRS);
1140 }
1141
1142 for (;;) {
1143 I = RPTracker.getNext();
1144
1145 if (Regions[CurRegion].first == I || NonDbgMI == I) {
1146 LiveIns[CurRegion] = RPTracker.getLiveRegs();
1147 RPTracker.clearMaxPressure();
1148 }
1149
1150 if (Regions[CurRegion].second == I) {
1151 Pressure[CurRegion] = RPTracker.moveMaxPressure();
1152 if (CurRegion-- == RegionIdx)
1153 break;
1154 auto &Rgn = Regions[CurRegion];
1155 NonDbgMI = &*skipDebugInstructionsForward(Rgn.first, Rgn.second);
1156 }
1157 RPTracker.advanceBeforeNext();
1158 RPTracker.advanceToNext();
1159 }
1160
1161 if (OnlySucc) {
1162 if (I != MBB->end()) {
1163 RPTracker.advanceBeforeNext();
1164 RPTracker.advanceToNext();
1165 RPTracker.advance(MBB->end());
1166 }
1167 MBBLiveIns[OnlySucc] = RPTracker.moveLiveRegs();
1168 }
1169}
1170
1172GCNScheduleDAGMILive::getRegionLiveInMap() const {
1173 assert(!Regions.empty());
1174 std::vector<MachineInstr *> RegionFirstMIs;
1175 RegionFirstMIs.reserve(Regions.size());
1176 for (auto &[RegionBegin, RegionEnd] : reverse(Regions))
1177 RegionFirstMIs.push_back(
1179
1180 return getLiveRegMap(RegionFirstMIs, /*After=*/false, *LIS);
1181}
1182
1184GCNScheduleDAGMILive::getRegionLiveOutMap() const {
1185 assert(!Regions.empty());
1186 std::vector<MachineInstr *> RegionLastMIs;
1187 RegionLastMIs.reserve(Regions.size());
1188 for (auto &[RegionBegin, RegionEnd] : reverse(Regions)) {
1189 // Skip empty regions.
1190 if (RegionBegin == RegionEnd)
1191 continue;
1192 RegionLastMIs.push_back(getLastMIForRegion(RegionBegin, RegionEnd));
1193 }
1194 return getLiveRegMap(RegionLastMIs, /*After=*/true, *LIS);
1195}
1196
1198 IdxToInstruction.clear();
1199
1200 RegionLiveRegMap =
1201 IsLiveOut ? DAG->getRegionLiveOutMap() : DAG->getRegionLiveInMap();
1202 for (unsigned I = 0; I < DAG->Regions.size(); I++) {
1203 auto &[RegionBegin, RegionEnd] = DAG->Regions[I];
1204 // Skip empty regions.
1205 if (RegionBegin == RegionEnd)
1206 continue;
1207 MachineInstr *RegionKey =
1208 IsLiveOut ? getLastMIForRegion(RegionBegin, RegionEnd) : &*RegionBegin;
1209 IdxToInstruction[I] = RegionKey;
1210 }
1211}
1212
1214 // Start actual scheduling here. This function is called by the base
1215 // MachineScheduler after all regions have been recorded by
1216 // GCNScheduleDAGMILive::schedule().
1217 LiveIns.resize(Regions.size());
1218 Pressure.resize(Regions.size());
1219 RegionsWithHighRP.resize(Regions.size());
1220 RegionsWithExcessRP.resize(Regions.size());
1221 RegionsWithIGLPInstrs.resize(Regions.size());
1222 RegionsWithHighRP.reset();
1223 RegionsWithExcessRP.reset();
1224 RegionsWithIGLPInstrs.reset();
1225
1226 runSchedStages();
1227}
1228
1229void GCNScheduleDAGMILive::runSchedStages() {
1230 LLVM_DEBUG(dbgs() << "All regions recorded, starting actual scheduling.\n");
1231
1232 GCNSchedStrategy &S = static_cast<GCNSchedStrategy &>(*SchedImpl);
1233 if (!Regions.empty()) {
1234 BBLiveInMap = getRegionLiveInMap();
1235 if (S.useGCNTrackers())
1236 RegionLiveOuts.buildLiveRegMap();
1237 }
1238
1239#ifdef DUMP_MAX_REG_PRESSURE
1243 LIS->dump();
1244 }
1245#endif
1246
1247 while (S.advanceStage()) {
1248 auto Stage = createSchedStage(S.getCurrentStage());
1249 if (!Stage->initGCNSchedStage())
1250 continue;
1251
1252 for (auto Region : Regions) {
1253 RegionBegin = Region.first;
1254 RegionEnd = Region.second;
1255 // Setup for scheduling the region and check whether it should be skipped.
1256 if (!Stage->initGCNRegion()) {
1257 Stage->advanceRegion();
1258 exitRegion();
1259 continue;
1260 }
1261
1262 if (S.useGCNTrackers()) {
1263 const unsigned RegionIdx = Stage->getRegionIdx();
1264 S.getDownwardTracker().reset(MRI, LiveIns[RegionIdx]);
1266 MRI, RegionLiveOuts.getLiveRegsForRegionIdx(RegionIdx));
1267 }
1268
1270 Stage->finalizeGCNRegion();
1271 Stage->advanceRegion();
1272 exitRegion();
1273 }
1274
1275 Stage->finalizeGCNSchedStage();
1276 }
1277
1278#ifdef DUMP_MAX_REG_PRESSURE
1282 LIS->dump();
1283 }
1284#endif
1285}
1286
1287#ifndef NDEBUG
1289 switch (StageID) {
1291 OS << "Max Occupancy Initial Schedule";
1292 break;
1294 OS << "Instruction Rewriting Reschedule";
1295 break;
1297 OS << "Unclustered High Register Pressure Reschedule";
1298 break;
1300 OS << "Clustered Low Occupancy Reschedule";
1301 break;
1303 OS << "Pre-RA Rematerialize";
1304 break;
1306 OS << "Max ILP Initial Schedule";
1307 break;
1309 OS << "Max memory clause Initial Schedule";
1310 break;
1312 OS << "Live Interval RP Reschedule";
1313 break;
1314 }
1315
1316 return OS;
1317}
1318#endif
1319
1323
1325 if (!DAG.LIS)
1326 return false;
1327
1328 LLVM_DEBUG(dbgs() << "Starting scheduling stage: " << StageID << "\n");
1329 return true;
1330}
1331
1332void RewriteMFMAFormStage::findReachingDefs(
1333 MachineOperand &UseMO, LiveIntervals *LIS,
1334 SmallVectorImpl<SlotIndex> &DefIdxs) {
1335 MachineInstr *UseMI = UseMO.getParent();
1336 LiveInterval &UseLI = LIS->getInterval(UseMO.getReg());
1337 VNInfo *VNI = UseLI.getVNInfoAt(LIS->getInstructionIndex(*UseMI));
1338
1339 // If the def is not a PHI, then it must be the only reaching def.
1340 if (!VNI->isPHIDef()) {
1341 DefIdxs.push_back(VNI->def);
1342 return;
1343 }
1344
1345 SmallPtrSet<MachineBasicBlock *, 8> Visited = {UseMI->getParent()};
1347
1348 // Mark the predecessor blocks for traversal
1349 for (MachineBasicBlock *PredMBB : UseMI->getParent()->predecessors()) {
1350 Worklist.push_back(PredMBB);
1351 Visited.insert(PredMBB);
1352 }
1353
1354 while (!Worklist.empty()) {
1355 MachineBasicBlock *CurrMBB = Worklist.pop_back_val();
1356
1357 SlotIndex CurrMBBEnd = LIS->getMBBEndIdx(CurrMBB);
1358 VNInfo *VNI = UseLI.getVNInfoAt(CurrMBBEnd.getPrevSlot());
1359
1360 MachineBasicBlock *DefMBB = LIS->getMBBFromIndex(VNI->def);
1361
1362 // If there is a def in this block, then add it to the list. This is the
1363 // reaching def of this path.
1364 if (!VNI->isPHIDef()) {
1365 DefIdxs.push_back(VNI->def);
1366 continue;
1367 }
1368
1369 for (MachineBasicBlock *PredMBB : DefMBB->predecessors()) {
1370 if (Visited.insert(PredMBB).second)
1371 Worklist.push_back(PredMBB);
1372 }
1373 }
1374}
1375
1376void RewriteMFMAFormStage::findReachingUses(
1377 const MachineInstr *DefMI, LiveIntervals *LIS,
1378 SmallVectorImpl<MachineOperand *> &ReachingUses) {
1379 SlotIndex DefIdx = LIS->getInstructionIndex(*DefMI);
1380 for (MachineOperand &UseMO :
1381 DAG.MRI.use_nodbg_operands(DefMI->getOperand(0).getReg())) {
1382 SmallVector<SlotIndex, 8> ReachingDefIndexes;
1383 findReachingDefs(UseMO, LIS, ReachingDefIndexes);
1384
1385 // If we find a use that contains this DefMI in its reachingDefs, then it is
1386 // a reaching use.
1387 if (any_of(ReachingDefIndexes, [DefIdx](SlotIndex RDIdx) {
1388 return SlotIndex::isSameInstr(RDIdx, DefIdx);
1389 }))
1390 ReachingUses.push_back(&UseMO);
1391 }
1392}
1393
1395 // We only need to run this pass if the architecture supports AGPRs.
1396 // Additionally, we don't use AGPRs at occupancy levels above 1 so there
1397 // is no need for this pass in that case, either.
1398 const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
1399 if (!ST.hasGFX90AInsts() || MFI.getMinWavesPerEU() > 1)
1400 return false;
1401
1402 RegionsWithExcessArchVGPR.resize(DAG.Regions.size());
1403 RegionsWithExcessArchVGPR.reset();
1404 for (unsigned Region = 0; Region < DAG.Regions.size(); Region++) {
1406 if (PressureBefore.getArchVGPRNum() > ST.getAddressableNumArchVGPRs())
1407 RegionsWithExcessArchVGPR[Region] = true;
1408 }
1409
1410 if (RegionsWithExcessArchVGPR.none())
1411 return false;
1412
1413 TII = ST.getInstrInfo();
1414 SRI = ST.getRegisterInfo();
1415
1416 std::vector<std::pair<MachineInstr *, unsigned>> RewriteCands;
1419
1420 if (!initHeuristics(RewriteCands, CopyForUse, CopyForDef))
1421 return false;
1422
1423 int64_t Cost = getRewriteCost(RewriteCands, CopyForUse, CopyForDef);
1424
1425 // If we haven't found the beneficial conditions, prefer the VGPR form which
1426 // may result in less cross RC copies.
1427 if (Cost > 0)
1428 return false;
1429
1430 return rewrite(RewriteCands);
1431}
1432
1435 return false;
1436
1438 return false;
1439
1440 if (DAG.RegionsWithHighRP.none() && DAG.RegionsWithExcessRP.none())
1441 return false;
1442
1443 SavedMutations.swap(DAG.Mutations);
1444 DAG.addMutation(
1446
1447 InitialOccupancy = DAG.MinOccupancy;
1448 // Aggressively try to reduce register pressure in the unclustered high RP
1449 // stage. Temporarily increase occupancy target in the region.
1450 TempTargetOccupancy = MFI.getMaxWavesPerEU() > DAG.MinOccupancy
1451 ? InitialOccupancy + 1
1452 : InitialOccupancy;
1453 IsAnyRegionScheduled = false;
1454 S.SGPRLimitBias = S.HighRPSGPRBias;
1455 S.VGPRLimitBias = S.HighRPVGPRBias;
1456
1457 LLVM_DEBUG(
1458 dbgs()
1459 << "Retrying function scheduling without clustering. "
1460 "Aggressively try to reduce register pressure to achieve occupancy "
1461 << TempTargetOccupancy << ".\n");
1462
1463 return true;
1464}
1465
1468 return false;
1469
1471 return false;
1472
1473 // Don't bother trying to improve ILP in lower RP regions if occupancy has not
1474 // been dropped. All regions will have already been scheduled with the ideal
1475 // occupancy targets.
1476 if (DAG.StartingOccupancy <= DAG.MinOccupancy)
1477 return false;
1478
1479 LLVM_DEBUG(
1480 dbgs() << "Retrying function scheduling with lowest recorded occupancy "
1481 << DAG.MinOccupancy << ".\n");
1482 return true;
1483}
1484
1485/// Allows to easily filter for this stage's debug output.
1486#define REMAT_PREFIX "[PreRARemat] "
1487#define REMAT_DEBUG(X) LLVM_DEBUG(dbgs() << REMAT_PREFIX; X;)
1488
1489#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
1490Printable PreRARematStage::ScoredRemat::print() const {
1491 return Printable([&](raw_ostream &OS) {
1492 OS << '(' << MaxFreq << ", " << FreqDiff << ", " << RegionImpact << ')';
1493 });
1494}
1495#endif
1496
1498 // FIXME: This pass will invalidate cached BBLiveInMap and MBBLiveIns for
1499 // regions inbetween the defs and region we sinked the def to. Will need to be
1500 // fixed if there is another pass after this pass.
1501 assert(!S.hasNextStage());
1502
1503 if (!GCNSchedStage::initGCNSchedStage() || DAG.Regions.size() <= 1)
1504 return false;
1505
1506#ifndef NDEBUG
1507 auto PrintTargetRegions = [&]() -> void {
1508 if (TargetRegions.none()) {
1509 dbgs() << REMAT_PREFIX << "No target regions\n";
1510 return;
1511 }
1512 dbgs() << REMAT_PREFIX << "Target regions:\n";
1513 for (unsigned I : TargetRegions.set_bits())
1514 dbgs() << REMAT_PREFIX << " [" << I << "] " << RPTargets[I] << '\n';
1515 };
1516#endif
1517
1518 // Set an objective for the stage based on current RP in each region.
1519 REMAT_DEBUG({
1520 dbgs() << "Analyzing ";
1521 MF.getFunction().printAsOperand(dbgs(), false);
1522 dbgs() << ": ";
1523 });
1524 if (!setObjective()) {
1525 LLVM_DEBUG(dbgs() << "no objective to achieve, occupancy is maximal at "
1526 << MFI.getMaxWavesPerEU() << '\n');
1527 return false;
1528 }
1529 LLVM_DEBUG({
1530 if (TargetOcc) {
1531 dbgs() << "increase occupancy from " << *TargetOcc - 1 << '\n';
1532 } else {
1533 dbgs() << "reduce spilling (minimum target occupancy is "
1534 << MFI.getMinWavesPerEU() << ")\n";
1535 }
1536 PrintTargetRegions();
1537 });
1538
1539 // We need up-to-date live-out info. to query live-out register masks in
1540 // regions containing rematerializable instructions.
1541 DAG.RegionLiveOuts.buildLiveRegMap();
1542
1543 if (!Remater.analyze()) {
1544 REMAT_DEBUG(dbgs() << "No rematerializable registers\n");
1545 return false;
1546 }
1547 const ScoredRemat::FreqInfo FreqInfo(MF, DAG);
1548
1549 // Set of registers already marked for potential remterialization; used to
1550 // avoid rematerialization chains.
1551 SmallSet<Register, 4> MarkedRegs;
1552
1553 // Collect candidates. We have more restrictions on what we can track here
1554 // compared to the rematerializer.
1555 SmallVector<ScoredRemat, 8> Candidates;
1556 // Map registers to candidate indices. Use ~0u as null value
1557 // since 0 is a valid index.
1558 IndexedMap<unsigned, VirtReg2IndexFunctor> DefRegToCandIdx(~0u);
1559 DefRegToCandIdx.resize(DAG.MRI.getNumVirtRegs());
1560 const unsigned NumRegions = DAG.Regions.size();
1561
1562 for (unsigned RegIdx = 0, E = Remater.getNumRegs(); RegIdx < E; ++RegIdx) {
1563 const Rematerializer::Reg &CandReg = Remater.getReg(RegIdx);
1564 if (!CandReg.hasUsersOutsideDefRegion())
1565 continue;
1566
1567 // Rematerialization moves the defining instruction into the region of its
1568 // uses, which may sit under different control dependencies (e.g., across a
1569 // change of EXEC). Convergent operations must not be made control-dependent
1570 // on additional values, so they cannot be safely relocated this way. This
1571 // mirrors the check MachineSink performs before sinking an instruction.
1572 if (any_of(CandReg.Defs,
1573 [](const MachineInstr *DefMI) { return DefMI->isConvergent(); }))
1574 continue;
1575
1576 // Rematerializing a load into multiple using regions duplicates the
1577 // memory access itself. Conservatively restrict rematerialization of loads
1578 // to a single region.
1579 if (CandReg.Uses.size() > 1 &&
1580 any_of(CandReg.Defs,
1581 [](const MachineInstr *DefMI) { return DefMI->mayLoad(); }))
1582 continue;
1583
1584 // We further filter the registers that we can rematerialize based on our
1585 // current tracking capabilities in the stage. This ensures that we are not
1586 // extending any live range while rematerializing, and that rematerializing
1587 // any register candidate will not affect other candidates.
1588
1589 // All register dependencies should not already be considered
1590 // rematerializable.
1591 if (llvm::any_of(CandReg.Dependencies, [&](RegisterIdx DepRegIdx) {
1592 return MarkedRegs.contains(Remater.getReg(DepRegIdx).getDefReg());
1593 }))
1594 continue;
1595
1596 if (!candidateHasValidUsers(RegIdx, MarkedRegs))
1597 continue;
1598
1599 Register DefReg = CandReg.getDefReg();
1600 MarkedRegs.insert(DefReg);
1601 DefRegToCandIdx[DefReg] = Candidates.size();
1602 Candidates.emplace_back(RegIdx, NumRegions);
1603 }
1604
1605 // Initialize the LiveIn and LiveOut sets of all candidates.
1606 // Iterating all regions and their live regs once is considerably
1607 // more efficient than querying those structures for each candidate
1608 // separately in ScoredRemat::init.
1609 for (unsigned I = 0; I < NumRegions; ++I) {
1610 for (const auto &[Reg, Mask] : DAG.LiveIns[I]) {
1612 continue;
1613 unsigned CandIdx = DefRegToCandIdx[Reg];
1614 if (CandIdx != ~0u)
1615 Candidates[CandIdx].LiveIn.set(I);
1616 }
1617 for (const auto &[Reg, Mask] :
1618 DAG.RegionLiveOuts.getLiveRegsForRegionIdx(I)) {
1620 continue;
1621 unsigned CandIdx = DefRegToCandIdx[Reg];
1622 if (CandIdx != ~0u)
1623 Candidates[CandIdx].LiveOut.set(I);
1624 }
1625 }
1626
1627 // Finish initializing candidates.
1628 SmallVector<unsigned> CandidateOrder;
1629 for (auto [CandIdx, Cand] : enumerate(Candidates)) {
1630 Cand.init(FreqInfo, Remater, DAG);
1631 Cand.update(TargetRegions, RPTargets, FreqInfo, !TargetOcc);
1632 if (!Cand.hasNullScore())
1633 CandidateOrder.push_back(CandIdx);
1634 }
1635
1636 if (TargetOcc) {
1637 // Every rematerialization we do here is likely to move the instruction
1638 // into a higher frequency region, increasing the total sum latency of the
1639 // instruction itself. This is acceptable if we are eliminating a spill in
1640 // the process, but when the goal is increasing occupancy we get nothing
1641 // out of rematerialization if occupancy is not increased in the end; in
1642 // such cases we want to roll back the rematerialization.
1643 Rollback = std::make_unique<RollbackSupport>(Remater);
1644 }
1645
1646 // Rematerialize registers in successive rounds until all RP targets are
1647 // satisifed or until we run out of rematerialization candidates.
1648 BitVector RecomputeRP(DAG.Regions.size());
1649 for (;;) {
1650 RecomputeRP.reset();
1651
1652 // Sort candidates in increasing score order.
1653 sort(CandidateOrder, [&](unsigned LHSIndex, unsigned RHSIndex) {
1654 return Candidates[LHSIndex] < Candidates[RHSIndex];
1655 });
1656
1657 REMAT_DEBUG({
1658 dbgs() << "==== NEW REMAT ROUND ====\n"
1659 << REMAT_PREFIX
1660 << "Candidates with non-null score, in rematerialization order:\n";
1661 for (const ScoredRemat &Cand : reverse(Candidates)) {
1662 dbgs() << REMAT_PREFIX << " " << Cand.print() << " | "
1663 << Remater.printRematReg(Cand.RegIdx) << '\n';
1664 }
1665 PrintTargetRegions();
1666 });
1667
1668 // Rematerialize registers in decreasing score order until we estimate
1669 // that all RP targets are satisfied or until rematerialization candidates
1670 // are no longer useful to decrease RP.
1671 while (!CandidateOrder.empty()) {
1672 const ScoredRemat &Cand = Candidates[CandidateOrder.back()];
1673 const Rematerializer::Reg &Reg = Remater.getReg(Cand.RegIdx);
1674
1675 // When previous rematerializations in this round have already satisfied
1676 // RP targets in all regions this rematerialization can impact, we have a
1677 // good indication that our scores have diverged significantly from
1678 // reality, in which case we interrupt this round and re-score. This also
1679 // ensures that every rematerialization we perform is possibly impactful
1680 // in at least one target region.
1681 if (!Cand.maybeBeneficial(TargetRegions, RPTargets)) {
1682 REMAT_DEBUG(dbgs() << "Interrupt round on stale score for "
1683 << Cand.print() << " | "
1684 << Remater.printRematReg(Cand.RegIdx));
1685 break;
1686 }
1687 CandidateOrder.pop_back();
1688
1689#ifdef EXPENSIVE_CHECKS
1690 // All uses outside the defining region are known to be available / live
1691 // at the remat points. Thus, the uses should already be live in to
1692 // those using regions.
1693 for (const MachineInstr *DefMI : Reg.Defs) {
1694 for (const MachineOperand &MO : DefMI->operands()) {
1695 // Exclude the defined register. We are rematerializing all
1696 // instructions defining it so we don't care that its value is
1697 // available at the remat point.
1698 if (!MO.isReg() || !MO.getReg() || !MO.readsReg() || MO.isDef())
1699 continue;
1700
1701 Register UseReg = MO.getReg();
1702 if (!UseReg.isVirtual())
1703 continue;
1704
1705 LiveInterval &LI = DAG.LIS->getInterval(UseReg);
1706 LaneBitmask LM = DAG.MRI.getMaxLaneMaskForVReg(MO.getReg());
1707 if (LI.hasSubRanges() && MO.getSubReg())
1708 LM = DAG.TRI->getSubRegIndexLaneMask(MO.getSubReg());
1709
1710 for (const auto &[UseRegion, _] : Reg.Uses) {
1711 if (UseRegion == Reg.DefRegion)
1712 continue;
1713 LaneBitmask LiveInMask = DAG.LiveIns[UseRegion].at(UseReg);
1714 LaneBitmask UncoveredLanes = LM & ~(LiveInMask & LM);
1715 // If this register has lanes not covered by the LiveIns, be sure
1716 // they do not map to any subrange. ref:
1717 // machine-scheduler-sink-trivial-remats.mir::omitted_subrange
1718 if (UncoveredLanes.any()) {
1719 assert(LI.hasSubRanges());
1720 for (LiveInterval::SubRange &SR : LI.subranges())
1721 assert((SR.LaneMask & UncoveredLanes).none());
1722 }
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 bool UnifiedVGPRFile = ST.hasGFX90AInsts();
1995 unsigned VectorCriticalLimit =
1996 UnifiedVGPRFile ? S.UnifiedVGPRCriticalLimit : S.VGPRCriticalLimit;
1997 // Fitting the combined occupancy budget does not rule out spilling in one
1998 // bank. Keep the per-bank excess checks before taking this early exit.
1999 if (PressureAfter.getSGPRNum() <= S.SGPRCriticalLimit &&
2000 PressureAfter.getVGPRNum(UnifiedVGPRFile) <= VectorCriticalLimit &&
2001 (!UnifiedVGPRFile ||
2002 (PressureAfter.getArchVGPRNum() <= S.VGPRExcessLimit &&
2003 PressureAfter.getAGPRNum() <= S.AGPRExcessLimit))) {
2004 DAG.Pressure[RegionIdx] = PressureAfter;
2005
2006 // Early out if we have achieved the occupancy target.
2007 LLVM_DEBUG(dbgs() << "Pressure in desired limits, done.\n");
2008 return;
2009 }
2010
2011 unsigned TargetOccupancy = std::min(
2012 S.getTargetOccupancy(), ST.getOccupancyWithWorkGroupSizes(MF).second);
2013 unsigned WavesAfter = std::min(
2014 TargetOccupancy, PressureAfter.getOccupancy(ST, DynamicVGPRBlockSize));
2015 unsigned WavesBefore = std::min(
2016 TargetOccupancy, PressureBefore.getOccupancy(ST, DynamicVGPRBlockSize));
2017 LLVM_DEBUG(dbgs() << "Occupancy before scheduling: " << WavesBefore
2018 << ", after " << WavesAfter << ".\n");
2019
2020 // We may not be able to keep the current target occupancy because of the just
2021 // scheduled region. We might still be able to revert scheduling if the
2022 // occupancy before was higher, or if the current schedule has register
2023 // pressure higher than the excess limits which could lead to more spilling.
2024 unsigned NewOccupancy = std::max(WavesAfter, WavesBefore);
2025
2026 // Allow memory bound functions to drop to 4 waves if not limited by an
2027 // attribute.
2028 if (WavesAfter < WavesBefore && WavesAfter < DAG.MinOccupancy &&
2029 WavesAfter >= MFI.getMinAllowedOccupancy()) {
2030 LLVM_DEBUG(dbgs() << "Function is memory bound, allow occupancy drop up to "
2031 << MFI.getMinAllowedOccupancy() << " waves\n");
2032 NewOccupancy = WavesAfter;
2033 }
2034
2035 if (NewOccupancy < DAG.MinOccupancy) {
2036 DAG.MinOccupancy = NewOccupancy;
2037 MFI.limitOccupancy(DAG.MinOccupancy);
2038 LLVM_DEBUG(dbgs() << "Occupancy lowered for the function to "
2039 << DAG.MinOccupancy << ".\n");
2040 }
2041 // The maximum number of arch VGPR on non-unified register file, or the
2042 // maximum VGPR + AGPR in the unified register file case.
2043 unsigned MaxVGPRs = ST.getMaxNumVGPRs(MF);
2044 // The maximum number of arch VGPR for both unified and non-unified register
2045 // file.
2046 unsigned MaxArchVGPRs = std::min(MaxVGPRs, ST.getAddressableNumArchVGPRs());
2047 unsigned MaxSGPRs = ST.getMaxNumSGPRs(MF);
2048
2049 if (PressureAfter.getVGPRNum(ST.hasGFX90AInsts()) > MaxVGPRs ||
2050 PressureAfter.getArchVGPRNum() > MaxArchVGPRs ||
2051 PressureAfter.getAGPRNum() > MaxArchVGPRs ||
2052 PressureAfter.getSGPRNum() > MaxSGPRs) {
2053 DAG.RegionsWithHighRP[RegionIdx] = true;
2054 DAG.RegionsWithExcessRP[RegionIdx] = true;
2055 }
2056
2057 // Revert if this region's schedule would cause a drop in occupancy or
2058 // spilling.
2059 if (shouldRevertScheduling(WavesAfter)) {
2061 std::tie(DAG.RegionBegin, DAG.RegionEnd) = DAG.Regions[RegionIdx];
2062 } else {
2063 DAG.Pressure[RegionIdx] = PressureAfter;
2064 }
2065}
2066
2067unsigned
2068GCNSchedStage::computeSUnitReadyCycle(const SUnit &SU, unsigned CurrCycle,
2069 DenseMap<unsigned, unsigned> &ReadyCycles,
2070 const TargetSchedModel &SM) {
2071 unsigned ReadyCycle = CurrCycle;
2072 for (auto &D : SU.Preds) {
2073 if (D.isAssignedRegDep()) {
2074 MachineInstr *DefMI = D.getSUnit()->getInstr();
2075 unsigned Latency = SM.computeInstrLatency(DefMI);
2076 unsigned DefReady = ReadyCycles[DAG.getSUnit(DefMI)->NodeNum];
2077 ReadyCycle = std::max(ReadyCycle, DefReady + Latency);
2078 }
2079 }
2080 ReadyCycles[SU.NodeNum] = ReadyCycle;
2081 return ReadyCycle;
2082}
2083
2084#ifndef NDEBUG
2086 bool operator()(std::pair<MachineInstr *, unsigned> A,
2087 std::pair<MachineInstr *, unsigned> B) const {
2088 return A.second < B.second;
2089 }
2090};
2091
2092static void printScheduleModel(std::set<std::pair<MachineInstr *, unsigned>,
2093 EarlierIssuingCycle> &ReadyCycles) {
2094 if (ReadyCycles.empty())
2095 return;
2096 unsigned BBNum = ReadyCycles.begin()->first->getParent()->getNumber();
2097 dbgs() << "\n################## Schedule time ReadyCycles for MBB : " << BBNum
2098 << " ##################\n# Cycle #\t\t\tInstruction "
2099 " "
2100 " \n";
2101 unsigned IPrev = 1;
2102 for (auto &I : ReadyCycles) {
2103 if (I.second > IPrev + 1)
2104 dbgs() << "****************************** BUBBLE OF " << I.second - IPrev
2105 << " CYCLES DETECTED ******************************\n\n";
2106 dbgs() << "[ " << I.second << " ] : " << *I.first << "\n";
2107 IPrev = I.second;
2108 }
2109}
2110#endif
2111
2112ScheduleMetrics
2113GCNSchedStage::getScheduleMetrics(const std::vector<SUnit> &InputSchedule) {
2114#ifndef NDEBUG
2115 std::set<std::pair<MachineInstr *, unsigned>, EarlierIssuingCycle>
2116 ReadyCyclesSorted;
2117#endif
2118 const TargetSchedModel &SM = ST.getInstrInfo()->getSchedModel();
2119 unsigned SumBubbles = 0;
2120 DenseMap<unsigned, unsigned> ReadyCycles;
2121 unsigned CurrCycle = 0;
2122 for (auto &SU : InputSchedule) {
2123 unsigned ReadyCycle =
2124 computeSUnitReadyCycle(SU, CurrCycle, ReadyCycles, SM);
2125 SumBubbles += ReadyCycle - CurrCycle;
2126#ifndef NDEBUG
2127 ReadyCyclesSorted.insert(std::make_pair(SU.getInstr(), ReadyCycle));
2128#endif
2129 CurrCycle = ++ReadyCycle;
2130 }
2131#ifndef NDEBUG
2132 LLVM_DEBUG(
2133 printScheduleModel(ReadyCyclesSorted);
2134 dbgs() << "\n\t"
2135 << "Metric: "
2136 << (SumBubbles
2137 ? (SumBubbles * ScheduleMetrics::ScaleFactor) / CurrCycle
2138 : 1)
2139 << "\n\n");
2140#endif
2141
2142 return ScheduleMetrics(CurrCycle, SumBubbles);
2143}
2144
2147#ifndef NDEBUG
2148 std::set<std::pair<MachineInstr *, unsigned>, EarlierIssuingCycle>
2149 ReadyCyclesSorted;
2150#endif
2151 const TargetSchedModel &SM = ST.getInstrInfo()->getSchedModel();
2152 unsigned SumBubbles = 0;
2153 DenseMap<unsigned, unsigned> ReadyCycles;
2154 unsigned CurrCycle = 0;
2155 for (auto &MI : DAG) {
2156 SUnit *SU = DAG.getSUnit(&MI);
2157 if (!SU)
2158 continue;
2159 unsigned ReadyCycle =
2160 computeSUnitReadyCycle(*SU, CurrCycle, ReadyCycles, SM);
2161 SumBubbles += ReadyCycle - CurrCycle;
2162#ifndef NDEBUG
2163 ReadyCyclesSorted.insert(std::make_pair(SU->getInstr(), ReadyCycle));
2164#endif
2165 CurrCycle = ++ReadyCycle;
2166 }
2167#ifndef NDEBUG
2168 LLVM_DEBUG(
2169 printScheduleModel(ReadyCyclesSorted);
2170 dbgs() << "\n\t"
2171 << "Metric: "
2172 << (SumBubbles
2173 ? (SumBubbles * ScheduleMetrics::ScaleFactor) / CurrCycle
2174 : 1)
2175 << "\n\n");
2176#endif
2177
2178 return ScheduleMetrics(CurrCycle, SumBubbles);
2179}
2180
2181bool GCNSchedStage::shouldRevertScheduling(unsigned WavesAfter) {
2182 if (WavesAfter < DAG.MinOccupancy)
2183 return true;
2184
2185 // For dynamic VGPR mode, we don't want to waste any VGPR blocks.
2186 if (DAG.MFI.isDynamicVGPREnabled()) {
2187 unsigned BlocksBefore = AMDGPU::IsaInfo::getAllocatedNumVGPRBlocks(
2188 ST, PressureBefore.getVGPRNum(false),
2189 DAG.MFI.getDynamicVGPRBlockSize());
2190 unsigned BlocksAfter = AMDGPU::IsaInfo::getAllocatedNumVGPRBlocks(
2191 ST, PressureAfter.getVGPRNum(false), DAG.MFI.getDynamicVGPRBlockSize());
2192 if (BlocksAfter > BlocksBefore)
2193 return true;
2194 }
2195
2196 return false;
2197}
2198
2201 return false;
2202
2204 return true;
2205
2206 if (mayCauseSpilling(WavesAfter))
2207 return true;
2208
2209 return false;
2210}
2211
2213 // If RP is not reduced in the unclustered reschedule stage, revert to the
2214 // old schedule.
2215 if ((WavesAfter <=
2216 PressureBefore.getOccupancy(ST, DAG.MFI.getDynamicVGPRBlockSize()) &&
2217 mayCauseSpilling(WavesAfter)) ||
2219 LLVM_DEBUG(dbgs() << "Unclustered reschedule did not help.\n");
2220 return true;
2221 }
2222
2223 // Do not attempt to relax schedule even more if we are already spilling.
2225 return false;
2226
2227 LLVM_DEBUG(
2228 dbgs()
2229 << "\n\t *** In shouldRevertScheduling ***\n"
2230 << " *********** BEFORE UnclusteredHighRPStage ***********\n");
2231 ScheduleMetrics MBefore = getScheduleMetrics(DAG.SUnits);
2232 LLVM_DEBUG(
2233 dbgs()
2234 << "\n *********** AFTER UnclusteredHighRPStage ***********\n");
2236 unsigned OldMetric = MBefore.getMetric();
2237 unsigned NewMetric = MAfter.getMetric();
2238 unsigned WavesBefore = std::min(
2239 S.getTargetOccupancy(),
2240 PressureBefore.getOccupancy(ST, DAG.MFI.getDynamicVGPRBlockSize()));
2241 unsigned Profit =
2242 ((WavesAfter * ScheduleMetrics::ScaleFactor) / WavesBefore *
2244 NewMetric) /
2246 LLVM_DEBUG(dbgs() << "\tMetric before " << MBefore << "\tMetric after "
2247 << MAfter << "Profit: " << Profit << "\n");
2248 return Profit < ScheduleMetrics::ScaleFactor;
2249}
2250
2253 return false;
2254
2256 return true;
2257
2258 if (mayCauseSpilling(WavesAfter))
2259 return true;
2260
2261 return false;
2262}
2263
2265 return GCNSchedStage::shouldRevertScheduling(WavesAfter) ||
2266 mayCauseSpilling(WavesAfter);
2267}
2268
2270 if (mayCauseSpilling(WavesAfter))
2271 return true;
2272
2273 return false;
2274}
2275
2277 unsigned WavesAfter) {
2278 return mayCauseSpilling(WavesAfter);
2279}
2280
2282 "amdgpu-lirp-reschedule", cl::Hidden,
2283 cl::desc("Enable live interval RP reschedule stage"), cl::init(true));
2284
2286 "amdgpu-lirp-threshold", cl::Hidden,
2287 cl::desc("Percent increase of live interval RP over instant pressure to "
2288 "trigger rescheduling"),
2289 cl::init(10));
2290
2292 "amdgpu-lirp-vgpr-reduction", cl::Hidden,
2293 cl::desc(
2294 "Reduction factor (percent) for VGPR threshold during live interval RP "
2295 "reschedule stage"),
2296 cl::init(90));
2297
2299 "amdgpu-lirp-instant-lower-bound", cl::Hidden,
2300 cl::desc("Lower bound (percent of the VGPR excess limit) on instant RP, "
2301 "below which a region is skipped"),
2302 cl::init(10));
2303
2306 return false;
2307
2309 return false;
2310
2311 if (!S.VGPRThresholdPercent) {
2312 LLVM_DEBUG(dbgs() << "LIRP: expected VGPRThresholdPercent to be enabled, "
2313 "not using live interval RP reschedule stage\n");
2314 return false;
2315 }
2316
2317 return true;
2318}
2319
2321 unsigned InstantRP = DAG.Pressure[RegionIdx].getArchVGPRNum();
2322 auto [RegionBegin, RegionEnd] = DAG.Regions[RegionIdx];
2323 if (RegionBegin == RegionEnd)
2324 return false;
2325
2326 unsigned LIRP = estimateGreedyVGPRPressure(
2327 RegionBegin, RegionEnd, DAG.LiveIns[RegionIdx], *DAG.getLIS(),
2328 DAG.MF.getRegInfo(), static_cast<const SIRegisterInfo &>(*DAG.TRI));
2329
2330 unsigned NewVGPRThresholdPercent =
2331 (S.VGPRThresholdPercent * LiveIntervalRPVGPRReduction + 99) / 100;
2332
2333 LLVM_DEBUG(dbgs() << "LIRP: Region " << RegionIdx
2334 << ", VGPRThresholdPercent: " << S.VGPRThresholdPercent
2335 << " -> " << NewVGPRThresholdPercent
2336 << ", VGPRExcessLimit=" << S.VGPRExcessLimit
2337 << ", VGPRCriticalLimit=" << S.VGPRCriticalLimit
2338 << ", InstantRP=" << InstantRP << ", LIRP=" << LIRP);
2339
2340 bool DoRescheduling = false;
2341 // Lower bound on InstantRP to skip over tiny regions.
2342 unsigned InstantRPLowerBound =
2343 S.VGPRExcessLimit * LiveIntervalRPInstantLowerBound / 100;
2344 if (LIRP > S.VGPRExcessLimit) {
2345 LLVM_DEBUG(dbgs() << " [LIRP exceeds the limit (" << S.VGPRExcessLimit
2346 << "), rescheduling]");
2347 DoRescheduling = true;
2348 } else if (LIRP > InstantRP && InstantRP > InstantRPLowerBound) {
2349 unsigned IncreasePercent = ((LIRP - InstantRP) * 100) / InstantRP;
2350 if (IncreasePercent > LiveIntervalRPThreshold) {
2351 LLVM_DEBUG(dbgs() << " [" << IncreasePercent << "% > "
2352 << LiveIntervalRPThreshold << "%, rescheduling]");
2353 DoRescheduling = true;
2354 }
2355 }
2356 LLVM_DEBUG(dbgs() << '\n');
2357
2358 if (DoRescheduling && GCNSchedStage::initGCNRegion()) {
2359 SavedVGPRExcessLimit = S.VGPRExcessLimit;
2360 SavedVGPRCriticalLimit = S.VGPRCriticalLimit;
2361 SavedUnifiedVGPRCriticalLimit = S.UnifiedVGPRCriticalLimit;
2362 SavedVGPRThresholdPercent = S.VGPRThresholdPercent;
2363 S.VGPRThresholdPercent = NewVGPRThresholdPercent;
2364 return true;
2365 }
2366
2367 return false;
2368}
2369
2371 S.VGPRExcessLimit = SavedVGPRExcessLimit;
2372 S.VGPRCriticalLimit = SavedVGPRCriticalLimit;
2373 S.UnifiedVGPRCriticalLimit = SavedUnifiedVGPRCriticalLimit;
2374 S.VGPRThresholdPercent = SavedVGPRThresholdPercent;
2376}
2377
2378bool GCNSchedStage::mayCauseSpilling(unsigned WavesAfter) {
2379 if (WavesAfter <= MFI.getMinWavesPerEU() && isRegionWithExcessRP() &&
2381 LLVM_DEBUG(dbgs() << "New pressure will result in more spilling.\n");
2382 return true;
2383 }
2384
2385 return false;
2386}
2387
2389 ArrayRef<MachineInstr *> MIOrder) {
2390 assert(static_cast<size_t>(std::distance(DAG.Regions[RegionIdx].first,
2391 DAG.Regions[RegionIdx].second)) ==
2392 MIOrder.size() &&
2393 "instruction number mismatch");
2394 if (MIOrder.empty())
2395 return;
2396
2397 LLVM_DEBUG(dbgs() << "Reverting scheduling for region " << RegionIdx << '\n');
2398
2399 // Reconstruct MI sequence by moving instructions in desired order before
2400 // the current region's start.
2401 MachineBasicBlock::iterator RegionEnd = DAG.Regions[RegionIdx].first;
2402 MachineBasicBlock *MBB = MIOrder.front()->getParent();
2403 for (MachineInstr *MI : MIOrder) {
2404 // Either move the next MI in order before the end of the region or move the
2405 // region end past the MI if it is at the correct position.
2406 MachineBasicBlock::iterator MII = MI->getIterator();
2407 if (MII != RegionEnd) {
2408 // Will subsequent splice move MI up past a non-debug instruction?
2409 bool NonDebugReordered =
2410 !MI->isDebugInstr() &&
2411 skipDebugInstructionsForward(RegionEnd, MII) != MII;
2412 MBB->splice(RegionEnd, MBB, MI);
2413 // Only update LiveIntervals information if non-debug instructions are
2414 // reordered. Otherwise debug instructions could cause code generation to
2415 // change.
2416 if (NonDebugReordered)
2417 DAG.LIS->handleMove(*MI, true);
2418 } else {
2419 // MI is already at the expected position. However, earlier splices in
2420 // this loop may have changed neighboring slot indices, so this MI's
2421 // slot index can become non-monotonic w.r.t. the physical MBB order.
2422 // Only re-seat when monotonicity is actually violated to avoid
2423 // unnecessary LiveInterval changes that could perturb scheduling.
2424 if (!MI->isDebugInstr()) {
2425 SlotIndex MIIdx = DAG.LIS->getInstructionIndex(*MI);
2426 SlotIndex PrevIdx = DAG.LIS->getSlotIndexes()->getIndexBefore(*MI);
2427 if (PrevIdx >= MIIdx)
2428 DAG.LIS->handleMove(*MI, true);
2429 }
2430 ++RegionEnd;
2431 }
2432 if (MI->isDebugInstr()) {
2433 LLVM_DEBUG(dbgs() << "Scheduling " << *MI);
2434 continue;
2435 }
2436
2437 // Reset read-undef flags and update them later.
2439 DAG.ShouldTrackLaneMasks);
2440 LLVM_DEBUG(dbgs() << "Scheduling " << *MI);
2441 }
2442
2443 // The region end doesn't change throughout scheduling since it itself is
2444 // outside the region (whether that is a MBB end or a terminator MI).
2445 assert(RegionEnd == DAG.Regions[RegionIdx].second && "region end mismatch");
2446 DAG.Regions[RegionIdx].first = MIOrder.front();
2447}
2448
2449/// Returns true if reaching def \p RD will be in AGPR form after the rewrite
2450/// and so needs no bridge copy: a candidate MFMA in \p RewriteSet, an
2451/// AV_MOV_*_IMM_PSEUDO, or a copy from a candidate src2 reg in \p CandSrc2Regs.
2452/// A non-candidate MFMA stays in VGPR form and still needs a bridge.
2454 MachineInstr *RD, const SmallPtrSetImpl<MachineInstr *> &RewriteSet,
2455 const DenseSet<Register> &CandSrc2Regs, const SIInstrInfo &TII) {
2456 if (TII.isMAI(*RD))
2457 return RewriteSet.contains(RD);
2458 if (RD->getOpcode() == AMDGPU::AV_MOV_B32_IMM_PSEUDO ||
2459 RD->getOpcode() == AMDGPU::AV_MOV_B64_IMM_PSEUDO)
2460 return true;
2461 if (RD->isCopy() && CandSrc2Regs.contains(RD->getOperand(1).getReg()))
2462 return true;
2463 return false;
2464}
2465
2466bool RewriteMFMAFormStage::hasUseRequiringVGPR(
2467 ArrayRef<SlotIndex> Src2ReachingDefs,
2468 const SmallPtrSetImpl<MachineInstr *> &RewriteSet) {
2469 for (SlotIndex RDIdx : Src2ReachingDefs) {
2470 const MachineInstr *RD = DAG.LIS->getInstructionFromIndex(RDIdx);
2472 findReachingUses(RD, DAG.LIS, ReachingUses);
2473 for (const MachineOperand *UseMO : ReachingUses) {
2474 const MachineInstr *UseMI = UseMO->getParent();
2475 if (UseMI->isCopy())
2476 continue;
2477 if (TII->isMAI(*UseMI) && RewriteSet.contains(UseMI))
2478 continue;
2479 return true;
2480 }
2481 }
2482 return false;
2483}
2484
2485void RewriteMFMAFormStage::resetRewriteCandsToVGPR(
2486 ArrayRef<std::pair<MachineInstr *, unsigned>> RewriteCands) {
2487 for (auto [MI, OriginalOpcode] : RewriteCands) {
2488 assert(TII->isMAI(*MI));
2489 const TargetRegisterClass *ADefRC =
2490 DAG.MRI.getRegClass(MI->getOperand(0).getReg());
2491 const TargetRegisterClass *VDefRC = SRI->getEquivalentVGPRClass(ADefRC);
2492 DAG.MRI.setRegClass(MI->getOperand(0).getReg(), VDefRC);
2493 MI->setDesc(TII->get(OriginalOpcode));
2494
2495 MachineOperand *Src2 = TII->getNamedOperand(*MI, AMDGPU::OpName::src2);
2496 if (!Src2->isReg())
2497 continue;
2498
2499 // Have to get src types separately since subregs may cause C and D
2500 // registers to be different types even though the actual operand is
2501 // the same size.
2502 const TargetRegisterClass *AUseRC = DAG.MRI.getRegClass(Src2->getReg());
2503 const TargetRegisterClass *VUseRC = SRI->getEquivalentVGPRClass(AUseRC);
2504 DAG.MRI.setRegClass(Src2->getReg(), VUseRC);
2505 }
2506}
2507
2508bool RewriteMFMAFormStage::isRewriteCandidate(MachineInstr *MI) const {
2509 if (!static_cast<const SIInstrInfo *>(DAG.TII)->isMAI(*MI))
2510 return false;
2511 if (AMDGPU::getAGPRFormOp(MI->getOpcode()) == -1)
2512 return false;
2513 // Reject candidates whose users force an unavoidable bridge copy.
2514 Register DstReg = MI->getOperand(0).getReg();
2515 for (const MachineInstr &UseMI : DAG.MRI.use_nodbg_instructions(DstReg)) {
2516 if (!TII->isMAI(UseMI) && !UseMI.isCopy())
2517 return false;
2518 }
2519 return true;
2520}
2521
2522bool RewriteMFMAFormStage::initHeuristics(
2523 std::vector<std::pair<MachineInstr *, unsigned>> &RewriteCands,
2524 DenseMap<MachineBasicBlock *, std::set<Register>> &CopyForUse,
2525 SmallPtrSetImpl<MachineInstr *> &CopyForDef) {
2526 bool Changed = false;
2527
2528 // Collect the candidate group, its members share AGPR-form operands
2529 // post-rewrite, so reaching defs feeding any member don't need bridge copy.
2530 SmallPtrSet<MachineInstr *, 16> RewriteSet;
2531 DenseSet<Register> CandSrc2Regs;
2532 for (MachineBasicBlock &MBB : MF) {
2533 for (MachineInstr &MI : MBB) {
2534 if (!isRewriteCandidate(&MI))
2535 continue;
2536 RewriteSet.insert(&MI);
2537 MachineOperand *Src2 = TII->getNamedOperand(MI, AMDGPU::OpName::src2);
2538 if (Src2 && Src2->isReg())
2539 CandSrc2Regs.insert(Src2->getReg());
2540 }
2541 }
2542
2543 // Prepare for the heuristics
2544 for (MachineBasicBlock &MBB : MF) {
2545 for (MachineInstr &MI : MBB) {
2546 if (!isRewriteCandidate(&MI))
2547 continue;
2548
2549 int ReplacementOp = AMDGPU::getAGPRFormOp(MI.getOpcode());
2550 assert(ReplacementOp != -1);
2551
2552 RewriteCands.push_back({&MI, MI.getOpcode()});
2553 MI.setDesc(TII->get(ReplacementOp));
2554
2555 MachineOperand *Src2 = TII->getNamedOperand(MI, AMDGPU::OpName::src2);
2556 if (Src2->isReg()) {
2557 SmallVector<SlotIndex, 8> Src2ReachingDefs;
2558 findReachingDefs(*Src2, DAG.LIS, Src2ReachingDefs);
2559
2560 // If src2 has a use that must remain VGPR, it cannot be reclassified to
2561 // AGPR.
2562 bool Src2NeedsVGPR = hasUseRequiringVGPR(Src2ReachingDefs, RewriteSet);
2563 Src2NeedsVGPRCache[&MI] = Src2NeedsVGPR;
2564
2565 for (SlotIndex RDIdx : Src2ReachingDefs) {
2566 MachineInstr *RD = DAG.LIS->getInstructionFromIndex(RDIdx);
2567 if (!Src2NeedsVGPR &&
2568 isReachingDefAGPRForm(RD, RewriteSet, CandSrc2Regs, *TII))
2569 continue;
2570 CopyForDef.insert(RD);
2571 }
2572 }
2573
2574 MachineOperand &Dst = MI.getOperand(0);
2575 SmallVector<MachineOperand *, 8> DstReachingUses;
2576
2577 findReachingUses(&MI, DAG.LIS, DstReachingUses);
2578
2579 for (MachineOperand *RUOp : DstReachingUses) {
2580 MachineInstr *UserMI = RUOp->getParent();
2581 // Group members read the AGPR result directly.
2582 if (TII->isMAI(*UserMI) && RewriteSet.contains(UserMI))
2583 continue;
2584
2585 // For any user of the result of the MFMA which is not an MFMA, we
2586 // insert a copy. For a given register, we will only insert one copy
2587 // per user block.
2588 CopyForUse[UserMI->getParent()].insert(RUOp->getReg());
2589
2590 if (TII->isMAI(*UserMI))
2591 continue;
2592
2593 SmallVector<SlotIndex, 8> DstUsesReachingDefs;
2594 findReachingDefs(*RUOp, DAG.LIS, DstUsesReachingDefs);
2595
2596 for (SlotIndex RDIndex : DstUsesReachingDefs) {
2597 MachineInstr *RD = DAG.LIS->getInstructionFromIndex(RDIndex);
2598 if (TII->isMAI(*RD))
2599 continue;
2600
2601 // For any definition of the user of the MFMA which is not an MFMA,
2602 // we insert a copy. We do this to transform all the reaching defs
2603 // of this use to AGPR. By doing this, we can insert a copy from
2604 // AGPR to VGPR at the user rather than after the MFMA.
2605 CopyForDef.insert(RD);
2606 }
2607 }
2608
2609 // Do the rewrite to allow for updated RP calculation.
2610 const TargetRegisterClass *VDefRC = DAG.MRI.getRegClass(Dst.getReg());
2611 const TargetRegisterClass *ADefRC = SRI->getEquivalentAGPRClass(VDefRC);
2612 DAG.MRI.setRegClass(Dst.getReg(), ADefRC);
2613 if (Src2->isReg()) {
2614 // Have to get src types separately since subregs may cause C and D
2615 // registers to be different types even though the actual operand is
2616 // the same size.
2617 const TargetRegisterClass *VUseRC = DAG.MRI.getRegClass(Src2->getReg());
2618 const TargetRegisterClass *AUseRC = SRI->getEquivalentAGPRClass(VUseRC);
2619 DAG.MRI.setRegClass(Src2->getReg(), AUseRC);
2620 }
2621 Changed = true;
2622 }
2623 }
2624
2625 return Changed;
2626}
2627
2628int64_t RewriteMFMAFormStage::getRewriteCost(
2629 ArrayRef<std::pair<MachineInstr *, unsigned>> RewriteCands,
2630 const DenseMap<MachineBasicBlock *, std::set<Register>> &CopyForUse,
2631 const SmallPtrSetImpl<MachineInstr *> &CopyForDef) {
2632 MachineBlockFrequencyInfo *MBFI = DAG.MBFI;
2633
2634 int64_t BestSpillCost = 0;
2635 int64_t Cost = 0;
2636 uint64_t EntryFreq = MBFI->getEntryFreq().getFrequency();
2637
2638 std::pair<unsigned, unsigned> MaxVectorRegs =
2639 ST.getMaxNumVectorRegs(MF.getFunction());
2640 unsigned ArchVGPRThreshold = MaxVectorRegs.first;
2641 unsigned AGPRThreshold = MaxVectorRegs.second;
2642 unsigned CombinedThreshold = ST.getMaxNumVGPRs(MF);
2643
2644 for (unsigned Region = 0; Region < DAG.Regions.size(); Region++) {
2645 if (!RegionsWithExcessArchVGPR[Region])
2646 continue;
2647
2648 GCNRegPressure &PressureBefore = DAG.Pressure[Region];
2649 unsigned SpillCostBefore = PressureBefore.getVGPRSpills(
2650 MF, ArchVGPRThreshold, AGPRThreshold, CombinedThreshold);
2651
2652 // For the cases we care about (i.e. ArchVGPR usage is greater than the
2653 // addressable limit), rewriting alone should bring pressure to manageable
2654 // level. If we find any such region, then the rewrite is potentially
2655 // beneficial.
2656 GCNRegPressure PressureAfter = DAG.getRealRegPressure(Region);
2657 unsigned SpillCostAfter = PressureAfter.getVGPRSpills(
2658 MF, ArchVGPRThreshold, AGPRThreshold, CombinedThreshold);
2659
2660 uint64_t BlockFreq =
2661 MBFI->getBlockFreq(DAG.Regions[Region].first->getParent())
2662 .getFrequency();
2663
2664 bool RelativeFreqIsDenom = EntryFreq > BlockFreq;
2665 uint64_t RelativeFreq = EntryFreq && BlockFreq
2666 ? (RelativeFreqIsDenom ? EntryFreq / BlockFreq
2667 : BlockFreq / EntryFreq)
2668 : 1;
2669
2670 // This assumes perfect spilling / splitting -- using one spill / copy
2671 // instruction and one restoreFrom / copy for each excess register,
2672 int64_t SpillCost = ((int)SpillCostAfter - (int)SpillCostBefore) * 2;
2673
2674 // Also account for the block frequency.
2675 if (RelativeFreqIsDenom)
2676 SpillCost /= (int64_t)RelativeFreq;
2677 else
2678 SpillCost *= (int64_t)RelativeFreq;
2679
2680 // If we have increased spilling in any block, just bail.
2681 if (SpillCost > 0) {
2682 resetRewriteCandsToVGPR(RewriteCands);
2683 return SpillCost;
2684 }
2685
2686 if (SpillCost < BestSpillCost)
2687 BestSpillCost = SpillCost;
2688 }
2689
2690 // Set the cost to the largest decrease in spill cost in order to not double
2691 // count spill reductions.
2692 Cost = BestSpillCost;
2693 assert(Cost <= 0);
2694
2695 unsigned CopyCost = 0;
2696
2697 // For each CopyForDef, increase the cost by the register size while
2698 // accounting for block frequency.
2699 for (MachineInstr *DefMI : CopyForDef) {
2700 Register DefReg = DefMI->getOperand(0).getReg();
2701 uint64_t DefFreq =
2702 EntryFreq
2703 ? MBFI->getBlockFreq(DefMI->getParent()).getFrequency() / EntryFreq
2704 : 1;
2705
2706 const TargetRegisterClass *RC = DAG.MRI.getRegClass(DefReg);
2707 CopyCost += RC->getCopyCost() * DefFreq;
2708 }
2709
2710 // Account for CopyForUse copies in each block that the register is used.
2711 for (auto &[UseBlock, UseRegs] : CopyForUse) {
2712 uint64_t UseFreq =
2713 EntryFreq ? MBFI->getBlockFreq(UseBlock).getFrequency() / EntryFreq : 1;
2714
2715 for (Register UseReg : UseRegs) {
2716 const TargetRegisterClass *RC = DAG.MRI.getRegClass(UseReg);
2717 CopyCost += RC->getCopyCost() * UseFreq;
2718 }
2719 }
2720
2721 // Reset the classes that were changed to AGPR for better register bank
2722 // analysis. We must do rewriting after copy-insertion, as some defs of the
2723 // register may require VGPR. Additionally, if we bail out and don't perform
2724 // the rewrite then these need to be restored anyway.
2725 resetRewriteCandsToVGPR(RewriteCands);
2726
2727 return Cost + CopyCost;
2728}
2729
2730bool RewriteMFMAFormStage::rewrite(
2731 ArrayRef<std::pair<MachineInstr *, unsigned>> RewriteCands) {
2732 DenseMap<MachineInstr *, unsigned> FirstMIToRegion;
2733 DenseMap<MachineInstr *, unsigned> LastMIToRegion;
2734
2735 for (unsigned Region = 0; Region < DAG.Regions.size(); Region++) {
2736 RegionBoundaries Entry = DAG.Regions[Region];
2737 if (Entry.first == Entry.second)
2738 continue;
2739
2740 FirstMIToRegion[&*Entry.first] = Region;
2741 if (Entry.second != Entry.first->getParent()->end())
2742 LastMIToRegion[&*Entry.second] = Region;
2743 }
2744
2745 // Rewrite the MFMAs to AGPR, and insert any copies as needed.
2746 // The general assumption of the algorithm (and the previous cost calculation)
2747 // is that it is better to insert the copies in the MBB of the def of the src2
2748 // operands, and in the MBB of the user of the dest operands. This is based on
2749 // the assumption that the MFMAs are likely to appear in loop bodies, while
2750 // the src2 and dest operands are live-in / live-out of the loop. Due to this
2751 // design, the algorithm for finding copy insertion points is more
2752 // complicated.
2753 //
2754 // There are three main cases to handle: 1. the reaching defs of the src2
2755 // operands, 2. the reaching uses of the dst operands, and 3. the reaching
2756 // defs of the reaching uses of the dst operand.
2757 //
2758 // In the first case, we simply insert copies after each of the reaching
2759 // definitions. In the second case, we collect all the uses of a given dest
2760 // and organize them by MBB. Then, we insert 1 copy for each MBB before the
2761 // earliest use. Since the use may have multiple reaching defs, and since we
2762 // want to replace the register it is using with the result of the copy, we
2763 // must handle case 3. In the third case, we simply insert a copy after each
2764 // of the reaching defs to connect to the copy of the reaching uses of the dst
2765 // reg. This allows us to avoid inserting copies next to the MFMAs.
2766 //
2767 // While inserting the copies, we maintain a map of operands which will use
2768 // different regs (i.e. the result of the copies). For example, a case 1 src2
2769 // operand will use the register result of the copies after the reaching defs,
2770 // as opposed to the original register. Now that we have completed our copy
2771 // analysis and placement, we can bulk update the registers. We do this
2772 // separately as to avoid complicating the reachingDef and reachingUse
2773 // queries.
2774 //
2775 // While inserting the copies, we also maintain a list or registers which we
2776 // will want to reclassify as AGPR. After doing the copy insertion and the
2777 // register replacement, we can finally do the reclassification. This uses the
2778 // redef map, as the registers we are interested in reclassifying may be
2779 // replaced by the result of a copy. We must do this after the copy analysis
2780 // and placement as we must have an accurate redef map -- otherwise we may end
2781 // up creating illegal instructions.
2782
2783 // The original registers of the MFMA that need to be reclassified as AGPR.
2784 DenseSet<Register> RewriteRegs;
2785 // The map of an original register in the MFMA to a new register (result of a
2786 // copy) that it should be replaced with.
2787 DenseMap<Register, Register> RedefMap;
2788 // The map of the original MFMA registers to the relevant MFMA operands.
2789 DenseMap<Register, DenseSet<MachineOperand *>> ReplaceMap;
2790 // The map of reaching defs for a given register -- to avoid duplicate copies.
2791 DenseMap<Register, SmallPtrSet<MachineInstr *, 8>> ReachingDefCopyMap;
2792 // The map of reaching uses for a given register by basic block -- to avoid
2793 // duplicate copies and to calculate per MBB insert pts.
2794 DenseMap<unsigned, DenseMap<Register, SmallPtrSet<MachineOperand *, 8>>>
2795 ReachingUseTracker;
2796
2797 // Collect the candidate group; its members share AGPR-form operands
2798 // post-rewrite, so reaching defs feeding any member need no bridge copy.
2799 SmallPtrSet<MachineInstr *, 16> RewriteCandsSet;
2800 DenseSet<Register> RewriteSrc2Regs;
2801 for (auto &[MI, OriginalOpcode] : RewriteCands) {
2802 RewriteCandsSet.insert(MI);
2803 MachineOperand *Src2 = TII->getNamedOperand(*MI, AMDGPU::OpName::src2);
2804 if (Src2 && Src2->isReg())
2805 RewriteSrc2Regs.insert(Src2->getReg());
2806 }
2807
2808 for (auto &[MI, OriginalOpcode] : RewriteCands) {
2809 int ReplacementOp = AMDGPU::getAGPRFormOp(MI->getOpcode());
2810 if (ReplacementOp == -1)
2811 continue;
2812 MI->setDesc(TII->get(ReplacementOp));
2813
2814 // Case 1: insert copies for the reaching defs of the Src2Reg.
2815 MachineOperand *Src2 = TII->getNamedOperand(*MI, AMDGPU::OpName::src2);
2816 if (Src2->isReg()) {
2817 Register Src2Reg = Src2->getReg();
2818 if (!Src2Reg.isVirtual())
2819 return false;
2820
2821 Register MappedReg = Src2->getReg();
2822 SmallVector<SlotIndex, 8> Src2ReachingDefs;
2823 findReachingDefs(*Src2, DAG.LIS, Src2ReachingDefs);
2824 SmallSetVector<MachineInstr *, 8> Src2DefsReplace;
2825
2826 // If src2 has a use that must remain VGPR, it cannot be reclassified to
2827 // AGPR.
2828 bool Src2NeedsVGPR = Src2NeedsVGPRCache.lookup(MI);
2829
2830 for (SlotIndex RDIndex : Src2ReachingDefs) {
2831 MachineInstr *RD = DAG.LIS->getInstructionFromIndex(RDIndex);
2832 if (!Src2NeedsVGPR &&
2833 isReachingDefAGPRForm(RD, RewriteCandsSet, RewriteSrc2Regs, *TII))
2834 continue;
2835
2836 Src2DefsReplace.insert(RD);
2837 }
2838
2839 if (!Src2DefsReplace.empty()) {
2840 auto RI = RedefMap.find(Src2Reg);
2841 if (RI != RedefMap.end()) {
2842 MappedReg = RI->second;
2843 } else {
2844 assert(!ReachingDefCopyMap.contains(Src2Reg));
2845 const TargetRegisterClass *Src2RC = DAG.MRI.getRegClass(Src2Reg);
2846 const TargetRegisterClass *VGPRRC =
2847 SRI->getEquivalentVGPRClass(Src2RC);
2848
2849 // Track the mapping of the original register to the new register.
2850 MappedReg = DAG.MRI.createVirtualRegister(VGPRRC);
2851 RedefMap[Src2Reg] = MappedReg;
2852 }
2853
2854 // If none exists, create a copy from this reaching def.
2855 // We may have inserted a copy already in an earlier iteration.
2856 for (MachineInstr *RD : Src2DefsReplace) {
2857 // Do not create redundant copies.
2858 if (ReachingDefCopyMap[Src2Reg].insert(RD).second) {
2859 MachineInstrBuilder VGPRCopy =
2860 BuildMI(*RD->getParent(), std::next(RD->getIterator()),
2861 RD->getDebugLoc(), TII->get(TargetOpcode::COPY))
2862 .addDef(MappedReg, {}, 0)
2863 .addUse(Src2Reg, {}, 0);
2864 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
2865
2866 // If this reaching def was the last MI in the region, update the
2867 // region boundaries.
2868 if (LastMIToRegion.contains(RD)) {
2869 unsigned UpdateRegion = LastMIToRegion[RD];
2870 DAG.Regions[UpdateRegion].second = VGPRCopy;
2871 LastMIToRegion.erase(RD);
2872 }
2873 }
2874 }
2875 }
2876
2877 // Track the register for reclassification
2878 RewriteRegs.insert(Src2Reg);
2879
2880 // Always insert the operand for replacement. If this corresponds with a
2881 // chain of tied-def we may not see the VGPR requirement until later.
2882 ReplaceMap[Src2Reg].insert(Src2);
2883 }
2884
2885 // Case 2 and Case 3: insert copies before the reaching uses of the dsts,
2886 // and after the reaching defs of the reaching uses of the dsts.
2887
2888 MachineOperand *Dst = &MI->getOperand(0);
2889 Register DstReg = Dst->getReg();
2890 if (!DstReg.isVirtual())
2891 return false;
2892
2893 Register MappedReg = DstReg;
2894 SmallVector<MachineOperand *, 8> DstReachingUses;
2895
2896 SmallVector<MachineOperand *, 8> DstReachingUseCopies;
2897 SmallVector<MachineInstr *, 8> DstUseDefsReplace;
2898
2899 findReachingUses(MI, DAG.LIS, DstReachingUses);
2900
2901 for (MachineOperand *RUOp : DstReachingUses) {
2902 MachineInstr *UserMI = RUOp->getParent();
2903 // Group members read the AGPR result directly.
2904 if (TII->isMAI(*UserMI) && RewriteCandsSet.contains(UserMI))
2905 continue;
2906
2907 // If there is a non mai reaching use, then we need a copy.
2908 if (find(DstReachingUseCopies, RUOp) == DstReachingUseCopies.end())
2909 DstReachingUseCopies.push_back(RUOp);
2910
2911 // Non-rewritten MAI: its defs aren't being reclassified.
2912 if (TII->isMAI(*UserMI))
2913 continue;
2914
2915 SmallVector<SlotIndex, 8> DstUsesReachingDefs;
2916 findReachingDefs(*RUOp, DAG.LIS, DstUsesReachingDefs);
2917
2918 for (SlotIndex RDIndex : DstUsesReachingDefs) {
2919 MachineInstr *RD = DAG.LIS->getInstructionFromIndex(RDIndex);
2920 if (TII->isMAI(*RD))
2921 continue;
2922
2923 // If there is a non mai reaching def of this reaching use, then we will
2924 // need a copy.
2925 if (find(DstUseDefsReplace, RD) == DstUseDefsReplace.end())
2926 DstUseDefsReplace.push_back(RD);
2927 }
2928 }
2929
2930 if (!DstUseDefsReplace.empty()) {
2931 auto RI = RedefMap.find(DstReg);
2932 if (RI != RedefMap.end()) {
2933 MappedReg = RI->second;
2934 } else {
2935 assert(!ReachingDefCopyMap.contains(DstReg));
2936 const TargetRegisterClass *DstRC = DAG.MRI.getRegClass(DstReg);
2937 const TargetRegisterClass *VGPRRC = SRI->getEquivalentVGPRClass(DstRC);
2938
2939 // Track the mapping of the original register to the new register.
2940 MappedReg = DAG.MRI.createVirtualRegister(VGPRRC);
2941 RedefMap[DstReg] = MappedReg;
2942 }
2943
2944 // If none exists, create a copy from this reaching def.
2945 // We may have inserted a copy already in an earlier iteration.
2946 for (MachineInstr *RD : DstUseDefsReplace) {
2947 // Do not create reundant copies.
2948 if (ReachingDefCopyMap[DstReg].insert(RD).second) {
2949 MachineInstrBuilder VGPRCopy =
2950 BuildMI(*RD->getParent(), std::next(RD->getIterator()),
2951 RD->getDebugLoc(), TII->get(TargetOpcode::COPY))
2952 .addDef(MappedReg, {}, 0)
2953 .addUse(DstReg, {}, 0);
2954 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
2955
2956 // If this reaching def was the last MI in the region, update the
2957 // region boundaries.
2958 auto LMI = LastMIToRegion.find(RD);
2959 if (LMI != LastMIToRegion.end()) {
2960 unsigned UpdateRegion = LMI->second;
2961 DAG.Regions[UpdateRegion].second = VGPRCopy;
2962 LastMIToRegion.erase(RD);
2963 }
2964 }
2965 }
2966 }
2967
2968 DenseSet<MachineOperand *> &DstRegSet = ReplaceMap[DstReg];
2969 // One AGPR→VGPR copy per dst register, shared by all same-block uses.
2970 Register SameBlockCopyReg;
2971 MachineInstr *EarliestSameBlockUse = nullptr;
2972 for (MachineOperand *RU : DstReachingUseCopies) {
2973 MachineBasicBlock *RUBlock = RU->getParent()->getParent();
2974 // Just keep track of the reaching use of this register by block. After we
2975 // have scanned all the MFMAs we can find optimal insert pts.
2976 if (RUBlock != MI->getParent()) {
2977 ReachingUseTracker[RUBlock->getNumber()][DstReg].insert(RU);
2978 continue;
2979 }
2980
2981 // Lazily create the copy register on first same-block use.
2982 if (!SameBlockCopyReg.isValid()) {
2983 const TargetRegisterClass *DstRC = DAG.MRI.getRegClass(DstReg);
2984 const TargetRegisterClass *VGPRRC = SRI->getEquivalentVGPRClass(DstRC);
2985 SameBlockCopyReg = DAG.MRI.createVirtualRegister(VGPRRC);
2986 }
2987
2988 // Track the earliest use for copy insertion point.
2989 MachineInstr *UseInst = RU->getParent();
2990 if (!EarliestSameBlockUse ||
2992 DAG.LIS->getInstructionIndex(*UseInst),
2993 DAG.LIS->getInstructionIndex(*EarliestSameBlockUse)))
2994 EarliestSameBlockUse = UseInst;
2995 RU->setReg(SameBlockCopyReg);
2996 }
2997
2998 // Insert the copy before the earliest same-block use.
2999 if (SameBlockCopyReg.isValid()) {
3000 MachineInstrBuilder VGPRCopy =
3001 BuildMI(*EarliestSameBlockUse->getParent(),
3002 EarliestSameBlockUse->getIterator(), DebugLoc(),
3003 TII->get(TargetOpcode::COPY), SameBlockCopyReg)
3004 .addUse(DstReg, {}, 0);
3005 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
3006 DstRegSet.insert(&VGPRCopy->getOperand(1));
3007 }
3008
3009 // Track the register for reclassification
3010 RewriteRegs.insert(DstReg);
3011
3012 // Insert the dst operand for replacement. If this dst is in a chain of
3013 // tied-def MFMAs, and the first src2 needs to be replaced with a new reg,
3014 // all the correspond operands need to be replaced.
3015 DstRegSet.insert(Dst);
3016 }
3017
3018 // Handle the copies for dst uses.
3019 using RUBType =
3020 std::pair<unsigned, DenseMap<Register, SmallPtrSet<MachineOperand *, 8>>>;
3021 for (RUBType RUBlockEntry : ReachingUseTracker) {
3022 using RUDType = std::pair<Register, SmallPtrSet<MachineOperand *, 8>>;
3023 for (RUDType RUDst : RUBlockEntry.second) {
3024 MachineOperand *OpBegin = *RUDst.second.begin();
3025 SlotIndex InstPt = DAG.LIS->getInstructionIndex(*OpBegin->getParent());
3026
3027 // Find the earliest use in this block.
3028 for (MachineOperand *User : RUDst.second) {
3029 SlotIndex NewInstPt = DAG.LIS->getInstructionIndex(*User->getParent());
3030 if (SlotIndex::isEarlierInstr(NewInstPt, InstPt))
3031 InstPt = NewInstPt;
3032 }
3033
3034 const TargetRegisterClass *DstRC = DAG.MRI.getRegClass(RUDst.first);
3035 const TargetRegisterClass *VGPRRC = SRI->getEquivalentVGPRClass(DstRC);
3036 Register NewUseReg = DAG.MRI.createVirtualRegister(VGPRRC);
3037 MachineInstr *UseInst = DAG.LIS->getInstructionFromIndex(InstPt);
3038
3039 MachineInstrBuilder VGPRCopy =
3040 BuildMI(*UseInst->getParent(), UseInst->getIterator(),
3041 UseInst->getDebugLoc(), TII->get(TargetOpcode::COPY))
3042 .addDef(NewUseReg, {}, 0)
3043 .addUse(RUDst.first, {}, 0);
3044 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
3045
3046 // If this UseInst was the first MI in the region, update the region
3047 // boundaries.
3048 auto FI = FirstMIToRegion.find(UseInst);
3049 if (FI != FirstMIToRegion.end()) {
3050 unsigned UpdateRegion = FI->second;
3051 DAG.Regions[UpdateRegion].first = VGPRCopy;
3052 FirstMIToRegion.erase(UseInst);
3053 }
3054
3055 // Replace the operand for all users.
3056 for (MachineOperand *User : RUDst.second) {
3057 User->setReg(NewUseReg);
3058 }
3059
3060 // Track the copy source operand for replacement.
3061 ReplaceMap[RUDst.first].insert(&VGPRCopy->getOperand(1));
3062 }
3063 }
3064
3065 // We may have needed to insert copies after the reaching defs of the MFMAs.
3066 // Replace the original register with the result of the copy for all relevant
3067 // operands.
3068 for (std::pair<Register, Register> NewDef : RedefMap) {
3069 Register OldReg = NewDef.first;
3070 Register NewReg = NewDef.second;
3071
3072 // Replace the register for any associated operand in the MFMA chain.
3073 for (MachineOperand *ReplaceOp : ReplaceMap[OldReg])
3074 ReplaceOp->setReg(NewReg);
3075 }
3076
3077 // Finally, do the reclassification of the MFMA registers.
3078 for (Register RewriteReg : RewriteRegs) {
3079 Register RegToRewrite = RewriteReg;
3080
3081 // Be sure to update the replacement register and not the original.
3082 auto RI = RedefMap.find(RewriteReg);
3083 if (RI != RedefMap.end())
3084 RegToRewrite = RI->second;
3085
3086 const TargetRegisterClass *CurrRC = DAG.MRI.getRegClass(RegToRewrite);
3087 const TargetRegisterClass *AGPRRC = SRI->getEquivalentAGPRClass(CurrRC);
3088
3089 DAG.MRI.setRegClass(RegToRewrite, AGPRRC);
3090 }
3091
3092 // Bulk update the LIS.
3093 DAG.LIS->reanalyze(DAG.MF);
3094 // Liveins may have been modified for cross RC copies
3095 RegionPressureMap LiveInUpdater(&DAG, false);
3096 LiveInUpdater.buildLiveRegMap();
3097
3098 for (unsigned Region = 0; Region < DAG.Regions.size(); Region++)
3099 DAG.LiveIns[Region] = LiveInUpdater.getLiveRegsForRegionIdx(Region);
3100
3101 DAG.Pressure[RegionIdx] = DAG.getRealRegPressure(RegionIdx);
3102
3103 return true;
3104}
3105
3106unsigned PreRARematStage::getStageTargetOccupancy() const {
3107 return TargetOcc ? *TargetOcc : MFI.getMinWavesPerEU();
3108}
3109
3110bool PreRARematStage::setObjective() {
3111 const Function &F = MF.getFunction();
3112
3113 // Set up "spilling targets" for all regions.
3114 unsigned MaxSGPRs = ST.getMaxNumSGPRs(F);
3115 unsigned MaxVGPRs = ST.getMaxNumVGPRs(F);
3116 bool HasVectorRegisterExcess = false;
3117 for (unsigned I = 0, E = DAG.Regions.size(); I != E; ++I) {
3118 const GCNRegPressure &RP = DAG.Pressure[I];
3119 GCNRPTarget &Target = RPTargets.emplace_back(MaxSGPRs, MaxVGPRs, MF, RP);
3120 if (!Target.satisfied())
3121 TargetRegions.set(I);
3122 HasVectorRegisterExcess |= Target.hasVectorRegisterExcess();
3123 }
3124
3125 if (HasVectorRegisterExcess || DAG.MinOccupancy >= MFI.getMaxWavesPerEU()) {
3126 // In addition to register usage being above addressable limits, occupancy
3127 // below the minimum is considered like "spilling" as well.
3128 TargetOcc = std::nullopt;
3129 } else {
3130 // There is no spilling and room to improve occupancy; set up "increased
3131 // occupancy targets" for all regions.
3132 TargetOcc = DAG.MinOccupancy + 1;
3133 const unsigned VGPRBlockSize = MFI.getDynamicVGPRBlockSize();
3134 MaxSGPRs = ST.getMaxNumSGPRs(*TargetOcc, false);
3135 MaxVGPRs = ST.getMaxNumVGPRs(*TargetOcc, VGPRBlockSize);
3136 for (auto [I, Target] : enumerate(RPTargets)) {
3137 Target.setTarget(MaxSGPRs, MaxVGPRs);
3138 if (!Target.satisfied())
3139 TargetRegions.set(I);
3140 }
3141 }
3142
3143 return TargetRegions.any();
3144}
3145
3146bool PreRARematStage::candidateHasValidUsers(
3147 RegisterIdx CandIdx, const SmallSet<Register, 4> &MarkedRegs) const {
3148 const Rematerializer::Reg &CandReg = Remater.getReg(CandIdx);
3149 SlotIndex RefIdx =
3150 DAG.LIS->getInstructionIndex(*CandReg.getLastDef()).getRegSlot(true);
3151
3152 for (const auto &[UseRegion, Users] : CandReg.Uses) {
3153 // Users cannot themselves be rematerializable.
3154 if (llvm::any_of(Users, [&](const MachineInstr *UserMI) {
3155 assert(UserMI->getNumOperands() > 0 &&
3156 "user must have at least one operand");
3157 // A user is rematerializable if its first register operand (its
3158 // register def) was marked already.
3159 const MachineOperand &DefMO = UserMI->getOperand(0);
3160 return DefMO.isReg() && MarkedRegs.contains(DefMO.getReg());
3161 }))
3162 return false;
3163
3164 MachineInstr *FirstUseMI =
3165 CandReg.getRegionUseBounds(UseRegion, *DAG.LIS).first;
3166 assert(FirstUseMI && "there must be a user in the region");
3167 SlotIndex FirstUseIdx =
3168 DAG.LIS->getInstructionIndex(*FirstUseMI).getRegSlot(true);
3169
3170 // All dependencies must be available at the first use in the region.
3171 if (llvm::any_of(CandReg.Dependencies, [&](RegisterIdx DepRegIdx) {
3172 const Rematerializer::Reg &DepReg = Remater.getReg(DepRegIdx);
3173 Register DepDefReg = DepReg.getDefReg();
3174 return !Remater.isRegIdenticalAtUses(DepDefReg, DepReg.Mask, RefIdx,
3175 {FirstUseIdx});
3176 }))
3177 return false;
3178 if (llvm::any_of(Remater.getUnrematableDeps(CandIdx),
3179 [&](const std::pair<Register, LaneBitmask> &RegAndMask) {
3180 const auto &[Reg, Mask] = RegAndMask;
3181 return !Remater.isRegIdenticalAtUses(Reg, Mask, RefIdx,
3182 {FirstUseIdx});
3183 }))
3184 return false;
3185 }
3186 return true;
3187}
3188
3189bool PreRARematStage::ScoredRemat::maybeBeneficial(
3190 const BitVector &TargetRegions, ArrayRef<GCNRPTarget> RPTargets) const {
3191 for (unsigned I : TargetRegions.set_bits()) {
3192 if (Live[I] && RPTargets[I].isSaveBeneficial(RPSave))
3193 return true;
3194 }
3195 return false;
3196}
3197
3201 MachineCycleInfo MCI;
3202 MCI.compute(MF);
3203 MachineBlockFrequencyInfo MBFI(MF, MBPI, MCI);
3204
3205 const unsigned NumRegions = DAG.Regions.size();
3207 MaxFreq = 0;
3208 Regions.reserve(NumRegions);
3209 for (unsigned I = 0; I < NumRegions; ++I) {
3210 MachineBasicBlock *MBB = DAG.Regions[I].first->getParent();
3211 uint64_t BlockFreq = MBFI.getBlockFreq(MBB).getFrequency();
3212 Regions.push_back(BlockFreq);
3213 if (BlockFreq && BlockFreq < MinFreq)
3214 MinFreq = BlockFreq;
3215 else if (BlockFreq > MaxFreq)
3216 MaxFreq = BlockFreq;
3217 }
3218 if (!MinFreq)
3219 return;
3220
3221 // Scale everything down if frequencies are high.
3222 if (MinFreq >= ScaleFactor * ScaleFactor) {
3223 for (uint64_t &Freq : Regions)
3224 Freq /= ScaleFactor;
3225 MinFreq /= ScaleFactor;
3226 MaxFreq /= ScaleFactor;
3227 }
3228}
3229
3230void PreRARematStage::ScoredRemat::init(const FreqInfo &Freq,
3231 const Rematerializer &Remater,
3233 const Rematerializer::Reg &Reg = Remater.getReg(RegIdx);
3234 Register DefReg = Reg.getDefReg();
3235
3236 Live |= LiveIn;
3237 Live |= LiveOut;
3238
3239 for (unsigned I : Live.set_bits()) {
3240 // If the register is both unused and live-through in the region, the
3241 // latter's RP is guaranteed to decrease.
3242 if (!LiveIn[I] || !LiveOut[I] || Reg.Uses.contains(I))
3243 UnpredictableRPSave.set(I);
3244 }
3245 RPSave.inc(DefReg, LaneBitmask::getNone(), Reg.Mask, DAG.MRI);
3246
3247 // Estimate the difference in instruction execution frequency that will be
3248 // induced by the rematerialization. A rematerialization from the least
3249 // frequent region to the most frequent region should yield the greatest
3250 // frequency penalty (most negative frequency difference). When the register
3251 // has users in its defining region the original instruction(s) won't be
3252 // deleted so there is no frequency gain in the defining region.
3253 int64_t DefOrMin = Reg.hasUsersInDefRegion()
3254 ? 0
3255 : std::max(Freq.Regions[Reg.DefRegion], Freq.MinFreq);
3256 int64_t UseOrMax = 0;
3257 for (const auto &[UseRegion, _] : Reg.Uses) {
3258 if (Reg.DefRegion == UseRegion)
3259 continue;
3260 uint64_t RegionFreq = Freq.Regions[UseRegion];
3261 UseOrMax += RegionFreq != 0 ? RegionFreq : Freq.MaxFreq;
3262 }
3263 FreqDiff = DefOrMin - UseOrMax;
3264}
3265
3266void PreRARematStage::ScoredRemat::update(const BitVector &TargetRegions,
3267 ArrayRef<GCNRPTarget> RPTargets,
3268 const FreqInfo &FreqInfo,
3269 bool ReduceSpill) {
3270 MaxFreq = 0;
3271 RegionImpact = 0;
3272 for (unsigned I : TargetRegions.set_bits()) {
3273 if (!Live[I])
3274 continue;
3275
3276 // The rematerialization must contribute positively in at least one
3277 // register class with usage above the RP target for this region to
3278 // contribute to the score.
3279 const GCNRPTarget &RegionTarget = RPTargets[I];
3280 const unsigned NumRegsBenefit = RegionTarget.getNumRegsBenefit(RPSave);
3281 if (!NumRegsBenefit)
3282 continue;
3283
3284 // Regions in which RP is guaranteed to decrease have more weight.
3285 RegionImpact += (UnpredictableRPSave[I] ? 1 : 2) * NumRegsBenefit;
3286
3287 if (ReduceSpill) {
3288 uint64_t Freq = FreqInfo.Regions[I];
3289 if (UnpredictableRPSave[I]) {
3290 // Apply a frequency penalty in regions in which we are not sure that RP
3291 // will decrease.
3292 Freq /= 2;
3293 }
3294 MaxFreq = std::max(MaxFreq, Freq);
3295 }
3296 }
3297}
3298
3299void PreRARematStage::ScoredRemat::rematerialize(
3300 Rematerializer &Remater) const {
3301 const Rematerializer::Reg &Reg = Remater.getReg(RegIdx);
3302
3303 // All rematerializable dependencies are re-used for all rematerializations.
3304 Rematerializer::DependencyReuseInfo DRI;
3305 for (RegisterIdx DepRegIdx : Reg.Dependencies)
3306 DRI.reuse(DepRegIdx);
3307
3308 // Rematerialize once per using region, except in the defining region.
3309 SmallVector<unsigned, 8> RematRegions;
3310 RematRegions.reserve(Reg.Uses.size());
3311 for (const auto &[UseRegion, _] : Reg.Uses) {
3312 if (Reg.DefRegion != UseRegion)
3313 RematRegions.push_back(UseRegion);
3314 }
3315 for (const unsigned UseRegion : RematRegions) {
3316 Rematerializer::DependencyReuseInfo RegionDRI(DRI);
3317 Remater.rematerializeToRegion(RegIdx, UseRegion, RegionDRI);
3318 }
3319}
3320
3321void PreRARematStage::updateRPTargets(const BitVector &Regions,
3322 const GCNRegPressure &RPSave) {
3323 for (unsigned I : Regions.set_bits()) {
3324 RPTargets[I].saveRP(RPSave);
3325 if (TargetRegions[I] && RPTargets[I].satisfied()) {
3326 REMAT_DEBUG(dbgs() << " [" << I << "] Target reached!\n");
3327 TargetRegions.reset(I);
3328 }
3329 }
3330}
3331
3332bool PreRARematStage::updateAndVerifyRPTargets(const BitVector &Regions) {
3333 bool TooOptimistic = false;
3334 for (unsigned I : Regions.set_bits()) {
3335 GCNRPTarget &Target = RPTargets[I];
3336 Target.setRP(DAG.getRealRegPressure(I));
3337
3338 // Since we were optimistic in assessing RP decreases in these regions, we
3339 // may need to remark the target as a target region if RP didn't decrease
3340 // as expected.
3341 if (!TargetRegions[I] && !Target.satisfied()) {
3342 REMAT_DEBUG(dbgs() << " [" << I << "] Incorrect RP estimation\n");
3343 TooOptimistic = true;
3344 TargetRegions.set(I);
3345 }
3346 }
3347 return TooOptimistic;
3348}
3349
3350void PreRARematStage::removeFromLiveMaps(Register Reg, const BitVector &LiveIn,
3351 const BitVector &LiveOut) {
3352 assert(LiveIn.size() == DAG.Regions.size() &&
3353 LiveOut.size() == DAG.Regions.size() && "region num mismatch");
3354 for (unsigned I : LiveIn.set_bits())
3355 DAG.LiveIns[I].erase(Reg);
3356 for (unsigned I : LiveOut.set_bits())
3357 DAG.RegionLiveOuts.getLiveRegsForRegionIdx(I).erase(Reg);
3358}
3359
3360void PreRARematStage::addToLiveMaps(Register Reg, LaneBitmask Mask,
3361 const BitVector &LiveIn,
3362 const BitVector &LiveOut) {
3363 assert(LiveIn.size() == DAG.Regions.size() &&
3364 LiveOut.size() == DAG.Regions.size() && "region num mismatch");
3365 std::pair<Register, LaneBitmask> LiveReg(Reg, Mask);
3366 for (unsigned I : LiveIn.set_bits())
3367 DAG.LiveIns[I].insert(LiveReg);
3368 for (unsigned I : LiveOut.set_bits())
3369 DAG.RegionLiveOuts.getLiveRegsForRegionIdx(I).insert(LiveReg);
3370}
3371
3373 // We consider that reducing spilling is always beneficial so we never
3374 // rollback rematerializations or revert scheduling in such cases.
3375 if (!TargetOcc)
3376 return;
3377
3378 // When increasing occupancy, it is possible that re-scheduling is not able to
3379 // achieve the target occupancy in all regions, in which case re-scheduling in
3380 // all regions should be reverted.
3381 if (DAG.MinOccupancy >= *TargetOcc)
3382 return;
3383
3384 // Revert re-scheduling in all affected regions.
3385 for (const auto &[RegionIdx, OrigMIOrder, MaxPressure] : RegionReverts) {
3386 REMAT_DEBUG(dbgs() << "Reverting re-scheduling in region " << RegionIdx
3387 << '\n');
3388 DAG.Pressure[RegionIdx] = MaxPressure;
3389 modifyRegionSchedule(RegionIdx, OrigMIOrder);
3390 }
3391
3392 // It is possible that re-scheduling lowers occupancy over the one achieved
3393 // just through rematerializations, in which case we revert re-scheduling in
3394 // all regions but do not roll back rematerializations.
3395 if (AchievedOcc >= *TargetOcc) {
3396 DAG.setTargetOccupancy(AchievedOcc);
3397 return;
3398 }
3399
3400 // Reset the target occupancy to what it was pre-rematerialization.
3401 DAG.setTargetOccupancy(*TargetOcc - 1);
3402
3403 // Roll back changes made by the stage, then recompute pressure in all
3404 // affected regions.
3405 REMAT_DEBUG(dbgs() << "==== ROLLBACK ====\n");
3406 assert(Rollback && "rollbacker should be defined");
3407 Rollback->Listener.rollback(Remater);
3408 for (const auto &[RegIdx, LiveIn, LiveOut] : Rollback->LiveMapUpdates) {
3409 const Rematerializer::Reg &Reg = Remater.getReg(RegIdx);
3410 addToLiveMaps(Reg.getDefReg(), Reg.Mask, LiveIn, LiveOut);
3411 }
3412
3413#ifdef EXPENSIVE_CHECKS
3414 // In particular, we want to check for coherent MI/slot order in regions in
3415 // which reverts and/or rollbacks may have happened.
3416 MF.verify();
3417#endif
3418 for (unsigned I : RescheduleRegions.set_bits())
3419 DAG.Pressure[I] = DAG.getRealRegPressure(I);
3420
3422}
3423
3424void GCNScheduleDAGMILive::setTargetOccupancy(unsigned TargetOccupancy) {
3425 MinOccupancy = TargetOccupancy;
3426 if (MFI.getOccupancy() < TargetOccupancy)
3427 MFI.increaseOccupancy(MF, MinOccupancy);
3428 else
3429 MFI.limitOccupancy(MinOccupancy);
3430}
3431
3433 const SIInstrInfo *SII = static_cast<const SIInstrInfo *>(DAG->TII);
3434 return any_of(*DAG, [SII](MachineBasicBlock::iterator MI) {
3435 return SII->isIGLPMutationOnly(MI->getOpcode());
3436 });
3437}
3438
3443
3445 HasIGLPInstrs = hasIGLPInstrs(this);
3446 if (HasIGLPInstrs) {
3447 SavedMutations.clear();
3448 SavedMutations.swap(Mutations);
3450 }
3451
3453}
3454
3456 if (HasIGLPInstrs)
3457 SavedMutations.swap(Mutations);
3458
3460}
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static SUnit * pickOnlyChoice(SchedBoundary &Zone)
uint64_t 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 MachineInstr * getLastMIForRegion(MachineBasicBlock::iterator RegionBegin, MachineBasicBlock::iterator RegionEnd)
static bool shouldCheckPending(SchedBoundary &Zone, const TargetSchedModel *SchedModel)
static cl::opt< bool > EnableLiveIntervalRPReschedule("amdgpu-lirp-reschedule", cl::Hidden, cl::desc("Enable live interval RP reschedule stage"), cl::init(true))
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 > LiveIntervalRPVGPRReduction("amdgpu-lirp-vgpr-reduction", cl::Hidden, cl::desc("Reduction factor (percent) for VGPR threshold during live interval RP " "reschedule stage"), cl::init(90))
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 > LiveIntervalRPInstantLowerBound("amdgpu-lirp-instant-lower-bound", cl::Hidden, cl::desc("Lower bound (percent of the VGPR excess limit) on instant RP, " "below which a region is skipped"), cl::init(10))
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 cl::opt< unsigned > LiveIntervalRPThreshold("amdgpu-lirp-threshold", cl::Hidden, cl::desc("Percent increase of live interval RP over instant pressure to " "trigger rescheduling"), cl::init(10))
static Register UseReg(const MachineOperand &MO)
const HexagonInstrInfo * TII
#define _
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.
#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)
MachineRegisterInfo & MRI
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
BitVector & reset()
Reset all bits in the bitvector.
Definition BitVector.h:409
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
bool contains(const_arg_type_t< KeyT > Val) const
Return true if the specified key is in the map, false otherwise.
Definition DenseMap.h:757
iterator find(const_arg_type_t< KeyT > Val)
Definition DenseMap.h:766
iterator end()
Definition DenseMap.h:686
bool erase(const KeyT &Val)
Definition DenseMap.h:930
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition DenseMap.h:827
Implements a dense probed hash-table based set.
Definition DenseSet.h:281
Common behavior for downward RP trackers. Unconstructible directly.
Downward RP tracker that relies on program order to advance down the instruction stream.
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
void reset(const MachineInstr &MI, bool After)
Resets tracker before or After the provided MI, which can be a debug instruction.
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.
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
void getRegisterPressures(bool AtTop, const RegPressureTracker &RPTracker, SUnit *SU, std::vector< unsigned > &Pressure, std::vector< unsigned > &MaxPressure, const GCNDownwardRPTrackerBase &DownwardTracker, const GCNUpwardRPTracker &UpwardTracker, ScheduleDAGMI *DAG, const SIRegisterInfo *SRI)
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)
GCNManualDownwardRPTracker DownwardTracker
GCNUpwardRPTracker & getUpwardTracker()
void initCandidate(SchedCandidate &Cand, SUnit *SU, bool AtTop, const RegPressureTracker &RPTracker, const SIRegisterInfo *SRI, unsigned SGPRPressure, unsigned VGPRPressure, unsigned AGPRPressure, bool IsBottomUp)
GCNDownwardRPTrackerBase & getDownwardTracker()
SUnit * pickNode(bool &IsTopNode) override
Pick the next node to schedule, or return NULL.
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
void resize(typename StorageT::size_type S)
Definition IndexedMap.h:67
A live range for subregisters.
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.
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.
static LLVM_ABI void restoreLivenessFlags(MachineInstr &MI, const TargetRegisterInfo &TRI, const MachineRegisterInfo &MRI, LiveIntervals &LIS, bool TrackLaneMasks=true, ArrayRef< Register > OnlyRegs={})
Clear potentially-stale read-undef flags on the defs of MI, then recompute them from LIS.
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
static constexpr bool isVirtualRegister(unsigned Reg)
Return true if the specified register number is in the virtual register namespace.
Definition Register.h:66
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 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.
LLVM_ABI bool checkHazard(SUnit *SU)
Does this SU have a hazard within the current instruction group.
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.
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 exitRegion() override
Called when the scheduler has finished scheduling the current region.
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:70
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 reserve(size_type N)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
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...
LLVM Value Representation.
Definition Value.h:75
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
#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)
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
@ Entry
Definition COFF.h:862
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:1781
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:2570
GCNRegPressure getRegPressure(const MachineRegisterInfo &MRI, Range &&LiveRegs)
std::unique_ptr< ScheduleDAGMutation > createIGroupLPDAGMutation(AMDGPU::SchedulingPhase Phase)
Phase specifes whether or not this is a reentry into the IGroupLPDAGMutation.
constexpr T alignDown(U Value, V Align, W Skew=0)
Returns the largest unsigned integer less than or equal to Value and is Skew mod Align.
Definition MathExtras.h:546
std::pair< MachineBasicBlock::iterator, MachineBasicBlock::iterator > RegionBoundaries
A region's boundaries i.e.
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:1762
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:408
void sort(IteratorTy Start, IteratorTy End)
Definition STLExtras.h:1652
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
cl::opt< unsigned, false, VGPRThresholdParser > VGPRThresholdPercentOpt
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
LLVM_ABI bool shouldVerifyScheduling()
Returns whether -verify-misched is set.
iterator_range< ConstMIBundleOperands > const_mi_bundle_ops(const MachineInstr &MI)
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:1933
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)
unsigned estimateGreedyVGPRPressure(MachineBasicBlock::const_iterator RegionBegin, MachineBasicBlock::const_iterator RegionEnd, const GCNRPTracker::LiveRegSet &LiveIns, const LiveIntervals &LIS, const MachineRegisterInfo &MRI, const SIRegisterInfo &TRI)
Estimate VGPR pressure using greedy, non-splitting register allocation simulation,...
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
static unsigned getUnifiedVGPRNum(unsigned NumArchVGPRs, unsigned NumAGPRs, unsigned NumAVGPRs)
Returns the aggregated VGPR pressure, assuming NumArchVGPRs ArchVGPRs NumAGPRs AGPRS,...
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
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.
bool hasUsersOutsideDefRegion() const
SmallDenseMap< unsigned, RegionUsers, 2 > Uses
Uses of the register, mapped by region.
MachineInstr * getLastDef() const
Register getDefReg() const
Returns the rematerializable register from one of its defining instructions.
SmallVector< RegisterIdx, 2 > Dependencies
This register's rematerializable dependencies, one per unique rematerializable register operand over ...
bool parse(cl::Option &O, StringRef ArgName, StringRef Arg, unsigned &Value)