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