47#define DEBUG_TYPE "machine-scheduler"
52 "amdgpu-disable-unclustered-high-rp-reschedule",
cl::Hidden,
53 cl::desc(
"Disable unclustered high register pressure "
54 "reduction scheduling stage."),
58 "amdgpu-disable-clustered-low-occupancy-reschedule",
cl::Hidden,
59 cl::desc(
"Disable clustered low occupancy "
60 "rescheduling for ILP scheduling stage."),
66 "Sets the bias which adds weight to occupancy vs latency. Set it to "
67 "100 to chase the occupancy only."),
72 cl::desc(
"Relax occupancy targets for kernels which are memory "
73 "bound (amdgpu-membound-threshold), or "
74 "Wave Limited (amdgpu-limit-wave-threshold)."),
79 cl::desc(
"Use the AMDGPU specific RPTrackers during scheduling"),
83 "amdgpu-scheduler-pending-queue-limit",
cl::Hidden,
85 "Max (Available+Pending) size to inspect pending queue (0 disables)"),
88#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
89#define DUMP_MAX_REG_PRESSURE
91 "amdgpu-print-max-reg-pressure-regusage-before-scheduler",
cl::Hidden,
92 cl::desc(
"Print a list of live registers along with their def/uses at the "
93 "point of maximum register pressure before scheduling."),
97 "amdgpu-print-max-reg-pressure-regusage-after-scheduler",
cl::Hidden,
98 cl::desc(
"Print a list of live registers along with their def/uses at the "
99 "point of maximum register pressure after scheduling."),
104 "amdgpu-disable-rewrite-mfma-form-sched-stage",
cl::Hidden,
110 return O.error(
"'" + Arg +
"' value invalid for uint argument!");
113 return O.error(
"'" + Arg +
"' value must be in the range [0, 100]!");
120 cl::desc(
"Percent of VGPR limits that we should use as RP threshold "
121 "during scheduling. We have two limits relevant to scheduling: "
122 "Critical (avoid decreasing occupancy), Excess (avoid spilling). "
123 "This flag scales both limits back by an equal percent: (0 = use "
124 " default calculation, 1-100 = use percentage), default: 0"),
145 Context->RegClassInfo->getNumAllocatableRegs(&AMDGPU::SGPR_32RegClass);
147 Context->RegClassInfo->getNumAllocatableRegs(&AMDGPU::VGPR_32RegClass);
149 Context->RegClassInfo->getNumAllocatableRegs(&AMDGPU::AGPR_32RegClass);
172 "VGPRCriticalLimit calculation method.\n");
176 unsigned Addressable =
179 VGPRBudget = std::max(VGPRBudget, Granule);
198 <<
". VGPRCriticalLimit: " << OriginalVGPRCriticalLimit
216 <<
", UnifiedVGPRCriticalLimit = "
249 if (!
Op.isReg() ||
Op.isImplicit())
251 if (
Op.getReg().isPhysical() ||
252 (
Op.isDef() &&
Op.getSubReg() != AMDGPU::NoSubRegister))
287 Pressure[AMDGPU::RegisterPressureSets::VGPR_32] =
296 unsigned SGPRPressure,
297 unsigned VGPRPressure,
298 unsigned AGPRPressure,
bool IsBottomUp) {
302 if (!
DAG->isTrackingPressure())
325 Pressure[AMDGPU::RegisterPressureSets::SReg_32] = SGPRPressure;
326 Pressure[AMDGPU::RegisterPressureSets::VGPR_32] = VGPRPressure;
327 Pressure[AMDGPU::RegisterPressureSets::AGPR_32] = AGPRPressure;
329 for (
const auto &Diff :
DAG->getPressureDiff(SU)) {
335 (IsBottomUp ? Diff.getUnitInc() : -Diff.getUnitInc());
338#ifdef EXPENSIVE_CHECKS
339 std::vector<unsigned> CheckPressure, CheckMaxPressure;
342 if (
Pressure[AMDGPU::RegisterPressureSets::SReg_32] !=
343 CheckPressure[AMDGPU::RegisterPressureSets::SReg_32] ||
344 Pressure[AMDGPU::RegisterPressureSets::VGPR_32] !=
345 CheckPressure[AMDGPU::RegisterPressureSets::VGPR_32] ||
346 Pressure[AMDGPU::RegisterPressureSets::AGPR_32] !=
347 CheckPressure[AMDGPU::RegisterPressureSets::AGPR_32]) {
348 errs() <<
"Register Pressure is inaccurate when calculated through "
350 <<
"SGPR got " <<
Pressure[AMDGPU::RegisterPressureSets::SReg_32]
352 << CheckPressure[AMDGPU::RegisterPressureSets::SReg_32] <<
"\n"
353 <<
"VGPR got " <<
Pressure[AMDGPU::RegisterPressureSets::VGPR_32]
355 << CheckPressure[AMDGPU::RegisterPressureSets::VGPR_32] <<
"\n"
356 <<
"AGPR got " <<
Pressure[AMDGPU::RegisterPressureSets::AGPR_32]
358 << CheckPressure[AMDGPU::RegisterPressureSets::AGPR_32] <<
"\n";
364 unsigned NewAGPRPressure =
Pressure[AMDGPU::RegisterPressureSets::AGPR_32];
365 unsigned NewSGPRPressure =
Pressure[AMDGPU::RegisterPressureSets::SReg_32];
366 unsigned NewVGPRPressure =
Pressure[AMDGPU::RegisterPressureSets::VGPR_32];
376 const unsigned MaxVGPRPressureInc = 16;
377 bool ShouldTrackVGPRs = VGPRPressure + MaxVGPRPressureInc >=
VGPRExcessLimit;
380 bool ShouldTrackSGPRs =
381 !ShouldTrackVGPRs && !ShouldTrackAGPRs && SGPRPressure >=
SGPRExcessLimit;
416 bool UnifiedVGPRFile =
MF->getSubtarget<
GCNSubtarget>().hasGFX90AInsts();
418 if (UnifiedVGPRFile) {
426 int VGPRDelta = NewVGPRPressure - VectorCriticalLimit;
429 : std::numeric_limits<int>::min();
431 if (SGPRDelta >= 0 || VGPRDelta >= 0 || AGPRDelta >= 0) {
434 if (VGPRDelta >= SGPRDelta && VGPRDelta >= AGPRDelta) {
438 }
else if (AGPRDelta >= SGPRDelta) {
452 bool HasBufferedModel =
471 dbgs() <<
"Prefer:\t\t";
472 DAG->dumpNode(*Preferred.
SU);
476 DAG->dumpNode(*Current.
SU);
479 dbgs() <<
"Reason:\t\t";
493 unsigned SGPRPressure = 0;
494 unsigned VGPRPressure = 0;
495 unsigned AGPRPressure = 0;
497 if (
DAG->isTrackingPressure()) {
499 SGPRPressure =
Pressure[AMDGPU::RegisterPressureSets::SReg_32];
500 VGPRPressure =
Pressure[AMDGPU::RegisterPressureSets::VGPR_32];
501 AGPRPressure =
Pressure[AMDGPU::RegisterPressureSets::AGPR_32];
506 SGPRPressure =
T->getPressure().getSGPRNum();
507 VGPRPressure =
T->getPressure().getArchVGPRNum();
508 AGPRPressure =
T->getPressure().getAGPRNum();
513 for (
SUnit *SU : AQ) {
517 VGPRPressure, AGPRPressure, IsBottomUp);
537 for (
SUnit *SU : PQ) {
541 VGPRPressure, AGPRPressure, IsBottomUp);
561 bool &PickedPending) {
581 bool BotPending =
false;
601 "Last pick result should correspond to re-picking right now");
606 bool TopPending =
false;
626 "Last pick result should correspond to re-picking right now");
636 PickedPending = BotPending && TopPending;
639 if (BotPending || TopPending) {
646 Cand.setBest(TryCand);
651 IsTopNode = Cand.AtTop;
658 if (
DAG->top() ==
DAG->bottom()) {
660 Bot.Available.empty() &&
Bot.Pending.empty() &&
"ReadyQ garbage");
666 PickedPending =
false;
700 if (ReadyCycle > CurrentCycle)
765 if (
DAG->isTrackingPressure() &&
771 if (
DAG->isTrackingPressure() &&
776 bool SameBoundary = Zone !=
nullptr;
800 if (IsLegacyScheduler)
819 if (
DAG->isTrackingPressure() &&
829 bool SameBoundary = Zone !=
nullptr;
864 bool CandIsClusterSucc =
866 bool TryCandIsClusterSucc =
868 if (
tryGreater(TryCandIsClusterSucc, CandIsClusterSucc, TryCand, Cand,
873 if (
DAG->isTrackingPressure() &&
879 if (
DAG->isTrackingPressure() &&
925 if (
DAG->isTrackingPressure()) {
941 bool CandIsClusterSucc =
943 bool TryCandIsClusterSucc =
945 if (
tryGreater(TryCandIsClusterSucc, CandIsClusterSucc, TryCand, Cand,
954 bool SameBoundary = Zone !=
nullptr;
971 if (TryMayLoad || CandMayLoad) {
972 bool TryLongLatency =
974 bool CandLongLatency =
978 Zone->
isTop() ? CandLongLatency : TryLongLatency, TryCand,
996 if (
DAG->isTrackingPressure() &&
1015 !
Rem.IsAcyclicLatencyLimited &&
tryLatency(TryCand, Cand, *Zone))
1033 StartingOccupancy(MFI.getOccupancy()), MinOccupancy(StartingOccupancy),
1034 RegionLiveOuts(this,
true) {
1040 LLVM_DEBUG(
dbgs() <<
"Starting occupancy is " << StartingOccupancy <<
".\n");
1042 MinOccupancy = std::min(MFI.getMinAllowedOccupancy(), StartingOccupancy);
1043 if (MinOccupancy != StartingOccupancy)
1044 LLVM_DEBUG(
dbgs() <<
"Allowing Occupancy drops to " << MinOccupancy
1049std::unique_ptr<GCNSchedStage>
1051 switch (SchedStageID) {
1053 return std::make_unique<OccInitialScheduleStage>(SchedStageID, *
this);
1055 return std::make_unique<RewriteMFMAFormStage>(SchedStageID, *
this);
1057 return std::make_unique<UnclusteredHighRPStage>(SchedStageID, *
this);
1059 return std::make_unique<ClusteredLowOccStage>(SchedStageID, *
this);
1061 return std::make_unique<PreRARematStage>(SchedStageID, *
this);
1063 return std::make_unique<ILPInitialScheduleStage>(SchedStageID, *
this);
1065 return std::make_unique<MemoryClauseInitialScheduleStage>(SchedStageID,
1068 return std::make_unique<LiveIntervalRPStage>(SchedStageID, *
this);
1081GCNScheduleDAGMILive::getRealRegPressure(
unsigned RegionIdx)
const {
1082 if (Regions[RegionIdx].first == Regions[RegionIdx].second)
1086 &LiveIns[RegionIdx]);
1092 assert(RegionBegin != RegionEnd &&
"Region must not be empty");
1096void GCNScheduleDAGMILive::computeBlockPressure(
unsigned RegionIdx,
1108 const MachineBasicBlock *OnlySucc =
nullptr;
1111 if (!Candidate->empty() && Candidate->pred_size() == 1) {
1112 SlotIndexes *Ind =
LIS->getSlotIndexes();
1114 OnlySucc = Candidate;
1119 size_t CurRegion = RegionIdx;
1120 for (
size_t E = Regions.size(); CurRegion !=
E; ++CurRegion)
1121 if (Regions[CurRegion].first->getParent() !=
MBB)
1126 auto LiveInIt = MBBLiveIns.find(
MBB);
1127 auto &Rgn = Regions[CurRegion];
1129 if (LiveInIt != MBBLiveIns.end()) {
1130 auto LiveIn = std::move(LiveInIt->second);
1132 MBBLiveIns.erase(LiveInIt);
1135 auto LRS = BBLiveInMap.lookup(NonDbgMI);
1136#ifdef EXPENSIVE_CHECKS
1145 if (Regions[CurRegion].first ==
I || NonDbgMI ==
I) {
1146 LiveIns[CurRegion] =
RPTracker.getLiveRegs();
1150 if (Regions[CurRegion].second ==
I) {
1151 Pressure[CurRegion] =
RPTracker.moveMaxPressure();
1152 if (CurRegion-- == RegionIdx)
1154 auto &Rgn = Regions[CurRegion];
1167 MBBLiveIns[OnlySucc] =
RPTracker.moveLiveRegs();
1172GCNScheduleDAGMILive::getRegionLiveInMap()
const {
1173 assert(!Regions.empty());
1174 std::vector<MachineInstr *> RegionFirstMIs;
1175 RegionFirstMIs.reserve(Regions.size());
1177 RegionFirstMIs.push_back(
1184GCNScheduleDAGMILive::getRegionLiveOutMap()
const {
1185 assert(!Regions.empty());
1186 std::vector<MachineInstr *> RegionLastMIs;
1187 RegionLastMIs.reserve(Regions.size());
1198 IdxToInstruction.clear();
1201 IsLiveOut ? DAG->getRegionLiveOutMap() : DAG->getRegionLiveInMap();
1202 for (
unsigned I = 0;
I < DAG->Regions.size();
I++) {
1203 auto &[RegionBegin, RegionEnd] = DAG->Regions[
I];
1205 if (RegionBegin == RegionEnd)
1209 IdxToInstruction[
I] = RegionKey;
1217 LiveIns.resize(Regions.size());
1218 Pressure.resize(Regions.size());
1219 RegionsWithHighRP.resize(
static_cast<unsigned>(Regions.size()));
1220 RegionsWithExcessRP.resize(
static_cast<unsigned>(Regions.size()));
1221 RegionsWithIGLPInstrs.resize(
static_cast<unsigned>(Regions.size()));
1222 RegionsWithHighRP.reset();
1223 RegionsWithExcessRP.reset();
1224 RegionsWithIGLPInstrs.reset();
1229void GCNScheduleDAGMILive::runSchedStages() {
1230 LLVM_DEBUG(
dbgs() <<
"All regions recorded, starting actual scheduling.\n");
1233 if (!Regions.
empty()) {
1234 BBLiveInMap = getRegionLiveInMap();
1239#ifdef DUMP_MAX_REG_PRESSURE
1249 if (!Stage->initGCNSchedStage())
1252 for (
auto Region : Regions) {
1256 if (!Stage->initGCNRegion()) {
1257 Stage->advanceRegion();
1263 const unsigned RegionIdx = Stage->getRegionIdx();
1266 MRI, RegionLiveOuts.getLiveRegsForRegionIdx(RegionIdx));
1270 Stage->finalizeGCNRegion();
1271 Stage->advanceRegion();
1275 Stage->finalizeGCNSchedStage();
1278#ifdef DUMP_MAX_REG_PRESSURE
1291 OS <<
"Max Occupancy Initial Schedule";
1294 OS <<
"Instruction Rewriting Reschedule";
1297 OS <<
"Unclustered High Register Pressure Reschedule";
1300 OS <<
"Clustered Low Occupancy Reschedule";
1303 OS <<
"Pre-RA Rematerialize";
1306 OS <<
"Max ILP Initial Schedule";
1309 OS <<
"Max memory clause Initial Schedule";
1312 OS <<
"Live Interval RP Reschedule";
1332void RewriteMFMAFormStage::findReachingDefs(
1354 while (!Worklist.
empty()) {
1369 for (MachineBasicBlock *PredMBB : DefMBB->
predecessors()) {
1370 if (Visited.
insert(PredMBB).second)
1376void RewriteMFMAFormStage::findReachingUses(
1380 for (MachineOperand &UseMO :
1383 findReachingDefs(UseMO, LIS, ReachingDefIndexes);
1387 if (
any_of(ReachingDefIndexes, [DefIdx](SlotIndex RDIdx) {
1399 if (!
ST.hasGFX90AInsts() ||
MFI.getMinWavesPerEU() > 1)
1402 RegionsWithExcessArchVGPR.resize(
static_cast<unsigned>(
DAG.Regions.size()));
1403 RegionsWithExcessArchVGPR.reset();
1407 RegionsWithExcessArchVGPR[
Region] =
true;
1410 if (RegionsWithExcessArchVGPR.none())
1413 TII =
ST.getInstrInfo();
1414 SRI =
ST.getRegisterInfo();
1416 std::vector<std::pair<MachineInstr *, unsigned>> RewriteCands;
1420 if (!initHeuristics(RewriteCands, CopyForUse, CopyForDef))
1423 int64_t
Cost = getRewriteCost(RewriteCands, CopyForUse, CopyForDef);
1430 return rewrite(RewriteCands);
1440 if (
DAG.RegionsWithHighRP.none() &&
DAG.RegionsWithExcessRP.none())
1447 InitialOccupancy =
DAG.MinOccupancy;
1450 TempTargetOccupancy =
MFI.getMaxWavesPerEU() >
DAG.MinOccupancy
1451 ? InitialOccupancy + 1
1453 IsAnyRegionScheduled =
false;
1454 S.SGPRLimitBias =
S.HighRPSGPRBias;
1455 S.VGPRLimitBias =
S.HighRPVGPRBias;
1459 <<
"Retrying function scheduling without clustering. "
1460 "Aggressively try to reduce register pressure to achieve occupancy "
1461 << TempTargetOccupancy <<
".\n");
1476 if (
DAG.StartingOccupancy <=
DAG.MinOccupancy)
1480 dbgs() <<
"Retrying function scheduling with lowest recorded occupancy "
1481 <<
DAG.MinOccupancy <<
".\n");
1486#define REMAT_PREFIX "[PreRARemat] "
1487#define REMAT_DEBUG(X) LLVM_DEBUG(dbgs() << REMAT_PREFIX; X;)
1489#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
1490Printable PreRARematStage::ScoredRemat::print()
const {
1492 OS <<
'(' << MaxFreq <<
", " << FreqDiff <<
", " << RegionImpact <<
')';
1507 auto PrintTargetRegions = [&]() ->
void {
1508 if (TargetRegions.none()) {
1513 for (
unsigned I : TargetRegions.set_bits())
1520 dbgs() <<
"Analyzing ";
1521 MF.getFunction().printAsOperand(
dbgs(),
false);
1524 if (!setObjective()) {
1525 LLVM_DEBUG(
dbgs() <<
"no objective to achieve, occupancy is maximal at "
1526 <<
MFI.getMaxWavesPerEU() <<
'\n');
1531 dbgs() <<
"increase occupancy from " << *TargetOcc - 1 <<
'\n';
1533 dbgs() <<
"reduce spilling (minimum target occupancy is "
1534 <<
MFI.getMinWavesPerEU() <<
")\n";
1536 PrintTargetRegions();
1541 DAG.RegionLiveOuts.buildLiveRegMap();
1543 if (!Remater.analyze()) {
1559 DefRegToCandIdx.
resize(
DAG.MRI.getNumVirtRegs());
1560 const unsigned NumRegions =
static_cast<unsigned>(
DAG.Regions.size());
1562 for (
unsigned RegIdx = 0, E = Remater.getNumRegs(); RegIdx < E; ++RegIdx) {
1579 if (CandReg.
Uses.size() > 1 &&
1592 return MarkedRegs.contains(Remater.getReg(DepRegIdx).getDefReg());
1596 if (!candidateHasValidUsers(RegIdx, MarkedRegs))
1600 MarkedRegs.
insert(DefReg);
1601 DefRegToCandIdx[DefReg] =
static_cast<unsigned>(Candidates.
size());
1609 for (
unsigned I = 0;
I < NumRegions; ++
I) {
1610 for (
const auto &[Reg, Mask] :
DAG.LiveIns[
I]) {
1613 unsigned CandIdx = DefRegToCandIdx[Reg];
1615 Candidates[CandIdx].LiveIn.set(
I);
1617 for (
const auto &[Reg, Mask] :
1618 DAG.RegionLiveOuts.getLiveRegsForRegionIdx(
I)) {
1621 unsigned CandIdx = DefRegToCandIdx[Reg];
1623 Candidates[CandIdx].LiveOut.set(
I);
1629 for (
auto [CandIdx, Cand] :
enumerate(Candidates)) {
1630 Cand.init(FreqInfo, Remater,
DAG);
1631 Cand.update(TargetRegions, RPTargets, FreqInfo, !TargetOcc);
1632 if (!Cand.hasNullScore())
1643 Rollback = std::make_unique<RollbackSupport>(Remater);
1648 BitVector RecomputeRP(
static_cast<unsigned>(
DAG.Regions.size()));
1650 RecomputeRP.
reset();
1653 sort(CandidateOrder, [&](
size_t LHSIndex,
size_t RHSIndex) {
1654 return Candidates[LHSIndex] < Candidates[RHSIndex];
1658 dbgs() <<
"==== NEW REMAT ROUND ====\n"
1660 <<
"Candidates with non-null score, in rematerialization order:\n";
1661 for (
const ScoredRemat &Cand :
reverse(Candidates)) {
1663 << Remater.printRematReg(Cand.RegIdx) <<
'\n';
1665 PrintTargetRegions();
1671 while (!CandidateOrder.
empty()) {
1672 const ScoredRemat &Cand = Candidates[CandidateOrder.
back()];
1681 if (!Cand.maybeBeneficial(TargetRegions, RPTargets)) {
1683 << Cand.print() <<
" | "
1684 << Remater.printRematReg(Cand.RegIdx));
1689#ifdef EXPENSIVE_CHECKS
1698 if (!MO.isReg() || !MO.getReg() || !MO.readsReg() || MO.isDef())
1708 LM =
DAG.TRI->getSubRegIndexLaneMask(MO.getSubReg());
1710 for (
const auto &[UseRegion,
_] : Reg.Uses) {
1711 if (UseRegion == Reg.DefRegion)
1714 LaneBitmask UncoveredLanes = LM & ~(LiveInMask & LM);
1718 if (UncoveredLanes.
any()) {
1721 assert((SR.LaneMask & UncoveredLanes).none());
1730 REMAT_DEBUG(
dbgs() <<
"** REMAT " << Remater.printRematReg(Cand.RegIdx)
1732 removeFromLiveMaps(Reg.getDefReg(), Cand.LiveIn, Cand.LiveOut);
1734 Rollback->LiveMapUpdates.emplace_back(Cand.RegIdx, Cand.LiveIn,
1737 Cand.rematerialize(Remater);
1742 updateRPTargets(Cand.Live, Cand.RPSave);
1743 RecomputeRP |= Cand.UnpredictableRPSave;
1744 RescheduleRegions |= Cand.Live;
1745 if (!TargetRegions.any()) {
1751 if (!updateAndVerifyRPTargets(RecomputeRP) && !TargetRegions.any()) {
1760 unsigned NumUsefulCandidates = 0;
1761 for (
size_t CandIdx : CandidateOrder) {
1762 ScoredRemat &Candidate = Candidates[CandIdx];
1763 Candidate.update(TargetRegions, RPTargets, FreqInfo, !TargetOcc);
1764 if (!Candidate.hasNullScore())
1765 CandidateOrder[NumUsefulCandidates++] = CandIdx;
1767 if (NumUsefulCandidates == 0) {
1768 REMAT_DEBUG(
dbgs() <<
"Stop on exhausted rematerialization candidates\n");
1771 CandidateOrder.truncate(NumUsefulCandidates);
1774 if (RescheduleRegions.none())
1780 unsigned DynamicVGPRBlockSize =
MFI.getDynamicVGPRBlockSize();
1781 for (
unsigned I : RescheduleRegions.set_bits()) {
1782 DAG.Pressure[
I] = RPTargets[
I].getCurrentRP();
1784 <<
DAG.Pressure[
I].getOccupancy(
ST, DynamicVGPRBlockSize)
1785 <<
" (" << RPTargets[
I] <<
")\n");
1787 AchievedOcc =
MFI.getMaxWavesPerEU();
1790 std::min(AchievedOcc, RP.getOccupancy(
ST, DynamicVGPRBlockSize));
1794 dbgs() <<
"Retrying function scheduling with new min. occupancy of "
1795 << AchievedOcc <<
" from rematerializing (original was "
1796 <<
DAG.MinOccupancy;
1798 dbgs() <<
", target was " << *TargetOcc;
1802 DAG.setTargetOccupancy(getStageTargetOccupancy());
1813 S.SGPRLimitBias =
S.VGPRLimitBias = 0;
1814 if (
DAG.MinOccupancy > InitialOccupancy) {
1815 assert(IsAnyRegionScheduled);
1817 <<
" stage successfully increased occupancy to "
1818 <<
DAG.MinOccupancy <<
'\n');
1819 }
else if (!IsAnyRegionScheduled) {
1820 assert(
DAG.MinOccupancy == InitialOccupancy);
1822 <<
": No regions scheduled, min occupancy stays at "
1823 <<
DAG.MinOccupancy <<
", MFI occupancy stays at "
1824 <<
MFI.getOccupancy() <<
".\n");
1832 if (
DAG.begin() ==
DAG.end())
1839 unsigned NumRegionInstrs =
1840 static_cast<unsigned>(std::distance(
DAG.begin(),
DAG.end()));
1844 if (
DAG.begin() == std::prev(
DAG.end()))
1850 <<
"\n From: " << *
DAG.begin() <<
" To: ";
1852 else dbgs() <<
"End";
1853 dbgs() <<
" RegionInstrs: " << NumRegionInstrs <<
'\n');
1861 for (
auto &
I :
DAG) {
1874 dbgs() <<
"Pressure before scheduling:\nRegion live-ins:"
1876 <<
"Region live-in pressure: "
1880 S.HasHighPressure =
false;
1902 unsigned DynamicVGPRBlockSize =
DAG.MFI.getDynamicVGPRBlockSize();
1905 unsigned CurrentTargetOccupancy =
1906 IsAnyRegionScheduled ?
DAG.MinOccupancy : TempTargetOccupancy;
1908 (CurrentTargetOccupancy <= InitialOccupancy ||
1909 DAG.Pressure[
RegionIdx].getOccupancy(
ST, DynamicVGPRBlockSize) !=
1916 if (!IsAnyRegionScheduled && IsSchedulingThisRegion) {
1917 IsAnyRegionScheduled =
true;
1918 if (
MFI.getMaxWavesPerEU() >
DAG.MinOccupancy)
1919 DAG.setTargetOccupancy(TempTargetOccupancy);
1921 return IsSchedulingThisRegion;
1937 return !RevertAllRegions && RescheduleRegions[
RegionIdx] &&
1957 if (
S.HasHighPressure)
1978 if (
DAG.MinOccupancy < *TargetOcc) {
1980 <<
" cannot meet occupancy target, interrupting "
1981 "re-scheduling in all regions\n");
1982 RevertAllRegions =
true;
1993 unsigned DynamicVGPRBlockSize =
DAG.MFI.getDynamicVGPRBlockSize();
1995 bool UnifiedVGPRFile =
ST.hasGFX90AInsts();
1996 unsigned VectorCriticalLimit =
1997 UnifiedVGPRFile ?
S.UnifiedVGPRCriticalLimit :
S.VGPRCriticalLimit;
2001 PressureAfter.getVGPRNum(UnifiedVGPRFile) <= VectorCriticalLimit &&
2002 (!UnifiedVGPRFile ||
2012 unsigned TargetOccupancy = std::min(
2013 S.getTargetOccupancy(),
ST.getOccupancyWithWorkGroupSizes(
MF).second);
2014 unsigned WavesAfter = std::min(
2015 TargetOccupancy,
PressureAfter.getOccupancy(
ST, DynamicVGPRBlockSize));
2016 unsigned WavesBefore = std::min(
2018 LLVM_DEBUG(
dbgs() <<
"Occupancy before scheduling: " << WavesBefore
2019 <<
", after " << WavesAfter <<
".\n");
2025 unsigned NewOccupancy = std::max(WavesAfter, WavesBefore);
2029 if (WavesAfter < WavesBefore && WavesAfter <
DAG.MinOccupancy &&
2030 WavesAfter >=
MFI.getMinAllowedOccupancy()) {
2031 LLVM_DEBUG(
dbgs() <<
"Function is memory bound, allow occupancy drop up to "
2032 <<
MFI.getMinAllowedOccupancy() <<
" waves\n");
2033 NewOccupancy = WavesAfter;
2036 if (NewOccupancy <
DAG.MinOccupancy) {
2037 DAG.MinOccupancy = NewOccupancy;
2038 MFI.limitOccupancy(
DAG.MinOccupancy);
2040 <<
DAG.MinOccupancy <<
".\n");
2044 unsigned MaxVGPRs =
ST.getMaxNumVGPRs(
MF);
2047 unsigned MaxArchVGPRs = std::min(MaxVGPRs,
ST.getAddressableNumArchVGPRs());
2048 unsigned MaxSGPRs =
ST.getMaxNumSGPRs(
MF);
2072 unsigned ReadyCycle = CurrCycle;
2073 for (
auto &
D : SU.
Preds) {
2074 if (
D.isAssignedRegDep()) {
2077 unsigned DefReady = ReadyCycles[
DAG.getSUnit(
DefMI)->NodeNum];
2078 ReadyCycle = std::max(ReadyCycle, DefReady +
Latency);
2081 ReadyCycles[SU.
NodeNum] = ReadyCycle;
2088 std::pair<MachineInstr *, unsigned>
B)
const {
2089 return A.second <
B.second;
2095 if (ReadyCycles.empty())
2097 unsigned BBNum = ReadyCycles.begin()->first->getParent()->getNumber();
2098 dbgs() <<
"\n################## Schedule time ReadyCycles for MBB : " << BBNum
2099 <<
" ##################\n# Cycle #\t\t\tInstruction "
2103 for (
auto &
I : ReadyCycles) {
2104 if (
I.second > IPrev + 1)
2105 dbgs() <<
"****************************** BUBBLE OF " <<
I.second - IPrev
2106 <<
" CYCLES DETECTED ******************************\n\n";
2107 dbgs() <<
"[ " <<
I.second <<
" ] : " << *
I.first <<
"\n";
2120 unsigned SumBubbles = 0;
2122 unsigned CurrCycle = 0;
2123 for (
auto &SU : InputSchedule) {
2124 unsigned ReadyCycle =
2126 SumBubbles += ReadyCycle - CurrCycle;
2128 ReadyCyclesSorted.insert(std::make_pair(SU.getInstr(), ReadyCycle));
2130 CurrCycle = ++ReadyCycle;
2153 unsigned SumBubbles = 0;
2155 unsigned CurrCycle = 0;
2156 for (
auto &
MI :
DAG) {
2160 unsigned ReadyCycle =
2162 SumBubbles += ReadyCycle - CurrCycle;
2164 ReadyCyclesSorted.insert(std::make_pair(SU->
getInstr(), ReadyCycle));
2166 CurrCycle = ++ReadyCycle;
2183 if (WavesAfter <
DAG.MinOccupancy)
2187 if (
DAG.MFI.isDynamicVGPREnabled()) {
2190 DAG.MFI.getDynamicVGPRBlockSize());
2193 if (BlocksAfter > BlocksBefore)
2230 <<
"\n\t *** In shouldRevertScheduling ***\n"
2231 <<
" *********** BEFORE UnclusteredHighRPStage ***********\n");
2235 <<
"\n *********** AFTER UnclusteredHighRPStage ***********\n");
2237 unsigned OldMetric = MBefore.
getMetric();
2238 unsigned NewMetric = MAfter.
getMetric();
2239 unsigned WavesBefore = std::min(
2240 S.getTargetOccupancy(),
2247 LLVM_DEBUG(
dbgs() <<
"\tMetric before " << MBefore <<
"\tMetric after "
2248 << MAfter <<
"Profit: " << Profit <<
"\n");
2278 unsigned WavesAfter) {
2288 cl::desc(
"Percent increase of live interval RP over instant pressure to "
2289 "trigger rescheduling"),
2295 "Reduction factor (percent) for VGPR threshold during live interval RP "
2296 "reschedule stage"),
2300 "amdgpu-lirp-instant-lower-bound",
cl::Hidden,
2301 cl::desc(
"Lower bound (percent of the VGPR excess limit) on instant RP, "
2302 "below which a region is skipped"),
2312 if (!
S.VGPRThresholdPercent) {
2313 LLVM_DEBUG(
dbgs() <<
"LIRP: expected VGPRThresholdPercent to be enabled, "
2314 "not using live interval RP reschedule stage\n");
2322 unsigned InstantRP =
DAG.Pressure[
RegionIdx].getArchVGPRNum();
2323 auto [RegionBegin, RegionEnd] =
DAG.Regions[
RegionIdx];
2324 if (RegionBegin == RegionEnd)
2331 unsigned NewVGPRThresholdPercent =
2335 <<
", VGPRThresholdPercent: " <<
S.VGPRThresholdPercent
2336 <<
" -> " << NewVGPRThresholdPercent
2337 <<
", VGPRExcessLimit=" <<
S.VGPRExcessLimit
2338 <<
", VGPRCriticalLimit=" <<
S.VGPRCriticalLimit
2339 <<
", InstantRP=" << InstantRP <<
", LIRP=" << LIRP);
2341 bool DoRescheduling =
false;
2343 unsigned InstantRPLowerBound =
2345 if (LIRP >
S.VGPRExcessLimit) {
2346 LLVM_DEBUG(
dbgs() <<
" [LIRP exceeds the limit (" <<
S.VGPRExcessLimit
2347 <<
"), rescheduling]");
2348 DoRescheduling =
true;
2349 }
else if (LIRP > InstantRP && InstantRP > InstantRPLowerBound) {
2350 unsigned IncreasePercent = ((LIRP - InstantRP) * 100) / InstantRP;
2354 DoRescheduling =
true;
2360 SavedVGPRExcessLimit =
S.VGPRExcessLimit;
2361 SavedVGPRCriticalLimit =
S.VGPRCriticalLimit;
2362 SavedUnifiedVGPRCriticalLimit =
S.UnifiedVGPRCriticalLimit;
2363 SavedVGPRThresholdPercent =
S.VGPRThresholdPercent;
2364 S.VGPRThresholdPercent = NewVGPRThresholdPercent;
2372 S.VGPRExcessLimit = SavedVGPRExcessLimit;
2373 S.VGPRCriticalLimit = SavedVGPRCriticalLimit;
2374 S.UnifiedVGPRCriticalLimit = SavedUnifiedVGPRCriticalLimit;
2375 S.VGPRThresholdPercent = SavedVGPRThresholdPercent;
2382 LLVM_DEBUG(
dbgs() <<
"New pressure will result in more spilling.\n");
2394 "instruction number mismatch");
2395 if (MIOrder.
empty())
2408 if (MII != RegionEnd) {
2410 bool NonDebugReordered =
2411 !
MI->isDebugInstr() &&
2417 if (NonDebugReordered)
2418 DAG.LIS->handleMove(*
MI,
true);
2425 if (!
MI->isDebugInstr()) {
2427 SlotIndex PrevIdx =
DAG.LIS->getSlotIndexes()->getIndexBefore(*
MI);
2428 if (PrevIdx >= MIIdx)
2429 DAG.LIS->handleMove(*
MI,
true);
2433 if (
MI->isDebugInstr()) {
2440 DAG.ShouldTrackLaneMasks);
2459 if (RD->
getOpcode() == AMDGPU::AV_MOV_B32_IMM_PSEUDO ||
2460 RD->
getOpcode() == AMDGPU::AV_MOV_B64_IMM_PSEUDO)
2467bool RewriteMFMAFormStage::hasUseRequiringVGPR(
2469 const SmallPtrSetImpl<MachineInstr *> &RewriteSet) {
2470 for (SlotIndex RDIdx : Src2ReachingDefs) {
2471 const MachineInstr *RD =
DAG.LIS->getInstructionFromIndex(RDIdx);
2473 findReachingUses(RD,
DAG.LIS, ReachingUses);
2474 for (
const MachineOperand *UseMO : ReachingUses) {
2486void RewriteMFMAFormStage::resetRewriteCandsToVGPR(
2487 ArrayRef<std::pair<MachineInstr *, unsigned>> RewriteCands) {
2488 for (
auto [
MI, OriginalOpcode] : RewriteCands) {
2491 DAG.MRI.getRegClass(
MI->getOperand(0).getReg());
2493 DAG.MRI.setRegClass(
MI->getOperand(0).getReg(), VDefRC);
2494 MI->setDesc(
TII->get(OriginalOpcode));
2496 MachineOperand *
Src2 =
TII->getNamedOperand(*
MI, AMDGPU::OpName::src2);
2505 DAG.MRI.setRegClass(
Src2->getReg(), VUseRC);
2509bool RewriteMFMAFormStage::isRewriteCandidate(MachineInstr *
MI)
const {
2510 if (!
static_cast<const SIInstrInfo *
>(
DAG.TII)->isMAI(*
MI))
2515 Register DstReg =
MI->getOperand(0).getReg();
2516 for (
const MachineInstr &
UseMI :
DAG.MRI.use_nodbg_instructions(DstReg)) {
2523bool RewriteMFMAFormStage::initHeuristics(
2524 std::vector<std::pair<MachineInstr *, unsigned>> &RewriteCands,
2525 DenseMap<MachineBasicBlock *, std::set<Register>> &CopyForUse,
2526 SmallPtrSetImpl<MachineInstr *> &CopyForDef) {
2531 SmallPtrSet<MachineInstr *, 16> RewriteSet;
2532 DenseSet<Register> CandSrc2Regs;
2533 for (MachineBasicBlock &
MBB :
MF) {
2534 for (MachineInstr &
MI :
MBB) {
2535 if (!isRewriteCandidate(&
MI))
2538 MachineOperand *
Src2 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src2);
2539 if (Src2 &&
Src2->isReg())
2545 for (MachineBasicBlock &
MBB :
MF) {
2546 for (MachineInstr &
MI :
MBB) {
2547 if (!isRewriteCandidate(&
MI))
2551 assert(ReplacementOp != -1);
2553 RewriteCands.push_back({&
MI,
MI.getOpcode()});
2554 MI.setDesc(
TII->get(ReplacementOp));
2556 MachineOperand *
Src2 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src2);
2557 if (
Src2->isReg()) {
2559 findReachingDefs(*Src2,
DAG.LIS, Src2ReachingDefs);
2563 bool Src2NeedsVGPR = hasUseRequiringVGPR(Src2ReachingDefs, RewriteSet);
2564 Src2NeedsVGPRCache[&
MI] = Src2NeedsVGPR;
2566 for (SlotIndex RDIdx : Src2ReachingDefs) {
2567 MachineInstr *RD =
DAG.LIS->getInstructionFromIndex(RDIdx);
2568 if (!Src2NeedsVGPR &&
2575 MachineOperand &Dst =
MI.getOperand(0);
2578 findReachingUses(&
MI,
DAG.LIS, DstReachingUses);
2580 for (MachineOperand *RUOp : DstReachingUses) {
2581 MachineInstr *UserMI = RUOp->getParent();
2583 if (
TII->isMAI(*UserMI) && RewriteSet.
contains(UserMI))
2589 CopyForUse[UserMI->
getParent()].insert(RUOp->getReg());
2591 if (
TII->isMAI(*UserMI))
2595 findReachingDefs(*RUOp,
DAG.LIS, DstUsesReachingDefs);
2597 for (SlotIndex RDIndex : DstUsesReachingDefs) {
2598 MachineInstr *RD =
DAG.LIS->getInstructionFromIndex(RDIndex);
2599 if (
TII->isMAI(*RD))
2613 DAG.MRI.setRegClass(Dst.getReg(), ADefRC);
2614 if (
Src2->isReg()) {
2620 DAG.MRI.setRegClass(
Src2->getReg(), AUseRC);
2629int64_t RewriteMFMAFormStage::getRewriteCost(
2630 ArrayRef<std::pair<MachineInstr *, unsigned>> RewriteCands,
2631 const DenseMap<MachineBasicBlock *, std::set<Register>> &CopyForUse,
2632 const SmallPtrSetImpl<MachineInstr *> &CopyForDef) {
2633 MachineBlockFrequencyInfo *MBFI =
DAG.MBFI;
2635 int64_t BestSpillCost = 0;
2639 std::pair<unsigned, unsigned> MaxVectorRegs =
2640 ST.getMaxNumVectorRegs(
MF.getFunction());
2641 unsigned ArchVGPRThreshold = MaxVectorRegs.first;
2642 unsigned AGPRThreshold = MaxVectorRegs.second;
2643 unsigned CombinedThreshold =
ST.getMaxNumVGPRs(
MF);
2646 if (!RegionsWithExcessArchVGPR[Region])
2651 MF, ArchVGPRThreshold, AGPRThreshold, CombinedThreshold);
2659 MF, ArchVGPRThreshold, AGPRThreshold, CombinedThreshold);
2665 bool RelativeFreqIsDenom = EntryFreq > BlockFreq;
2666 uint64_t RelativeFreq = EntryFreq && BlockFreq
2667 ? (RelativeFreqIsDenom ? EntryFreq / BlockFreq
2668 : BlockFreq / EntryFreq)
2673 int64_t SpillCost = ((int)SpillCostAfter - (int)SpillCostBefore) * 2;
2676 if (RelativeFreqIsDenom)
2677 SpillCost /= (int64_t)RelativeFreq;
2679 SpillCost *= (int64_t)RelativeFreq;
2682 if (SpillCost > 0) {
2683 resetRewriteCandsToVGPR(RewriteCands);
2687 if (SpillCost < BestSpillCost)
2688 BestSpillCost = SpillCost;
2693 Cost = BestSpillCost;
2696 unsigned CopyCost = 0;
2700 for (MachineInstr *
DefMI : CopyForDef) {
2708 CopyCost +=
static_cast<unsigned>(RC->
getCopyCost() * DefFreq);
2712 for (
auto &[UseBlock, UseRegs] : CopyForUse) {
2718 CopyCost +=
static_cast<unsigned>(RC->
getCopyCost() * UseFreq);
2726 resetRewriteCandsToVGPR(RewriteCands);
2728 return Cost + CopyCost;
2731bool RewriteMFMAFormStage::rewrite(
2732 ArrayRef<std::pair<MachineInstr *, unsigned>> RewriteCands) {
2733 DenseMap<MachineInstr *, unsigned> FirstMIToRegion;
2734 DenseMap<MachineInstr *, unsigned> LastMIToRegion;
2742 if (
Entry.second !=
Entry.first->getParent()->end())
2785 DenseSet<Register> RewriteRegs;
2788 DenseMap<Register, Register> RedefMap;
2790 DenseMap<Register, DenseSet<MachineOperand *>>
ReplaceMap;
2792 DenseMap<Register, SmallPtrSet<MachineInstr *, 8>> ReachingDefCopyMap;
2795 DenseMap<unsigned, DenseMap<Register, SmallPtrSet<MachineOperand *, 8>>>
2800 SmallPtrSet<MachineInstr *, 16> RewriteCandsSet;
2801 DenseSet<Register> RewriteSrc2Regs;
2802 for (
auto &[
MI, OriginalOpcode] : RewriteCands) {
2804 MachineOperand *
Src2 =
TII->getNamedOperand(*
MI, AMDGPU::OpName::src2);
2805 if (Src2 &&
Src2->isReg())
2809 for (
auto &[
MI, OriginalOpcode] : RewriteCands) {
2811 if (ReplacementOp == -1)
2813 MI->setDesc(
TII->get(ReplacementOp));
2816 MachineOperand *
Src2 =
TII->getNamedOperand(*
MI, AMDGPU::OpName::src2);
2817 if (
Src2->isReg()) {
2824 findReachingDefs(*Src2,
DAG.LIS, Src2ReachingDefs);
2825 SmallSetVector<MachineInstr *, 8> Src2DefsReplace;
2829 bool Src2NeedsVGPR = Src2NeedsVGPRCache.lookup(
MI);
2831 for (SlotIndex RDIndex : Src2ReachingDefs) {
2832 MachineInstr *RD =
DAG.LIS->getInstructionFromIndex(RDIndex);
2833 if (!Src2NeedsVGPR &&
2837 Src2DefsReplace.
insert(RD);
2840 if (!Src2DefsReplace.
empty()) {
2841 auto RI = RedefMap.
find(Src2Reg);
2842 if (RI != RedefMap.
end()) {
2843 MappedReg = RI->second;
2848 SRI->getEquivalentVGPRClass(Src2RC);
2851 MappedReg =
DAG.MRI.createVirtualRegister(VGPRRC);
2852 RedefMap[Src2Reg] = MappedReg;
2857 for (MachineInstr *RD : Src2DefsReplace) {
2859 if (ReachingDefCopyMap[Src2Reg].insert(RD).second) {
2860 MachineInstrBuilder VGPRCopy =
2863 .
addDef(MappedReg, {}, 0)
2864 .addUse(Src2Reg, {}, 0);
2865 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
2870 unsigned UpdateRegion = LastMIToRegion[RD];
2871 DAG.Regions[UpdateRegion].second = VGPRCopy;
2872 LastMIToRegion.
erase(RD);
2879 RewriteRegs.
insert(Src2Reg);
2889 MachineOperand *Dst = &
MI->getOperand(0);
2898 SmallVector<MachineInstr *, 8> DstUseDefsReplace;
2900 findReachingUses(
MI,
DAG.LIS, DstReachingUses);
2902 for (MachineOperand *RUOp : DstReachingUses) {
2903 MachineInstr *UserMI = RUOp->
getParent();
2905 if (
TII->isMAI(*UserMI) && RewriteCandsSet.
contains(UserMI))
2909 if (
find(DstReachingUseCopies, RUOp) == DstReachingUseCopies.
end())
2913 if (
TII->isMAI(*UserMI))
2917 findReachingDefs(*RUOp,
DAG.LIS, DstUsesReachingDefs);
2919 for (SlotIndex RDIndex : DstUsesReachingDefs) {
2920 MachineInstr *RD =
DAG.LIS->getInstructionFromIndex(RDIndex);
2921 if (
TII->isMAI(*RD))
2926 if (
find(DstUseDefsReplace, RD) == DstUseDefsReplace.
end())
2931 if (!DstUseDefsReplace.
empty()) {
2932 auto RI = RedefMap.
find(DstReg);
2933 if (RI != RedefMap.
end()) {
2934 MappedReg = RI->second;
2941 MappedReg =
DAG.MRI.createVirtualRegister(VGPRRC);
2942 RedefMap[DstReg] = MappedReg;
2947 for (MachineInstr *RD : DstUseDefsReplace) {
2949 if (ReachingDefCopyMap[DstReg].insert(RD).second) {
2950 MachineInstrBuilder VGPRCopy =
2953 .
addDef(MappedReg, {}, 0)
2954 .addUse(DstReg, {}, 0);
2955 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
2959 auto LMI = LastMIToRegion.
find(RD);
2960 if (LMI != LastMIToRegion.
end()) {
2961 unsigned UpdateRegion = LMI->second;
2962 DAG.Regions[UpdateRegion].second = VGPRCopy;
2963 LastMIToRegion.
erase(RD);
2969 DenseSet<MachineOperand *> &DstRegSet =
ReplaceMap[DstReg];
2972 MachineInstr *EarliestSameBlockUse =
nullptr;
2973 for (MachineOperand *RU : DstReachingUseCopies) {
2974 MachineBasicBlock *RUBlock = RU->getParent()->getParent();
2977 if (RUBlock !=
MI->getParent()) {
2983 if (!SameBlockCopyReg.
isValid()) {
2986 SameBlockCopyReg =
DAG.MRI.createVirtualRegister(VGPRRC);
2990 MachineInstr *UseInst = RU->getParent();
2991 if (!EarliestSameBlockUse ||
2993 DAG.LIS->getInstructionIndex(*UseInst),
2994 DAG.LIS->getInstructionIndex(*EarliestSameBlockUse)))
2995 EarliestSameBlockUse = UseInst;
2996 RU->setReg(SameBlockCopyReg);
3000 if (SameBlockCopyReg.
isValid()) {
3001 MachineInstrBuilder VGPRCopy =
3004 TII->get(TargetOpcode::COPY), SameBlockCopyReg)
3006 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
3011 RewriteRegs.
insert(DstReg);
3021 std::pair<unsigned, DenseMap<Register, SmallPtrSet<MachineOperand *, 8>>>;
3022 for (RUBType RUBlockEntry : ReachingUseTracker) {
3023 using RUDType = std::pair<Register, SmallPtrSet<MachineOperand *, 8>>;
3024 for (RUDType RUDst : RUBlockEntry.second) {
3025 MachineOperand *OpBegin = *RUDst.second.begin();
3026 SlotIndex InstPt =
DAG.LIS->getInstructionIndex(*OpBegin->
getParent());
3029 for (MachineOperand *User : RUDst.second) {
3030 SlotIndex NewInstPt =
DAG.LIS->getInstructionIndex(*
User->getParent());
3037 Register NewUseReg =
DAG.MRI.createVirtualRegister(VGPRRC);
3038 MachineInstr *UseInst =
DAG.LIS->getInstructionFromIndex(InstPt);
3040 MachineInstrBuilder VGPRCopy =
3043 .
addDef(NewUseReg, {}, 0)
3044 .addUse(RUDst.first, {}, 0);
3045 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
3049 auto FI = FirstMIToRegion.
find(UseInst);
3050 if (FI != FirstMIToRegion.
end()) {
3051 unsigned UpdateRegion = FI->second;
3052 DAG.Regions[UpdateRegion].first = VGPRCopy;
3053 FirstMIToRegion.
erase(UseInst);
3057 for (MachineOperand *User : RUDst.second) {
3058 User->setReg(NewUseReg);
3069 for (std::pair<Register, Register> NewDef : RedefMap) {
3074 for (MachineOperand *ReplaceOp :
ReplaceMap[OldReg])
3075 ReplaceOp->setReg(NewReg);
3079 for (
Register RewriteReg : RewriteRegs) {
3080 Register RegToRewrite = RewriteReg;
3083 auto RI = RedefMap.find(RewriteReg);
3084 if (RI != RedefMap.end())
3085 RegToRewrite = RI->second;
3090 DAG.MRI.setRegClass(RegToRewrite, AGPRRC);
3094 DAG.LIS->reanalyze(
DAG.MF);
3096 RegionPressureMap LiveInUpdater(&
DAG,
false);
3097 LiveInUpdater.buildLiveRegMap();
3100 DAG.LiveIns[Region] = LiveInUpdater.getLiveRegsForRegionIdx(Region);
3107unsigned PreRARematStage::getStageTargetOccupancy()
const {
3108 return TargetOcc ? *TargetOcc :
MFI.getMinWavesPerEU();
3111bool PreRARematStage::setObjective() {
3115 unsigned MaxSGPRs =
ST.getMaxNumSGPRs(
F);
3116 unsigned MaxVGPRs =
ST.getMaxNumVGPRs(
F);
3117 bool HasVectorRegisterExcess =
false;
3118 for (
unsigned I = 0,
E =
static_cast<unsigned>(
DAG.Regions.size());
I !=
E;
3120 const GCNRegPressure &
RP =
DAG.Pressure[
I];
3121 GCNRPTarget &
Target = RPTargets.emplace_back(MaxSGPRs, MaxVGPRs,
MF, RP);
3123 TargetRegions.set(
I);
3124 HasVectorRegisterExcess |=
Target.hasVectorRegisterExcess();
3127 if (HasVectorRegisterExcess ||
DAG.MinOccupancy >=
MFI.getMaxWavesPerEU()) {
3130 TargetOcc = std::nullopt;
3134 TargetOcc =
DAG.MinOccupancy + 1;
3135 const unsigned VGPRBlockSize =
MFI.getDynamicVGPRBlockSize();
3136 MaxSGPRs =
ST.getMaxNumSGPRs(*TargetOcc,
false);
3137 MaxVGPRs =
ST.getMaxNumVGPRs(*TargetOcc, VGPRBlockSize);
3138 for (
auto [
I, Target] :
enumerate(RPTargets)) {
3139 Target.setTarget(MaxSGPRs, MaxVGPRs);
3141 TargetRegions.set(
static_cast<unsigned>(
I));
3145 return TargetRegions.any();
3148bool PreRARematStage::candidateHasValidUsers(
3149 RegisterIdx CandIdx,
const SmallSet<Register, 4> &MarkedRegs)
const {
3150 const Rematerializer::Reg &CandReg = Remater.getReg(CandIdx);
3152 DAG.LIS->getInstructionIndex(*CandReg.
getLastDef()).getRegSlot(
true);
3154 for (
const auto &[UseRegion,
Users] : CandReg.
Uses) {
3158 "user must have at least one operand");
3161 const MachineOperand &DefMO = UserMI->
getOperand(0);
3166 MachineInstr *FirstUseMI =
3168 assert(FirstUseMI &&
"there must be a user in the region");
3169 SlotIndex FirstUseIdx =
3170 DAG.LIS->getInstructionIndex(*FirstUseMI).getRegSlot(
true);
3174 const Rematerializer::Reg &DepReg = Remater.getReg(DepRegIdx);
3175 Register DepDefReg = DepReg.getDefReg();
3176 return !Remater.isRegIdenticalAtUses(DepDefReg, DepReg.Mask, RefIdx,
3181 [&](
const std::pair<Register, LaneBitmask> &RegAndMask) {
3182 const auto &[
Reg,
Mask] = RegAndMask;
3183 return !Remater.isRegIdenticalAtUses(
Reg, Mask, RefIdx,
3191bool PreRARematStage::ScoredRemat::maybeBeneficial(
3193 for (
unsigned I : TargetRegions.set_bits()) {
3194 if (Live[
I] && RPTargets[
I].isSaveBeneficial(RPSave))
3207 const size_t NumRegions =
DAG.Regions.size();
3211 for (
size_t I = 0;
I < NumRegions; ++
I) {
3215 if (BlockFreq && BlockFreq <
MinFreq)
3224 if (
MinFreq >= ScaleFactor * ScaleFactor) {
3225 for (uint64_t &Freq :
Regions)
3226 Freq /= ScaleFactor;
3232void PreRARematStage::ScoredRemat::init(
const FreqInfo &Freq,
3241 for (
unsigned I : Live.set_bits()) {
3244 if (!LiveIn[
I] || !LiveOut[
I] || Reg.Uses.contains(
I))
3245 UnpredictableRPSave.set(
I);
3255 int64_t DefOrMin = Reg.hasUsersInDefRegion()
3258 int64_t UseOrMax = 0;
3259 for (
const auto &[UseRegion,
_] : Reg.Uses) {
3260 if (Reg.DefRegion == UseRegion)
3262 uint64_t RegionFreq = Freq.
Regions[UseRegion];
3263 UseOrMax += RegionFreq != 0 ? RegionFreq : Freq.
MaxFreq;
3265 FreqDiff = DefOrMin - UseOrMax;
3268void PreRARematStage::ScoredRemat::update(
const BitVector &TargetRegions,
3270 const FreqInfo &FreqInfo,
3274 for (
unsigned I : TargetRegions.
set_bits()) {
3283 if (!NumRegsBenefit)
3287 RegionImpact += (UnpredictableRPSave[
I] ? 1 : 2) * NumRegsBenefit;
3291 if (UnpredictableRPSave[
I]) {
3296 MaxFreq = std::max(MaxFreq, Freq);
3301void PreRARematStage::ScoredRemat::rematerialize(
3302 Rematerializer &Remater)
const {
3303 const Rematerializer::Reg &
Reg = Remater.getReg(RegIdx);
3306 Rematerializer::DependencyReuseInfo DRI;
3307 for (RegisterIdx DepRegIdx :
Reg.Dependencies)
3308 DRI.
reuse(DepRegIdx);
3311 SmallVector<unsigned, 8> RematRegions;
3313 for (
const auto &[UseRegion,
_] :
Reg.Uses) {
3314 if (
Reg.DefRegion != UseRegion)
3317 for (
const unsigned UseRegion : RematRegions) {
3318 Rematerializer::DependencyReuseInfo RegionDRI(DRI);
3319 Remater.rematerializeToRegion(RegIdx, UseRegion, RegionDRI);
3323void PreRARematStage::updateRPTargets(
const BitVector &Regions,
3324 const GCNRegPressure &RPSave) {
3326 RPTargets[
I].saveRP(RPSave);
3327 if (TargetRegions[
I] && RPTargets[
I].satisfied()) {
3329 TargetRegions.reset(
I);
3334bool PreRARematStage::updateAndVerifyRPTargets(
const BitVector &Regions) {
3335 bool TooOptimistic =
false;
3337 GCNRPTarget &
Target = RPTargets[
I];
3343 if (!TargetRegions[
I] && !
Target.satisfied()) {
3345 TooOptimistic =
true;
3346 TargetRegions.set(
I);
3349 return TooOptimistic;
3352void PreRARematStage::removeFromLiveMaps(
Register Reg,
const BitVector &LiveIn,
3353 const BitVector &LiveOut) {
3355 LiveOut.
size() ==
DAG.Regions.size() &&
"region num mismatch");
3359 DAG.RegionLiveOuts.getLiveRegsForRegionIdx(
I).erase(
Reg);
3362void PreRARematStage::addToLiveMaps(
Register Reg, LaneBitmask Mask,
3363 const BitVector &LiveIn,
3364 const BitVector &LiveOut) {
3366 LiveOut.
size() ==
DAG.Regions.size() &&
"region num mismatch");
3367 std::pair<Register, LaneBitmask> LiveReg(
Reg, Mask);
3369 DAG.LiveIns[
I].insert(LiveReg);
3371 DAG.RegionLiveOuts.getLiveRegsForRegionIdx(
I).insert(LiveReg);
3383 if (
DAG.MinOccupancy >= *TargetOcc)
3387 for (
const auto &[
RegionIdx, OrigMIOrder, MaxPressure] : RegionReverts) {
3397 if (AchievedOcc >= *TargetOcc) {
3398 DAG.setTargetOccupancy(AchievedOcc);
3403 DAG.setTargetOccupancy(*TargetOcc - 1);
3408 assert(Rollback &&
"rollbacker should be defined");
3409 Rollback->Listener.rollback(Remater);
3410 for (
const auto &[RegIdx, LiveIn, LiveOut] : Rollback->LiveMapUpdates) {
3411 const Rematerializer::Reg &
Reg = Remater.getReg(RegIdx);
3412 addToLiveMaps(
Reg.getDefReg(),
Reg.Mask, LiveIn, LiveOut);
3415#ifdef EXPENSIVE_CHECKS
3420 for (
unsigned I : RescheduleRegions.set_bits())
3421 DAG.Pressure[
I] =
DAG.getRealRegPressure(
I);
3426void GCNScheduleDAGMILive::setTargetOccupancy(
unsigned TargetOccupancy) {
3427 MinOccupancy = TargetOccupancy;
3428 if (
MFI.getOccupancy() < TargetOccupancy)
3429 MFI.increaseOccupancy(
MF, MinOccupancy);
3431 MFI.limitOccupancy(MinOccupancy);
3448 if (HasIGLPInstrs) {
3449 SavedMutations.clear();
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static SUnit * pickOnlyChoice(SchedBoundary &Zone)
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))
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[]
iv Induction Variable Users
A common definition of LaneBitmask for use in TableGen and CodeGen.
Promote Memory to Register
MachineRegisterInfo & MRI
MIR-level target-independent rematerialization helpers.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
const T & front() const
Get the first element.
size_t size() const
Get the array size.
bool empty() const
Check if the array is empty.
BitVector & reset()
Reset all bits in the bitvector.
iterator_range< const_set_bits_iterator > set_bits() const
size_type size() const
Returns the number of bits in this bitvector.
uint64_t getFrequency() const
Returns the frequency as a fixpoint number scaled by the entry frequency.
bool initGCNSchedStage() override
bool shouldRevertScheduling(unsigned WavesAfter) override
bool initGCNRegion() override
bool contains(const_arg_type_t< KeyT > Val) const
Return true if the specified key is in the map, false otherwise.
iterator find(const_arg_type_t< KeyT > Val)
bool erase(const KeyT &Val)
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Implements a dense probed hash-table based set.
Common behavior for downward RP trackers. Unconstructible directly.
Downward RP tracker that relies on program order to advance down the instruction stream.
GCNMaxILPSchedStrategy(const MachineSchedContext *C)
bool tryCandidate(SchedCandidate &Cand, SchedCandidate &TryCand, SchedBoundary *Zone) const override
Apply a set of heuristics to a new candidate.
bool tryCandidate(SchedCandidate &Cand, SchedCandidate &TryCand, SchedBoundary *Zone) const override
GCNMaxMemoryClauseSchedStrategy tries best to clause memory instructions as much as possible.
GCNMaxMemoryClauseSchedStrategy(const MachineSchedContext *C)
GCNMaxOccupancySchedStrategy(const MachineSchedContext *C, bool IsLegacyScheduler=false)
void finalizeSchedule() override
Allow targets to perform final scheduling actions at the level of the whole MachineFunction.
void schedule() override
Orders nodes according to selected style.
GCNPostScheduleDAGMILive(MachineSchedContext *C, std::unique_ptr< MachineSchedStrategy > S, bool RemoveKillFlags)
Models a register pressure target, allowing to evaluate and track register savings against that targe...
unsigned getNumRegsBenefit(const GCNRegPressure &SaveRP) const
Returns the benefit towards achieving the RP target that saving SaveRP represents,...
GCNRegPressure getPressure() const
void reset(const MachineInstr &MI, bool After)
Resets tracker before or After the provided MI, which can be a debug instruction.
virtual bool initGCNRegion()
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
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
This is a minimal scheduler strategy.
bool useGCNTrackers() const
GCNSchedStrategy(const MachineSchedContext *C)
SmallVector< GCNSchedStageID, 4 > SchedStages
unsigned SGPRCriticalLimit
unsigned VGPRThresholdPercent
std::vector< unsigned > MaxPressure
bool hasNextStage() const
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
unsigned VGPRCriticalLimit
void schedNode(SUnit *SU, bool IsTopNode) override
Notify MachineSchedStrategy that ScheduleDAGMI has scheduled an instruction and updated scheduled/rem...
std::optional< bool > GCNTrackersOverride
void getRegisterPressures(bool AtTop, const RegPressureTracker &RPTracker, SUnit *SU, std::vector< unsigned > &Pressure, std::vector< unsigned > &MaxPressure, const GCNDownwardRPTrackerBase &DownwardTracker, const GCNUpwardRPTracker &UpwardTracker, ScheduleDAGMI *DAG, const SIRegisterInfo *SRI)
unsigned AGPRCriticalLimit
std::vector< unsigned > Pressure
unsigned UnifiedVGPRCriticalLimit
void initialize(ScheduleDAGMI *DAG) override
Initialize the strategy after building the DAG for a new region.
GCNUpwardRPTracker UpwardTracker
void printCandidateDecision(const SchedCandidate &Current, const SchedCandidate &Preferred)
void pickNodeFromQueue(SchedBoundary &Zone, const CandPolicy &ZonePolicy, const RegPressureTracker &RPTracker, SchedCandidate &Cand, bool &IsPending, bool IsBottomUp)
GCNManualDownwardRPTracker DownwardTracker
GCNUpwardRPTracker & getUpwardTracker()
void initCandidate(SchedCandidate &Cand, SUnit *SU, bool AtTop, const RegPressureTracker &RPTracker, const SIRegisterInfo *SRI, unsigned SGPRPressure, unsigned VGPRPressure, unsigned AGPRPressure, bool IsBottomUp)
GCNDownwardRPTrackerBase & getDownwardTracker()
SUnit * pickNode(bool &IsTopNode) override
Pick the next node to schedule, or return NULL.
void finalizeSchedule() override
Allow targets to perform final scheduling actions at the level of the whole MachineFunction.
void schedule() override
Orders nodes according to selected style.
GCNScheduleDAGMILive(MachineSchedContext *C, std::unique_ptr< MachineSchedStrategy > S)
void recede(const MachineInstr &MI)
Move to the state of RP just before the MI.
void reset(const MachineInstr &MI)
Resets tracker to the point just after MI (in program order), which can be a debug instruction.
void compute(FunctionT &F)
Compute the cycle info for a function.
void traceCandidate(const SchedCandidate &Cand)
LLVM_ABI void setPolicy(CandPolicy &Policy, bool IsPostRA, SchedBoundary &CurrZone, SchedBoundary *OtherZone)
Set the CandPolicy given a scheduling zone given the current resources and latencies inside and outsi...
MachineSchedPolicy RegionPolicy
const TargetSchedModel * SchedModel
const MachineSchedContext * Context
const TargetRegisterInfo * TRI
SchedCandidate BotCand
Candidate last picked from Bot boundary.
SchedCandidate TopCand
Candidate last picked from Top boundary.
virtual bool tryCandidate(SchedCandidate &Cand, SchedCandidate &TryCand, SchedBoundary *Zone) const
Apply a set of heuristics to a new candidate.
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)
void finalizeGCNRegion() override
bool initGCNRegion() override
bool initGCNSchedStage() override
A live range for subregisters.
LiveInterval - This class represents the liveness of a register, or stack slot.
bool hasSubRanges() const
Returns true if subregister liveness information is available.
iterator_range< subrange_iterator > subranges()
SlotIndex getInstructionIndex(const MachineInstr &Instr) const
Returns the base index of the given instruction.
SlotIndex getMBBEndIdx(const MachineBasicBlock *mbb) const
Return the last index in the given basic block.
LiveInterval & getInterval(Register Reg)
LLVM_ABI void dump() const
MachineBasicBlock * getMBBFromIndex(SlotIndex index) const
VNInfo * getVNInfoAt(SlotIndex Idx) const
getVNInfoAt - Return the VNInfo that is live at Idx, or NULL.
uint8_t getCopyCost() const
getCopyCost - Return the cost of copying a value between two registers in this class.
int getNumber() const
MachineBasicBlocks are uniquely numbered at the function level, unless they're not in a MachineFuncti...
succ_iterator succ_begin()
unsigned succ_size() const
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.
const MachineBasicBlock * getParent() const
unsigned getNumOperands() const
Retuns the total number of operands.
bool mayLoad(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly read memory.
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
const MachineOperand & getOperand(unsigned i) const
MachineOperand class - Representation of each machine instruction operand.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
Register getReg() const
getReg - Returns the register number.
bool shouldRevertScheduling(unsigned WavesAfter) override
bool shouldRevertScheduling(unsigned WavesAfter) override
bool shouldRevertScheduling(unsigned WavesAfter) override
void finalizeGCNRegion() override
bool initGCNRegion() override
bool initGCNSchedStage() override
Capture a change in pressure for a single pressure set.
Simple wrapper around std::function<void(raw_ostream&)>.
Helpers for implementing custom MachineSchedStrategy classes.
Track the current register pressure at some position in the instruction stream, and remember the high...
LLVM_ABI void advance()
Advance across the current instruction.
LLVM_ABI void getDownwardPressure(const MachineInstr *MI, std::vector< unsigned > &PressureResult, std::vector< unsigned > &MaxPressureResult)
Get the pressure of each PSet after traversing this instruction top-down.
const std::vector< unsigned > & getRegSetPressureAtPos() const
Get the register set pressure at the current position, which may be less than the pressure across the...
LLVM_ABI void getUpwardPressure(const MachineInstr *MI, std::vector< unsigned > &PressureResult, std::vector< unsigned > &MaxPressureResult)
Get the pressure of each PSet after traversing this instruction bottom-up.
static LLVM_ABI void restoreLivenessFlags(MachineInstr &MI, const TargetRegisterInfo &TRI, const MachineRegisterInfo &MRI, LiveIntervals &LIS, bool TrackLaneMasks=true, ArrayRef< Register > OnlyRegs={})
Clear potentially-stale read-undef flags on the defs of MI, then recompute them from LIS.
Wrapper class representing virtual and physical registers.
constexpr bool isValid() const
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
static constexpr bool isVirtualRegister(unsigned Reg)
Return true if the specified register number is in the virtual register namespace.
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...
unsigned getOccupancy() const
unsigned getDynamicVGPRBlockSize() const
unsigned getMinAllowedOccupancy() const
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
SmallVector< SDep, 4 > Preds
All sunit predecessors.
MachineInstr * getInstr() const
Returns the representative MachineInstr for this SUnit.
Each Scheduling boundary is associated with ready queues.
LLVM_ABI void releasePending()
Release pending ready nodes in to the available queue.
LLVM_ABI unsigned getLatencyStallCycles(SUnit *SU)
Get the difference between the given SUnit's ready time and the current cycle.
LLVM_ABI SUnit * pickOnlyChoice()
Call this before applying any other heuristics to the Available queue.
LLVM_ABI void bumpCycle(unsigned NextCycle)
Move the boundary of scheduled code by one cycle.
unsigned getCurrMOps() const
Micro-ops issued in the current cycle.
unsigned getCurrCycle() const
Number of cycles to issue the instructions scheduled in this zone.
LLVM_ABI bool checkHazard(SUnit *SU)
Does this SU have a hazard within the current instruction group.
A ScheduleDAG for scheduling lists of MachineInstr.
bool ScheduleSingleMIRegions
True if regions with a single MI should be scheduled.
MachineBasicBlock::iterator RegionEnd
The end of the range to be scheduled.
virtual void finalizeSchedule()
Allow targets to perform final scheduling actions at the level of the whole MachineFunction.
const MachineLoopInfo * MLI
bool RemoveKillFlags
True if the DAG builder should remove kill flags (in preparation for rescheduling).
MachineBasicBlock::iterator RegionBegin
The beginning of the range to be scheduled.
void schedule() override
Implement ScheduleDAGInstrs interface for scheduling a sequence of reorderable instructions.
ScheduleDAGMILive(MachineSchedContext *C, std::unique_ptr< MachineSchedStrategy > S)
RegPressureTracker RPTracker
ScheduleDAGMI is an implementation of ScheduleDAGInstrs that simply schedules machine instructions ac...
void exitRegion() override
Called when the scheduler has finished scheduling the current region.
void addMutation(std::unique_ptr< ScheduleDAGMutation > Mutation)
Add a postprocessing step to the DAG builder.
void schedule() override
Implement ScheduleDAGInstrs interface for scheduling a sequence of reorderable instructions.
ScheduleDAGMI(MachineSchedContext *C, std::unique_ptr< MachineSchedStrategy > S, bool RemoveKillFlags)
std::vector< std::unique_ptr< ScheduleDAGMutation > > Mutations
Ordered list of DAG postprocessing steps.
MachineRegisterInfo & MRI
Virtual/real register map.
const TargetInstrInfo * TII
Target instruction information.
MachineFunction & MF
Machine function.
static const unsigned ScaleFactor
unsigned getMetric() const
bool empty() const
Determine if the SetVector is empty or not.
bool insert(const value_type &X)
Insert a new element into the SetVector.
SlotIndex - An opaque wrapper around machine indexes.
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...
bool contains(const T &V) const
Check if the SmallSet contains the given element.
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
reference emplace_back(ArgTypes &&... Args)
void reserve(size_type N)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
bool getAsInteger(unsigned Radix, T &Result) const
Parse the current string as an integer of the specified radix.
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 initGCNSchedStage() override
bool initGCNRegion() override
void finalizeGCNSchedStage() override
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.
std::pair< iterator, bool > insert(const ValueT &V)
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
self_iterator getIterator()
This class implements an extremely fast bulk output stream that can only output to a stream.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned getAddressableNumVGPRs(const MCSubtargetInfo &STI, unsigned DynamicVGPRBlockSize)
unsigned getAllocatedNumVGPRBlocks(const MCSubtargetInfo &STI, unsigned NumVGPRs, unsigned DynamicVGPRBlockSize, std::optional< bool > EnableWavefrontSize32)
unsigned getVGPRAllocGranule(const MCSubtargetInfo &STI, unsigned DynamicVGPRBlockSize, std::optional< bool > EnableWavefrontSize32)
LLVM_READONLY int32_t getAGPRFormOp(uint32_t Opcode)
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
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.
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.
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
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.
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.
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)
@ UnclusteredHighRPReschedule
@ MemoryClauseInitialSchedule
@ LiveIntervalRPReschedule
@ ClusteredLowOccupancyReschedule
auto reverse(ContainerTy &&C)
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
cl::opt< unsigned, false, VGPRThresholdParser > VGPRThresholdPercentOpt
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
LLVM_ABI bool shouldVerifyScheduling()
Returns whether -verify-misched is set.
iterator_range< ConstMIBundleOperands > const_mi_bundle_ops(const MachineInstr &MI)
LLVM_ABI bool tryLatency(GenericSchedulerBase::SchedCandidate &TryCand, GenericSchedulerBase::SchedCandidate &Cand, SchedBoundary &Zone)
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
IterT skipDebugInstructionsBackward(IterT It, IterT Begin, bool SkipPseudoOp=true)
Decrement It until it points to a non-debug instruction or to Begin and return the resulting iterator...
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
bool isTheSameCluster(unsigned A, unsigned B)
Return whether the input cluster ID's are the same and valid.
DWARFExpression::Operation Op
LLVM_ABI bool tryGreater(int TryVal, int CandVal, GenericSchedulerBase::SchedCandidate &TryCand, GenericSchedulerBase::SchedCandidate &Cand, GenericSchedulerBase::CandReason Reason)
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
ArrayRef(const T &OneElt) -> ArrayRef< T >
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
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
Implement std::hash so that hash_code can be used in STL containers.
bool operator()(std::pair< MachineInstr *, unsigned > A, std::pair< MachineInstr *, unsigned > B) const
unsigned getArchVGPRNum() const
unsigned getAGPRNum() const
unsigned getSGPRNum() const
static unsigned getUnifiedVGPRNum(unsigned NumArchVGPRs, unsigned NumAGPRs, unsigned NumAVGPRs)
Returns the aggregated VGPR pressure, assuming NumArchVGPRs ArchVGPRs NumAGPRs AGPRS,...
Policy for scheduling the next instruction in the candidate's zone.
Store the state used by GenericScheduler heuristics, required for the lifetime of one invocation of p...
void setBest(SchedCandidate &Best)
void reset(const CandPolicy &NewPolicy)
LLVM_ABI void initResourceDelta(const ScheduleDAGMI *DAG, const TargetSchedModel *SchedModel)
SchedResourceDelta ResDelta
Status of an instruction's critical resource consumption.
unsigned DemandedResources
constexpr bool any() const
static constexpr LaneBitmask getNone()
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)
PressureChange CriticalMax
PressureChange CurrentMax
DependencyReuseInfo & reuse(RegisterIdx DepIdx)
A rematerializable register, potentially defined by multiple instructions.
LLVM_ABI std::pair< MachineInstr *, MachineInstr * > getRegionUseBounds(unsigned UseRegion, const LiveIntervals &LIS) const
Returns the first and last user of the register in region UseRegion.
SmallVector< MachineInstr *, 1 > Defs
All instructions that define the register, in program order.
bool hasUsersOutsideDefRegion() const
SmallDenseMap< unsigned, RegionUsers, 2 > Uses
Uses of the register, mapped by region.
MachineInstr * getLastDef() const
Register getDefReg() const
Returns the rematerializable register from one of its defining instructions.
SmallVector< RegisterIdx, 2 > Dependencies
This register's rematerializable dependencies, one per unique rematerializable register operand over ...
bool parse(cl::Option &O, StringRef ArgName, StringRef Arg, unsigned &Value)