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,
108struct VGPRThresholdParser :
public cl::parser<unsigned> {
111 bool parse(cl::Option &O, StringRef ArgName, StringRef Arg,
unsigned &
Value) {
113 return O.error(
"'" + Arg +
"' value invalid for uint argument!");
116 return O.error(
"'" + Arg +
"' value must be in the range [0, 100]!");
126 cl::desc(
"Percent of VGPR limits that we should use as RP threshold "
127 "during scheduling. We have two limits relevant to scheduling: "
128 "Critical (avoid decreasing occupancy), Excess (avoid spilling). "
129 "This flag scales both limits back by an equal percent: (0 = use "
130 " default calculation, 1-100 = use percentage), default: 0"),
150 Context->RegClassInfo->getNumAllocatableRegs(&AMDGPU::SGPR_32RegClass);
152 Context->RegClassInfo->getNumAllocatableRegs(&AMDGPU::VGPR_32RegClass);
154 Context->RegClassInfo->getNumAllocatableRegs(&AMDGPU::AGPR_32RegClass);
176 "VGPRCriticalLimit calculation method.\n");
180 unsigned Addressable =
183 VGPRBudget = std::max(VGPRBudget, Granule);
200 <<
". VGPRCriticalLimit: " << OriginalVGPRCriticalLimit
246 if (!
Op.isReg() ||
Op.isImplicit())
248 if (
Op.getReg().isPhysical() ||
249 (
Op.isDef() &&
Op.getSubReg() != AMDGPU::NoSubRegister))
284 Pressure[AMDGPU::RegisterPressureSets::VGPR_32] =
293 unsigned SGPRPressure,
294 unsigned VGPRPressure,
295 unsigned AGPRPressure,
bool IsBottomUp) {
299 if (!
DAG->isTrackingPressure())
322 Pressure[AMDGPU::RegisterPressureSets::SReg_32] = SGPRPressure;
323 Pressure[AMDGPU::RegisterPressureSets::VGPR_32] = VGPRPressure;
324 Pressure[AMDGPU::RegisterPressureSets::AGPR_32] = AGPRPressure;
326 for (
const auto &Diff :
DAG->getPressureDiff(SU)) {
332 (IsBottomUp ? Diff.getUnitInc() : -Diff.getUnitInc());
335#ifdef EXPENSIVE_CHECKS
336 std::vector<unsigned> CheckPressure, CheckMaxPressure;
339 if (
Pressure[AMDGPU::RegisterPressureSets::SReg_32] !=
340 CheckPressure[AMDGPU::RegisterPressureSets::SReg_32] ||
341 Pressure[AMDGPU::RegisterPressureSets::VGPR_32] !=
342 CheckPressure[AMDGPU::RegisterPressureSets::VGPR_32] ||
343 Pressure[AMDGPU::RegisterPressureSets::AGPR_32] !=
344 CheckPressure[AMDGPU::RegisterPressureSets::AGPR_32]) {
345 errs() <<
"Register Pressure is inaccurate when calculated through "
347 <<
"SGPR got " <<
Pressure[AMDGPU::RegisterPressureSets::SReg_32]
349 << CheckPressure[AMDGPU::RegisterPressureSets::SReg_32] <<
"\n"
350 <<
"VGPR got " <<
Pressure[AMDGPU::RegisterPressureSets::VGPR_32]
352 << CheckPressure[AMDGPU::RegisterPressureSets::VGPR_32] <<
"\n"
353 <<
"AGPR got " <<
Pressure[AMDGPU::RegisterPressureSets::AGPR_32]
355 << CheckPressure[AMDGPU::RegisterPressureSets::AGPR_32] <<
"\n";
361 unsigned NewAGPRPressure =
Pressure[AMDGPU::RegisterPressureSets::AGPR_32];
362 unsigned NewSGPRPressure =
Pressure[AMDGPU::RegisterPressureSets::SReg_32];
363 unsigned NewVGPRPressure =
Pressure[AMDGPU::RegisterPressureSets::VGPR_32];
373 const unsigned MaxVGPRPressureInc = 16;
374 bool ShouldTrackVGPRs = VGPRPressure + MaxVGPRPressureInc >=
VGPRExcessLimit;
377 bool ShouldTrackSGPRs =
378 !ShouldTrackVGPRs && !ShouldTrackAGPRs && SGPRPressure >=
SGPRExcessLimit;
413 : std::numeric_limits<int>::min();
415 if (SGPRDelta >= 0 || VGPRDelta >= 0 || AGPRDelta >= 0) {
418 if (VGPRDelta >= SGPRDelta && VGPRDelta >= AGPRDelta) {
422 }
else if (AGPRDelta >= SGPRDelta) {
436 bool HasBufferedModel =
455 dbgs() <<
"Prefer:\t\t";
456 DAG->dumpNode(*Preferred.
SU);
460 DAG->dumpNode(*Current.
SU);
463 dbgs() <<
"Reason:\t\t";
477 unsigned SGPRPressure = 0;
478 unsigned VGPRPressure = 0;
479 unsigned AGPRPressure = 0;
481 if (
DAG->isTrackingPressure()) {
483 SGPRPressure =
Pressure[AMDGPU::RegisterPressureSets::SReg_32];
484 VGPRPressure =
Pressure[AMDGPU::RegisterPressureSets::VGPR_32];
485 AGPRPressure =
Pressure[AMDGPU::RegisterPressureSets::AGPR_32];
490 SGPRPressure =
T->getPressure().getSGPRNum();
491 VGPRPressure =
T->getPressure().getArchVGPRNum();
492 AGPRPressure =
T->getPressure().getAGPRNum();
497 for (
SUnit *SU : AQ) {
501 VGPRPressure, AGPRPressure, IsBottomUp);
521 for (
SUnit *SU : PQ) {
525 VGPRPressure, AGPRPressure, IsBottomUp);
545 bool &PickedPending) {
565 bool BotPending =
false;
585 "Last pick result should correspond to re-picking right now");
590 bool TopPending =
false;
610 "Last pick result should correspond to re-picking right now");
620 PickedPending = BotPending && TopPending;
623 if (BotPending || TopPending) {
630 Cand.setBest(TryCand);
635 IsTopNode = Cand.AtTop;
642 if (
DAG->top() ==
DAG->bottom()) {
644 Bot.Available.empty() &&
Bot.Pending.empty() &&
"ReadyQ garbage");
650 PickedPending =
false;
684 if (ReadyCycle > CurrentCycle)
756 if (
DAG->isTrackingPressure() &&
762 if (
DAG->isTrackingPressure() &&
767 bool SameBoundary = Zone !=
nullptr;
791 if (IsLegacyScheduler)
810 if (
DAG->isTrackingPressure() &&
820 bool SameBoundary = Zone !=
nullptr;
855 bool CandIsClusterSucc =
857 bool TryCandIsClusterSucc =
859 if (
tryGreater(TryCandIsClusterSucc, CandIsClusterSucc, TryCand, Cand,
864 if (
DAG->isTrackingPressure() &&
870 if (
DAG->isTrackingPressure() &&
916 if (
DAG->isTrackingPressure()) {
932 bool CandIsClusterSucc =
934 bool TryCandIsClusterSucc =
936 if (
tryGreater(TryCandIsClusterSucc, CandIsClusterSucc, TryCand, Cand,
945 bool SameBoundary = Zone !=
nullptr;
962 if (TryMayLoad || CandMayLoad) {
963 bool TryLongLatency =
965 bool CandLongLatency =
969 Zone->
isTop() ? CandLongLatency : TryLongLatency, TryCand,
987 if (
DAG->isTrackingPressure() &&
1006 !
Rem.IsAcyclicLatencyLimited &&
tryLatency(TryCand, Cand, *Zone))
1024 StartingOccupancy(MFI.getOccupancy()), MinOccupancy(StartingOccupancy),
1025 RegionLiveOuts(this,
true) {
1031 LLVM_DEBUG(
dbgs() <<
"Starting occupancy is " << StartingOccupancy <<
".\n");
1033 MinOccupancy = std::min(MFI.getMinAllowedOccupancy(), StartingOccupancy);
1034 if (MinOccupancy != StartingOccupancy)
1035 LLVM_DEBUG(
dbgs() <<
"Allowing Occupancy drops to " << MinOccupancy
1040std::unique_ptr<GCNSchedStage>
1042 switch (SchedStageID) {
1044 return std::make_unique<OccInitialScheduleStage>(SchedStageID, *
this);
1046 return std::make_unique<RewriteMFMAFormStage>(SchedStageID, *
this);
1048 return std::make_unique<UnclusteredHighRPStage>(SchedStageID, *
this);
1050 return std::make_unique<ClusteredLowOccStage>(SchedStageID, *
this);
1052 return std::make_unique<PreRARematStage>(SchedStageID, *
this);
1054 return std::make_unique<ILPInitialScheduleStage>(SchedStageID, *
this);
1056 return std::make_unique<MemoryClauseInitialScheduleStage>(SchedStageID,
1070GCNScheduleDAGMILive::getRealRegPressure(
unsigned RegionIdx)
const {
1071 if (Regions[RegionIdx].first == Regions[RegionIdx].second)
1075 &LiveIns[RegionIdx]);
1081 assert(RegionBegin != RegionEnd &&
"Region must not be empty");
1085void GCNScheduleDAGMILive::computeBlockPressure(
unsigned RegionIdx,
1097 const MachineBasicBlock *OnlySucc =
nullptr;
1100 if (!Candidate->empty() && Candidate->pred_size() == 1) {
1101 SlotIndexes *Ind =
LIS->getSlotIndexes();
1103 OnlySucc = Candidate;
1108 size_t CurRegion = RegionIdx;
1109 for (
size_t E = Regions.size(); CurRegion !=
E; ++CurRegion)
1110 if (Regions[CurRegion].first->getParent() !=
MBB)
1115 auto LiveInIt = MBBLiveIns.find(
MBB);
1116 auto &Rgn = Regions[CurRegion];
1118 if (LiveInIt != MBBLiveIns.end()) {
1119 auto LiveIn = std::move(LiveInIt->second);
1121 MBBLiveIns.erase(LiveInIt);
1124 auto LRS = BBLiveInMap.lookup(NonDbgMI);
1125#ifdef EXPENSIVE_CHECKS
1134 if (Regions[CurRegion].first ==
I || NonDbgMI ==
I) {
1135 LiveIns[CurRegion] =
RPTracker.getLiveRegs();
1139 if (Regions[CurRegion].second ==
I) {
1140 Pressure[CurRegion] =
RPTracker.moveMaxPressure();
1141 if (CurRegion-- == RegionIdx)
1143 auto &Rgn = Regions[CurRegion];
1156 MBBLiveIns[OnlySucc] =
RPTracker.moveLiveRegs();
1161GCNScheduleDAGMILive::getRegionLiveInMap()
const {
1162 assert(!Regions.empty());
1163 std::vector<MachineInstr *> RegionFirstMIs;
1164 RegionFirstMIs.reserve(Regions.size());
1166 RegionFirstMIs.push_back(
1173GCNScheduleDAGMILive::getRegionLiveOutMap()
const {
1174 assert(!Regions.empty());
1175 std::vector<MachineInstr *> RegionLastMIs;
1176 RegionLastMIs.reserve(Regions.size());
1187 IdxToInstruction.clear();
1190 IsLiveOut ? DAG->getRegionLiveOutMap() : DAG->getRegionLiveInMap();
1191 for (
unsigned I = 0;
I < DAG->Regions.size();
I++) {
1192 auto &[RegionBegin, RegionEnd] = DAG->Regions[
I];
1194 if (RegionBegin == RegionEnd)
1198 IdxToInstruction[
I] = RegionKey;
1206 LiveIns.resize(Regions.size());
1207 Pressure.resize(Regions.size());
1208 RegionsWithHighRP.resize(Regions.size());
1209 RegionsWithExcessRP.resize(Regions.size());
1210 RegionsWithIGLPInstrs.resize(Regions.size());
1211 RegionsWithHighRP.reset();
1212 RegionsWithExcessRP.reset();
1213 RegionsWithIGLPInstrs.reset();
1218void GCNScheduleDAGMILive::runSchedStages() {
1219 LLVM_DEBUG(
dbgs() <<
"All regions recorded, starting actual scheduling.\n");
1222 if (!Regions.
empty()) {
1223 BBLiveInMap = getRegionLiveInMap();
1228#ifdef DUMP_MAX_REG_PRESSURE
1238 if (!Stage->initGCNSchedStage())
1241 for (
auto Region : Regions) {
1245 if (!Stage->initGCNRegion()) {
1246 Stage->advanceRegion();
1252 const unsigned RegionIdx = Stage->getRegionIdx();
1255 MRI, RegionLiveOuts.getLiveRegsForRegionIdx(RegionIdx));
1259 Stage->finalizeGCNRegion();
1260 Stage->advanceRegion();
1264 Stage->finalizeGCNSchedStage();
1267#ifdef DUMP_MAX_REG_PRESSURE
1280 OS <<
"Max Occupancy Initial Schedule";
1283 OS <<
"Instruction Rewriting Reschedule";
1286 OS <<
"Unclustered High Register Pressure Reschedule";
1289 OS <<
"Clustered Low Occupancy Reschedule";
1292 OS <<
"Pre-RA Rematerialize";
1295 OS <<
"Max ILP Initial Schedule";
1298 OS <<
"Max memory clause Initial Schedule";
1318void RewriteMFMAFormStage::findReachingDefs(
1340 while (!Worklist.
empty()) {
1355 for (MachineBasicBlock *PredMBB : DefMBB->
predecessors()) {
1356 if (Visited.
insert(PredMBB).second)
1362void RewriteMFMAFormStage::findReachingUses(
1366 for (MachineOperand &UseMO :
1369 findReachingDefs(UseMO, LIS, ReachingDefIndexes);
1373 if (
any_of(ReachingDefIndexes, [DefIdx](SlotIndex RDIdx) {
1385 if (!
ST.hasGFX90AInsts() ||
MFI.getMinWavesPerEU() > 1)
1388 RegionsWithExcessArchVGPR.resize(
DAG.Regions.size());
1389 RegionsWithExcessArchVGPR.reset();
1393 RegionsWithExcessArchVGPR[
Region] =
true;
1396 if (RegionsWithExcessArchVGPR.none())
1399 TII =
ST.getInstrInfo();
1400 SRI =
ST.getRegisterInfo();
1402 std::vector<std::pair<MachineInstr *, unsigned>> RewriteCands;
1406 if (!initHeuristics(RewriteCands, CopyForUse, CopyForDef))
1409 int64_t
Cost = getRewriteCost(RewriteCands, CopyForUse, CopyForDef);
1416 return rewrite(RewriteCands);
1426 if (
DAG.RegionsWithHighRP.none() &&
DAG.RegionsWithExcessRP.none())
1433 InitialOccupancy =
DAG.MinOccupancy;
1436 TempTargetOccupancy =
MFI.getMaxWavesPerEU() >
DAG.MinOccupancy
1437 ? InitialOccupancy + 1
1439 IsAnyRegionScheduled =
false;
1440 S.SGPRLimitBias =
S.HighRPSGPRBias;
1441 S.VGPRLimitBias =
S.HighRPVGPRBias;
1445 <<
"Retrying function scheduling without clustering. "
1446 "Aggressively try to reduce register pressure to achieve occupancy "
1447 << TempTargetOccupancy <<
".\n");
1462 if (
DAG.StartingOccupancy <=
DAG.MinOccupancy)
1466 dbgs() <<
"Retrying function scheduling with lowest recorded occupancy "
1467 <<
DAG.MinOccupancy <<
".\n");
1472#define REMAT_PREFIX "[PreRARemat] "
1473#define REMAT_DEBUG(X) LLVM_DEBUG(dbgs() << REMAT_PREFIX; X;)
1475#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
1476Printable PreRARematStage::ScoredRemat::print()
const {
1478 OS <<
'(' << MaxFreq <<
", " << FreqDiff <<
", " << RegionImpact <<
')';
1493 auto PrintTargetRegions = [&]() ->
void {
1494 if (TargetRegions.none()) {
1499 for (
unsigned I : TargetRegions.set_bits())
1506 dbgs() <<
"Analyzing ";
1507 MF.getFunction().printAsOperand(
dbgs(),
false);
1510 if (!setObjective()) {
1511 LLVM_DEBUG(
dbgs() <<
"no objective to achieve, occupancy is maximal at "
1512 <<
MFI.getMaxWavesPerEU() <<
'\n');
1517 dbgs() <<
"increase occupancy from " << *TargetOcc - 1 <<
'\n';
1519 dbgs() <<
"reduce spilling (minimum target occupancy is "
1520 <<
MFI.getMinWavesPerEU() <<
")\n";
1522 PrintTargetRegions();
1527 DAG.RegionLiveOuts.buildLiveRegMap();
1529 if (!Remater.analyze()) {
1545 DefRegToCandIdx.
resize(
DAG.MRI.getNumVirtRegs());
1546 const unsigned NumRegions =
DAG.Regions.size();
1548 for (
unsigned RegIdx = 0, E = Remater.getNumRegs(); RegIdx < E; ++RegIdx) {
1552 if (CandReg.
Uses.size() != 1)
1554 const auto [UseRegion,
Users] = *CandReg.
Uses.begin();
1573 "user must have at least one operand");
1580 assert(FirstUseMI &&
"there must be a user in the region");
1582 DAG.LIS->getInstructionIndex(*FirstUseMI).getRegSlot(
true);
1584 DAG.LIS->getInstructionIndex(*CandReg.
getLastDef()).getRegSlot(
true);
1586 const Rematerializer::Reg &DepReg = Remater.getReg(DepRegIdx);
1587 Register DepDefReg = DepReg.getDefReg();
1588 return MarkedRegs.contains(DepDefReg) ||
1589 !Remater.isRegIdenticalAtUses(DepDefReg, DepReg.Mask, RefIdx,
1594 [&](
const std::pair<Register, LaneBitmask> &RegAndMask) {
1595 const auto &[Reg, Mask] = RegAndMask;
1596 return !Remater.isRegIdenticalAtUses(Reg, Mask, RefIdx,
1601 Register DefReg = CandReg.getDefReg();
1602 MarkedRegs.
insert(DefReg);
1603 DefRegToCandIdx[DefReg] = Candidates.
size();
1611 for (
unsigned I = 0;
I < NumRegions; ++
I) {
1612 for (
const auto &[Reg, Mask] :
DAG.LiveIns[
I]) {
1615 unsigned CandIdx = DefRegToCandIdx[Reg];
1617 Candidates[CandIdx].LiveIn.set(
I);
1619 for (
const auto &[
Reg, Mask] :
1623 unsigned CandIdx = DefRegToCandIdx[
Reg];
1625 Candidates[CandIdx].LiveOut.set(
I);
1630 SmallVector<unsigned> CandidateOrder;
1631 for (
auto [CandIdx, Cand] :
enumerate(Candidates)) {
1632 Cand.init(FreqInfo, Remater,
DAG);
1633 Cand.update(TargetRegions, RPTargets, FreqInfo, !TargetOcc);
1634 if (!Cand.hasNullScore())
1645 Rollback = std::make_unique<RollbackSupport>(Remater);
1650 BitVector RecomputeRP(
DAG.Regions.size());
1652 RecomputeRP.reset();
1655 sort(CandidateOrder, [&](
unsigned LHSIndex,
unsigned RHSIndex) {
1656 return Candidates[LHSIndex] < Candidates[RHSIndex];
1660 dbgs() <<
"==== NEW REMAT ROUND ====\n"
1662 <<
"Candidates with non-null score, in rematerialization order:\n";
1663 for (
const ScoredRemat &Cand :
reverse(Candidates)) {
1665 << Remater.printRematReg(Cand.RegIdx) <<
'\n';
1667 PrintTargetRegions();
1673 while (!CandidateOrder.
empty()) {
1674 const ScoredRemat &Cand = Candidates[CandidateOrder.
back()];
1675 const Rematerializer::Reg &
Reg = Remater.getReg(Cand.RegIdx);
1683 if (!Cand.maybeBeneficial(TargetRegions, RPTargets)) {
1685 << Cand.print() <<
" | "
1686 << Remater.printRematReg(Cand.RegIdx));
1691#ifdef EXPENSIVE_CHECKS
1694 for (
const MachineInstr *
DefMI :
Reg.Defs) {
1699 if (!MO.isReg() || !MO.getReg() || !MO.readsReg() || MO.isDef())
1706 LiveInterval &LI =
DAG.LIS->getInterval(
UseReg);
1707 LaneBitmask LM =
DAG.MRI.getMaxLaneMaskForVReg(MO.getReg());
1709 LM =
DAG.TRI->getSubRegIndexLaneMask(MO.getSubReg());
1711 const unsigned UseRegion =
Reg.Uses.begin()->first;
1712 LaneBitmask LiveInMask =
DAG.LiveIns[UseRegion].at(
UseReg);
1713 LaneBitmask UncoveredLanes = LM & ~(LiveInMask & LM);
1717 if (UncoveredLanes.
any()) {
1719 for (LiveInterval::SubRange &SR : LI.
subranges())
1720 assert((SR.LaneMask & UncoveredLanes).none());
1728 REMAT_DEBUG(
dbgs() <<
"** REMAT " << Remater.printRematReg(Cand.RegIdx)
1730 removeFromLiveMaps(
Reg.getDefReg(), Cand.LiveIn, Cand.LiveOut);
1732 Rollback->LiveMapUpdates.emplace_back(Cand.RegIdx, Cand.LiveIn,
1735 Cand.rematerialize(Remater);
1740 updateRPTargets(Cand.Live, Cand.RPSave);
1741 RecomputeRP |= Cand.UnpredictableRPSave;
1742 RescheduleRegions |= Cand.Live;
1743 if (!TargetRegions.any()) {
1749 if (!updateAndVerifyRPTargets(RecomputeRP) && !TargetRegions.any()) {
1758 unsigned NumUsefulCandidates = 0;
1759 for (
unsigned CandIdx : CandidateOrder) {
1760 ScoredRemat &Candidate = Candidates[CandIdx];
1761 Candidate.update(TargetRegions, RPTargets, FreqInfo, !TargetOcc);
1762 if (!Candidate.hasNullScore())
1763 CandidateOrder[NumUsefulCandidates++] = CandIdx;
1765 if (NumUsefulCandidates == 0) {
1766 REMAT_DEBUG(
dbgs() <<
"Stop on exhausted rematerialization candidates\n");
1769 CandidateOrder.truncate(NumUsefulCandidates);
1772 if (RescheduleRegions.none())
1778 unsigned DynamicVGPRBlockSize =
MFI.getDynamicVGPRBlockSize();
1779 for (
unsigned I : RescheduleRegions.set_bits()) {
1780 DAG.Pressure[
I] = RPTargets[
I].getCurrentRP();
1782 <<
DAG.Pressure[
I].getOccupancy(
ST, DynamicVGPRBlockSize)
1783 <<
" (" << RPTargets[
I] <<
")\n");
1785 AchievedOcc =
MFI.getMaxWavesPerEU();
1786 for (
const GCNRegPressure &RP :
DAG.Pressure) {
1788 std::min(AchievedOcc,
RP.getOccupancy(
ST, DynamicVGPRBlockSize));
1792 dbgs() <<
"Retrying function scheduling with new min. occupancy of "
1793 << AchievedOcc <<
" from rematerializing (original was "
1794 <<
DAG.MinOccupancy;
1796 dbgs() <<
", target was " << *TargetOcc;
1800 DAG.setTargetOccupancy(getStageTargetOccupancy());
1811 S.SGPRLimitBias =
S.VGPRLimitBias = 0;
1812 if (
DAG.MinOccupancy > InitialOccupancy) {
1813 assert(IsAnyRegionScheduled);
1815 <<
" stage successfully increased occupancy to "
1816 <<
DAG.MinOccupancy <<
'\n');
1817 }
else if (!IsAnyRegionScheduled) {
1818 assert(
DAG.MinOccupancy == InitialOccupancy);
1820 <<
": No regions scheduled, min occupancy stays at "
1821 <<
DAG.MinOccupancy <<
", MFI occupancy stays at "
1822 <<
MFI.getOccupancy() <<
".\n");
1830 if (
DAG.begin() ==
DAG.end())
1837 unsigned NumRegionInstrs = std::distance(
DAG.begin(),
DAG.end());
1841 if (
DAG.begin() == std::prev(
DAG.end()))
1847 <<
"\n From: " << *
DAG.begin() <<
" To: ";
1849 else dbgs() <<
"End";
1850 dbgs() <<
" RegionInstrs: " << NumRegionInstrs <<
'\n');
1858 for (
auto &
I :
DAG) {
1871 dbgs() <<
"Pressure before scheduling:\nRegion live-ins:"
1873 <<
"Region live-in pressure: "
1877 S.HasHighPressure =
false;
1899 unsigned DynamicVGPRBlockSize =
DAG.MFI.getDynamicVGPRBlockSize();
1902 unsigned CurrentTargetOccupancy =
1903 IsAnyRegionScheduled ?
DAG.MinOccupancy : TempTargetOccupancy;
1905 (CurrentTargetOccupancy <= InitialOccupancy ||
1906 DAG.Pressure[
RegionIdx].getOccupancy(
ST, DynamicVGPRBlockSize) !=
1913 if (!IsAnyRegionScheduled && IsSchedulingThisRegion) {
1914 IsAnyRegionScheduled =
true;
1915 if (
MFI.getMaxWavesPerEU() >
DAG.MinOccupancy)
1916 DAG.setTargetOccupancy(TempTargetOccupancy);
1918 return IsSchedulingThisRegion;
1934 return !RevertAllRegions && RescheduleRegions[
RegionIdx] &&
1954 if (
S.HasHighPressure)
1975 if (
DAG.MinOccupancy < *TargetOcc) {
1977 <<
" cannot meet occupancy target, interrupting "
1978 "re-scheduling in all regions\n");
1979 RevertAllRegions =
true;
1990 unsigned DynamicVGPRBlockSize =
DAG.MFI.getDynamicVGPRBlockSize();
2001 unsigned TargetOccupancy = std::min(
2002 S.getTargetOccupancy(),
ST.getOccupancyWithWorkGroupSizes(
MF).second);
2003 unsigned WavesAfter = std::min(
2004 TargetOccupancy,
PressureAfter.getOccupancy(
ST, DynamicVGPRBlockSize));
2005 unsigned WavesBefore = std::min(
2007 LLVM_DEBUG(
dbgs() <<
"Occupancy before scheduling: " << WavesBefore
2008 <<
", after " << WavesAfter <<
".\n");
2014 unsigned NewOccupancy = std::max(WavesAfter, WavesBefore);
2018 if (WavesAfter < WavesBefore && WavesAfter <
DAG.MinOccupancy &&
2019 WavesAfter >=
MFI.getMinAllowedOccupancy()) {
2020 LLVM_DEBUG(
dbgs() <<
"Function is memory bound, allow occupancy drop up to "
2021 <<
MFI.getMinAllowedOccupancy() <<
" waves\n");
2022 NewOccupancy = WavesAfter;
2025 if (NewOccupancy <
DAG.MinOccupancy) {
2026 DAG.MinOccupancy = NewOccupancy;
2027 MFI.limitOccupancy(
DAG.MinOccupancy);
2029 <<
DAG.MinOccupancy <<
".\n");
2033 unsigned MaxVGPRs =
ST.getMaxNumVGPRs(
MF);
2036 unsigned MaxArchVGPRs = std::min(MaxVGPRs,
ST.getAddressableNumArchVGPRs());
2037 unsigned MaxSGPRs =
ST.getMaxNumSGPRs(
MF);
2061 unsigned ReadyCycle = CurrCycle;
2062 for (
auto &
D : SU.
Preds) {
2063 if (
D.isAssignedRegDep()) {
2066 unsigned DefReady = ReadyCycles[
DAG.getSUnit(
DefMI)->NodeNum];
2067 ReadyCycle = std::max(ReadyCycle, DefReady +
Latency);
2070 ReadyCycles[SU.
NodeNum] = ReadyCycle;
2077 std::pair<MachineInstr *, unsigned>
B)
const {
2078 return A.second <
B.second;
2084 if (ReadyCycles.empty())
2086 unsigned BBNum = ReadyCycles.begin()->first->getParent()->getNumber();
2087 dbgs() <<
"\n################## Schedule time ReadyCycles for MBB : " << BBNum
2088 <<
" ##################\n# Cycle #\t\t\tInstruction "
2092 for (
auto &
I : ReadyCycles) {
2093 if (
I.second > IPrev + 1)
2094 dbgs() <<
"****************************** BUBBLE OF " <<
I.second - IPrev
2095 <<
" CYCLES DETECTED ******************************\n\n";
2096 dbgs() <<
"[ " <<
I.second <<
" ] : " << *
I.first <<
"\n";
2109 unsigned SumBubbles = 0;
2111 unsigned CurrCycle = 0;
2112 for (
auto &SU : InputSchedule) {
2113 unsigned ReadyCycle =
2115 SumBubbles += ReadyCycle - CurrCycle;
2117 ReadyCyclesSorted.insert(std::make_pair(SU.getInstr(), ReadyCycle));
2119 CurrCycle = ++ReadyCycle;
2142 unsigned SumBubbles = 0;
2144 unsigned CurrCycle = 0;
2145 for (
auto &
MI :
DAG) {
2149 unsigned ReadyCycle =
2151 SumBubbles += ReadyCycle - CurrCycle;
2153 ReadyCyclesSorted.insert(std::make_pair(SU->
getInstr(), ReadyCycle));
2155 CurrCycle = ++ReadyCycle;
2172 if (WavesAfter <
DAG.MinOccupancy)
2176 if (
DAG.MFI.isDynamicVGPREnabled()) {
2179 DAG.MFI.getDynamicVGPRBlockSize());
2182 if (BlocksAfter > BlocksBefore)
2219 <<
"\n\t *** In shouldRevertScheduling ***\n"
2220 <<
" *********** BEFORE UnclusteredHighRPStage ***********\n");
2224 <<
"\n *********** AFTER UnclusteredHighRPStage ***********\n");
2226 unsigned OldMetric = MBefore.
getMetric();
2227 unsigned NewMetric = MAfter.
getMetric();
2228 unsigned WavesBefore = std::min(
2229 S.getTargetOccupancy(),
2236 LLVM_DEBUG(
dbgs() <<
"\tMetric before " << MBefore <<
"\tMetric after "
2237 << MAfter <<
"Profit: " << Profit <<
"\n");
2268 unsigned WavesAfter) {
2275 LLVM_DEBUG(
dbgs() <<
"New pressure will result in more spilling.\n");
2287 "instruction number mismatch");
2288 if (MIOrder.
empty())
2301 if (MII != RegionEnd) {
2303 bool NonDebugReordered =
2304 !
MI->isDebugInstr() &&
2310 if (NonDebugReordered)
2311 DAG.LIS->handleMove(*
MI,
true);
2318 if (!
MI->isDebugInstr()) {
2320 SlotIndex PrevIdx =
DAG.LIS->getSlotIndexes()->getIndexBefore(*
MI);
2321 if (PrevIdx >= MIIdx)
2322 DAG.LIS->handleMove(*
MI,
true);
2326 if (
MI->isDebugInstr()) {
2333 Op.setIsUndef(
false);
2336 if (
DAG.ShouldTrackLaneMasks) {
2361 if (RD->
getOpcode() == AMDGPU::AV_MOV_B32_IMM_PSEUDO ||
2362 RD->
getOpcode() == AMDGPU::AV_MOV_B64_IMM_PSEUDO)
2369bool RewriteMFMAFormStage::hasUseRequiringVGPR(
2371 const SmallPtrSetImpl<MachineInstr *> &RewriteSet) {
2372 for (SlotIndex RDIdx : Src2ReachingDefs) {
2373 const MachineInstr *RD =
DAG.LIS->getInstructionFromIndex(RDIdx);
2375 findReachingUses(RD,
DAG.LIS, ReachingUses);
2376 for (
const MachineOperand *UseMO : ReachingUses) {
2388void RewriteMFMAFormStage::resetRewriteCandsToVGPR(
2389 ArrayRef<std::pair<MachineInstr *, unsigned>> RewriteCands) {
2390 for (
auto [
MI, OriginalOpcode] : RewriteCands) {
2393 DAG.MRI.getRegClass(
MI->getOperand(0).getReg());
2395 DAG.MRI.setRegClass(
MI->getOperand(0).getReg(), VDefRC);
2396 MI->setDesc(
TII->get(OriginalOpcode));
2398 MachineOperand *Src2 =
TII->getNamedOperand(*
MI, AMDGPU::OpName::src2);
2407 DAG.MRI.setRegClass(Src2->
getReg(), VUseRC);
2411bool RewriteMFMAFormStage::isRewriteCandidate(MachineInstr *
MI)
const {
2412 if (!
static_cast<const SIInstrInfo *
>(
DAG.TII)->isMAI(*
MI))
2417 Register DstReg =
MI->getOperand(0).getReg();
2418 for (
const MachineInstr &
UseMI :
DAG.MRI.use_nodbg_instructions(DstReg)) {
2425bool RewriteMFMAFormStage::initHeuristics(
2426 std::vector<std::pair<MachineInstr *, unsigned>> &RewriteCands,
2427 DenseMap<MachineBasicBlock *, std::set<Register>> &CopyForUse,
2428 SmallPtrSetImpl<MachineInstr *> &CopyForDef) {
2433 SmallPtrSet<MachineInstr *, 16> RewriteSet;
2434 DenseSet<Register> CandSrc2Regs;
2435 for (MachineBasicBlock &
MBB :
MF) {
2436 for (MachineInstr &
MI :
MBB) {
2437 if (!isRewriteCandidate(&
MI))
2440 MachineOperand *Src2 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src2);
2441 if (Src2 && Src2->
isReg())
2447 for (MachineBasicBlock &
MBB :
MF) {
2448 for (MachineInstr &
MI :
MBB) {
2449 if (!isRewriteCandidate(&
MI))
2453 assert(ReplacementOp != -1);
2455 RewriteCands.push_back({&
MI,
MI.getOpcode()});
2456 MI.setDesc(
TII->get(ReplacementOp));
2458 MachineOperand *Src2 =
TII->getNamedOperand(
MI, AMDGPU::OpName::src2);
2459 if (Src2->
isReg()) {
2461 findReachingDefs(*Src2,
DAG.LIS, Src2ReachingDefs);
2465 bool Src2NeedsVGPR = hasUseRequiringVGPR(Src2ReachingDefs, RewriteSet);
2466 Src2NeedsVGPRCache[&
MI] = Src2NeedsVGPR;
2468 for (SlotIndex RDIdx : Src2ReachingDefs) {
2469 MachineInstr *RD =
DAG.LIS->getInstructionFromIndex(RDIdx);
2470 if (!Src2NeedsVGPR &&
2477 MachineOperand &Dst =
MI.getOperand(0);
2480 findReachingUses(&
MI,
DAG.LIS, DstReachingUses);
2482 for (MachineOperand *RUOp : DstReachingUses) {
2483 MachineInstr *UserMI = RUOp->getParent();
2485 if (
TII->isMAI(*UserMI) && RewriteSet.
contains(UserMI))
2491 CopyForUse[UserMI->
getParent()].insert(RUOp->getReg());
2493 if (
TII->isMAI(*UserMI))
2497 findReachingDefs(*RUOp,
DAG.LIS, DstUsesReachingDefs);
2499 for (SlotIndex RDIndex : DstUsesReachingDefs) {
2500 MachineInstr *RD =
DAG.LIS->getInstructionFromIndex(RDIndex);
2501 if (
TII->isMAI(*RD))
2515 DAG.MRI.setRegClass(Dst.getReg(), ADefRC);
2516 if (Src2->
isReg()) {
2522 DAG.MRI.setRegClass(Src2->
getReg(), AUseRC);
2531int64_t RewriteMFMAFormStage::getRewriteCost(
2532 ArrayRef<std::pair<MachineInstr *, unsigned>> RewriteCands,
2533 const DenseMap<MachineBasicBlock *, std::set<Register>> &CopyForUse,
2534 const SmallPtrSetImpl<MachineInstr *> &CopyForDef) {
2535 MachineBlockFrequencyInfo *MBFI =
DAG.MBFI;
2537 int64_t BestSpillCost = 0;
2541 std::pair<unsigned, unsigned> MaxVectorRegs =
2542 ST.getMaxNumVectorRegs(
MF.getFunction());
2543 unsigned ArchVGPRThreshold = MaxVectorRegs.first;
2544 unsigned AGPRThreshold = MaxVectorRegs.second;
2545 unsigned CombinedThreshold =
ST.getMaxNumVGPRs(
MF);
2548 if (!RegionsWithExcessArchVGPR[Region])
2553 MF, ArchVGPRThreshold, AGPRThreshold, CombinedThreshold);
2561 MF, ArchVGPRThreshold, AGPRThreshold, CombinedThreshold);
2567 bool RelativeFreqIsDenom = EntryFreq > BlockFreq;
2568 uint64_t RelativeFreq = EntryFreq && BlockFreq
2569 ? (RelativeFreqIsDenom ? EntryFreq / BlockFreq
2570 : BlockFreq / EntryFreq)
2575 int64_t SpillCost = ((int)SpillCostAfter - (int)SpillCostBefore) * 2;
2578 if (RelativeFreqIsDenom)
2579 SpillCost /= (int64_t)RelativeFreq;
2581 SpillCost *= (int64_t)RelativeFreq;
2584 if (SpillCost > 0) {
2585 resetRewriteCandsToVGPR(RewriteCands);
2589 if (SpillCost < BestSpillCost)
2590 BestSpillCost = SpillCost;
2595 Cost = BestSpillCost;
2598 unsigned CopyCost = 0;
2602 for (MachineInstr *
DefMI : CopyForDef) {
2614 for (
auto &[UseBlock, UseRegs] : CopyForUse) {
2628 resetRewriteCandsToVGPR(RewriteCands);
2630 return Cost + CopyCost;
2633bool RewriteMFMAFormStage::rewrite(
2634 ArrayRef<std::pair<MachineInstr *, unsigned>> RewriteCands) {
2635 DenseMap<MachineInstr *, unsigned> FirstMIToRegion;
2636 DenseMap<MachineInstr *, unsigned> LastMIToRegion;
2644 if (
Entry.second !=
Entry.first->getParent()->end())
2687 DenseSet<Register> RewriteRegs;
2690 DenseMap<Register, Register> RedefMap;
2692 DenseMap<Register, DenseSet<MachineOperand *>>
ReplaceMap;
2694 DenseMap<Register, SmallPtrSet<MachineInstr *, 8>> ReachingDefCopyMap;
2697 DenseMap<unsigned, DenseMap<Register, SmallPtrSet<MachineOperand *, 8>>>
2702 SmallPtrSet<MachineInstr *, 16> RewriteCandsSet;
2703 DenseSet<Register> RewriteSrc2Regs;
2704 for (
auto &[
MI, OriginalOpcode] : RewriteCands) {
2706 MachineOperand *Src2 =
TII->getNamedOperand(*
MI, AMDGPU::OpName::src2);
2707 if (Src2 && Src2->
isReg())
2711 for (
auto &[
MI, OriginalOpcode] : RewriteCands) {
2713 if (ReplacementOp == -1)
2715 MI->setDesc(
TII->get(ReplacementOp));
2718 MachineOperand *Src2 =
TII->getNamedOperand(*
MI, AMDGPU::OpName::src2);
2719 if (Src2->
isReg()) {
2726 findReachingDefs(*Src2,
DAG.LIS, Src2ReachingDefs);
2727 SmallSetVector<MachineInstr *, 8> Src2DefsReplace;
2731 bool Src2NeedsVGPR = Src2NeedsVGPRCache.lookup(
MI);
2733 for (SlotIndex RDIndex : Src2ReachingDefs) {
2734 MachineInstr *RD =
DAG.LIS->getInstructionFromIndex(RDIndex);
2735 if (!Src2NeedsVGPR &&
2739 Src2DefsReplace.
insert(RD);
2742 if (!Src2DefsReplace.
empty()) {
2743 auto RI = RedefMap.
find(Src2Reg);
2744 if (RI != RedefMap.
end()) {
2745 MappedReg = RI->second;
2750 SRI->getEquivalentVGPRClass(Src2RC);
2753 MappedReg =
DAG.MRI.createVirtualRegister(VGPRRC);
2754 RedefMap[Src2Reg] = MappedReg;
2759 for (MachineInstr *RD : Src2DefsReplace) {
2761 if (ReachingDefCopyMap[Src2Reg].insert(RD).second) {
2762 MachineInstrBuilder VGPRCopy =
2765 .
addDef(MappedReg, {}, 0)
2766 .addUse(Src2Reg, {}, 0);
2767 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
2772 unsigned UpdateRegion = LastMIToRegion[RD];
2773 DAG.Regions[UpdateRegion].second = VGPRCopy;
2774 LastMIToRegion.
erase(RD);
2781 RewriteRegs.
insert(Src2Reg);
2791 MachineOperand *Dst = &
MI->getOperand(0);
2800 SmallVector<MachineInstr *, 8> DstUseDefsReplace;
2802 findReachingUses(
MI,
DAG.LIS, DstReachingUses);
2804 for (MachineOperand *RUOp : DstReachingUses) {
2805 MachineInstr *UserMI = RUOp->
getParent();
2807 if (
TII->isMAI(*UserMI) && RewriteCandsSet.
contains(UserMI))
2811 if (
find(DstReachingUseCopies, RUOp) == DstReachingUseCopies.
end())
2815 if (
TII->isMAI(*UserMI))
2819 findReachingDefs(*RUOp,
DAG.LIS, DstUsesReachingDefs);
2821 for (SlotIndex RDIndex : DstUsesReachingDefs) {
2822 MachineInstr *RD =
DAG.LIS->getInstructionFromIndex(RDIndex);
2823 if (
TII->isMAI(*RD))
2828 if (
find(DstUseDefsReplace, RD) == DstUseDefsReplace.
end())
2833 if (!DstUseDefsReplace.
empty()) {
2834 auto RI = RedefMap.
find(DstReg);
2835 if (RI != RedefMap.
end()) {
2836 MappedReg = RI->second;
2843 MappedReg =
DAG.MRI.createVirtualRegister(VGPRRC);
2844 RedefMap[DstReg] = MappedReg;
2849 for (MachineInstr *RD : DstUseDefsReplace) {
2851 if (ReachingDefCopyMap[DstReg].insert(RD).second) {
2852 MachineInstrBuilder VGPRCopy =
2855 .
addDef(MappedReg, {}, 0)
2856 .addUse(DstReg, {}, 0);
2857 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
2861 auto LMI = LastMIToRegion.
find(RD);
2862 if (LMI != LastMIToRegion.
end()) {
2863 unsigned UpdateRegion = LMI->second;
2864 DAG.Regions[UpdateRegion].second = VGPRCopy;
2865 LastMIToRegion.
erase(RD);
2871 DenseSet<MachineOperand *> &DstRegSet =
ReplaceMap[DstReg];
2874 MachineInstr *EarliestSameBlockUse =
nullptr;
2875 for (MachineOperand *RU : DstReachingUseCopies) {
2876 MachineBasicBlock *RUBlock = RU->getParent()->getParent();
2879 if (RUBlock !=
MI->getParent()) {
2885 if (!SameBlockCopyReg.
isValid()) {
2888 SameBlockCopyReg =
DAG.MRI.createVirtualRegister(VGPRRC);
2892 MachineInstr *UseInst = RU->getParent();
2893 if (!EarliestSameBlockUse ||
2895 DAG.LIS->getInstructionIndex(*UseInst),
2896 DAG.LIS->getInstructionIndex(*EarliestSameBlockUse)))
2897 EarliestSameBlockUse = UseInst;
2898 RU->setReg(SameBlockCopyReg);
2902 if (SameBlockCopyReg.
isValid()) {
2903 MachineInstrBuilder VGPRCopy =
2906 TII->get(TargetOpcode::COPY), SameBlockCopyReg)
2908 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
2913 RewriteRegs.
insert(DstReg);
2923 std::pair<unsigned, DenseMap<Register, SmallPtrSet<MachineOperand *, 8>>>;
2924 for (RUBType RUBlockEntry : ReachingUseTracker) {
2925 using RUDType = std::pair<Register, SmallPtrSet<MachineOperand *, 8>>;
2926 for (RUDType RUDst : RUBlockEntry.second) {
2927 MachineOperand *OpBegin = *RUDst.second.begin();
2928 SlotIndex InstPt =
DAG.LIS->getInstructionIndex(*OpBegin->
getParent());
2931 for (MachineOperand *User : RUDst.second) {
2932 SlotIndex NewInstPt =
DAG.LIS->getInstructionIndex(*
User->getParent());
2939 Register NewUseReg =
DAG.MRI.createVirtualRegister(VGPRRC);
2940 MachineInstr *UseInst =
DAG.LIS->getInstructionFromIndex(InstPt);
2942 MachineInstrBuilder VGPRCopy =
2945 .
addDef(NewUseReg, {}, 0)
2946 .addUse(RUDst.first, {}, 0);
2947 DAG.LIS->InsertMachineInstrInMaps(*VGPRCopy);
2951 auto FI = FirstMIToRegion.
find(UseInst);
2952 if (FI != FirstMIToRegion.
end()) {
2953 unsigned UpdateRegion = FI->second;
2954 DAG.Regions[UpdateRegion].first = VGPRCopy;
2955 FirstMIToRegion.
erase(UseInst);
2959 for (MachineOperand *User : RUDst.second) {
2960 User->setReg(NewUseReg);
2971 for (std::pair<Register, Register> NewDef : RedefMap) {
2976 for (MachineOperand *ReplaceOp :
ReplaceMap[OldReg])
2977 ReplaceOp->setReg(NewReg);
2981 for (
Register RewriteReg : RewriteRegs) {
2982 Register RegToRewrite = RewriteReg;
2985 auto RI = RedefMap.find(RewriteReg);
2986 if (RI != RedefMap.end())
2987 RegToRewrite = RI->second;
2992 DAG.MRI.setRegClass(RegToRewrite, AGPRRC);
2996 DAG.LIS->reanalyze(
DAG.MF);
2998 RegionPressureMap LiveInUpdater(&
DAG,
false);
2999 LiveInUpdater.buildLiveRegMap();
3002 DAG.LiveIns[Region] = LiveInUpdater.getLiveRegsForRegionIdx(Region);
3009unsigned PreRARematStage::getStageTargetOccupancy()
const {
3010 return TargetOcc ? *TargetOcc :
MFI.getMinWavesPerEU();
3013bool PreRARematStage::setObjective() {
3017 unsigned MaxSGPRs =
ST.getMaxNumSGPRs(
F);
3018 unsigned MaxVGPRs =
ST.getMaxNumVGPRs(
F);
3019 bool HasVectorRegisterExcess =
false;
3020 for (
unsigned I = 0,
E =
DAG.Regions.size();
I !=
E; ++
I) {
3021 const GCNRegPressure &
RP =
DAG.Pressure[
I];
3022 GCNRPTarget &
Target = RPTargets.emplace_back(MaxSGPRs, MaxVGPRs,
MF, RP);
3024 TargetRegions.set(
I);
3025 HasVectorRegisterExcess |=
Target.hasVectorRegisterExcess();
3028 if (HasVectorRegisterExcess ||
DAG.MinOccupancy >=
MFI.getMaxWavesPerEU()) {
3031 TargetOcc = std::nullopt;
3035 TargetOcc =
DAG.MinOccupancy + 1;
3036 const unsigned VGPRBlockSize =
MFI.getDynamicVGPRBlockSize();
3037 MaxSGPRs =
ST.getMaxNumSGPRs(*TargetOcc,
false);
3038 MaxVGPRs =
ST.getMaxNumVGPRs(*TargetOcc, VGPRBlockSize);
3039 for (
auto [
I, Target] :
enumerate(RPTargets)) {
3040 Target.setTarget(MaxSGPRs, MaxVGPRs);
3042 TargetRegions.set(
I);
3046 return TargetRegions.any();
3049bool PreRARematStage::ScoredRemat::maybeBeneficial(
3051 for (
unsigned I : TargetRegions.set_bits()) {
3052 if (Live[
I] && RPTargets[
I].isSaveBeneficial(RPSave))
3065 const unsigned NumRegions =
DAG.Regions.size();
3069 for (
unsigned I = 0;
I < NumRegions; ++
I) {
3073 if (BlockFreq && BlockFreq <
MinFreq)
3082 if (
MinFreq >= ScaleFactor * ScaleFactor) {
3083 for (uint64_t &Freq :
Regions)
3084 Freq /= ScaleFactor;
3090void PreRARematStage::ScoredRemat::init(
const FreqInfo &Freq,
3095 assert(Reg.Uses.size() == 1 &&
"expected users in single region");
3096 const unsigned UseRegion = Reg.Uses.begin()->first;
3101 for (
unsigned I : Live.set_bits()) {
3104 if (!LiveIn[
I] || !LiveOut[
I] ||
I == UseRegion)
3105 UnpredictableRPSave.set(
I);
3112 int64_t DefOrMin = std::max(Freq.
Regions[Reg.DefRegion], Freq.
MinFreq);
3113 int64_t UseOrMax = Freq.
Regions[UseRegion];
3116 FreqDiff = DefOrMin - UseOrMax;
3119void PreRARematStage::ScoredRemat::update(
const BitVector &TargetRegions,
3121 const FreqInfo &FreqInfo,
3125 for (
unsigned I : TargetRegions.
set_bits()) {
3134 if (!NumRegsBenefit)
3138 RegionImpact += (UnpredictableRPSave[
I] ? 1 : 2) * NumRegsBenefit;
3141 uint64_t Freq = FreqInfo.
Regions[
I];
3142 if (UnpredictableRPSave[
I]) {
3147 MaxFreq = std::max(MaxFreq, Freq);
3152void PreRARematStage::ScoredRemat::rematerialize(
3153 Rematerializer &Remater)
const {
3154 const Rematerializer::Reg &
Reg = Remater.getReg(RegIdx);
3155 Rematerializer::DependencyReuseInfo DRI;
3156 for (RegisterIdx DepRegIdx :
Reg.Dependencies)
3157 DRI.
reuse(DepRegIdx);
3158 unsigned UseRegion =
Reg.Uses.begin()->first;
3159 Remater.rematerializeToRegion(RegIdx, UseRegion, DRI);
3162void PreRARematStage::updateRPTargets(
const BitVector &Regions,
3163 const GCNRegPressure &RPSave) {
3165 RPTargets[
I].saveRP(RPSave);
3166 if (TargetRegions[
I] && RPTargets[
I].satisfied()) {
3168 TargetRegions.reset(
I);
3173bool PreRARematStage::updateAndVerifyRPTargets(
const BitVector &Regions) {
3174 bool TooOptimistic =
false;
3176 GCNRPTarget &
Target = RPTargets[
I];
3182 if (!TargetRegions[
I] && !
Target.satisfied()) {
3184 TooOptimistic =
true;
3185 TargetRegions.set(
I);
3188 return TooOptimistic;
3191void PreRARematStage::removeFromLiveMaps(
Register Reg,
const BitVector &LiveIn,
3192 const BitVector &LiveOut) {
3194 LiveOut.
size() ==
DAG.Regions.size() &&
"region num mismatch");
3198 DAG.RegionLiveOuts.getLiveRegsForRegionIdx(
I).erase(
Reg);
3201void PreRARematStage::addToLiveMaps(
Register Reg, LaneBitmask Mask,
3202 const BitVector &LiveIn,
3203 const BitVector &LiveOut) {
3205 LiveOut.
size() ==
DAG.Regions.size() &&
"region num mismatch");
3206 std::pair<Register, LaneBitmask> LiveReg(
Reg, Mask);
3208 DAG.LiveIns[
I].insert(LiveReg);
3210 DAG.RegionLiveOuts.getLiveRegsForRegionIdx(
I).insert(LiveReg);
3222 if (
DAG.MinOccupancy >= *TargetOcc)
3226 for (
const auto &[
RegionIdx, OrigMIOrder, MaxPressure] : RegionReverts) {
3236 if (AchievedOcc >= *TargetOcc) {
3237 DAG.setTargetOccupancy(AchievedOcc);
3242 DAG.setTargetOccupancy(*TargetOcc - 1);
3247 assert(Rollback &&
"rollbacker should be defined");
3248 Rollback->Listener.rollback(Remater);
3249 for (
const auto &[RegIdx, LiveIn, LiveOut] : Rollback->LiveMapUpdates) {
3250 const Rematerializer::Reg &
Reg = Remater.getReg(RegIdx);
3251 addToLiveMaps(
Reg.getDefReg(),
Reg.Mask, LiveIn, LiveOut);
3254#ifdef EXPENSIVE_CHECKS
3259 for (
unsigned I : RescheduleRegions.set_bits())
3260 DAG.Pressure[
I] =
DAG.getRealRegPressure(
I);
3265void GCNScheduleDAGMILive::setTargetOccupancy(
unsigned TargetOccupancy) {
3266 MinOccupancy = TargetOccupancy;
3267 if (
MFI.getOccupancy() < TargetOccupancy)
3268 MFI.increaseOccupancy(
MF, MinOccupancy);
3270 MFI.limitOccupancy(MinOccupancy);
3287 if (HasIGLPInstrs) {
3288 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 cl::opt< unsigned, false, VGPRThresholdParser > VGPRThresholdPercentOpt("amdgpu-vgpr-threshold-percent", cl::Hidden, cl::desc("Percent of VGPR limits that we should use as RP threshold " "during scheduling. We have two limits relevant to scheduling: " "Critical (avoid decreasing occupancy), Excess (avoid spilling). " "This flag scales both limits back by an equal percent: (0 = use " " default calculation, 1-100 = use percentage), default: 0"), cl::init(0))
static MachineInstr * getLastMIForRegion(MachineBasicBlock::iterator RegionBegin, MachineBasicBlock::iterator RegionEnd)
static bool shouldCheckPending(SchedBoundary &Zone, const TargetSchedModel *SchedModel)
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 > 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 > 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 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.
static llvm::Error parse(GsymDataExtractor &Data, uint64_t BaseAddr, LineEntryCallback const &Callback)
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
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)
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.
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...
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)
This namespace contains all of the command line option processing machinery.
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.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
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
@ 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.
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)
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 ...