46#define DEBUG_TYPE "machine-scheduler"
51 "amdgpu-disable-unclustered-high-rp-reschedule",
cl::Hidden,
52 cl::desc(
"Disable unclustered high register pressure "
53 "reduction scheduling stage."),
57 "amdgpu-disable-clustered-low-occupancy-reschedule",
cl::Hidden,
58 cl::desc(
"Disable clustered low occupancy "
59 "rescheduling for ILP scheduling stage."),
65 "Sets the bias which adds weight to occupancy vs latency. Set it to "
66 "100 to chase the occupancy only."),
71 cl::desc(
"Relax occupancy targets for kernels which are memory "
72 "bound (amdgpu-membound-threshold), or "
73 "Wave Limited (amdgpu-limit-wave-threshold)."),
78 cl::desc(
"Use the AMDGPU specific RPTrackers during scheduling"),
82 "amdgpu-scheduler-pending-queue-limit",
cl::Hidden,
84 "Max (Available+Pending) size to inspect pending queue (0 disables)"),
87#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
88#define DUMP_MAX_REG_PRESSURE
90 "amdgpu-print-max-reg-pressure-regusage-before-scheduler",
cl::Hidden,
91 cl::desc(
"Print a list of live registers along with their def/uses at the "
92 "point of maximum register pressure before scheduling."),
96 "amdgpu-print-max-reg-pressure-regusage-after-scheduler",
cl::Hidden,
97 cl::desc(
"Print a list of live registers along with their def/uses at the "
98 "point of maximum register pressure after scheduling."),
103 "amdgpu-disable-rewrite-mfma-form-sched-stage",
cl::Hidden,
109 return O.error(
"'" + Arg +
"' value invalid for uint argument!");
112 return O.error(
"'" + Arg +
"' value must be in the range [0, 100]!");
119 cl::desc(
"Percent of VGPR limits that we should use as RP threshold "
120 "during scheduling. We have two limits relevant to scheduling: "
121 "Critical (avoid decreasing occupancy), Excess (avoid spilling). "
122 "This flag scales both limits back by an equal percent: (0 = use "
123 " default calculation, 1-100 = use percentage), default: 0"),
144 Context->RegClassInfo->getNumAllocatableRegs(&AMDGPU::SGPR_32RegClass);
146 Context->RegClassInfo->getNumAllocatableRegs(&AMDGPU::VGPR_32RegClass);
148 Context->RegClassInfo->getNumAllocatableRegs(&AMDGPU::AGPR_32RegClass);
170 "VGPRCriticalLimit calculation method.\n");
174 unsigned Addressable =
177 VGPRBudget = std::max(VGPRBudget, Granule);
193 <<
". VGPRCriticalLimit: " << OriginalVGPRCriticalLimit
239 if (!
Op.isReg() ||
Op.isImplicit())
241 if (
Op.getReg().isPhysical() ||
242 (
Op.isDef() &&
Op.getSubReg() != AMDGPU::NoSubRegister))
277 Pressure[AMDGPU::RegisterPressureSets::VGPR_32] =
286 unsigned SGPRPressure,
287 unsigned VGPRPressure,
288 unsigned AGPRPressure,
bool IsBottomUp) {
292 if (!
DAG->isTrackingPressure())
315 Pressure[AMDGPU::RegisterPressureSets::SReg_32] = SGPRPressure;
316 Pressure[AMDGPU::RegisterPressureSets::VGPR_32] = VGPRPressure;
317 Pressure[AMDGPU::RegisterPressureSets::AGPR_32] = AGPRPressure;
319 for (
const auto &Diff :
DAG->getPressureDiff(SU)) {
325 (IsBottomUp ? Diff.getUnitInc() : -Diff.getUnitInc());
328#ifdef EXPENSIVE_CHECKS
329 std::vector<unsigned> CheckPressure, CheckMaxPressure;
332 if (
Pressure[AMDGPU::RegisterPressureSets::SReg_32] !=
333 CheckPressure[AMDGPU::RegisterPressureSets::SReg_32] ||
334 Pressure[AMDGPU::RegisterPressureSets::VGPR_32] !=
335 CheckPressure[AMDGPU::RegisterPressureSets::VGPR_32] ||
336 Pressure[AMDGPU::RegisterPressureSets::AGPR_32] !=
337 CheckPressure[AMDGPU::RegisterPressureSets::AGPR_32]) {
338 errs() <<
"Register Pressure is inaccurate when calculated through "
340 <<
"SGPR got " <<
Pressure[AMDGPU::RegisterPressureSets::SReg_32]
342 << CheckPressure[AMDGPU::RegisterPressureSets::SReg_32] <<
"\n"
343 <<
"VGPR got " <<
Pressure[AMDGPU::RegisterPressureSets::VGPR_32]
345 << CheckPressure[AMDGPU::RegisterPressureSets::VGPR_32] <<
"\n"
346 <<
"AGPR got " <<
Pressure[AMDGPU::RegisterPressureSets::AGPR_32]
348 << CheckPressure[AMDGPU::RegisterPressureSets::AGPR_32] <<
"\n";
354 unsigned NewAGPRPressure =
Pressure[AMDGPU::RegisterPressureSets::AGPR_32];
355 unsigned NewSGPRPressure =
Pressure[AMDGPU::RegisterPressureSets::SReg_32];
356 unsigned NewVGPRPressure =
Pressure[AMDGPU::RegisterPressureSets::VGPR_32];
366 const unsigned MaxVGPRPressureInc = 16;
367 bool ShouldTrackVGPRs = VGPRPressure + MaxVGPRPressureInc >=
VGPRExcessLimit;
370 bool ShouldTrackSGPRs =
371 !ShouldTrackVGPRs && !ShouldTrackAGPRs && SGPRPressure >=
SGPRExcessLimit;
406 : std::numeric_limits<int>::min();
408 if (SGPRDelta >= 0 || VGPRDelta >= 0 || AGPRDelta >= 0) {
411 if (VGPRDelta >= SGPRDelta && VGPRDelta >= AGPRDelta) {
415 }
else if (AGPRDelta >= SGPRDelta) {
429 bool HasBufferedModel =
448 dbgs() <<
"Prefer:\t\t";
449 DAG->dumpNode(*Preferred.
SU);
453 DAG->dumpNode(*Current.
SU);
456 dbgs() <<
"Reason:\t\t";
470 unsigned SGPRPressure = 0;
471 unsigned VGPRPressure = 0;
472 unsigned AGPRPressure = 0;
474 if (
DAG->isTrackingPressure()) {
476 SGPRPressure =
Pressure[AMDGPU::RegisterPressureSets::SReg_32];
477 VGPRPressure =
Pressure[AMDGPU::RegisterPressureSets::VGPR_32];
478 AGPRPressure =
Pressure[AMDGPU::RegisterPressureSets::AGPR_32];
483 SGPRPressure =
T->getPressure().getSGPRNum();
484 VGPRPressure =
T->getPressure().getArchVGPRNum();
485 AGPRPressure =
T->getPressure().getAGPRNum();
490 for (
SUnit *SU : AQ) {
494 VGPRPressure, AGPRPressure, IsBottomUp);
514 for (
SUnit *SU : PQ) {
518 VGPRPressure, AGPRPressure, IsBottomUp);
538 bool &PickedPending) {
558 bool BotPending =
false;
578 "Last pick result should correspond to re-picking right now");
583 bool TopPending =
false;
603 "Last pick result should correspond to re-picking right now");
613 PickedPending = BotPending && TopPending;
616 if (BotPending || TopPending) {
623 Cand.setBest(TryCand);
628 IsTopNode = Cand.AtTop;
635 if (
DAG->top() ==
DAG->bottom()) {
637 Bot.Available.empty() &&
Bot.Pending.empty() &&
"ReadyQ garbage");
643 PickedPending =
false;
677 if (ReadyCycle > CurrentCycle)
749 if (
DAG->isTrackingPressure() &&
755 if (
DAG->isTrackingPressure() &&
760 bool SameBoundary = Zone !=
nullptr;
784 if (IsLegacyScheduler)
803 if (
DAG->isTrackingPressure() &&
813 bool SameBoundary = Zone !=
nullptr;
848 bool CandIsClusterSucc =
850 bool TryCandIsClusterSucc =
852 if (
tryGreater(TryCandIsClusterSucc, CandIsClusterSucc, TryCand, Cand,
857 if (
DAG->isTrackingPressure() &&
863 if (
DAG->isTrackingPressure() &&
909 if (
DAG->isTrackingPressure()) {
925 bool CandIsClusterSucc =
927 bool TryCandIsClusterSucc =
929 if (
tryGreater(TryCandIsClusterSucc, CandIsClusterSucc, TryCand, Cand,
938 bool SameBoundary = Zone !=
nullptr;
955 if (TryMayLoad || CandMayLoad) {
956 bool TryLongLatency =
958 bool CandLongLatency =
962 Zone->
isTop() ? CandLongLatency : TryLongLatency, TryCand,
980 if (
DAG->isTrackingPressure() &&
999 !
Rem.IsAcyclicLatencyLimited &&
tryLatency(TryCand, Cand, *Zone))
1017 StartingOccupancy(MFI.getOccupancy()), MinOccupancy(StartingOccupancy),
1018 RegionLiveOuts(this,
true) {
1024 LLVM_DEBUG(
dbgs() <<
"Starting occupancy is " << StartingOccupancy <<
".\n");
1026 MinOccupancy = std::min(MFI.getMinAllowedOccupancy(), StartingOccupancy);
1027 if (MinOccupancy != StartingOccupancy)
1028 LLVM_DEBUG(
dbgs() <<
"Allowing Occupancy drops to " << MinOccupancy
1033std::unique_ptr<GCNSchedStage>
1035 switch (SchedStageID) {
1037 return std::make_unique<OccInitialScheduleStage>(SchedStageID, *
this);
1039 return std::make_unique<RewriteMFMAFormStage>(SchedStageID, *
this);
1041 return std::make_unique<UnclusteredHighRPStage>(SchedStageID, *
this);
1043 return std::make_unique<ClusteredLowOccStage>(SchedStageID, *
this);
1045 return std::make_unique<PreRARematStage>(SchedStageID, *
this);
1047 return std::make_unique<ILPInitialScheduleStage>(SchedStageID, *
this);
1049 return std::make_unique<MemoryClauseInitialScheduleStage>(SchedStageID,
1052 return std::make_unique<LiveIntervalRPStage>(SchedStageID, *
this);
1065GCNScheduleDAGMILive::getRealRegPressure(
unsigned RegionIdx)
const {
1066 if (Regions[RegionIdx].first == Regions[RegionIdx].second)
1070 &LiveIns[RegionIdx]);
1076 assert(RegionBegin != RegionEnd &&
"Region must not be empty");
1080void GCNScheduleDAGMILive::computeBlockPressure(
unsigned RegionIdx,
1092 const MachineBasicBlock *OnlySucc =
nullptr;
1095 if (!Candidate->empty() && Candidate->pred_size() == 1) {
1096 SlotIndexes *Ind =
LIS->getSlotIndexes();
1098 OnlySucc = Candidate;
1103 size_t CurRegion = RegionIdx;
1104 for (
size_t E = Regions.size(); CurRegion !=
E; ++CurRegion)
1105 if (Regions[CurRegion].first->getParent() !=
MBB)
1110 auto LiveInIt = MBBLiveIns.find(
MBB);
1111 auto &Rgn = Regions[CurRegion];
1113 if (LiveInIt != MBBLiveIns.end()) {
1114 auto LiveIn = std::move(LiveInIt->second);
1116 MBBLiveIns.erase(LiveInIt);
1119 auto LRS = BBLiveInMap.lookup(NonDbgMI);
1120#ifdef EXPENSIVE_CHECKS
1129 if (Regions[CurRegion].first ==
I || NonDbgMI ==
I) {
1130 LiveIns[CurRegion] =
RPTracker.getLiveRegs();
1134 if (Regions[CurRegion].second ==
I) {
1135 Pressure[CurRegion] =
RPTracker.moveMaxPressure();
1136 if (CurRegion-- == RegionIdx)
1138 auto &Rgn = Regions[CurRegion];
1151 MBBLiveIns[OnlySucc] =
RPTracker.moveLiveRegs();
1156GCNScheduleDAGMILive::getRegionLiveInMap()
const {
1157 assert(!Regions.empty());
1158 std::vector<MachineInstr *> RegionFirstMIs;
1159 RegionFirstMIs.reserve(Regions.size());
1161 RegionFirstMIs.push_back(
1168GCNScheduleDAGMILive::getRegionLiveOutMap()
const {
1169 assert(!Regions.empty());
1170 std::vector<MachineInstr *> RegionLastMIs;
1171 RegionLastMIs.reserve(Regions.size());
1182 IdxToInstruction.clear();
1185 IsLiveOut ? DAG->getRegionLiveOutMap() : DAG->getRegionLiveInMap();
1186 for (
unsigned I = 0;
I < DAG->Regions.size();
I++) {
1187 auto &[RegionBegin, RegionEnd] = DAG->Regions[
I];
1189 if (RegionBegin == RegionEnd)
1193 IdxToInstruction[
I] = RegionKey;
1201 LiveIns.resize(Regions.size());
1202 Pressure.resize(Regions.size());
1203 RegionsWithHighRP.resize(Regions.size());
1204 RegionsWithExcessRP.resize(Regions.size());
1205 RegionsWithIGLPInstrs.resize(Regions.size());
1206 RegionsWithHighRP.reset();
1207 RegionsWithExcessRP.reset();
1208 RegionsWithIGLPInstrs.reset();
1213void GCNScheduleDAGMILive::runSchedStages() {
1214 LLVM_DEBUG(
dbgs() <<
"All regions recorded, starting actual scheduling.\n");
1217 if (!Regions.
empty()) {
1218 BBLiveInMap = getRegionLiveInMap();
1223#ifdef DUMP_MAX_REG_PRESSURE
1233 if (!Stage->initGCNSchedStage())
1236 for (
auto Region : Regions) {
1240 if (!Stage->initGCNRegion()) {
1241 Stage->advanceRegion();
1247 const unsigned RegionIdx = Stage->getRegionIdx();
1250 MRI, RegionLiveOuts.getLiveRegsForRegionIdx(RegionIdx));
1254 Stage->finalizeGCNRegion();
1255 Stage->advanceRegion();
1259 Stage->finalizeGCNSchedStage();
1262#ifdef DUMP_MAX_REG_PRESSURE
1275 OS <<
"Max Occupancy Initial Schedule";
1278 OS <<
"Instruction Rewriting Reschedule";
1281 OS <<
"Unclustered High Register Pressure Reschedule";
1284 OS <<
"Clustered Low Occupancy Reschedule";
1287 OS <<
"Pre-RA Rematerialize";
1290 OS <<
"Max ILP Initial Schedule";
1293 OS <<
"Max memory clause Initial Schedule";
1296 OS <<
"Live Interval RP Reschedule";
1316void RewriteMFMAFormStage::findReachingDefs(
1338 while (!Worklist.
empty()) {
1353 for (MachineBasicBlock *PredMBB : DefMBB->
predecessors()) {
1354 if (Visited.
insert(PredMBB).second)
1360void RewriteMFMAFormStage::findReachingUses(
1364 for (MachineOperand &UseMO :
1367 findReachingDefs(UseMO, LIS, ReachingDefIndexes);
1371 if (
any_of(ReachingDefIndexes, [DefIdx](SlotIndex RDIdx) {
1383 if (!
ST.hasGFX90AInsts() ||
MFI.getMinWavesPerEU() > 1)
1386 RegionsWithExcessArchVGPR.resize(
DAG.Regions.size());
1387 RegionsWithExcessArchVGPR.reset();
1391 RegionsWithExcessArchVGPR[
Region] =
true;
1394 if (RegionsWithExcessArchVGPR.none())
1397 TII =
ST.getInstrInfo();
1398 SRI =
ST.getRegisterInfo();
1400 std::vector<std::pair<MachineInstr *, unsigned>> RewriteCands;
1404 if (!initHeuristics(RewriteCands, CopyForUse, CopyForDef))
1407 int64_t
Cost = getRewriteCost(RewriteCands, CopyForUse, CopyForDef);
1414 return rewrite(RewriteCands);
1424 if (
DAG.RegionsWithHighRP.none() &&
DAG.RegionsWithExcessRP.none())
1431 InitialOccupancy =
DAG.MinOccupancy;
1434 TempTargetOccupancy =
MFI.getMaxWavesPerEU() >
DAG.MinOccupancy
1435 ? InitialOccupancy + 1
1437 IsAnyRegionScheduled =
false;
1438 S.SGPRLimitBias =
S.HighRPSGPRBias;
1439 S.VGPRLimitBias =
S.HighRPVGPRBias;
1443 <<
"Retrying function scheduling without clustering. "
1444 "Aggressively try to reduce register pressure to achieve occupancy "
1445 << TempTargetOccupancy <<
".\n");
1460 if (
DAG.StartingOccupancy <=
DAG.MinOccupancy)
1464 dbgs() <<
"Retrying function scheduling with lowest recorded occupancy "
1465 <<
DAG.MinOccupancy <<
".\n");
1470#define REMAT_PREFIX "[PreRARemat] "
1471#define REMAT_DEBUG(X) LLVM_DEBUG(dbgs() << REMAT_PREFIX; X;)
1473#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
1474Printable PreRARematStage::ScoredRemat::print()
const {
1476 OS <<
'(' << MaxFreq <<
", " << FreqDiff <<
", " << RegionImpact <<
')';
1491 auto PrintTargetRegions = [&]() ->
void {
1492 if (TargetRegions.none()) {
1497 for (
unsigned I : TargetRegions.set_bits())
1504 dbgs() <<
"Analyzing ";
1505 MF.getFunction().printAsOperand(
dbgs(),
false);
1508 if (!setObjective()) {
1509 LLVM_DEBUG(
dbgs() <<
"no objective to achieve, occupancy is maximal at "
1510 <<
MFI.getMaxWavesPerEU() <<
'\n');
1515 dbgs() <<
"increase occupancy from " << *TargetOcc - 1 <<
'\n';
1517 dbgs() <<
"reduce spilling (minimum target occupancy is "
1518 <<
MFI.getMinWavesPerEU() <<
")\n";
1520 PrintTargetRegions();
1525 DAG.RegionLiveOuts.buildLiveRegMap();
1527 if (!Remater.analyze()) {
1543 DefRegToCandIdx.
resize(
DAG.MRI.getNumVirtRegs());
1544 const unsigned NumRegions =
DAG.Regions.size();
1546 for (
unsigned RegIdx = 0, E = Remater.getNumRegs(); RegIdx < E; ++RegIdx) {
1550 if (CandReg.
Uses.size() != 1)
1552 const auto [UseRegion,
Users] = *CandReg.
Uses.begin();
1571 "user must have at least one operand");
1578 assert(FirstUseMI &&
"there must be a user in the region");
1580 DAG.LIS->getInstructionIndex(*FirstUseMI).getRegSlot(
true);
1582 DAG.LIS->getInstructionIndex(*CandReg.
getLastDef()).getRegSlot(
true);
1584 const Rematerializer::Reg &DepReg = Remater.getReg(DepRegIdx);
1585 Register DepDefReg = DepReg.getDefReg();
1586 return MarkedRegs.contains(DepDefReg) ||
1587 !Remater.isRegIdenticalAtUses(DepDefReg, DepReg.Mask, RefIdx,
1592 [&](
const std::pair<Register, LaneBitmask> &RegAndMask) {
1593 const auto &[Reg, Mask] = RegAndMask;
1594 return !Remater.isRegIdenticalAtUses(Reg, Mask, RefIdx,
1599 Register DefReg = CandReg.getDefReg();
1600 MarkedRegs.
insert(DefReg);
1601 DefRegToCandIdx[DefReg] = 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] :
1621 unsigned CandIdx = DefRegToCandIdx[
Reg];
1623 Candidates[CandIdx].LiveOut.set(
I);
1628 SmallVector<unsigned> CandidateOrder;
1629 for (
auto [CandIdx, Cand] :
enumerate(Candidates)) {
1630 Cand.init(FreqInfo, Remater,
DAG);
1631 Cand.update(TargetRegions, RPTargets, FreqInfo, !TargetOcc);
1632 if (!Cand.hasNullScore())
1643 Rollback = std::make_unique<RollbackSupport>(Remater);
1648 BitVector RecomputeRP(
DAG.Regions.size());
1650 RecomputeRP.reset();
1653 sort(CandidateOrder, [&](
unsigned LHSIndex,
unsigned 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()];
1673 const Rematerializer::Reg &
Reg = Remater.getReg(Cand.RegIdx);
1681 if (!Cand.maybeBeneficial(TargetRegions, RPTargets)) {
1683 << Cand.print() <<
" | "
1684 << Remater.printRematReg(Cand.RegIdx));
1689#ifdef EXPENSIVE_CHECKS
1692 for (
const MachineInstr *
DefMI :
Reg.Defs) {
1697 if (!MO.isReg() || !MO.getReg() || !MO.readsReg() || MO.isDef())
1704 LiveInterval &LI =
DAG.LIS->getInterval(
UseReg);
1705 LaneBitmask LM =
DAG.MRI.getMaxLaneMaskForVReg(MO.getReg());
1707 LM =
DAG.TRI->getSubRegIndexLaneMask(MO.getSubReg());
1709 const unsigned UseRegion =
Reg.Uses.begin()->first;
1710 LaneBitmask LiveInMask =
DAG.LiveIns[UseRegion].at(
UseReg);
1711 LaneBitmask UncoveredLanes = LM & ~(LiveInMask & LM);
1715 if (UncoveredLanes.
any()) {
1717 for (LiveInterval::SubRange &SR : LI.
subranges())
1718 assert((SR.LaneMask & UncoveredLanes).none());
1726 REMAT_DEBUG(
dbgs() <<
"** REMAT " << Remater.printRematReg(Cand.RegIdx)
1728 removeFromLiveMaps(
Reg.getDefReg(), Cand.LiveIn, Cand.LiveOut);
1730 Rollback->LiveMapUpdates.emplace_back(Cand.RegIdx, Cand.LiveIn,
1733 Cand.rematerialize(Remater);
1738 updateRPTargets(Cand.Live, Cand.RPSave);
1739 RecomputeRP |= Cand.UnpredictableRPSave;
1740 RescheduleRegions |= Cand.Live;
1741 if (!TargetRegions.any()) {
1747 if (!updateAndVerifyRPTargets(RecomputeRP) && !TargetRegions.any()) {
1756 unsigned NumUsefulCandidates = 0;
1757 for (
unsigned CandIdx : CandidateOrder) {
1758 ScoredRemat &Candidate = Candidates[CandIdx];
1759 Candidate.update(TargetRegions, RPTargets, FreqInfo, !TargetOcc);
1760 if (!Candidate.hasNullScore())
1761 CandidateOrder[NumUsefulCandidates++] = CandIdx;
1763 if (NumUsefulCandidates == 0) {
1764 REMAT_DEBUG(
dbgs() <<
"Stop on exhausted rematerialization candidates\n");
1767 CandidateOrder.truncate(NumUsefulCandidates);
1770 if (RescheduleRegions.none())
1776 unsigned DynamicVGPRBlockSize =
MFI.getDynamicVGPRBlockSize();
1777 for (
unsigned I : RescheduleRegions.set_bits()) {
1778 DAG.Pressure[
I] = RPTargets[
I].getCurrentRP();
1780 <<
DAG.Pressure[
I].getOccupancy(
ST, DynamicVGPRBlockSize)
1781 <<
" (" << RPTargets[
I] <<
")\n");
1783 AchievedOcc =
MFI.getMaxWavesPerEU();
1784 for (
const GCNRegPressure &RP :
DAG.Pressure) {
1786 std::min(AchievedOcc,
RP.getOccupancy(
ST, DynamicVGPRBlockSize));
1790 dbgs() <<
"Retrying function scheduling with new min. occupancy of "
1791 << AchievedOcc <<
" from rematerializing (original was "
1792 <<
DAG.MinOccupancy;
1794 dbgs() <<
", target was " << *TargetOcc;
1798 DAG.setTargetOccupancy(getStageTargetOccupancy());
1809 S.SGPRLimitBias =
S.VGPRLimitBias = 0;
1810 if (
DAG.MinOccupancy > InitialOccupancy) {
1811 assert(IsAnyRegionScheduled);
1813 <<
" stage successfully increased occupancy to "
1814 <<
DAG.MinOccupancy <<
'\n');
1815 }
else if (!IsAnyRegionScheduled) {
1816 assert(
DAG.MinOccupancy == InitialOccupancy);
1818 <<
": No regions scheduled, min occupancy stays at "
1819 <<
DAG.MinOccupancy <<
", MFI occupancy stays at "
1820 <<
MFI.getOccupancy() <<
".\n");
1828 if (
DAG.begin() ==
DAG.end())
1835 unsigned NumRegionInstrs = std::distance(
DAG.begin(),
DAG.end());
1839 if (
DAG.begin() == std::prev(
DAG.end()))
1845 <<
"\n From: " << *
DAG.begin() <<
" To: ";
1847 else dbgs() <<
"End";
1848 dbgs() <<
" RegionInstrs: " << NumRegionInstrs <<
'\n');
1856 for (
auto &
I :
DAG) {
1869 dbgs() <<
"Pressure before scheduling:\nRegion live-ins:"
1871 <<
"Region live-in pressure: "
1875 S.HasHighPressure =
false;
1897 unsigned DynamicVGPRBlockSize =
DAG.MFI.getDynamicVGPRBlockSize();
1900 unsigned CurrentTargetOccupancy =
1901 IsAnyRegionScheduled ?
DAG.MinOccupancy : TempTargetOccupancy;
1903 (CurrentTargetOccupancy <= InitialOccupancy ||
1904 DAG.Pressure[
RegionIdx].getOccupancy(
ST, DynamicVGPRBlockSize) !=
1911 if (!IsAnyRegionScheduled && IsSchedulingThisRegion) {
1912 IsAnyRegionScheduled =
true;
1913 if (
MFI.getMaxWavesPerEU() >
DAG.MinOccupancy)
1914 DAG.setTargetOccupancy(TempTargetOccupancy);
1916 return IsSchedulingThisRegion;
1932 return !RevertAllRegions && RescheduleRegions[
RegionIdx] &&
1952 if (
S.HasHighPressure)
1973 if (
DAG.MinOccupancy < *TargetOcc) {
1975 <<
" cannot meet occupancy target, interrupting "
1976 "re-scheduling in all regions\n");
1977 RevertAllRegions =
true;
1988 unsigned DynamicVGPRBlockSize =
DAG.MFI.getDynamicVGPRBlockSize();
1999 unsigned TargetOccupancy = std::min(
2000 S.getTargetOccupancy(),
ST.getOccupancyWithWorkGroupSizes(
MF).second);
2001 unsigned WavesAfter = std::min(
2002 TargetOccupancy,
PressureAfter.getOccupancy(
ST, DynamicVGPRBlockSize));
2003 unsigned WavesBefore = std::min(
2005 LLVM_DEBUG(
dbgs() <<
"Occupancy before scheduling: " << WavesBefore
2006 <<
", after " << WavesAfter <<
".\n");
2012 unsigned NewOccupancy = std::max(WavesAfter, WavesBefore);
2016 if (WavesAfter < WavesBefore && WavesAfter <
DAG.MinOccupancy &&
2017 WavesAfter >=
MFI.getMinAllowedOccupancy()) {
2018 LLVM_DEBUG(
dbgs() <<
"Function is memory bound, allow occupancy drop up to "
2019 <<
MFI.getMinAllowedOccupancy() <<
" waves\n");
2020 NewOccupancy = WavesAfter;
2023 if (NewOccupancy <
DAG.MinOccupancy) {
2024 DAG.MinOccupancy = NewOccupancy;
2025 MFI.limitOccupancy(
DAG.MinOccupancy);
2027 <<
DAG.MinOccupancy <<
".\n");
2031 unsigned MaxVGPRs =
ST.getMaxNumVGPRs(
MF);
2034 unsigned MaxArchVGPRs = std::min(MaxVGPRs,
ST.getAddressableNumArchVGPRs());
2035 unsigned MaxSGPRs =
ST.getMaxNumSGPRs(
MF);
2059 unsigned ReadyCycle = CurrCycle;
2060 for (
auto &
D : SU.
Preds) {
2061 if (
D.isAssignedRegDep()) {
2064 unsigned DefReady = ReadyCycles[
DAG.getSUnit(
DefMI)->NodeNum];
2065 ReadyCycle = std::max(ReadyCycle, DefReady +
Latency);
2068 ReadyCycles[SU.
NodeNum] = ReadyCycle;
2075 std::pair<MachineInstr *, unsigned>
B)
const {
2076 return A.second <
B.second;
2082 if (ReadyCycles.empty())
2084 unsigned BBNum = ReadyCycles.begin()->first->getParent()->getNumber();
2085 dbgs() <<
"\n################## Schedule time ReadyCycles for MBB : " << BBNum
2086 <<
" ##################\n# Cycle #\t\t\tInstruction "
2090 for (
auto &
I : ReadyCycles) {
2091 if (
I.second > IPrev + 1)
2092 dbgs() <<
"****************************** BUBBLE OF " <<
I.second - IPrev
2093 <<
" CYCLES DETECTED ******************************\n\n";
2094 dbgs() <<
"[ " <<
I.second <<
" ] : " << *
I.first <<
"\n";
2107 unsigned SumBubbles = 0;
2109 unsigned CurrCycle = 0;
2110 for (
auto &SU : InputSchedule) {
2111 unsigned ReadyCycle =
2113 SumBubbles += ReadyCycle - CurrCycle;
2115 ReadyCyclesSorted.insert(std::make_pair(SU.getInstr(), ReadyCycle));
2117 CurrCycle = ++ReadyCycle;
2140 unsigned SumBubbles = 0;
2142 unsigned CurrCycle = 0;
2143 for (
auto &
MI :
DAG) {
2147 unsigned ReadyCycle =
2149 SumBubbles += ReadyCycle - CurrCycle;
2151 ReadyCyclesSorted.insert(std::make_pair(SU->
getInstr(), ReadyCycle));
2153 CurrCycle = ++ReadyCycle;
2170 if (WavesAfter <
DAG.MinOccupancy)
2174 if (
DAG.MFI.isDynamicVGPREnabled()) {
2177 DAG.MFI.getDynamicVGPRBlockSize());
2180 if (BlocksAfter > BlocksBefore)
2217 <<
"\n\t *** In shouldRevertScheduling ***\n"
2218 <<
" *********** BEFORE UnclusteredHighRPStage ***********\n");
2222 <<
"\n *********** AFTER UnclusteredHighRPStage ***********\n");
2224 unsigned OldMetric = MBefore.
getMetric();
2225 unsigned NewMetric = MAfter.
getMetric();
2226 unsigned WavesBefore = std::min(
2227 S.getTargetOccupancy(),
2234 LLVM_DEBUG(
dbgs() <<
"\tMetric before " << MBefore <<
"\tMetric after "
2235 << MAfter <<
"Profit: " << Profit <<
"\n");
2266 unsigned WavesAfter) {
2276 cl::desc(
"Percent increase of live interval RP over instant pressure to "
2277 "trigger rescheduling"),
2283 "Reduction factor (percent) for VGPR threshold during live interval RP "
2284 "reschedule stage"),
2288 "amdgpu-lirp-instant-lower-bound",
cl::Hidden,
2289 cl::desc(
"Lower bound (percent of the VGPR excess limit) on instant RP, "
2290 "below which a region is skipped"),
2300 if (!
S.VGPRThresholdPercent) {
2301 LLVM_DEBUG(
dbgs() <<
"LIRP: expected VGPRThresholdPercent to be enabled, "
2302 "not using live interval RP reschedule stage\n");
2310 unsigned InstantRP =
DAG.Pressure[
RegionIdx].getArchVGPRNum();
2311 auto [RegionBegin, RegionEnd] =
DAG.Regions[
RegionIdx];
2312 if (RegionBegin == RegionEnd)
2319 unsigned NewVGPRThresholdPercent =
2323 <<
", VGPRThresholdPercent: " <<
S.VGPRThresholdPercent
2324 <<
" -> " << NewVGPRThresholdPercent
2325 <<
", VGPRExcessLimit=" <<
S.VGPRExcessLimit
2326 <<
", VGPRCriticalLimit=" <<
S.VGPRCriticalLimit
2327 <<
", InstantRP=" << InstantRP <<
", LIRP=" << LIRP);
2329 bool DoRescheduling =
false;
2331 unsigned InstantRPLowerBound =
2333 if (LIRP >
S.VGPRExcessLimit) {
2334 LLVM_DEBUG(
dbgs() <<
" [LIRP exceeds the limit (" <<
S.VGPRExcessLimit
2335 <<
"), rescheduling]");
2336 DoRescheduling =
true;
2337 }
else if (LIRP > InstantRP && InstantRP > InstantRPLowerBound) {
2338 unsigned IncreasePercent = ((LIRP - InstantRP) * 100) / InstantRP;
2342 DoRescheduling =
true;
2348 SavedVGPRExcessLimit =
S.VGPRExcessLimit;
2349 SavedVGPRCriticalLimit =
S.VGPRCriticalLimit;
2350 SavedVGPRThresholdPercent =
S.VGPRThresholdPercent;
2351 S.VGPRThresholdPercent = NewVGPRThresholdPercent;
2359 S.VGPRExcessLimit = SavedVGPRExcessLimit;
2360 S.VGPRCriticalLimit = SavedVGPRCriticalLimit;
2361 S.VGPRThresholdPercent = SavedVGPRThresholdPercent;
2368 LLVM_DEBUG(
dbgs() <<
"New pressure will result in more spilling.\n");
2380 "instruction number mismatch");
2381 if (MIOrder.
empty())
2394 if (MII != RegionEnd) {
2396 bool NonDebugReordered =
2397 !
MI->isDebugInstr() &&
2403 if (NonDebugReordered)
2404 DAG.LIS->handleMove(*
MI,
true);
2411 if (!
MI->isDebugInstr()) {
2413 SlotIndex PrevIdx =
DAG.LIS->getSlotIndexes()->getIndexBefore(*
MI);
2414 if (PrevIdx >= MIIdx)
2415 DAG.LIS->handleMove(*
MI,
true);
2419 if (
MI->isDebugInstr()) {
2426 Op.setIsUndef(
false);
2429 if (
DAG.ShouldTrackLaneMasks) {
2454 if (RD->
getOpcode() == AMDGPU::AV_MOV_B32_IMM_PSEUDO ||
2455 RD->
getOpcode() == AMDGPU::AV_MOV_B64_IMM_PSEUDO)
2462bool RewriteMFMAFormStage::hasUseRequiringVGPR(
2464 const SmallPtrSetImpl<MachineInstr *> &RewriteSet) {
2465 for (SlotIndex RDIdx : Src2ReachingDefs) {
2466 const MachineInstr *RD =
DAG.LIS->getInstructionFromIndex(RDIdx);
2468 findReachingUses(RD,
DAG.LIS, ReachingUses);
2469 for (
const MachineOperand *UseMO : ReachingUses) {
2481void RewriteMFMAFormStage::resetRewriteCandsToVGPR(
2482 ArrayRef<std::pair<MachineInstr *, unsigned>> RewriteCands) {
2483 for (
auto [
MI, OriginalOpcode] : RewriteCands) {
2486 DAG.MRI.getRegClass(
MI->getOperand(0).getReg());
2488 DAG.MRI.setRegClass(
MI->getOperand(0).getReg(), VDefRC);
2489 MI->setDesc(
TII->get(OriginalOpcode));
2491 MachineOperand *Src2 =
TII->getNamedOperand(*
MI, AMDGPU::OpName::src2);
2500 DAG.MRI.setRegClass(Src2->
getReg(), VUseRC);
2504bool RewriteMFMAFormStage::isRewriteCandidate(MachineInstr *
MI)
const {
2505 if (!
static_cast<const SIInstrInfo *
>(
DAG.TII)->isMAI(*
MI))
2510 Register DstReg =
MI->getOperand(0).getReg();
2511 for (
const MachineInstr &
UseMI :
DAG.MRI.use_nodbg_instructions(DstReg)) {
2518bool RewriteMFMAFormStage::initHeuristics(
2519 std::vector<std::pair<MachineInstr *, unsigned>> &RewriteCands,
2520 DenseMap<MachineBasicBlock *, std::set<Register>> &CopyForUse,
2521 SmallPtrSetImpl<MachineInstr *> &CopyForDef) {
2526 SmallPtrSet<MachineInstr *, 16> RewriteSet;
2527 DenseSet<Register> CandSrc2Regs;
2528 for (MachineBasicBlock &
MBB :
MF) {
2529 for (MachineInstr &
MI :
MBB) {
2530 if (!isRewriteCandidate(&
MI))
2533 MachineOperand *Src2 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src2);
2534 if (Src2 && Src2->
isReg())
2540 for (MachineBasicBlock &
MBB :
MF) {
2541 for (MachineInstr &
MI :
MBB) {
2542 if (!isRewriteCandidate(&
MI))
2546 assert(ReplacementOp != -1);
2548 RewriteCands.push_back({&
MI,
MI.getOpcode()});
2549 MI.setDesc(
TII->get(ReplacementOp));
2551 MachineOperand *Src2 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src2);
2552 if (Src2->
isReg()) {
2554 findReachingDefs(*Src2,
DAG.LIS, Src2ReachingDefs);
2558 bool Src2NeedsVGPR = hasUseRequiringVGPR(Src2ReachingDefs, RewriteSet);
2559 Src2NeedsVGPRCache[&
MI] = Src2NeedsVGPR;
2561 for (SlotIndex RDIdx : Src2ReachingDefs) {
2562 MachineInstr *RD =
DAG.LIS->getInstructionFromIndex(RDIdx);
2563 if (!Src2NeedsVGPR &&
2570 MachineOperand &Dst =
MI.getOperand(0);
2573 findReachingUses(&
MI,
DAG.LIS, DstReachingUses);
2575 for (MachineOperand *RUOp : DstReachingUses) {
2576 MachineInstr *UserMI = RUOp->getParent();
2578 if (
TII->isMAI(*UserMI) && RewriteSet.
contains(UserMI))
2584 CopyForUse[UserMI->
getParent()].insert(RUOp->getReg());
2586 if (
TII->isMAI(*UserMI))
2590 findReachingDefs(*RUOp,
DAG.LIS, DstUsesReachingDefs);
2592 for (SlotIndex RDIndex : DstUsesReachingDefs) {
2593 MachineInstr *RD =
DAG.LIS->getInstructionFromIndex(RDIndex);
2594 if (
TII->isMAI(*RD))
2608 DAG.MRI.setRegClass(Dst.getReg(), ADefRC);
2609 if (Src2->
isReg()) {
2615 DAG.MRI.setRegClass(Src2->
getReg(), AUseRC);
2624int64_t RewriteMFMAFormStage::getRewriteCost(
2625 ArrayRef<std::pair<MachineInstr *, unsigned>> RewriteCands,
2626 const DenseMap<MachineBasicBlock *, std::set<Register>> &CopyForUse,
2627 const SmallPtrSetImpl<MachineInstr *> &CopyForDef) {
2628 MachineBlockFrequencyInfo *MBFI =
DAG.MBFI;
2630 int64_t BestSpillCost = 0;
2634 std::pair<unsigned, unsigned> MaxVectorRegs =
2635 ST.getMaxNumVectorRegs(
MF.getFunction());
2636 unsigned ArchVGPRThreshold = MaxVectorRegs.first;
2637 unsigned AGPRThreshold = MaxVectorRegs.second;
2638 unsigned CombinedThreshold =
ST.getMaxNumVGPRs(
MF);
2641 if (!RegionsWithExcessArchVGPR[Region])
2646 MF, ArchVGPRThreshold, AGPRThreshold, CombinedThreshold);
2654 MF, ArchVGPRThreshold, AGPRThreshold, CombinedThreshold);
2660 bool RelativeFreqIsDenom = EntryFreq > BlockFreq;
2661 uint64_t RelativeFreq = EntryFreq && BlockFreq
2662 ? (RelativeFreqIsDenom ? EntryFreq / BlockFreq
2663 : BlockFreq / EntryFreq)
2668 int64_t SpillCost = ((int)SpillCostAfter - (int)SpillCostBefore) * 2;
2671 if (RelativeFreqIsDenom)
2672 SpillCost /= (int64_t)RelativeFreq;
2674 SpillCost *= (int64_t)RelativeFreq;
2677 if (SpillCost > 0) {
2678 resetRewriteCandsToVGPR(RewriteCands);
2682 if (SpillCost < BestSpillCost)
2683 BestSpillCost = SpillCost;
2688 Cost = BestSpillCost;
2691 unsigned CopyCost = 0;
2695 for (MachineInstr *
DefMI : CopyForDef) {
2707 for (
auto &[UseBlock, UseRegs] : CopyForUse) {
2721 resetRewriteCandsToVGPR(RewriteCands);
2723 return Cost + CopyCost;
2726bool RewriteMFMAFormStage::rewrite(
2727 ArrayRef<std::pair<MachineInstr *, unsigned>> RewriteCands) {
2728 DenseMap<MachineInstr *, unsigned> FirstMIToRegion;
2729 DenseMap<MachineInstr *, unsigned> LastMIToRegion;
2737 if (
Entry.second !=
Entry.first->getParent()->end())
2780 DenseSet<Register> RewriteRegs;
2783 DenseMap<Register, Register> RedefMap;
2785 DenseMap<Register, DenseSet<MachineOperand *>>
ReplaceMap;
2787 DenseMap<Register, SmallPtrSet<MachineInstr *, 8>> ReachingDefCopyMap;
2790 DenseMap<unsigned, DenseMap<Register, SmallPtrSet<MachineOperand *, 8>>>
2795 SmallPtrSet<MachineInstr *, 16> RewriteCandsSet;
2796 DenseSet<Register> RewriteSrc2Regs;
2797 for (
auto &[
MI, OriginalOpcode] : RewriteCands) {
2799 MachineOperand *Src2 =
TII->getNamedOperand(*
MI, AMDGPU::OpName::src2);
2800 if (Src2 && Src2->
isReg())
2804 for (
auto &[
MI, OriginalOpcode] : RewriteCands) {
2806 if (ReplacementOp == -1)
2808 MI->setDesc(
TII->get(ReplacementOp));
2811 MachineOperand *Src2 =
TII->getNamedOperand(*
MI, AMDGPU::OpName::src2);
2812 if (Src2->
isReg()) {
2819 findReachingDefs(*Src2,
DAG.LIS, Src2ReachingDefs);
2820 SmallSetVector<MachineInstr *, 8> Src2DefsReplace;
2824 bool Src2NeedsVGPR = Src2NeedsVGPRCache.lookup(
MI);
2826 for (SlotIndex RDIndex : Src2ReachingDefs) {
2827 MachineInstr *RD =
DAG.LIS->getInstructionFromIndex(RDIndex);
2828 if (!Src2NeedsVGPR &&
2832 Src2DefsReplace.
insert(RD);
2835 if (!Src2DefsReplace.
empty()) {
2836 auto RI = RedefMap.
find(Src2Reg);
2837 if (RI != RedefMap.
end()) {
2838 MappedReg = RI->second;
2843 SRI->getEquivalentVGPRClass(Src2RC);
2846 MappedReg =
DAG.MRI.createVirtualRegister(VGPRRC);
2847 RedefMap[Src2Reg] = MappedReg;
2852 for (MachineInstr *RD : Src2DefsReplace) {
2854 if (ReachingDefCopyMap[Src2Reg].insert(RD).second) {
2855 MachineInstrBuilder VGPRCopy =
2858 .
addDef(MappedReg, {}, 0)
2859 .addUse(Src2Reg, {}, 0);
2860 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
2865 unsigned UpdateRegion = LastMIToRegion[RD];
2866 DAG.Regions[UpdateRegion].second = VGPRCopy;
2867 LastMIToRegion.
erase(RD);
2874 RewriteRegs.
insert(Src2Reg);
2884 MachineOperand *Dst = &
MI->getOperand(0);
2893 SmallVector<MachineInstr *, 8> DstUseDefsReplace;
2895 findReachingUses(
MI,
DAG.LIS, DstReachingUses);
2897 for (MachineOperand *RUOp : DstReachingUses) {
2898 MachineInstr *UserMI = RUOp->
getParent();
2900 if (
TII->isMAI(*UserMI) && RewriteCandsSet.
contains(UserMI))
2904 if (
find(DstReachingUseCopies, RUOp) == DstReachingUseCopies.
end())
2908 if (
TII->isMAI(*UserMI))
2912 findReachingDefs(*RUOp,
DAG.LIS, DstUsesReachingDefs);
2914 for (SlotIndex RDIndex : DstUsesReachingDefs) {
2915 MachineInstr *RD =
DAG.LIS->getInstructionFromIndex(RDIndex);
2916 if (
TII->isMAI(*RD))
2921 if (
find(DstUseDefsReplace, RD) == DstUseDefsReplace.
end())
2926 if (!DstUseDefsReplace.
empty()) {
2927 auto RI = RedefMap.
find(DstReg);
2928 if (RI != RedefMap.
end()) {
2929 MappedReg = RI->second;
2936 MappedReg =
DAG.MRI.createVirtualRegister(VGPRRC);
2937 RedefMap[DstReg] = MappedReg;
2942 for (MachineInstr *RD : DstUseDefsReplace) {
2944 if (ReachingDefCopyMap[DstReg].insert(RD).second) {
2945 MachineInstrBuilder VGPRCopy =
2948 .
addDef(MappedReg, {}, 0)
2949 .addUse(DstReg, {}, 0);
2950 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
2954 auto LMI = LastMIToRegion.
find(RD);
2955 if (LMI != LastMIToRegion.
end()) {
2956 unsigned UpdateRegion = LMI->second;
2957 DAG.Regions[UpdateRegion].second = VGPRCopy;
2958 LastMIToRegion.
erase(RD);
2964 DenseSet<MachineOperand *> &DstRegSet =
ReplaceMap[DstReg];
2967 MachineInstr *EarliestSameBlockUse =
nullptr;
2968 for (MachineOperand *RU : DstReachingUseCopies) {
2969 MachineBasicBlock *RUBlock = RU->getParent()->getParent();
2972 if (RUBlock !=
MI->getParent()) {
2978 if (!SameBlockCopyReg.
isValid()) {
2981 SameBlockCopyReg =
DAG.MRI.createVirtualRegister(VGPRRC);
2985 MachineInstr *UseInst = RU->getParent();
2986 if (!EarliestSameBlockUse ||
2988 DAG.LIS->getInstructionIndex(*UseInst),
2989 DAG.LIS->getInstructionIndex(*EarliestSameBlockUse)))
2990 EarliestSameBlockUse = UseInst;
2991 RU->setReg(SameBlockCopyReg);
2995 if (SameBlockCopyReg.
isValid()) {
2996 MachineInstrBuilder VGPRCopy =
2999 TII->get(TargetOpcode::COPY), SameBlockCopyReg)
3001 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
3006 RewriteRegs.
insert(DstReg);
3016 std::pair<unsigned, DenseMap<Register, SmallPtrSet<MachineOperand *, 8>>>;
3017 for (RUBType RUBlockEntry : ReachingUseTracker) {
3018 using RUDType = std::pair<Register, SmallPtrSet<MachineOperand *, 8>>;
3019 for (RUDType RUDst : RUBlockEntry.second) {
3020 MachineOperand *OpBegin = *RUDst.second.begin();
3021 SlotIndex InstPt =
DAG.LIS->getInstructionIndex(*OpBegin->
getParent());
3024 for (MachineOperand *User : RUDst.second) {
3025 SlotIndex NewInstPt =
DAG.LIS->getInstructionIndex(*
User->getParent());
3032 Register NewUseReg =
DAG.MRI.createVirtualRegister(VGPRRC);
3033 MachineInstr *UseInst =
DAG.LIS->getInstructionFromIndex(InstPt);
3035 MachineInstrBuilder VGPRCopy =
3038 .
addDef(NewUseReg, {}, 0)
3039 .addUse(RUDst.first, {}, 0);
3040 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
3044 auto FI = FirstMIToRegion.
find(UseInst);
3045 if (FI != FirstMIToRegion.
end()) {
3046 unsigned UpdateRegion = FI->second;
3047 DAG.Regions[UpdateRegion].first = VGPRCopy;
3048 FirstMIToRegion.
erase(UseInst);
3052 for (MachineOperand *User : RUDst.second) {
3053 User->setReg(NewUseReg);
3064 for (std::pair<Register, Register> NewDef : RedefMap) {
3069 for (MachineOperand *ReplaceOp :
ReplaceMap[OldReg])
3070 ReplaceOp->setReg(NewReg);
3074 for (
Register RewriteReg : RewriteRegs) {
3075 Register RegToRewrite = RewriteReg;
3078 auto RI = RedefMap.find(RewriteReg);
3079 if (RI != RedefMap.end())
3080 RegToRewrite = RI->second;
3085 DAG.MRI.setRegClass(RegToRewrite, AGPRRC);
3089 DAG.LIS->reanalyze(
DAG.MF);
3091 RegionPressureMap LiveInUpdater(&
DAG,
false);
3092 LiveInUpdater.buildLiveRegMap();
3095 DAG.LiveIns[Region] = LiveInUpdater.getLiveRegsForRegionIdx(Region);
3102unsigned PreRARematStage::getStageTargetOccupancy()
const {
3103 return TargetOcc ? *TargetOcc :
MFI.getMinWavesPerEU();
3106bool PreRARematStage::setObjective() {
3110 unsigned MaxSGPRs =
ST.getMaxNumSGPRs(
F);
3111 unsigned MaxVGPRs =
ST.getMaxNumVGPRs(
F);
3112 bool HasVectorRegisterExcess =
false;
3113 for (
unsigned I = 0,
E =
DAG.Regions.size();
I !=
E; ++
I) {
3114 const GCNRegPressure &
RP =
DAG.Pressure[
I];
3115 GCNRPTarget &
Target = RPTargets.emplace_back(MaxSGPRs, MaxVGPRs,
MF, RP);
3117 TargetRegions.set(
I);
3118 HasVectorRegisterExcess |=
Target.hasVectorRegisterExcess();
3121 if (HasVectorRegisterExcess ||
DAG.MinOccupancy >=
MFI.getMaxWavesPerEU()) {
3124 TargetOcc = std::nullopt;
3128 TargetOcc =
DAG.MinOccupancy + 1;
3129 const unsigned VGPRBlockSize =
MFI.getDynamicVGPRBlockSize();
3130 MaxSGPRs =
ST.getMaxNumSGPRs(*TargetOcc,
false);
3131 MaxVGPRs =
ST.getMaxNumVGPRs(*TargetOcc, VGPRBlockSize);
3132 for (
auto [
I, Target] :
enumerate(RPTargets)) {
3133 Target.setTarget(MaxSGPRs, MaxVGPRs);
3135 TargetRegions.set(
I);
3139 return TargetRegions.any();
3142bool PreRARematStage::ScoredRemat::maybeBeneficial(
3144 for (
unsigned I : TargetRegions.set_bits()) {
3145 if (Live[
I] && RPTargets[
I].isSaveBeneficial(RPSave))
3158 const unsigned NumRegions =
DAG.Regions.size();
3162 for (
unsigned I = 0;
I < NumRegions; ++
I) {
3166 if (BlockFreq && BlockFreq <
MinFreq)
3175 if (
MinFreq >= ScaleFactor * ScaleFactor) {
3176 for (uint64_t &Freq :
Regions)
3177 Freq /= ScaleFactor;
3183void PreRARematStage::ScoredRemat::init(
const FreqInfo &Freq,
3188 assert(Reg.Uses.size() == 1 &&
"expected users in single region");
3189 const unsigned UseRegion = Reg.Uses.begin()->first;
3194 for (
unsigned I : Live.set_bits()) {
3197 if (!LiveIn[
I] || !LiveOut[
I] ||
I == UseRegion)
3198 UnpredictableRPSave.set(
I);
3205 int64_t DefOrMin = std::max(Freq.
Regions[Reg.DefRegion], Freq.
MinFreq);
3206 int64_t UseOrMax = Freq.
Regions[UseRegion];
3209 FreqDiff = DefOrMin - UseOrMax;
3212void PreRARematStage::ScoredRemat::update(
const BitVector &TargetRegions,
3214 const FreqInfo &FreqInfo,
3218 for (
unsigned I : TargetRegions.
set_bits()) {
3227 if (!NumRegsBenefit)
3231 RegionImpact += (UnpredictableRPSave[
I] ? 1 : 2) * NumRegsBenefit;
3234 uint64_t Freq = FreqInfo.
Regions[
I];
3235 if (UnpredictableRPSave[
I]) {
3240 MaxFreq = std::max(MaxFreq, Freq);
3245void PreRARematStage::ScoredRemat::rematerialize(
3246 Rematerializer &Remater)
const {
3247 const Rematerializer::Reg &
Reg = Remater.getReg(RegIdx);
3248 Rematerializer::DependencyReuseInfo DRI;
3249 for (RegisterIdx DepRegIdx :
Reg.Dependencies)
3250 DRI.
reuse(DepRegIdx);
3251 unsigned UseRegion =
Reg.Uses.begin()->first;
3252 Remater.rematerializeToRegion(RegIdx, UseRegion, DRI);
3255void PreRARematStage::updateRPTargets(
const BitVector &Regions,
3256 const GCNRegPressure &RPSave) {
3258 RPTargets[
I].saveRP(RPSave);
3259 if (TargetRegions[
I] && RPTargets[
I].satisfied()) {
3261 TargetRegions.reset(
I);
3266bool PreRARematStage::updateAndVerifyRPTargets(
const BitVector &Regions) {
3267 bool TooOptimistic =
false;
3269 GCNRPTarget &
Target = RPTargets[
I];
3275 if (!TargetRegions[
I] && !
Target.satisfied()) {
3277 TooOptimistic =
true;
3278 TargetRegions.set(
I);
3281 return TooOptimistic;
3284void PreRARematStage::removeFromLiveMaps(
Register Reg,
const BitVector &LiveIn,
3285 const BitVector &LiveOut) {
3287 LiveOut.
size() ==
DAG.Regions.size() &&
"region num mismatch");
3291 DAG.RegionLiveOuts.getLiveRegsForRegionIdx(
I).erase(
Reg);
3294void PreRARematStage::addToLiveMaps(
Register Reg, LaneBitmask Mask,
3295 const BitVector &LiveIn,
3296 const BitVector &LiveOut) {
3298 LiveOut.
size() ==
DAG.Regions.size() &&
"region num mismatch");
3299 std::pair<Register, LaneBitmask> LiveReg(
Reg, Mask);
3301 DAG.LiveIns[
I].insert(LiveReg);
3303 DAG.RegionLiveOuts.getLiveRegsForRegionIdx(
I).insert(LiveReg);
3315 if (
DAG.MinOccupancy >= *TargetOcc)
3319 for (
const auto &[
RegionIdx, OrigMIOrder, MaxPressure] : RegionReverts) {
3329 if (AchievedOcc >= *TargetOcc) {
3330 DAG.setTargetOccupancy(AchievedOcc);
3335 DAG.setTargetOccupancy(*TargetOcc - 1);
3340 assert(Rollback &&
"rollbacker should be defined");
3341 Rollback->Listener.rollback(Remater);
3342 for (
const auto &[RegIdx, LiveIn, LiveOut] : Rollback->LiveMapUpdates) {
3343 const Rematerializer::Reg &
Reg = Remater.getReg(RegIdx);
3344 addToLiveMaps(
Reg.getDefReg(),
Reg.Mask, LiveIn, LiveOut);
3347#ifdef EXPENSIVE_CHECKS
3352 for (
unsigned I : RescheduleRegions.set_bits())
3353 DAG.Pressure[
I] =
DAG.getRealRegPressure(
I);
3358void GCNScheduleDAGMILive::setTargetOccupancy(
unsigned TargetOccupancy) {
3359 MinOccupancy = TargetOccupancy;
3360 if (
MFI.getOccupancy() < TargetOccupancy)
3361 MFI.increaseOccupancy(
MF, MinOccupancy);
3363 MFI.limitOccupancy(MinOccupancy);
3380 if (HasIGLPInstrs) {
3381 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
iterator find(const_arg_type_t< KeyT > Val)
bool erase(const KeyT &Val)
bool contains(const_arg_type_t< KeyT > Val) const
Return true if the specified key is in the map, false otherwise.
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Implements a dense probed hash-table based set.
bool reset(const MachineInstr &MI, MachineBasicBlock::const_iterator End, const LiveRegSet *LiveRegs=nullptr)
Reset tracker to the point before the MI filling LiveRegs upon this point using LIS.
GCNRegPressure bumpDownwardPressure(const MachineInstr *MI, const SIRegisterInfo *TRI) const
Mostly copy/paste from CodeGen/RegisterPressure.cpp Calculate the impact MI will have on CurPressure ...
GCNMaxILPSchedStrategy(const MachineSchedContext *C)
bool tryCandidate(SchedCandidate &Cand, SchedCandidate &TryCand, SchedBoundary *Zone) const override
Apply a set of heuristics to a new candidate.
bool tryCandidate(SchedCandidate &Cand, SchedCandidate &TryCand, SchedBoundary *Zone) const override
GCNMaxMemoryClauseSchedStrategy tries best to clause memory instructions as much as possible.
GCNMaxMemoryClauseSchedStrategy(const MachineSchedContext *C)
GCNMaxOccupancySchedStrategy(const MachineSchedContext *C, bool IsLegacyScheduler=false)
void finalizeSchedule() override
Allow targets to perform final scheduling actions at the level of the whole MachineFunction.
void schedule() override
Orders nodes according to selected style.
GCNPostScheduleDAGMILive(MachineSchedContext *C, std::unique_ptr< MachineSchedStrategy > S, bool RemoveKillFlags)
Models a register pressure target, allowing to evaluate and track register savings against that targe...
unsigned getNumRegsBenefit(const GCNRegPressure &SaveRP) const
Returns the benefit towards achieving the RP target that saving SaveRP represents,...
GCNRegPressure getPressure() const
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.
GCNDownwardRPTracker DownwardTracker
bool useGCNTrackers() const
void getRegisterPressures(bool AtTop, const RegPressureTracker &RPTracker, SUnit *SU, std::vector< unsigned > &Pressure, std::vector< unsigned > &MaxPressure, GCNDownwardRPTracker &DownwardTracker, GCNUpwardRPTracker &UpwardTracker, ScheduleDAGMI *DAG, const SIRegisterInfo *SRI)
GCNSchedStrategy(const MachineSchedContext *C)
SmallVector< GCNSchedStageID, 4 > SchedStages
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
GCNDownwardRPTracker * getDownwardTracker()
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)
void initCandidate(SchedCandidate &Cand, SUnit *SU, bool AtTop, const RegPressureTracker &RPTracker, const SIRegisterInfo *SRI, unsigned SGPRPressure, unsigned VGPRPressure, unsigned AGPRPressure, bool IsBottomUp)
SUnit * pickNode(bool &IsTopNode) override
Pick the next node to schedule, or return NULL.
GCNUpwardRPTracker * getUpwardTracker()
GCNSchedStageID getNextStage() const
void finalizeSchedule() override
Allow targets to perform final scheduling actions at the level of the whole MachineFunction.
void schedule() override
Orders nodes according to selected style.
GCNScheduleDAGMILive(MachineSchedContext *C, std::unique_ptr< MachineSchedStrategy > S)
void recede(const MachineInstr &MI)
Move to the state of RP just before the MI .
void reset(const MachineInstr &MI)
Resets tracker to the point just after MI (in program order), which can be a debug instruction.
void compute(FunctionT &F)
Compute the cycle info for a function.
void traceCandidate(const SchedCandidate &Cand)
LLVM_ABI void setPolicy(CandPolicy &Policy, bool IsPostRA, SchedBoundary &CurrZone, SchedBoundary *OtherZone)
Set the CandPolicy given a scheduling zone given the current resources and latencies inside and outsi...
MachineSchedPolicy RegionPolicy
const TargetSchedModel * SchedModel
const MachineSchedContext * Context
const TargetRegisterInfo * TRI
SchedCandidate BotCand
Candidate last picked from Bot boundary.
SchedCandidate TopCand
Candidate last picked from Top boundary.
virtual bool tryCandidate(SchedCandidate &Cand, SchedCandidate &TryCand, SchedBoundary *Zone) const
Apply a set of heuristics to a new candidate.
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)
List of registers defined and used by a machine instruction.
LLVM_ABI void detectDeadDefs(const MachineInstr &MI, const LiveIntervals &LIS, const MachineRegisterInfo &MRI)
Use liveness information to find dead defs at MI's dead slot not marked with a dead flag and move the...
LLVM_ABI void adjustLaneLiveness(const LiveIntervals &LIS, const MachineRegisterInfo &MRI, SlotIndex Pos)
Use liveness information to find out which uses/defs are partially undefined/dead at Pos and adjust t...
LLVM_ABI void collect(const MachineInstr &MI, const TargetRegisterInfo &TRI, const MachineRegisterInfo &MRI, bool TrackLaneMasks, bool IgnoreDead)
Analyze the given instruction MI and fill in the Uses, Defs and DeadDefs list based on the MachineOpe...
Wrapper class representing virtual and physical registers.
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 cl::opt< bool > VerifyScheduling
LLVM_ABI bool tryLatency(GenericSchedulerBase::SchedCandidate &TryCand, GenericSchedulerBase::SchedCandidate &Cand, SchedBoundary &Zone)
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
IterT skipDebugInstructionsBackward(IterT It, IterT Begin, bool SkipPseudoOp=true)
Decrement It until it points to a non-debug instruction or to Begin and return the resulting iterator...
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
bool isTheSameCluster(unsigned A, unsigned B)
Return whether the input cluster ID's are the same and valid.
DWARFExpression::Operation Op
LLVM_ABI bool tryGreater(int TryVal, int CandVal, GenericSchedulerBase::SchedCandidate &TryCand, GenericSchedulerBase::SchedCandidate &Cand, GenericSchedulerBase::CandReason Reason)
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
ArrayRef(const T &OneElt) -> ArrayRef< T >
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
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)