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"
30#include "GCNRematStrategy.h"
33#include "llvm/ADT/BitVector.h"
34#include "llvm/ADT/STLExtras.h"
40#include "llvm/MC/MCSchedule.h"
43
44#define DEBUG_TYPE "machine-scheduler"
45
46using namespace llvm;
47
49 "amdgpu-disable-unclustered-high-rp-reschedule", cl::Hidden,
50 cl::desc("Disable unclustered high register pressure "
51 "reduction scheduling stage."),
52 cl::init(false));
53
55 "amdgpu-disable-clustered-low-occupancy-reschedule", cl::Hidden,
56 cl::desc("Disable clustered low occupancy "
57 "rescheduling for ILP scheduling stage."),
58 cl::init(false));
59
61 "amdgpu-schedule-metric-bias", cl::Hidden,
63 "Sets the bias which adds weight to occupancy vs latency. Set it to "
64 "100 to chase the occupancy only."),
65 cl::init(10));
66
67static cl::opt<bool>
68 RelaxedOcc("amdgpu-schedule-relaxed-occupancy", cl::Hidden,
69 cl::desc("Relax occupancy targets for kernels which are memory "
70 "bound (amdgpu-membound-threshold), or "
71 "Wave Limited (amdgpu-limit-wave-threshold)."),
72 cl::init(false));
73
75 "amdgpu-use-amdgpu-trackers", cl::Hidden,
76 cl::desc("Use the AMDGPU specific RPTrackers during scheduling"),
77 cl::init(false));
78
80 "amdgpu-scheduler-pending-queue-limit", cl::Hidden,
82 "Max (Available+Pending) size to inspect pending queue (0 disables)"),
83 cl::init(256));
84
85#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
86#define DUMP_MAX_REG_PRESSURE
88 "amdgpu-print-max-reg-pressure-regusage-before-scheduler", cl::Hidden,
89 cl::desc("Print a list of live registers along with their def/uses at the "
90 "point of maximum register pressure before scheduling."),
91 cl::init(false));
92
94 "amdgpu-print-max-reg-pressure-regusage-after-scheduler", cl::Hidden,
95 cl::desc("Print a list of live registers along with their def/uses at the "
96 "point of maximum register pressure after scheduling."),
97 cl::init(false));
98#endif
99
101 "amdgpu-disable-rewrite-mfma-form-sched-stage", cl::Hidden,
102 cl::desc("Disable rewrite mfma rewrite scheduling stage"), cl::init(true));
103
105 unsigned &Value) {
106 if (Arg.getAsInteger(0, Value))
107 return O.error("'" + Arg + "' value invalid for uint argument!");
108
109 if (Value > 100)
110 return O.error("'" + Arg + "' value must be in the range [0, 100]!");
111
112 return false;
113}
114
116 "amdgpu-vgpr-threshold-percent", cl::Hidden,
117 cl::desc("Percent of VGPR limits that we should use as RP threshold "
118 "during scheduling. We have two limits relevant to scheduling: "
119 "Critical (avoid decreasing occupancy), Excess (avoid spilling). "
120 "This flag scales both limits back by an equal percent: (0 = use "
121 " default calculation, 1-100 = use percentage), default: 0"),
122 cl::init(0));
123
124const unsigned ScheduleMetrics::ScaleFactor = 100;
125
133
136
137 MF = &DAG->MF;
138
139 const GCNSubtarget &ST = MF->getSubtarget<GCNSubtarget>();
140
142 Context->RegClassInfo->getNumAllocatableRegs(&AMDGPU::SGPR_32RegClass);
144 Context->RegClassInfo->getNumAllocatableRegs(&AMDGPU::VGPR_32RegClass);
146 Context->RegClassInfo->getNumAllocatableRegs(&AMDGPU::AGPR_32RegClass);
147
149 // Set the initial TargetOccupnacy to the maximum occupancy that we can
150 // achieve for this function. This effectively sets a lower bound on the
151 // 'Critical' register limits in the scheduler.
152 // Allow for lower occupancy targets if kernel is wave limited or memory
153 // bound, and using the relaxed occupancy feature.
157 std::min(ST.getMaxNumSGPRs(TargetOccupancy, true), SGPRExcessLimit);
158
159 if (!KnownExcessRP) {
160 // Preserve the combined occupancy budget before clamping to one bank.
162 ST.getMaxNumVGPRs(TargetOccupancy, MFI.getDynamicVGPRBlockSize());
164 } else {
165 // This is similar to ST.getMaxNumVGPRs(TargetOccupancy) result except
166 // returns a reasonably small number for targets with lots of VGPRs, such
167 // as GFX10 and GFX11.
168 LLVM_DEBUG(dbgs() << "Region is known to spill, use alternative "
169 "VGPRCriticalLimit calculation method.\n");
170 unsigned DynamicVGPRBlockSize = MFI.getDynamicVGPRBlockSize();
171 unsigned Granule =
172 AMDGPU::IsaInfo::getVGPRAllocGranule(ST, DynamicVGPRBlockSize);
173 unsigned Addressable =
174 AMDGPU::IsaInfo::getAddressableNumVGPRs(ST, DynamicVGPRBlockSize);
175 unsigned VGPRBudget = alignDown(Addressable / TargetOccupancy, Granule);
176 VGPRBudget = std::max(VGPRBudget, Granule);
177 UnifiedVGPRCriticalLimit = VGPRBudget;
178 VGPRCriticalLimit = std::min(VGPRBudget, VGPRExcessLimit);
179 }
180
181 // Reuse VGPR critical limit
183
184 // Apply VGPR excess threshold percentage if specified.
185 if (VGPRThresholdPercent > 0) {
186 [[maybe_unused]] unsigned OriginalVGPRExcessLimit = VGPRExcessLimit;
187 [[maybe_unused]] unsigned OriginalVGPRCriticalLimit = VGPRCriticalLimit;
192 LLVM_DEBUG(dbgs() << "Applied VGPR excess threshold "
193 << VGPRThresholdPercent << "%, VGPRExcessLimit: "
194 << OriginalVGPRExcessLimit << " -> " << VGPRExcessLimit
195 << ". VGPRCriticalLimit: " << OriginalVGPRCriticalLimit
196 << " -> " << VGPRCriticalLimit << '\n');
197 } else {
203 }
204
205 // Subtract error margin and bias from register limits and avoid overflow.
208
211
212 LLVM_DEBUG(dbgs() << "VGPRCriticalLimit = " << VGPRCriticalLimit
213 << ", UnifiedVGPRCriticalLimit = "
215 << ", VGPRExcessLimit = " << VGPRExcessLimit
216 << ", AGPRCriticalLimit = " << AGPRCriticalLimit
217 << ", AGPRExcessLimit = " << AGPRExcessLimit
218 << ", SGPRCriticalLimit = " << SGPRCriticalLimit
219 << ", SGPRExcessLimit = " << SGPRExcessLimit << "\n\n");
220}
221
222/// Checks whether \p SU can use the cached DAG pressure diffs to compute the
223/// current register pressure.
224///
225/// This works for the common case, but it has a few exceptions that have been
226/// observed through trial and error:
227/// - Explicit physical register operands
228/// - Subregister definitions
229///
230/// In both of those cases, PressureDiff doesn't represent the actual pressure,
231/// and querying LiveIntervals through the RegPressureTracker is needed to get
232/// an accurate value.
233///
234/// We should eventually only use PressureDiff for maximum performance, but this
235/// already allows 80% of SUs to take the fast path without changing scheduling
236/// at all. Further changes would either change scheduling, or require a lot
237/// more logic to recover an accurate pressure estimate from the PressureDiffs.
238static bool canUsePressureDiffs(const SUnit &SU) {
239 if (!SU.isInstr())
240 return false;
241
242 // Cannot use pressure diffs for subregister defs or with physregs, it's
243 // imprecise in both cases. For a bundle, check the instructions inside it:
244 // the BUNDLE header only has implicit operands.
245 for (const auto &Op : const_mi_bundle_ops(*SU.getInstr())) {
246 if (!Op.isReg() || Op.isImplicit())
247 continue;
248 if (Op.getReg().isPhysical() ||
249 (Op.isDef() && Op.getSubReg() != AMDGPU::NoSubRegister))
250 return false;
251 }
252 return true;
253}
254
256 bool AtTop, const RegPressureTracker &RPTracker, SUnit *SU,
257 std::vector<unsigned> &Pressure, std::vector<unsigned> &MaxPressure,
260 const SIRegisterInfo *SRI) {
261 // getDownwardPressure() and getUpwardPressure() make temporary changes to
262 // the tracker, so we need to pass those function a non-const copy.
263 RegPressureTracker &TempTracker = const_cast<RegPressureTracker &>(RPTracker);
264 if (!useGCNTrackers()) {
265 AtTop
266 ? TempTracker.getDownwardPressure(SU->getInstr(), Pressure, MaxPressure)
267 : TempTracker.getUpwardPressure(SU->getInstr(), Pressure, MaxPressure);
268
269 return;
270 }
271
272 // GCNTrackers
273 Pressure.resize(4, 0);
274 MachineInstr *MI = SU->getInstr();
275 GCNRegPressure NewPressure;
276 if (AtTop) {
277 NewPressure = DownwardTracker.bumpDownwardPressure(MI, SRI);
278 } else {
279 GCNUpwardRPTracker TempUpwardTracker(UpwardTracker);
280 TempUpwardTracker.recede(*MI);
281 NewPressure = TempUpwardTracker.getPressure();
282 }
283 Pressure[AMDGPU::RegisterPressureSets::SReg_32] = NewPressure.getSGPRNum();
284 Pressure[AMDGPU::RegisterPressureSets::VGPR_32] =
285 NewPressure.getArchVGPRNum();
286 Pressure[AMDGPU::RegisterPressureSets::AGPR_32] = NewPressure.getAGPRNum();
287}
288
290 bool AtTop,
291 const RegPressureTracker &RPTracker,
292 const SIRegisterInfo *SRI,
293 unsigned SGPRPressure,
294 unsigned VGPRPressure,
295 unsigned AGPRPressure, bool IsBottomUp) {
296 Cand.SU = SU;
297 Cand.AtTop = AtTop;
298
299 if (!DAG->isTrackingPressure())
300 return;
301
302 Pressure.clear();
303 MaxPressure.clear();
304
305 // We try to use the cached PressureDiffs in the ScheduleDAG whenever
306 // possible over querying the RegPressureTracker.
307 //
308 // RegPressureTracker will make a lot of LIS queries which are very
309 // expensive, it is considered a slow function in this context.
310 //
311 // PressureDiffs are precomputed and cached, and getPressureDiff is just a
312 // trivial lookup into an array. It is pretty much free.
313 //
314 // In EXPENSIVE_CHECKS, we always query RPTracker to verify the results of
315 // PressureDiffs.
316 if (AtTop || !canUsePressureDiffs(*SU) || useGCNTrackers()) {
317 getRegisterPressures(AtTop, RPTracker, SU, Pressure, MaxPressure,
319 } else {
320 // Reserve 4 slots.
321 Pressure.resize(4, 0);
322 Pressure[AMDGPU::RegisterPressureSets::SReg_32] = SGPRPressure;
323 Pressure[AMDGPU::RegisterPressureSets::VGPR_32] = VGPRPressure;
324 Pressure[AMDGPU::RegisterPressureSets::AGPR_32] = AGPRPressure;
325
326 for (const auto &Diff : DAG->getPressureDiff(SU)) {
327 if (!Diff.isValid())
328 continue;
329 // PressureDiffs is always bottom-up so if we're working top-down we need
330 // to invert its sign.
331 Pressure[Diff.getPSet()] +=
332 (IsBottomUp ? Diff.getUnitInc() : -Diff.getUnitInc());
333 }
334
335#ifdef EXPENSIVE_CHECKS
336 std::vector<unsigned> CheckPressure, CheckMaxPressure;
337 getRegisterPressures(AtTop, RPTracker, SU, CheckPressure, CheckMaxPressure,
339 if (Pressure[AMDGPU::RegisterPressureSets::SReg_32] !=
340 CheckPressure[AMDGPU::RegisterPressureSets::SReg_32] ||
341 Pressure[AMDGPU::RegisterPressureSets::VGPR_32] !=
342 CheckPressure[AMDGPU::RegisterPressureSets::VGPR_32] ||
343 Pressure[AMDGPU::RegisterPressureSets::AGPR_32] !=
344 CheckPressure[AMDGPU::RegisterPressureSets::AGPR_32]) {
345 errs() << "Register Pressure is inaccurate when calculated through "
346 "PressureDiff\n"
347 << "SGPR got " << Pressure[AMDGPU::RegisterPressureSets::SReg_32]
348 << ", expected "
349 << CheckPressure[AMDGPU::RegisterPressureSets::SReg_32] << "\n"
350 << "VGPR got " << Pressure[AMDGPU::RegisterPressureSets::VGPR_32]
351 << ", expected "
352 << CheckPressure[AMDGPU::RegisterPressureSets::VGPR_32] << "\n"
353 << "AGPR got " << Pressure[AMDGPU::RegisterPressureSets::AGPR_32]
354 << ", expected "
355 << CheckPressure[AMDGPU::RegisterPressureSets::AGPR_32] << "\n";
356 report_fatal_error("inaccurate register pressure calculation");
357 }
358#endif
359 }
360
361 unsigned NewAGPRPressure = Pressure[AMDGPU::RegisterPressureSets::AGPR_32];
362 unsigned NewSGPRPressure = Pressure[AMDGPU::RegisterPressureSets::SReg_32];
363 unsigned NewVGPRPressure = Pressure[AMDGPU::RegisterPressureSets::VGPR_32];
364
365 // If two instructions increase the pressure of different register sets
366 // by the same amount, the generic scheduler will prefer to schedule the
367 // instruction that increases the set with the least amount of registers,
368 // which in our case would be SGPRs. This is rarely what we want, so
369 // when we report excess/critical register pressure, we do it either
370 // only for VGPRs, AGPRs or SGPRs. Priority: VGPR > AGPR > SGPR.
371
372 // FIXME: Better heuristics to determine whether to prefer SGPRs or VGPRs.
373 const unsigned MaxVGPRPressureInc = 16;
374 bool ShouldTrackVGPRs = VGPRPressure + MaxVGPRPressureInc >= VGPRExcessLimit;
375 bool ShouldTrackAGPRs = AGPRExcessLimit > 0 && !ShouldTrackVGPRs &&
376 AGPRPressure + MaxVGPRPressureInc >= AGPRExcessLimit;
377 bool ShouldTrackSGPRs =
378 !ShouldTrackVGPRs && !ShouldTrackAGPRs && SGPRPressure >= SGPRExcessLimit;
379 // FIXME: We have to enter REG-EXCESS before we reach the actual threshold
380 // to increase the likelihood we don't go over the limits. We should improve
381 // the analysis to look through dependencies to find the path with the least
382 // register pressure.
383 // We only need to update the RPDelta for instructions that increase register
384 // pressure. Instructions that decrease or keep reg pressure the same will be
385 // marked as RegExcess in tryCandidate() when they are compared with
386 // instructions that increase the register pressure.
387 if (ShouldTrackVGPRs && NewVGPRPressure >= VGPRExcessLimit) {
388 HasHighPressure = true;
389 Cand.RPDelta.Excess = PressureChange(AMDGPU::RegisterPressureSets::VGPR_32);
390 Cand.RPDelta.Excess.setUnitInc(NewVGPRPressure - VGPRExcessLimit);
391 }
392
393 if (ShouldTrackAGPRs && NewAGPRPressure >= AGPRExcessLimit) {
394 HasHighPressure = true;
395 Cand.RPDelta.Excess = PressureChange(AMDGPU::RegisterPressureSets::AGPR_32);
396 Cand.RPDelta.Excess.setUnitInc(NewAGPRPressure - AGPRExcessLimit);
397 }
398
399 if (ShouldTrackSGPRs && NewSGPRPressure >= SGPRExcessLimit) {
400 HasHighPressure = true;
401 Cand.RPDelta.Excess = PressureChange(AMDGPU::RegisterPressureSets::SReg_32);
402 Cand.RPDelta.Excess.setUnitInc(NewSGPRPressure - SGPRExcessLimit);
403 }
404
405 // Register pressure is considered 'CRITICAL' if it is approaching a value
406 // that would reduce the wave occupancy for the execution unit. When
407 // register pressure is 'CRITICAL', increasing SGPR, VGPR, and AGPR
408 // pressure all has the same cost, so we pick the most critical type.
409
410 // Unified targets allocate both vector banks from the same occupancy budget.
411 // Keep the bank pressures above for excess checks, and do not align VGPRs
412 // when there are no AGPRs, matching GCNRegPressure::getVGPRNum().
413 bool UnifiedVGPRFile = MF->getSubtarget<GCNSubtarget>().hasGFX90AInsts();
414 unsigned VectorCriticalLimit = VGPRCriticalLimit;
415 if (UnifiedVGPRFile) {
416 if (NewAGPRPressure)
417 NewVGPRPressure = GCNRegPressure::getUnifiedVGPRNum(NewVGPRPressure,
418 NewAGPRPressure, 0);
419 VectorCriticalLimit = UnifiedVGPRCriticalLimit;
420 }
421
422 int SGPRDelta = NewSGPRPressure - SGPRCriticalLimit;
423 int VGPRDelta = NewVGPRPressure - VectorCriticalLimit;
424 int AGPRDelta = !UnifiedVGPRFile && AGPRExcessLimit > 0
425 ? NewAGPRPressure - AGPRCriticalLimit
426 : std::numeric_limits<int>::min();
427
428 if (SGPRDelta >= 0 || VGPRDelta >= 0 || AGPRDelta >= 0) {
429 HasHighPressure = true;
430 // Pick the most critical type.
431 if (VGPRDelta >= SGPRDelta && VGPRDelta >= AGPRDelta) {
432 Cand.RPDelta.CriticalMax =
433 PressureChange(AMDGPU::RegisterPressureSets::VGPR_32);
434 Cand.RPDelta.CriticalMax.setUnitInc(VGPRDelta);
435 } else if (AGPRDelta >= SGPRDelta) {
436 Cand.RPDelta.CriticalMax =
437 PressureChange(AMDGPU::RegisterPressureSets::AGPR_32);
438 Cand.RPDelta.CriticalMax.setUnitInc(AGPRDelta);
439 } else {
440 Cand.RPDelta.CriticalMax =
441 PressureChange(AMDGPU::RegisterPressureSets::SReg_32);
442 Cand.RPDelta.CriticalMax.setUnitInc(SGPRDelta);
443 }
444 }
445}
446
448 const TargetSchedModel *SchedModel) {
449 bool HasBufferedModel =
450 SchedModel->hasInstrSchedModel() && SchedModel->getMicroOpBufferSize();
451 unsigned Combined = Zone.Available.size() + Zone.Pending.size();
452 return Combined <= PendingQueueLimit && HasBufferedModel;
453}
454
456 const TargetSchedModel *SchedModel) {
457 // pickOnlyChoice() releases pending instructions and checks for new hazards.
458 SUnit *OnlyChoice = Zone.pickOnlyChoice();
459 if (!shouldCheckPending(Zone, SchedModel) || Zone.Pending.empty())
460 return OnlyChoice;
461
462 return nullptr;
463}
464
466 const SchedCandidate &Preferred) {
467 LLVM_DEBUG({
468 dbgs() << "Prefer:\t\t";
469 DAG->dumpNode(*Preferred.SU);
470
471 if (Current.SU) {
472 dbgs() << "Not:\t";
473 DAG->dumpNode(*Current.SU);
474 }
475
476 dbgs() << "Reason:\t\t";
477 traceCandidate(Preferred);
478 });
479}
480
481// This function is mostly cut and pasted from
482// GenericScheduler::pickNodeFromQueue()
484 const CandPolicy &ZonePolicy,
485 const RegPressureTracker &RPTracker,
486 SchedCandidate &Cand, bool &IsPending,
487 bool IsBottomUp) {
488 const SIRegisterInfo *SRI = static_cast<const SIRegisterInfo *>(TRI);
490 unsigned SGPRPressure = 0;
491 unsigned VGPRPressure = 0;
492 unsigned AGPRPressure = 0;
493 IsPending = false;
494 if (DAG->isTrackingPressure()) {
495 if (!useGCNTrackers()) {
496 SGPRPressure = Pressure[AMDGPU::RegisterPressureSets::SReg_32];
497 VGPRPressure = Pressure[AMDGPU::RegisterPressureSets::VGPR_32];
498 AGPRPressure = Pressure[AMDGPU::RegisterPressureSets::AGPR_32];
499 } else {
500 GCNRPTracker *T = IsBottomUp
501 ? static_cast<GCNRPTracker *>(&UpwardTracker)
502 : static_cast<GCNRPTracker *>(&DownwardTracker);
503 SGPRPressure = T->getPressure().getSGPRNum();
504 VGPRPressure = T->getPressure().getArchVGPRNum();
505 AGPRPressure = T->getPressure().getAGPRNum();
506 }
507 }
508 LLVM_DEBUG(dbgs() << "Available Q:\n");
509 ReadyQueue &AQ = Zone.Available;
510 for (SUnit *SU : AQ) {
511
512 SchedCandidate TryCand(ZonePolicy);
513 initCandidate(TryCand, SU, Zone.isTop(), RPTracker, SRI, SGPRPressure,
514 VGPRPressure, AGPRPressure, IsBottomUp);
515 // Pass SchedBoundary only when comparing nodes from the same boundary.
516 SchedBoundary *ZoneArg = Cand.AtTop == TryCand.AtTop ? &Zone : nullptr;
517 tryCandidate(Cand, TryCand, ZoneArg);
518 if (TryCand.Reason != NoCand) {
519 // Initialize resource delta if needed in case future heuristics query it.
520 if (TryCand.ResDelta == SchedResourceDelta())
521 TryCand.initResourceDelta(Zone.DAG, SchedModel);
522 LLVM_DEBUG(printCandidateDecision(Cand, TryCand));
523 Cand.setBest(TryCand);
524 } else {
525 printCandidateDecision(TryCand, Cand);
526 }
527 }
528
529 if (!shouldCheckPending(Zone, SchedModel))
530 return;
531
532 LLVM_DEBUG(dbgs() << "Pending Q:\n");
533 ReadyQueue &PQ = Zone.Pending;
534 for (SUnit *SU : PQ) {
535
536 SchedCandidate TryCand(ZonePolicy);
537 initCandidate(TryCand, SU, Zone.isTop(), RPTracker, SRI, SGPRPressure,
538 VGPRPressure, AGPRPressure, IsBottomUp);
539 // Pass SchedBoundary only when comparing nodes from the same boundary.
540 SchedBoundary *ZoneArg = Cand.AtTop == TryCand.AtTop ? &Zone : nullptr;
541 tryPendingCandidate(Cand, TryCand, ZoneArg);
542 if (TryCand.Reason != NoCand) {
543 // Initialize resource delta if needed in case future heuristics query it.
544 if (TryCand.ResDelta == SchedResourceDelta())
545 TryCand.initResourceDelta(Zone.DAG, SchedModel);
546 LLVM_DEBUG(printCandidateDecision(Cand, TryCand));
547 IsPending = true;
548 Cand.setBest(TryCand);
549 } else {
550 printCandidateDecision(TryCand, Cand);
551 }
552 }
553}
554
555// This function is mostly cut and pasted from
556// GenericScheduler::pickNodeBidirectional()
558 bool &PickedPending) {
559 // Schedule as far as possible in the direction of no choice. This is most
560 // efficient, but also provides the best heuristics for CriticalPSets.
561 if (SUnit *SU = pickOnlyChoice(Bot, SchedModel)) {
562 IsTopNode = false;
563 return SU;
564 }
565 if (SUnit *SU = pickOnlyChoice(Top, SchedModel)) {
566 IsTopNode = true;
567 return SU;
568 }
569 // Set the bottom-up policy based on the state of the current bottom zone
570 // and the instructions outside the zone, including the top zone.
571 CandPolicy BotPolicy;
572 setPolicy(BotPolicy, /*IsPostRA=*/false, Bot, &Top);
573 // Set the top-down policy based on the state of the current top zone and
574 // the instructions outside the zone, including the bottom zone.
575 CandPolicy TopPolicy;
576 setPolicy(TopPolicy, /*IsPostRA=*/false, Top, &Bot);
577
578 bool BotPending = false;
579 // See if BotCand is still valid (because we previously scheduled from Top).
580 LLVM_DEBUG(dbgs() << "Picking from Bot:\n");
581 if (!BotCand.isValid() || BotCand.SU->isScheduled ||
582 BotCand.Policy != BotPolicy) {
583 BotCand.reset(CandPolicy());
584 pickNodeFromQueue(Bot, BotPolicy, DAG->getBotRPTracker(), BotCand,
585 BotPending,
586 /*IsBottomUp=*/true);
587 assert(BotCand.Reason != NoCand && "failed to find the first candidate");
588 } else {
590#ifndef NDEBUG
592 SchedCandidate TCand;
593 TCand.reset(CandPolicy());
594 pickNodeFromQueue(Bot, BotPolicy, DAG->getBotRPTracker(), TCand,
595 BotPending,
596 /*IsBottomUp=*/true);
597 assert(TCand.SU == BotCand.SU &&
598 "Last pick result should correspond to re-picking right now");
599 }
600#endif
601 }
602
603 bool TopPending = false;
604 // Check if the top Q has a better candidate.
605 LLVM_DEBUG(dbgs() << "Picking from Top:\n");
606 if (!TopCand.isValid() || TopCand.SU->isScheduled ||
607 TopCand.Policy != TopPolicy) {
608 TopCand.reset(CandPolicy());
609 pickNodeFromQueue(Top, TopPolicy, DAG->getTopRPTracker(), TopCand,
610 TopPending,
611 /*IsBottomUp=*/false);
612 assert(TopCand.Reason != NoCand && "failed to find the first candidate");
613 } else {
615#ifndef NDEBUG
617 SchedCandidate TCand;
618 TCand.reset(CandPolicy());
619 pickNodeFromQueue(Top, TopPolicy, DAG->getTopRPTracker(), TCand,
620 TopPending,
621 /*IsBottomUp=*/false);
622 assert(TCand.SU == TopCand.SU &&
623 "Last pick result should correspond to re-picking right now");
624 }
625#endif
626 }
627
628 // Pick best from BotCand and TopCand.
629 LLVM_DEBUG(dbgs() << "Top Cand: "; traceCandidate(TopCand);
630 dbgs() << "Bot Cand: "; traceCandidate(BotCand););
631 SchedCandidate Cand = BotPending ? TopCand : BotCand;
632 SchedCandidate TryCand = BotPending ? BotCand : TopCand;
633 PickedPending = BotPending && TopPending;
634
635 TryCand.Reason = NoCand;
636 if (BotPending || TopPending) {
637 PickedPending |= tryPendingCandidate(Cand, TopCand, nullptr);
638 } else {
639 tryCandidate(Cand, TryCand, nullptr);
640 }
641
642 if (TryCand.Reason != NoCand) {
643 Cand.setBest(TryCand);
644 }
645
646 LLVM_DEBUG(dbgs() << "Picking: "; traceCandidate(Cand););
647
648 IsTopNode = Cand.AtTop;
649 return Cand.SU;
650}
651
652// This function is mostly cut and pasted from
653// GenericScheduler::pickNode()
655 if (DAG->top() == DAG->bottom()) {
656 assert(Top.Available.empty() && Top.Pending.empty() &&
657 Bot.Available.empty() && Bot.Pending.empty() && "ReadyQ garbage");
658 return nullptr;
659 }
660 bool PickedPending;
661 SUnit *SU;
662 do {
663 PickedPending = false;
664 if (RegionPolicy.OnlyTopDown) {
666 if (!SU) {
667 CandPolicy NoPolicy;
668 TopCand.reset(NoPolicy);
669 pickNodeFromQueue(Top, NoPolicy, DAG->getTopRPTracker(), TopCand,
670 PickedPending,
671 /*IsBottomUp=*/false);
672 assert(TopCand.Reason != NoCand && "failed to find a candidate");
673 SU = TopCand.SU;
674 }
675 IsTopNode = true;
676 } else if (RegionPolicy.OnlyBottomUp) {
678 if (!SU) {
679 CandPolicy NoPolicy;
680 BotCand.reset(NoPolicy);
681 pickNodeFromQueue(Bot, NoPolicy, DAG->getBotRPTracker(), BotCand,
682 PickedPending,
683 /*IsBottomUp=*/true);
684 assert(BotCand.Reason != NoCand && "failed to find a candidate");
685 SU = BotCand.SU;
686 }
687 IsTopNode = false;
688 } else {
689 SU = pickNodeBidirectional(IsTopNode, PickedPending);
690 }
691 } while (SU->isScheduled);
692
693 if (PickedPending) {
694 unsigned ReadyCycle = IsTopNode ? SU->TopReadyCycle : SU->BotReadyCycle;
695 SchedBoundary &Zone = IsTopNode ? Top : Bot;
696 unsigned CurrentCycle = Zone.getCurrCycle();
697 if (ReadyCycle > CurrentCycle)
698 Zone.bumpCycle(ReadyCycle);
699
700 // FIXME: checkHazard() doesn't give information about which cycle the
701 // hazard will resolve so just keep bumping the cycle by 1. This could be
702 // made more efficient if checkHazard() returned more details.
703 while (Zone.checkHazard(SU))
704 Zone.bumpCycle(Zone.getCurrCycle() + 1);
705
706 Zone.releasePending();
707 }
708
709 if (SU->isTopReady())
710 Top.removeReady(SU);
711 if (SU->isBottomReady())
712 Bot.removeReady(SU);
713
714 LLVM_DEBUG(dbgs() << "Scheduling " << *SU << " " << *SU->getInstr());
715 return SU;
716}
717
718void GCNSchedStrategy::schedNode(SUnit *SU, bool IsTopNode) {
719 if (useGCNTrackers()) {
720 MachineInstr *MI = SU->getInstr();
721 IsTopNode ? DownwardTracker.advance(*MI) : UpwardTracker.recede(*MI);
722 }
723
724 return GenericScheduler::schedNode(SU, IsTopNode);
725}
726
731
734 if (!CurrentStage)
735 CurrentStage = SchedStages.begin();
736 else
737 CurrentStage++;
738
739 return CurrentStage != SchedStages.end();
740}
741
744 return std::next(CurrentStage) != SchedStages.end();
745}
746
748 SchedCandidate &TryCand,
749 SchedBoundary *Zone) const {
750 // Initialize the candidate if needed.
751 if (!Cand.isValid()) {
752 TryCand.Reason = NodeOrder;
753 return true;
754 }
755
756 // Bias PhysReg Defs and copies to their uses and defined respectively.
757 if (tryGreater(biasPhysReg(TryCand.SU, TryCand.AtTop),
758 biasPhysReg(Cand.SU, Cand.AtTop), TryCand, Cand, PhysReg))
759 return TryCand.Reason != NoCand;
760
761 // Avoid exceeding the target's limit.
762 if (DAG->isTrackingPressure() &&
763 tryPressure(TryCand.RPDelta.Excess, Cand.RPDelta.Excess, TryCand, Cand,
764 RegExcess, TRI, DAG->MF))
765 return TryCand.Reason != NoCand;
766
767 // Avoid increasing the max critical pressure in the scheduled region.
768 if (DAG->isTrackingPressure() &&
770 TryCand, Cand, RegCritical, TRI, DAG->MF))
771 return TryCand.Reason != NoCand;
772
773 bool SameBoundary = Zone != nullptr;
774 if (SameBoundary) {
777 TryCand, Cand, ResourceReduce))
778 return TryCand.Reason != NoCand;
780 Cand.ResDelta.DemandedResources, TryCand, Cand,
782 return TryCand.Reason != NoCand;
783 }
784
785 return false;
786}
787
800
805
807 SchedCandidate &TryCand,
808 SchedBoundary *Zone) const {
809 // Initialize the candidate if needed.
810 if (!Cand.isValid()) {
811 TryCand.Reason = NodeOrder;
812 return true;
813 }
814
815 // Avoid spilling by exceeding the register limit.
816 if (DAG->isTrackingPressure() &&
817 tryPressure(TryCand.RPDelta.Excess, Cand.RPDelta.Excess, TryCand, Cand,
818 RegExcess, TRI, DAG->MF))
819 return TryCand.Reason != NoCand;
820
821 // Bias PhysReg Defs and copies to their uses and defined respectively.
822 if (tryGreater(biasPhysReg(TryCand.SU, TryCand.AtTop),
823 biasPhysReg(Cand.SU, Cand.AtTop), TryCand, Cand, PhysReg))
824 return TryCand.Reason != NoCand;
825
826 bool SameBoundary = Zone != nullptr;
827 if (SameBoundary) {
828 // Prioritize instructions that read unbuffered resources by stall cycles.
829 if (tryLess(Zone->getLatencyStallCycles(TryCand.SU),
830 Zone->getLatencyStallCycles(Cand.SU), TryCand, Cand, Stall))
831 return TryCand.Reason != NoCand;
832
833 // Avoid critical resource consumption and balance the schedule.
836 TryCand, Cand, ResourceReduce))
837 return TryCand.Reason != NoCand;
839 Cand.ResDelta.DemandedResources, TryCand, Cand,
841 return TryCand.Reason != NoCand;
842
843 // Unconditionally try to reduce latency.
844 if (tryLatency(TryCand, Cand, *Zone))
845 return TryCand.Reason != NoCand;
846
847 // Weak edges are for clustering and other constraints.
848 if (tryLess(getWeakLeft(TryCand.SU, TryCand.AtTop),
849 getWeakLeft(Cand.SU, Cand.AtTop), TryCand, Cand, Weak))
850 return TryCand.Reason != NoCand;
851 }
852
853 // Keep clustered nodes together to encourage downstream peephole
854 // optimizations which may reduce resource requirements.
855 //
856 // This is a best effort to set things up for a post-RA pass. Optimizations
857 // like generating loads of multiple registers should ideally be done within
858 // the scheduler pass by combining the loads during DAG postprocessing.
859 unsigned CandZoneCluster = Cand.AtTop ? TopClusterID : BotClusterID;
860 unsigned TryCandZoneCluster = TryCand.AtTop ? TopClusterID : BotClusterID;
861 bool CandIsClusterSucc =
862 isTheSameCluster(CandZoneCluster, Cand.SU->ParentClusterIdx);
863 bool TryCandIsClusterSucc =
864 isTheSameCluster(TryCandZoneCluster, TryCand.SU->ParentClusterIdx);
865 if (tryGreater(TryCandIsClusterSucc, CandIsClusterSucc, TryCand, Cand,
866 Cluster))
867 return TryCand.Reason != NoCand;
868
869 // Avoid increasing the max critical pressure in the scheduled region.
870 if (DAG->isTrackingPressure() &&
872 TryCand, Cand, RegCritical, TRI, DAG->MF))
873 return TryCand.Reason != NoCand;
874
875 // Avoid increasing the max pressure of the entire region.
876 if (DAG->isTrackingPressure() &&
877 tryPressure(TryCand.RPDelta.CurrentMax, Cand.RPDelta.CurrentMax, TryCand,
878 Cand, RegMax, TRI, DAG->MF))
879 return TryCand.Reason != NoCand;
880
881 if (SameBoundary) {
882 // Fall through to original instruction order.
883 if ((Zone->isTop() && TryCand.SU->NodeNum < Cand.SU->NodeNum) ||
884 (!Zone->isTop() && TryCand.SU->NodeNum > Cand.SU->NodeNum)) {
885 TryCand.Reason = NodeOrder;
886 return true;
887 }
888 }
889 return false;
890}
891
897
898/// GCNMaxMemoryClauseSchedStrategy tries best to clause memory instructions as
899/// much as possible. This is achieved by:
900// 1. Prioritize clustered operations before stall latency heuristic.
901// 2. Prioritize long-latency-load before stall latency heuristic.
902///
903/// \param Cand provides the policy and current best candidate.
904/// \param TryCand refers to the next SUnit candidate, otherwise uninitialized.
905/// \param Zone describes the scheduled zone that we are extending, or nullptr
906/// if Cand is from a different zone than TryCand.
907/// \return \c true if TryCand is better than Cand (Reason is NOT NoCand)
909 SchedCandidate &TryCand,
910 SchedBoundary *Zone) const {
911 // Initialize the candidate if needed.
912 if (!Cand.isValid()) {
913 TryCand.Reason = NodeOrder;
914 return true;
915 }
916
917 // Bias PhysReg Defs and copies to their uses and defined respectively.
918 if (tryGreater(biasPhysReg(TryCand.SU, TryCand.AtTop),
919 biasPhysReg(Cand.SU, Cand.AtTop), TryCand, Cand, PhysReg))
920 return TryCand.Reason != NoCand;
921
922 if (DAG->isTrackingPressure()) {
923 // Avoid exceeding the target's limit.
924 if (tryPressure(TryCand.RPDelta.Excess, Cand.RPDelta.Excess, TryCand, Cand,
925 RegExcess, TRI, DAG->MF))
926 return TryCand.Reason != NoCand;
927
928 // Avoid increasing the max critical pressure in the scheduled region.
930 TryCand, Cand, RegCritical, TRI, DAG->MF))
931 return TryCand.Reason != NoCand;
932 }
933
934 // MaxMemoryClause-specific: We prioritize clustered instructions as we would
935 // get more benefit from clausing these memory instructions.
936 unsigned CandZoneCluster = Cand.AtTop ? TopClusterID : BotClusterID;
937 unsigned TryCandZoneCluster = TryCand.AtTop ? TopClusterID : BotClusterID;
938 bool CandIsClusterSucc =
939 isTheSameCluster(CandZoneCluster, Cand.SU->ParentClusterIdx);
940 bool TryCandIsClusterSucc =
941 isTheSameCluster(TryCandZoneCluster, TryCand.SU->ParentClusterIdx);
942 if (tryGreater(TryCandIsClusterSucc, CandIsClusterSucc, TryCand, Cand,
943 Cluster))
944 return TryCand.Reason != NoCand;
945
946 // We only compare a subset of features when comparing nodes between
947 // Top and Bottom boundary. Some properties are simply incomparable, in many
948 // other instances we should only override the other boundary if something
949 // is a clear good pick on one boundary. Skip heuristics that are more
950 // "tie-breaking" in nature.
951 bool SameBoundary = Zone != nullptr;
952 if (SameBoundary) {
953 // For loops that are acyclic path limited, aggressively schedule for
954 // latency. Within an single cycle, whenever CurrMOps > 0, allow normal
955 // heuristics to take precedence.
956 if (Rem.IsAcyclicLatencyLimited && !Zone->getCurrMOps() &&
957 tryLatency(TryCand, Cand, *Zone))
958 return TryCand.Reason != NoCand;
959
960 // MaxMemoryClause-specific: Prioritize long latency memory load
961 // instructions in top-bottom order to hide more latency. The mayLoad check
962 // is used to exclude store-like instructions, which we do not want to
963 // scheduler them too early.
964 bool TryMayLoad =
965 TryCand.SU->isInstr() && TryCand.SU->getInstr()->mayLoad();
966 bool CandMayLoad = Cand.SU->isInstr() && Cand.SU->getInstr()->mayLoad();
967
968 if (TryMayLoad || CandMayLoad) {
969 bool TryLongLatency =
970 TryCand.SU->Latency > 10 * Cand.SU->Latency && TryMayLoad;
971 bool CandLongLatency =
972 10 * TryCand.SU->Latency < Cand.SU->Latency && CandMayLoad;
973
974 if (tryGreater(Zone->isTop() ? TryLongLatency : CandLongLatency,
975 Zone->isTop() ? CandLongLatency : TryLongLatency, TryCand,
976 Cand, Stall))
977 return TryCand.Reason != NoCand;
978 }
979 // Prioritize instructions that read unbuffered resources by stall cycles.
980 if (tryLess(Zone->getLatencyStallCycles(TryCand.SU),
981 Zone->getLatencyStallCycles(Cand.SU), TryCand, Cand, Stall))
982 return TryCand.Reason != NoCand;
983 }
984
985 if (SameBoundary) {
986 // Weak edges are for clustering and other constraints.
987 if (tryLess(getWeakLeft(TryCand.SU, TryCand.AtTop),
988 getWeakLeft(Cand.SU, Cand.AtTop), TryCand, Cand, Weak))
989 return TryCand.Reason != NoCand;
990 }
991
992 // Avoid increasing the max pressure of the entire region.
993 if (DAG->isTrackingPressure() &&
994 tryPressure(TryCand.RPDelta.CurrentMax, Cand.RPDelta.CurrentMax, TryCand,
995 Cand, RegMax, TRI, DAG->MF))
996 return TryCand.Reason != NoCand;
997
998 if (SameBoundary) {
999 // Avoid critical resource consumption and balance the schedule.
1002 TryCand, Cand, ResourceReduce))
1003 return TryCand.Reason != NoCand;
1005 Cand.ResDelta.DemandedResources, TryCand, Cand,
1007 return TryCand.Reason != NoCand;
1008
1009 // Avoid serializing long latency dependence chains.
1010 // For acyclic path limited loops, latency was already checked above.
1011 if (!RegionPolicy.DisableLatencyHeuristic && TryCand.Policy.ReduceLatency &&
1012 !Rem.IsAcyclicLatencyLimited && tryLatency(TryCand, Cand, *Zone))
1013 return TryCand.Reason != NoCand;
1014
1015 // Fall through to original instruction order.
1016 if (Zone->isTop() == (TryCand.SU->NodeNum < Cand.SU->NodeNum)) {
1017 assert(TryCand.SU->NodeNum != Cand.SU->NodeNum);
1018 TryCand.Reason = NodeOrder;
1019 return true;
1020 }
1021 }
1022
1023 return false;
1024}
1025
1027 MachineSchedContext *C, std::unique_ptr<MachineSchedStrategy> S)
1028 : ScheduleDAGMILive(C, std::move(S)), ST(MF.getSubtarget<GCNSubtarget>()),
1029 MFI(*MF.getInfo<SIMachineFunctionInfo>()),
1030 StartingOccupancy(MFI.getOccupancy()), MinOccupancy(StartingOccupancy),
1031 RegionLiveOuts(this, /*IsLiveOut=*/true) {
1032
1033 // We want regions with a single MI to be scheduled so that we can reason
1034 // about them correctly during scheduling stages that move MIs between regions
1035 // (e.g., rematerialization).
1037 LLVM_DEBUG(dbgs() << "Starting occupancy is " << StartingOccupancy << ".\n");
1038 if (RelaxedOcc) {
1039 MinOccupancy = std::min(MFI.getMinAllowedOccupancy(), StartingOccupancy);
1040 if (MinOccupancy != StartingOccupancy)
1041 LLVM_DEBUG(dbgs() << "Allowing Occupancy drops to " << MinOccupancy
1042 << ".\n");
1043 }
1044}
1045
1046std::unique_ptr<GCNSchedStage>
1047GCNScheduleDAGMILive::createSchedStage(GCNSchedStageID SchedStageID) {
1048 switch (SchedStageID) {
1050 return std::make_unique<OccInitialScheduleStage>(SchedStageID, *this);
1052 return std::make_unique<RewriteMFMAFormStage>(SchedStageID, *this);
1054 return std::make_unique<UnclusteredHighRPStage>(SchedStageID, *this);
1056 return std::make_unique<ClusteredLowOccStage>(SchedStageID, *this);
1058 return std::make_unique<PreRARematStage>(SchedStageID, *this);
1060 return std::make_unique<ILPInitialScheduleStage>(SchedStageID, *this);
1062 return std::make_unique<MemoryClauseInitialScheduleStage>(SchedStageID,
1063 *this);
1065 return std::make_unique<LiveIntervalRPStage>(SchedStageID, *this);
1066 }
1067
1068 llvm_unreachable("Unknown SchedStageID.");
1069}
1070
1072 // Collect all scheduling regions. The actual scheduling is performed in
1073 // GCNScheduleDAGMILive::finalizeSchedule.
1074 Regions.push_back(std::pair(RegionBegin, RegionEnd));
1075}
1076
1078GCNScheduleDAGMILive::getRealRegPressure(unsigned RegionIdx) const {
1079 if (Regions[RegionIdx].first == Regions[RegionIdx].second)
1080 return llvm::getRegPressure(MRI, LiveIns[RegionIdx]);
1082 RPTracker.advance(Regions[RegionIdx].first, Regions[RegionIdx].second,
1083 &LiveIns[RegionIdx]);
1084 return RPTracker.moveMaxPressure();
1085}
1086
1088 MachineBasicBlock::iterator RegionEnd) {
1089 assert(RegionBegin != RegionEnd && "Region must not be empty");
1090 return &*skipDebugInstructionsBackward(std::prev(RegionEnd), RegionBegin);
1091}
1092
1093void GCNScheduleDAGMILive::computeBlockPressure(unsigned RegionIdx,
1094 const MachineBasicBlock *MBB) {
1095 GCNDownwardRPTracker RPTracker(*LIS);
1096
1097 // If the block has the only successor then live-ins of that successor are
1098 // live-outs of the current block. We can reuse calculated live set if the
1099 // successor will be sent to scheduling past current block.
1100
1101 // However, due to the bug in LiveInterval analysis it may happen that two
1102 // predecessors of the same successor block have different lane bitmasks for
1103 // a live-out register. Workaround that by sticking to one-to-one relationship
1104 // i.e. one predecessor with one successor block.
1105 const MachineBasicBlock *OnlySucc = nullptr;
1106 if (MBB->succ_size() == 1) {
1107 auto *Candidate = *MBB->succ_begin();
1108 if (!Candidate->empty() && Candidate->pred_size() == 1) {
1109 SlotIndexes *Ind = LIS->getSlotIndexes();
1110 if (Ind->getMBBStartIdx(MBB) < Ind->getMBBStartIdx(Candidate))
1111 OnlySucc = Candidate;
1112 }
1113 }
1114
1115 // Scheduler sends regions from the end of the block upwards.
1116 size_t CurRegion = RegionIdx;
1117 for (size_t E = Regions.size(); CurRegion != E; ++CurRegion)
1118 if (Regions[CurRegion].first->getParent() != MBB)
1119 break;
1120 --CurRegion;
1121
1122 auto I = MBB->begin();
1123 auto LiveInIt = MBBLiveIns.find(MBB);
1124 auto &Rgn = Regions[CurRegion];
1125 auto *NonDbgMI = &*skipDebugInstructionsForward(Rgn.first, Rgn.second);
1126 if (LiveInIt != MBBLiveIns.end()) {
1127 auto LiveIn = std::move(LiveInIt->second);
1128 RPTracker.reset(*MBB->begin(), MBB->end(), &LiveIn);
1129 MBBLiveIns.erase(LiveInIt);
1130 } else {
1131 I = Rgn.first;
1132 auto LRS = BBLiveInMap.lookup(NonDbgMI);
1133#ifdef EXPENSIVE_CHECKS
1134 assert(isEqual(getLiveRegsBefore(*NonDbgMI, *LIS), LRS));
1135#endif
1136 RPTracker.reset(*I, I->getParent()->end(), &LRS);
1137 }
1138
1139 for (;;) {
1140 I = RPTracker.getNext();
1141
1142 if (Regions[CurRegion].first == I || NonDbgMI == I) {
1143 LiveIns[CurRegion] = RPTracker.getLiveRegs();
1144 RPTracker.clearMaxPressure();
1145 }
1146
1147 if (Regions[CurRegion].second == I) {
1148 Pressure[CurRegion] = RPTracker.moveMaxPressure();
1149 if (CurRegion-- == RegionIdx)
1150 break;
1151 auto &Rgn = Regions[CurRegion];
1152 NonDbgMI = &*skipDebugInstructionsForward(Rgn.first, Rgn.second);
1153 }
1154 RPTracker.advanceBeforeNext();
1155 RPTracker.advanceToNext();
1156 }
1157
1158 if (OnlySucc) {
1159 if (I != MBB->end()) {
1160 RPTracker.advanceBeforeNext();
1161 RPTracker.advanceToNext();
1162 RPTracker.advance(MBB->end());
1163 }
1164 MBBLiveIns[OnlySucc] = RPTracker.moveLiveRegs();
1165 }
1166}
1167
1169GCNScheduleDAGMILive::getRegionLiveInMap() const {
1170 assert(!Regions.empty());
1171 std::vector<MachineInstr *> RegionFirstMIs;
1172 RegionFirstMIs.reserve(Regions.size());
1173 for (auto &[RegionBegin, RegionEnd] : reverse(Regions))
1174 RegionFirstMIs.push_back(
1176
1177 return getLiveRegMap(RegionFirstMIs, /*After=*/false, *LIS);
1178}
1179
1181GCNScheduleDAGMILive::getRegionLiveOutMap() const {
1182 assert(!Regions.empty());
1183 std::vector<MachineInstr *> RegionLastMIs;
1184 RegionLastMIs.reserve(Regions.size());
1185 for (auto &[RegionBegin, RegionEnd] : reverse(Regions)) {
1186 // Skip empty regions.
1187 if (RegionBegin == RegionEnd)
1188 continue;
1189 RegionLastMIs.push_back(getLastMIForRegion(RegionBegin, RegionEnd));
1190 }
1191 return getLiveRegMap(RegionLastMIs, /*After=*/true, *LIS);
1192}
1193
1195 IdxToInstruction.clear();
1196
1197 RegionLiveRegMap =
1198 IsLiveOut ? DAG->getRegionLiveOutMap() : DAG->getRegionLiveInMap();
1199 for (unsigned I = 0; I < DAG->Regions.size(); I++) {
1200 auto &[RegionBegin, RegionEnd] = DAG->Regions[I];
1201 // Skip empty regions.
1202 if (RegionBegin == RegionEnd)
1203 continue;
1204 MachineInstr *RegionKey =
1205 IsLiveOut ? getLastMIForRegion(RegionBegin, RegionEnd) : &*RegionBegin;
1206 IdxToInstruction[I] = RegionKey;
1207 }
1208}
1209
1211 // Start actual scheduling here. This function is called by the base
1212 // MachineScheduler after all regions have been recorded by
1213 // GCNScheduleDAGMILive::schedule().
1214 LiveIns.resize(Regions.size());
1215 Pressure.resize(Regions.size());
1216 RegionsWithHighRP.resize(static_cast<unsigned>(Regions.size()));
1217 RegionsWithExcessRP.resize(static_cast<unsigned>(Regions.size()));
1218 RegionsWithIGLPInstrs.resize(static_cast<unsigned>(Regions.size()));
1219 RegionsWithHighRP.reset();
1220 RegionsWithExcessRP.reset();
1221 RegionsWithIGLPInstrs.reset();
1222
1223 runSchedStages();
1224}
1225
1226void GCNScheduleDAGMILive::runSchedStages() {
1227 LLVM_DEBUG(dbgs() << "All regions recorded, starting actual scheduling.\n");
1228
1229 GCNSchedStrategy &S = static_cast<GCNSchedStrategy &>(*SchedImpl);
1230 if (!Regions.empty()) {
1231 BBLiveInMap = getRegionLiveInMap();
1232 if (S.useGCNTrackers())
1233 RegionLiveOuts.buildLiveRegMap();
1234 }
1235
1236#ifdef DUMP_MAX_REG_PRESSURE
1240 LIS->dump();
1241 }
1242#endif
1243
1244 while (S.advanceStage()) {
1245 auto Stage = createSchedStage(S.getCurrentStage());
1246 if (!Stage->initGCNSchedStage())
1247 continue;
1248
1249 for (auto Region : Regions) {
1250 RegionBegin = Region.first;
1251 RegionEnd = Region.second;
1252 // Setup for scheduling the region and check whether it should be skipped.
1253 if (!Stage->initGCNRegion()) {
1254 Stage->advanceRegion();
1255 exitRegion();
1256 continue;
1257 }
1258
1259 if (S.useGCNTrackers()) {
1260 const unsigned RegionIdx = Stage->getRegionIdx();
1261 S.getDownwardTracker().reset(MRI, LiveIns[RegionIdx]);
1263 MRI, RegionLiveOuts.getLiveRegsForRegionIdx(RegionIdx));
1264 }
1265
1267 Stage->finalizeGCNRegion();
1268 Stage->advanceRegion();
1269 exitRegion();
1270 }
1271
1272 Stage->finalizeGCNSchedStage();
1273 }
1274
1275#ifdef DUMP_MAX_REG_PRESSURE
1279 LIS->dump();
1280 }
1281#endif
1282}
1283
1284#ifndef NDEBUG
1286 switch (StageID) {
1288 OS << "Max Occupancy Initial Schedule";
1289 break;
1291 OS << "Instruction Rewriting Reschedule";
1292 break;
1294 OS << "Unclustered High Register Pressure Reschedule";
1295 break;
1297 OS << "Clustered Low Occupancy Reschedule";
1298 break;
1300 OS << "Pre-RA Rematerialize";
1301 break;
1303 OS << "Max ILP Initial Schedule";
1304 break;
1306 OS << "Max memory clause Initial Schedule";
1307 break;
1309 OS << "Live Interval RP Reschedule";
1310 break;
1311 }
1312
1313 return OS;
1314}
1315#endif
1316
1320
1322 if (!DAG.LIS)
1323 return false;
1324
1325 LLVM_DEBUG(dbgs() << "Starting scheduling stage: " << StageID << "\n");
1326 return true;
1327}
1328
1329void RewriteMFMAFormStage::findReachingDefs(
1330 MachineOperand &UseMO, LiveIntervals *LIS,
1331 SmallVectorImpl<SlotIndex> &DefIdxs) {
1332 MachineInstr *UseMI = UseMO.getParent();
1333 LiveInterval &UseLI = LIS->getInterval(UseMO.getReg());
1334 VNInfo *VNI = UseLI.getVNInfoAt(LIS->getInstructionIndex(*UseMI));
1335
1336 // If the def is not a PHI, then it must be the only reaching def.
1337 if (!VNI->isPHIDef()) {
1338 DefIdxs.push_back(VNI->def);
1339 return;
1340 }
1341
1342 SmallPtrSet<MachineBasicBlock *, 8> Visited = {UseMI->getParent()};
1344
1345 // Mark the predecessor blocks for traversal
1346 for (MachineBasicBlock *PredMBB : UseMI->getParent()->predecessors()) {
1347 Worklist.push_back(PredMBB);
1348 Visited.insert(PredMBB);
1349 }
1350
1351 while (!Worklist.empty()) {
1352 MachineBasicBlock *CurrMBB = Worklist.pop_back_val();
1353
1354 SlotIndex CurrMBBEnd = LIS->getMBBEndIdx(CurrMBB);
1355 VNInfo *VNI = UseLI.getVNInfoAt(CurrMBBEnd.getPrevSlot());
1356
1357 MachineBasicBlock *DefMBB = LIS->getMBBFromIndex(VNI->def);
1358
1359 // If there is a def in this block, then add it to the list. This is the
1360 // reaching def of this path.
1361 if (!VNI->isPHIDef()) {
1362 DefIdxs.push_back(VNI->def);
1363 continue;
1364 }
1365
1366 for (MachineBasicBlock *PredMBB : DefMBB->predecessors()) {
1367 if (Visited.insert(PredMBB).second)
1368 Worklist.push_back(PredMBB);
1369 }
1370 }
1371}
1372
1373void RewriteMFMAFormStage::findReachingUses(
1374 const MachineInstr *DefMI, LiveIntervals *LIS,
1375 SmallVectorImpl<MachineOperand *> &ReachingUses) {
1376 SlotIndex DefIdx = LIS->getInstructionIndex(*DefMI);
1377 for (MachineOperand &UseMO :
1378 DAG.MRI.use_nodbg_operands(DefMI->getOperand(0).getReg())) {
1379 SmallVector<SlotIndex, 8> ReachingDefIndexes;
1380 findReachingDefs(UseMO, LIS, ReachingDefIndexes);
1381
1382 // If we find a use that contains this DefMI in its reachingDefs, then it is
1383 // a reaching use.
1384 if (any_of(ReachingDefIndexes, [DefIdx](SlotIndex RDIdx) {
1385 return SlotIndex::isSameInstr(RDIdx, DefIdx);
1386 }))
1387 ReachingUses.push_back(&UseMO);
1388 }
1389}
1390
1392 // We only need to run this pass if the architecture supports AGPRs.
1393 // Additionally, we don't use AGPRs at occupancy levels above 1 so there
1394 // is no need for this pass in that case, either.
1395 const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
1396 if (!ST.hasGFX90AInsts() || MFI.getMinWavesPerEU() > 1)
1397 return false;
1398
1399 RegionsWithExcessArchVGPR.resize(static_cast<unsigned>(DAG.Regions.size()));
1400 RegionsWithExcessArchVGPR.reset();
1401 for (unsigned Region = 0; Region < DAG.Regions.size(); Region++) {
1403 if (PressureBefore.getArchVGPRNum() > ST.getAddressableNumArchVGPRs())
1404 RegionsWithExcessArchVGPR[Region] = true;
1405 }
1406
1407 if (RegionsWithExcessArchVGPR.none())
1408 return false;
1409
1410 TII = ST.getInstrInfo();
1411 SRI = ST.getRegisterInfo();
1412
1413 std::vector<std::pair<MachineInstr *, unsigned>> RewriteCands;
1416
1417 if (!initHeuristics(RewriteCands, CopyForUse, CopyForDef))
1418 return false;
1419
1420 int64_t Cost = getRewriteCost(RewriteCands, CopyForUse, CopyForDef);
1421
1422 // If we haven't found the beneficial conditions, prefer the VGPR form which
1423 // may result in less cross RC copies.
1424 if (Cost > 0)
1425 return false;
1426
1427 return rewrite(RewriteCands);
1428}
1429
1432 return false;
1433
1435 return false;
1436
1437 if (DAG.RegionsWithHighRP.none() && DAG.RegionsWithExcessRP.none())
1438 return false;
1439
1440 SavedMutations.swap(DAG.Mutations);
1441 DAG.addMutation(
1443
1444 InitialOccupancy = DAG.MinOccupancy;
1445 // Aggressively try to reduce register pressure in the unclustered high RP
1446 // stage. Temporarily increase occupancy target in the region.
1447 TempTargetOccupancy = MFI.getMaxWavesPerEU() > DAG.MinOccupancy
1448 ? InitialOccupancy + 1
1449 : InitialOccupancy;
1450 IsAnyRegionScheduled = false;
1451 S.SGPRLimitBias = S.HighRPSGPRBias;
1452 S.VGPRLimitBias = S.HighRPVGPRBias;
1453
1454 LLVM_DEBUG(
1455 dbgs()
1456 << "Retrying function scheduling without clustering. "
1457 "Aggressively try to reduce register pressure to achieve occupancy "
1458 << TempTargetOccupancy << ".\n");
1459
1460 return true;
1461}
1462
1465 return false;
1466
1468 return false;
1469
1470 // Don't bother trying to improve ILP in lower RP regions if occupancy has not
1471 // been dropped. All regions will have already been scheduled with the ideal
1472 // occupancy targets.
1473 if (DAG.StartingOccupancy <= DAG.MinOccupancy)
1474 return false;
1475
1476 LLVM_DEBUG(
1477 dbgs() << "Retrying function scheduling with lowest recorded occupancy "
1478 << DAG.MinOccupancy << ".\n");
1479 return true;
1480}
1481
1483 // FIXME: This pass will invalidate cached BBLiveInMap and MBBLiveIns for
1484 // regions inbetween the defs and region we sinked the def to. Will need to be
1485 // fixed if there is another pass after this pass.
1486 assert(!S.hasNextStage());
1487
1488 if (!GCNSchedStage::initGCNSchedStage() || DAG.Regions.size() <= 1)
1489 return false;
1490
1491 // Set up "spilling targets" for all regions.
1492 const Function &F = MF.getFunction();
1493 unsigned MaxSGPRs = ST.getMaxNumSGPRs(F);
1494 unsigned MaxVGPRs = ST.getMaxNumVGPRs(F);
1495
1496 const unsigned VGPRBlockSize = MFI.getDynamicVGPRBlockSize();
1497 bool HasVectorRegisterExcess = false;
1498 for (const GCNRegPressure &RP : DAG.Pressure) {
1499 if (GCNRPTarget(MaxSGPRs, MaxVGPRs, MF, RP).hasVectorRegisterExcess()) {
1500 HasVectorRegisterExcess = true;
1501 break;
1502 }
1503 }
1504 if (HasVectorRegisterExcess || DAG.MinOccupancy >= MFI.getMaxWavesPerEU()) {
1505 // In addition to register usage being above addressable limits, occupancy
1506 // below the minimum is considered like "spilling" as well.
1507 TargetOcc = std::nullopt;
1508 } else {
1509 // There is no spilling and room to improve occupancy; set up "increased
1510 // occupancy targets" for all regions.
1511 TargetOcc = DAG.MinOccupancy + 1;
1512 MaxSGPRs = ST.getMaxNumSGPRs(*TargetOcc, false);
1513 MaxVGPRs = ST.getMaxNumVGPRs(*TargetOcc, VGPRBlockSize);
1514 }
1515
1516 LLVM_DEBUG({
1517 dbgs() << "In function ";
1518 MF.getFunction().printAsOperand(dbgs(), false);
1519 dbgs() << ": rematerializing to ";
1520 if (TargetOcc) {
1521 dbgs() << "increase occupancy from " << *TargetOcc - 1 << '\n';
1522 } else {
1523 dbgs() << "reduce spilling (minimum target occupancy is "
1524 << MFI.getMinWavesPerEU() << ")\n";
1525 }
1526 });
1527
1528 LiveOuts.reserve(DAG.Regions.size());
1529 DAG.RegionLiveOuts.buildLiveRegMap();
1530 for (unsigned RegionIdx : seq(DAG.Regions.size()))
1531 LiveOuts.push_back(DAG.RegionLiveOuts.getLiveRegsForRegionIdx(RegionIdx));
1532
1533 Strategy = std::make_unique<GCNRematStrategy>(MF, DAG.Regions, DAG.LiveIns,
1534 LiveOuts, *DAG.LIS, *DAG.MBFI);
1535 if (TargetOcc.has_value()) {
1536 // Rematerialization is likely to move instructions into higher frequency
1537 // regions, increasing their total sum latency. This is acceptable if we are
1538 // eliminating spills in the process, but when the goal is increasing
1539 // occupancy we get nothing out of rematerialization if occupancy is not
1540 // increased in the end; in such cases we want to be able to roll back
1541 // rematerializations.
1542 Strategy->startRecordingRemats();
1543 }
1544
1545 RescheduleRegions.resize(DAG.Regions.size());
1546 MutableArrayRef<GCNRegPressure> MaxPressure = DAG.Pressure;
1547 Strategy->rematerializeFor(MaxSGPRs, MaxVGPRs,
1548 /*ReduceSpill=*/!TargetOcc.has_value(),
1549 RescheduleRegions, &MaxPressure);
1550 if (RescheduleRegions.none())
1551 return false;
1552
1553 // Reflect changes in the DAG and compute achieved occupancy.
1554 LLVM_DEBUG(dbgs() << "==== REMAT RESULTS ====\n");
1555 for (unsigned RegionIdx : RescheduleRegions.set_bits()) {
1556 DAG.RegionLiveOuts.getLiveRegsForRegionIdx(RegionIdx) = LiveOuts[RegionIdx];
1557 LLVM_DEBUG(dbgs() << '[' << RegionIdx << "] Achieved occupancy "
1558 << DAG.Pressure[RegionIdx].getOccupancy(ST, VGPRBlockSize)
1559 << '\n');
1560 }
1561 AchievedOcc = MFI.getMaxWavesPerEU();
1562 for (const GCNRegPressure &RP : DAG.Pressure)
1563 AchievedOcc = std::min(AchievedOcc, RP.getOccupancy(ST, VGPRBlockSize));
1564
1565 LLVM_DEBUG({
1566 dbgs() << "Retrying function scheduling with new min. occupancy of "
1567 << AchievedOcc << " from rematerializing (original was "
1568 << DAG.MinOccupancy;
1569 if (TargetOcc)
1570 dbgs() << ", target was " << *TargetOcc;
1571 dbgs() << ")\n";
1572 });
1573
1574 DAG.setTargetOccupancy(getStageTargetOccupancy());
1575 return true;
1576}
1577
1579 DAG.finishBlock();
1580 LLVM_DEBUG(dbgs() << "Ending scheduling stage: " << StageID << "\n");
1581}
1582
1584 SavedMutations.swap(DAG.Mutations);
1585 S.SGPRLimitBias = S.VGPRLimitBias = 0;
1586 if (DAG.MinOccupancy > InitialOccupancy) {
1587 assert(IsAnyRegionScheduled);
1589 << " stage successfully increased occupancy to "
1590 << DAG.MinOccupancy << '\n');
1591 } else if (!IsAnyRegionScheduled) {
1592 assert(DAG.MinOccupancy == InitialOccupancy);
1594 << ": No regions scheduled, min occupancy stays at "
1595 << DAG.MinOccupancy << ", MFI occupancy stays at "
1596 << MFI.getOccupancy() << ".\n");
1597 }
1598
1600}
1601
1603 // Skip empty scheduling region.
1604 if (DAG.begin() == DAG.end())
1605 return false;
1606
1607 // Check whether this new region is also a new block.
1608 if (DAG.RegionBegin->getParent() != CurrentMBB)
1609 setupNewBlock();
1610
1611 unsigned NumRegionInstrs =
1612 static_cast<unsigned>(std::distance(DAG.begin(), DAG.end()));
1613 DAG.enterRegion(CurrentMBB, DAG.begin(), DAG.end(), NumRegionInstrs);
1614
1615 // Skip regions with 1 schedulable instruction.
1616 if (DAG.begin() == std::prev(DAG.end()))
1617 return false;
1618
1619 LLVM_DEBUG(dbgs() << "********** MI Scheduling **********\n");
1620 LLVM_DEBUG(dbgs() << MF.getName() << ":" << printMBBReference(*CurrentMBB)
1621 << " " << CurrentMBB->getName()
1622 << "\n From: " << *DAG.begin() << " To: ";
1623 if (DAG.RegionEnd != CurrentMBB->end()) dbgs() << *DAG.RegionEnd;
1624 else dbgs() << "End";
1625 dbgs() << " RegionInstrs: " << NumRegionInstrs << '\n');
1626
1627 // Save original instruction order before scheduling for possible revert.
1628 Unsched.clear();
1629 Unsched.reserve(DAG.NumRegionInstrs);
1632 const SIInstrInfo *SII = static_cast<const SIInstrInfo *>(DAG.TII);
1633 for (auto &I : DAG) {
1634 Unsched.push_back(&I);
1635 if (SII->isIGLPMutationOnly(I.getOpcode()))
1636 DAG.RegionsWithIGLPInstrs[RegionIdx] = true;
1637 }
1638 } else {
1639 for (auto &I : DAG)
1640 Unsched.push_back(&I);
1641 }
1642
1643 PressureBefore = DAG.Pressure[RegionIdx];
1644
1645 LLVM_DEBUG(
1646 dbgs() << "Pressure before scheduling:\nRegion live-ins:"
1647 << print(DAG.LiveIns[RegionIdx], DAG.MRI)
1648 << "Region live-in pressure: "
1649 << print(llvm::getRegPressure(DAG.MRI, DAG.LiveIns[RegionIdx]))
1650 << "Region register pressure: " << print(PressureBefore));
1651
1652 S.HasHighPressure = false;
1653 S.KnownExcessRP = isRegionWithExcessRP();
1654
1655 if (DAG.RegionsWithIGLPInstrs[RegionIdx] &&
1657 SavedMutations.clear();
1658 SavedMutations.swap(DAG.Mutations);
1659 bool IsInitialStage = StageID == GCNSchedStageID::OccInitialSchedule ||
1661 DAG.addMutation(createIGroupLPDAGMutation(
1662 IsInitialStage ? AMDGPU::SchedulingPhase::Initial
1664 }
1665
1666 return true;
1667}
1668
1670 // Only reschedule regions that have excess register pressure (i.e. spilling)
1671 // or had minimum occupancy at the beginning of the stage (as long as
1672 // rescheduling of previous regions did not make occupancy drop back down to
1673 // the initial minimum).
1674 unsigned DynamicVGPRBlockSize = DAG.MFI.getDynamicVGPRBlockSize();
1675 // If no region has been scheduled yet, the DAG has not yet been updated with
1676 // the occupancy target. So retrieve it from the temporary.
1677 unsigned CurrentTargetOccupancy =
1678 IsAnyRegionScheduled ? DAG.MinOccupancy : TempTargetOccupancy;
1679 if (!DAG.RegionsWithExcessRP[RegionIdx] &&
1680 (CurrentTargetOccupancy <= InitialOccupancy ||
1681 DAG.Pressure[RegionIdx].getOccupancy(ST, DynamicVGPRBlockSize) !=
1682 InitialOccupancy))
1683 return false;
1684
1685 bool IsSchedulingThisRegion = GCNSchedStage::initGCNRegion();
1686 // If this is the first region scheduled during this stage, make the target
1687 // occupancy changes in the DAG and MFI.
1688 if (!IsAnyRegionScheduled && IsSchedulingThisRegion) {
1689 IsAnyRegionScheduled = true;
1690 if (MFI.getMaxWavesPerEU() > DAG.MinOccupancy)
1691 DAG.setTargetOccupancy(TempTargetOccupancy);
1692 }
1693 return IsSchedulingThisRegion;
1694}
1695
1697 // We may need to reschedule this region if it wasn't rescheduled in the last
1698 // stage, or if we found it was testing critical register pressure limits in
1699 // the unclustered reschedule stage. The later is because we may not have been
1700 // able to raise the min occupancy in the previous stage so the region may be
1701 // overly constrained even if it was already rescheduled.
1702 if (!DAG.RegionsWithHighRP[RegionIdx])
1703 return false;
1704
1706}
1707
1709 return !RevertAllRegions && RescheduleRegions[RegionIdx] &&
1711}
1712
1714 if (CurrentMBB)
1715 DAG.finishBlock();
1716
1717 CurrentMBB = DAG.RegionBegin->getParent();
1718 DAG.startBlock(CurrentMBB);
1719 // Get real RP for the region if it hasn't be calculated before. After the
1720 // initial schedule stage real RP will be collected after scheduling.
1724 DAG.computeBlockPressure(RegionIdx, CurrentMBB);
1725}
1726
1728 DAG.Regions[RegionIdx] = std::pair(DAG.RegionBegin, DAG.RegionEnd);
1729 if (S.HasHighPressure)
1730 DAG.RegionsWithHighRP[RegionIdx] = true;
1731
1732 // Revert scheduling if we have dropped occupancy or there is some other
1733 // reason that the original schedule is better.
1735
1736 if (DAG.RegionsWithIGLPInstrs[RegionIdx] &&
1738 SavedMutations.swap(DAG.Mutations);
1739}
1740
1743 // When the goal is to increase occupancy, all regions must reach the target
1744 // occupancy for rematerializations to be possibly useful, otherwise we will
1745 // just hurt latency for no benefit. If minimum occupancy drops below the
1746 // target there is no point in trying to re-schedule further regions.
1747 if (!TargetOcc)
1748 return;
1749 RegionReverts.emplace_back(RegionIdx, Unsched, PressureBefore);
1750 if (DAG.MinOccupancy < *TargetOcc) {
1751 LLVM_DEBUG(dbgs() << "Region " << RegionIdx
1752 << " cannot meet occupancy target, interrupting "
1753 "re-scheduling in all regions\n");
1754 RevertAllRegions = true;
1755 }
1756}
1757
1759 // Check the results of scheduling.
1760 PressureAfter = DAG.getRealRegPressure(RegionIdx);
1761
1762 LLVM_DEBUG(dbgs() << "Pressure after scheduling: " << print(PressureAfter));
1763 LLVM_DEBUG(dbgs() << "Region: " << RegionIdx << ".\n");
1764
1765 unsigned DynamicVGPRBlockSize = DAG.MFI.getDynamicVGPRBlockSize();
1766
1767 bool UnifiedVGPRFile = ST.hasGFX90AInsts();
1768 unsigned VectorCriticalLimit =
1769 UnifiedVGPRFile ? S.UnifiedVGPRCriticalLimit : S.VGPRCriticalLimit;
1770 // Fitting the combined occupancy budget does not rule out spilling in one
1771 // bank. Keep the per-bank excess checks before taking this early exit.
1772 if (PressureAfter.getSGPRNum() <= S.SGPRCriticalLimit &&
1773 PressureAfter.getVGPRNum(UnifiedVGPRFile) <= VectorCriticalLimit &&
1774 (!UnifiedVGPRFile ||
1775 (PressureAfter.getArchVGPRNum() <= S.VGPRExcessLimit &&
1776 PressureAfter.getAGPRNum() <= S.AGPRExcessLimit))) {
1777 DAG.Pressure[RegionIdx] = PressureAfter;
1778
1779 // Early out if we have achieved the occupancy target.
1780 LLVM_DEBUG(dbgs() << "Pressure in desired limits, done.\n");
1781 return;
1782 }
1783
1784 unsigned TargetOccupancy = std::min(
1785 S.getTargetOccupancy(), ST.getOccupancyWithWorkGroupSizes(MF).second);
1786 unsigned WavesAfter = std::min(
1787 TargetOccupancy, PressureAfter.getOccupancy(ST, DynamicVGPRBlockSize));
1788 unsigned WavesBefore = std::min(
1789 TargetOccupancy, PressureBefore.getOccupancy(ST, DynamicVGPRBlockSize));
1790 LLVM_DEBUG(dbgs() << "Occupancy before scheduling: " << WavesBefore
1791 << ", after " << WavesAfter << ".\n");
1792
1793 // We may not be able to keep the current target occupancy because of the just
1794 // scheduled region. We might still be able to revert scheduling if the
1795 // occupancy before was higher, or if the current schedule has register
1796 // pressure higher than the excess limits which could lead to more spilling.
1797 unsigned NewOccupancy = std::max(WavesAfter, WavesBefore);
1798
1799 // Allow memory bound functions to drop to 4 waves if not limited by an
1800 // attribute.
1801 if (WavesAfter < WavesBefore && WavesAfter < DAG.MinOccupancy &&
1802 WavesAfter >= MFI.getMinAllowedOccupancy()) {
1803 LLVM_DEBUG(dbgs() << "Function is memory bound, allow occupancy drop up to "
1804 << MFI.getMinAllowedOccupancy() << " waves\n");
1805 NewOccupancy = WavesAfter;
1806 }
1807
1808 if (NewOccupancy < DAG.MinOccupancy) {
1809 DAG.MinOccupancy = NewOccupancy;
1810 MFI.limitOccupancy(DAG.MinOccupancy);
1811 LLVM_DEBUG(dbgs() << "Occupancy lowered for the function to "
1812 << DAG.MinOccupancy << ".\n");
1813 }
1814 // The maximum number of arch VGPR on non-unified register file, or the
1815 // maximum VGPR + AGPR in the unified register file case.
1816 unsigned MaxVGPRs = ST.getMaxNumVGPRs(MF);
1817 // The maximum number of arch VGPR for both unified and non-unified register
1818 // file.
1819 unsigned MaxArchVGPRs = std::min(MaxVGPRs, ST.getAddressableNumArchVGPRs());
1820 unsigned MaxSGPRs = ST.getMaxNumSGPRs(MF);
1821
1822 if (PressureAfter.getVGPRNum(ST.hasGFX90AInsts()) > MaxVGPRs ||
1823 PressureAfter.getArchVGPRNum() > MaxArchVGPRs ||
1824 PressureAfter.getAGPRNum() > MaxArchVGPRs ||
1825 PressureAfter.getSGPRNum() > MaxSGPRs) {
1826 DAG.RegionsWithHighRP[RegionIdx] = true;
1827 DAG.RegionsWithExcessRP[RegionIdx] = true;
1828 }
1829
1830 // Revert if this region's schedule would cause a drop in occupancy or
1831 // spilling.
1832 if (shouldRevertScheduling(WavesAfter)) {
1834 std::tie(DAG.RegionBegin, DAG.RegionEnd) = DAG.Regions[RegionIdx];
1835 } else {
1836 DAG.Pressure[RegionIdx] = PressureAfter;
1837 }
1838}
1839
1840unsigned
1841GCNSchedStage::computeSUnitReadyCycle(const SUnit &SU, unsigned CurrCycle,
1842 DenseMap<unsigned, unsigned> &ReadyCycles,
1843 const TargetSchedModel &SM) {
1844 unsigned ReadyCycle = CurrCycle;
1845 for (auto &D : SU.Preds) {
1846 if (D.isAssignedRegDep()) {
1847 MachineInstr *DefMI = D.getSUnit()->getInstr();
1848 unsigned Latency = SM.computeInstrLatency(DefMI);
1849 unsigned DefReady = ReadyCycles[DAG.getSUnit(DefMI)->NodeNum];
1850 ReadyCycle = std::max(ReadyCycle, DefReady + Latency);
1851 }
1852 }
1853 ReadyCycles[SU.NodeNum] = ReadyCycle;
1854 return ReadyCycle;
1855}
1856
1857#ifndef NDEBUG
1859 bool operator()(std::pair<MachineInstr *, unsigned> A,
1860 std::pair<MachineInstr *, unsigned> B) const {
1861 return A.second < B.second;
1862 }
1863};
1864
1865static void printScheduleModel(std::set<std::pair<MachineInstr *, unsigned>,
1866 EarlierIssuingCycle> &ReadyCycles) {
1867 if (ReadyCycles.empty())
1868 return;
1869 unsigned BBNum = ReadyCycles.begin()->first->getParent()->getNumber();
1870 dbgs() << "\n################## Schedule time ReadyCycles for MBB : " << BBNum
1871 << " ##################\n# Cycle #\t\t\tInstruction "
1872 " "
1873 " \n";
1874 unsigned IPrev = 1;
1875 for (auto &I : ReadyCycles) {
1876 if (I.second > IPrev + 1)
1877 dbgs() << "****************************** BUBBLE OF " << I.second - IPrev
1878 << " CYCLES DETECTED ******************************\n\n";
1879 dbgs() << "[ " << I.second << " ] : " << *I.first << "\n";
1880 IPrev = I.second;
1881 }
1882}
1883#endif
1884
1886GCNSchedStage::getScheduleMetrics(const std::vector<SUnit> &InputSchedule) {
1887#ifndef NDEBUG
1888 std::set<std::pair<MachineInstr *, unsigned>, EarlierIssuingCycle>
1889 ReadyCyclesSorted;
1890#endif
1891 const TargetSchedModel &SM = ST.getInstrInfo()->getSchedModel();
1892 unsigned SumBubbles = 0;
1893 DenseMap<unsigned, unsigned> ReadyCycles;
1894 unsigned CurrCycle = 0;
1895 for (auto &SU : InputSchedule) {
1896 unsigned ReadyCycle =
1897 computeSUnitReadyCycle(SU, CurrCycle, ReadyCycles, SM);
1898 SumBubbles += ReadyCycle - CurrCycle;
1899#ifndef NDEBUG
1900 ReadyCyclesSorted.insert(std::make_pair(SU.getInstr(), ReadyCycle));
1901#endif
1902 CurrCycle = ++ReadyCycle;
1903 }
1904#ifndef NDEBUG
1905 LLVM_DEBUG(
1906 printScheduleModel(ReadyCyclesSorted);
1907 dbgs() << "\n\t"
1908 << "Metric: "
1909 << (SumBubbles
1910 ? (SumBubbles * ScheduleMetrics::ScaleFactor) / CurrCycle
1911 : 1)
1912 << "\n\n");
1913#endif
1914
1915 return ScheduleMetrics(CurrCycle, SumBubbles);
1916}
1917
1920#ifndef NDEBUG
1921 std::set<std::pair<MachineInstr *, unsigned>, EarlierIssuingCycle>
1922 ReadyCyclesSorted;
1923#endif
1924 const TargetSchedModel &SM = ST.getInstrInfo()->getSchedModel();
1925 unsigned SumBubbles = 0;
1926 DenseMap<unsigned, unsigned> ReadyCycles;
1927 unsigned CurrCycle = 0;
1928 for (auto &MI : DAG) {
1929 SUnit *SU = DAG.getSUnit(&MI);
1930 if (!SU)
1931 continue;
1932 unsigned ReadyCycle =
1933 computeSUnitReadyCycle(*SU, CurrCycle, ReadyCycles, SM);
1934 SumBubbles += ReadyCycle - CurrCycle;
1935#ifndef NDEBUG
1936 ReadyCyclesSorted.insert(std::make_pair(SU->getInstr(), ReadyCycle));
1937#endif
1938 CurrCycle = ++ReadyCycle;
1939 }
1940#ifndef NDEBUG
1941 LLVM_DEBUG(
1942 printScheduleModel(ReadyCyclesSorted);
1943 dbgs() << "\n\t"
1944 << "Metric: "
1945 << (SumBubbles
1946 ? (SumBubbles * ScheduleMetrics::ScaleFactor) / CurrCycle
1947 : 1)
1948 << "\n\n");
1949#endif
1950
1951 return ScheduleMetrics(CurrCycle, SumBubbles);
1952}
1953
1954bool GCNSchedStage::shouldRevertScheduling(unsigned WavesAfter) {
1955 if (WavesAfter < DAG.MinOccupancy)
1956 return true;
1957
1958 // For dynamic VGPR mode, we don't want to waste any VGPR blocks.
1959 if (DAG.MFI.isDynamicVGPREnabled()) {
1960 unsigned BlocksBefore = AMDGPU::IsaInfo::getAllocatedNumVGPRBlocks(
1961 ST, PressureBefore.getVGPRNum(false),
1962 DAG.MFI.getDynamicVGPRBlockSize());
1963 unsigned BlocksAfter = AMDGPU::IsaInfo::getAllocatedNumVGPRBlocks(
1964 ST, PressureAfter.getVGPRNum(false), DAG.MFI.getDynamicVGPRBlockSize());
1965 if (BlocksAfter > BlocksBefore)
1966 return true;
1967 }
1968
1969 return false;
1970}
1971
1974 return false;
1975
1977 return true;
1978
1979 if (mayCauseSpilling(WavesAfter))
1980 return true;
1981
1982 return false;
1983}
1984
1986 // If RP is not reduced in the unclustered reschedule stage, revert to the
1987 // old schedule.
1988 if ((WavesAfter <=
1989 PressureBefore.getOccupancy(ST, DAG.MFI.getDynamicVGPRBlockSize()) &&
1990 mayCauseSpilling(WavesAfter)) ||
1992 LLVM_DEBUG(dbgs() << "Unclustered reschedule did not help.\n");
1993 return true;
1994 }
1995
1996 // Do not attempt to relax schedule even more if we are already spilling.
1998 return false;
1999
2000 LLVM_DEBUG(
2001 dbgs()
2002 << "\n\t *** In shouldRevertScheduling ***\n"
2003 << " *********** BEFORE UnclusteredHighRPStage ***********\n");
2004 ScheduleMetrics MBefore = getScheduleMetrics(DAG.SUnits);
2005 LLVM_DEBUG(
2006 dbgs()
2007 << "\n *********** AFTER UnclusteredHighRPStage ***********\n");
2009 unsigned OldMetric = MBefore.getMetric();
2010 unsigned NewMetric = MAfter.getMetric();
2011 unsigned WavesBefore = std::min(
2012 S.getTargetOccupancy(),
2013 PressureBefore.getOccupancy(ST, DAG.MFI.getDynamicVGPRBlockSize()));
2014 unsigned Profit =
2015 ((WavesAfter * ScheduleMetrics::ScaleFactor) / WavesBefore *
2017 NewMetric) /
2019 LLVM_DEBUG(dbgs() << "\tMetric before " << MBefore << "\tMetric after "
2020 << MAfter << "Profit: " << Profit << "\n");
2021 return Profit < ScheduleMetrics::ScaleFactor;
2022}
2023
2026 return false;
2027
2029 return true;
2030
2031 if (mayCauseSpilling(WavesAfter))
2032 return true;
2033
2034 return false;
2035}
2036
2038 return GCNSchedStage::shouldRevertScheduling(WavesAfter) ||
2039 mayCauseSpilling(WavesAfter);
2040}
2041
2043 if (mayCauseSpilling(WavesAfter))
2044 return true;
2045
2046 return false;
2047}
2048
2050 unsigned WavesAfter) {
2051 return mayCauseSpilling(WavesAfter);
2052}
2053
2055 "amdgpu-lirp-reschedule", cl::Hidden,
2056 cl::desc("Enable live interval RP reschedule stage"), cl::init(true));
2057
2059 "amdgpu-lirp-threshold", cl::Hidden,
2060 cl::desc("Percent increase of live interval RP over instant pressure to "
2061 "trigger rescheduling"),
2062 cl::init(10));
2063
2065 "amdgpu-lirp-vgpr-reduction", cl::Hidden,
2066 cl::desc(
2067 "Reduction factor (percent) for VGPR threshold during live interval RP "
2068 "reschedule stage"),
2069 cl::init(90));
2070
2072 "amdgpu-lirp-instant-lower-bound", cl::Hidden,
2073 cl::desc("Lower bound (percent of the VGPR excess limit) on instant RP, "
2074 "below which a region is skipped"),
2075 cl::init(10));
2076
2079 return false;
2080
2082 return false;
2083
2084 if (!S.VGPRThresholdPercent) {
2085 LLVM_DEBUG(dbgs() << "LIRP: expected VGPRThresholdPercent to be enabled, "
2086 "not using live interval RP reschedule stage\n");
2087 return false;
2088 }
2089
2090 return true;
2091}
2092
2094 unsigned InstantRP = DAG.Pressure[RegionIdx].getArchVGPRNum();
2095 auto [RegionBegin, RegionEnd] = DAG.Regions[RegionIdx];
2096 if (RegionBegin == RegionEnd)
2097 return false;
2098
2099 unsigned LIRP = estimateGreedyVGPRPressure(
2100 RegionBegin, RegionEnd, DAG.LiveIns[RegionIdx], *DAG.getLIS(),
2101 DAG.MF.getRegInfo(), static_cast<const SIRegisterInfo &>(*DAG.TRI));
2102
2103 unsigned NewVGPRThresholdPercent =
2104 (S.VGPRThresholdPercent * LiveIntervalRPVGPRReduction + 99) / 100;
2105
2106 LLVM_DEBUG(dbgs() << "LIRP: Region " << RegionIdx
2107 << ", VGPRThresholdPercent: " << S.VGPRThresholdPercent
2108 << " -> " << NewVGPRThresholdPercent
2109 << ", VGPRExcessLimit=" << S.VGPRExcessLimit
2110 << ", VGPRCriticalLimit=" << S.VGPRCriticalLimit
2111 << ", InstantRP=" << InstantRP << ", LIRP=" << LIRP);
2112
2113 bool DoRescheduling = false;
2114 // Lower bound on InstantRP to skip over tiny regions.
2115 unsigned InstantRPLowerBound =
2116 S.VGPRExcessLimit * LiveIntervalRPInstantLowerBound / 100;
2117 if (LIRP > S.VGPRExcessLimit) {
2118 LLVM_DEBUG(dbgs() << " [LIRP exceeds the limit (" << S.VGPRExcessLimit
2119 << "), rescheduling]");
2120 DoRescheduling = true;
2121 } else if (LIRP > InstantRP && InstantRP > InstantRPLowerBound) {
2122 unsigned IncreasePercent = ((LIRP - InstantRP) * 100) / InstantRP;
2123 if (IncreasePercent > LiveIntervalRPThreshold) {
2124 LLVM_DEBUG(dbgs() << " [" << IncreasePercent << "% > "
2125 << LiveIntervalRPThreshold << "%, rescheduling]");
2126 DoRescheduling = true;
2127 }
2128 }
2129 LLVM_DEBUG(dbgs() << '\n');
2130
2131 if (DoRescheduling && GCNSchedStage::initGCNRegion()) {
2132 SavedVGPRExcessLimit = S.VGPRExcessLimit;
2133 SavedVGPRCriticalLimit = S.VGPRCriticalLimit;
2134 SavedUnifiedVGPRCriticalLimit = S.UnifiedVGPRCriticalLimit;
2135 SavedVGPRThresholdPercent = S.VGPRThresholdPercent;
2136 S.VGPRThresholdPercent = NewVGPRThresholdPercent;
2137 return true;
2138 }
2139
2140 return false;
2141}
2142
2144 S.VGPRExcessLimit = SavedVGPRExcessLimit;
2145 S.VGPRCriticalLimit = SavedVGPRCriticalLimit;
2146 S.UnifiedVGPRCriticalLimit = SavedUnifiedVGPRCriticalLimit;
2147 S.VGPRThresholdPercent = SavedVGPRThresholdPercent;
2149}
2150
2151bool GCNSchedStage::mayCauseSpilling(unsigned WavesAfter) {
2152 if (WavesAfter <= MFI.getMinWavesPerEU() && isRegionWithExcessRP() &&
2154 LLVM_DEBUG(dbgs() << "New pressure will result in more spilling.\n");
2155 return true;
2156 }
2157
2158 return false;
2159}
2160
2162 ArrayRef<MachineInstr *> MIOrder) {
2163 assert(static_cast<size_t>(std::distance(DAG.Regions[RegionIdx].first,
2164 DAG.Regions[RegionIdx].second)) ==
2165 MIOrder.size() &&
2166 "instruction number mismatch");
2167 if (MIOrder.empty())
2168 return;
2169
2170 LLVM_DEBUG(dbgs() << "Reverting scheduling for region " << RegionIdx << '\n');
2171
2172 // Reconstruct MI sequence by moving instructions in desired order before
2173 // the current region's start.
2174 MachineBasicBlock::iterator RegionEnd = DAG.Regions[RegionIdx].first;
2175 MachineBasicBlock *MBB = MIOrder.front()->getParent();
2176 for (MachineInstr *MI : MIOrder) {
2177 // Either move the next MI in order before the end of the region or move the
2178 // region end past the MI if it is at the correct position.
2179 MachineBasicBlock::iterator MII = MI->getIterator();
2180 if (MII != RegionEnd) {
2181 // Will subsequent splice move MI up past a non-debug instruction?
2182 bool NonDebugReordered =
2183 !MI->isDebugInstr() &&
2184 skipDebugInstructionsForward(RegionEnd, MII) != MII;
2185 MBB->splice(RegionEnd, MBB, MI);
2186 // Only update LiveIntervals information if non-debug instructions are
2187 // reordered. Otherwise debug instructions could cause code generation to
2188 // change.
2189 if (NonDebugReordered)
2190 DAG.LIS->handleMove(*MI, true);
2191 } else {
2192 // MI is already at the expected position. However, earlier splices in
2193 // this loop may have changed neighboring slot indices, so this MI's
2194 // slot index can become non-monotonic w.r.t. the physical MBB order.
2195 // Only re-seat when monotonicity is actually violated to avoid
2196 // unnecessary LiveInterval changes that could perturb scheduling.
2197 if (!MI->isDebugInstr()) {
2198 SlotIndex MIIdx = DAG.LIS->getInstructionIndex(*MI);
2199 SlotIndex PrevIdx = DAG.LIS->getSlotIndexes()->getIndexBefore(*MI);
2200 if (PrevIdx >= MIIdx)
2201 DAG.LIS->handleMove(*MI, true);
2202 }
2203 ++RegionEnd;
2204 }
2205 if (MI->isDebugInstr()) {
2206 LLVM_DEBUG(dbgs() << "Scheduling " << *MI);
2207 continue;
2208 }
2209
2210 // Reset read-undef flags and update them later.
2212 DAG.ShouldTrackLaneMasks);
2213 LLVM_DEBUG(dbgs() << "Scheduling " << *MI);
2214 }
2215
2216 // The region end doesn't change throughout scheduling since it itself is
2217 // outside the region (whether that is a MBB end or a terminator MI).
2218 assert(RegionEnd == DAG.Regions[RegionIdx].second && "region end mismatch");
2219 DAG.Regions[RegionIdx].first = MIOrder.front();
2220}
2221
2222/// Returns true if reaching def \p RD will be in AGPR form after the rewrite
2223/// and so needs no bridge copy: a candidate MFMA in \p RewriteSet, an
2224/// AV_MOV_*_IMM_PSEUDO, or a copy from a candidate src2 reg in \p CandSrc2Regs.
2225/// A non-candidate MFMA stays in VGPR form and still needs a bridge.
2227 MachineInstr *RD, const SmallPtrSetImpl<MachineInstr *> &RewriteSet,
2228 const DenseSet<Register> &CandSrc2Regs, const SIInstrInfo &TII) {
2229 if (TII.isMAI(*RD))
2230 return RewriteSet.contains(RD);
2231 if (RD->getOpcode() == AMDGPU::AV_MOV_B32_IMM_PSEUDO ||
2232 RD->getOpcode() == AMDGPU::AV_MOV_B64_IMM_PSEUDO)
2233 return true;
2234 if (RD->isCopy() && CandSrc2Regs.contains(RD->getOperand(1).getReg()))
2235 return true;
2236 return false;
2237}
2238
2239bool RewriteMFMAFormStage::hasUseRequiringVGPR(
2240 ArrayRef<SlotIndex> Src2ReachingDefs,
2241 const SmallPtrSetImpl<MachineInstr *> &RewriteSet) {
2242 for (SlotIndex RDIdx : Src2ReachingDefs) {
2243 const MachineInstr *RD = DAG.LIS->getInstructionFromIndex(RDIdx);
2245 findReachingUses(RD, DAG.LIS, ReachingUses);
2246 for (const MachineOperand *UseMO : ReachingUses) {
2247 const MachineInstr *UseMI = UseMO->getParent();
2248 if (UseMI->isCopy())
2249 continue;
2250 if (TII->isMAI(*UseMI) && RewriteSet.contains(UseMI))
2251 continue;
2252 return true;
2253 }
2254 }
2255 return false;
2256}
2257
2258void RewriteMFMAFormStage::resetRewriteCandsToVGPR(
2259 ArrayRef<std::pair<MachineInstr *, unsigned>> RewriteCands) {
2260 for (auto [MI, OriginalOpcode] : RewriteCands) {
2261 assert(TII->isMAI(*MI));
2262 const TargetRegisterClass *ADefRC =
2263 DAG.MRI.getRegClass(MI->getOperand(0).getReg());
2264 const TargetRegisterClass *VDefRC = SRI->getEquivalentVGPRClass(ADefRC);
2265 DAG.MRI.setRegClass(MI->getOperand(0).getReg(), VDefRC);
2266 MI->setDesc(TII->get(OriginalOpcode));
2267
2268 MachineOperand *Src2 = TII->getNamedOperand(*MI, AMDGPU::OpName::src2);
2269 if (!Src2->isReg())
2270 continue;
2271
2272 // Have to get src types separately since subregs may cause C and D
2273 // registers to be different types even though the actual operand is
2274 // the same size.
2275 const TargetRegisterClass *AUseRC = DAG.MRI.getRegClass(Src2->getReg());
2276 const TargetRegisterClass *VUseRC = SRI->getEquivalentVGPRClass(AUseRC);
2277 DAG.MRI.setRegClass(Src2->getReg(), VUseRC);
2278 }
2279}
2280
2281bool RewriteMFMAFormStage::isRewriteCandidate(MachineInstr *MI) const {
2282 if (!static_cast<const SIInstrInfo *>(DAG.TII)->isMAI(*MI))
2283 return false;
2284 if (AMDGPU::getAGPRFormOp(MI->getOpcode()) == -1)
2285 return false;
2286 // Reject candidates whose users force an unavoidable bridge copy.
2287 Register DstReg = MI->getOperand(0).getReg();
2288 for (const MachineInstr &UseMI : DAG.MRI.use_nodbg_instructions(DstReg)) {
2289 if (!TII->isMAI(UseMI) && !UseMI.isCopy())
2290 return false;
2291 }
2292 return true;
2293}
2294
2295bool RewriteMFMAFormStage::initHeuristics(
2296 std::vector<std::pair<MachineInstr *, unsigned>> &RewriteCands,
2297 DenseMap<MachineBasicBlock *, std::set<Register>> &CopyForUse,
2298 SmallPtrSetImpl<MachineInstr *> &CopyForDef) {
2299 bool Changed = false;
2300
2301 // Collect the candidate group, its members share AGPR-form operands
2302 // post-rewrite, so reaching defs feeding any member don't need bridge copy.
2303 SmallPtrSet<MachineInstr *, 16> RewriteSet;
2304 DenseSet<Register> CandSrc2Regs;
2305 for (MachineBasicBlock &MBB : MF) {
2306 for (MachineInstr &MI : MBB) {
2307 if (!isRewriteCandidate(&MI))
2308 continue;
2309 RewriteSet.insert(&MI);
2310 MachineOperand *Src2 = TII->getNamedOperand(MI, AMDGPU::OpName::src2);
2311 if (Src2 && Src2->isReg())
2312 CandSrc2Regs.insert(Src2->getReg());
2313 }
2314 }
2315
2316 // Prepare for the heuristics
2317 for (MachineBasicBlock &MBB : MF) {
2318 for (MachineInstr &MI : MBB) {
2319 if (!isRewriteCandidate(&MI))
2320 continue;
2321
2322 int ReplacementOp = AMDGPU::getAGPRFormOp(MI.getOpcode());
2323 assert(ReplacementOp != -1);
2324
2325 RewriteCands.push_back({&MI, MI.getOpcode()});
2326 MI.setDesc(TII->get(ReplacementOp));
2327
2328 MachineOperand *Src2 = TII->getNamedOperand(MI, AMDGPU::OpName::src2);
2329 if (Src2->isReg()) {
2330 SmallVector<SlotIndex, 8> Src2ReachingDefs;
2331 findReachingDefs(*Src2, DAG.LIS, Src2ReachingDefs);
2332
2333 // If src2 has a use that must remain VGPR, it cannot be reclassified to
2334 // AGPR.
2335 bool Src2NeedsVGPR = hasUseRequiringVGPR(Src2ReachingDefs, RewriteSet);
2336 Src2NeedsVGPRCache[&MI] = Src2NeedsVGPR;
2337
2338 for (SlotIndex RDIdx : Src2ReachingDefs) {
2339 MachineInstr *RD = DAG.LIS->getInstructionFromIndex(RDIdx);
2340 if (!Src2NeedsVGPR &&
2341 isReachingDefAGPRForm(RD, RewriteSet, CandSrc2Regs, *TII))
2342 continue;
2343 CopyForDef.insert(RD);
2344 }
2345 }
2346
2347 MachineOperand &Dst = MI.getOperand(0);
2348 SmallVector<MachineOperand *, 8> DstReachingUses;
2349
2350 findReachingUses(&MI, DAG.LIS, DstReachingUses);
2351
2352 for (MachineOperand *RUOp : DstReachingUses) {
2353 MachineInstr *UserMI = RUOp->getParent();
2354 // Group members read the AGPR result directly.
2355 if (TII->isMAI(*UserMI) && RewriteSet.contains(UserMI))
2356 continue;
2357
2358 // For any user of the result of the MFMA which is not an MFMA, we
2359 // insert a copy. For a given register, we will only insert one copy
2360 // per user block.
2361 CopyForUse[UserMI->getParent()].insert(RUOp->getReg());
2362
2363 if (TII->isMAI(*UserMI))
2364 continue;
2365
2366 SmallVector<SlotIndex, 8> DstUsesReachingDefs;
2367 findReachingDefs(*RUOp, DAG.LIS, DstUsesReachingDefs);
2368
2369 for (SlotIndex RDIndex : DstUsesReachingDefs) {
2370 MachineInstr *RD = DAG.LIS->getInstructionFromIndex(RDIndex);
2371 if (TII->isMAI(*RD))
2372 continue;
2373
2374 // For any definition of the user of the MFMA which is not an MFMA,
2375 // we insert a copy. We do this to transform all the reaching defs
2376 // of this use to AGPR. By doing this, we can insert a copy from
2377 // AGPR to VGPR at the user rather than after the MFMA.
2378 CopyForDef.insert(RD);
2379 }
2380 }
2381
2382 // Do the rewrite to allow for updated RP calculation.
2383 const TargetRegisterClass *VDefRC = DAG.MRI.getRegClass(Dst.getReg());
2384 const TargetRegisterClass *ADefRC = SRI->getEquivalentAGPRClass(VDefRC);
2385 DAG.MRI.setRegClass(Dst.getReg(), ADefRC);
2386 if (Src2->isReg()) {
2387 // Have to get src types separately since subregs may cause C and D
2388 // registers to be different types even though the actual operand is
2389 // the same size.
2390 const TargetRegisterClass *VUseRC = DAG.MRI.getRegClass(Src2->getReg());
2391 const TargetRegisterClass *AUseRC = SRI->getEquivalentAGPRClass(VUseRC);
2392 DAG.MRI.setRegClass(Src2->getReg(), AUseRC);
2393 }
2394 Changed = true;
2395 }
2396 }
2397
2398 return Changed;
2399}
2400
2401int64_t RewriteMFMAFormStage::getRewriteCost(
2402 ArrayRef<std::pair<MachineInstr *, unsigned>> RewriteCands,
2403 const DenseMap<MachineBasicBlock *, std::set<Register>> &CopyForUse,
2404 const SmallPtrSetImpl<MachineInstr *> &CopyForDef) {
2405 MachineBlockFrequencyInfo *MBFI = DAG.MBFI;
2406
2407 int64_t BestSpillCost = 0;
2408 int64_t Cost = 0;
2409 uint64_t EntryFreq = MBFI->getEntryFreq().getFrequency();
2410
2411 std::pair<unsigned, unsigned> MaxVectorRegs =
2412 ST.getMaxNumVectorRegs(MF.getFunction());
2413 unsigned ArchVGPRThreshold = MaxVectorRegs.first;
2414 unsigned AGPRThreshold = MaxVectorRegs.second;
2415 unsigned CombinedThreshold = ST.getMaxNumVGPRs(MF);
2416
2417 for (unsigned Region = 0; Region < DAG.Regions.size(); Region++) {
2418 if (!RegionsWithExcessArchVGPR[Region])
2419 continue;
2420
2421 GCNRegPressure &PressureBefore = DAG.Pressure[Region];
2422 unsigned SpillCostBefore = PressureBefore.getVGPRSpills(
2423 MF, ArchVGPRThreshold, AGPRThreshold, CombinedThreshold);
2424
2425 // For the cases we care about (i.e. ArchVGPR usage is greater than the
2426 // addressable limit), rewriting alone should bring pressure to manageable
2427 // level. If we find any such region, then the rewrite is potentially
2428 // beneficial.
2429 GCNRegPressure PressureAfter = DAG.getRealRegPressure(Region);
2430 unsigned SpillCostAfter = PressureAfter.getVGPRSpills(
2431 MF, ArchVGPRThreshold, AGPRThreshold, CombinedThreshold);
2432
2433 uint64_t BlockFreq =
2434 MBFI->getBlockFreq(DAG.Regions[Region].first->getParent())
2435 .getFrequency();
2436
2437 bool RelativeFreqIsDenom = EntryFreq > BlockFreq;
2438 uint64_t RelativeFreq = EntryFreq && BlockFreq
2439 ? (RelativeFreqIsDenom ? EntryFreq / BlockFreq
2440 : BlockFreq / EntryFreq)
2441 : 1;
2442
2443 // This assumes perfect spilling / splitting -- using one spill / copy
2444 // instruction and one restoreFrom / copy for each excess register,
2445 int64_t SpillCost = ((int)SpillCostAfter - (int)SpillCostBefore) * 2;
2446
2447 // Also account for the block frequency.
2448 if (RelativeFreqIsDenom)
2449 SpillCost /= (int64_t)RelativeFreq;
2450 else
2451 SpillCost *= (int64_t)RelativeFreq;
2452
2453 // If we have increased spilling in any block, just bail.
2454 if (SpillCost > 0) {
2455 resetRewriteCandsToVGPR(RewriteCands);
2456 return SpillCost;
2457 }
2458
2459 if (SpillCost < BestSpillCost)
2460 BestSpillCost = SpillCost;
2461 }
2462
2463 // Set the cost to the largest decrease in spill cost in order to not double
2464 // count spill reductions.
2465 Cost = BestSpillCost;
2466 assert(Cost <= 0);
2467
2468 unsigned CopyCost = 0;
2469
2470 // For each CopyForDef, increase the cost by the register size while
2471 // accounting for block frequency.
2472 for (MachineInstr *DefMI : CopyForDef) {
2473 Register DefReg = DefMI->getOperand(0).getReg();
2474 uint64_t DefFreq =
2475 EntryFreq
2476 ? MBFI->getBlockFreq(DefMI->getParent()).getFrequency() / EntryFreq
2477 : 1;
2478
2479 const TargetRegisterClass *RC = DAG.MRI.getRegClass(DefReg);
2480 CopyCost += static_cast<unsigned>(RC->getCopyCost() * DefFreq);
2481 }
2482
2483 // Account for CopyForUse copies in each block that the register is used.
2484 for (auto &[UseBlock, UseRegs] : CopyForUse) {
2485 uint64_t UseFreq =
2486 EntryFreq ? MBFI->getBlockFreq(UseBlock).getFrequency() / EntryFreq : 1;
2487
2488 for (Register UseReg : UseRegs) {
2489 const TargetRegisterClass *RC = DAG.MRI.getRegClass(UseReg);
2490 CopyCost += static_cast<unsigned>(RC->getCopyCost() * UseFreq);
2491 }
2492 }
2493
2494 // Reset the classes that were changed to AGPR for better register bank
2495 // analysis. We must do rewriting after copy-insertion, as some defs of the
2496 // register may require VGPR. Additionally, if we bail out and don't perform
2497 // the rewrite then these need to be restored anyway.
2498 resetRewriteCandsToVGPR(RewriteCands);
2499
2500 return Cost + CopyCost;
2501}
2502
2503bool RewriteMFMAFormStage::rewrite(
2504 ArrayRef<std::pair<MachineInstr *, unsigned>> RewriteCands) {
2505 DenseMap<MachineInstr *, unsigned> FirstMIToRegion;
2506 DenseMap<MachineInstr *, unsigned> LastMIToRegion;
2507
2508 for (unsigned Region = 0; Region < DAG.Regions.size(); Region++) {
2509 RegionBoundaries Entry = DAG.Regions[Region];
2510 if (Entry.first == Entry.second)
2511 continue;
2512
2513 FirstMIToRegion[&*Entry.first] = Region;
2514 if (Entry.second != Entry.first->getParent()->end())
2515 LastMIToRegion[&*Entry.second] = Region;
2516 }
2517
2518 // Rewrite the MFMAs to AGPR, and insert any copies as needed.
2519 // The general assumption of the algorithm (and the previous cost calculation)
2520 // is that it is better to insert the copies in the MBB of the def of the src2
2521 // operands, and in the MBB of the user of the dest operands. This is based on
2522 // the assumption that the MFMAs are likely to appear in loop bodies, while
2523 // the src2 and dest operands are live-in / live-out of the loop. Due to this
2524 // design, the algorithm for finding copy insertion points is more
2525 // complicated.
2526 //
2527 // There are three main cases to handle: 1. the reaching defs of the src2
2528 // operands, 2. the reaching uses of the dst operands, and 3. the reaching
2529 // defs of the reaching uses of the dst operand.
2530 //
2531 // In the first case, we simply insert copies after each of the reaching
2532 // definitions. In the second case, we collect all the uses of a given dest
2533 // and organize them by MBB. Then, we insert 1 copy for each MBB before the
2534 // earliest use. Since the use may have multiple reaching defs, and since we
2535 // want to replace the register it is using with the result of the copy, we
2536 // must handle case 3. In the third case, we simply insert a copy after each
2537 // of the reaching defs to connect to the copy of the reaching uses of the dst
2538 // reg. This allows us to avoid inserting copies next to the MFMAs.
2539 //
2540 // While inserting the copies, we maintain a map of operands which will use
2541 // different regs (i.e. the result of the copies). For example, a case 1 src2
2542 // operand will use the register result of the copies after the reaching defs,
2543 // as opposed to the original register. Now that we have completed our copy
2544 // analysis and placement, we can bulk update the registers. We do this
2545 // separately as to avoid complicating the reachingDef and reachingUse
2546 // queries.
2547 //
2548 // While inserting the copies, we also maintain a list or registers which we
2549 // will want to reclassify as AGPR. After doing the copy insertion and the
2550 // register replacement, we can finally do the reclassification. This uses the
2551 // redef map, as the registers we are interested in reclassifying may be
2552 // replaced by the result of a copy. We must do this after the copy analysis
2553 // and placement as we must have an accurate redef map -- otherwise we may end
2554 // up creating illegal instructions.
2555
2556 // The original registers of the MFMA that need to be reclassified as AGPR.
2557 DenseSet<Register> RewriteRegs;
2558 // The map of an original register in the MFMA to a new register (result of a
2559 // copy) that it should be replaced with.
2560 DenseMap<Register, Register> RedefMap;
2561 // The map of the original MFMA registers to the relevant MFMA operands.
2562 DenseMap<Register, DenseSet<MachineOperand *>> ReplaceMap;
2563 // The map of reaching defs for a given register -- to avoid duplicate copies.
2564 DenseMap<Register, SmallPtrSet<MachineInstr *, 8>> ReachingDefCopyMap;
2565 // The map of reaching uses for a given register by basic block -- to avoid
2566 // duplicate copies and to calculate per MBB insert pts.
2567 DenseMap<unsigned, DenseMap<Register, SmallPtrSet<MachineOperand *, 8>>>
2568 ReachingUseTracker;
2569
2570 // Collect the candidate group; its members share AGPR-form operands
2571 // post-rewrite, so reaching defs feeding any member need no bridge copy.
2572 SmallPtrSet<MachineInstr *, 16> RewriteCandsSet;
2573 DenseSet<Register> RewriteSrc2Regs;
2574 for (auto &[MI, OriginalOpcode] : RewriteCands) {
2575 RewriteCandsSet.insert(MI);
2576 MachineOperand *Src2 = TII->getNamedOperand(*MI, AMDGPU::OpName::src2);
2577 if (Src2 && Src2->isReg())
2578 RewriteSrc2Regs.insert(Src2->getReg());
2579 }
2580
2581 for (auto &[MI, OriginalOpcode] : RewriteCands) {
2582 int ReplacementOp = AMDGPU::getAGPRFormOp(MI->getOpcode());
2583 if (ReplacementOp == -1)
2584 continue;
2585 MI->setDesc(TII->get(ReplacementOp));
2586
2587 // Case 1: insert copies for the reaching defs of the Src2Reg.
2588 MachineOperand *Src2 = TII->getNamedOperand(*MI, AMDGPU::OpName::src2);
2589 if (Src2->isReg()) {
2590 Register Src2Reg = Src2->getReg();
2591 if (!Src2Reg.isVirtual())
2592 return false;
2593
2594 Register MappedReg = Src2->getReg();
2595 SmallVector<SlotIndex, 8> Src2ReachingDefs;
2596 findReachingDefs(*Src2, DAG.LIS, Src2ReachingDefs);
2597 SmallSetVector<MachineInstr *, 8> Src2DefsReplace;
2598
2599 // If src2 has a use that must remain VGPR, it cannot be reclassified to
2600 // AGPR.
2601 bool Src2NeedsVGPR = Src2NeedsVGPRCache.lookup(MI);
2602
2603 for (SlotIndex RDIndex : Src2ReachingDefs) {
2604 MachineInstr *RD = DAG.LIS->getInstructionFromIndex(RDIndex);
2605 if (!Src2NeedsVGPR &&
2606 isReachingDefAGPRForm(RD, RewriteCandsSet, RewriteSrc2Regs, *TII))
2607 continue;
2608
2609 Src2DefsReplace.insert(RD);
2610 }
2611
2612 if (!Src2DefsReplace.empty()) {
2613 auto RI = RedefMap.find(Src2Reg);
2614 if (RI != RedefMap.end()) {
2615 MappedReg = RI->second;
2616 } else {
2617 assert(!ReachingDefCopyMap.contains(Src2Reg));
2618 const TargetRegisterClass *Src2RC = DAG.MRI.getRegClass(Src2Reg);
2619 const TargetRegisterClass *VGPRRC =
2620 SRI->getEquivalentVGPRClass(Src2RC);
2621
2622 // Track the mapping of the original register to the new register.
2623 MappedReg = DAG.MRI.createVirtualRegister(VGPRRC);
2624 RedefMap[Src2Reg] = MappedReg;
2625 }
2626
2627 // If none exists, create a copy from this reaching def.
2628 // We may have inserted a copy already in an earlier iteration.
2629 for (MachineInstr *RD : Src2DefsReplace) {
2630 // Do not create redundant copies.
2631 if (ReachingDefCopyMap[Src2Reg].insert(RD).second) {
2632 MachineInstrBuilder VGPRCopy =
2633 BuildMI(*RD->getParent(), std::next(RD->getIterator()),
2634 RD->getDebugLoc(), TII->get(TargetOpcode::COPY))
2635 .addDef(MappedReg, {}, 0)
2636 .addUse(Src2Reg, {}, 0);
2637 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
2638
2639 // If this reaching def was the last MI in the region, update the
2640 // region boundaries.
2641 if (LastMIToRegion.contains(RD)) {
2642 unsigned UpdateRegion = LastMIToRegion[RD];
2643 DAG.Regions[UpdateRegion].second = VGPRCopy;
2644 LastMIToRegion.erase(RD);
2645 }
2646 }
2647 }
2648 }
2649
2650 // Track the register for reclassification
2651 RewriteRegs.insert(Src2Reg);
2652
2653 // Always insert the operand for replacement. If this corresponds with a
2654 // chain of tied-def we may not see the VGPR requirement until later.
2655 ReplaceMap[Src2Reg].insert(Src2);
2656 }
2657
2658 // Case 2 and Case 3: insert copies before the reaching uses of the dsts,
2659 // and after the reaching defs of the reaching uses of the dsts.
2660
2661 MachineOperand *Dst = &MI->getOperand(0);
2662 Register DstReg = Dst->getReg();
2663 if (!DstReg.isVirtual())
2664 return false;
2665
2666 Register MappedReg = DstReg;
2667 SmallVector<MachineOperand *, 8> DstReachingUses;
2668
2669 SmallVector<MachineOperand *, 8> DstReachingUseCopies;
2670 SmallVector<MachineInstr *, 8> DstUseDefsReplace;
2671
2672 findReachingUses(MI, DAG.LIS, DstReachingUses);
2673
2674 for (MachineOperand *RUOp : DstReachingUses) {
2675 MachineInstr *UserMI = RUOp->getParent();
2676 // Group members read the AGPR result directly.
2677 if (TII->isMAI(*UserMI) && RewriteCandsSet.contains(UserMI))
2678 continue;
2679
2680 // If there is a non mai reaching use, then we need a copy.
2681 if (find(DstReachingUseCopies, RUOp) == DstReachingUseCopies.end())
2682 DstReachingUseCopies.push_back(RUOp);
2683
2684 // Non-rewritten MAI: its defs aren't being reclassified.
2685 if (TII->isMAI(*UserMI))
2686 continue;
2687
2688 SmallVector<SlotIndex, 8> DstUsesReachingDefs;
2689 findReachingDefs(*RUOp, DAG.LIS, DstUsesReachingDefs);
2690
2691 for (SlotIndex RDIndex : DstUsesReachingDefs) {
2692 MachineInstr *RD = DAG.LIS->getInstructionFromIndex(RDIndex);
2693 if (TII->isMAI(*RD))
2694 continue;
2695
2696 // If there is a non mai reaching def of this reaching use, then we will
2697 // need a copy.
2698 if (find(DstUseDefsReplace, RD) == DstUseDefsReplace.end())
2699 DstUseDefsReplace.push_back(RD);
2700 }
2701 }
2702
2703 if (!DstUseDefsReplace.empty()) {
2704 auto RI = RedefMap.find(DstReg);
2705 if (RI != RedefMap.end()) {
2706 MappedReg = RI->second;
2707 } else {
2708 assert(!ReachingDefCopyMap.contains(DstReg));
2709 const TargetRegisterClass *DstRC = DAG.MRI.getRegClass(DstReg);
2710 const TargetRegisterClass *VGPRRC = SRI->getEquivalentVGPRClass(DstRC);
2711
2712 // Track the mapping of the original register to the new register.
2713 MappedReg = DAG.MRI.createVirtualRegister(VGPRRC);
2714 RedefMap[DstReg] = MappedReg;
2715 }
2716
2717 // If none exists, create a copy from this reaching def.
2718 // We may have inserted a copy already in an earlier iteration.
2719 for (MachineInstr *RD : DstUseDefsReplace) {
2720 // Do not create reundant copies.
2721 if (ReachingDefCopyMap[DstReg].insert(RD).second) {
2722 MachineInstrBuilder VGPRCopy =
2723 BuildMI(*RD->getParent(), std::next(RD->getIterator()),
2724 RD->getDebugLoc(), TII->get(TargetOpcode::COPY))
2725 .addDef(MappedReg, {}, 0)
2726 .addUse(DstReg, {}, 0);
2727 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
2728
2729 // If this reaching def was the last MI in the region, update the
2730 // region boundaries.
2731 auto LMI = LastMIToRegion.find(RD);
2732 if (LMI != LastMIToRegion.end()) {
2733 unsigned UpdateRegion = LMI->second;
2734 DAG.Regions[UpdateRegion].second = VGPRCopy;
2735 LastMIToRegion.erase(RD);
2736 }
2737 }
2738 }
2739 }
2740
2741 DenseSet<MachineOperand *> &DstRegSet = ReplaceMap[DstReg];
2742 // One AGPR→VGPR copy per dst register, shared by all same-block uses.
2743 Register SameBlockCopyReg;
2744 MachineInstr *EarliestSameBlockUse = nullptr;
2745 for (MachineOperand *RU : DstReachingUseCopies) {
2746 MachineBasicBlock *RUBlock = RU->getParent()->getParent();
2747 // Just keep track of the reaching use of this register by block. After we
2748 // have scanned all the MFMAs we can find optimal insert pts.
2749 if (RUBlock != MI->getParent()) {
2750 ReachingUseTracker[RUBlock->getNumber()][DstReg].insert(RU);
2751 continue;
2752 }
2753
2754 // Lazily create the copy register on first same-block use.
2755 if (!SameBlockCopyReg.isValid()) {
2756 const TargetRegisterClass *DstRC = DAG.MRI.getRegClass(DstReg);
2757 const TargetRegisterClass *VGPRRC = SRI->getEquivalentVGPRClass(DstRC);
2758 SameBlockCopyReg = DAG.MRI.createVirtualRegister(VGPRRC);
2759 }
2760
2761 // Track the earliest use for copy insertion point.
2762 MachineInstr *UseInst = RU->getParent();
2763 if (!EarliestSameBlockUse ||
2765 DAG.LIS->getInstructionIndex(*UseInst),
2766 DAG.LIS->getInstructionIndex(*EarliestSameBlockUse)))
2767 EarliestSameBlockUse = UseInst;
2768 RU->setReg(SameBlockCopyReg);
2769 }
2770
2771 // Insert the copy before the earliest same-block use.
2772 if (SameBlockCopyReg.isValid()) {
2773 MachineInstrBuilder VGPRCopy =
2774 BuildMI(*EarliestSameBlockUse->getParent(),
2775 EarliestSameBlockUse->getIterator(), DebugLoc(),
2776 TII->get(TargetOpcode::COPY), SameBlockCopyReg)
2777 .addUse(DstReg, {}, 0);
2778 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
2779 DstRegSet.insert(&VGPRCopy->getOperand(1));
2780 }
2781
2782 // Track the register for reclassification
2783 RewriteRegs.insert(DstReg);
2784
2785 // Insert the dst operand for replacement. If this dst is in a chain of
2786 // tied-def MFMAs, and the first src2 needs to be replaced with a new reg,
2787 // all the correspond operands need to be replaced.
2788 DstRegSet.insert(Dst);
2789 }
2790
2791 // Handle the copies for dst uses.
2792 using RUBType =
2793 std::pair<unsigned, DenseMap<Register, SmallPtrSet<MachineOperand *, 8>>>;
2794 for (RUBType RUBlockEntry : ReachingUseTracker) {
2795 using RUDType = std::pair<Register, SmallPtrSet<MachineOperand *, 8>>;
2796 for (RUDType RUDst : RUBlockEntry.second) {
2797 MachineOperand *OpBegin = *RUDst.second.begin();
2798 SlotIndex InstPt = DAG.LIS->getInstructionIndex(*OpBegin->getParent());
2799
2800 // Find the earliest use in this block.
2801 for (MachineOperand *User : RUDst.second) {
2802 SlotIndex NewInstPt = DAG.LIS->getInstructionIndex(*User->getParent());
2803 if (SlotIndex::isEarlierInstr(NewInstPt, InstPt))
2804 InstPt = NewInstPt;
2805 }
2806
2807 const TargetRegisterClass *DstRC = DAG.MRI.getRegClass(RUDst.first);
2808 const TargetRegisterClass *VGPRRC = SRI->getEquivalentVGPRClass(DstRC);
2809 Register NewUseReg = DAG.MRI.createVirtualRegister(VGPRRC);
2810 MachineInstr *UseInst = DAG.LIS->getInstructionFromIndex(InstPt);
2811
2812 MachineInstrBuilder VGPRCopy =
2813 BuildMI(*UseInst->getParent(), UseInst->getIterator(),
2814 UseInst->getDebugLoc(), TII->get(TargetOpcode::COPY))
2815 .addDef(NewUseReg, {}, 0)
2816 .addUse(RUDst.first, {}, 0);
2817 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
2818
2819 // If this UseInst was the first MI in the region, update the region
2820 // boundaries.
2821 auto FI = FirstMIToRegion.find(UseInst);
2822 if (FI != FirstMIToRegion.end()) {
2823 unsigned UpdateRegion = FI->second;
2824 DAG.Regions[UpdateRegion].first = VGPRCopy;
2825 FirstMIToRegion.erase(UseInst);
2826 }
2827
2828 // Replace the operand for all users.
2829 for (MachineOperand *User : RUDst.second) {
2830 User->setReg(NewUseReg);
2831 }
2832
2833 // Track the copy source operand for replacement.
2834 ReplaceMap[RUDst.first].insert(&VGPRCopy->getOperand(1));
2835 }
2836 }
2837
2838 // We may have needed to insert copies after the reaching defs of the MFMAs.
2839 // Replace the original register with the result of the copy for all relevant
2840 // operands.
2841 for (std::pair<Register, Register> NewDef : RedefMap) {
2842 Register OldReg = NewDef.first;
2843 Register NewReg = NewDef.second;
2844
2845 // Replace the register for any associated operand in the MFMA chain.
2846 for (MachineOperand *ReplaceOp : ReplaceMap[OldReg])
2847 ReplaceOp->setReg(NewReg);
2848 }
2849
2850 // Finally, do the reclassification of the MFMA registers.
2851 for (Register RewriteReg : RewriteRegs) {
2852 Register RegToRewrite = RewriteReg;
2853
2854 // Be sure to update the replacement register and not the original.
2855 auto RI = RedefMap.find(RewriteReg);
2856 if (RI != RedefMap.end())
2857 RegToRewrite = RI->second;
2858
2859 const TargetRegisterClass *CurrRC = DAG.MRI.getRegClass(RegToRewrite);
2860 const TargetRegisterClass *AGPRRC = SRI->getEquivalentAGPRClass(CurrRC);
2861
2862 DAG.MRI.setRegClass(RegToRewrite, AGPRRC);
2863 }
2864
2865 // Bulk update the LIS.
2866 DAG.LIS->reanalyze(DAG.MF);
2867 // Liveins may have been modified for cross RC copies
2868 RegionPressureMap LiveInUpdater(&DAG, false);
2869 LiveInUpdater.buildLiveRegMap();
2870
2871 for (unsigned Region = 0; Region < DAG.Regions.size(); Region++)
2872 DAG.LiveIns[Region] = LiveInUpdater.getLiveRegsForRegionIdx(Region);
2873
2874 DAG.Pressure[RegionIdx] = DAG.getRealRegPressure(RegionIdx);
2875
2876 return true;
2877}
2878
2879unsigned PreRARematStage::getStageTargetOccupancy() const {
2880 return TargetOcc ? *TargetOcc : MFI.getMinWavesPerEU();
2881}
2882
2884 // We consider that reducing spilling is always beneficial so we never
2885 // rollback rematerializations or revert scheduling in such cases.
2886 if (!TargetOcc)
2887 return;
2888
2889 // When increasing occupancy, it is possible that re-scheduling is not able to
2890 // achieve the target occupancy in all regions, in which case re-scheduling in
2891 // all regions should be reverted.
2892 if (DAG.MinOccupancy >= *TargetOcc)
2893 return;
2894
2895 // Revert re-scheduling in all affected regions.
2896 for (const auto &[RegionIdx, OrigMIOrder, MaxPressure] : RegionReverts) {
2897 LLVM_DEBUG(dbgs() << "Reverting re-scheduling in region " << RegionIdx
2898 << '\n');
2899 DAG.Pressure[RegionIdx] = MaxPressure;
2900 modifyRegionSchedule(RegionIdx, OrigMIOrder);
2901 }
2902
2903 // It is possible that re-scheduling lowers occupancy over the one achieved
2904 // just through rematerializations, in which case we revert re-scheduling in
2905 // all regions but do not roll back rematerializations.
2906 if (AchievedOcc >= *TargetOcc) {
2907 DAG.setTargetOccupancy(AchievedOcc);
2908 return;
2909 }
2910
2911 // Reset the target occupancy to what it was pre-rematerialization.
2912 DAG.setTargetOccupancy(*TargetOcc - 1);
2913 Strategy->rollbackRecordedRemats();
2914 for (unsigned RegionIdx : RescheduleRegions.set_bits()) {
2915 DAG.RegionLiveOuts.getLiveRegsForRegionIdx(RegionIdx) = LiveOuts[RegionIdx];
2916 DAG.Pressure[RegionIdx] = DAG.getRealRegPressure(RegionIdx);
2917 }
2918
2919#ifdef EXPENSIVE_CHECKS
2920 // In particular, we want to check for coherent MI/slot order in regions in
2921 // which reverts and/or rollbacks may have happened.
2922 MF.verify();
2923#endif
2924
2926}
2927
2928void GCNScheduleDAGMILive::setTargetOccupancy(unsigned TargetOccupancy) {
2929 MinOccupancy = TargetOccupancy;
2930 if (MFI.getOccupancy() < TargetOccupancy)
2931 MFI.increaseOccupancy(MF, MinOccupancy);
2932 else
2933 MFI.limitOccupancy(MinOccupancy);
2934}
2935
2937 const SIInstrInfo *SII = static_cast<const SIInstrInfo *>(DAG->TII);
2938 return any_of(*DAG, [SII](MachineBasicBlock::iterator MI) {
2939 return SII->isIGLPMutationOnly(MI->getOpcode());
2940 });
2941}
2942
2944 MachineSchedContext *C, std::unique_ptr<MachineSchedStrategy> S,
2945 bool RemoveKillFlags)
2947
2949 HasIGLPInstrs = hasIGLPInstrs(this);
2950 if (HasIGLPInstrs) {
2951 SavedMutations.clear();
2952 SavedMutations.swap(Mutations);
2954 }
2955
2957}
2958
2960 if (HasIGLPInstrs)
2961 SavedMutations.swap(Mutations);
2962
2964}
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...
Rematerialization strategy, based on the target-independent rematerializer.
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))
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))
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
static constexpr std::pair< StringLiteral, StringLiteral > ReplaceMap[]
IRTranslator LLVM IR MI
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Promote Memory to Register
Definition Mem2Reg.cpp:110
#define T
if(PassOpts->AAPipeline)
MachineRegisterInfo & MRI
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
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:283
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...
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 traceCandidate(const SchedCandidate &Cand)
LLVM_ABI void setPolicy(CandPolicy &Policy, bool IsPostRA, SchedBoundary &CurrZone, SchedBoundary *OtherZone)
Set the CandPolicy given a scheduling zone given the current resources and latencies inside and outsi...
MachineSchedPolicy RegionPolicy
const TargetSchedModel * SchedModel
const MachineSchedContext * Context
const TargetRegisterInfo * TRI
SchedCandidate BotCand
Candidate last picked from Bot boundary.
SchedCandidate TopCand
Candidate last picked from Top boundary.
virtual bool tryCandidate(SchedCandidate &Cand, SchedCandidate &TryCand, SchedBoundary *Zone) const
Apply a set of heuristics to a new candidate.
ScheduleDAGMILive * DAG
void initialize(ScheduleDAGMI *dag) override
Initialize the strategy after building the DAG for a new region.
void schedNode(SUnit *SU, bool IsTopNode) override
Update the scheduler's state after scheduling a node.
GenericScheduler(const MachineSchedContext *C)
bool shouldRevertScheduling(unsigned WavesAfter) override
LiveInterval - This class represents the liveness of a register, or stack slot.
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.
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
Definition Metadata.h:1579
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
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
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.
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
Register getReg() const
getReg - Returns the register number.
bool shouldRevertScheduling(unsigned WavesAfter) override
Represent a mutable reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:294
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.
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.
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
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.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
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:210
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
Definition DenseSet.h:183
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)
@ 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
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
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)
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
constexpr auto seq(T Begin, T End)
Iterate over an integral type from Begin up to - but not including - End.
Definition Sequence.h:341
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.
MachineSchedContext provides enough context from the MachineScheduler pass for the target to instanti...
bool parse(cl::Option &O, StringRef ArgName, StringRef Arg, unsigned &Value)