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