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);
171 "VGPRCriticalLimit calculation method.\n");
175 unsigned Addressable =
178 VGPRBudget = std::max(VGPRBudget, Granule);
194 <<
". VGPRCriticalLimit: " << OriginalVGPRCriticalLimit
241 if (!
Op.isReg() ||
Op.isImplicit())
243 if (
Op.getReg().isPhysical() ||
244 (
Op.isDef() &&
Op.getSubReg() != AMDGPU::NoSubRegister))
279 Pressure[AMDGPU::RegisterPressureSets::VGPR_32] =
288 unsigned SGPRPressure,
289 unsigned VGPRPressure,
290 unsigned AGPRPressure,
bool IsBottomUp) {
294 if (!
DAG->isTrackingPressure())
317 Pressure[AMDGPU::RegisterPressureSets::SReg_32] = SGPRPressure;
318 Pressure[AMDGPU::RegisterPressureSets::VGPR_32] = VGPRPressure;
319 Pressure[AMDGPU::RegisterPressureSets::AGPR_32] = AGPRPressure;
321 for (
const auto &Diff :
DAG->getPressureDiff(SU)) {
327 (IsBottomUp ? Diff.getUnitInc() : -Diff.getUnitInc());
330#ifdef EXPENSIVE_CHECKS
331 std::vector<unsigned> CheckPressure, CheckMaxPressure;
334 if (
Pressure[AMDGPU::RegisterPressureSets::SReg_32] !=
335 CheckPressure[AMDGPU::RegisterPressureSets::SReg_32] ||
336 Pressure[AMDGPU::RegisterPressureSets::VGPR_32] !=
337 CheckPressure[AMDGPU::RegisterPressureSets::VGPR_32] ||
338 Pressure[AMDGPU::RegisterPressureSets::AGPR_32] !=
339 CheckPressure[AMDGPU::RegisterPressureSets::AGPR_32]) {
340 errs() <<
"Register Pressure is inaccurate when calculated through "
342 <<
"SGPR got " <<
Pressure[AMDGPU::RegisterPressureSets::SReg_32]
344 << CheckPressure[AMDGPU::RegisterPressureSets::SReg_32] <<
"\n"
345 <<
"VGPR got " <<
Pressure[AMDGPU::RegisterPressureSets::VGPR_32]
347 << CheckPressure[AMDGPU::RegisterPressureSets::VGPR_32] <<
"\n"
348 <<
"AGPR got " <<
Pressure[AMDGPU::RegisterPressureSets::AGPR_32]
350 << CheckPressure[AMDGPU::RegisterPressureSets::AGPR_32] <<
"\n";
356 unsigned NewAGPRPressure =
Pressure[AMDGPU::RegisterPressureSets::AGPR_32];
357 unsigned NewSGPRPressure =
Pressure[AMDGPU::RegisterPressureSets::SReg_32];
358 unsigned NewVGPRPressure =
Pressure[AMDGPU::RegisterPressureSets::VGPR_32];
368 const unsigned MaxVGPRPressureInc = 16;
369 bool ShouldTrackVGPRs = VGPRPressure + MaxVGPRPressureInc >=
VGPRExcessLimit;
372 bool ShouldTrackSGPRs =
373 !ShouldTrackVGPRs && !ShouldTrackAGPRs && SGPRPressure >=
SGPRExcessLimit;
408 : std::numeric_limits<int>::min();
410 if (SGPRDelta >= 0 || VGPRDelta >= 0 || AGPRDelta >= 0) {
413 if (VGPRDelta >= SGPRDelta && VGPRDelta >= AGPRDelta) {
417 }
else if (AGPRDelta >= SGPRDelta) {
431 bool HasBufferedModel =
450 dbgs() <<
"Prefer:\t\t";
451 DAG->dumpNode(*Preferred.
SU);
455 DAG->dumpNode(*Current.
SU);
458 dbgs() <<
"Reason:\t\t";
472 unsigned SGPRPressure = 0;
473 unsigned VGPRPressure = 0;
474 unsigned AGPRPressure = 0;
476 if (
DAG->isTrackingPressure()) {
478 SGPRPressure =
Pressure[AMDGPU::RegisterPressureSets::SReg_32];
479 VGPRPressure =
Pressure[AMDGPU::RegisterPressureSets::VGPR_32];
480 AGPRPressure =
Pressure[AMDGPU::RegisterPressureSets::AGPR_32];
485 SGPRPressure =
T->getPressure().getSGPRNum();
486 VGPRPressure =
T->getPressure().getArchVGPRNum();
487 AGPRPressure =
T->getPressure().getAGPRNum();
492 for (
SUnit *SU : AQ) {
496 VGPRPressure, AGPRPressure, IsBottomUp);
516 for (
SUnit *SU : PQ) {
520 VGPRPressure, AGPRPressure, IsBottomUp);
540 bool &PickedPending) {
560 bool BotPending =
false;
580 "Last pick result should correspond to re-picking right now");
585 bool TopPending =
false;
605 "Last pick result should correspond to re-picking right now");
615 PickedPending = BotPending && TopPending;
618 if (BotPending || TopPending) {
625 Cand.setBest(TryCand);
630 IsTopNode = Cand.AtTop;
637 if (
DAG->top() ==
DAG->bottom()) {
639 Bot.Available.empty() &&
Bot.Pending.empty() &&
"ReadyQ garbage");
645 PickedPending =
false;
679 if (ReadyCycle > CurrentCycle)
744 if (
DAG->isTrackingPressure() &&
750 if (
DAG->isTrackingPressure() &&
755 bool SameBoundary = Zone !=
nullptr;
779 if (IsLegacyScheduler)
798 if (
DAG->isTrackingPressure() &&
808 bool SameBoundary = Zone !=
nullptr;
843 bool CandIsClusterSucc =
845 bool TryCandIsClusterSucc =
847 if (
tryGreater(TryCandIsClusterSucc, CandIsClusterSucc, TryCand, Cand,
852 if (
DAG->isTrackingPressure() &&
858 if (
DAG->isTrackingPressure() &&
904 if (
DAG->isTrackingPressure()) {
920 bool CandIsClusterSucc =
922 bool TryCandIsClusterSucc =
924 if (
tryGreater(TryCandIsClusterSucc, CandIsClusterSucc, TryCand, Cand,
933 bool SameBoundary = Zone !=
nullptr;
950 if (TryMayLoad || CandMayLoad) {
951 bool TryLongLatency =
953 bool CandLongLatency =
957 Zone->
isTop() ? CandLongLatency : TryLongLatency, TryCand,
975 if (
DAG->isTrackingPressure() &&
994 !
Rem.IsAcyclicLatencyLimited &&
tryLatency(TryCand, Cand, *Zone))
1012 StartingOccupancy(MFI.getOccupancy()), MinOccupancy(StartingOccupancy),
1013 RegionLiveOuts(this,
true) {
1019 LLVM_DEBUG(
dbgs() <<
"Starting occupancy is " << StartingOccupancy <<
".\n");
1021 MinOccupancy = std::min(MFI.getMinAllowedOccupancy(), StartingOccupancy);
1022 if (MinOccupancy != StartingOccupancy)
1023 LLVM_DEBUG(
dbgs() <<
"Allowing Occupancy drops to " << MinOccupancy
1028std::unique_ptr<GCNSchedStage>
1030 switch (SchedStageID) {
1032 return std::make_unique<OccInitialScheduleStage>(SchedStageID, *
this);
1034 return std::make_unique<RewriteMFMAFormStage>(SchedStageID, *
this);
1036 return std::make_unique<UnclusteredHighRPStage>(SchedStageID, *
this);
1038 return std::make_unique<ClusteredLowOccStage>(SchedStageID, *
this);
1040 return std::make_unique<PreRARematStage>(SchedStageID, *
this);
1042 return std::make_unique<ILPInitialScheduleStage>(SchedStageID, *
this);
1044 return std::make_unique<MemoryClauseInitialScheduleStage>(SchedStageID,
1047 return std::make_unique<LiveIntervalRPStage>(SchedStageID, *
this);
1060GCNScheduleDAGMILive::getRealRegPressure(
unsigned RegionIdx)
const {
1061 if (Regions[RegionIdx].first == Regions[RegionIdx].second)
1065 &LiveIns[RegionIdx]);
1071 assert(RegionBegin != RegionEnd &&
"Region must not be empty");
1075void GCNScheduleDAGMILive::computeBlockPressure(
unsigned RegionIdx,
1087 const MachineBasicBlock *OnlySucc =
nullptr;
1090 if (!Candidate->empty() && Candidate->pred_size() == 1) {
1091 SlotIndexes *Ind =
LIS->getSlotIndexes();
1093 OnlySucc = Candidate;
1098 size_t CurRegion = RegionIdx;
1099 for (
size_t E = Regions.size(); CurRegion !=
E; ++CurRegion)
1100 if (Regions[CurRegion].first->getParent() !=
MBB)
1105 auto LiveInIt = MBBLiveIns.find(
MBB);
1106 auto &Rgn = Regions[CurRegion];
1108 if (LiveInIt != MBBLiveIns.end()) {
1109 auto LiveIn = std::move(LiveInIt->second);
1111 MBBLiveIns.erase(LiveInIt);
1114 auto LRS = BBLiveInMap.lookup(NonDbgMI);
1115#ifdef EXPENSIVE_CHECKS
1124 if (Regions[CurRegion].first ==
I || NonDbgMI ==
I) {
1125 LiveIns[CurRegion] =
RPTracker.getLiveRegs();
1129 if (Regions[CurRegion].second ==
I) {
1130 Pressure[CurRegion] =
RPTracker.moveMaxPressure();
1131 if (CurRegion-- == RegionIdx)
1133 auto &Rgn = Regions[CurRegion];
1146 MBBLiveIns[OnlySucc] =
RPTracker.moveLiveRegs();
1151GCNScheduleDAGMILive::getRegionLiveInMap()
const {
1152 assert(!Regions.empty());
1153 std::vector<MachineInstr *> RegionFirstMIs;
1154 RegionFirstMIs.reserve(Regions.size());
1156 RegionFirstMIs.push_back(
1163GCNScheduleDAGMILive::getRegionLiveOutMap()
const {
1164 assert(!Regions.empty());
1165 std::vector<MachineInstr *> RegionLastMIs;
1166 RegionLastMIs.reserve(Regions.size());
1177 IdxToInstruction.clear();
1180 IsLiveOut ? DAG->getRegionLiveOutMap() : DAG->getRegionLiveInMap();
1181 for (
unsigned I = 0;
I < DAG->Regions.size();
I++) {
1182 auto &[RegionBegin, RegionEnd] = DAG->Regions[
I];
1184 if (RegionBegin == RegionEnd)
1188 IdxToInstruction[
I] = RegionKey;
1196 LiveIns.resize(Regions.size());
1197 Pressure.resize(Regions.size());
1198 RegionsWithHighRP.resize(Regions.size());
1199 RegionsWithExcessRP.resize(Regions.size());
1200 RegionsWithIGLPInstrs.resize(Regions.size());
1201 RegionsWithHighRP.reset();
1202 RegionsWithExcessRP.reset();
1203 RegionsWithIGLPInstrs.reset();
1208void GCNScheduleDAGMILive::runSchedStages() {
1209 LLVM_DEBUG(
dbgs() <<
"All regions recorded, starting actual scheduling.\n");
1212 if (!Regions.
empty()) {
1213 BBLiveInMap = getRegionLiveInMap();
1218#ifdef DUMP_MAX_REG_PRESSURE
1228 if (!Stage->initGCNSchedStage())
1231 for (
auto Region : Regions) {
1235 if (!Stage->initGCNRegion()) {
1236 Stage->advanceRegion();
1242 const unsigned RegionIdx = Stage->getRegionIdx();
1245 MRI, RegionLiveOuts.getLiveRegsForRegionIdx(RegionIdx));
1249 Stage->finalizeGCNRegion();
1250 Stage->advanceRegion();
1254 Stage->finalizeGCNSchedStage();
1257#ifdef DUMP_MAX_REG_PRESSURE
1270 OS <<
"Max Occupancy Initial Schedule";
1273 OS <<
"Instruction Rewriting Reschedule";
1276 OS <<
"Unclustered High Register Pressure Reschedule";
1279 OS <<
"Clustered Low Occupancy Reschedule";
1282 OS <<
"Pre-RA Rematerialize";
1285 OS <<
"Max ILP Initial Schedule";
1288 OS <<
"Max memory clause Initial Schedule";
1291 OS <<
"Live Interval RP Reschedule";
1311void RewriteMFMAFormStage::findReachingDefs(
1333 while (!Worklist.
empty()) {
1348 for (MachineBasicBlock *PredMBB : DefMBB->
predecessors()) {
1349 if (Visited.
insert(PredMBB).second)
1355void RewriteMFMAFormStage::findReachingUses(
1359 for (MachineOperand &UseMO :
1362 findReachingDefs(UseMO, LIS, ReachingDefIndexes);
1366 if (
any_of(ReachingDefIndexes, [DefIdx](SlotIndex RDIdx) {
1378 if (!
ST.hasGFX90AInsts() ||
MFI.getMinWavesPerEU() > 1)
1381 RegionsWithExcessArchVGPR.resize(
DAG.Regions.size());
1382 RegionsWithExcessArchVGPR.reset();
1386 RegionsWithExcessArchVGPR[
Region] =
true;
1389 if (RegionsWithExcessArchVGPR.none())
1392 TII =
ST.getInstrInfo();
1393 SRI =
ST.getRegisterInfo();
1395 std::vector<std::pair<MachineInstr *, unsigned>> RewriteCands;
1399 if (!initHeuristics(RewriteCands, CopyForUse, CopyForDef))
1402 int64_t
Cost = getRewriteCost(RewriteCands, CopyForUse, CopyForDef);
1409 return rewrite(RewriteCands);
1419 if (
DAG.RegionsWithHighRP.none() &&
DAG.RegionsWithExcessRP.none())
1426 InitialOccupancy =
DAG.MinOccupancy;
1429 TempTargetOccupancy =
MFI.getMaxWavesPerEU() >
DAG.MinOccupancy
1430 ? InitialOccupancy + 1
1432 IsAnyRegionScheduled =
false;
1433 S.SGPRLimitBias =
S.HighRPSGPRBias;
1434 S.VGPRLimitBias =
S.HighRPVGPRBias;
1438 <<
"Retrying function scheduling without clustering. "
1439 "Aggressively try to reduce register pressure to achieve occupancy "
1440 << TempTargetOccupancy <<
".\n");
1455 if (
DAG.StartingOccupancy <=
DAG.MinOccupancy)
1459 dbgs() <<
"Retrying function scheduling with lowest recorded occupancy "
1460 <<
DAG.MinOccupancy <<
".\n");
1465#define REMAT_PREFIX "[PreRARemat] "
1466#define REMAT_DEBUG(X) LLVM_DEBUG(dbgs() << REMAT_PREFIX; X;)
1468#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
1469Printable PreRARematStage::ScoredRemat::print()
const {
1471 OS <<
'(' << MaxFreq <<
", " << FreqDiff <<
", " << RegionImpact <<
')';
1486 auto PrintTargetRegions = [&]() ->
void {
1487 if (TargetRegions.none()) {
1492 for (
unsigned I : TargetRegions.set_bits())
1499 dbgs() <<
"Analyzing ";
1500 MF.getFunction().printAsOperand(
dbgs(),
false);
1503 if (!setObjective()) {
1504 LLVM_DEBUG(
dbgs() <<
"no objective to achieve, occupancy is maximal at "
1505 <<
MFI.getMaxWavesPerEU() <<
'\n');
1510 dbgs() <<
"increase occupancy from " << *TargetOcc - 1 <<
'\n';
1512 dbgs() <<
"reduce spilling (minimum target occupancy is "
1513 <<
MFI.getMinWavesPerEU() <<
")\n";
1515 PrintTargetRegions();
1520 DAG.RegionLiveOuts.buildLiveRegMap();
1522 if (!Remater.analyze()) {
1538 DefRegToCandIdx.
resize(
DAG.MRI.getNumVirtRegs());
1539 const unsigned NumRegions =
DAG.Regions.size();
1541 for (
unsigned RegIdx = 0, E = Remater.getNumRegs(); RegIdx < E; ++RegIdx) {
1545 if (CandReg.
Uses.size() != 1)
1547 const auto [UseRegion,
Users] = *CandReg.
Uses.begin();
1566 "user must have at least one operand");
1573 assert(FirstUseMI &&
"there must be a user in the region");
1575 DAG.LIS->getInstructionIndex(*FirstUseMI).getRegSlot(
true);
1577 DAG.LIS->getInstructionIndex(*CandReg.
getLastDef()).getRegSlot(
true);
1579 const Rematerializer::Reg &DepReg = Remater.getReg(DepRegIdx);
1580 Register DepDefReg = DepReg.getDefReg();
1581 return MarkedRegs.contains(DepDefReg) ||
1582 !Remater.isRegIdenticalAtUses(DepDefReg, DepReg.Mask, RefIdx,
1587 [&](
const std::pair<Register, LaneBitmask> &RegAndMask) {
1588 const auto &[Reg, Mask] = RegAndMask;
1589 return !Remater.isRegIdenticalAtUses(Reg, Mask, RefIdx,
1594 Register DefReg = CandReg.getDefReg();
1595 MarkedRegs.
insert(DefReg);
1596 DefRegToCandIdx[DefReg] = Candidates.
size();
1604 for (
unsigned I = 0;
I < NumRegions; ++
I) {
1605 for (
const auto &[Reg, Mask] :
DAG.LiveIns[
I]) {
1608 unsigned CandIdx = DefRegToCandIdx[Reg];
1610 Candidates[CandIdx].LiveIn.set(
I);
1612 for (
const auto &[
Reg, Mask] :
1616 unsigned CandIdx = DefRegToCandIdx[
Reg];
1618 Candidates[CandIdx].LiveOut.set(
I);
1623 SmallVector<unsigned> CandidateOrder;
1624 for (
auto [CandIdx, Cand] :
enumerate(Candidates)) {
1625 Cand.init(FreqInfo, Remater,
DAG);
1626 Cand.update(TargetRegions, RPTargets, FreqInfo, !TargetOcc);
1627 if (!Cand.hasNullScore())
1638 Rollback = std::make_unique<RollbackSupport>(Remater);
1643 BitVector RecomputeRP(
DAG.Regions.size());
1645 RecomputeRP.reset();
1648 sort(CandidateOrder, [&](
unsigned LHSIndex,
unsigned RHSIndex) {
1649 return Candidates[LHSIndex] < Candidates[RHSIndex];
1653 dbgs() <<
"==== NEW REMAT ROUND ====\n"
1655 <<
"Candidates with non-null score, in rematerialization order:\n";
1656 for (
const ScoredRemat &Cand :
reverse(Candidates)) {
1658 << Remater.printRematReg(Cand.RegIdx) <<
'\n';
1660 PrintTargetRegions();
1666 while (!CandidateOrder.
empty()) {
1667 const ScoredRemat &Cand = Candidates[CandidateOrder.
back()];
1668 const Rematerializer::Reg &
Reg = Remater.getReg(Cand.RegIdx);
1676 if (!Cand.maybeBeneficial(TargetRegions, RPTargets)) {
1678 << Cand.print() <<
" | "
1679 << Remater.printRematReg(Cand.RegIdx));
1684#ifdef EXPENSIVE_CHECKS
1687 for (
const MachineInstr *
DefMI :
Reg.Defs) {
1692 if (!MO.isReg() || !MO.getReg() || !MO.readsReg() || MO.isDef())
1699 LiveInterval &LI =
DAG.LIS->getInterval(
UseReg);
1700 LaneBitmask LM =
DAG.MRI.getMaxLaneMaskForVReg(MO.getReg());
1702 LM =
DAG.TRI->getSubRegIndexLaneMask(MO.getSubReg());
1704 const unsigned UseRegion =
Reg.Uses.begin()->first;
1705 LaneBitmask LiveInMask =
DAG.LiveIns[UseRegion].at(
UseReg);
1706 LaneBitmask UncoveredLanes = LM & ~(LiveInMask & LM);
1710 if (UncoveredLanes.
any()) {
1712 for (LiveInterval::SubRange &SR : LI.
subranges())
1713 assert((SR.LaneMask & UncoveredLanes).none());
1721 REMAT_DEBUG(
dbgs() <<
"** REMAT " << Remater.printRematReg(Cand.RegIdx)
1723 removeFromLiveMaps(
Reg.getDefReg(), Cand.LiveIn, Cand.LiveOut);
1725 Rollback->LiveMapUpdates.emplace_back(Cand.RegIdx, Cand.LiveIn,
1728 Cand.rematerialize(Remater);
1733 updateRPTargets(Cand.Live, Cand.RPSave);
1734 RecomputeRP |= Cand.UnpredictableRPSave;
1735 RescheduleRegions |= Cand.Live;
1736 if (!TargetRegions.any()) {
1742 if (!updateAndVerifyRPTargets(RecomputeRP) && !TargetRegions.any()) {
1751 unsigned NumUsefulCandidates = 0;
1752 for (
unsigned CandIdx : CandidateOrder) {
1753 ScoredRemat &Candidate = Candidates[CandIdx];
1754 Candidate.update(TargetRegions, RPTargets, FreqInfo, !TargetOcc);
1755 if (!Candidate.hasNullScore())
1756 CandidateOrder[NumUsefulCandidates++] = CandIdx;
1758 if (NumUsefulCandidates == 0) {
1759 REMAT_DEBUG(
dbgs() <<
"Stop on exhausted rematerialization candidates\n");
1762 CandidateOrder.truncate(NumUsefulCandidates);
1765 if (RescheduleRegions.none())
1771 unsigned DynamicVGPRBlockSize =
MFI.getDynamicVGPRBlockSize();
1772 for (
unsigned I : RescheduleRegions.set_bits()) {
1773 DAG.Pressure[
I] = RPTargets[
I].getCurrentRP();
1775 <<
DAG.Pressure[
I].getOccupancy(
ST, DynamicVGPRBlockSize)
1776 <<
" (" << RPTargets[
I] <<
")\n");
1778 AchievedOcc =
MFI.getMaxWavesPerEU();
1779 for (
const GCNRegPressure &RP :
DAG.Pressure) {
1781 std::min(AchievedOcc,
RP.getOccupancy(
ST, DynamicVGPRBlockSize));
1785 dbgs() <<
"Retrying function scheduling with new min. occupancy of "
1786 << AchievedOcc <<
" from rematerializing (original was "
1787 <<
DAG.MinOccupancy;
1789 dbgs() <<
", target was " << *TargetOcc;
1793 DAG.setTargetOccupancy(getStageTargetOccupancy());
1804 S.SGPRLimitBias =
S.VGPRLimitBias = 0;
1805 if (
DAG.MinOccupancy > InitialOccupancy) {
1806 assert(IsAnyRegionScheduled);
1808 <<
" stage successfully increased occupancy to "
1809 <<
DAG.MinOccupancy <<
'\n');
1810 }
else if (!IsAnyRegionScheduled) {
1811 assert(
DAG.MinOccupancy == InitialOccupancy);
1813 <<
": No regions scheduled, min occupancy stays at "
1814 <<
DAG.MinOccupancy <<
", MFI occupancy stays at "
1815 <<
MFI.getOccupancy() <<
".\n");
1823 if (
DAG.begin() ==
DAG.end())
1830 unsigned NumRegionInstrs = std::distance(
DAG.begin(),
DAG.end());
1834 if (
DAG.begin() == std::prev(
DAG.end()))
1840 <<
"\n From: " << *
DAG.begin() <<
" To: ";
1842 else dbgs() <<
"End";
1843 dbgs() <<
" RegionInstrs: " << NumRegionInstrs <<
'\n');
1851 for (
auto &
I :
DAG) {
1864 dbgs() <<
"Pressure before scheduling:\nRegion live-ins:"
1866 <<
"Region live-in pressure: "
1870 S.HasHighPressure =
false;
1892 unsigned DynamicVGPRBlockSize =
DAG.MFI.getDynamicVGPRBlockSize();
1895 unsigned CurrentTargetOccupancy =
1896 IsAnyRegionScheduled ?
DAG.MinOccupancy : TempTargetOccupancy;
1898 (CurrentTargetOccupancy <= InitialOccupancy ||
1899 DAG.Pressure[
RegionIdx].getOccupancy(
ST, DynamicVGPRBlockSize) !=
1906 if (!IsAnyRegionScheduled && IsSchedulingThisRegion) {
1907 IsAnyRegionScheduled =
true;
1908 if (
MFI.getMaxWavesPerEU() >
DAG.MinOccupancy)
1909 DAG.setTargetOccupancy(TempTargetOccupancy);
1911 return IsSchedulingThisRegion;
1927 return !RevertAllRegions && RescheduleRegions[
RegionIdx] &&
1947 if (
S.HasHighPressure)
1968 if (
DAG.MinOccupancy < *TargetOcc) {
1970 <<
" cannot meet occupancy target, interrupting "
1971 "re-scheduling in all regions\n");
1972 RevertAllRegions =
true;
1983 unsigned DynamicVGPRBlockSize =
DAG.MFI.getDynamicVGPRBlockSize();
1994 unsigned TargetOccupancy = std::min(
1995 S.getTargetOccupancy(),
ST.getOccupancyWithWorkGroupSizes(
MF).second);
1996 unsigned WavesAfter = std::min(
1997 TargetOccupancy,
PressureAfter.getOccupancy(
ST, DynamicVGPRBlockSize));
1998 unsigned WavesBefore = std::min(
2000 LLVM_DEBUG(
dbgs() <<
"Occupancy before scheduling: " << WavesBefore
2001 <<
", after " << WavesAfter <<
".\n");
2007 unsigned NewOccupancy = std::max(WavesAfter, WavesBefore);
2011 if (WavesAfter < WavesBefore && WavesAfter <
DAG.MinOccupancy &&
2012 WavesAfter >=
MFI.getMinAllowedOccupancy()) {
2013 LLVM_DEBUG(
dbgs() <<
"Function is memory bound, allow occupancy drop up to "
2014 <<
MFI.getMinAllowedOccupancy() <<
" waves\n");
2015 NewOccupancy = WavesAfter;
2018 if (NewOccupancy <
DAG.MinOccupancy) {
2019 DAG.MinOccupancy = NewOccupancy;
2020 MFI.limitOccupancy(
DAG.MinOccupancy);
2022 <<
DAG.MinOccupancy <<
".\n");
2026 unsigned MaxVGPRs =
ST.getMaxNumVGPRs(
MF);
2029 unsigned MaxArchVGPRs = std::min(MaxVGPRs,
ST.getAddressableNumArchVGPRs());
2030 unsigned MaxSGPRs =
ST.getMaxNumSGPRs(
MF);
2054 unsigned ReadyCycle = CurrCycle;
2055 for (
auto &
D : SU.
Preds) {
2056 if (
D.isAssignedRegDep()) {
2059 unsigned DefReady = ReadyCycles[
DAG.getSUnit(
DefMI)->NodeNum];
2060 ReadyCycle = std::max(ReadyCycle, DefReady +
Latency);
2063 ReadyCycles[SU.
NodeNum] = ReadyCycle;
2070 std::pair<MachineInstr *, unsigned>
B)
const {
2071 return A.second <
B.second;
2077 if (ReadyCycles.empty())
2079 unsigned BBNum = ReadyCycles.begin()->first->getParent()->getNumber();
2080 dbgs() <<
"\n################## Schedule time ReadyCycles for MBB : " << BBNum
2081 <<
" ##################\n# Cycle #\t\t\tInstruction "
2085 for (
auto &
I : ReadyCycles) {
2086 if (
I.second > IPrev + 1)
2087 dbgs() <<
"****************************** BUBBLE OF " <<
I.second - IPrev
2088 <<
" CYCLES DETECTED ******************************\n\n";
2089 dbgs() <<
"[ " <<
I.second <<
" ] : " << *
I.first <<
"\n";
2102 unsigned SumBubbles = 0;
2104 unsigned CurrCycle = 0;
2105 for (
auto &SU : InputSchedule) {
2106 unsigned ReadyCycle =
2108 SumBubbles += ReadyCycle - CurrCycle;
2110 ReadyCyclesSorted.insert(std::make_pair(SU.getInstr(), ReadyCycle));
2112 CurrCycle = ++ReadyCycle;
2135 unsigned SumBubbles = 0;
2137 unsigned CurrCycle = 0;
2138 for (
auto &
MI :
DAG) {
2142 unsigned ReadyCycle =
2144 SumBubbles += ReadyCycle - CurrCycle;
2146 ReadyCyclesSorted.insert(std::make_pair(SU->
getInstr(), ReadyCycle));
2148 CurrCycle = ++ReadyCycle;
2165 if (WavesAfter <
DAG.MinOccupancy)
2169 if (
DAG.MFI.isDynamicVGPREnabled()) {
2172 DAG.MFI.getDynamicVGPRBlockSize());
2175 if (BlocksAfter > BlocksBefore)
2212 <<
"\n\t *** In shouldRevertScheduling ***\n"
2213 <<
" *********** BEFORE UnclusteredHighRPStage ***********\n");
2217 <<
"\n *********** AFTER UnclusteredHighRPStage ***********\n");
2219 unsigned OldMetric = MBefore.
getMetric();
2220 unsigned NewMetric = MAfter.
getMetric();
2221 unsigned WavesBefore = std::min(
2222 S.getTargetOccupancy(),
2229 LLVM_DEBUG(
dbgs() <<
"\tMetric before " << MBefore <<
"\tMetric after "
2230 << MAfter <<
"Profit: " << Profit <<
"\n");
2261 unsigned WavesAfter) {
2271 cl::desc(
"Percent increase of live interval RP over instant pressure to "
2272 "trigger rescheduling"),
2278 "Reduction factor (percent) for VGPR threshold during live interval RP "
2279 "reschedule stage"),
2283 "amdgpu-lirp-instant-lower-bound",
cl::Hidden,
2284 cl::desc(
"Lower bound (percent of the VGPR excess limit) on instant RP, "
2285 "below which a region is skipped"),
2295 if (!
S.VGPRThresholdPercent) {
2296 LLVM_DEBUG(
dbgs() <<
"LIRP: expected VGPRThresholdPercent to be enabled, "
2297 "not using live interval RP reschedule stage\n");
2305 unsigned InstantRP =
DAG.Pressure[
RegionIdx].getArchVGPRNum();
2306 auto [RegionBegin, RegionEnd] =
DAG.Regions[
RegionIdx];
2307 if (RegionBegin == RegionEnd)
2314 unsigned NewVGPRThresholdPercent =
2318 <<
", VGPRThresholdPercent: " <<
S.VGPRThresholdPercent
2319 <<
" -> " << NewVGPRThresholdPercent
2320 <<
", VGPRExcessLimit=" <<
S.VGPRExcessLimit
2321 <<
", VGPRCriticalLimit=" <<
S.VGPRCriticalLimit
2322 <<
", InstantRP=" << InstantRP <<
", LIRP=" << LIRP);
2324 bool DoRescheduling =
false;
2326 unsigned InstantRPLowerBound =
2328 if (LIRP >
S.VGPRExcessLimit) {
2329 LLVM_DEBUG(
dbgs() <<
" [LIRP exceeds the limit (" <<
S.VGPRExcessLimit
2330 <<
"), rescheduling]");
2331 DoRescheduling =
true;
2332 }
else if (LIRP > InstantRP && InstantRP > InstantRPLowerBound) {
2333 unsigned IncreasePercent = ((LIRP - InstantRP) * 100) / InstantRP;
2337 DoRescheduling =
true;
2343 SavedVGPRExcessLimit =
S.VGPRExcessLimit;
2344 SavedVGPRCriticalLimit =
S.VGPRCriticalLimit;
2345 SavedVGPRThresholdPercent =
S.VGPRThresholdPercent;
2346 S.VGPRThresholdPercent = NewVGPRThresholdPercent;
2354 S.VGPRExcessLimit = SavedVGPRExcessLimit;
2355 S.VGPRCriticalLimit = SavedVGPRCriticalLimit;
2356 S.VGPRThresholdPercent = SavedVGPRThresholdPercent;
2363 LLVM_DEBUG(
dbgs() <<
"New pressure will result in more spilling.\n");
2375 "instruction number mismatch");
2376 if (MIOrder.
empty())
2389 if (MII != RegionEnd) {
2391 bool NonDebugReordered =
2392 !
MI->isDebugInstr() &&
2398 if (NonDebugReordered)
2399 DAG.LIS->handleMove(*
MI,
true);
2406 if (!
MI->isDebugInstr()) {
2408 SlotIndex PrevIdx =
DAG.LIS->getSlotIndexes()->getIndexBefore(*
MI);
2409 if (PrevIdx >= MIIdx)
2410 DAG.LIS->handleMove(*
MI,
true);
2414 if (
MI->isDebugInstr()) {
2421 DAG.ShouldTrackLaneMasks);
2440 if (RD->
getOpcode() == AMDGPU::AV_MOV_B32_IMM_PSEUDO ||
2441 RD->
getOpcode() == AMDGPU::AV_MOV_B64_IMM_PSEUDO)
2448bool RewriteMFMAFormStage::hasUseRequiringVGPR(
2450 const SmallPtrSetImpl<MachineInstr *> &RewriteSet) {
2451 for (SlotIndex RDIdx : Src2ReachingDefs) {
2452 const MachineInstr *RD =
DAG.LIS->getInstructionFromIndex(RDIdx);
2454 findReachingUses(RD,
DAG.LIS, ReachingUses);
2455 for (
const MachineOperand *UseMO : ReachingUses) {
2467void RewriteMFMAFormStage::resetRewriteCandsToVGPR(
2468 ArrayRef<std::pair<MachineInstr *, unsigned>> RewriteCands) {
2469 for (
auto [
MI, OriginalOpcode] : RewriteCands) {
2472 DAG.MRI.getRegClass(
MI->getOperand(0).getReg());
2474 DAG.MRI.setRegClass(
MI->getOperand(0).getReg(), VDefRC);
2475 MI->setDesc(
TII->get(OriginalOpcode));
2477 MachineOperand *
Src2 =
TII->getNamedOperand(*
MI, AMDGPU::OpName::src2);
2486 DAG.MRI.setRegClass(
Src2->getReg(), VUseRC);
2490bool RewriteMFMAFormStage::isRewriteCandidate(MachineInstr *
MI)
const {
2491 if (!
static_cast<const SIInstrInfo *
>(
DAG.TII)->isMAI(*
MI))
2496 Register DstReg =
MI->getOperand(0).getReg();
2497 for (
const MachineInstr &
UseMI :
DAG.MRI.use_nodbg_instructions(DstReg)) {
2504bool RewriteMFMAFormStage::initHeuristics(
2505 std::vector<std::pair<MachineInstr *, unsigned>> &RewriteCands,
2506 DenseMap<MachineBasicBlock *, std::set<Register>> &CopyForUse,
2507 SmallPtrSetImpl<MachineInstr *> &CopyForDef) {
2512 SmallPtrSet<MachineInstr *, 16> RewriteSet;
2513 DenseSet<Register> CandSrc2Regs;
2514 for (MachineBasicBlock &
MBB :
MF) {
2515 for (MachineInstr &
MI :
MBB) {
2516 if (!isRewriteCandidate(&
MI))
2519 MachineOperand *
Src2 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src2);
2520 if (Src2 &&
Src2->isReg())
2526 for (MachineBasicBlock &
MBB :
MF) {
2527 for (MachineInstr &
MI :
MBB) {
2528 if (!isRewriteCandidate(&
MI))
2532 assert(ReplacementOp != -1);
2534 RewriteCands.push_back({&
MI,
MI.getOpcode()});
2535 MI.setDesc(
TII->get(ReplacementOp));
2537 MachineOperand *
Src2 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src2);
2538 if (
Src2->isReg()) {
2540 findReachingDefs(*Src2,
DAG.LIS, Src2ReachingDefs);
2544 bool Src2NeedsVGPR = hasUseRequiringVGPR(Src2ReachingDefs, RewriteSet);
2545 Src2NeedsVGPRCache[&
MI] = Src2NeedsVGPR;
2547 for (SlotIndex RDIdx : Src2ReachingDefs) {
2548 MachineInstr *RD =
DAG.LIS->getInstructionFromIndex(RDIdx);
2549 if (!Src2NeedsVGPR &&
2556 MachineOperand &Dst =
MI.getOperand(0);
2559 findReachingUses(&
MI,
DAG.LIS, DstReachingUses);
2561 for (MachineOperand *RUOp : DstReachingUses) {
2562 MachineInstr *UserMI = RUOp->getParent();
2564 if (
TII->isMAI(*UserMI) && RewriteSet.
contains(UserMI))
2570 CopyForUse[UserMI->
getParent()].insert(RUOp->getReg());
2572 if (
TII->isMAI(*UserMI))
2576 findReachingDefs(*RUOp,
DAG.LIS, DstUsesReachingDefs);
2578 for (SlotIndex RDIndex : DstUsesReachingDefs) {
2579 MachineInstr *RD =
DAG.LIS->getInstructionFromIndex(RDIndex);
2580 if (
TII->isMAI(*RD))
2594 DAG.MRI.setRegClass(Dst.getReg(), ADefRC);
2595 if (
Src2->isReg()) {
2601 DAG.MRI.setRegClass(
Src2->getReg(), AUseRC);
2610int64_t RewriteMFMAFormStage::getRewriteCost(
2611 ArrayRef<std::pair<MachineInstr *, unsigned>> RewriteCands,
2612 const DenseMap<MachineBasicBlock *, std::set<Register>> &CopyForUse,
2613 const SmallPtrSetImpl<MachineInstr *> &CopyForDef) {
2614 MachineBlockFrequencyInfo *MBFI =
DAG.MBFI;
2616 int64_t BestSpillCost = 0;
2620 std::pair<unsigned, unsigned> MaxVectorRegs =
2621 ST.getMaxNumVectorRegs(
MF.getFunction());
2622 unsigned ArchVGPRThreshold = MaxVectorRegs.first;
2623 unsigned AGPRThreshold = MaxVectorRegs.second;
2624 unsigned CombinedThreshold =
ST.getMaxNumVGPRs(
MF);
2627 if (!RegionsWithExcessArchVGPR[Region])
2632 MF, ArchVGPRThreshold, AGPRThreshold, CombinedThreshold);
2640 MF, ArchVGPRThreshold, AGPRThreshold, CombinedThreshold);
2646 bool RelativeFreqIsDenom = EntryFreq > BlockFreq;
2647 uint64_t RelativeFreq = EntryFreq && BlockFreq
2648 ? (RelativeFreqIsDenom ? EntryFreq / BlockFreq
2649 : BlockFreq / EntryFreq)
2654 int64_t SpillCost = ((int)SpillCostAfter - (int)SpillCostBefore) * 2;
2657 if (RelativeFreqIsDenom)
2658 SpillCost /= (int64_t)RelativeFreq;
2660 SpillCost *= (int64_t)RelativeFreq;
2663 if (SpillCost > 0) {
2664 resetRewriteCandsToVGPR(RewriteCands);
2668 if (SpillCost < BestSpillCost)
2669 BestSpillCost = SpillCost;
2674 Cost = BestSpillCost;
2677 unsigned CopyCost = 0;
2681 for (MachineInstr *
DefMI : CopyForDef) {
2693 for (
auto &[UseBlock, UseRegs] : CopyForUse) {
2707 resetRewriteCandsToVGPR(RewriteCands);
2709 return Cost + CopyCost;
2712bool RewriteMFMAFormStage::rewrite(
2713 ArrayRef<std::pair<MachineInstr *, unsigned>> RewriteCands) {
2714 DenseMap<MachineInstr *, unsigned> FirstMIToRegion;
2715 DenseMap<MachineInstr *, unsigned> LastMIToRegion;
2723 if (
Entry.second !=
Entry.first->getParent()->end())
2766 DenseSet<Register> RewriteRegs;
2769 DenseMap<Register, Register> RedefMap;
2771 DenseMap<Register, DenseSet<MachineOperand *>>
ReplaceMap;
2773 DenseMap<Register, SmallPtrSet<MachineInstr *, 8>> ReachingDefCopyMap;
2776 DenseMap<unsigned, DenseMap<Register, SmallPtrSet<MachineOperand *, 8>>>
2781 SmallPtrSet<MachineInstr *, 16> RewriteCandsSet;
2782 DenseSet<Register> RewriteSrc2Regs;
2783 for (
auto &[
MI, OriginalOpcode] : RewriteCands) {
2785 MachineOperand *
Src2 =
TII->getNamedOperand(*
MI, AMDGPU::OpName::src2);
2786 if (Src2 &&
Src2->isReg())
2790 for (
auto &[
MI, OriginalOpcode] : RewriteCands) {
2792 if (ReplacementOp == -1)
2794 MI->setDesc(
TII->get(ReplacementOp));
2797 MachineOperand *
Src2 =
TII->getNamedOperand(*
MI, AMDGPU::OpName::src2);
2798 if (
Src2->isReg()) {
2805 findReachingDefs(*Src2,
DAG.LIS, Src2ReachingDefs);
2806 SmallSetVector<MachineInstr *, 8> Src2DefsReplace;
2810 bool Src2NeedsVGPR = Src2NeedsVGPRCache.lookup(
MI);
2812 for (SlotIndex RDIndex : Src2ReachingDefs) {
2813 MachineInstr *RD =
DAG.LIS->getInstructionFromIndex(RDIndex);
2814 if (!Src2NeedsVGPR &&
2818 Src2DefsReplace.
insert(RD);
2821 if (!Src2DefsReplace.
empty()) {
2822 auto RI = RedefMap.
find(Src2Reg);
2823 if (RI != RedefMap.
end()) {
2824 MappedReg = RI->second;
2829 SRI->getEquivalentVGPRClass(Src2RC);
2832 MappedReg =
DAG.MRI.createVirtualRegister(VGPRRC);
2833 RedefMap[Src2Reg] = MappedReg;
2838 for (MachineInstr *RD : Src2DefsReplace) {
2840 if (ReachingDefCopyMap[Src2Reg].insert(RD).second) {
2841 MachineInstrBuilder VGPRCopy =
2844 .
addDef(MappedReg, {}, 0)
2845 .addUse(Src2Reg, {}, 0);
2846 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
2851 unsigned UpdateRegion = LastMIToRegion[RD];
2852 DAG.Regions[UpdateRegion].second = VGPRCopy;
2853 LastMIToRegion.
erase(RD);
2860 RewriteRegs.
insert(Src2Reg);
2870 MachineOperand *Dst = &
MI->getOperand(0);
2879 SmallVector<MachineInstr *, 8> DstUseDefsReplace;
2881 findReachingUses(
MI,
DAG.LIS, DstReachingUses);
2883 for (MachineOperand *RUOp : DstReachingUses) {
2884 MachineInstr *UserMI = RUOp->
getParent();
2886 if (
TII->isMAI(*UserMI) && RewriteCandsSet.
contains(UserMI))
2890 if (
find(DstReachingUseCopies, RUOp) == DstReachingUseCopies.
end())
2894 if (
TII->isMAI(*UserMI))
2898 findReachingDefs(*RUOp,
DAG.LIS, DstUsesReachingDefs);
2900 for (SlotIndex RDIndex : DstUsesReachingDefs) {
2901 MachineInstr *RD =
DAG.LIS->getInstructionFromIndex(RDIndex);
2902 if (
TII->isMAI(*RD))
2907 if (
find(DstUseDefsReplace, RD) == DstUseDefsReplace.
end())
2912 if (!DstUseDefsReplace.
empty()) {
2913 auto RI = RedefMap.
find(DstReg);
2914 if (RI != RedefMap.
end()) {
2915 MappedReg = RI->second;
2922 MappedReg =
DAG.MRI.createVirtualRegister(VGPRRC);
2923 RedefMap[DstReg] = MappedReg;
2928 for (MachineInstr *RD : DstUseDefsReplace) {
2930 if (ReachingDefCopyMap[DstReg].insert(RD).second) {
2931 MachineInstrBuilder VGPRCopy =
2934 .
addDef(MappedReg, {}, 0)
2935 .addUse(DstReg, {}, 0);
2936 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
2940 auto LMI = LastMIToRegion.
find(RD);
2941 if (LMI != LastMIToRegion.
end()) {
2942 unsigned UpdateRegion = LMI->second;
2943 DAG.Regions[UpdateRegion].second = VGPRCopy;
2944 LastMIToRegion.
erase(RD);
2950 DenseSet<MachineOperand *> &DstRegSet =
ReplaceMap[DstReg];
2953 MachineInstr *EarliestSameBlockUse =
nullptr;
2954 for (MachineOperand *RU : DstReachingUseCopies) {
2955 MachineBasicBlock *RUBlock = RU->getParent()->getParent();
2958 if (RUBlock !=
MI->getParent()) {
2964 if (!SameBlockCopyReg.
isValid()) {
2967 SameBlockCopyReg =
DAG.MRI.createVirtualRegister(VGPRRC);
2971 MachineInstr *UseInst = RU->getParent();
2972 if (!EarliestSameBlockUse ||
2974 DAG.LIS->getInstructionIndex(*UseInst),
2975 DAG.LIS->getInstructionIndex(*EarliestSameBlockUse)))
2976 EarliestSameBlockUse = UseInst;
2977 RU->setReg(SameBlockCopyReg);
2981 if (SameBlockCopyReg.
isValid()) {
2982 MachineInstrBuilder VGPRCopy =
2985 TII->get(TargetOpcode::COPY), SameBlockCopyReg)
2987 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
2992 RewriteRegs.
insert(DstReg);
3002 std::pair<unsigned, DenseMap<Register, SmallPtrSet<MachineOperand *, 8>>>;
3003 for (RUBType RUBlockEntry : ReachingUseTracker) {
3004 using RUDType = std::pair<Register, SmallPtrSet<MachineOperand *, 8>>;
3005 for (RUDType RUDst : RUBlockEntry.second) {
3006 MachineOperand *OpBegin = *RUDst.second.begin();
3007 SlotIndex InstPt =
DAG.LIS->getInstructionIndex(*OpBegin->
getParent());
3010 for (MachineOperand *User : RUDst.second) {
3011 SlotIndex NewInstPt =
DAG.LIS->getInstructionIndex(*
User->getParent());
3018 Register NewUseReg =
DAG.MRI.createVirtualRegister(VGPRRC);
3019 MachineInstr *UseInst =
DAG.LIS->getInstructionFromIndex(InstPt);
3021 MachineInstrBuilder VGPRCopy =
3024 .
addDef(NewUseReg, {}, 0)
3025 .addUse(RUDst.first, {}, 0);
3026 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
3030 auto FI = FirstMIToRegion.
find(UseInst);
3031 if (FI != FirstMIToRegion.
end()) {
3032 unsigned UpdateRegion = FI->second;
3033 DAG.Regions[UpdateRegion].first = VGPRCopy;
3034 FirstMIToRegion.
erase(UseInst);
3038 for (MachineOperand *User : RUDst.second) {
3039 User->setReg(NewUseReg);
3050 for (std::pair<Register, Register> NewDef : RedefMap) {
3055 for (MachineOperand *ReplaceOp :
ReplaceMap[OldReg])
3056 ReplaceOp->setReg(NewReg);
3060 for (
Register RewriteReg : RewriteRegs) {
3061 Register RegToRewrite = RewriteReg;
3064 auto RI = RedefMap.find(RewriteReg);
3065 if (RI != RedefMap.end())
3066 RegToRewrite = RI->second;
3071 DAG.MRI.setRegClass(RegToRewrite, AGPRRC);
3075 DAG.LIS->reanalyze(
DAG.MF);
3077 RegionPressureMap LiveInUpdater(&
DAG,
false);
3078 LiveInUpdater.buildLiveRegMap();
3081 DAG.LiveIns[Region] = LiveInUpdater.getLiveRegsForRegionIdx(Region);
3088unsigned PreRARematStage::getStageTargetOccupancy()
const {
3089 return TargetOcc ? *TargetOcc :
MFI.getMinWavesPerEU();
3092bool PreRARematStage::setObjective() {
3096 unsigned MaxSGPRs =
ST.getMaxNumSGPRs(
F);
3097 unsigned MaxVGPRs =
ST.getMaxNumVGPRs(
F);
3098 bool HasVectorRegisterExcess =
false;
3099 for (
unsigned I = 0,
E =
DAG.Regions.size();
I !=
E; ++
I) {
3100 const GCNRegPressure &
RP =
DAG.Pressure[
I];
3101 GCNRPTarget &
Target = RPTargets.emplace_back(MaxSGPRs, MaxVGPRs,
MF, RP);
3103 TargetRegions.set(
I);
3104 HasVectorRegisterExcess |=
Target.hasVectorRegisterExcess();
3107 if (HasVectorRegisterExcess ||
DAG.MinOccupancy >=
MFI.getMaxWavesPerEU()) {
3110 TargetOcc = std::nullopt;
3114 TargetOcc =
DAG.MinOccupancy + 1;
3115 const unsigned VGPRBlockSize =
MFI.getDynamicVGPRBlockSize();
3116 MaxSGPRs =
ST.getMaxNumSGPRs(*TargetOcc,
false);
3117 MaxVGPRs =
ST.getMaxNumVGPRs(*TargetOcc, VGPRBlockSize);
3118 for (
auto [
I, Target] :
enumerate(RPTargets)) {
3119 Target.setTarget(MaxSGPRs, MaxVGPRs);
3121 TargetRegions.set(
I);
3125 return TargetRegions.any();
3128bool PreRARematStage::ScoredRemat::maybeBeneficial(
3130 for (
unsigned I : TargetRegions.set_bits()) {
3131 if (Live[
I] && RPTargets[
I].isSaveBeneficial(RPSave))
3144 const unsigned NumRegions =
DAG.Regions.size();
3148 for (
unsigned I = 0;
I < NumRegions; ++
I) {
3152 if (BlockFreq && BlockFreq <
MinFreq)
3161 if (
MinFreq >= ScaleFactor * ScaleFactor) {
3162 for (uint64_t &Freq :
Regions)
3163 Freq /= ScaleFactor;
3169void PreRARematStage::ScoredRemat::init(
const FreqInfo &Freq,
3174 assert(Reg.Uses.size() == 1 &&
"expected users in single region");
3175 const unsigned UseRegion = Reg.Uses.begin()->first;
3180 for (
unsigned I : Live.set_bits()) {
3183 if (!LiveIn[
I] || !LiveOut[
I] ||
I == UseRegion)
3184 UnpredictableRPSave.set(
I);
3191 int64_t DefOrMin = std::max(Freq.
Regions[Reg.DefRegion], Freq.
MinFreq);
3192 int64_t UseOrMax = Freq.
Regions[UseRegion];
3195 FreqDiff = DefOrMin - UseOrMax;
3198void PreRARematStage::ScoredRemat::update(
const BitVector &TargetRegions,
3200 const FreqInfo &FreqInfo,
3204 for (
unsigned I : TargetRegions.
set_bits()) {
3213 if (!NumRegsBenefit)
3217 RegionImpact += (UnpredictableRPSave[
I] ? 1 : 2) * NumRegsBenefit;
3220 uint64_t Freq = FreqInfo.
Regions[
I];
3221 if (UnpredictableRPSave[
I]) {
3226 MaxFreq = std::max(MaxFreq, Freq);
3231void PreRARematStage::ScoredRemat::rematerialize(
3232 Rematerializer &Remater)
const {
3233 const Rematerializer::Reg &
Reg = Remater.getReg(RegIdx);
3234 Rematerializer::DependencyReuseInfo DRI;
3235 for (RegisterIdx DepRegIdx :
Reg.Dependencies)
3236 DRI.
reuse(DepRegIdx);
3237 unsigned UseRegion =
Reg.Uses.begin()->first;
3238 Remater.rematerializeToRegion(RegIdx, UseRegion, DRI);
3241void PreRARematStage::updateRPTargets(
const BitVector &Regions,
3242 const GCNRegPressure &RPSave) {
3244 RPTargets[
I].saveRP(RPSave);
3245 if (TargetRegions[
I] && RPTargets[
I].satisfied()) {
3247 TargetRegions.reset(
I);
3252bool PreRARematStage::updateAndVerifyRPTargets(
const BitVector &Regions) {
3253 bool TooOptimistic =
false;
3255 GCNRPTarget &
Target = RPTargets[
I];
3261 if (!TargetRegions[
I] && !
Target.satisfied()) {
3263 TooOptimistic =
true;
3264 TargetRegions.set(
I);
3267 return TooOptimistic;
3270void PreRARematStage::removeFromLiveMaps(
Register Reg,
const BitVector &LiveIn,
3271 const BitVector &LiveOut) {
3273 LiveOut.
size() ==
DAG.Regions.size() &&
"region num mismatch");
3277 DAG.RegionLiveOuts.getLiveRegsForRegionIdx(
I).erase(
Reg);
3280void PreRARematStage::addToLiveMaps(
Register Reg, LaneBitmask Mask,
3281 const BitVector &LiveIn,
3282 const BitVector &LiveOut) {
3284 LiveOut.
size() ==
DAG.Regions.size() &&
"region num mismatch");
3285 std::pair<Register, LaneBitmask> LiveReg(
Reg, Mask);
3287 DAG.LiveIns[
I].insert(LiveReg);
3289 DAG.RegionLiveOuts.getLiveRegsForRegionIdx(
I).insert(LiveReg);
3301 if (
DAG.MinOccupancy >= *TargetOcc)
3305 for (
const auto &[
RegionIdx, OrigMIOrder, MaxPressure] : RegionReverts) {
3315 if (AchievedOcc >= *TargetOcc) {
3316 DAG.setTargetOccupancy(AchievedOcc);
3321 DAG.setTargetOccupancy(*TargetOcc - 1);
3326 assert(Rollback &&
"rollbacker should be defined");
3327 Rollback->Listener.rollback(Remater);
3328 for (
const auto &[RegIdx, LiveIn, LiveOut] : Rollback->LiveMapUpdates) {
3329 const Rematerializer::Reg &
Reg = Remater.getReg(RegIdx);
3330 addToLiveMaps(
Reg.getDefReg(),
Reg.Mask, LiveIn, LiveOut);
3333#ifdef EXPENSIVE_CHECKS
3338 for (
unsigned I : RescheduleRegions.set_bits())
3339 DAG.Pressure[
I] =
DAG.getRealRegPressure(
I);
3344void GCNScheduleDAGMILive::setTargetOccupancy(
unsigned TargetOccupancy) {
3345 MinOccupancy = TargetOccupancy;
3346 if (
MFI.getOccupancy() < TargetOccupancy)
3347 MFI.increaseOccupancy(
MF, MinOccupancy);
3349 MFI.limitOccupancy(MinOccupancy);
3366 if (HasIGLPInstrs) {
3367 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
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.
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
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
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.
GCNRPTracker::LiveRegSet & getLiveRegsForRegionIdx(unsigned RegionIdx)
static LLVM_ABI void restoreLivenessFlags(MachineInstr &MI, const TargetRegisterInfo &TRI, const MachineRegisterInfo &MRI, LiveIntervals &LIS, bool TrackLaneMasks=true, ArrayRef< Register > OnlyRegs={})
Clear potentially-stale read-undef flags on the defs of MI, then recompute them from LIS.
Wrapper class representing virtual and physical registers.
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.
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.
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 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)
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
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.
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)