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->getInstr());
695 return SU;
696}
697
698void GCNSchedStrategy::schedNode(SUnit *SU, bool IsTopNode) {
699 if (useGCNTrackers()) {
700 MachineInstr *MI = SU->getInstr();
701 IsTopNode ? (void)DownwardTracker.advance(MI, false)
702 : UpwardTracker.recede(*MI);
703 }
704
705 return GenericScheduler::schedNode(SU, IsTopNode);
706}
707
712
715 if (!CurrentStage)
716 CurrentStage = SchedStages.begin();
717 else
718 CurrentStage++;
719
720 return CurrentStage != SchedStages.end();
721}
722
725 return std::next(CurrentStage) != SchedStages.end();
726}
727
729 assert(CurrentStage && std::next(CurrentStage) != SchedStages.end());
730 return *std::next(CurrentStage);
731}
732
734 SchedCandidate &TryCand,
735 SchedBoundary *Zone) const {
736 // Initialize the candidate if needed.
737 if (!Cand.isValid()) {
738 TryCand.Reason = NodeOrder;
739 return true;
740 }
741
742 // Bias PhysReg Defs and copies to their uses and defined respectively.
743 if (tryGreater(biasPhysReg(TryCand.SU, TryCand.AtTop),
744 biasPhysReg(Cand.SU, Cand.AtTop), TryCand, Cand, PhysReg))
745 return TryCand.Reason != NoCand;
746
747 // Avoid exceeding the target's limit.
748 if (DAG->isTrackingPressure() &&
749 tryPressure(TryCand.RPDelta.Excess, Cand.RPDelta.Excess, TryCand, Cand,
750 RegExcess, TRI, DAG->MF))
751 return TryCand.Reason != NoCand;
752
753 // Avoid increasing the max critical pressure in the scheduled region.
754 if (DAG->isTrackingPressure() &&
756 TryCand, Cand, RegCritical, TRI, DAG->MF))
757 return TryCand.Reason != NoCand;
758
759 bool SameBoundary = Zone != nullptr;
760 if (SameBoundary) {
763 TryCand, Cand, ResourceReduce))
764 return TryCand.Reason != NoCand;
766 Cand.ResDelta.DemandedResources, TryCand, Cand,
768 return TryCand.Reason != NoCand;
769 }
770
771 return false;
772}
773
786
791
793 SchedCandidate &TryCand,
794 SchedBoundary *Zone) const {
795 // Initialize the candidate if needed.
796 if (!Cand.isValid()) {
797 TryCand.Reason = NodeOrder;
798 return true;
799 }
800
801 // Avoid spilling by exceeding the register limit.
802 if (DAG->isTrackingPressure() &&
803 tryPressure(TryCand.RPDelta.Excess, Cand.RPDelta.Excess, TryCand, Cand,
804 RegExcess, TRI, DAG->MF))
805 return TryCand.Reason != NoCand;
806
807 // Bias PhysReg Defs and copies to their uses and defined respectively.
808 if (tryGreater(biasPhysReg(TryCand.SU, TryCand.AtTop),
809 biasPhysReg(Cand.SU, Cand.AtTop), TryCand, Cand, PhysReg))
810 return TryCand.Reason != NoCand;
811
812 bool SameBoundary = Zone != nullptr;
813 if (SameBoundary) {
814 // Prioritize instructions that read unbuffered resources by stall cycles.
815 if (tryLess(Zone->getLatencyStallCycles(TryCand.SU),
816 Zone->getLatencyStallCycles(Cand.SU), TryCand, Cand, Stall))
817 return TryCand.Reason != NoCand;
818
819 // Avoid critical resource consumption and balance the schedule.
822 TryCand, Cand, ResourceReduce))
823 return TryCand.Reason != NoCand;
825 Cand.ResDelta.DemandedResources, TryCand, Cand,
827 return TryCand.Reason != NoCand;
828
829 // Unconditionally try to reduce latency.
830 if (tryLatency(TryCand, Cand, *Zone))
831 return TryCand.Reason != NoCand;
832
833 // Weak edges are for clustering and other constraints.
834 if (tryLess(getWeakLeft(TryCand.SU, TryCand.AtTop),
835 getWeakLeft(Cand.SU, Cand.AtTop), TryCand, Cand, Weak))
836 return TryCand.Reason != NoCand;
837 }
838
839 // Keep clustered nodes together to encourage downstream peephole
840 // optimizations which may reduce resource requirements.
841 //
842 // This is a best effort to set things up for a post-RA pass. Optimizations
843 // like generating loads of multiple registers should ideally be done within
844 // the scheduler pass by combining the loads during DAG postprocessing.
845 unsigned CandZoneCluster = Cand.AtTop ? TopClusterID : BotClusterID;
846 unsigned TryCandZoneCluster = TryCand.AtTop ? TopClusterID : BotClusterID;
847 bool CandIsClusterSucc =
848 isTheSameCluster(CandZoneCluster, Cand.SU->ParentClusterIdx);
849 bool TryCandIsClusterSucc =
850 isTheSameCluster(TryCandZoneCluster, TryCand.SU->ParentClusterIdx);
851 if (tryGreater(TryCandIsClusterSucc, CandIsClusterSucc, TryCand, Cand,
852 Cluster))
853 return TryCand.Reason != NoCand;
854
855 // Avoid increasing the max critical pressure in the scheduled region.
856 if (DAG->isTrackingPressure() &&
858 TryCand, Cand, RegCritical, TRI, DAG->MF))
859 return TryCand.Reason != NoCand;
860
861 // Avoid increasing the max pressure of the entire region.
862 if (DAG->isTrackingPressure() &&
863 tryPressure(TryCand.RPDelta.CurrentMax, Cand.RPDelta.CurrentMax, TryCand,
864 Cand, RegMax, TRI, DAG->MF))
865 return TryCand.Reason != NoCand;
866
867 if (SameBoundary) {
868 // Fall through to original instruction order.
869 if ((Zone->isTop() && TryCand.SU->NodeNum < Cand.SU->NodeNum) ||
870 (!Zone->isTop() && TryCand.SU->NodeNum > Cand.SU->NodeNum)) {
871 TryCand.Reason = NodeOrder;
872 return true;
873 }
874 }
875 return false;
876}
877
883
884/// GCNMaxMemoryClauseSchedStrategy tries best to clause memory instructions as
885/// much as possible. This is achieved by:
886// 1. Prioritize clustered operations before stall latency heuristic.
887// 2. Prioritize long-latency-load before stall latency heuristic.
888///
889/// \param Cand provides the policy and current best candidate.
890/// \param TryCand refers to the next SUnit candidate, otherwise uninitialized.
891/// \param Zone describes the scheduled zone that we are extending, or nullptr
892/// if Cand is from a different zone than TryCand.
893/// \return \c true if TryCand is better than Cand (Reason is NOT NoCand)
895 SchedCandidate &TryCand,
896 SchedBoundary *Zone) const {
897 // Initialize the candidate if needed.
898 if (!Cand.isValid()) {
899 TryCand.Reason = NodeOrder;
900 return true;
901 }
902
903 // Bias PhysReg Defs and copies to their uses and defined respectively.
904 if (tryGreater(biasPhysReg(TryCand.SU, TryCand.AtTop),
905 biasPhysReg(Cand.SU, Cand.AtTop), TryCand, Cand, PhysReg))
906 return TryCand.Reason != NoCand;
907
908 if (DAG->isTrackingPressure()) {
909 // Avoid exceeding the target's limit.
910 if (tryPressure(TryCand.RPDelta.Excess, Cand.RPDelta.Excess, TryCand, Cand,
911 RegExcess, TRI, DAG->MF))
912 return TryCand.Reason != NoCand;
913
914 // Avoid increasing the max critical pressure in the scheduled region.
916 TryCand, Cand, RegCritical, TRI, DAG->MF))
917 return TryCand.Reason != NoCand;
918 }
919
920 // MaxMemoryClause-specific: We prioritize clustered instructions as we would
921 // get more benefit from clausing these memory instructions.
922 unsigned CandZoneCluster = Cand.AtTop ? TopClusterID : BotClusterID;
923 unsigned TryCandZoneCluster = TryCand.AtTop ? TopClusterID : BotClusterID;
924 bool CandIsClusterSucc =
925 isTheSameCluster(CandZoneCluster, Cand.SU->ParentClusterIdx);
926 bool TryCandIsClusterSucc =
927 isTheSameCluster(TryCandZoneCluster, TryCand.SU->ParentClusterIdx);
928 if (tryGreater(TryCandIsClusterSucc, CandIsClusterSucc, TryCand, Cand,
929 Cluster))
930 return TryCand.Reason != NoCand;
931
932 // We only compare a subset of features when comparing nodes between
933 // Top and Bottom boundary. Some properties are simply incomparable, in many
934 // other instances we should only override the other boundary if something
935 // is a clear good pick on one boundary. Skip heuristics that are more
936 // "tie-breaking" in nature.
937 bool SameBoundary = Zone != nullptr;
938 if (SameBoundary) {
939 // For loops that are acyclic path limited, aggressively schedule for
940 // latency. Within an single cycle, whenever CurrMOps > 0, allow normal
941 // heuristics to take precedence.
942 if (Rem.IsAcyclicLatencyLimited && !Zone->getCurrMOps() &&
943 tryLatency(TryCand, Cand, *Zone))
944 return TryCand.Reason != NoCand;
945
946 // MaxMemoryClause-specific: Prioritize long latency memory load
947 // instructions in top-bottom order to hide more latency. The mayLoad check
948 // is used to exclude store-like instructions, which we do not want to
949 // scheduler them too early.
950 bool TryMayLoad =
951 TryCand.SU->isInstr() && TryCand.SU->getInstr()->mayLoad();
952 bool CandMayLoad = Cand.SU->isInstr() && Cand.SU->getInstr()->mayLoad();
953
954 if (TryMayLoad || CandMayLoad) {
955 bool TryLongLatency =
956 TryCand.SU->Latency > 10 * Cand.SU->Latency && TryMayLoad;
957 bool CandLongLatency =
958 10 * TryCand.SU->Latency < Cand.SU->Latency && CandMayLoad;
959
960 if (tryGreater(Zone->isTop() ? TryLongLatency : CandLongLatency,
961 Zone->isTop() ? CandLongLatency : TryLongLatency, TryCand,
962 Cand, Stall))
963 return TryCand.Reason != NoCand;
964 }
965 // Prioritize instructions that read unbuffered resources by stall cycles.
966 if (tryLess(Zone->getLatencyStallCycles(TryCand.SU),
967 Zone->getLatencyStallCycles(Cand.SU), TryCand, Cand, Stall))
968 return TryCand.Reason != NoCand;
969 }
970
971 if (SameBoundary) {
972 // Weak edges are for clustering and other constraints.
973 if (tryLess(getWeakLeft(TryCand.SU, TryCand.AtTop),
974 getWeakLeft(Cand.SU, Cand.AtTop), TryCand, Cand, Weak))
975 return TryCand.Reason != NoCand;
976 }
977
978 // Avoid increasing the max pressure of the entire region.
979 if (DAG->isTrackingPressure() &&
980 tryPressure(TryCand.RPDelta.CurrentMax, Cand.RPDelta.CurrentMax, TryCand,
981 Cand, RegMax, TRI, DAG->MF))
982 return TryCand.Reason != NoCand;
983
984 if (SameBoundary) {
985 // Avoid critical resource consumption and balance the schedule.
988 TryCand, Cand, ResourceReduce))
989 return TryCand.Reason != NoCand;
991 Cand.ResDelta.DemandedResources, TryCand, Cand,
993 return TryCand.Reason != NoCand;
994
995 // Avoid serializing long latency dependence chains.
996 // For acyclic path limited loops, latency was already checked above.
997 if (!RegionPolicy.DisableLatencyHeuristic && TryCand.Policy.ReduceLatency &&
998 !Rem.IsAcyclicLatencyLimited && tryLatency(TryCand, Cand, *Zone))
999 return TryCand.Reason != NoCand;
1000
1001 // Fall through to original instruction order.
1002 if (Zone->isTop() == (TryCand.SU->NodeNum < Cand.SU->NodeNum)) {
1003 assert(TryCand.SU->NodeNum != Cand.SU->NodeNum);
1004 TryCand.Reason = NodeOrder;
1005 return true;
1006 }
1007 }
1008
1009 return false;
1010}
1011
1013 MachineSchedContext *C, std::unique_ptr<MachineSchedStrategy> S)
1014 : ScheduleDAGMILive(C, std::move(S)), ST(MF.getSubtarget<GCNSubtarget>()),
1015 MFI(*MF.getInfo<SIMachineFunctionInfo>()),
1016 StartingOccupancy(MFI.getOccupancy()), MinOccupancy(StartingOccupancy),
1017 RegionLiveOuts(this, /*IsLiveOut=*/true) {
1018
1019 // We want regions with a single MI to be scheduled so that we can reason
1020 // about them correctly during scheduling stages that move MIs between regions
1021 // (e.g., rematerialization).
1023 LLVM_DEBUG(dbgs() << "Starting occupancy is " << StartingOccupancy << ".\n");
1024 if (RelaxedOcc) {
1025 MinOccupancy = std::min(MFI.getMinAllowedOccupancy(), StartingOccupancy);
1026 if (MinOccupancy != StartingOccupancy)
1027 LLVM_DEBUG(dbgs() << "Allowing Occupancy drops to " << MinOccupancy
1028 << ".\n");
1029 }
1030}
1031
1032std::unique_ptr<GCNSchedStage>
1033GCNScheduleDAGMILive::createSchedStage(GCNSchedStageID SchedStageID) {
1034 switch (SchedStageID) {
1036 return std::make_unique<OccInitialScheduleStage>(SchedStageID, *this);
1038 return std::make_unique<RewriteMFMAFormStage>(SchedStageID, *this);
1040 return std::make_unique<UnclusteredHighRPStage>(SchedStageID, *this);
1042 return std::make_unique<ClusteredLowOccStage>(SchedStageID, *this);
1044 return std::make_unique<PreRARematStage>(SchedStageID, *this);
1046 return std::make_unique<ILPInitialScheduleStage>(SchedStageID, *this);
1048 return std::make_unique<MemoryClauseInitialScheduleStage>(SchedStageID,
1049 *this);
1051 return std::make_unique<LiveIntervalRPStage>(SchedStageID, *this);
1052 }
1053
1054 llvm_unreachable("Unknown SchedStageID.");
1055}
1056
1058 // Collect all scheduling regions. The actual scheduling is performed in
1059 // GCNScheduleDAGMILive::finalizeSchedule.
1060 Regions.push_back(std::pair(RegionBegin, RegionEnd));
1061}
1062
1064GCNScheduleDAGMILive::getRealRegPressure(unsigned RegionIdx) const {
1065 if (Regions[RegionIdx].first == Regions[RegionIdx].second)
1066 return llvm::getRegPressure(MRI, LiveIns[RegionIdx]);
1068 RPTracker.advance(Regions[RegionIdx].first, Regions[RegionIdx].second,
1069 &LiveIns[RegionIdx]);
1070 return RPTracker.moveMaxPressure();
1071}
1072
1074 MachineBasicBlock::iterator RegionEnd) {
1075 assert(RegionBegin != RegionEnd && "Region must not be empty");
1076 return &*skipDebugInstructionsBackward(std::prev(RegionEnd), RegionBegin);
1077}
1078
1079void GCNScheduleDAGMILive::computeBlockPressure(unsigned RegionIdx,
1080 const MachineBasicBlock *MBB) {
1081 GCNDownwardRPTracker RPTracker(*LIS);
1082
1083 // If the block has the only successor then live-ins of that successor are
1084 // live-outs of the current block. We can reuse calculated live set if the
1085 // successor will be sent to scheduling past current block.
1086
1087 // However, due to the bug in LiveInterval analysis it may happen that two
1088 // predecessors of the same successor block have different lane bitmasks for
1089 // a live-out register. Workaround that by sticking to one-to-one relationship
1090 // i.e. one predecessor with one successor block.
1091 const MachineBasicBlock *OnlySucc = nullptr;
1092 if (MBB->succ_size() == 1) {
1093 auto *Candidate = *MBB->succ_begin();
1094 if (!Candidate->empty() && Candidate->pred_size() == 1) {
1095 SlotIndexes *Ind = LIS->getSlotIndexes();
1096 if (Ind->getMBBStartIdx(MBB) < Ind->getMBBStartIdx(Candidate))
1097 OnlySucc = Candidate;
1098 }
1099 }
1100
1101 // Scheduler sends regions from the end of the block upwards.
1102 size_t CurRegion = RegionIdx;
1103 for (size_t E = Regions.size(); CurRegion != E; ++CurRegion)
1104 if (Regions[CurRegion].first->getParent() != MBB)
1105 break;
1106 --CurRegion;
1107
1108 auto I = MBB->begin();
1109 auto LiveInIt = MBBLiveIns.find(MBB);
1110 auto &Rgn = Regions[CurRegion];
1111 auto *NonDbgMI = &*skipDebugInstructionsForward(Rgn.first, Rgn.second);
1112 if (LiveInIt != MBBLiveIns.end()) {
1113 auto LiveIn = std::move(LiveInIt->second);
1114 RPTracker.reset(*MBB->begin(), MBB->end(), &LiveIn);
1115 MBBLiveIns.erase(LiveInIt);
1116 } else {
1117 I = Rgn.first;
1118 auto LRS = BBLiveInMap.lookup(NonDbgMI);
1119#ifdef EXPENSIVE_CHECKS
1120 assert(isEqual(getLiveRegsBefore(*NonDbgMI, *LIS), LRS));
1121#endif
1122 RPTracker.reset(*I, I->getParent()->end(), &LRS);
1123 }
1124
1125 for (;;) {
1126 I = RPTracker.getNext();
1127
1128 if (Regions[CurRegion].first == I || NonDbgMI == I) {
1129 LiveIns[CurRegion] = RPTracker.getLiveRegs();
1130 RPTracker.clearMaxPressure();
1131 }
1132
1133 if (Regions[CurRegion].second == I) {
1134 Pressure[CurRegion] = RPTracker.moveMaxPressure();
1135 if (CurRegion-- == RegionIdx)
1136 break;
1137 auto &Rgn = Regions[CurRegion];
1138 NonDbgMI = &*skipDebugInstructionsForward(Rgn.first, Rgn.second);
1139 }
1140 RPTracker.advanceBeforeNext();
1141 RPTracker.advanceToNext();
1142 }
1143
1144 if (OnlySucc) {
1145 if (I != MBB->end()) {
1146 RPTracker.advanceBeforeNext();
1147 RPTracker.advanceToNext();
1148 RPTracker.advance(MBB->end());
1149 }
1150 MBBLiveIns[OnlySucc] = RPTracker.moveLiveRegs();
1151 }
1152}
1153
1155GCNScheduleDAGMILive::getRegionLiveInMap() const {
1156 assert(!Regions.empty());
1157 std::vector<MachineInstr *> RegionFirstMIs;
1158 RegionFirstMIs.reserve(Regions.size());
1159 for (auto &[RegionBegin, RegionEnd] : reverse(Regions))
1160 RegionFirstMIs.push_back(
1162
1163 return getLiveRegMap(RegionFirstMIs, /*After=*/false, *LIS);
1164}
1165
1167GCNScheduleDAGMILive::getRegionLiveOutMap() const {
1168 assert(!Regions.empty());
1169 std::vector<MachineInstr *> RegionLastMIs;
1170 RegionLastMIs.reserve(Regions.size());
1171 for (auto &[RegionBegin, RegionEnd] : reverse(Regions)) {
1172 // Skip empty regions.
1173 if (RegionBegin == RegionEnd)
1174 continue;
1175 RegionLastMIs.push_back(getLastMIForRegion(RegionBegin, RegionEnd));
1176 }
1177 return getLiveRegMap(RegionLastMIs, /*After=*/true, *LIS);
1178}
1179
1181 IdxToInstruction.clear();
1182
1183 RegionLiveRegMap =
1184 IsLiveOut ? DAG->getRegionLiveOutMap() : DAG->getRegionLiveInMap();
1185 for (unsigned I = 0; I < DAG->Regions.size(); I++) {
1186 auto &[RegionBegin, RegionEnd] = DAG->Regions[I];
1187 // Skip empty regions.
1188 if (RegionBegin == RegionEnd)
1189 continue;
1190 MachineInstr *RegionKey =
1191 IsLiveOut ? getLastMIForRegion(RegionBegin, RegionEnd) : &*RegionBegin;
1192 IdxToInstruction[I] = RegionKey;
1193 }
1194}
1195
1197 // Start actual scheduling here. This function is called by the base
1198 // MachineScheduler after all regions have been recorded by
1199 // GCNScheduleDAGMILive::schedule().
1200 LiveIns.resize(Regions.size());
1201 Pressure.resize(Regions.size());
1202 RegionsWithHighRP.resize(Regions.size());
1203 RegionsWithExcessRP.resize(Regions.size());
1204 RegionsWithIGLPInstrs.resize(Regions.size());
1205 RegionsWithHighRP.reset();
1206 RegionsWithExcessRP.reset();
1207 RegionsWithIGLPInstrs.reset();
1208
1209 runSchedStages();
1210}
1211
1212void GCNScheduleDAGMILive::runSchedStages() {
1213 LLVM_DEBUG(dbgs() << "All regions recorded, starting actual scheduling.\n");
1214
1215 GCNSchedStrategy &S = static_cast<GCNSchedStrategy &>(*SchedImpl);
1216 if (!Regions.empty()) {
1217 BBLiveInMap = getRegionLiveInMap();
1218 if (S.useGCNTrackers())
1219 RegionLiveOuts.buildLiveRegMap();
1220 }
1221
1222#ifdef DUMP_MAX_REG_PRESSURE
1226 LIS->dump();
1227 }
1228#endif
1229
1230 while (S.advanceStage()) {
1231 auto Stage = createSchedStage(S.getCurrentStage());
1232 if (!Stage->initGCNSchedStage())
1233 continue;
1234
1235 for (auto Region : Regions) {
1236 RegionBegin = Region.first;
1237 RegionEnd = Region.second;
1238 // Setup for scheduling the region and check whether it should be skipped.
1239 if (!Stage->initGCNRegion()) {
1240 Stage->advanceRegion();
1241 exitRegion();
1242 continue;
1243 }
1244
1245 if (S.useGCNTrackers()) {
1246 const unsigned RegionIdx = Stage->getRegionIdx();
1247 S.getDownwardTracker()->reset(MRI, LiveIns[RegionIdx]);
1249 MRI, RegionLiveOuts.getLiveRegsForRegionIdx(RegionIdx));
1250 }
1251
1253 Stage->finalizeGCNRegion();
1254 Stage->advanceRegion();
1255 exitRegion();
1256 }
1257
1258 Stage->finalizeGCNSchedStage();
1259 }
1260
1261#ifdef DUMP_MAX_REG_PRESSURE
1265 LIS->dump();
1266 }
1267#endif
1268}
1269
1270#ifndef NDEBUG
1272 switch (StageID) {
1274 OS << "Max Occupancy Initial Schedule";
1275 break;
1277 OS << "Instruction Rewriting Reschedule";
1278 break;
1280 OS << "Unclustered High Register Pressure Reschedule";
1281 break;
1283 OS << "Clustered Low Occupancy Reschedule";
1284 break;
1286 OS << "Pre-RA Rematerialize";
1287 break;
1289 OS << "Max ILP Initial Schedule";
1290 break;
1292 OS << "Max memory clause Initial Schedule";
1293 break;
1295 OS << "Live Interval RP Reschedule";
1296 break;
1297 }
1298
1299 return OS;
1300}
1301#endif
1302
1306
1308 if (!DAG.LIS)
1309 return false;
1310
1311 LLVM_DEBUG(dbgs() << "Starting scheduling stage: " << StageID << "\n");
1312 return true;
1313}
1314
1315void RewriteMFMAFormStage::findReachingDefs(
1316 MachineOperand &UseMO, LiveIntervals *LIS,
1317 SmallVectorImpl<SlotIndex> &DefIdxs) {
1318 MachineInstr *UseMI = UseMO.getParent();
1319 LiveInterval &UseLI = LIS->getInterval(UseMO.getReg());
1320 VNInfo *VNI = UseLI.getVNInfoAt(LIS->getInstructionIndex(*UseMI));
1321
1322 // If the def is not a PHI, then it must be the only reaching def.
1323 if (!VNI->isPHIDef()) {
1324 DefIdxs.push_back(VNI->def);
1325 return;
1326 }
1327
1328 SmallPtrSet<MachineBasicBlock *, 8> Visited = {UseMI->getParent()};
1330
1331 // Mark the predecessor blocks for traversal
1332 for (MachineBasicBlock *PredMBB : UseMI->getParent()->predecessors()) {
1333 Worklist.push_back(PredMBB);
1334 Visited.insert(PredMBB);
1335 }
1336
1337 while (!Worklist.empty()) {
1338 MachineBasicBlock *CurrMBB = Worklist.pop_back_val();
1339
1340 SlotIndex CurrMBBEnd = LIS->getMBBEndIdx(CurrMBB);
1341 VNInfo *VNI = UseLI.getVNInfoAt(CurrMBBEnd.getPrevSlot());
1342
1343 MachineBasicBlock *DefMBB = LIS->getMBBFromIndex(VNI->def);
1344
1345 // If there is a def in this block, then add it to the list. This is the
1346 // reaching def of this path.
1347 if (!VNI->isPHIDef()) {
1348 DefIdxs.push_back(VNI->def);
1349 continue;
1350 }
1351
1352 for (MachineBasicBlock *PredMBB : DefMBB->predecessors()) {
1353 if (Visited.insert(PredMBB).second)
1354 Worklist.push_back(PredMBB);
1355 }
1356 }
1357}
1358
1359void RewriteMFMAFormStage::findReachingUses(
1360 const MachineInstr *DefMI, LiveIntervals *LIS,
1361 SmallVectorImpl<MachineOperand *> &ReachingUses) {
1362 SlotIndex DefIdx = LIS->getInstructionIndex(*DefMI);
1363 for (MachineOperand &UseMO :
1364 DAG.MRI.use_nodbg_operands(DefMI->getOperand(0).getReg())) {
1365 SmallVector<SlotIndex, 8> ReachingDefIndexes;
1366 findReachingDefs(UseMO, LIS, ReachingDefIndexes);
1367
1368 // If we find a use that contains this DefMI in its reachingDefs, then it is
1369 // a reaching use.
1370 if (any_of(ReachingDefIndexes, [DefIdx](SlotIndex RDIdx) {
1371 return SlotIndex::isSameInstr(RDIdx, DefIdx);
1372 }))
1373 ReachingUses.push_back(&UseMO);
1374 }
1375}
1376
1378 // We only need to run this pass if the architecture supports AGPRs.
1379 // Additionally, we don't use AGPRs at occupancy levels above 1 so there
1380 // is no need for this pass in that case, either.
1381 const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
1382 if (!ST.hasGFX90AInsts() || MFI.getMinWavesPerEU() > 1)
1383 return false;
1384
1385 RegionsWithExcessArchVGPR.resize(DAG.Regions.size());
1386 RegionsWithExcessArchVGPR.reset();
1387 for (unsigned Region = 0; Region < DAG.Regions.size(); Region++) {
1389 if (PressureBefore.getArchVGPRNum() > ST.getAddressableNumArchVGPRs())
1390 RegionsWithExcessArchVGPR[Region] = true;
1391 }
1392
1393 if (RegionsWithExcessArchVGPR.none())
1394 return false;
1395
1396 TII = ST.getInstrInfo();
1397 SRI = ST.getRegisterInfo();
1398
1399 std::vector<std::pair<MachineInstr *, unsigned>> RewriteCands;
1402
1403 if (!initHeuristics(RewriteCands, CopyForUse, CopyForDef))
1404 return false;
1405
1406 int64_t Cost = getRewriteCost(RewriteCands, CopyForUse, CopyForDef);
1407
1408 // If we haven't found the beneficial conditions, prefer the VGPR form which
1409 // may result in less cross RC copies.
1410 if (Cost > 0)
1411 return false;
1412
1413 return rewrite(RewriteCands);
1414}
1415
1418 return false;
1419
1421 return false;
1422
1423 if (DAG.RegionsWithHighRP.none() && DAG.RegionsWithExcessRP.none())
1424 return false;
1425
1426 SavedMutations.swap(DAG.Mutations);
1427 DAG.addMutation(
1429
1430 InitialOccupancy = DAG.MinOccupancy;
1431 // Aggressively try to reduce register pressure in the unclustered high RP
1432 // stage. Temporarily increase occupancy target in the region.
1433 TempTargetOccupancy = MFI.getMaxWavesPerEU() > DAG.MinOccupancy
1434 ? InitialOccupancy + 1
1435 : InitialOccupancy;
1436 IsAnyRegionScheduled = false;
1437 S.SGPRLimitBias = S.HighRPSGPRBias;
1438 S.VGPRLimitBias = S.HighRPVGPRBias;
1439
1440 LLVM_DEBUG(
1441 dbgs()
1442 << "Retrying function scheduling without clustering. "
1443 "Aggressively try to reduce register pressure to achieve occupancy "
1444 << TempTargetOccupancy << ".\n");
1445
1446 return true;
1447}
1448
1451 return false;
1452
1454 return false;
1455
1456 // Don't bother trying to improve ILP in lower RP regions if occupancy has not
1457 // been dropped. All regions will have already been scheduled with the ideal
1458 // occupancy targets.
1459 if (DAG.StartingOccupancy <= DAG.MinOccupancy)
1460 return false;
1461
1462 LLVM_DEBUG(
1463 dbgs() << "Retrying function scheduling with lowest recorded occupancy "
1464 << DAG.MinOccupancy << ".\n");
1465 return true;
1466}
1467
1468/// Allows to easily filter for this stage's debug output.
1469#define REMAT_PREFIX "[PreRARemat] "
1470#define REMAT_DEBUG(X) LLVM_DEBUG(dbgs() << REMAT_PREFIX; X;)
1471
1472#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
1473Printable PreRARematStage::ScoredRemat::print() const {
1474 return Printable([&](raw_ostream &OS) {
1475 OS << '(' << MaxFreq << ", " << FreqDiff << ", " << RegionImpact << ')';
1476 });
1477}
1478#endif
1479
1481 // FIXME: This pass will invalidate cached BBLiveInMap and MBBLiveIns for
1482 // regions inbetween the defs and region we sinked the def to. Will need to be
1483 // fixed if there is another pass after this pass.
1484 assert(!S.hasNextStage());
1485
1486 if (!GCNSchedStage::initGCNSchedStage() || DAG.Regions.size() <= 1)
1487 return false;
1488
1489#ifndef NDEBUG
1490 auto PrintTargetRegions = [&]() -> void {
1491 if (TargetRegions.none()) {
1492 dbgs() << REMAT_PREFIX << "No target regions\n";
1493 return;
1494 }
1495 dbgs() << REMAT_PREFIX << "Target regions:\n";
1496 for (unsigned I : TargetRegions.set_bits())
1497 dbgs() << REMAT_PREFIX << " [" << I << "] " << RPTargets[I] << '\n';
1498 };
1499#endif
1500
1501 // Set an objective for the stage based on current RP in each region.
1502 REMAT_DEBUG({
1503 dbgs() << "Analyzing ";
1504 MF.getFunction().printAsOperand(dbgs(), false);
1505 dbgs() << ": ";
1506 });
1507 if (!setObjective()) {
1508 LLVM_DEBUG(dbgs() << "no objective to achieve, occupancy is maximal at "
1509 << MFI.getMaxWavesPerEU() << '\n');
1510 return false;
1511 }
1512 LLVM_DEBUG({
1513 if (TargetOcc) {
1514 dbgs() << "increase occupancy from " << *TargetOcc - 1 << '\n';
1515 } else {
1516 dbgs() << "reduce spilling (minimum target occupancy is "
1517 << MFI.getMinWavesPerEU() << ")\n";
1518 }
1519 PrintTargetRegions();
1520 });
1521
1522 // We need up-to-date live-out info. to query live-out register masks in
1523 // regions containing rematerializable instructions.
1524 DAG.RegionLiveOuts.buildLiveRegMap();
1525
1526 if (!Remater.analyze()) {
1527 REMAT_DEBUG(dbgs() << "No rematerializable registers\n");
1528 return false;
1529 }
1530 const ScoredRemat::FreqInfo FreqInfo(MF, DAG);
1531
1532 // Set of registers already marked for potential remterialization; used to
1533 // avoid rematerialization chains.
1534 SmallSet<Register, 4> MarkedRegs;
1535
1536 // Collect candidates. We have more restrictions on what we can track here
1537 // compared to the rematerializer.
1538 SmallVector<ScoredRemat, 8> Candidates;
1539 // Map registers to candidate indices. Use ~0u as null value
1540 // since 0 is a valid index.
1541 IndexedMap<unsigned, VirtReg2IndexFunctor> DefRegToCandIdx(~0u);
1542 DefRegToCandIdx.resize(DAG.MRI.getNumVirtRegs());
1543 const unsigned NumRegions = DAG.Regions.size();
1544
1545 for (unsigned RegIdx = 0, E = Remater.getNumRegs(); RegIdx < E; ++RegIdx) {
1546 const Rematerializer::Reg &CandReg = Remater.getReg(RegIdx);
1547
1548 // All users must be in a single region.
1549 if (CandReg.Uses.size() != 1)
1550 continue;
1551 const auto [UseRegion, Users] = *CandReg.Uses.begin();
1552
1553 // Rematerialization moves the defining instruction into the region of its
1554 // use, which may sit under different control dependencies (e.g., across a
1555 // change of EXEC). Convergent operations must not be made control-dependent
1556 // on additional values, so they cannot be safely relocated this way. This
1557 // mirrors the check MachineSink performs before sinking an instruction.
1558 if (any_of(CandReg.Defs,
1559 [](const MachineInstr *DefMI) { return DefMI->isConvergent(); }))
1560 continue;
1561
1562 // We further filter the registers that we can rematerialize based on our
1563 // current tracking capabilities in the stage. Users cannot themselves be
1564 // marked rematerializable, and no register operand of the defining MI can
1565 // be marked rematerializable. We also do not rematerialize an instruction
1566 // if it uses registers that aren't available at its use. This ensures that
1567 // we are not extending any live range while rematerializing.
1568 if (llvm::any_of(Users, [&MarkedRegs](const MachineInstr *UserMI) {
1569 assert(UserMI->getNumOperands() > 0 &&
1570 "user must have at least one operand");
1571 const MachineOperand &UseMO = UserMI->getOperand(0);
1572 return UseMO.isReg() && MarkedRegs.contains(UseMO.getReg());
1573 }))
1574 continue;
1575 MachineInstr *FirstUseMI =
1576 CandReg.getRegionUseBounds(UseRegion, *DAG.LIS).first;
1577 assert(FirstUseMI && "there must be a user in the region");
1578 SlotIndex FirstUseIdx =
1579 DAG.LIS->getInstructionIndex(*FirstUseMI).getRegSlot(true);
1580 SlotIndex RefIdx =
1581 DAG.LIS->getInstructionIndex(*CandReg.getLastDef()).getRegSlot(true);
1582 if (llvm::any_of(CandReg.Dependencies, [&](RegisterIdx DepRegIdx) {
1583 const Rematerializer::Reg &DepReg = Remater.getReg(DepRegIdx);
1584 Register DepDefReg = DepReg.getDefReg();
1585 return MarkedRegs.contains(DepDefReg) ||
1586 !Remater.isRegIdenticalAtUses(DepDefReg, DepReg.Mask, RefIdx,
1587 {FirstUseIdx});
1588 }))
1589 continue;
1590 if (llvm::any_of(Remater.getUnrematableDeps(RegIdx),
1591 [&](const std::pair<Register, LaneBitmask> &RegAndMask) {
1592 const auto &[Reg, Mask] = RegAndMask;
1593 return !Remater.isRegIdenticalAtUses(Reg, Mask, RefIdx,
1594 {FirstUseIdx});
1595 }))
1596 continue;
1597
1598 Register DefReg = CandReg.getDefReg();
1599 MarkedRegs.insert(DefReg);
1600 DefRegToCandIdx[DefReg] = Candidates.size();
1601 Candidates.emplace_back(RegIdx, NumRegions);
1602 }
1603
1604 // Initialize the LiveIn and LiveOut sets of all candidates.
1605 // Iterating all regions and their live regs once is considerably
1606 // more efficient than querying those structures for each candidate
1607 // separately in ScoredRemat::init.
1608 for (unsigned I = 0; I < NumRegions; ++I) {
1609 for (const auto &[Reg, Mask] : DAG.LiveIns[I]) {
1611 continue;
1612 unsigned CandIdx = DefRegToCandIdx[Reg];
1613 if (CandIdx != ~0u)
1614 Candidates[CandIdx].LiveIn.set(I);
1615 }
1616 for (const auto &[Reg, Mask] :
1617 DAG.RegionLiveOuts.getLiveRegsForRegionIdx(I)) {
1619 continue;
1620 unsigned CandIdx = DefRegToCandIdx[Reg];
1621 if (CandIdx != ~0u)
1622 Candidates[CandIdx].LiveOut.set(I);
1623 }
1624 }
1625
1626 // Finish initializing candidates.
1627 SmallVector<unsigned> CandidateOrder;
1628 for (auto [CandIdx, Cand] : enumerate(Candidates)) {
1629 Cand.init(FreqInfo, Remater, DAG);
1630 Cand.update(TargetRegions, RPTargets, FreqInfo, !TargetOcc);
1631 if (!Cand.hasNullScore())
1632 CandidateOrder.push_back(CandIdx);
1633 }
1634
1635 if (TargetOcc) {
1636 // Every rematerialization we do here is likely to move the instruction
1637 // into a higher frequency region, increasing the total sum latency of the
1638 // instruction itself. This is acceptable if we are eliminating a spill in
1639 // the process, but when the goal is increasing occupancy we get nothing
1640 // out of rematerialization if occupancy is not increased in the end; in
1641 // such cases we want to roll back the rematerialization.
1642 Rollback = std::make_unique<RollbackSupport>(Remater);
1643 }
1644
1645 // Rematerialize registers in successive rounds until all RP targets are
1646 // satisifed or until we run out of rematerialization candidates.
1647 BitVector RecomputeRP(DAG.Regions.size());
1648 for (;;) {
1649 RecomputeRP.reset();
1650
1651 // Sort candidates in increasing score order.
1652 sort(CandidateOrder, [&](unsigned LHSIndex, unsigned RHSIndex) {
1653 return Candidates[LHSIndex] < Candidates[RHSIndex];
1654 });
1655
1656 REMAT_DEBUG({
1657 dbgs() << "==== NEW REMAT ROUND ====\n"
1658 << REMAT_PREFIX
1659 << "Candidates with non-null score, in rematerialization order:\n";
1660 for (const ScoredRemat &Cand : reverse(Candidates)) {
1661 dbgs() << REMAT_PREFIX << " " << Cand.print() << " | "
1662 << Remater.printRematReg(Cand.RegIdx) << '\n';
1663 }
1664 PrintTargetRegions();
1665 });
1666
1667 // Rematerialize registers in decreasing score order until we estimate
1668 // that all RP targets are satisfied or until rematerialization candidates
1669 // are no longer useful to decrease RP.
1670 while (!CandidateOrder.empty()) {
1671 const ScoredRemat &Cand = Candidates[CandidateOrder.back()];
1672 const Rematerializer::Reg &Reg = Remater.getReg(Cand.RegIdx);
1673
1674 // When previous rematerializations in this round have already satisfied
1675 // RP targets in all regions this rematerialization can impact, we have a
1676 // good indication that our scores have diverged significantly from
1677 // reality, in which case we interrupt this round and re-score. This also
1678 // ensures that every rematerialization we perform is possibly impactful
1679 // in at least one target region.
1680 if (!Cand.maybeBeneficial(TargetRegions, RPTargets)) {
1681 REMAT_DEBUG(dbgs() << "Interrupt round on stale score for "
1682 << Cand.print() << " | "
1683 << Remater.printRematReg(Cand.RegIdx));
1684 break;
1685 }
1686 CandidateOrder.pop_back();
1687
1688#ifdef EXPENSIVE_CHECKS
1689 // All uses are known to be available / live at the remat point. Thus,
1690 // the uses should already be live in to the using region.
1691 for (const MachineInstr *DefMI : Reg.Defs) {
1692 for (const MachineOperand &MO : DefMI->operands()) {
1693 // Exclude the defined register. We are rematerializing all
1694 // instructions defining it so we don't care that its value is
1695 // available at the remat point.
1696 if (!MO.isReg() || !MO.getReg() || !MO.readsReg() || MO.isDef())
1697 continue;
1698
1699 Register UseReg = MO.getReg();
1700 if (!UseReg.isVirtual())
1701 continue;
1702
1703 LiveInterval &LI = DAG.LIS->getInterval(UseReg);
1704 LaneBitmask LM = DAG.MRI.getMaxLaneMaskForVReg(MO.getReg());
1705 if (LI.hasSubRanges() && MO.getSubReg())
1706 LM = DAG.TRI->getSubRegIndexLaneMask(MO.getSubReg());
1707
1708 const unsigned UseRegion = Reg.Uses.begin()->first;
1709 LaneBitmask LiveInMask = DAG.LiveIns[UseRegion].at(UseReg);
1710 LaneBitmask UncoveredLanes = LM & ~(LiveInMask & LM);
1711 // If this register has lanes not covered by the LiveIns, be sure they
1712 // do not map to any subrange. ref:
1713 // machine-scheduler-sink-trivial-remats.mir::omitted_subrange
1714 if (UncoveredLanes.any()) {
1715 assert(LI.hasSubRanges());
1716 for (LiveInterval::SubRange &SR : LI.subranges())
1717 assert((SR.LaneMask & UncoveredLanes).none());
1718 }
1719 }
1720 }
1721#endif
1722
1723 // Remove the register from all regions where it is a live-in or live-out,
1724 // then rematerialize the register.
1725 REMAT_DEBUG(dbgs() << "** REMAT " << Remater.printRematReg(Cand.RegIdx)
1726 << '\n');
1727 removeFromLiveMaps(Reg.getDefReg(), Cand.LiveIn, Cand.LiveOut);
1728 if (Rollback) {
1729 Rollback->LiveMapUpdates.emplace_back(Cand.RegIdx, Cand.LiveIn,
1730 Cand.LiveOut);
1731 }
1732 Cand.rematerialize(Remater);
1733
1734 // Adjust RP targets. The save is guaranteed in regions in which the
1735 // register is live-through and unused but optimistic in all other regions
1736 // where the register is live.
1737 updateRPTargets(Cand.Live, Cand.RPSave);
1738 RecomputeRP |= Cand.UnpredictableRPSave;
1739 RescheduleRegions |= Cand.Live;
1740 if (!TargetRegions.any()) {
1741 REMAT_DEBUG(dbgs() << "All targets cleared, verifying...\n");
1742 break;
1743 }
1744 }
1745
1746 if (!updateAndVerifyRPTargets(RecomputeRP) && !TargetRegions.any()) {
1747 REMAT_DEBUG(dbgs() << "Objectives achieved!\n");
1748 break;
1749 }
1750
1751 // Update the score of remaining candidates and filter out those that have
1752 // become useless from the vector. Candidates never become useful after
1753 // having been useless for a round, so we can freely drop them without
1754 // losing any future rematerialization opportunity.
1755 unsigned NumUsefulCandidates = 0;
1756 for (unsigned CandIdx : CandidateOrder) {
1757 ScoredRemat &Candidate = Candidates[CandIdx];
1758 Candidate.update(TargetRegions, RPTargets, FreqInfo, !TargetOcc);
1759 if (!Candidate.hasNullScore())
1760 CandidateOrder[NumUsefulCandidates++] = CandIdx;
1761 }
1762 if (NumUsefulCandidates == 0) {
1763 REMAT_DEBUG(dbgs() << "Stop on exhausted rematerialization candidates\n");
1764 break;
1765 }
1766 CandidateOrder.truncate(NumUsefulCandidates);
1767 }
1768
1769 if (RescheduleRegions.none())
1770 return false;
1771
1772 // Commit all pressure changes to the DAG and compute minimum achieved
1773 // occupancy in impacted regions.
1774 REMAT_DEBUG(dbgs() << "==== REMAT RESULTS ====\n");
1775 unsigned DynamicVGPRBlockSize = MFI.getDynamicVGPRBlockSize();
1776 for (unsigned I : RescheduleRegions.set_bits()) {
1777 DAG.Pressure[I] = RPTargets[I].getCurrentRP();
1778 REMAT_DEBUG(dbgs() << '[' << I << "] Achieved occupancy "
1779 << DAG.Pressure[I].getOccupancy(ST, DynamicVGPRBlockSize)
1780 << " (" << RPTargets[I] << ")\n");
1781 }
1782 AchievedOcc = MFI.getMaxWavesPerEU();
1783 for (const GCNRegPressure &RP : DAG.Pressure) {
1784 AchievedOcc =
1785 std::min(AchievedOcc, RP.getOccupancy(ST, DynamicVGPRBlockSize));
1786 }
1787
1788 REMAT_DEBUG({
1789 dbgs() << "Retrying function scheduling with new min. occupancy of "
1790 << AchievedOcc << " from rematerializing (original was "
1791 << DAG.MinOccupancy;
1792 if (TargetOcc)
1793 dbgs() << ", target was " << *TargetOcc;
1794 dbgs() << ")\n";
1795 });
1796
1797 DAG.setTargetOccupancy(getStageTargetOccupancy());
1798 return true;
1799}
1800
1802 DAG.finishBlock();
1803 LLVM_DEBUG(dbgs() << "Ending scheduling stage: " << StageID << "\n");
1804}
1805
1807 SavedMutations.swap(DAG.Mutations);
1808 S.SGPRLimitBias = S.VGPRLimitBias = 0;
1809 if (DAG.MinOccupancy > InitialOccupancy) {
1810 assert(IsAnyRegionScheduled);
1812 << " stage successfully increased occupancy to "
1813 << DAG.MinOccupancy << '\n');
1814 } else if (!IsAnyRegionScheduled) {
1815 assert(DAG.MinOccupancy == InitialOccupancy);
1817 << ": No regions scheduled, min occupancy stays at "
1818 << DAG.MinOccupancy << ", MFI occupancy stays at "
1819 << MFI.getOccupancy() << ".\n");
1820 }
1821
1823}
1824
1826 // Skip empty scheduling region.
1827 if (DAG.begin() == DAG.end())
1828 return false;
1829
1830 // Check whether this new region is also a new block.
1831 if (DAG.RegionBegin->getParent() != CurrentMBB)
1832 setupNewBlock();
1833
1834 unsigned NumRegionInstrs = std::distance(DAG.begin(), DAG.end());
1835 DAG.enterRegion(CurrentMBB, DAG.begin(), DAG.end(), NumRegionInstrs);
1836
1837 // Skip regions with 1 schedulable instruction.
1838 if (DAG.begin() == std::prev(DAG.end()))
1839 return false;
1840
1841 LLVM_DEBUG(dbgs() << "********** MI Scheduling **********\n");
1842 LLVM_DEBUG(dbgs() << MF.getName() << ":" << printMBBReference(*CurrentMBB)
1843 << " " << CurrentMBB->getName()
1844 << "\n From: " << *DAG.begin() << " To: ";
1845 if (DAG.RegionEnd != CurrentMBB->end()) dbgs() << *DAG.RegionEnd;
1846 else dbgs() << "End";
1847 dbgs() << " RegionInstrs: " << NumRegionInstrs << '\n');
1848
1849 // Save original instruction order before scheduling for possible revert.
1850 Unsched.clear();
1851 Unsched.reserve(DAG.NumRegionInstrs);
1854 const SIInstrInfo *SII = static_cast<const SIInstrInfo *>(DAG.TII);
1855 for (auto &I : DAG) {
1856 Unsched.push_back(&I);
1857 if (SII->isIGLPMutationOnly(I.getOpcode()))
1858 DAG.RegionsWithIGLPInstrs[RegionIdx] = true;
1859 }
1860 } else {
1861 for (auto &I : DAG)
1862 Unsched.push_back(&I);
1863 }
1864
1865 PressureBefore = DAG.Pressure[RegionIdx];
1866
1867 LLVM_DEBUG(
1868 dbgs() << "Pressure before scheduling:\nRegion live-ins:"
1869 << print(DAG.LiveIns[RegionIdx], DAG.MRI)
1870 << "Region live-in pressure: "
1871 << print(llvm::getRegPressure(DAG.MRI, DAG.LiveIns[RegionIdx]))
1872 << "Region register pressure: " << print(PressureBefore));
1873
1874 S.HasHighPressure = false;
1875 S.KnownExcessRP = isRegionWithExcessRP();
1876
1877 if (DAG.RegionsWithIGLPInstrs[RegionIdx] &&
1879 SavedMutations.clear();
1880 SavedMutations.swap(DAG.Mutations);
1881 bool IsInitialStage = StageID == GCNSchedStageID::OccInitialSchedule ||
1883 DAG.addMutation(createIGroupLPDAGMutation(
1884 IsInitialStage ? AMDGPU::SchedulingPhase::Initial
1886 }
1887
1888 return true;
1889}
1890
1892 // Only reschedule regions that have excess register pressure (i.e. spilling)
1893 // or had minimum occupancy at the beginning of the stage (as long as
1894 // rescheduling of previous regions did not make occupancy drop back down to
1895 // the initial minimum).
1896 unsigned DynamicVGPRBlockSize = DAG.MFI.getDynamicVGPRBlockSize();
1897 // If no region has been scheduled yet, the DAG has not yet been updated with
1898 // the occupancy target. So retrieve it from the temporary.
1899 unsigned CurrentTargetOccupancy =
1900 IsAnyRegionScheduled ? DAG.MinOccupancy : TempTargetOccupancy;
1901 if (!DAG.RegionsWithExcessRP[RegionIdx] &&
1902 (CurrentTargetOccupancy <= InitialOccupancy ||
1903 DAG.Pressure[RegionIdx].getOccupancy(ST, DynamicVGPRBlockSize) !=
1904 InitialOccupancy))
1905 return false;
1906
1907 bool IsSchedulingThisRegion = GCNSchedStage::initGCNRegion();
1908 // If this is the first region scheduled during this stage, make the target
1909 // occupancy changes in the DAG and MFI.
1910 if (!IsAnyRegionScheduled && IsSchedulingThisRegion) {
1911 IsAnyRegionScheduled = true;
1912 if (MFI.getMaxWavesPerEU() > DAG.MinOccupancy)
1913 DAG.setTargetOccupancy(TempTargetOccupancy);
1914 }
1915 return IsSchedulingThisRegion;
1916}
1917
1919 // We may need to reschedule this region if it wasn't rescheduled in the last
1920 // stage, or if we found it was testing critical register pressure limits in
1921 // the unclustered reschedule stage. The later is because we may not have been
1922 // able to raise the min occupancy in the previous stage so the region may be
1923 // overly constrained even if it was already rescheduled.
1924 if (!DAG.RegionsWithHighRP[RegionIdx])
1925 return false;
1926
1928}
1929
1931 return !RevertAllRegions && RescheduleRegions[RegionIdx] &&
1933}
1934
1936 if (CurrentMBB)
1937 DAG.finishBlock();
1938
1939 CurrentMBB = DAG.RegionBegin->getParent();
1940 DAG.startBlock(CurrentMBB);
1941 // Get real RP for the region if it hasn't be calculated before. After the
1942 // initial schedule stage real RP will be collected after scheduling.
1946 DAG.computeBlockPressure(RegionIdx, CurrentMBB);
1947}
1948
1950 DAG.Regions[RegionIdx] = std::pair(DAG.RegionBegin, DAG.RegionEnd);
1951 if (S.HasHighPressure)
1952 DAG.RegionsWithHighRP[RegionIdx] = true;
1953
1954 // Revert scheduling if we have dropped occupancy or there is some other
1955 // reason that the original schedule is better.
1957
1958 if (DAG.RegionsWithIGLPInstrs[RegionIdx] &&
1960 SavedMutations.swap(DAG.Mutations);
1961}
1962
1965 // When the goal is to increase occupancy, all regions must reach the target
1966 // occupancy for rematerializations to be possibly useful, otherwise we will
1967 // just hurt latency for no benefit. If minimum occupancy drops below the
1968 // target there is no point in trying to re-schedule further regions.
1969 if (!TargetOcc)
1970 return;
1971 RegionReverts.emplace_back(RegionIdx, Unsched, PressureBefore);
1972 if (DAG.MinOccupancy < *TargetOcc) {
1973 REMAT_DEBUG(dbgs() << "Region " << RegionIdx
1974 << " cannot meet occupancy target, interrupting "
1975 "re-scheduling in all regions\n");
1976 RevertAllRegions = true;
1977 }
1978}
1979
1981 // Check the results of scheduling.
1982 PressureAfter = DAG.getRealRegPressure(RegionIdx);
1983
1984 LLVM_DEBUG(dbgs() << "Pressure after scheduling: " << print(PressureAfter));
1985 LLVM_DEBUG(dbgs() << "Region: " << RegionIdx << ".\n");
1986
1987 unsigned DynamicVGPRBlockSize = DAG.MFI.getDynamicVGPRBlockSize();
1988
1989 if (PressureAfter.getSGPRNum() <= S.SGPRCriticalLimit &&
1990 PressureAfter.getVGPRNum(ST.hasGFX90AInsts()) <= S.VGPRCriticalLimit) {
1991 DAG.Pressure[RegionIdx] = PressureAfter;
1992
1993 // Early out if we have achieved the occupancy target.
1994 LLVM_DEBUG(dbgs() << "Pressure in desired limits, done.\n");
1995 return;
1996 }
1997
1998 unsigned TargetOccupancy = std::min(
1999 S.getTargetOccupancy(), ST.getOccupancyWithWorkGroupSizes(MF).second);
2000 unsigned WavesAfter = std::min(
2001 TargetOccupancy, PressureAfter.getOccupancy(ST, DynamicVGPRBlockSize));
2002 unsigned WavesBefore = std::min(
2003 TargetOccupancy, PressureBefore.getOccupancy(ST, DynamicVGPRBlockSize));
2004 LLVM_DEBUG(dbgs() << "Occupancy before scheduling: " << WavesBefore
2005 << ", after " << WavesAfter << ".\n");
2006
2007 // We may not be able to keep the current target occupancy because of the just
2008 // scheduled region. We might still be able to revert scheduling if the
2009 // occupancy before was higher, or if the current schedule has register
2010 // pressure higher than the excess limits which could lead to more spilling.
2011 unsigned NewOccupancy = std::max(WavesAfter, WavesBefore);
2012
2013 // Allow memory bound functions to drop to 4 waves if not limited by an
2014 // attribute.
2015 if (WavesAfter < WavesBefore && WavesAfter < DAG.MinOccupancy &&
2016 WavesAfter >= MFI.getMinAllowedOccupancy()) {
2017 LLVM_DEBUG(dbgs() << "Function is memory bound, allow occupancy drop up to "
2018 << MFI.getMinAllowedOccupancy() << " waves\n");
2019 NewOccupancy = WavesAfter;
2020 }
2021
2022 if (NewOccupancy < DAG.MinOccupancy) {
2023 DAG.MinOccupancy = NewOccupancy;
2024 MFI.limitOccupancy(DAG.MinOccupancy);
2025 LLVM_DEBUG(dbgs() << "Occupancy lowered for the function to "
2026 << DAG.MinOccupancy << ".\n");
2027 }
2028 // The maximum number of arch VGPR on non-unified register file, or the
2029 // maximum VGPR + AGPR in the unified register file case.
2030 unsigned MaxVGPRs = ST.getMaxNumVGPRs(MF);
2031 // The maximum number of arch VGPR for both unified and non-unified register
2032 // file.
2033 unsigned MaxArchVGPRs = std::min(MaxVGPRs, ST.getAddressableNumArchVGPRs());
2034 unsigned MaxSGPRs = ST.getMaxNumSGPRs(MF);
2035
2036 if (PressureAfter.getVGPRNum(ST.hasGFX90AInsts()) > MaxVGPRs ||
2037 PressureAfter.getArchVGPRNum() > MaxArchVGPRs ||
2038 PressureAfter.getAGPRNum() > MaxArchVGPRs ||
2039 PressureAfter.getSGPRNum() > MaxSGPRs) {
2040 DAG.RegionsWithHighRP[RegionIdx] = true;
2041 DAG.RegionsWithExcessRP[RegionIdx] = true;
2042 }
2043
2044 // Revert if this region's schedule would cause a drop in occupancy or
2045 // spilling.
2046 if (shouldRevertScheduling(WavesAfter)) {
2048 std::tie(DAG.RegionBegin, DAG.RegionEnd) = DAG.Regions[RegionIdx];
2049 } else {
2050 DAG.Pressure[RegionIdx] = PressureAfter;
2051 }
2052}
2053
2054unsigned
2055GCNSchedStage::computeSUnitReadyCycle(const SUnit &SU, unsigned CurrCycle,
2056 DenseMap<unsigned, unsigned> &ReadyCycles,
2057 const TargetSchedModel &SM) {
2058 unsigned ReadyCycle = CurrCycle;
2059 for (auto &D : SU.Preds) {
2060 if (D.isAssignedRegDep()) {
2061 MachineInstr *DefMI = D.getSUnit()->getInstr();
2062 unsigned Latency = SM.computeInstrLatency(DefMI);
2063 unsigned DefReady = ReadyCycles[DAG.getSUnit(DefMI)->NodeNum];
2064 ReadyCycle = std::max(ReadyCycle, DefReady + Latency);
2065 }
2066 }
2067 ReadyCycles[SU.NodeNum] = ReadyCycle;
2068 return ReadyCycle;
2069}
2070
2071#ifndef NDEBUG
2073 bool operator()(std::pair<MachineInstr *, unsigned> A,
2074 std::pair<MachineInstr *, unsigned> B) const {
2075 return A.second < B.second;
2076 }
2077};
2078
2079static void printScheduleModel(std::set<std::pair<MachineInstr *, unsigned>,
2080 EarlierIssuingCycle> &ReadyCycles) {
2081 if (ReadyCycles.empty())
2082 return;
2083 unsigned BBNum = ReadyCycles.begin()->first->getParent()->getNumber();
2084 dbgs() << "\n################## Schedule time ReadyCycles for MBB : " << BBNum
2085 << " ##################\n# Cycle #\t\t\tInstruction "
2086 " "
2087 " \n";
2088 unsigned IPrev = 1;
2089 for (auto &I : ReadyCycles) {
2090 if (I.second > IPrev + 1)
2091 dbgs() << "****************************** BUBBLE OF " << I.second - IPrev
2092 << " CYCLES DETECTED ******************************\n\n";
2093 dbgs() << "[ " << I.second << " ] : " << *I.first << "\n";
2094 IPrev = I.second;
2095 }
2096}
2097#endif
2098
2099ScheduleMetrics
2100GCNSchedStage::getScheduleMetrics(const std::vector<SUnit> &InputSchedule) {
2101#ifndef NDEBUG
2102 std::set<std::pair<MachineInstr *, unsigned>, EarlierIssuingCycle>
2103 ReadyCyclesSorted;
2104#endif
2105 const TargetSchedModel &SM = ST.getInstrInfo()->getSchedModel();
2106 unsigned SumBubbles = 0;
2107 DenseMap<unsigned, unsigned> ReadyCycles;
2108 unsigned CurrCycle = 0;
2109 for (auto &SU : InputSchedule) {
2110 unsigned ReadyCycle =
2111 computeSUnitReadyCycle(SU, CurrCycle, ReadyCycles, SM);
2112 SumBubbles += ReadyCycle - CurrCycle;
2113#ifndef NDEBUG
2114 ReadyCyclesSorted.insert(std::make_pair(SU.getInstr(), ReadyCycle));
2115#endif
2116 CurrCycle = ++ReadyCycle;
2117 }
2118#ifndef NDEBUG
2119 LLVM_DEBUG(
2120 printScheduleModel(ReadyCyclesSorted);
2121 dbgs() << "\n\t"
2122 << "Metric: "
2123 << (SumBubbles
2124 ? (SumBubbles * ScheduleMetrics::ScaleFactor) / CurrCycle
2125 : 1)
2126 << "\n\n");
2127#endif
2128
2129 return ScheduleMetrics(CurrCycle, SumBubbles);
2130}
2131
2134#ifndef NDEBUG
2135 std::set<std::pair<MachineInstr *, unsigned>, EarlierIssuingCycle>
2136 ReadyCyclesSorted;
2137#endif
2138 const TargetSchedModel &SM = ST.getInstrInfo()->getSchedModel();
2139 unsigned SumBubbles = 0;
2140 DenseMap<unsigned, unsigned> ReadyCycles;
2141 unsigned CurrCycle = 0;
2142 for (auto &MI : DAG) {
2143 SUnit *SU = DAG.getSUnit(&MI);
2144 if (!SU)
2145 continue;
2146 unsigned ReadyCycle =
2147 computeSUnitReadyCycle(*SU, CurrCycle, ReadyCycles, SM);
2148 SumBubbles += ReadyCycle - CurrCycle;
2149#ifndef NDEBUG
2150 ReadyCyclesSorted.insert(std::make_pair(SU->getInstr(), ReadyCycle));
2151#endif
2152 CurrCycle = ++ReadyCycle;
2153 }
2154#ifndef NDEBUG
2155 LLVM_DEBUG(
2156 printScheduleModel(ReadyCyclesSorted);
2157 dbgs() << "\n\t"
2158 << "Metric: "
2159 << (SumBubbles
2160 ? (SumBubbles * ScheduleMetrics::ScaleFactor) / CurrCycle
2161 : 1)
2162 << "\n\n");
2163#endif
2164
2165 return ScheduleMetrics(CurrCycle, SumBubbles);
2166}
2167
2168bool GCNSchedStage::shouldRevertScheduling(unsigned WavesAfter) {
2169 if (WavesAfter < DAG.MinOccupancy)
2170 return true;
2171
2172 // For dynamic VGPR mode, we don't want to waste any VGPR blocks.
2173 if (DAG.MFI.isDynamicVGPREnabled()) {
2174 unsigned BlocksBefore = AMDGPU::IsaInfo::getAllocatedNumVGPRBlocks(
2175 ST, PressureBefore.getVGPRNum(false),
2176 DAG.MFI.getDynamicVGPRBlockSize());
2177 unsigned BlocksAfter = AMDGPU::IsaInfo::getAllocatedNumVGPRBlocks(
2178 ST, PressureAfter.getVGPRNum(false), DAG.MFI.getDynamicVGPRBlockSize());
2179 if (BlocksAfter > BlocksBefore)
2180 return true;
2181 }
2182
2183 return false;
2184}
2185
2188 return false;
2189
2191 return true;
2192
2193 if (mayCauseSpilling(WavesAfter))
2194 return true;
2195
2196 return false;
2197}
2198
2200 // If RP is not reduced in the unclustered reschedule stage, revert to the
2201 // old schedule.
2202 if ((WavesAfter <=
2203 PressureBefore.getOccupancy(ST, DAG.MFI.getDynamicVGPRBlockSize()) &&
2204 mayCauseSpilling(WavesAfter)) ||
2206 LLVM_DEBUG(dbgs() << "Unclustered reschedule did not help.\n");
2207 return true;
2208 }
2209
2210 // Do not attempt to relax schedule even more if we are already spilling.
2212 return false;
2213
2214 LLVM_DEBUG(
2215 dbgs()
2216 << "\n\t *** In shouldRevertScheduling ***\n"
2217 << " *********** BEFORE UnclusteredHighRPStage ***********\n");
2218 ScheduleMetrics MBefore = getScheduleMetrics(DAG.SUnits);
2219 LLVM_DEBUG(
2220 dbgs()
2221 << "\n *********** AFTER UnclusteredHighRPStage ***********\n");
2223 unsigned OldMetric = MBefore.getMetric();
2224 unsigned NewMetric = MAfter.getMetric();
2225 unsigned WavesBefore = std::min(
2226 S.getTargetOccupancy(),
2227 PressureBefore.getOccupancy(ST, DAG.MFI.getDynamicVGPRBlockSize()));
2228 unsigned Profit =
2229 ((WavesAfter * ScheduleMetrics::ScaleFactor) / WavesBefore *
2231 NewMetric) /
2233 LLVM_DEBUG(dbgs() << "\tMetric before " << MBefore << "\tMetric after "
2234 << MAfter << "Profit: " << Profit << "\n");
2235 return Profit < ScheduleMetrics::ScaleFactor;
2236}
2237
2240 return false;
2241
2243 return true;
2244
2245 if (mayCauseSpilling(WavesAfter))
2246 return true;
2247
2248 return false;
2249}
2250
2252 // When trying to increase occupancy (TargetOcc == true) the stage manages
2253 // region reverts globally (all or none), so we always return false here.
2254 return !TargetOcc && mayCauseSpilling(WavesAfter);
2255}
2256
2258 if (mayCauseSpilling(WavesAfter))
2259 return true;
2260
2261 return false;
2262}
2263
2265 unsigned WavesAfter) {
2266 return mayCauseSpilling(WavesAfter);
2267}
2268
2270 "amdgpu-lirp-reschedule", cl::Hidden,
2271 cl::desc("Enable live interval RP reschedule stage"), cl::init(true));
2272
2274 "amdgpu-lirp-threshold", cl::Hidden,
2275 cl::desc("Percent increase of live interval RP over instant pressure to "
2276 "trigger rescheduling"),
2277 cl::init(10));
2278
2280 "amdgpu-lirp-vgpr-reduction", cl::Hidden,
2281 cl::desc(
2282 "Reduction factor (percent) for VGPR threshold during live interval RP "
2283 "reschedule stage"),
2284 cl::init(90));
2285
2287 "amdgpu-lirp-instant-lower-bound", cl::Hidden,
2288 cl::desc("Lower bound (percent of the VGPR excess limit) on instant RP, "
2289 "below which a region is skipped"),
2290 cl::init(10));
2291
2294 return false;
2295
2297 return false;
2298
2299 if (!S.VGPRThresholdPercent) {
2300 LLVM_DEBUG(dbgs() << "LIRP: expected VGPRThresholdPercent to be enabled, "
2301 "not using live interval RP reschedule stage\n");
2302 return false;
2303 }
2304
2305 return true;
2306}
2307
2309 unsigned InstantRP = DAG.Pressure[RegionIdx].getArchVGPRNum();
2310 auto [RegionBegin, RegionEnd] = DAG.Regions[RegionIdx];
2311 if (RegionBegin == RegionEnd)
2312 return false;
2313
2314 unsigned LIRP = estimateGreedyVGPRPressure(
2315 RegionBegin, RegionEnd, DAG.LiveIns[RegionIdx], *DAG.getLIS(),
2316 DAG.MF.getRegInfo(), static_cast<const SIRegisterInfo &>(*DAG.TRI));
2317
2318 unsigned NewVGPRThresholdPercent =
2319 (S.VGPRThresholdPercent * LiveIntervalRPVGPRReduction + 99) / 100;
2320
2321 LLVM_DEBUG(dbgs() << "LIRP: Region " << RegionIdx
2322 << ", VGPRThresholdPercent: " << S.VGPRThresholdPercent
2323 << " -> " << NewVGPRThresholdPercent
2324 << ", VGPRExcessLimit=" << S.VGPRExcessLimit
2325 << ", VGPRCriticalLimit=" << S.VGPRCriticalLimit
2326 << ", InstantRP=" << InstantRP << ", LIRP=" << LIRP);
2327
2328 bool DoRescheduling = false;
2329 // Lower bound on InstantRP to skip over tiny regions.
2330 unsigned InstantRPLowerBound =
2331 S.VGPRExcessLimit * LiveIntervalRPInstantLowerBound / 100;
2332 if (LIRP > S.VGPRExcessLimit) {
2333 LLVM_DEBUG(dbgs() << " [LIRP exceeds the limit (" << S.VGPRExcessLimit
2334 << "), rescheduling]");
2335 DoRescheduling = true;
2336 } else if (LIRP > InstantRP && InstantRP > InstantRPLowerBound) {
2337 unsigned IncreasePercent = ((LIRP - InstantRP) * 100) / InstantRP;
2338 if (IncreasePercent > LiveIntervalRPThreshold) {
2339 LLVM_DEBUG(dbgs() << " [" << IncreasePercent << "% > "
2340 << LiveIntervalRPThreshold << "%, rescheduling]");
2341 DoRescheduling = true;
2342 }
2343 }
2344 LLVM_DEBUG(dbgs() << '\n');
2345
2346 if (DoRescheduling && GCNSchedStage::initGCNRegion()) {
2347 SavedVGPRExcessLimit = S.VGPRExcessLimit;
2348 SavedVGPRCriticalLimit = S.VGPRCriticalLimit;
2349 SavedVGPRThresholdPercent = S.VGPRThresholdPercent;
2350 S.VGPRThresholdPercent = NewVGPRThresholdPercent;
2351 return true;
2352 }
2353
2354 return false;
2355}
2356
2358 S.VGPRExcessLimit = SavedVGPRExcessLimit;
2359 S.VGPRCriticalLimit = SavedVGPRCriticalLimit;
2360 S.VGPRThresholdPercent = SavedVGPRThresholdPercent;
2362}
2363
2364bool GCNSchedStage::mayCauseSpilling(unsigned WavesAfter) {
2365 if (WavesAfter <= MFI.getMinWavesPerEU() && isRegionWithExcessRP() &&
2367 LLVM_DEBUG(dbgs() << "New pressure will result in more spilling.\n");
2368 return true;
2369 }
2370
2371 return false;
2372}
2373
2375 ArrayRef<MachineInstr *> MIOrder) {
2376 assert(static_cast<size_t>(std::distance(DAG.Regions[RegionIdx].first,
2377 DAG.Regions[RegionIdx].second)) ==
2378 MIOrder.size() &&
2379 "instruction number mismatch");
2380 if (MIOrder.empty())
2381 return;
2382
2383 LLVM_DEBUG(dbgs() << "Reverting scheduling for region " << RegionIdx << '\n');
2384
2385 // Reconstruct MI sequence by moving instructions in desired order before
2386 // the current region's start.
2387 MachineBasicBlock::iterator RegionEnd = DAG.Regions[RegionIdx].first;
2388 MachineBasicBlock *MBB = MIOrder.front()->getParent();
2389 for (MachineInstr *MI : MIOrder) {
2390 // Either move the next MI in order before the end of the region or move the
2391 // region end past the MI if it is at the correct position.
2392 MachineBasicBlock::iterator MII = MI->getIterator();
2393 if (MII != RegionEnd) {
2394 // Will subsequent splice move MI up past a non-debug instruction?
2395 bool NonDebugReordered =
2396 !MI->isDebugInstr() &&
2397 skipDebugInstructionsForward(RegionEnd, MII) != MII;
2398 MBB->splice(RegionEnd, MBB, MI);
2399 // Only update LiveIntervals information if non-debug instructions are
2400 // reordered. Otherwise debug instructions could cause code generation to
2401 // change.
2402 if (NonDebugReordered)
2403 DAG.LIS->handleMove(*MI, true);
2404 } else {
2405 // MI is already at the expected position. However, earlier splices in
2406 // this loop may have changed neighboring slot indices, so this MI's
2407 // slot index can become non-monotonic w.r.t. the physical MBB order.
2408 // Only re-seat when monotonicity is actually violated to avoid
2409 // unnecessary LiveInterval changes that could perturb scheduling.
2410 if (!MI->isDebugInstr()) {
2411 SlotIndex MIIdx = DAG.LIS->getInstructionIndex(*MI);
2412 SlotIndex PrevIdx = DAG.LIS->getSlotIndexes()->getIndexBefore(*MI);
2413 if (PrevIdx >= MIIdx)
2414 DAG.LIS->handleMove(*MI, true);
2415 }
2416 ++RegionEnd;
2417 }
2418 if (MI->isDebugInstr()) {
2419 LLVM_DEBUG(dbgs() << "Scheduling " << *MI);
2420 continue;
2421 }
2422
2423 // Reset read-undef flags and update them later.
2424 for (MachineOperand &Op : MI->all_defs())
2425 Op.setIsUndef(false);
2426 RegisterOperands RegOpers;
2427 RegOpers.collect(*MI, *DAG.TRI, DAG.MRI, DAG.ShouldTrackLaneMasks, false);
2428 if (DAG.ShouldTrackLaneMasks) {
2429 // Adjust liveness and add missing dead+read-undef flags.
2430 RegOpers.adjustLaneLiveness(*DAG.LIS, DAG.MRI, *MI);
2431 } else {
2432 // Adjust for missing dead-def flags.
2433 RegOpers.detectDeadDefs(*MI, *DAG.LIS, DAG.MRI);
2434 }
2435 LLVM_DEBUG(dbgs() << "Scheduling " << *MI);
2436 }
2437
2438 // The region end doesn't change throughout scheduling since it itself is
2439 // outside the region (whether that is a MBB end or a terminator MI).
2440 assert(RegionEnd == DAG.Regions[RegionIdx].second && "region end mismatch");
2441 DAG.Regions[RegionIdx].first = MIOrder.front();
2442}
2443
2444/// Returns true if reaching def \p RD will be in AGPR form after the rewrite
2445/// and so needs no bridge copy: a candidate MFMA in \p RewriteSet, an
2446/// AV_MOV_*_IMM_PSEUDO, or a copy from a candidate src2 reg in \p CandSrc2Regs.
2447/// A non-candidate MFMA stays in VGPR form and still needs a bridge.
2449 MachineInstr *RD, const SmallPtrSetImpl<MachineInstr *> &RewriteSet,
2450 const DenseSet<Register> &CandSrc2Regs, const SIInstrInfo &TII) {
2451 if (TII.isMAI(*RD))
2452 return RewriteSet.contains(RD);
2453 if (RD->getOpcode() == AMDGPU::AV_MOV_B32_IMM_PSEUDO ||
2454 RD->getOpcode() == AMDGPU::AV_MOV_B64_IMM_PSEUDO)
2455 return true;
2456 if (RD->isCopy() && CandSrc2Regs.contains(RD->getOperand(1).getReg()))
2457 return true;
2458 return false;
2459}
2460
2461bool RewriteMFMAFormStage::hasUseRequiringVGPR(
2462 ArrayRef<SlotIndex> Src2ReachingDefs,
2463 const SmallPtrSetImpl<MachineInstr *> &RewriteSet) {
2464 for (SlotIndex RDIdx : Src2ReachingDefs) {
2465 const MachineInstr *RD = DAG.LIS->getInstructionFromIndex(RDIdx);
2467 findReachingUses(RD, DAG.LIS, ReachingUses);
2468 for (const MachineOperand *UseMO : ReachingUses) {
2469 const MachineInstr *UseMI = UseMO->getParent();
2470 if (UseMI->isCopy())
2471 continue;
2472 if (TII->isMAI(*UseMI) && RewriteSet.contains(UseMI))
2473 continue;
2474 return true;
2475 }
2476 }
2477 return false;
2478}
2479
2480void RewriteMFMAFormStage::resetRewriteCandsToVGPR(
2481 ArrayRef<std::pair<MachineInstr *, unsigned>> RewriteCands) {
2482 for (auto [MI, OriginalOpcode] : RewriteCands) {
2483 assert(TII->isMAI(*MI));
2484 const TargetRegisterClass *ADefRC =
2485 DAG.MRI.getRegClass(MI->getOperand(0).getReg());
2486 const TargetRegisterClass *VDefRC = SRI->getEquivalentVGPRClass(ADefRC);
2487 DAG.MRI.setRegClass(MI->getOperand(0).getReg(), VDefRC);
2488 MI->setDesc(TII->get(OriginalOpcode));
2489
2490 MachineOperand *Src2 = TII->getNamedOperand(*MI, AMDGPU::OpName::src2);
2491 if (!Src2->isReg())
2492 continue;
2493
2494 // Have to get src types separately since subregs may cause C and D
2495 // registers to be different types even though the actual operand is
2496 // the same size.
2497 const TargetRegisterClass *AUseRC = DAG.MRI.getRegClass(Src2->getReg());
2498 const TargetRegisterClass *VUseRC = SRI->getEquivalentVGPRClass(AUseRC);
2499 DAG.MRI.setRegClass(Src2->getReg(), VUseRC);
2500 }
2501}
2502
2503bool RewriteMFMAFormStage::isRewriteCandidate(MachineInstr *MI) const {
2504 if (!static_cast<const SIInstrInfo *>(DAG.TII)->isMAI(*MI))
2505 return false;
2506 if (AMDGPU::getAGPRFormOp(MI->getOpcode()) == -1)
2507 return false;
2508 // Reject candidates whose users force an unavoidable bridge copy.
2509 Register DstReg = MI->getOperand(0).getReg();
2510 for (const MachineInstr &UseMI : DAG.MRI.use_nodbg_instructions(DstReg)) {
2511 if (!TII->isMAI(UseMI) && !UseMI.isCopy())
2512 return false;
2513 }
2514 return true;
2515}
2516
2517bool RewriteMFMAFormStage::initHeuristics(
2518 std::vector<std::pair<MachineInstr *, unsigned>> &RewriteCands,
2519 DenseMap<MachineBasicBlock *, std::set<Register>> &CopyForUse,
2520 SmallPtrSetImpl<MachineInstr *> &CopyForDef) {
2521 bool Changed = false;
2522
2523 // Collect the candidate group, its members share AGPR-form operands
2524 // post-rewrite, so reaching defs feeding any member don't need bridge copy.
2525 SmallPtrSet<MachineInstr *, 16> RewriteSet;
2526 DenseSet<Register> CandSrc2Regs;
2527 for (MachineBasicBlock &MBB : MF) {
2528 for (MachineInstr &MI : MBB) {
2529 if (!isRewriteCandidate(&MI))
2530 continue;
2531 RewriteSet.insert(&MI);
2532 MachineOperand *Src2 = TII->getNamedOperand(MI, AMDGPU::OpName::src2);
2533 if (Src2 && Src2->isReg())
2534 CandSrc2Regs.insert(Src2->getReg());
2535 }
2536 }
2537
2538 // Prepare for the heuristics
2539 for (MachineBasicBlock &MBB : MF) {
2540 for (MachineInstr &MI : MBB) {
2541 if (!isRewriteCandidate(&MI))
2542 continue;
2543
2544 int ReplacementOp = AMDGPU::getAGPRFormOp(MI.getOpcode());
2545 assert(ReplacementOp != -1);
2546
2547 RewriteCands.push_back({&MI, MI.getOpcode()});
2548 MI.setDesc(TII->get(ReplacementOp));
2549
2550 MachineOperand *Src2 = TII->getNamedOperand(MI, AMDGPU::OpName::src2);
2551 if (Src2->isReg()) {
2552 SmallVector<SlotIndex, 8> Src2ReachingDefs;
2553 findReachingDefs(*Src2, DAG.LIS, Src2ReachingDefs);
2554
2555 // If src2 has a use that must remain VGPR, it cannot be reclassified to
2556 // AGPR.
2557 bool Src2NeedsVGPR = hasUseRequiringVGPR(Src2ReachingDefs, RewriteSet);
2558 Src2NeedsVGPRCache[&MI] = Src2NeedsVGPR;
2559
2560 for (SlotIndex RDIdx : Src2ReachingDefs) {
2561 MachineInstr *RD = DAG.LIS->getInstructionFromIndex(RDIdx);
2562 if (!Src2NeedsVGPR &&
2563 isReachingDefAGPRForm(RD, RewriteSet, CandSrc2Regs, *TII))
2564 continue;
2565 CopyForDef.insert(RD);
2566 }
2567 }
2568
2569 MachineOperand &Dst = MI.getOperand(0);
2570 SmallVector<MachineOperand *, 8> DstReachingUses;
2571
2572 findReachingUses(&MI, DAG.LIS, DstReachingUses);
2573
2574 for (MachineOperand *RUOp : DstReachingUses) {
2575 MachineInstr *UserMI = RUOp->getParent();
2576 // Group members read the AGPR result directly.
2577 if (TII->isMAI(*UserMI) && RewriteSet.contains(UserMI))
2578 continue;
2579
2580 // For any user of the result of the MFMA which is not an MFMA, we
2581 // insert a copy. For a given register, we will only insert one copy
2582 // per user block.
2583 CopyForUse[UserMI->getParent()].insert(RUOp->getReg());
2584
2585 if (TII->isMAI(*UserMI))
2586 continue;
2587
2588 SmallVector<SlotIndex, 8> DstUsesReachingDefs;
2589 findReachingDefs(*RUOp, DAG.LIS, DstUsesReachingDefs);
2590
2591 for (SlotIndex RDIndex : DstUsesReachingDefs) {
2592 MachineInstr *RD = DAG.LIS->getInstructionFromIndex(RDIndex);
2593 if (TII->isMAI(*RD))
2594 continue;
2595
2596 // For any definition of the user of the MFMA which is not an MFMA,
2597 // we insert a copy. We do this to transform all the reaching defs
2598 // of this use to AGPR. By doing this, we can insert a copy from
2599 // AGPR to VGPR at the user rather than after the MFMA.
2600 CopyForDef.insert(RD);
2601 }
2602 }
2603
2604 // Do the rewrite to allow for updated RP calculation.
2605 const TargetRegisterClass *VDefRC = DAG.MRI.getRegClass(Dst.getReg());
2606 const TargetRegisterClass *ADefRC = SRI->getEquivalentAGPRClass(VDefRC);
2607 DAG.MRI.setRegClass(Dst.getReg(), ADefRC);
2608 if (Src2->isReg()) {
2609 // Have to get src types separately since subregs may cause C and D
2610 // registers to be different types even though the actual operand is
2611 // the same size.
2612 const TargetRegisterClass *VUseRC = DAG.MRI.getRegClass(Src2->getReg());
2613 const TargetRegisterClass *AUseRC = SRI->getEquivalentAGPRClass(VUseRC);
2614 DAG.MRI.setRegClass(Src2->getReg(), AUseRC);
2615 }
2616 Changed = true;
2617 }
2618 }
2619
2620 return Changed;
2621}
2622
2623int64_t RewriteMFMAFormStage::getRewriteCost(
2624 ArrayRef<std::pair<MachineInstr *, unsigned>> RewriteCands,
2625 const DenseMap<MachineBasicBlock *, std::set<Register>> &CopyForUse,
2626 const SmallPtrSetImpl<MachineInstr *> &CopyForDef) {
2627 MachineBlockFrequencyInfo *MBFI = DAG.MBFI;
2628
2629 int64_t BestSpillCost = 0;
2630 int64_t Cost = 0;
2631 uint64_t EntryFreq = MBFI->getEntryFreq().getFrequency();
2632
2633 std::pair<unsigned, unsigned> MaxVectorRegs =
2634 ST.getMaxNumVectorRegs(MF.getFunction());
2635 unsigned ArchVGPRThreshold = MaxVectorRegs.first;
2636 unsigned AGPRThreshold = MaxVectorRegs.second;
2637 unsigned CombinedThreshold = ST.getMaxNumVGPRs(MF);
2638
2639 for (unsigned Region = 0; Region < DAG.Regions.size(); Region++) {
2640 if (!RegionsWithExcessArchVGPR[Region])
2641 continue;
2642
2643 GCNRegPressure &PressureBefore = DAG.Pressure[Region];
2644 unsigned SpillCostBefore = PressureBefore.getVGPRSpills(
2645 MF, ArchVGPRThreshold, AGPRThreshold, CombinedThreshold);
2646
2647 // For the cases we care about (i.e. ArchVGPR usage is greater than the
2648 // addressable limit), rewriting alone should bring pressure to manageable
2649 // level. If we find any such region, then the rewrite is potentially
2650 // beneficial.
2651 GCNRegPressure PressureAfter = DAG.getRealRegPressure(Region);
2652 unsigned SpillCostAfter = PressureAfter.getVGPRSpills(
2653 MF, ArchVGPRThreshold, AGPRThreshold, CombinedThreshold);
2654
2655 uint64_t BlockFreq =
2656 MBFI->getBlockFreq(DAG.Regions[Region].first->getParent())
2657 .getFrequency();
2658
2659 bool RelativeFreqIsDenom = EntryFreq > BlockFreq;
2660 uint64_t RelativeFreq = EntryFreq && BlockFreq
2661 ? (RelativeFreqIsDenom ? EntryFreq / BlockFreq
2662 : BlockFreq / EntryFreq)
2663 : 1;
2664
2665 // This assumes perfect spilling / splitting -- using one spill / copy
2666 // instruction and one restoreFrom / copy for each excess register,
2667 int64_t SpillCost = ((int)SpillCostAfter - (int)SpillCostBefore) * 2;
2668
2669 // Also account for the block frequency.
2670 if (RelativeFreqIsDenom)
2671 SpillCost /= (int64_t)RelativeFreq;
2672 else
2673 SpillCost *= (int64_t)RelativeFreq;
2674
2675 // If we have increased spilling in any block, just bail.
2676 if (SpillCost > 0) {
2677 resetRewriteCandsToVGPR(RewriteCands);
2678 return SpillCost;
2679 }
2680
2681 if (SpillCost < BestSpillCost)
2682 BestSpillCost = SpillCost;
2683 }
2684
2685 // Set the cost to the largest decrease in spill cost in order to not double
2686 // count spill reductions.
2687 Cost = BestSpillCost;
2688 assert(Cost <= 0);
2689
2690 unsigned CopyCost = 0;
2691
2692 // For each CopyForDef, increase the cost by the register size while
2693 // accounting for block frequency.
2694 for (MachineInstr *DefMI : CopyForDef) {
2695 Register DefReg = DefMI->getOperand(0).getReg();
2696 uint64_t DefFreq =
2697 EntryFreq
2698 ? MBFI->getBlockFreq(DefMI->getParent()).getFrequency() / EntryFreq
2699 : 1;
2700
2701 const TargetRegisterClass *RC = DAG.MRI.getRegClass(DefReg);
2702 CopyCost += RC->getCopyCost() * DefFreq;
2703 }
2704
2705 // Account for CopyForUse copies in each block that the register is used.
2706 for (auto &[UseBlock, UseRegs] : CopyForUse) {
2707 uint64_t UseFreq =
2708 EntryFreq ? MBFI->getBlockFreq(UseBlock).getFrequency() / EntryFreq : 1;
2709
2710 for (Register UseReg : UseRegs) {
2711 const TargetRegisterClass *RC = DAG.MRI.getRegClass(UseReg);
2712 CopyCost += RC->getCopyCost() * UseFreq;
2713 }
2714 }
2715
2716 // Reset the classes that were changed to AGPR for better register bank
2717 // analysis. We must do rewriting after copy-insertion, as some defs of the
2718 // register may require VGPR. Additionally, if we bail out and don't perform
2719 // the rewrite then these need to be restored anyway.
2720 resetRewriteCandsToVGPR(RewriteCands);
2721
2722 return Cost + CopyCost;
2723}
2724
2725bool RewriteMFMAFormStage::rewrite(
2726 ArrayRef<std::pair<MachineInstr *, unsigned>> RewriteCands) {
2727 DenseMap<MachineInstr *, unsigned> FirstMIToRegion;
2728 DenseMap<MachineInstr *, unsigned> LastMIToRegion;
2729
2730 for (unsigned Region = 0; Region < DAG.Regions.size(); Region++) {
2731 RegionBoundaries Entry = DAG.Regions[Region];
2732 if (Entry.first == Entry.second)
2733 continue;
2734
2735 FirstMIToRegion[&*Entry.first] = Region;
2736 if (Entry.second != Entry.first->getParent()->end())
2737 LastMIToRegion[&*Entry.second] = Region;
2738 }
2739
2740 // Rewrite the MFMAs to AGPR, and insert any copies as needed.
2741 // The general assumption of the algorithm (and the previous cost calculation)
2742 // is that it is better to insert the copies in the MBB of the def of the src2
2743 // operands, and in the MBB of the user of the dest operands. This is based on
2744 // the assumption that the MFMAs are likely to appear in loop bodies, while
2745 // the src2 and dest operands are live-in / live-out of the loop. Due to this
2746 // design, the algorithm for finding copy insertion points is more
2747 // complicated.
2748 //
2749 // There are three main cases to handle: 1. the reaching defs of the src2
2750 // operands, 2. the reaching uses of the dst operands, and 3. the reaching
2751 // defs of the reaching uses of the dst operand.
2752 //
2753 // In the first case, we simply insert copies after each of the reaching
2754 // definitions. In the second case, we collect all the uses of a given dest
2755 // and organize them by MBB. Then, we insert 1 copy for each MBB before the
2756 // earliest use. Since the use may have multiple reaching defs, and since we
2757 // want to replace the register it is using with the result of the copy, we
2758 // must handle case 3. In the third case, we simply insert a copy after each
2759 // of the reaching defs to connect to the copy of the reaching uses of the dst
2760 // reg. This allows us to avoid inserting copies next to the MFMAs.
2761 //
2762 // While inserting the copies, we maintain a map of operands which will use
2763 // different regs (i.e. the result of the copies). For example, a case 1 src2
2764 // operand will use the register result of the copies after the reaching defs,
2765 // as opposed to the original register. Now that we have completed our copy
2766 // analysis and placement, we can bulk update the registers. We do this
2767 // separately as to avoid complicating the reachingDef and reachingUse
2768 // queries.
2769 //
2770 // While inserting the copies, we also maintain a list or registers which we
2771 // will want to reclassify as AGPR. After doing the copy insertion and the
2772 // register replacement, we can finally do the reclassification. This uses the
2773 // redef map, as the registers we are interested in reclassifying may be
2774 // replaced by the result of a copy. We must do this after the copy analysis
2775 // and placement as we must have an accurate redef map -- otherwise we may end
2776 // up creating illegal instructions.
2777
2778 // The original registers of the MFMA that need to be reclassified as AGPR.
2779 DenseSet<Register> RewriteRegs;
2780 // The map of an original register in the MFMA to a new register (result of a
2781 // copy) that it should be replaced with.
2782 DenseMap<Register, Register> RedefMap;
2783 // The map of the original MFMA registers to the relevant MFMA operands.
2784 DenseMap<Register, DenseSet<MachineOperand *>> ReplaceMap;
2785 // The map of reaching defs for a given register -- to avoid duplicate copies.
2786 DenseMap<Register, SmallPtrSet<MachineInstr *, 8>> ReachingDefCopyMap;
2787 // The map of reaching uses for a given register by basic block -- to avoid
2788 // duplicate copies and to calculate per MBB insert pts.
2789 DenseMap<unsigned, DenseMap<Register, SmallPtrSet<MachineOperand *, 8>>>
2790 ReachingUseTracker;
2791
2792 // Collect the candidate group; its members share AGPR-form operands
2793 // post-rewrite, so reaching defs feeding any member need no bridge copy.
2794 SmallPtrSet<MachineInstr *, 16> RewriteCandsSet;
2795 DenseSet<Register> RewriteSrc2Regs;
2796 for (auto &[MI, OriginalOpcode] : RewriteCands) {
2797 RewriteCandsSet.insert(MI);
2798 MachineOperand *Src2 = TII->getNamedOperand(*MI, AMDGPU::OpName::src2);
2799 if (Src2 && Src2->isReg())
2800 RewriteSrc2Regs.insert(Src2->getReg());
2801 }
2802
2803 for (auto &[MI, OriginalOpcode] : RewriteCands) {
2804 int ReplacementOp = AMDGPU::getAGPRFormOp(MI->getOpcode());
2805 if (ReplacementOp == -1)
2806 continue;
2807 MI->setDesc(TII->get(ReplacementOp));
2808
2809 // Case 1: insert copies for the reaching defs of the Src2Reg.
2810 MachineOperand *Src2 = TII->getNamedOperand(*MI, AMDGPU::OpName::src2);
2811 if (Src2->isReg()) {
2812 Register Src2Reg = Src2->getReg();
2813 if (!Src2Reg.isVirtual())
2814 return false;
2815
2816 Register MappedReg = Src2->getReg();
2817 SmallVector<SlotIndex, 8> Src2ReachingDefs;
2818 findReachingDefs(*Src2, DAG.LIS, Src2ReachingDefs);
2819 SmallSetVector<MachineInstr *, 8> Src2DefsReplace;
2820
2821 // If src2 has a use that must remain VGPR, it cannot be reclassified to
2822 // AGPR.
2823 bool Src2NeedsVGPR = Src2NeedsVGPRCache.lookup(MI);
2824
2825 for (SlotIndex RDIndex : Src2ReachingDefs) {
2826 MachineInstr *RD = DAG.LIS->getInstructionFromIndex(RDIndex);
2827 if (!Src2NeedsVGPR &&
2828 isReachingDefAGPRForm(RD, RewriteCandsSet, RewriteSrc2Regs, *TII))
2829 continue;
2830
2831 Src2DefsReplace.insert(RD);
2832 }
2833
2834 if (!Src2DefsReplace.empty()) {
2835 auto RI = RedefMap.find(Src2Reg);
2836 if (RI != RedefMap.end()) {
2837 MappedReg = RI->second;
2838 } else {
2839 assert(!ReachingDefCopyMap.contains(Src2Reg));
2840 const TargetRegisterClass *Src2RC = DAG.MRI.getRegClass(Src2Reg);
2841 const TargetRegisterClass *VGPRRC =
2842 SRI->getEquivalentVGPRClass(Src2RC);
2843
2844 // Track the mapping of the original register to the new register.
2845 MappedReg = DAG.MRI.createVirtualRegister(VGPRRC);
2846 RedefMap[Src2Reg] = MappedReg;
2847 }
2848
2849 // If none exists, create a copy from this reaching def.
2850 // We may have inserted a copy already in an earlier iteration.
2851 for (MachineInstr *RD : Src2DefsReplace) {
2852 // Do not create redundant copies.
2853 if (ReachingDefCopyMap[Src2Reg].insert(RD).second) {
2854 MachineInstrBuilder VGPRCopy =
2855 BuildMI(*RD->getParent(), std::next(RD->getIterator()),
2856 RD->getDebugLoc(), TII->get(TargetOpcode::COPY))
2857 .addDef(MappedReg, {}, 0)
2858 .addUse(Src2Reg, {}, 0);
2859 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
2860
2861 // If this reaching def was the last MI in the region, update the
2862 // region boundaries.
2863 if (LastMIToRegion.contains(RD)) {
2864 unsigned UpdateRegion = LastMIToRegion[RD];
2865 DAG.Regions[UpdateRegion].second = VGPRCopy;
2866 LastMIToRegion.erase(RD);
2867 }
2868 }
2869 }
2870 }
2871
2872 // Track the register for reclassification
2873 RewriteRegs.insert(Src2Reg);
2874
2875 // Always insert the operand for replacement. If this corresponds with a
2876 // chain of tied-def we may not see the VGPR requirement until later.
2877 ReplaceMap[Src2Reg].insert(Src2);
2878 }
2879
2880 // Case 2 and Case 3: insert copies before the reaching uses of the dsts,
2881 // and after the reaching defs of the reaching uses of the dsts.
2882
2883 MachineOperand *Dst = &MI->getOperand(0);
2884 Register DstReg = Dst->getReg();
2885 if (!DstReg.isVirtual())
2886 return false;
2887
2888 Register MappedReg = DstReg;
2889 SmallVector<MachineOperand *, 8> DstReachingUses;
2890
2891 SmallVector<MachineOperand *, 8> DstReachingUseCopies;
2892 SmallVector<MachineInstr *, 8> DstUseDefsReplace;
2893
2894 findReachingUses(MI, DAG.LIS, DstReachingUses);
2895
2896 for (MachineOperand *RUOp : DstReachingUses) {
2897 MachineInstr *UserMI = RUOp->getParent();
2898 // Group members read the AGPR result directly.
2899 if (TII->isMAI(*UserMI) && RewriteCandsSet.contains(UserMI))
2900 continue;
2901
2902 // If there is a non mai reaching use, then we need a copy.
2903 if (find(DstReachingUseCopies, RUOp) == DstReachingUseCopies.end())
2904 DstReachingUseCopies.push_back(RUOp);
2905
2906 // Non-rewritten MAI: its defs aren't being reclassified.
2907 if (TII->isMAI(*UserMI))
2908 continue;
2909
2910 SmallVector<SlotIndex, 8> DstUsesReachingDefs;
2911 findReachingDefs(*RUOp, DAG.LIS, DstUsesReachingDefs);
2912
2913 for (SlotIndex RDIndex : DstUsesReachingDefs) {
2914 MachineInstr *RD = DAG.LIS->getInstructionFromIndex(RDIndex);
2915 if (TII->isMAI(*RD))
2916 continue;
2917
2918 // If there is a non mai reaching def of this reaching use, then we will
2919 // need a copy.
2920 if (find(DstUseDefsReplace, RD) == DstUseDefsReplace.end())
2921 DstUseDefsReplace.push_back(RD);
2922 }
2923 }
2924
2925 if (!DstUseDefsReplace.empty()) {
2926 auto RI = RedefMap.find(DstReg);
2927 if (RI != RedefMap.end()) {
2928 MappedReg = RI->second;
2929 } else {
2930 assert(!ReachingDefCopyMap.contains(DstReg));
2931 const TargetRegisterClass *DstRC = DAG.MRI.getRegClass(DstReg);
2932 const TargetRegisterClass *VGPRRC = SRI->getEquivalentVGPRClass(DstRC);
2933
2934 // Track the mapping of the original register to the new register.
2935 MappedReg = DAG.MRI.createVirtualRegister(VGPRRC);
2936 RedefMap[DstReg] = MappedReg;
2937 }
2938
2939 // If none exists, create a copy from this reaching def.
2940 // We may have inserted a copy already in an earlier iteration.
2941 for (MachineInstr *RD : DstUseDefsReplace) {
2942 // Do not create reundant copies.
2943 if (ReachingDefCopyMap[DstReg].insert(RD).second) {
2944 MachineInstrBuilder VGPRCopy =
2945 BuildMI(*RD->getParent(), std::next(RD->getIterator()),
2946 RD->getDebugLoc(), TII->get(TargetOpcode::COPY))
2947 .addDef(MappedReg, {}, 0)
2948 .addUse(DstReg, {}, 0);
2949 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
2950
2951 // If this reaching def was the last MI in the region, update the
2952 // region boundaries.
2953 auto LMI = LastMIToRegion.find(RD);
2954 if (LMI != LastMIToRegion.end()) {
2955 unsigned UpdateRegion = LMI->second;
2956 DAG.Regions[UpdateRegion].second = VGPRCopy;
2957 LastMIToRegion.erase(RD);
2958 }
2959 }
2960 }
2961 }
2962
2963 DenseSet<MachineOperand *> &DstRegSet = ReplaceMap[DstReg];
2964 // One AGPR→VGPR copy per dst register, shared by all same-block uses.
2965 Register SameBlockCopyReg;
2966 MachineInstr *EarliestSameBlockUse = nullptr;
2967 for (MachineOperand *RU : DstReachingUseCopies) {
2968 MachineBasicBlock *RUBlock = RU->getParent()->getParent();
2969 // Just keep track of the reaching use of this register by block. After we
2970 // have scanned all the MFMAs we can find optimal insert pts.
2971 if (RUBlock != MI->getParent()) {
2972 ReachingUseTracker[RUBlock->getNumber()][DstReg].insert(RU);
2973 continue;
2974 }
2975
2976 // Lazily create the copy register on first same-block use.
2977 if (!SameBlockCopyReg.isValid()) {
2978 const TargetRegisterClass *DstRC = DAG.MRI.getRegClass(DstReg);
2979 const TargetRegisterClass *VGPRRC = SRI->getEquivalentVGPRClass(DstRC);
2980 SameBlockCopyReg = DAG.MRI.createVirtualRegister(VGPRRC);
2981 }
2982
2983 // Track the earliest use for copy insertion point.
2984 MachineInstr *UseInst = RU->getParent();
2985 if (!EarliestSameBlockUse ||
2987 DAG.LIS->getInstructionIndex(*UseInst),
2988 DAG.LIS->getInstructionIndex(*EarliestSameBlockUse)))
2989 EarliestSameBlockUse = UseInst;
2990 RU->setReg(SameBlockCopyReg);
2991 }
2992
2993 // Insert the copy before the earliest same-block use.
2994 if (SameBlockCopyReg.isValid()) {
2995 MachineInstrBuilder VGPRCopy =
2996 BuildMI(*EarliestSameBlockUse->getParent(),
2997 EarliestSameBlockUse->getIterator(), DebugLoc(),
2998 TII->get(TargetOpcode::COPY), SameBlockCopyReg)
2999 .addUse(DstReg, {}, 0);
3000 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
3001 DstRegSet.insert(&VGPRCopy->getOperand(1));
3002 }
3003
3004 // Track the register for reclassification
3005 RewriteRegs.insert(DstReg);
3006
3007 // Insert the dst operand for replacement. If this dst is in a chain of
3008 // tied-def MFMAs, and the first src2 needs to be replaced with a new reg,
3009 // all the correspond operands need to be replaced.
3010 DstRegSet.insert(Dst);
3011 }
3012
3013 // Handle the copies for dst uses.
3014 using RUBType =
3015 std::pair<unsigned, DenseMap<Register, SmallPtrSet<MachineOperand *, 8>>>;
3016 for (RUBType RUBlockEntry : ReachingUseTracker) {
3017 using RUDType = std::pair<Register, SmallPtrSet<MachineOperand *, 8>>;
3018 for (RUDType RUDst : RUBlockEntry.second) {
3019 MachineOperand *OpBegin = *RUDst.second.begin();
3020 SlotIndex InstPt = DAG.LIS->getInstructionIndex(*OpBegin->getParent());
3021
3022 // Find the earliest use in this block.
3023 for (MachineOperand *User : RUDst.second) {
3024 SlotIndex NewInstPt = DAG.LIS->getInstructionIndex(*User->getParent());
3025 if (SlotIndex::isEarlierInstr(NewInstPt, InstPt))
3026 InstPt = NewInstPt;
3027 }
3028
3029 const TargetRegisterClass *DstRC = DAG.MRI.getRegClass(RUDst.first);
3030 const TargetRegisterClass *VGPRRC = SRI->getEquivalentVGPRClass(DstRC);
3031 Register NewUseReg = DAG.MRI.createVirtualRegister(VGPRRC);
3032 MachineInstr *UseInst = DAG.LIS->getInstructionFromIndex(InstPt);
3033
3034 MachineInstrBuilder VGPRCopy =
3035 BuildMI(*UseInst->getParent(), UseInst->getIterator(),
3036 UseInst->getDebugLoc(), TII->get(TargetOpcode::COPY))
3037 .addDef(NewUseReg, {}, 0)
3038 .addUse(RUDst.first, {}, 0);
3039 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
3040
3041 // If this UseInst was the first MI in the region, update the region
3042 // boundaries.
3043 auto FI = FirstMIToRegion.find(UseInst);
3044 if (FI != FirstMIToRegion.end()) {
3045 unsigned UpdateRegion = FI->second;
3046 DAG.Regions[UpdateRegion].first = VGPRCopy;
3047 FirstMIToRegion.erase(UseInst);
3048 }
3049
3050 // Replace the operand for all users.
3051 for (MachineOperand *User : RUDst.second) {
3052 User->setReg(NewUseReg);
3053 }
3054
3055 // Track the copy source operand for replacement.
3056 ReplaceMap[RUDst.first].insert(&VGPRCopy->getOperand(1));
3057 }
3058 }
3059
3060 // We may have needed to insert copies after the reaching defs of the MFMAs.
3061 // Replace the original register with the result of the copy for all relevant
3062 // operands.
3063 for (std::pair<Register, Register> NewDef : RedefMap) {
3064 Register OldReg = NewDef.first;
3065 Register NewReg = NewDef.second;
3066
3067 // Replace the register for any associated operand in the MFMA chain.
3068 for (MachineOperand *ReplaceOp : ReplaceMap[OldReg])
3069 ReplaceOp->setReg(NewReg);
3070 }
3071
3072 // Finally, do the reclassification of the MFMA registers.
3073 for (Register RewriteReg : RewriteRegs) {
3074 Register RegToRewrite = RewriteReg;
3075
3076 // Be sure to update the replacement register and not the original.
3077 auto RI = RedefMap.find(RewriteReg);
3078 if (RI != RedefMap.end())
3079 RegToRewrite = RI->second;
3080
3081 const TargetRegisterClass *CurrRC = DAG.MRI.getRegClass(RegToRewrite);
3082 const TargetRegisterClass *AGPRRC = SRI->getEquivalentAGPRClass(CurrRC);
3083
3084 DAG.MRI.setRegClass(RegToRewrite, AGPRRC);
3085 }
3086
3087 // Bulk update the LIS.
3088 DAG.LIS->reanalyze(DAG.MF);
3089 // Liveins may have been modified for cross RC copies
3090 RegionPressureMap LiveInUpdater(&DAG, false);
3091 LiveInUpdater.buildLiveRegMap();
3092
3093 for (unsigned Region = 0; Region < DAG.Regions.size(); Region++)
3094 DAG.LiveIns[Region] = LiveInUpdater.getLiveRegsForRegionIdx(Region);
3095
3096 DAG.Pressure[RegionIdx] = DAG.getRealRegPressure(RegionIdx);
3097
3098 return true;
3099}
3100
3101unsigned PreRARematStage::getStageTargetOccupancy() const {
3102 return TargetOcc ? *TargetOcc : MFI.getMinWavesPerEU();
3103}
3104
3105bool PreRARematStage::setObjective() {
3106 const Function &F = MF.getFunction();
3107
3108 // Set up "spilling targets" for all regions.
3109 unsigned MaxSGPRs = ST.getMaxNumSGPRs(F);
3110 unsigned MaxVGPRs = ST.getMaxNumVGPRs(F);
3111 bool HasVectorRegisterExcess = false;
3112 for (unsigned I = 0, E = DAG.Regions.size(); I != E; ++I) {
3113 const GCNRegPressure &RP = DAG.Pressure[I];
3114 GCNRPTarget &Target = RPTargets.emplace_back(MaxSGPRs, MaxVGPRs, MF, RP);
3115 if (!Target.satisfied())
3116 TargetRegions.set(I);
3117 HasVectorRegisterExcess |= Target.hasVectorRegisterExcess();
3118 }
3119
3120 if (HasVectorRegisterExcess || DAG.MinOccupancy >= MFI.getMaxWavesPerEU()) {
3121 // In addition to register usage being above addressable limits, occupancy
3122 // below the minimum is considered like "spilling" as well.
3123 TargetOcc = std::nullopt;
3124 } else {
3125 // There is no spilling and room to improve occupancy; set up "increased
3126 // occupancy targets" for all regions.
3127 TargetOcc = DAG.MinOccupancy + 1;
3128 const unsigned VGPRBlockSize = MFI.getDynamicVGPRBlockSize();
3129 MaxSGPRs = ST.getMaxNumSGPRs(*TargetOcc, false);
3130 MaxVGPRs = ST.getMaxNumVGPRs(*TargetOcc, VGPRBlockSize);
3131 for (auto [I, Target] : enumerate(RPTargets)) {
3132 Target.setTarget(MaxSGPRs, MaxVGPRs);
3133 if (!Target.satisfied())
3134 TargetRegions.set(I);
3135 }
3136 }
3137
3138 return TargetRegions.any();
3139}
3140
3141bool PreRARematStage::ScoredRemat::maybeBeneficial(
3142 const BitVector &TargetRegions, ArrayRef<GCNRPTarget> RPTargets) const {
3143 for (unsigned I : TargetRegions.set_bits()) {
3144 if (Live[I] && RPTargets[I].isSaveBeneficial(RPSave))
3145 return true;
3146 }
3147 return false;
3148}
3149
3153 MachineCycleInfo MCI;
3154 MCI.compute(MF);
3155 MachineBlockFrequencyInfo MBFI(MF, MBPI, MCI);
3156
3157 const unsigned NumRegions = DAG.Regions.size();
3159 MaxFreq = 0;
3160 Regions.reserve(NumRegions);
3161 for (unsigned I = 0; I < NumRegions; ++I) {
3162 MachineBasicBlock *MBB = DAG.Regions[I].first->getParent();
3163 uint64_t BlockFreq = MBFI.getBlockFreq(MBB).getFrequency();
3164 Regions.push_back(BlockFreq);
3165 if (BlockFreq && BlockFreq < MinFreq)
3166 MinFreq = BlockFreq;
3167 else if (BlockFreq > MaxFreq)
3168 MaxFreq = BlockFreq;
3169 }
3170 if (!MinFreq)
3171 return;
3172
3173 // Scale everything down if frequencies are high.
3174 if (MinFreq >= ScaleFactor * ScaleFactor) {
3175 for (uint64_t &Freq : Regions)
3176 Freq /= ScaleFactor;
3177 MinFreq /= ScaleFactor;
3178 MaxFreq /= ScaleFactor;
3179 }
3180}
3181
3182void PreRARematStage::ScoredRemat::init(const FreqInfo &Freq,
3183 const Rematerializer &Remater,
3185 const Rematerializer::Reg &Reg = Remater.getReg(RegIdx);
3186 Register DefReg = Reg.getDefReg();
3187 assert(Reg.Uses.size() == 1 && "expected users in single region");
3188 const unsigned UseRegion = Reg.Uses.begin()->first;
3189
3190 Live |= LiveIn;
3191 Live |= LiveOut;
3192
3193 for (unsigned I : Live.set_bits()) {
3194 // If the register is both unused and live-through in the region, the
3195 // latter's RP is guaranteed to decrease.
3196 if (!LiveIn[I] || !LiveOut[I] || I == UseRegion)
3197 UnpredictableRPSave.set(I);
3198 }
3199 RPSave.inc(DefReg, LaneBitmask::getNone(), Reg.Mask, DAG.MRI);
3200
3201 // Get frequencies of defining and using regions. A rematerialization from the
3202 // least frequent region to the most frequent region will yield the greatest
3203 // in order to penalize rematerializations from or into regions whose
3204 int64_t DefOrMin = std::max(Freq.Regions[Reg.DefRegion], Freq.MinFreq);
3205 int64_t UseOrMax = Freq.Regions[UseRegion];
3206 if (!UseOrMax)
3207 UseOrMax = Freq.MaxFreq;
3208 FreqDiff = DefOrMin - UseOrMax;
3209}
3210
3211void PreRARematStage::ScoredRemat::update(const BitVector &TargetRegions,
3212 ArrayRef<GCNRPTarget> RPTargets,
3213 const FreqInfo &FreqInfo,
3214 bool ReduceSpill) {
3215 MaxFreq = 0;
3216 RegionImpact = 0;
3217 for (unsigned I : TargetRegions.set_bits()) {
3218 if (!Live[I])
3219 continue;
3220
3221 // The rematerialization must contribute positively in at least one
3222 // register class with usage above the RP target for this region to
3223 // contribute to the score.
3224 const GCNRPTarget &RegionTarget = RPTargets[I];
3225 const unsigned NumRegsBenefit = RegionTarget.getNumRegsBenefit(RPSave);
3226 if (!NumRegsBenefit)
3227 continue;
3228
3229 // Regions in which RP is guaranteed to decrease have more weight.
3230 RegionImpact += (UnpredictableRPSave[I] ? 1 : 2) * NumRegsBenefit;
3231
3232 if (ReduceSpill) {
3233 uint64_t Freq = FreqInfo.Regions[I];
3234 if (UnpredictableRPSave[I]) {
3235 // Apply a frequency penalty in regions in which we are not sure that RP
3236 // will decrease.
3237 Freq /= 2;
3238 }
3239 MaxFreq = std::max(MaxFreq, Freq);
3240 }
3241 }
3242}
3243
3244void PreRARematStage::ScoredRemat::rematerialize(
3245 Rematerializer &Remater) const {
3246 const Rematerializer::Reg &Reg = Remater.getReg(RegIdx);
3247 Rematerializer::DependencyReuseInfo DRI;
3248 for (RegisterIdx DepRegIdx : Reg.Dependencies)
3249 DRI.reuse(DepRegIdx);
3250 unsigned UseRegion = Reg.Uses.begin()->first;
3251 Remater.rematerializeToRegion(RegIdx, UseRegion, DRI);
3252}
3253
3254void PreRARematStage::updateRPTargets(const BitVector &Regions,
3255 const GCNRegPressure &RPSave) {
3256 for (unsigned I : Regions.set_bits()) {
3257 RPTargets[I].saveRP(RPSave);
3258 if (TargetRegions[I] && RPTargets[I].satisfied()) {
3259 REMAT_DEBUG(dbgs() << " [" << I << "] Target reached!\n");
3260 TargetRegions.reset(I);
3261 }
3262 }
3263}
3264
3265bool PreRARematStage::updateAndVerifyRPTargets(const BitVector &Regions) {
3266 bool TooOptimistic = false;
3267 for (unsigned I : Regions.set_bits()) {
3268 GCNRPTarget &Target = RPTargets[I];
3269 Target.setRP(DAG.getRealRegPressure(I));
3270
3271 // Since we were optimistic in assessing RP decreases in these regions, we
3272 // may need to remark the target as a target region if RP didn't decrease
3273 // as expected.
3274 if (!TargetRegions[I] && !Target.satisfied()) {
3275 REMAT_DEBUG(dbgs() << " [" << I << "] Incorrect RP estimation\n");
3276 TooOptimistic = true;
3277 TargetRegions.set(I);
3278 }
3279 }
3280 return TooOptimistic;
3281}
3282
3283void PreRARematStage::removeFromLiveMaps(Register Reg, const BitVector &LiveIn,
3284 const BitVector &LiveOut) {
3285 assert(LiveIn.size() == DAG.Regions.size() &&
3286 LiveOut.size() == DAG.Regions.size() && "region num mismatch");
3287 for (unsigned I : LiveIn.set_bits())
3288 DAG.LiveIns[I].erase(Reg);
3289 for (unsigned I : LiveOut.set_bits())
3290 DAG.RegionLiveOuts.getLiveRegsForRegionIdx(I).erase(Reg);
3291}
3292
3293void PreRARematStage::addToLiveMaps(Register Reg, LaneBitmask Mask,
3294 const BitVector &LiveIn,
3295 const BitVector &LiveOut) {
3296 assert(LiveIn.size() == DAG.Regions.size() &&
3297 LiveOut.size() == DAG.Regions.size() && "region num mismatch");
3298 std::pair<Register, LaneBitmask> LiveReg(Reg, Mask);
3299 for (unsigned I : LiveIn.set_bits())
3300 DAG.LiveIns[I].insert(LiveReg);
3301 for (unsigned I : LiveOut.set_bits())
3302 DAG.RegionLiveOuts.getLiveRegsForRegionIdx(I).insert(LiveReg);
3303}
3304
3306 // We consider that reducing spilling is always beneficial so we never
3307 // rollback rematerializations or revert scheduling in such cases.
3308 if (!TargetOcc)
3309 return;
3310
3311 // When increasing occupancy, it is possible that re-scheduling is not able to
3312 // achieve the target occupancy in all regions, in which case re-scheduling in
3313 // all regions should be reverted.
3314 if (DAG.MinOccupancy >= *TargetOcc)
3315 return;
3316
3317 // Revert re-scheduling in all affected regions.
3318 for (const auto &[RegionIdx, OrigMIOrder, MaxPressure] : RegionReverts) {
3319 REMAT_DEBUG(dbgs() << "Reverting re-scheduling in region " << RegionIdx
3320 << '\n');
3321 DAG.Pressure[RegionIdx] = MaxPressure;
3322 modifyRegionSchedule(RegionIdx, OrigMIOrder);
3323 }
3324
3325 // It is possible that re-scheduling lowers occupancy over the one achieved
3326 // just through rematerializations, in which case we revert re-scheduling in
3327 // all regions but do not roll back rematerializations.
3328 if (AchievedOcc >= *TargetOcc) {
3329 DAG.setTargetOccupancy(AchievedOcc);
3330 return;
3331 }
3332
3333 // Reset the target occupancy to what it was pre-rematerialization.
3334 DAG.setTargetOccupancy(*TargetOcc - 1);
3335
3336 // Roll back changes made by the stage, then recompute pressure in all
3337 // affected regions.
3338 REMAT_DEBUG(dbgs() << "==== ROLLBACK ====\n");
3339 assert(Rollback && "rollbacker should be defined");
3340 Rollback->Listener.rollback(Remater);
3341 for (const auto &[RegIdx, LiveIn, LiveOut] : Rollback->LiveMapUpdates) {
3342 const Rematerializer::Reg &Reg = Remater.getReg(RegIdx);
3343 addToLiveMaps(Reg.getDefReg(), Reg.Mask, LiveIn, LiveOut);
3344 }
3345
3346#ifdef EXPENSIVE_CHECKS
3347 // In particular, we want to check for coherent MI/slot order in regions in
3348 // which reverts and/or rollbacks may have happened.
3349 MF.verify();
3350#endif
3351 for (unsigned I : RescheduleRegions.set_bits())
3352 DAG.Pressure[I] = DAG.getRealRegPressure(I);
3353
3355}
3356
3357void GCNScheduleDAGMILive::setTargetOccupancy(unsigned TargetOccupancy) {
3358 MinOccupancy = TargetOccupancy;
3359 if (MFI.getOccupancy() < TargetOccupancy)
3360 MFI.increaseOccupancy(MF, MinOccupancy);
3361 else
3362 MFI.limitOccupancy(MinOccupancy);
3363}
3364
3366 const SIInstrInfo *SII = static_cast<const SIInstrInfo *>(DAG->TII);
3367 return any_of(*DAG, [SII](MachineBasicBlock::iterator MI) {
3368 return SII->isIGLPMutationOnly(MI->getOpcode());
3369 });
3370}
3371
3376
3378 HasIGLPInstrs = hasIGLPInstrs(this);
3379 if (HasIGLPInstrs) {
3380 SavedMutations.clear();
3381 SavedMutations.swap(Mutations);
3383 }
3384
3386}
3387
3389 if (HasIGLPInstrs)
3390 SavedMutations.swap(Mutations);
3391
3393}
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static SUnit * pickOnlyChoice(SchedBoundary &Zone)
unsigned uint64_t
MachineBasicBlock & MBB
This file implements the BitVector class.
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file defines the GCNRegPressure class, which tracks registry pressure by bookkeeping number of S...
static cl::opt< bool > GCNTrackers("amdgpu-use-amdgpu-trackers", cl::Hidden, cl::desc("Use the AMDGPU specific RPTrackers during scheduling"), cl::init(false))
static cl::opt< bool > DisableClusteredLowOccupancy("amdgpu-disable-clustered-low-occupancy-reschedule", cl::Hidden, cl::desc("Disable clustered low occupancy " "rescheduling for ILP scheduling stage."), cl::init(false))
#define REMAT_PREFIX
Allows to easily filter for this stage's debug output.
static MachineInstr * getLastMIForRegion(MachineBasicBlock::iterator RegionBegin, MachineBasicBlock::iterator RegionEnd)
static bool shouldCheckPending(SchedBoundary &Zone, const TargetSchedModel *SchedModel)
static cl::opt< bool > EnableLiveIntervalRPReschedule("amdgpu-lirp-reschedule", cl::Hidden, cl::desc("Enable live interval RP reschedule stage"), cl::init(true))
static cl::opt< bool > RelaxedOcc("amdgpu-schedule-relaxed-occupancy", cl::Hidden, cl::desc("Relax occupancy targets for kernels which are memory " "bound (amdgpu-membound-threshold), or " "Wave Limited (amdgpu-limit-wave-threshold)."), cl::init(false))
#define REMAT_DEBUG(X)
static cl::opt< bool > DisableUnclusterHighRP("amdgpu-disable-unclustered-high-rp-reschedule", cl::Hidden, cl::desc("Disable unclustered high register pressure " "reduction scheduling stage."), cl::init(false))
static void printScheduleModel(std::set< std::pair< MachineInstr *, unsigned >, EarlierIssuingCycle > &ReadyCycles)
static bool isReachingDefAGPRForm(MachineInstr *RD, const SmallPtrSetImpl< MachineInstr * > &RewriteSet, const DenseSet< Register > &CandSrc2Regs, const SIInstrInfo &TII)
Returns true if reaching def RD will be in AGPR form after the rewrite and so needs no bridge copy: a...
static cl::opt< bool > PrintMaxRPRegUsageAfterScheduler("amdgpu-print-max-reg-pressure-regusage-after-scheduler", cl::Hidden, cl::desc("Print a list of live registers along with their def/uses at the " "point of maximum register pressure after scheduling."), cl::init(false))
static bool hasIGLPInstrs(ScheduleDAGInstrs *DAG)
static cl::opt< bool > DisableRewriteMFMAFormSchedStage("amdgpu-disable-rewrite-mfma-form-sched-stage", cl::Hidden, cl::desc("Disable rewrite mfma rewrite scheduling stage"), cl::init(true))
static bool canUsePressureDiffs(const SUnit &SU)
Checks whether SU can use the cached DAG pressure diffs to compute the current register pressure.
static cl::opt< unsigned > LiveIntervalRPVGPRReduction("amdgpu-lirp-vgpr-reduction", cl::Hidden, cl::desc("Reduction factor (percent) for VGPR threshold during live interval RP " "reschedule stage"), cl::init(90))
static cl::opt< unsigned > PendingQueueLimit("amdgpu-scheduler-pending-queue-limit", cl::Hidden, cl::desc("Max (Available+Pending) size to inspect pending queue (0 disables)"), cl::init(256))
static cl::opt< bool > PrintMaxRPRegUsageBeforeScheduler("amdgpu-print-max-reg-pressure-regusage-before-scheduler", cl::Hidden, cl::desc("Print a list of live registers along with their def/uses at the " "point of maximum register pressure before scheduling."), cl::init(false))
static cl::opt< unsigned > LiveIntervalRPInstantLowerBound("amdgpu-lirp-instant-lower-bound", cl::Hidden, cl::desc("Lower bound (percent of the VGPR excess limit) on instant RP, " "below which a region is skipped"), cl::init(10))
static cl::opt< unsigned > ScheduleMetricBias("amdgpu-schedule-metric-bias", cl::Hidden, cl::desc("Sets the bias which adds weight to occupancy vs latency. Set it to " "100 to chase the occupancy only."), cl::init(10))
static cl::opt< unsigned > LiveIntervalRPThreshold("amdgpu-lirp-threshold", cl::Hidden, cl::desc("Percent increase of live interval RP over instant pressure to " "trigger rescheduling"), cl::init(10))
static Register UseReg(const MachineOperand &MO)
const HexagonInstrInfo * TII
static constexpr std::pair< StringLiteral, StringLiteral > ReplaceMap[]
IRTranslator LLVM IR MI
iv Induction Variable Users
Definition IVUsers.cpp:48
A common definition of LaneBitmask for use in TableGen and CodeGen.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Register Reg
Promote Memory to Register
Definition Mem2Reg.cpp:110
#define T
if(PassOpts->AAPipeline)
MIR-level target-independent rematerialization helpers.
This file contains some templates that are useful if you are working with the STL at all.
#define LLVM_DEBUG(...)
Definition Debug.h:119
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
const T & front() const
Get the first element.
Definition ArrayRef.h:144
size_t size() const
Get the array size.
Definition ArrayRef.h:141
bool empty() const
Check if the array is empty.
Definition ArrayRef.h:136
iterator_range< const_set_bits_iterator > set_bits() const
Definition BitVector.h:159
size_type size() const
Returns the number of bits in this bitvector.
Definition BitVector.h:178
uint64_t getFrequency() const
Returns the frequency as a fixpoint number scaled by the entry frequency.
bool shouldRevertScheduling(unsigned WavesAfter) override
bool contains(const_arg_type_t< KeyT > Val) const
Return true if the specified key is in the map, false otherwise.
Definition DenseMap.h:773
iterator find(const_arg_type_t< KeyT > Val)
Definition DenseMap.h:782
iterator end()
Definition DenseMap.h:702
bool erase(const KeyT &Val)
Definition DenseMap.h:946
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition DenseMap.h:843
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)