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(static_cast<unsigned>(Regions.size()));
1220 RegionsWithExcessRP.resize(static_cast<unsigned>(Regions.size()));
1221 RegionsWithIGLPInstrs.resize(static_cast<unsigned>(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(static_cast<unsigned>(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 = static_cast<unsigned>(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] = static_cast<unsigned>(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<size_t> 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(static_cast<unsigned>(DAG.Regions.size()));
1649 for (;;) {
1650 RecomputeRP.reset();
1651
1652 // Sort candidates in increasing score order.
1653 sort(CandidateOrder, [&](size_t LHSIndex, size_t 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 (size_t 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 =
1840 static_cast<unsigned>(std::distance(DAG.begin(), DAG.end()));
1841 DAG.enterRegion(CurrentMBB, DAG.begin(), DAG.end(), NumRegionInstrs);
1842
1843 // Skip regions with 1 schedulable instruction.
1844 if (DAG.begin() == std::prev(DAG.end()))
1845 return false;
1846
1847 LLVM_DEBUG(dbgs() << "********** MI Scheduling **********\n");
1848 LLVM_DEBUG(dbgs() << MF.getName() << ":" << printMBBReference(*CurrentMBB)
1849 << " " << CurrentMBB->getName()
1850 << "\n From: " << *DAG.begin() << " To: ";
1851 if (DAG.RegionEnd != CurrentMBB->end()) dbgs() << *DAG.RegionEnd;
1852 else dbgs() << "End";
1853 dbgs() << " RegionInstrs: " << NumRegionInstrs << '\n');
1854
1855 // Save original instruction order before scheduling for possible revert.
1856 Unsched.clear();
1857 Unsched.reserve(DAG.NumRegionInstrs);
1860 const SIInstrInfo *SII = static_cast<const SIInstrInfo *>(DAG.TII);
1861 for (auto &I : DAG) {
1862 Unsched.push_back(&I);
1863 if (SII->isIGLPMutationOnly(I.getOpcode()))
1864 DAG.RegionsWithIGLPInstrs[RegionIdx] = true;
1865 }
1866 } else {
1867 for (auto &I : DAG)
1868 Unsched.push_back(&I);
1869 }
1870
1871 PressureBefore = DAG.Pressure[RegionIdx];
1872
1873 LLVM_DEBUG(
1874 dbgs() << "Pressure before scheduling:\nRegion live-ins:"
1875 << print(DAG.LiveIns[RegionIdx], DAG.MRI)
1876 << "Region live-in pressure: "
1877 << print(llvm::getRegPressure(DAG.MRI, DAG.LiveIns[RegionIdx]))
1878 << "Region register pressure: " << print(PressureBefore));
1879
1880 S.HasHighPressure = false;
1881 S.KnownExcessRP = isRegionWithExcessRP();
1882
1883 if (DAG.RegionsWithIGLPInstrs[RegionIdx] &&
1885 SavedMutations.clear();
1886 SavedMutations.swap(DAG.Mutations);
1887 bool IsInitialStage = StageID == GCNSchedStageID::OccInitialSchedule ||
1889 DAG.addMutation(createIGroupLPDAGMutation(
1890 IsInitialStage ? AMDGPU::SchedulingPhase::Initial
1892 }
1893
1894 return true;
1895}
1896
1898 // Only reschedule regions that have excess register pressure (i.e. spilling)
1899 // or had minimum occupancy at the beginning of the stage (as long as
1900 // rescheduling of previous regions did not make occupancy drop back down to
1901 // the initial minimum).
1902 unsigned DynamicVGPRBlockSize = DAG.MFI.getDynamicVGPRBlockSize();
1903 // If no region has been scheduled yet, the DAG has not yet been updated with
1904 // the occupancy target. So retrieve it from the temporary.
1905 unsigned CurrentTargetOccupancy =
1906 IsAnyRegionScheduled ? DAG.MinOccupancy : TempTargetOccupancy;
1907 if (!DAG.RegionsWithExcessRP[RegionIdx] &&
1908 (CurrentTargetOccupancy <= InitialOccupancy ||
1909 DAG.Pressure[RegionIdx].getOccupancy(ST, DynamicVGPRBlockSize) !=
1910 InitialOccupancy))
1911 return false;
1912
1913 bool IsSchedulingThisRegion = GCNSchedStage::initGCNRegion();
1914 // If this is the first region scheduled during this stage, make the target
1915 // occupancy changes in the DAG and MFI.
1916 if (!IsAnyRegionScheduled && IsSchedulingThisRegion) {
1917 IsAnyRegionScheduled = true;
1918 if (MFI.getMaxWavesPerEU() > DAG.MinOccupancy)
1919 DAG.setTargetOccupancy(TempTargetOccupancy);
1920 }
1921 return IsSchedulingThisRegion;
1922}
1923
1925 // We may need to reschedule this region if it wasn't rescheduled in the last
1926 // stage, or if we found it was testing critical register pressure limits in
1927 // the unclustered reschedule stage. The later is because we may not have been
1928 // able to raise the min occupancy in the previous stage so the region may be
1929 // overly constrained even if it was already rescheduled.
1930 if (!DAG.RegionsWithHighRP[RegionIdx])
1931 return false;
1932
1934}
1935
1937 return !RevertAllRegions && RescheduleRegions[RegionIdx] &&
1939}
1940
1942 if (CurrentMBB)
1943 DAG.finishBlock();
1944
1945 CurrentMBB = DAG.RegionBegin->getParent();
1946 DAG.startBlock(CurrentMBB);
1947 // Get real RP for the region if it hasn't be calculated before. After the
1948 // initial schedule stage real RP will be collected after scheduling.
1952 DAG.computeBlockPressure(RegionIdx, CurrentMBB);
1953}
1954
1956 DAG.Regions[RegionIdx] = std::pair(DAG.RegionBegin, DAG.RegionEnd);
1957 if (S.HasHighPressure)
1958 DAG.RegionsWithHighRP[RegionIdx] = true;
1959
1960 // Revert scheduling if we have dropped occupancy or there is some other
1961 // reason that the original schedule is better.
1963
1964 if (DAG.RegionsWithIGLPInstrs[RegionIdx] &&
1966 SavedMutations.swap(DAG.Mutations);
1967}
1968
1971 // When the goal is to increase occupancy, all regions must reach the target
1972 // occupancy for rematerializations to be possibly useful, otherwise we will
1973 // just hurt latency for no benefit. If minimum occupancy drops below the
1974 // target there is no point in trying to re-schedule further regions.
1975 if (!TargetOcc)
1976 return;
1977 RegionReverts.emplace_back(RegionIdx, Unsched, PressureBefore);
1978 if (DAG.MinOccupancy < *TargetOcc) {
1979 REMAT_DEBUG(dbgs() << "Region " << RegionIdx
1980 << " cannot meet occupancy target, interrupting "
1981 "re-scheduling in all regions\n");
1982 RevertAllRegions = true;
1983 }
1984}
1985
1987 // Check the results of scheduling.
1988 PressureAfter = DAG.getRealRegPressure(RegionIdx);
1989
1990 LLVM_DEBUG(dbgs() << "Pressure after scheduling: " << print(PressureAfter));
1991 LLVM_DEBUG(dbgs() << "Region: " << RegionIdx << ".\n");
1992
1993 unsigned DynamicVGPRBlockSize = DAG.MFI.getDynamicVGPRBlockSize();
1994
1995 bool UnifiedVGPRFile = ST.hasGFX90AInsts();
1996 unsigned VectorCriticalLimit =
1997 UnifiedVGPRFile ? S.UnifiedVGPRCriticalLimit : S.VGPRCriticalLimit;
1998 // Fitting the combined occupancy budget does not rule out spilling in one
1999 // bank. Keep the per-bank excess checks before taking this early exit.
2000 if (PressureAfter.getSGPRNum() <= S.SGPRCriticalLimit &&
2001 PressureAfter.getVGPRNum(UnifiedVGPRFile) <= VectorCriticalLimit &&
2002 (!UnifiedVGPRFile ||
2003 (PressureAfter.getArchVGPRNum() <= S.VGPRExcessLimit &&
2004 PressureAfter.getAGPRNum() <= S.AGPRExcessLimit))) {
2005 DAG.Pressure[RegionIdx] = PressureAfter;
2006
2007 // Early out if we have achieved the occupancy target.
2008 LLVM_DEBUG(dbgs() << "Pressure in desired limits, done.\n");
2009 return;
2010 }
2011
2012 unsigned TargetOccupancy = std::min(
2013 S.getTargetOccupancy(), ST.getOccupancyWithWorkGroupSizes(MF).second);
2014 unsigned WavesAfter = std::min(
2015 TargetOccupancy, PressureAfter.getOccupancy(ST, DynamicVGPRBlockSize));
2016 unsigned WavesBefore = std::min(
2017 TargetOccupancy, PressureBefore.getOccupancy(ST, DynamicVGPRBlockSize));
2018 LLVM_DEBUG(dbgs() << "Occupancy before scheduling: " << WavesBefore
2019 << ", after " << WavesAfter << ".\n");
2020
2021 // We may not be able to keep the current target occupancy because of the just
2022 // scheduled region. We might still be able to revert scheduling if the
2023 // occupancy before was higher, or if the current schedule has register
2024 // pressure higher than the excess limits which could lead to more spilling.
2025 unsigned NewOccupancy = std::max(WavesAfter, WavesBefore);
2026
2027 // Allow memory bound functions to drop to 4 waves if not limited by an
2028 // attribute.
2029 if (WavesAfter < WavesBefore && WavesAfter < DAG.MinOccupancy &&
2030 WavesAfter >= MFI.getMinAllowedOccupancy()) {
2031 LLVM_DEBUG(dbgs() << "Function is memory bound, allow occupancy drop up to "
2032 << MFI.getMinAllowedOccupancy() << " waves\n");
2033 NewOccupancy = WavesAfter;
2034 }
2035
2036 if (NewOccupancy < DAG.MinOccupancy) {
2037 DAG.MinOccupancy = NewOccupancy;
2038 MFI.limitOccupancy(DAG.MinOccupancy);
2039 LLVM_DEBUG(dbgs() << "Occupancy lowered for the function to "
2040 << DAG.MinOccupancy << ".\n");
2041 }
2042 // The maximum number of arch VGPR on non-unified register file, or the
2043 // maximum VGPR + AGPR in the unified register file case.
2044 unsigned MaxVGPRs = ST.getMaxNumVGPRs(MF);
2045 // The maximum number of arch VGPR for both unified and non-unified register
2046 // file.
2047 unsigned MaxArchVGPRs = std::min(MaxVGPRs, ST.getAddressableNumArchVGPRs());
2048 unsigned MaxSGPRs = ST.getMaxNumSGPRs(MF);
2049
2050 if (PressureAfter.getVGPRNum(ST.hasGFX90AInsts()) > MaxVGPRs ||
2051 PressureAfter.getArchVGPRNum() > MaxArchVGPRs ||
2052 PressureAfter.getAGPRNum() > MaxArchVGPRs ||
2053 PressureAfter.getSGPRNum() > MaxSGPRs) {
2054 DAG.RegionsWithHighRP[RegionIdx] = true;
2055 DAG.RegionsWithExcessRP[RegionIdx] = true;
2056 }
2057
2058 // Revert if this region's schedule would cause a drop in occupancy or
2059 // spilling.
2060 if (shouldRevertScheduling(WavesAfter)) {
2062 std::tie(DAG.RegionBegin, DAG.RegionEnd) = DAG.Regions[RegionIdx];
2063 } else {
2064 DAG.Pressure[RegionIdx] = PressureAfter;
2065 }
2066}
2067
2068unsigned
2069GCNSchedStage::computeSUnitReadyCycle(const SUnit &SU, unsigned CurrCycle,
2070 DenseMap<unsigned, unsigned> &ReadyCycles,
2071 const TargetSchedModel &SM) {
2072 unsigned ReadyCycle = CurrCycle;
2073 for (auto &D : SU.Preds) {
2074 if (D.isAssignedRegDep()) {
2075 MachineInstr *DefMI = D.getSUnit()->getInstr();
2076 unsigned Latency = SM.computeInstrLatency(DefMI);
2077 unsigned DefReady = ReadyCycles[DAG.getSUnit(DefMI)->NodeNum];
2078 ReadyCycle = std::max(ReadyCycle, DefReady + Latency);
2079 }
2080 }
2081 ReadyCycles[SU.NodeNum] = ReadyCycle;
2082 return ReadyCycle;
2083}
2084
2085#ifndef NDEBUG
2087 bool operator()(std::pair<MachineInstr *, unsigned> A,
2088 std::pair<MachineInstr *, unsigned> B) const {
2089 return A.second < B.second;
2090 }
2091};
2092
2093static void printScheduleModel(std::set<std::pair<MachineInstr *, unsigned>,
2094 EarlierIssuingCycle> &ReadyCycles) {
2095 if (ReadyCycles.empty())
2096 return;
2097 unsigned BBNum = ReadyCycles.begin()->first->getParent()->getNumber();
2098 dbgs() << "\n################## Schedule time ReadyCycles for MBB : " << BBNum
2099 << " ##################\n# Cycle #\t\t\tInstruction "
2100 " "
2101 " \n";
2102 unsigned IPrev = 1;
2103 for (auto &I : ReadyCycles) {
2104 if (I.second > IPrev + 1)
2105 dbgs() << "****************************** BUBBLE OF " << I.second - IPrev
2106 << " CYCLES DETECTED ******************************\n\n";
2107 dbgs() << "[ " << I.second << " ] : " << *I.first << "\n";
2108 IPrev = I.second;
2109 }
2110}
2111#endif
2112
2113ScheduleMetrics
2114GCNSchedStage::getScheduleMetrics(const std::vector<SUnit> &InputSchedule) {
2115#ifndef NDEBUG
2116 std::set<std::pair<MachineInstr *, unsigned>, EarlierIssuingCycle>
2117 ReadyCyclesSorted;
2118#endif
2119 const TargetSchedModel &SM = ST.getInstrInfo()->getSchedModel();
2120 unsigned SumBubbles = 0;
2121 DenseMap<unsigned, unsigned> ReadyCycles;
2122 unsigned CurrCycle = 0;
2123 for (auto &SU : InputSchedule) {
2124 unsigned ReadyCycle =
2125 computeSUnitReadyCycle(SU, CurrCycle, ReadyCycles, SM);
2126 SumBubbles += ReadyCycle - CurrCycle;
2127#ifndef NDEBUG
2128 ReadyCyclesSorted.insert(std::make_pair(SU.getInstr(), ReadyCycle));
2129#endif
2130 CurrCycle = ++ReadyCycle;
2131 }
2132#ifndef NDEBUG
2133 LLVM_DEBUG(
2134 printScheduleModel(ReadyCyclesSorted);
2135 dbgs() << "\n\t"
2136 << "Metric: "
2137 << (SumBubbles
2138 ? (SumBubbles * ScheduleMetrics::ScaleFactor) / CurrCycle
2139 : 1)
2140 << "\n\n");
2141#endif
2142
2143 return ScheduleMetrics(CurrCycle, SumBubbles);
2144}
2145
2148#ifndef NDEBUG
2149 std::set<std::pair<MachineInstr *, unsigned>, EarlierIssuingCycle>
2150 ReadyCyclesSorted;
2151#endif
2152 const TargetSchedModel &SM = ST.getInstrInfo()->getSchedModel();
2153 unsigned SumBubbles = 0;
2154 DenseMap<unsigned, unsigned> ReadyCycles;
2155 unsigned CurrCycle = 0;
2156 for (auto &MI : DAG) {
2157 SUnit *SU = DAG.getSUnit(&MI);
2158 if (!SU)
2159 continue;
2160 unsigned ReadyCycle =
2161 computeSUnitReadyCycle(*SU, CurrCycle, ReadyCycles, SM);
2162 SumBubbles += ReadyCycle - CurrCycle;
2163#ifndef NDEBUG
2164 ReadyCyclesSorted.insert(std::make_pair(SU->getInstr(), ReadyCycle));
2165#endif
2166 CurrCycle = ++ReadyCycle;
2167 }
2168#ifndef NDEBUG
2169 LLVM_DEBUG(
2170 printScheduleModel(ReadyCyclesSorted);
2171 dbgs() << "\n\t"
2172 << "Metric: "
2173 << (SumBubbles
2174 ? (SumBubbles * ScheduleMetrics::ScaleFactor) / CurrCycle
2175 : 1)
2176 << "\n\n");
2177#endif
2178
2179 return ScheduleMetrics(CurrCycle, SumBubbles);
2180}
2181
2182bool GCNSchedStage::shouldRevertScheduling(unsigned WavesAfter) {
2183 if (WavesAfter < DAG.MinOccupancy)
2184 return true;
2185
2186 // For dynamic VGPR mode, we don't want to waste any VGPR blocks.
2187 if (DAG.MFI.isDynamicVGPREnabled()) {
2188 unsigned BlocksBefore = AMDGPU::IsaInfo::getAllocatedNumVGPRBlocks(
2189 ST, PressureBefore.getVGPRNum(false),
2190 DAG.MFI.getDynamicVGPRBlockSize());
2191 unsigned BlocksAfter = AMDGPU::IsaInfo::getAllocatedNumVGPRBlocks(
2192 ST, PressureAfter.getVGPRNum(false), DAG.MFI.getDynamicVGPRBlockSize());
2193 if (BlocksAfter > BlocksBefore)
2194 return true;
2195 }
2196
2197 return false;
2198}
2199
2202 return false;
2203
2205 return true;
2206
2207 if (mayCauseSpilling(WavesAfter))
2208 return true;
2209
2210 return false;
2211}
2212
2214 // If RP is not reduced in the unclustered reschedule stage, revert to the
2215 // old schedule.
2216 if ((WavesAfter <=
2217 PressureBefore.getOccupancy(ST, DAG.MFI.getDynamicVGPRBlockSize()) &&
2218 mayCauseSpilling(WavesAfter)) ||
2220 LLVM_DEBUG(dbgs() << "Unclustered reschedule did not help.\n");
2221 return true;
2222 }
2223
2224 // Do not attempt to relax schedule even more if we are already spilling.
2226 return false;
2227
2228 LLVM_DEBUG(
2229 dbgs()
2230 << "\n\t *** In shouldRevertScheduling ***\n"
2231 << " *********** BEFORE UnclusteredHighRPStage ***********\n");
2232 ScheduleMetrics MBefore = getScheduleMetrics(DAG.SUnits);
2233 LLVM_DEBUG(
2234 dbgs()
2235 << "\n *********** AFTER UnclusteredHighRPStage ***********\n");
2237 unsigned OldMetric = MBefore.getMetric();
2238 unsigned NewMetric = MAfter.getMetric();
2239 unsigned WavesBefore = std::min(
2240 S.getTargetOccupancy(),
2241 PressureBefore.getOccupancy(ST, DAG.MFI.getDynamicVGPRBlockSize()));
2242 unsigned Profit =
2243 ((WavesAfter * ScheduleMetrics::ScaleFactor) / WavesBefore *
2245 NewMetric) /
2247 LLVM_DEBUG(dbgs() << "\tMetric before " << MBefore << "\tMetric after "
2248 << MAfter << "Profit: " << Profit << "\n");
2249 return Profit < ScheduleMetrics::ScaleFactor;
2250}
2251
2254 return false;
2255
2257 return true;
2258
2259 if (mayCauseSpilling(WavesAfter))
2260 return true;
2261
2262 return false;
2263}
2264
2266 return GCNSchedStage::shouldRevertScheduling(WavesAfter) ||
2267 mayCauseSpilling(WavesAfter);
2268}
2269
2271 if (mayCauseSpilling(WavesAfter))
2272 return true;
2273
2274 return false;
2275}
2276
2278 unsigned WavesAfter) {
2279 return mayCauseSpilling(WavesAfter);
2280}
2281
2283 "amdgpu-lirp-reschedule", cl::Hidden,
2284 cl::desc("Enable live interval RP reschedule stage"), cl::init(true));
2285
2287 "amdgpu-lirp-threshold", cl::Hidden,
2288 cl::desc("Percent increase of live interval RP over instant pressure to "
2289 "trigger rescheduling"),
2290 cl::init(10));
2291
2293 "amdgpu-lirp-vgpr-reduction", cl::Hidden,
2294 cl::desc(
2295 "Reduction factor (percent) for VGPR threshold during live interval RP "
2296 "reschedule stage"),
2297 cl::init(90));
2298
2300 "amdgpu-lirp-instant-lower-bound", cl::Hidden,
2301 cl::desc("Lower bound (percent of the VGPR excess limit) on instant RP, "
2302 "below which a region is skipped"),
2303 cl::init(10));
2304
2307 return false;
2308
2310 return false;
2311
2312 if (!S.VGPRThresholdPercent) {
2313 LLVM_DEBUG(dbgs() << "LIRP: expected VGPRThresholdPercent to be enabled, "
2314 "not using live interval RP reschedule stage\n");
2315 return false;
2316 }
2317
2318 return true;
2319}
2320
2322 unsigned InstantRP = DAG.Pressure[RegionIdx].getArchVGPRNum();
2323 auto [RegionBegin, RegionEnd] = DAG.Regions[RegionIdx];
2324 if (RegionBegin == RegionEnd)
2325 return false;
2326
2327 unsigned LIRP = estimateGreedyVGPRPressure(
2328 RegionBegin, RegionEnd, DAG.LiveIns[RegionIdx], *DAG.getLIS(),
2329 DAG.MF.getRegInfo(), static_cast<const SIRegisterInfo &>(*DAG.TRI));
2330
2331 unsigned NewVGPRThresholdPercent =
2332 (S.VGPRThresholdPercent * LiveIntervalRPVGPRReduction + 99) / 100;
2333
2334 LLVM_DEBUG(dbgs() << "LIRP: Region " << RegionIdx
2335 << ", VGPRThresholdPercent: " << S.VGPRThresholdPercent
2336 << " -> " << NewVGPRThresholdPercent
2337 << ", VGPRExcessLimit=" << S.VGPRExcessLimit
2338 << ", VGPRCriticalLimit=" << S.VGPRCriticalLimit
2339 << ", InstantRP=" << InstantRP << ", LIRP=" << LIRP);
2340
2341 bool DoRescheduling = false;
2342 // Lower bound on InstantRP to skip over tiny regions.
2343 unsigned InstantRPLowerBound =
2344 S.VGPRExcessLimit * LiveIntervalRPInstantLowerBound / 100;
2345 if (LIRP > S.VGPRExcessLimit) {
2346 LLVM_DEBUG(dbgs() << " [LIRP exceeds the limit (" << S.VGPRExcessLimit
2347 << "), rescheduling]");
2348 DoRescheduling = true;
2349 } else if (LIRP > InstantRP && InstantRP > InstantRPLowerBound) {
2350 unsigned IncreasePercent = ((LIRP - InstantRP) * 100) / InstantRP;
2351 if (IncreasePercent > LiveIntervalRPThreshold) {
2352 LLVM_DEBUG(dbgs() << " [" << IncreasePercent << "% > "
2353 << LiveIntervalRPThreshold << "%, rescheduling]");
2354 DoRescheduling = true;
2355 }
2356 }
2357 LLVM_DEBUG(dbgs() << '\n');
2358
2359 if (DoRescheduling && GCNSchedStage::initGCNRegion()) {
2360 SavedVGPRExcessLimit = S.VGPRExcessLimit;
2361 SavedVGPRCriticalLimit = S.VGPRCriticalLimit;
2362 SavedUnifiedVGPRCriticalLimit = S.UnifiedVGPRCriticalLimit;
2363 SavedVGPRThresholdPercent = S.VGPRThresholdPercent;
2364 S.VGPRThresholdPercent = NewVGPRThresholdPercent;
2365 return true;
2366 }
2367
2368 return false;
2369}
2370
2372 S.VGPRExcessLimit = SavedVGPRExcessLimit;
2373 S.VGPRCriticalLimit = SavedVGPRCriticalLimit;
2374 S.UnifiedVGPRCriticalLimit = SavedUnifiedVGPRCriticalLimit;
2375 S.VGPRThresholdPercent = SavedVGPRThresholdPercent;
2377}
2378
2379bool GCNSchedStage::mayCauseSpilling(unsigned WavesAfter) {
2380 if (WavesAfter <= MFI.getMinWavesPerEU() && isRegionWithExcessRP() &&
2382 LLVM_DEBUG(dbgs() << "New pressure will result in more spilling.\n");
2383 return true;
2384 }
2385
2386 return false;
2387}
2388
2390 ArrayRef<MachineInstr *> MIOrder) {
2391 assert(static_cast<size_t>(std::distance(DAG.Regions[RegionIdx].first,
2392 DAG.Regions[RegionIdx].second)) ==
2393 MIOrder.size() &&
2394 "instruction number mismatch");
2395 if (MIOrder.empty())
2396 return;
2397
2398 LLVM_DEBUG(dbgs() << "Reverting scheduling for region " << RegionIdx << '\n');
2399
2400 // Reconstruct MI sequence by moving instructions in desired order before
2401 // the current region's start.
2402 MachineBasicBlock::iterator RegionEnd = DAG.Regions[RegionIdx].first;
2403 MachineBasicBlock *MBB = MIOrder.front()->getParent();
2404 for (MachineInstr *MI : MIOrder) {
2405 // Either move the next MI in order before the end of the region or move the
2406 // region end past the MI if it is at the correct position.
2407 MachineBasicBlock::iterator MII = MI->getIterator();
2408 if (MII != RegionEnd) {
2409 // Will subsequent splice move MI up past a non-debug instruction?
2410 bool NonDebugReordered =
2411 !MI->isDebugInstr() &&
2412 skipDebugInstructionsForward(RegionEnd, MII) != MII;
2413 MBB->splice(RegionEnd, MBB, MI);
2414 // Only update LiveIntervals information if non-debug instructions are
2415 // reordered. Otherwise debug instructions could cause code generation to
2416 // change.
2417 if (NonDebugReordered)
2418 DAG.LIS->handleMove(*MI, true);
2419 } else {
2420 // MI is already at the expected position. However, earlier splices in
2421 // this loop may have changed neighboring slot indices, so this MI's
2422 // slot index can become non-monotonic w.r.t. the physical MBB order.
2423 // Only re-seat when monotonicity is actually violated to avoid
2424 // unnecessary LiveInterval changes that could perturb scheduling.
2425 if (!MI->isDebugInstr()) {
2426 SlotIndex MIIdx = DAG.LIS->getInstructionIndex(*MI);
2427 SlotIndex PrevIdx = DAG.LIS->getSlotIndexes()->getIndexBefore(*MI);
2428 if (PrevIdx >= MIIdx)
2429 DAG.LIS->handleMove(*MI, true);
2430 }
2431 ++RegionEnd;
2432 }
2433 if (MI->isDebugInstr()) {
2434 LLVM_DEBUG(dbgs() << "Scheduling " << *MI);
2435 continue;
2436 }
2437
2438 // Reset read-undef flags and update them later.
2440 DAG.ShouldTrackLaneMasks);
2441 LLVM_DEBUG(dbgs() << "Scheduling " << *MI);
2442 }
2443
2444 // The region end doesn't change throughout scheduling since it itself is
2445 // outside the region (whether that is a MBB end or a terminator MI).
2446 assert(RegionEnd == DAG.Regions[RegionIdx].second && "region end mismatch");
2447 DAG.Regions[RegionIdx].first = MIOrder.front();
2448}
2449
2450/// Returns true if reaching def \p RD will be in AGPR form after the rewrite
2451/// and so needs no bridge copy: a candidate MFMA in \p RewriteSet, an
2452/// AV_MOV_*_IMM_PSEUDO, or a copy from a candidate src2 reg in \p CandSrc2Regs.
2453/// A non-candidate MFMA stays in VGPR form and still needs a bridge.
2455 MachineInstr *RD, const SmallPtrSetImpl<MachineInstr *> &RewriteSet,
2456 const DenseSet<Register> &CandSrc2Regs, const SIInstrInfo &TII) {
2457 if (TII.isMAI(*RD))
2458 return RewriteSet.contains(RD);
2459 if (RD->getOpcode() == AMDGPU::AV_MOV_B32_IMM_PSEUDO ||
2460 RD->getOpcode() == AMDGPU::AV_MOV_B64_IMM_PSEUDO)
2461 return true;
2462 if (RD->isCopy() && CandSrc2Regs.contains(RD->getOperand(1).getReg()))
2463 return true;
2464 return false;
2465}
2466
2467bool RewriteMFMAFormStage::hasUseRequiringVGPR(
2468 ArrayRef<SlotIndex> Src2ReachingDefs,
2469 const SmallPtrSetImpl<MachineInstr *> &RewriteSet) {
2470 for (SlotIndex RDIdx : Src2ReachingDefs) {
2471 const MachineInstr *RD = DAG.LIS->getInstructionFromIndex(RDIdx);
2473 findReachingUses(RD, DAG.LIS, ReachingUses);
2474 for (const MachineOperand *UseMO : ReachingUses) {
2475 const MachineInstr *UseMI = UseMO->getParent();
2476 if (UseMI->isCopy())
2477 continue;
2478 if (TII->isMAI(*UseMI) && RewriteSet.contains(UseMI))
2479 continue;
2480 return true;
2481 }
2482 }
2483 return false;
2484}
2485
2486void RewriteMFMAFormStage::resetRewriteCandsToVGPR(
2487 ArrayRef<std::pair<MachineInstr *, unsigned>> RewriteCands) {
2488 for (auto [MI, OriginalOpcode] : RewriteCands) {
2489 assert(TII->isMAI(*MI));
2490 const TargetRegisterClass *ADefRC =
2491 DAG.MRI.getRegClass(MI->getOperand(0).getReg());
2492 const TargetRegisterClass *VDefRC = SRI->getEquivalentVGPRClass(ADefRC);
2493 DAG.MRI.setRegClass(MI->getOperand(0).getReg(), VDefRC);
2494 MI->setDesc(TII->get(OriginalOpcode));
2495
2496 MachineOperand *Src2 = TII->getNamedOperand(*MI, AMDGPU::OpName::src2);
2497 if (!Src2->isReg())
2498 continue;
2499
2500 // Have to get src types separately since subregs may cause C and D
2501 // registers to be different types even though the actual operand is
2502 // the same size.
2503 const TargetRegisterClass *AUseRC = DAG.MRI.getRegClass(Src2->getReg());
2504 const TargetRegisterClass *VUseRC = SRI->getEquivalentVGPRClass(AUseRC);
2505 DAG.MRI.setRegClass(Src2->getReg(), VUseRC);
2506 }
2507}
2508
2509bool RewriteMFMAFormStage::isRewriteCandidate(MachineInstr *MI) const {
2510 if (!static_cast<const SIInstrInfo *>(DAG.TII)->isMAI(*MI))
2511 return false;
2512 if (AMDGPU::getAGPRFormOp(MI->getOpcode()) == -1)
2513 return false;
2514 // Reject candidates whose users force an unavoidable bridge copy.
2515 Register DstReg = MI->getOperand(0).getReg();
2516 for (const MachineInstr &UseMI : DAG.MRI.use_nodbg_instructions(DstReg)) {
2517 if (!TII->isMAI(UseMI) && !UseMI.isCopy())
2518 return false;
2519 }
2520 return true;
2521}
2522
2523bool RewriteMFMAFormStage::initHeuristics(
2524 std::vector<std::pair<MachineInstr *, unsigned>> &RewriteCands,
2525 DenseMap<MachineBasicBlock *, std::set<Register>> &CopyForUse,
2526 SmallPtrSetImpl<MachineInstr *> &CopyForDef) {
2527 bool Changed = false;
2528
2529 // Collect the candidate group, its members share AGPR-form operands
2530 // post-rewrite, so reaching defs feeding any member don't need bridge copy.
2531 SmallPtrSet<MachineInstr *, 16> RewriteSet;
2532 DenseSet<Register> CandSrc2Regs;
2533 for (MachineBasicBlock &MBB : MF) {
2534 for (MachineInstr &MI : MBB) {
2535 if (!isRewriteCandidate(&MI))
2536 continue;
2537 RewriteSet.insert(&MI);
2538 MachineOperand *Src2 = TII->getNamedOperand(MI, AMDGPU::OpName::src2);
2539 if (Src2 && Src2->isReg())
2540 CandSrc2Regs.insert(Src2->getReg());
2541 }
2542 }
2543
2544 // Prepare for the heuristics
2545 for (MachineBasicBlock &MBB : MF) {
2546 for (MachineInstr &MI : MBB) {
2547 if (!isRewriteCandidate(&MI))
2548 continue;
2549
2550 int ReplacementOp = AMDGPU::getAGPRFormOp(MI.getOpcode());
2551 assert(ReplacementOp != -1);
2552
2553 RewriteCands.push_back({&MI, MI.getOpcode()});
2554 MI.setDesc(TII->get(ReplacementOp));
2555
2556 MachineOperand *Src2 = TII->getNamedOperand(MI, AMDGPU::OpName::src2);
2557 if (Src2->isReg()) {
2558 SmallVector<SlotIndex, 8> Src2ReachingDefs;
2559 findReachingDefs(*Src2, DAG.LIS, Src2ReachingDefs);
2560
2561 // If src2 has a use that must remain VGPR, it cannot be reclassified to
2562 // AGPR.
2563 bool Src2NeedsVGPR = hasUseRequiringVGPR(Src2ReachingDefs, RewriteSet);
2564 Src2NeedsVGPRCache[&MI] = Src2NeedsVGPR;
2565
2566 for (SlotIndex RDIdx : Src2ReachingDefs) {
2567 MachineInstr *RD = DAG.LIS->getInstructionFromIndex(RDIdx);
2568 if (!Src2NeedsVGPR &&
2569 isReachingDefAGPRForm(RD, RewriteSet, CandSrc2Regs, *TII))
2570 continue;
2571 CopyForDef.insert(RD);
2572 }
2573 }
2574
2575 MachineOperand &Dst = MI.getOperand(0);
2576 SmallVector<MachineOperand *, 8> DstReachingUses;
2577
2578 findReachingUses(&MI, DAG.LIS, DstReachingUses);
2579
2580 for (MachineOperand *RUOp : DstReachingUses) {
2581 MachineInstr *UserMI = RUOp->getParent();
2582 // Group members read the AGPR result directly.
2583 if (TII->isMAI(*UserMI) && RewriteSet.contains(UserMI))
2584 continue;
2585
2586 // For any user of the result of the MFMA which is not an MFMA, we
2587 // insert a copy. For a given register, we will only insert one copy
2588 // per user block.
2589 CopyForUse[UserMI->getParent()].insert(RUOp->getReg());
2590
2591 if (TII->isMAI(*UserMI))
2592 continue;
2593
2594 SmallVector<SlotIndex, 8> DstUsesReachingDefs;
2595 findReachingDefs(*RUOp, DAG.LIS, DstUsesReachingDefs);
2596
2597 for (SlotIndex RDIndex : DstUsesReachingDefs) {
2598 MachineInstr *RD = DAG.LIS->getInstructionFromIndex(RDIndex);
2599 if (TII->isMAI(*RD))
2600 continue;
2601
2602 // For any definition of the user of the MFMA which is not an MFMA,
2603 // we insert a copy. We do this to transform all the reaching defs
2604 // of this use to AGPR. By doing this, we can insert a copy from
2605 // AGPR to VGPR at the user rather than after the MFMA.
2606 CopyForDef.insert(RD);
2607 }
2608 }
2609
2610 // Do the rewrite to allow for updated RP calculation.
2611 const TargetRegisterClass *VDefRC = DAG.MRI.getRegClass(Dst.getReg());
2612 const TargetRegisterClass *ADefRC = SRI->getEquivalentAGPRClass(VDefRC);
2613 DAG.MRI.setRegClass(Dst.getReg(), ADefRC);
2614 if (Src2->isReg()) {
2615 // Have to get src types separately since subregs may cause C and D
2616 // registers to be different types even though the actual operand is
2617 // the same size.
2618 const TargetRegisterClass *VUseRC = DAG.MRI.getRegClass(Src2->getReg());
2619 const TargetRegisterClass *AUseRC = SRI->getEquivalentAGPRClass(VUseRC);
2620 DAG.MRI.setRegClass(Src2->getReg(), AUseRC);
2621 }
2622 Changed = true;
2623 }
2624 }
2625
2626 return Changed;
2627}
2628
2629int64_t RewriteMFMAFormStage::getRewriteCost(
2630 ArrayRef<std::pair<MachineInstr *, unsigned>> RewriteCands,
2631 const DenseMap<MachineBasicBlock *, std::set<Register>> &CopyForUse,
2632 const SmallPtrSetImpl<MachineInstr *> &CopyForDef) {
2633 MachineBlockFrequencyInfo *MBFI = DAG.MBFI;
2634
2635 int64_t BestSpillCost = 0;
2636 int64_t Cost = 0;
2637 uint64_t EntryFreq = MBFI->getEntryFreq().getFrequency();
2638
2639 std::pair<unsigned, unsigned> MaxVectorRegs =
2640 ST.getMaxNumVectorRegs(MF.getFunction());
2641 unsigned ArchVGPRThreshold = MaxVectorRegs.first;
2642 unsigned AGPRThreshold = MaxVectorRegs.second;
2643 unsigned CombinedThreshold = ST.getMaxNumVGPRs(MF);
2644
2645 for (unsigned Region = 0; Region < DAG.Regions.size(); Region++) {
2646 if (!RegionsWithExcessArchVGPR[Region])
2647 continue;
2648
2649 GCNRegPressure &PressureBefore = DAG.Pressure[Region];
2650 unsigned SpillCostBefore = PressureBefore.getVGPRSpills(
2651 MF, ArchVGPRThreshold, AGPRThreshold, CombinedThreshold);
2652
2653 // For the cases we care about (i.e. ArchVGPR usage is greater than the
2654 // addressable limit), rewriting alone should bring pressure to manageable
2655 // level. If we find any such region, then the rewrite is potentially
2656 // beneficial.
2657 GCNRegPressure PressureAfter = DAG.getRealRegPressure(Region);
2658 unsigned SpillCostAfter = PressureAfter.getVGPRSpills(
2659 MF, ArchVGPRThreshold, AGPRThreshold, CombinedThreshold);
2660
2661 uint64_t BlockFreq =
2662 MBFI->getBlockFreq(DAG.Regions[Region].first->getParent())
2663 .getFrequency();
2664
2665 bool RelativeFreqIsDenom = EntryFreq > BlockFreq;
2666 uint64_t RelativeFreq = EntryFreq && BlockFreq
2667 ? (RelativeFreqIsDenom ? EntryFreq / BlockFreq
2668 : BlockFreq / EntryFreq)
2669 : 1;
2670
2671 // This assumes perfect spilling / splitting -- using one spill / copy
2672 // instruction and one restoreFrom / copy for each excess register,
2673 int64_t SpillCost = ((int)SpillCostAfter - (int)SpillCostBefore) * 2;
2674
2675 // Also account for the block frequency.
2676 if (RelativeFreqIsDenom)
2677 SpillCost /= (int64_t)RelativeFreq;
2678 else
2679 SpillCost *= (int64_t)RelativeFreq;
2680
2681 // If we have increased spilling in any block, just bail.
2682 if (SpillCost > 0) {
2683 resetRewriteCandsToVGPR(RewriteCands);
2684 return SpillCost;
2685 }
2686
2687 if (SpillCost < BestSpillCost)
2688 BestSpillCost = SpillCost;
2689 }
2690
2691 // Set the cost to the largest decrease in spill cost in order to not double
2692 // count spill reductions.
2693 Cost = BestSpillCost;
2694 assert(Cost <= 0);
2695
2696 unsigned CopyCost = 0;
2697
2698 // For each CopyForDef, increase the cost by the register size while
2699 // accounting for block frequency.
2700 for (MachineInstr *DefMI : CopyForDef) {
2701 Register DefReg = DefMI->getOperand(0).getReg();
2702 uint64_t DefFreq =
2703 EntryFreq
2704 ? MBFI->getBlockFreq(DefMI->getParent()).getFrequency() / EntryFreq
2705 : 1;
2706
2707 const TargetRegisterClass *RC = DAG.MRI.getRegClass(DefReg);
2708 CopyCost += static_cast<unsigned>(RC->getCopyCost() * DefFreq);
2709 }
2710
2711 // Account for CopyForUse copies in each block that the register is used.
2712 for (auto &[UseBlock, UseRegs] : CopyForUse) {
2713 uint64_t UseFreq =
2714 EntryFreq ? MBFI->getBlockFreq(UseBlock).getFrequency() / EntryFreq : 1;
2715
2716 for (Register UseReg : UseRegs) {
2717 const TargetRegisterClass *RC = DAG.MRI.getRegClass(UseReg);
2718 CopyCost += static_cast<unsigned>(RC->getCopyCost() * UseFreq);
2719 }
2720 }
2721
2722 // Reset the classes that were changed to AGPR for better register bank
2723 // analysis. We must do rewriting after copy-insertion, as some defs of the
2724 // register may require VGPR. Additionally, if we bail out and don't perform
2725 // the rewrite then these need to be restored anyway.
2726 resetRewriteCandsToVGPR(RewriteCands);
2727
2728 return Cost + CopyCost;
2729}
2730
2731bool RewriteMFMAFormStage::rewrite(
2732 ArrayRef<std::pair<MachineInstr *, unsigned>> RewriteCands) {
2733 DenseMap<MachineInstr *, unsigned> FirstMIToRegion;
2734 DenseMap<MachineInstr *, unsigned> LastMIToRegion;
2735
2736 for (unsigned Region = 0; Region < DAG.Regions.size(); Region++) {
2737 RegionBoundaries Entry = DAG.Regions[Region];
2738 if (Entry.first == Entry.second)
2739 continue;
2740
2741 FirstMIToRegion[&*Entry.first] = Region;
2742 if (Entry.second != Entry.first->getParent()->end())
2743 LastMIToRegion[&*Entry.second] = Region;
2744 }
2745
2746 // Rewrite the MFMAs to AGPR, and insert any copies as needed.
2747 // The general assumption of the algorithm (and the previous cost calculation)
2748 // is that it is better to insert the copies in the MBB of the def of the src2
2749 // operands, and in the MBB of the user of the dest operands. This is based on
2750 // the assumption that the MFMAs are likely to appear in loop bodies, while
2751 // the src2 and dest operands are live-in / live-out of the loop. Due to this
2752 // design, the algorithm for finding copy insertion points is more
2753 // complicated.
2754 //
2755 // There are three main cases to handle: 1. the reaching defs of the src2
2756 // operands, 2. the reaching uses of the dst operands, and 3. the reaching
2757 // defs of the reaching uses of the dst operand.
2758 //
2759 // In the first case, we simply insert copies after each of the reaching
2760 // definitions. In the second case, we collect all the uses of a given dest
2761 // and organize them by MBB. Then, we insert 1 copy for each MBB before the
2762 // earliest use. Since the use may have multiple reaching defs, and since we
2763 // want to replace the register it is using with the result of the copy, we
2764 // must handle case 3. In the third case, we simply insert a copy after each
2765 // of the reaching defs to connect to the copy of the reaching uses of the dst
2766 // reg. This allows us to avoid inserting copies next to the MFMAs.
2767 //
2768 // While inserting the copies, we maintain a map of operands which will use
2769 // different regs (i.e. the result of the copies). For example, a case 1 src2
2770 // operand will use the register result of the copies after the reaching defs,
2771 // as opposed to the original register. Now that we have completed our copy
2772 // analysis and placement, we can bulk update the registers. We do this
2773 // separately as to avoid complicating the reachingDef and reachingUse
2774 // queries.
2775 //
2776 // While inserting the copies, we also maintain a list or registers which we
2777 // will want to reclassify as AGPR. After doing the copy insertion and the
2778 // register replacement, we can finally do the reclassification. This uses the
2779 // redef map, as the registers we are interested in reclassifying may be
2780 // replaced by the result of a copy. We must do this after the copy analysis
2781 // and placement as we must have an accurate redef map -- otherwise we may end
2782 // up creating illegal instructions.
2783
2784 // The original registers of the MFMA that need to be reclassified as AGPR.
2785 DenseSet<Register> RewriteRegs;
2786 // The map of an original register in the MFMA to a new register (result of a
2787 // copy) that it should be replaced with.
2788 DenseMap<Register, Register> RedefMap;
2789 // The map of the original MFMA registers to the relevant MFMA operands.
2790 DenseMap<Register, DenseSet<MachineOperand *>> ReplaceMap;
2791 // The map of reaching defs for a given register -- to avoid duplicate copies.
2792 DenseMap<Register, SmallPtrSet<MachineInstr *, 8>> ReachingDefCopyMap;
2793 // The map of reaching uses for a given register by basic block -- to avoid
2794 // duplicate copies and to calculate per MBB insert pts.
2795 DenseMap<unsigned, DenseMap<Register, SmallPtrSet<MachineOperand *, 8>>>
2796 ReachingUseTracker;
2797
2798 // Collect the candidate group; its members share AGPR-form operands
2799 // post-rewrite, so reaching defs feeding any member need no bridge copy.
2800 SmallPtrSet<MachineInstr *, 16> RewriteCandsSet;
2801 DenseSet<Register> RewriteSrc2Regs;
2802 for (auto &[MI, OriginalOpcode] : RewriteCands) {
2803 RewriteCandsSet.insert(MI);
2804 MachineOperand *Src2 = TII->getNamedOperand(*MI, AMDGPU::OpName::src2);
2805 if (Src2 && Src2->isReg())
2806 RewriteSrc2Regs.insert(Src2->getReg());
2807 }
2808
2809 for (auto &[MI, OriginalOpcode] : RewriteCands) {
2810 int ReplacementOp = AMDGPU::getAGPRFormOp(MI->getOpcode());
2811 if (ReplacementOp == -1)
2812 continue;
2813 MI->setDesc(TII->get(ReplacementOp));
2814
2815 // Case 1: insert copies for the reaching defs of the Src2Reg.
2816 MachineOperand *Src2 = TII->getNamedOperand(*MI, AMDGPU::OpName::src2);
2817 if (Src2->isReg()) {
2818 Register Src2Reg = Src2->getReg();
2819 if (!Src2Reg.isVirtual())
2820 return false;
2821
2822 Register MappedReg = Src2->getReg();
2823 SmallVector<SlotIndex, 8> Src2ReachingDefs;
2824 findReachingDefs(*Src2, DAG.LIS, Src2ReachingDefs);
2825 SmallSetVector<MachineInstr *, 8> Src2DefsReplace;
2826
2827 // If src2 has a use that must remain VGPR, it cannot be reclassified to
2828 // AGPR.
2829 bool Src2NeedsVGPR = Src2NeedsVGPRCache.lookup(MI);
2830
2831 for (SlotIndex RDIndex : Src2ReachingDefs) {
2832 MachineInstr *RD = DAG.LIS->getInstructionFromIndex(RDIndex);
2833 if (!Src2NeedsVGPR &&
2834 isReachingDefAGPRForm(RD, RewriteCandsSet, RewriteSrc2Regs, *TII))
2835 continue;
2836
2837 Src2DefsReplace.insert(RD);
2838 }
2839
2840 if (!Src2DefsReplace.empty()) {
2841 auto RI = RedefMap.find(Src2Reg);
2842 if (RI != RedefMap.end()) {
2843 MappedReg = RI->second;
2844 } else {
2845 assert(!ReachingDefCopyMap.contains(Src2Reg));
2846 const TargetRegisterClass *Src2RC = DAG.MRI.getRegClass(Src2Reg);
2847 const TargetRegisterClass *VGPRRC =
2848 SRI->getEquivalentVGPRClass(Src2RC);
2849
2850 // Track the mapping of the original register to the new register.
2851 MappedReg = DAG.MRI.createVirtualRegister(VGPRRC);
2852 RedefMap[Src2Reg] = MappedReg;
2853 }
2854
2855 // If none exists, create a copy from this reaching def.
2856 // We may have inserted a copy already in an earlier iteration.
2857 for (MachineInstr *RD : Src2DefsReplace) {
2858 // Do not create redundant copies.
2859 if (ReachingDefCopyMap[Src2Reg].insert(RD).second) {
2860 MachineInstrBuilder VGPRCopy =
2861 BuildMI(*RD->getParent(), std::next(RD->getIterator()),
2862 RD->getDebugLoc(), TII->get(TargetOpcode::COPY))
2863 .addDef(MappedReg, {}, 0)
2864 .addUse(Src2Reg, {}, 0);
2865 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
2866
2867 // If this reaching def was the last MI in the region, update the
2868 // region boundaries.
2869 if (LastMIToRegion.contains(RD)) {
2870 unsigned UpdateRegion = LastMIToRegion[RD];
2871 DAG.Regions[UpdateRegion].second = VGPRCopy;
2872 LastMIToRegion.erase(RD);
2873 }
2874 }
2875 }
2876 }
2877
2878 // Track the register for reclassification
2879 RewriteRegs.insert(Src2Reg);
2880
2881 // Always insert the operand for replacement. If this corresponds with a
2882 // chain of tied-def we may not see the VGPR requirement until later.
2883 ReplaceMap[Src2Reg].insert(Src2);
2884 }
2885
2886 // Case 2 and Case 3: insert copies before the reaching uses of the dsts,
2887 // and after the reaching defs of the reaching uses of the dsts.
2888
2889 MachineOperand *Dst = &MI->getOperand(0);
2890 Register DstReg = Dst->getReg();
2891 if (!DstReg.isVirtual())
2892 return false;
2893
2894 Register MappedReg = DstReg;
2895 SmallVector<MachineOperand *, 8> DstReachingUses;
2896
2897 SmallVector<MachineOperand *, 8> DstReachingUseCopies;
2898 SmallVector<MachineInstr *, 8> DstUseDefsReplace;
2899
2900 findReachingUses(MI, DAG.LIS, DstReachingUses);
2901
2902 for (MachineOperand *RUOp : DstReachingUses) {
2903 MachineInstr *UserMI = RUOp->getParent();
2904 // Group members read the AGPR result directly.
2905 if (TII->isMAI(*UserMI) && RewriteCandsSet.contains(UserMI))
2906 continue;
2907
2908 // If there is a non mai reaching use, then we need a copy.
2909 if (find(DstReachingUseCopies, RUOp) == DstReachingUseCopies.end())
2910 DstReachingUseCopies.push_back(RUOp);
2911
2912 // Non-rewritten MAI: its defs aren't being reclassified.
2913 if (TII->isMAI(*UserMI))
2914 continue;
2915
2916 SmallVector<SlotIndex, 8> DstUsesReachingDefs;
2917 findReachingDefs(*RUOp, DAG.LIS, DstUsesReachingDefs);
2918
2919 for (SlotIndex RDIndex : DstUsesReachingDefs) {
2920 MachineInstr *RD = DAG.LIS->getInstructionFromIndex(RDIndex);
2921 if (TII->isMAI(*RD))
2922 continue;
2923
2924 // If there is a non mai reaching def of this reaching use, then we will
2925 // need a copy.
2926 if (find(DstUseDefsReplace, RD) == DstUseDefsReplace.end())
2927 DstUseDefsReplace.push_back(RD);
2928 }
2929 }
2930
2931 if (!DstUseDefsReplace.empty()) {
2932 auto RI = RedefMap.find(DstReg);
2933 if (RI != RedefMap.end()) {
2934 MappedReg = RI->second;
2935 } else {
2936 assert(!ReachingDefCopyMap.contains(DstReg));
2937 const TargetRegisterClass *DstRC = DAG.MRI.getRegClass(DstReg);
2938 const TargetRegisterClass *VGPRRC = SRI->getEquivalentVGPRClass(DstRC);
2939
2940 // Track the mapping of the original register to the new register.
2941 MappedReg = DAG.MRI.createVirtualRegister(VGPRRC);
2942 RedefMap[DstReg] = MappedReg;
2943 }
2944
2945 // If none exists, create a copy from this reaching def.
2946 // We may have inserted a copy already in an earlier iteration.
2947 for (MachineInstr *RD : DstUseDefsReplace) {
2948 // Do not create reundant copies.
2949 if (ReachingDefCopyMap[DstReg].insert(RD).second) {
2950 MachineInstrBuilder VGPRCopy =
2951 BuildMI(*RD->getParent(), std::next(RD->getIterator()),
2952 RD->getDebugLoc(), TII->get(TargetOpcode::COPY))
2953 .addDef(MappedReg, {}, 0)
2954 .addUse(DstReg, {}, 0);
2955 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
2956
2957 // If this reaching def was the last MI in the region, update the
2958 // region boundaries.
2959 auto LMI = LastMIToRegion.find(RD);
2960 if (LMI != LastMIToRegion.end()) {
2961 unsigned UpdateRegion = LMI->second;
2962 DAG.Regions[UpdateRegion].second = VGPRCopy;
2963 LastMIToRegion.erase(RD);
2964 }
2965 }
2966 }
2967 }
2968
2969 DenseSet<MachineOperand *> &DstRegSet = ReplaceMap[DstReg];
2970 // One AGPR→VGPR copy per dst register, shared by all same-block uses.
2971 Register SameBlockCopyReg;
2972 MachineInstr *EarliestSameBlockUse = nullptr;
2973 for (MachineOperand *RU : DstReachingUseCopies) {
2974 MachineBasicBlock *RUBlock = RU->getParent()->getParent();
2975 // Just keep track of the reaching use of this register by block. After we
2976 // have scanned all the MFMAs we can find optimal insert pts.
2977 if (RUBlock != MI->getParent()) {
2978 ReachingUseTracker[RUBlock->getNumber()][DstReg].insert(RU);
2979 continue;
2980 }
2981
2982 // Lazily create the copy register on first same-block use.
2983 if (!SameBlockCopyReg.isValid()) {
2984 const TargetRegisterClass *DstRC = DAG.MRI.getRegClass(DstReg);
2985 const TargetRegisterClass *VGPRRC = SRI->getEquivalentVGPRClass(DstRC);
2986 SameBlockCopyReg = DAG.MRI.createVirtualRegister(VGPRRC);
2987 }
2988
2989 // Track the earliest use for copy insertion point.
2990 MachineInstr *UseInst = RU->getParent();
2991 if (!EarliestSameBlockUse ||
2993 DAG.LIS->getInstructionIndex(*UseInst),
2994 DAG.LIS->getInstructionIndex(*EarliestSameBlockUse)))
2995 EarliestSameBlockUse = UseInst;
2996 RU->setReg(SameBlockCopyReg);
2997 }
2998
2999 // Insert the copy before the earliest same-block use.
3000 if (SameBlockCopyReg.isValid()) {
3001 MachineInstrBuilder VGPRCopy =
3002 BuildMI(*EarliestSameBlockUse->getParent(),
3003 EarliestSameBlockUse->getIterator(), DebugLoc(),
3004 TII->get(TargetOpcode::COPY), SameBlockCopyReg)
3005 .addUse(DstReg, {}, 0);
3006 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
3007 DstRegSet.insert(&VGPRCopy->getOperand(1));
3008 }
3009
3010 // Track the register for reclassification
3011 RewriteRegs.insert(DstReg);
3012
3013 // Insert the dst operand for replacement. If this dst is in a chain of
3014 // tied-def MFMAs, and the first src2 needs to be replaced with a new reg,
3015 // all the correspond operands need to be replaced.
3016 DstRegSet.insert(Dst);
3017 }
3018
3019 // Handle the copies for dst uses.
3020 using RUBType =
3021 std::pair<unsigned, DenseMap<Register, SmallPtrSet<MachineOperand *, 8>>>;
3022 for (RUBType RUBlockEntry : ReachingUseTracker) {
3023 using RUDType = std::pair<Register, SmallPtrSet<MachineOperand *, 8>>;
3024 for (RUDType RUDst : RUBlockEntry.second) {
3025 MachineOperand *OpBegin = *RUDst.second.begin();
3026 SlotIndex InstPt = DAG.LIS->getInstructionIndex(*OpBegin->getParent());
3027
3028 // Find the earliest use in this block.
3029 for (MachineOperand *User : RUDst.second) {
3030 SlotIndex NewInstPt = DAG.LIS->getInstructionIndex(*User->getParent());
3031 if (SlotIndex::isEarlierInstr(NewInstPt, InstPt))
3032 InstPt = NewInstPt;
3033 }
3034
3035 const TargetRegisterClass *DstRC = DAG.MRI.getRegClass(RUDst.first);
3036 const TargetRegisterClass *VGPRRC = SRI->getEquivalentVGPRClass(DstRC);
3037 Register NewUseReg = DAG.MRI.createVirtualRegister(VGPRRC);
3038 MachineInstr *UseInst = DAG.LIS->getInstructionFromIndex(InstPt);
3039
3040 MachineInstrBuilder VGPRCopy =
3041 BuildMI(*UseInst->getParent(), UseInst->getIterator(),
3042 UseInst->getDebugLoc(), TII->get(TargetOpcode::COPY))
3043 .addDef(NewUseReg, {}, 0)
3044 .addUse(RUDst.first, {}, 0);
3045 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
3046
3047 // If this UseInst was the first MI in the region, update the region
3048 // boundaries.
3049 auto FI = FirstMIToRegion.find(UseInst);
3050 if (FI != FirstMIToRegion.end()) {
3051 unsigned UpdateRegion = FI->second;
3052 DAG.Regions[UpdateRegion].first = VGPRCopy;
3053 FirstMIToRegion.erase(UseInst);
3054 }
3055
3056 // Replace the operand for all users.
3057 for (MachineOperand *User : RUDst.second) {
3058 User->setReg(NewUseReg);
3059 }
3060
3061 // Track the copy source operand for replacement.
3062 ReplaceMap[RUDst.first].insert(&VGPRCopy->getOperand(1));
3063 }
3064 }
3065
3066 // We may have needed to insert copies after the reaching defs of the MFMAs.
3067 // Replace the original register with the result of the copy for all relevant
3068 // operands.
3069 for (std::pair<Register, Register> NewDef : RedefMap) {
3070 Register OldReg = NewDef.first;
3071 Register NewReg = NewDef.second;
3072
3073 // Replace the register for any associated operand in the MFMA chain.
3074 for (MachineOperand *ReplaceOp : ReplaceMap[OldReg])
3075 ReplaceOp->setReg(NewReg);
3076 }
3077
3078 // Finally, do the reclassification of the MFMA registers.
3079 for (Register RewriteReg : RewriteRegs) {
3080 Register RegToRewrite = RewriteReg;
3081
3082 // Be sure to update the replacement register and not the original.
3083 auto RI = RedefMap.find(RewriteReg);
3084 if (RI != RedefMap.end())
3085 RegToRewrite = RI->second;
3086
3087 const TargetRegisterClass *CurrRC = DAG.MRI.getRegClass(RegToRewrite);
3088 const TargetRegisterClass *AGPRRC = SRI->getEquivalentAGPRClass(CurrRC);
3089
3090 DAG.MRI.setRegClass(RegToRewrite, AGPRRC);
3091 }
3092
3093 // Bulk update the LIS.
3094 DAG.LIS->reanalyze(DAG.MF);
3095 // Liveins may have been modified for cross RC copies
3096 RegionPressureMap LiveInUpdater(&DAG, false);
3097 LiveInUpdater.buildLiveRegMap();
3098
3099 for (unsigned Region = 0; Region < DAG.Regions.size(); Region++)
3100 DAG.LiveIns[Region] = LiveInUpdater.getLiveRegsForRegionIdx(Region);
3101
3102 DAG.Pressure[RegionIdx] = DAG.getRealRegPressure(RegionIdx);
3103
3104 return true;
3105}
3106
3107unsigned PreRARematStage::getStageTargetOccupancy() const {
3108 return TargetOcc ? *TargetOcc : MFI.getMinWavesPerEU();
3109}
3110
3111bool PreRARematStage::setObjective() {
3112 const Function &F = MF.getFunction();
3113
3114 // Set up "spilling targets" for all regions.
3115 unsigned MaxSGPRs = ST.getMaxNumSGPRs(F);
3116 unsigned MaxVGPRs = ST.getMaxNumVGPRs(F);
3117 bool HasVectorRegisterExcess = false;
3118 for (unsigned I = 0, E = static_cast<unsigned>(DAG.Regions.size()); I != E;
3119 ++I) {
3120 const GCNRegPressure &RP = DAG.Pressure[I];
3121 GCNRPTarget &Target = RPTargets.emplace_back(MaxSGPRs, MaxVGPRs, MF, RP);
3122 if (!Target.satisfied())
3123 TargetRegions.set(I);
3124 HasVectorRegisterExcess |= Target.hasVectorRegisterExcess();
3125 }
3126
3127 if (HasVectorRegisterExcess || DAG.MinOccupancy >= MFI.getMaxWavesPerEU()) {
3128 // In addition to register usage being above addressable limits, occupancy
3129 // below the minimum is considered like "spilling" as well.
3130 TargetOcc = std::nullopt;
3131 } else {
3132 // There is no spilling and room to improve occupancy; set up "increased
3133 // occupancy targets" for all regions.
3134 TargetOcc = DAG.MinOccupancy + 1;
3135 const unsigned VGPRBlockSize = MFI.getDynamicVGPRBlockSize();
3136 MaxSGPRs = ST.getMaxNumSGPRs(*TargetOcc, false);
3137 MaxVGPRs = ST.getMaxNumVGPRs(*TargetOcc, VGPRBlockSize);
3138 for (auto [I, Target] : enumerate(RPTargets)) {
3139 Target.setTarget(MaxSGPRs, MaxVGPRs);
3140 if (!Target.satisfied())
3141 TargetRegions.set(static_cast<unsigned>(I));
3142 }
3143 }
3144
3145 return TargetRegions.any();
3146}
3147
3148bool PreRARematStage::candidateHasValidUsers(
3149 RegisterIdx CandIdx, const SmallSet<Register, 4> &MarkedRegs) const {
3150 const Rematerializer::Reg &CandReg = Remater.getReg(CandIdx);
3151 SlotIndex RefIdx =
3152 DAG.LIS->getInstructionIndex(*CandReg.getLastDef()).getRegSlot(true);
3153
3154 for (const auto &[UseRegion, Users] : CandReg.Uses) {
3155 // Users cannot themselves be rematerializable.
3156 if (llvm::any_of(Users, [&](const MachineInstr *UserMI) {
3157 assert(UserMI->getNumOperands() > 0 &&
3158 "user must have at least one operand");
3159 // A user is rematerializable if its first register operand (its
3160 // register def) was marked already.
3161 const MachineOperand &DefMO = UserMI->getOperand(0);
3162 return DefMO.isReg() && MarkedRegs.contains(DefMO.getReg());
3163 }))
3164 return false;
3165
3166 MachineInstr *FirstUseMI =
3167 CandReg.getRegionUseBounds(UseRegion, *DAG.LIS).first;
3168 assert(FirstUseMI && "there must be a user in the region");
3169 SlotIndex FirstUseIdx =
3170 DAG.LIS->getInstructionIndex(*FirstUseMI).getRegSlot(true);
3171
3172 // All dependencies must be available at the first use in the region.
3173 if (llvm::any_of(CandReg.Dependencies, [&](RegisterIdx DepRegIdx) {
3174 const Rematerializer::Reg &DepReg = Remater.getReg(DepRegIdx);
3175 Register DepDefReg = DepReg.getDefReg();
3176 return !Remater.isRegIdenticalAtUses(DepDefReg, DepReg.Mask, RefIdx,
3177 {FirstUseIdx});
3178 }))
3179 return false;
3180 if (llvm::any_of(Remater.getUnrematableDeps(CandIdx),
3181 [&](const std::pair<Register, LaneBitmask> &RegAndMask) {
3182 const auto &[Reg, Mask] = RegAndMask;
3183 return !Remater.isRegIdenticalAtUses(Reg, Mask, RefIdx,
3184 {FirstUseIdx});
3185 }))
3186 return false;
3187 }
3188 return true;
3189}
3190
3191bool PreRARematStage::ScoredRemat::maybeBeneficial(
3192 const BitVector &TargetRegions, ArrayRef<GCNRPTarget> RPTargets) const {
3193 for (unsigned I : TargetRegions.set_bits()) {
3194 if (Live[I] && RPTargets[I].isSaveBeneficial(RPSave))
3195 return true;
3196 }
3197 return false;
3198}
3199
3203 MachineCycleInfo MCI;
3204 MCI.compute(MF);
3205 MachineBlockFrequencyInfo MBFI(MF, MBPI, MCI);
3206
3207 const size_t NumRegions = DAG.Regions.size();
3209 MaxFreq = 0;
3210 Regions.reserve(NumRegions);
3211 for (size_t I = 0; I < NumRegions; ++I) {
3212 MachineBasicBlock *MBB = DAG.Regions[I].first->getParent();
3213 uint64_t BlockFreq = MBFI.getBlockFreq(MBB).getFrequency();
3214 Regions.push_back(BlockFreq);
3215 if (BlockFreq && BlockFreq < MinFreq)
3216 MinFreq = BlockFreq;
3217 else if (BlockFreq > MaxFreq)
3218 MaxFreq = BlockFreq;
3219 }
3220 if (!MinFreq)
3221 return;
3222
3223 // Scale everything down if frequencies are high.
3224 if (MinFreq >= ScaleFactor * ScaleFactor) {
3225 for (uint64_t &Freq : Regions)
3226 Freq /= ScaleFactor;
3227 MinFreq /= ScaleFactor;
3228 MaxFreq /= ScaleFactor;
3229 }
3230}
3231
3232void PreRARematStage::ScoredRemat::init(const FreqInfo &Freq,
3233 const Rematerializer &Remater,
3235 const Rematerializer::Reg &Reg = Remater.getReg(RegIdx);
3236 Register DefReg = Reg.getDefReg();
3237
3238 Live |= LiveIn;
3239 Live |= LiveOut;
3240
3241 for (unsigned I : Live.set_bits()) {
3242 // If the register is both unused and live-through in the region, the
3243 // latter's RP is guaranteed to decrease.
3244 if (!LiveIn[I] || !LiveOut[I] || Reg.Uses.contains(I))
3245 UnpredictableRPSave.set(I);
3246 }
3247 RPSave.inc(DefReg, LaneBitmask::getNone(), Reg.Mask, DAG.MRI);
3248
3249 // Estimate the difference in instruction execution frequency that will be
3250 // induced by the rematerialization. A rematerialization from the least
3251 // frequent region to the most frequent region should yield the greatest
3252 // frequency penalty (most negative frequency difference). When the register
3253 // has users in its defining region the original instruction(s) won't be
3254 // deleted so there is no frequency gain in the defining region.
3255 int64_t DefOrMin = Reg.hasUsersInDefRegion()
3256 ? 0
3257 : std::max(Freq.Regions[Reg.DefRegion], Freq.MinFreq);
3258 int64_t UseOrMax = 0;
3259 for (const auto &[UseRegion, _] : Reg.Uses) {
3260 if (Reg.DefRegion == UseRegion)
3261 continue;
3262 uint64_t RegionFreq = Freq.Regions[UseRegion];
3263 UseOrMax += RegionFreq != 0 ? RegionFreq : Freq.MaxFreq;
3264 }
3265 FreqDiff = DefOrMin - UseOrMax;
3266}
3267
3268void PreRARematStage::ScoredRemat::update(const BitVector &TargetRegions,
3269 ArrayRef<GCNRPTarget> RPTargets,
3270 const FreqInfo &FreqInfo,
3271 bool ReduceSpill) {
3272 MaxFreq = 0;
3273 RegionImpact = 0;
3274 for (unsigned I : TargetRegions.set_bits()) {
3275 if (!Live[I])
3276 continue;
3277
3278 // The rematerialization must contribute positively in at least one
3279 // register class with usage above the RP target for this region to
3280 // contribute to the score.
3281 const GCNRPTarget &RegionTarget = RPTargets[I];
3282 const unsigned NumRegsBenefit = RegionTarget.getNumRegsBenefit(RPSave);
3283 if (!NumRegsBenefit)
3284 continue;
3285
3286 // Regions in which RP is guaranteed to decrease have more weight.
3287 RegionImpact += (UnpredictableRPSave[I] ? 1 : 2) * NumRegsBenefit;
3288
3289 if (ReduceSpill) {
3290 uint64_t Freq = FreqInfo.Regions[I];
3291 if (UnpredictableRPSave[I]) {
3292 // Apply a frequency penalty in regions in which we are not sure that RP
3293 // will decrease.
3294 Freq /= 2;
3295 }
3296 MaxFreq = std::max(MaxFreq, Freq);
3297 }
3298 }
3299}
3300
3301void PreRARematStage::ScoredRemat::rematerialize(
3302 Rematerializer &Remater) const {
3303 const Rematerializer::Reg &Reg = Remater.getReg(RegIdx);
3304
3305 // All rematerializable dependencies are re-used for all rematerializations.
3306 Rematerializer::DependencyReuseInfo DRI;
3307 for (RegisterIdx DepRegIdx : Reg.Dependencies)
3308 DRI.reuse(DepRegIdx);
3309
3310 // Rematerialize once per using region, except in the defining region.
3311 SmallVector<unsigned, 8> RematRegions;
3312 RematRegions.reserve(Reg.Uses.size());
3313 for (const auto &[UseRegion, _] : Reg.Uses) {
3314 if (Reg.DefRegion != UseRegion)
3315 RematRegions.push_back(UseRegion);
3316 }
3317 for (const unsigned UseRegion : RematRegions) {
3318 Rematerializer::DependencyReuseInfo RegionDRI(DRI);
3319 Remater.rematerializeToRegion(RegIdx, UseRegion, RegionDRI);
3320 }
3321}
3322
3323void PreRARematStage::updateRPTargets(const BitVector &Regions,
3324 const GCNRegPressure &RPSave) {
3325 for (unsigned I : Regions.set_bits()) {
3326 RPTargets[I].saveRP(RPSave);
3327 if (TargetRegions[I] && RPTargets[I].satisfied()) {
3328 REMAT_DEBUG(dbgs() << " [" << I << "] Target reached!\n");
3329 TargetRegions.reset(I);
3330 }
3331 }
3332}
3333
3334bool PreRARematStage::updateAndVerifyRPTargets(const BitVector &Regions) {
3335 bool TooOptimistic = false;
3336 for (unsigned I : Regions.set_bits()) {
3337 GCNRPTarget &Target = RPTargets[I];
3338 Target.setRP(DAG.getRealRegPressure(I));
3339
3340 // Since we were optimistic in assessing RP decreases in these regions, we
3341 // may need to remark the target as a target region if RP didn't decrease
3342 // as expected.
3343 if (!TargetRegions[I] && !Target.satisfied()) {
3344 REMAT_DEBUG(dbgs() << " [" << I << "] Incorrect RP estimation\n");
3345 TooOptimistic = true;
3346 TargetRegions.set(I);
3347 }
3348 }
3349 return TooOptimistic;
3350}
3351
3352void PreRARematStage::removeFromLiveMaps(Register Reg, const BitVector &LiveIn,
3353 const BitVector &LiveOut) {
3354 assert(LiveIn.size() == DAG.Regions.size() &&
3355 LiveOut.size() == DAG.Regions.size() && "region num mismatch");
3356 for (unsigned I : LiveIn.set_bits())
3357 DAG.LiveIns[I].erase(Reg);
3358 for (unsigned I : LiveOut.set_bits())
3359 DAG.RegionLiveOuts.getLiveRegsForRegionIdx(I).erase(Reg);
3360}
3361
3362void PreRARematStage::addToLiveMaps(Register Reg, LaneBitmask Mask,
3363 const BitVector &LiveIn,
3364 const BitVector &LiveOut) {
3365 assert(LiveIn.size() == DAG.Regions.size() &&
3366 LiveOut.size() == DAG.Regions.size() && "region num mismatch");
3367 std::pair<Register, LaneBitmask> LiveReg(Reg, Mask);
3368 for (unsigned I : LiveIn.set_bits())
3369 DAG.LiveIns[I].insert(LiveReg);
3370 for (unsigned I : LiveOut.set_bits())
3371 DAG.RegionLiveOuts.getLiveRegsForRegionIdx(I).insert(LiveReg);
3372}
3373
3375 // We consider that reducing spilling is always beneficial so we never
3376 // rollback rematerializations or revert scheduling in such cases.
3377 if (!TargetOcc)
3378 return;
3379
3380 // When increasing occupancy, it is possible that re-scheduling is not able to
3381 // achieve the target occupancy in all regions, in which case re-scheduling in
3382 // all regions should be reverted.
3383 if (DAG.MinOccupancy >= *TargetOcc)
3384 return;
3385
3386 // Revert re-scheduling in all affected regions.
3387 for (const auto &[RegionIdx, OrigMIOrder, MaxPressure] : RegionReverts) {
3388 REMAT_DEBUG(dbgs() << "Reverting re-scheduling in region " << RegionIdx
3389 << '\n');
3390 DAG.Pressure[RegionIdx] = MaxPressure;
3391 modifyRegionSchedule(RegionIdx, OrigMIOrder);
3392 }
3393
3394 // It is possible that re-scheduling lowers occupancy over the one achieved
3395 // just through rematerializations, in which case we revert re-scheduling in
3396 // all regions but do not roll back rematerializations.
3397 if (AchievedOcc >= *TargetOcc) {
3398 DAG.setTargetOccupancy(AchievedOcc);
3399 return;
3400 }
3401
3402 // Reset the target occupancy to what it was pre-rematerialization.
3403 DAG.setTargetOccupancy(*TargetOcc - 1);
3404
3405 // Roll back changes made by the stage, then recompute pressure in all
3406 // affected regions.
3407 REMAT_DEBUG(dbgs() << "==== ROLLBACK ====\n");
3408 assert(Rollback && "rollbacker should be defined");
3409 Rollback->Listener.rollback(Remater);
3410 for (const auto &[RegIdx, LiveIn, LiveOut] : Rollback->LiveMapUpdates) {
3411 const Rematerializer::Reg &Reg = Remater.getReg(RegIdx);
3412 addToLiveMaps(Reg.getDefReg(), Reg.Mask, LiveIn, LiveOut);
3413 }
3414
3415#ifdef EXPENSIVE_CHECKS
3416 // In particular, we want to check for coherent MI/slot order in regions in
3417 // which reverts and/or rollbacks may have happened.
3418 MF.verify();
3419#endif
3420 for (unsigned I : RescheduleRegions.set_bits())
3421 DAG.Pressure[I] = DAG.getRealRegPressure(I);
3422
3424}
3425
3426void GCNScheduleDAGMILive::setTargetOccupancy(unsigned TargetOccupancy) {
3427 MinOccupancy = TargetOccupancy;
3428 if (MFI.getOccupancy() < TargetOccupancy)
3429 MFI.increaseOccupancy(MF, MinOccupancy);
3430 else
3431 MFI.limitOccupancy(MinOccupancy);
3432}
3433
3435 const SIInstrInfo *SII = static_cast<const SIInstrInfo *>(DAG->TII);
3436 return any_of(*DAG, [SII](MachineBasicBlock::iterator MI) {
3437 return SII->isIGLPMutationOnly(MI->getOpcode());
3438 });
3439}
3440
3445
3447 HasIGLPInstrs = hasIGLPInstrs(this);
3448 if (HasIGLPInstrs) {
3449 SavedMutations.clear();
3450 SavedMutations.swap(Mutations);
3452 }
3453
3455}
3456
3458 if (HasIGLPInstrs)
3459 SavedMutations.swap(Mutations);
3460
3462}
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)