28#define DEBUG_TYPE "igrouplp"
34 cl::desc(
"Whether to use the exponential time solver to fit "
35 "the instructions to the pipeline as closely as "
41 cl::desc(
"The maximum number of scheduling group conflicts "
42 "which we attempt to solve with the exponential time "
43 "exact solver. Problem sizes greater than this will"
44 "be solved by the less accurate greedy algorithm. Selecting "
45 "solver by size is superseded by manually selecting "
46 "the solver (e.g. by amdgpu-igrouplp-exact-solver"));
50 cl::desc(
"The amount of branches that we are willing to explore with"
51 "the exact algorithm before giving up."));
55 cl::desc(
"Whether to use the cost heuristic to make choices as we "
56 "traverse the search space using the exact solver. Defaulted "
57 "to on, and if turned off, we will use the node order -- "
58 "attempting to put the later nodes in the later sched groups. "
59 "Experimentally, results are mixed, so this should be set on a "
60 "case-by-case basis."));
64enum class SchedGroupMask {
79 DS_READ | DS_WRITE |
TRANS | LDSDMA,
88class InstructionRule {
94 std::optional<SmallVector<SUnit *, 4>> Cache;
104 bool NeedsCache =
false)
111 virtual ~InstructionRule() =
default;
124 SchedGroupMask SGMask;
127 std::optional<unsigned> MaxSize;
140 static unsigned NumSchedGroups;
157 bool canAddSU(
SUnit &SU)
const;
162 void link(
SUnit &SU,
bool MakePred =
false);
166 int link(
SUnit &SU,
bool MakePred,
167 std::list<std::pair<SUnit *, SUnit *>> &AddedEdges);
176 void link(SchedGroup &OtherGroup);
179 bool isFull()
const {
return MaxSize && Collection.
size() >= *MaxSize; }
185 void addRule(std::shared_ptr<InstructionRule> NewRule) {
190 bool allowedByRules(
const SUnit *SU,
192 for (
auto &Rule : Rules) {
193 if (!Rule->apply(SU, Collection, SyncPipe))
200 void add(
SUnit &SU) {
202 <<
format_hex((
int)SGMask, 10,
true) <<
" adding "
208 void pop() { Collection.
pop_back(); }
211 void findCandidateSUnits(
T Begin,
T End,
212 SUnitsToCandidateSGsMap &SyncedInstrs);
217 void findCandidateSUnits(SUnitsToCandidateSGsMap &SyncedInstrs);
219 int getSyncID() {
return SyncID; }
221 int getSGID() {
return SGID; }
223 SchedGroupMask
getMask() {
return SGMask; }
225 SchedGroup(SchedGroupMask SGMask, std::optional<unsigned> MaxSize,
227 : SGMask(SGMask), MaxSize(MaxSize), DAG(DAG),
TII(
TII) {
228 SGID = NumSchedGroups++;
231 SchedGroup(SchedGroupMask SGMask, std::optional<unsigned> MaxSize,
int SyncID,
233 : SGMask(SGMask), MaxSize(MaxSize), SyncID(SyncID), DAG(DAG),
TII(
TII) {
234 SGID = NumSchedGroups++;
238using SUToCandSGsPair = std::pair<SUnit *, SmallVector<int, 4>>;
250class PipelineSolver {
263 bool NeedsSolver =
false;
267 unsigned computeProblemSize();
278 int CurrConflInstNo = 0;
280 int CurrSyncGroupIdx = 0;
282 int BeginSyncGroupIdx = 0;
288 bool IsBottomUp =
true;
291 void advancePosition();
294 void retreatPosition();
303 template <
typename T>
304 void greedyFind(std::list<std::pair<SUnit *, SUnit *>> &AddedEdges,
T I,
T E);
309 template <
typename T>
316 template <
typename T>
void linkSchedGroups(
T I,
T E);
320 std::list<std::pair<SUnit *, SUnit *>> &AddedEdges);
326 class EdgeSetBuilder {
332 bool Initialized =
false;
336 template <
bool ComputePreds>
350 : SU(SU), SyncPipeline(SyncPipeline), IsBottomUp(IsBottomUp) {}
356 int build(
int SGID, std::list<std::pair<SUnit *, SUnit *>> &NewEdges);
359 template <
typename T>
361 std::list<std::pair<SUnit *, SUnit *>> &NewEdges);
367 template <
typename T>
368 int linkSUnit(
SUnit *SU,
int SGID,
369 std::list<std::pair<SUnit *, SUnit *>> &AddedEdges,
T I,
T E);
371 void removeEdges(
const std::list<std::pair<SUnit *, SUnit *>> &AddedEdges);
373 void convertSyncMapsToArrays();
385 : DAG(DAG), SyncedInstrs(SyncedInstrs),
386 SyncedSchedGroups(SyncedSchedGroups), IsBottomUp(IsBottomUp) {
388 for (
auto &PipelineInstrs : SyncedInstrs) {
389 if (!PipelineInstrs.second.
empty()) {
398 convertSyncMapsToArrays();
400 CurrPipeline = BestPipeline;
402 while (
static_cast<size_t>(BeginSyncGroupIdx) < PipelineInstrs.
size() &&
403 PipelineInstrs[BeginSyncGroupIdx].
empty())
406 if (
static_cast<size_t>(BeginSyncGroupIdx) >= PipelineInstrs.
size())
411void PipelineSolver::reset() {
413 for (
auto &SyncPipeline : CurrPipeline) {
414 for (
auto &SG : SyncPipeline) {
416 SG.Collection.
clear();
420 if (SchedBarr != TempCollection.
end())
421 SG.Collection.push_back(*SchedBarr);
425 CurrSyncGroupIdx = BeginSyncGroupIdx;
430void PipelineSolver::convertSyncMapsToArrays() {
431 for (
auto &SyncPipe : SyncedSchedGroups) {
432 BestPipeline.insert(BestPipeline.begin(), SyncPipe.second);
435 int PipelineIDx = SyncedInstrs.size() - 1;
436 PipelineInstrs.resize(SyncedInstrs.size());
437 for (
auto &SyncInstrMap : SyncedInstrs) {
438 for (
auto &SUsToCandSGs : SyncInstrMap.second) {
439 if (PipelineInstrs[PipelineIDx].empty()) {
440 PipelineInstrs[PipelineIDx].push_back(
441 std::pair(SUsToCandSGs.first, SUsToCandSGs.second));
444 auto *SortPosition = PipelineInstrs[PipelineIDx].begin();
447 while (SortPosition != PipelineInstrs[PipelineIDx].end() &&
448 SUsToCandSGs.first->NodeNum > SortPosition->first->NodeNum)
450 PipelineInstrs[PipelineIDx].insert(
451 SortPosition, std::pair(SUsToCandSGs.first, SUsToCandSGs.second));
457template <
typename T>
void PipelineSolver::linkSchedGroups(
T I,
T E) {
458 for (;
I !=
E; ++
I) {
460 for (
auto J = std::next(
I); J !=
E; ++J) {
467void PipelineSolver::makePipeline() {
469 for (
auto &SyncPipeline : BestPipeline) {
471 for (
auto &SG : SyncPipeline) {
474 SUnit *SGBarr =
nullptr;
475 for (
auto &SU : SG.Collection) {
476 if (SU->getInstr()->getOpcode() == AMDGPU::SCHED_GROUP_BARRIER)
483 SG.link(*SGBarr,
false);
487 for (
auto &SyncPipeline : BestPipeline) {
488 IsBottomUp ? linkSchedGroups(SyncPipeline.rbegin(), SyncPipeline.rend())
489 : linkSchedGroups(SyncPipeline.begin(), SyncPipeline.end());
494int PipelineSolver::linkSUnit(
495 SUnit *SU,
int SGID, std::list<std::pair<SUnit *, SUnit *>> &AddedEdges,
497 bool MakePred =
false;
500 if (
I->getSGID() == SGID) {
505 AddedCost += Group.link(*SU, MakePred, AddedEdges);
511template <
bool ComputePreds>
512void PipelineSolver::EdgeSetBuilder::computeReachable(
514 if (!Reachable.insert(Start).second)
519 while (!WorkList.
empty()) {
522 for (
const SDep &Dep : ComputePreds ? Current->
Preds : Current->
Succs) {
523 if (Reachable.insert(Dep.getSUnit()).second)
531 computeReachable<
true>(Preds, Start);
536 computeReachable<
false>(Succs, Start);
539int PipelineSolver::EdgeSetBuilder::build(
540 int SGID, std::list<std::pair<SUnit *, SUnit *>> &NewEdges) {
542 computePreds(InitialPreds, SU);
543 computeSuccs(Succs, SU);
548 return IsBottomUp ? buildImpl(SGID,
reverse(SyncPipeline), NewEdges)
556int PipelineSolver::EdgeSetBuilder::buildImpl(
558 std::list<std::pair<SUnit *, SUnit *>> &NewEdges) {
576 bool MakePred =
false;
577 for (SchedGroup &SG : SchedGroups) {
578 if (SG.getSGID() == SGID) {
583 for (
SUnit *
A : SG.Collection) {
584 if (
A->getInstr()->getOpcode() == AMDGPU::SCHED_GROUP_BARRIER)
595 NewEdges.emplace_back(SU,
A);
604 NewEdges.emplace_back(
A, SU);
605 computePreds(Preds,
A);
612int PipelineSolver::addEdges(
614 std::list<std::pair<SUnit *, SUnit *>> &AddedEdges) {
624 return IsBottomUp ? linkSUnit(SU, SGID, AddedEdges, SyncPipeline.
rbegin(),
626 : linkSUnit(SU, SGID, AddedEdges, SyncPipeline.
begin(),
630void PipelineSolver::removeEdges(
631 const std::list<std::pair<SUnit *, SUnit *>> &EdgesToRemove) {
634 for (
auto &PredSuccPair : EdgesToRemove) {
635 SUnit *Pred = PredSuccPair.first;
636 SUnit *Succ = PredSuccPair.second;
639 return P.getSUnit() == Pred && P.isArtificial();
641 if (Match != Succ->
Preds.end())
646void PipelineSolver::advancePosition() {
649 if (
static_cast<size_t>(CurrConflInstNo) >=
650 PipelineInstrs[CurrSyncGroupIdx].
size()) {
654 while (
static_cast<size_t>(CurrSyncGroupIdx) < PipelineInstrs.size() &&
655 PipelineInstrs[CurrSyncGroupIdx].empty())
660void PipelineSolver::retreatPosition() {
661 assert(CurrConflInstNo >= 0);
662 assert(CurrSyncGroupIdx >= 0);
664 if (CurrConflInstNo > 0) {
669 if (CurrConflInstNo == 0) {
672 if (CurrSyncGroupIdx == BeginSyncGroupIdx)
677 while (PipelineInstrs[CurrSyncGroupIdx].empty())
680 CurrConflInstNo = PipelineInstrs[CurrSyncGroupIdx].size() - 1;
684bool PipelineSolver::checkOptimal() {
685 if (
static_cast<size_t>(CurrSyncGroupIdx) == PipelineInstrs.size()) {
686 if (BestCost == -1 || CurrCost < BestCost) {
687 BestPipeline = CurrPipeline;
694 bool DoneExploring =
false;
695 if (MaxBranchesExplored > 0 && BranchesExplored >= MaxBranchesExplored)
696 DoneExploring =
true;
698 return (DoneExploring || BestCost == 0);
702void PipelineSolver::populateReadyList(
704 SUToCandSGsPair CurrSU = PipelineInstrs[CurrSyncGroupIdx][CurrConflInstNo];
705 auto SyncPipeline = CurrPipeline[CurrSyncGroupIdx];
706 assert(CurrSU.second.size() >= 1);
708 for (;
I !=
E; ++
I) {
709 std::list<std::pair<SUnit *, SUnit *>> AddedEdges;
711 SchedGroup *Match =
llvm::find_if(SyncPipeline, [CandSGID](SchedGroup &SG) {
712 return SG.getSGID() == CandSGID;
717 if (Match->isFull()) {
718 ReadyList.push_back(std::pair(*
I, MissPenalty));
722 int TempCost = addEdges(SyncPipeline, CurrSU.first, CandSGID, AddedEdges);
723 ReadyList.push_back(std::pair(*
I, TempCost));
724 removeEdges(AddedEdges);
726 ReadyList.push_back(std::pair(*
I, -1));
732 assert(ReadyList.size() == CurrSU.second.size());
735bool PipelineSolver::solveExact() {
739 if (
static_cast<size_t>(CurrSyncGroupIdx) == PipelineInstrs.size())
742 assert(
static_cast<size_t>(CurrSyncGroupIdx) < PipelineInstrs.size());
743 assert(
static_cast<size_t>(CurrConflInstNo) <
744 PipelineInstrs[CurrSyncGroupIdx].
size());
745 SUToCandSGsPair CurrSU = PipelineInstrs[CurrSyncGroupIdx][CurrConflInstNo];
747 <<
") in Pipeline # " << CurrSyncGroupIdx <<
"\n");
752 IsBottomUp ? populateReadyList(ReadyList, CurrSU.second.
rbegin(),
753 CurrSU.second.rend())
754 : populateReadyList(ReadyList, CurrSU.second.
begin(),
755 CurrSU.second.end());
757 auto *
I = ReadyList.
begin();
758 auto *
E = ReadyList.
end();
759 for (;
I !=
E; ++
I) {
763 if (BestCost != -1 && (CurrCost +
I->second > BestCost))
766 int CandSGID =
I->first;
768 std::list<std::pair<SUnit *, SUnit *>> AddedEdges;
769 auto &SyncPipeline = CurrPipeline[CurrSyncGroupIdx];
770 SchedGroup *Match =
llvm::find_if(SyncPipeline, [CandSGID](SchedGroup &SG) {
771 return SG.getSGID() == CandSGID;
778 if (!Match->allowedByRules(CurrSU.first, SyncPipeline))
782 << (
int)Match->getMask() <<
"and ID " << CandSGID
784 Match->add(*CurrSU.first);
785 AddedCost = addEdges(SyncPipeline, CurrSU.first, CandSGID, AddedEdges);
786 LLVM_DEBUG(
dbgs() <<
"Cost of Assignment: " << AddedCost <<
"\n");
787 CurrCost += AddedCost;
790 bool FinishedExploring =
false;
793 if (CurrCost < BestCost || BestCost == -1) {
795 FinishedExploring = BestCost != 0;
796 if (!FinishedExploring)
802 CurrCost -= AddedCost;
803 removeEdges(AddedEdges);
805 CurrPipeline[CurrSyncGroupIdx] = SyncPipeline;
806 if (FinishedExploring)
813 CurrCost += MissPenalty;
816 LLVM_DEBUG(
dbgs() <<
"NOT Assigned (" << CurrSU.first->NodeNum <<
")\n");
818 bool FinishedExploring =
false;
819 if (CurrCost < BestCost || BestCost == -1) {
821 bool FinishedExploring = BestCost != 0;
822 if (!FinishedExploring)
828 CurrCost -= MissPenalty;
829 return FinishedExploring;
833void PipelineSolver::greedyFind(
834 std::list<std::pair<SUnit *, SUnit *>> &AddedEdges,
T I,
T E) {
835 SUToCandSGsPair CurrSU = PipelineInstrs[CurrSyncGroupIdx][CurrConflInstNo];
839 std::list<std::pair<SUnit *, SUnit *>> Edges;
842 std::optional<GroupInfo> Best;
844 auto &SyncPipeline = CurrPipeline[CurrSyncGroupIdx];
846 <<
") in Pipeline # " << CurrSyncGroupIdx <<
"\n");
848 EdgeSetBuilder Builder(CurrSU.first, SyncPipeline, IsBottomUp);
854 for (;
I !=
E; ++
I) {
856 SchedGroup *Match =
llvm::find_if(SyncPipeline, [CandSGID](SchedGroup &SG) {
857 return SG.getSGID() == CandSGID;
861 LLVM_DEBUG(
dbgs() <<
"Trying SGID # " << CandSGID <<
" with Mask "
862 << (
int)Match->getMask() <<
"\n");
864 if (Match->isFull()) {
868 if (!Match->allowedByRules(CurrSU.first, SyncPipeline)) {
869 LLVM_DEBUG(
dbgs() <<
"SGID # " << CandSGID <<
" has conflicting rule\n");
873 std::list<std::pair<SUnit *, SUnit *>> TempEdges;
874 int TempCost = Builder.build(CandSGID, TempEdges);
877 if (!Best || TempCost < Best->Cost) {
878 Best = {Match, TempEdges, TempCost};
885 SchedGroup *SG = Best->SG;
886 std::list<std::pair<SUnit *, SUnit *>> &Edges = Best->Edges;
888 SG->add(*CurrSU.first);
889 if (AddedEdges.empty())
892 AddedEdges.splice(std::prev(AddedEdges.cend()), Edges);
894 for (
const std::pair<SUnit *, SUnit *> &
E : Edges) {
895 if (!SG->tryAddEdge(
E.first,
E.second))
899 LLVM_DEBUG(
dbgs() <<
"Best Group has ID: " << SG->getSGID() <<
" and Mask"
900 << (
int)SG->getMask() <<
"\n");
901 BestCost += Best->Cost;
903 BestCost += MissPenalty;
906bool PipelineSolver::solveGreedy() {
908 std::list<std::pair<SUnit *, SUnit *>> AddedEdges;
910 while (
static_cast<size_t>(CurrSyncGroupIdx) < PipelineInstrs.size()) {
911 SUToCandSGsPair CurrSU = PipelineInstrs[CurrSyncGroupIdx][CurrConflInstNo];
913 ? greedyFind(AddedEdges, CurrSU.second.rbegin(), CurrSU.second.rend())
914 : greedyFind(AddedEdges, CurrSU.second.begin(), CurrSU.second.end());
917 BestPipeline = CurrPipeline;
918 removeEdges(AddedEdges);
922unsigned PipelineSolver::computeProblemSize() {
923 unsigned ProblemSize = 0;
924 for (
auto &PipeConflicts : PipelineInstrs) {
925 ProblemSize += PipeConflicts.size();
931void PipelineSolver::solve() {
935 unsigned ProblemSize = computeProblemSize();
938 bool BelowCutoff = (CutoffForExact > 0) && ProblemSize <= CutoffForExact;
939 MissPenalty = (ProblemSize / 2) + 1;
942 if (EnableExactSolver || BelowCutoff) {
946 LLVM_DEBUG(
dbgs() <<
"Greedy produced best cost of " << BestCost <<
"\n");
950 LLVM_DEBUG(
dbgs() <<
"Exact produced best cost of " << BestCost <<
"\n");
955 LLVM_DEBUG(
dbgs() <<
"Greedy produced best cost of " << BestCost <<
"\n");
972 virtual bool applyIGLPStrategy(
981 bool IsBottomUp =
true;
986 virtual ~IGLPStrategy() =
default;
989class MFMASmallGemmOpt final :
public IGLPStrategy {
992 bool applyIGLPStrategy(
1003 : IGLPStrategy(DAG,
TII) {
1008bool MFMASmallGemmOpt::applyIGLPStrategy(
1013 unsigned MFMACount = 0;
1015 if (
TII->isMFMAorWMMA(
I))
1018 const unsigned PipelineSyncID = 0;
1019 SchedGroup *SG =
nullptr;
1020 for (
unsigned I = 0;
I < MFMACount * 3; ++
I) {
1021 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1022 SchedGroupMask::DS, 2, PipelineSyncID, DAG,
TII);
1023 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1025 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1026 SchedGroupMask::MFMA, 1, PipelineSyncID, DAG,
TII);
1027 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1033class MFMAExpInterleaveOpt final :
public IGLPStrategy {
1036 static unsigned TransPipeCount;
1038 static unsigned MFMAPipeCount;
1040 static unsigned AddPipeCount;
1042 static unsigned MFMAEnablement;
1044 static unsigned ExpRequirement;
1046 static unsigned MFMAChains;
1051 static bool HasChainBetweenCvt;
1053 static std::optional<unsigned> FirstPipeDSR;
1062 class IsPipeExp final :
public InstructionRule {
1067 auto *DAG = SyncPipe[0].DAG;
1069 if (Cache->empty()) {
1070 auto I = DAG->SUnits.rbegin();
1071 auto E = DAG->SUnits.rend();
1072 for (;
I !=
E;
I++) {
1073 if (
TII->isMFMAorWMMA(*
I->getInstr()))
1074 Cache->push_back(&*
I);
1080 auto Reaches =
any_of(*Cache, [&SU, &DAG](
SUnit *TargetSU) {
1081 return DAG->IsReachable(TargetSU,
const_cast<SUnit *
>(SU));
1086 IsPipeExp(
const SIInstrInfo *
TII,
unsigned SGID,
bool NeedsCache =
false)
1087 : InstructionRule(
TII, SGID, NeedsCache) {}
1092 class EnablesNthMFMA final :
public InstructionRule {
1099 bool FoundTrans =
false;
1100 unsigned Counter = 1;
1101 auto *DAG = SyncPipe[0].DAG;
1103 if (Cache->empty()) {
1104 auto I = DAG->SUnits.begin();
1105 auto E = DAG->SUnits.end();
1106 for (;
I !=
E;
I++) {
1107 if (FoundTrans &&
TII->isMFMAorWMMA(*
I->getInstr())) {
1109 Cache->push_back(&*
I);
1114 if (!FoundTrans &&
TII->isTRANS(
I->getInstr()->getOpcode()))
1121 return DAG->IsReachable((*Cache)[0],
const_cast<SUnit *
>(SU));
1125 bool NeedsCache =
false)
1131 class EnablesNthMFMAInChain final :
public InstructionRule {
1139 auto *DAG = SyncPipe[0].DAG;
1141 if (!SU || !
TII->isMFMAorWMMA(*ChainSeed->
getInstr()))
1144 if (Cache->empty()) {
1145 auto *TempSU = ChainSeed;
1150 for (
auto &Succ : TempSU->Succs) {
1151 if (
TII->isMFMAorWMMA(*Succ.getSUnit()->getInstr())) {
1152 TempSU = Succ.getSUnit();
1161 Cache->push_back(TempSU);
1167 return DAG->IsReachable((*Cache)[0],
const_cast<SUnit *
>(SU));
1170 EnablesNthMFMAInChain(
unsigned Number,
SUnit *ChainSeed,
1172 bool NeedsCache =
false)
1174 ChainSeed(ChainSeed) {}
1180 class LessThanNSuccs final :
public InstructionRule {
1183 bool HasIntermediary =
false;
1188 if (!SyncPipe.
size())
1192 return Succ.getKind() == SDep::Data;
1194 if (SuccSize >=
Size)
1197 if (HasIntermediary) {
1198 for (
auto Succ : SU->
Succs) {
1201 return SuccSucc.getKind() == SDep::Data;
1203 if (SuccSize >=
Size)
1211 bool HasIntermediary =
false,
bool NeedsCache =
false)
1212 : InstructionRule(
TII, SGID, NeedsCache),
Size(
Size),
1213 HasIntermediary(HasIntermediary) {}
1220 class GreaterThanOrEqualToNSuccs final :
public InstructionRule {
1223 bool HasIntermediary =
false;
1228 if (!SyncPipe.
size())
1232 return Succ.getKind() == SDep::Data;
1234 if (SuccSize >=
Size)
1237 if (HasIntermediary) {
1238 for (
auto Succ : SU->
Succs) {
1241 return SuccSucc.getKind() == SDep::Data;
1243 if (SuccSize >=
Size)
1251 unsigned SGID,
bool HasIntermediary =
false,
1252 bool NeedsCache =
false)
1253 : InstructionRule(
TII, SGID, NeedsCache),
Size(
Size),
1254 HasIntermediary(HasIntermediary) {}
1258 class IsCvt final :
public InstructionRule {
1263 return Opc == AMDGPU::V_CVT_F16_F32_e32 ||
1264 Opc == AMDGPU::V_CVT_I32_F32_e32;
1266 IsCvt(
const SIInstrInfo *
TII,
unsigned SGID,
bool NeedsCache =
false)
1267 : InstructionRule(
TII, SGID, NeedsCache) {}
1271 class IsFMA final :
public InstructionRule {
1278 IsFMA(
const SIInstrInfo *
TII,
unsigned SGID,
bool NeedsCache =
false)
1279 : InstructionRule(
TII, SGID, NeedsCache) {}
1283 class IsPipeAdd final :
public InstructionRule {
1289 IsPipeAdd(
const SIInstrInfo *
TII,
unsigned SGID,
bool NeedsCache =
false)
1290 : InstructionRule(
TII, SGID, NeedsCache) {}
1295 class IsSuccOfPrevNthGroup final :
public InstructionRule {
1297 unsigned Distance = 1;
1302 SchedGroup *OtherGroup =
nullptr;
1303 if (!SyncPipe.
size())
1306 for (
auto &PipeSG : SyncPipe) {
1307 if ((
unsigned)PipeSG.getSGID() == SGID - Distance)
1308 OtherGroup = &PipeSG;
1313 if (!OtherGroup->Collection.size())
1316 for (
auto &OtherEle : OtherGroup->Collection) {
1317 for (
auto &Succ : OtherEle->Succs) {
1318 if (Succ.getSUnit() == SU && Succ.getKind() ==
SDep::Data)
1326 unsigned SGID,
bool NeedsCache =
false)
1327 : InstructionRule(
TII, SGID, NeedsCache), Distance(Distance) {}
1332 class IsReachableFromPrevNthGroup final :
public InstructionRule {
1334 unsigned Distance = 1;
1339 SchedGroup *OtherGroup =
nullptr;
1340 if (!SyncPipe.
size())
1343 for (
auto &PipeSG : SyncPipe) {
1344 if ((
unsigned)PipeSG.getSGID() == SGID - Distance)
1345 OtherGroup = &PipeSG;
1350 if (!OtherGroup->Collection.size())
1353 auto *DAG = SyncPipe[0].DAG;
1355 for (
auto &OtherEle : OtherGroup->Collection)
1356 if (DAG->IsReachable(
const_cast<SUnit *
>(SU), OtherEle))
1361 IsReachableFromPrevNthGroup(
unsigned Distance,
const SIInstrInfo *
TII,
1362 unsigned SGID,
bool NeedsCache =
false)
1363 : InstructionRule(
TII, SGID, NeedsCache), Distance(Distance) {}
1367 class OccursAtOrAfterNode final :
public InstructionRule {
1378 bool NeedsCache =
false)
1384 class IsExactMFMA final :
public InstructionRule {
1392 if (!SU || !
TII->isMFMAorWMMA(*ChainSeed->
getInstr()))
1395 if (Cache->empty()) {
1396 auto *TempSU = ChainSeed;
1401 for (
auto &Succ : TempSU->Succs) {
1402 if (
TII->isMFMAorWMMA(*Succ.getSUnit()->getInstr())) {
1403 TempSU = Succ.getSUnit();
1412 Cache->push_back(TempSU);
1418 return (*Cache)[0] == SU;
1422 unsigned SGID,
bool NeedsCache =
false)
1424 ChainSeed(ChainSeed) {}
1430 class OccursAfterExp final :
public InstructionRule {
1435 auto *DAG = SyncPipe[0].DAG;
1436 if (Cache->empty()) {
1437 for (
auto &SU : DAG->SUnits)
1439 Cache->push_back(&SU);
1446 return SU->
NodeNum > (*Cache)[0]->NodeNum;
1450 bool NeedsCache =
false)
1451 : InstructionRule(
TII, SGID, NeedsCache) {}
1455 bool applyIGLPStrategy(
1464 : IGLPStrategy(DAG,
TII) {
1469unsigned MFMAExpInterleaveOpt::TransPipeCount = 0;
1470unsigned MFMAExpInterleaveOpt::MFMAPipeCount = 0;
1471unsigned MFMAExpInterleaveOpt::AddPipeCount = 0;
1472unsigned MFMAExpInterleaveOpt::MFMAEnablement = 0;
1473unsigned MFMAExpInterleaveOpt::ExpRequirement = 0;
1474unsigned MFMAExpInterleaveOpt::MFMAChains = 0;
1475bool MFMAExpInterleaveOpt::HasCvt =
false;
1476bool MFMAExpInterleaveOpt::HasChainBetweenCvt =
false;
1477std::optional<unsigned> MFMAExpInterleaveOpt::FirstPipeDSR = std::nullopt;
1486 auto isBitPack = [](
unsigned Opc) {
1487 return Opc == AMDGPU::V_PACK_B32_F16_e64 ||
Opc == AMDGPU::V_PERM_B32_e64;
1490 auto isCvt = [](
unsigned Opc) {
1491 return Opc == AMDGPU::V_CVT_F16_F32_e32 ||
Opc == AMDGPU::V_CVT_I32_F32_e32;
1494 auto isAdd = [](
unsigned Opc) {
return Opc == AMDGPU::V_ADD_F32_e32; };
1501 if (SU.
Succs.size() >= 7)
1503 for (
auto &Succ : SU.
Succs) {
1504 if (Succ.getSUnit()->Succs.size() >= 7)
1523 if (!(PackSUs.
size() && MFMAPipeCands.
size() && ExpPipeCands.
size()))
1528 std::optional<SUnit *> TempMFMA;
1529 std::optional<SUnit *> TempExp;
1531 for (
auto &PredSU : ExpPipeCands) {
1532 for (
auto &SuccSU : MFMAPipeCands) {
1545 if (!(TempExp && TempMFMA))
1548 HasChainBetweenCvt =
none_of((*TempExp)->Succs, [&isCvt](
SDep &Succ) {
1549 return isCvt(Succ.getSUnit()->getInstr()->getOpcode());
1553 for (
auto &SuccSU : MFMAPipeCands) {
1554 if (MFMAPipeSUs.
size() &&
1555 any_of(MFMAPipeSUs, [&SuccSU](
SUnit *PotentialMatch) {
1556 return PotentialMatch->
NodeNum == SuccSU->NodeNum;
1560 for (
auto &PredSU : ExpPipeCands) {
1568 MFMAPipeCount = MFMAPipeSUs.
size();
1570 assert(TempExp && TempMFMA);
1571 assert(MFMAPipeCount > 0);
1573 std::optional<SUnit *> TempCvt;
1574 for (
auto &SuccSU : CvtSUs) {
1582 if (TempCvt.has_value()) {
1583 for (
auto &SuccSU : MFMAPipeSUs) {
1592 for (
auto &MFMAPipeSU : MFMAPipeSUs) {
1596 return TII->isMFMAorWMMA(*Succ.getSUnit()->getInstr());
1598 MFMAChainSeeds.push_back(MFMAPipeSU);
1606 for (
auto Pred : MFMAChainSeeds[0]->Preds) {
1607 if (
TII->isDS(Pred.getSUnit()->getInstr()->getOpcode()) &&
1608 Pred.getSUnit()->getInstr()->mayLoad())
1609 FirstPipeDSR = Pred.getSUnit()->NodeNum;
1613 unsigned PackSuccCount =
1619 unsigned PackPredCount =
1621 auto Opc = Pred.getSUnit()->getInstr()->getOpcode();
1622 return isBitPack(Opc);
1626 auto Opc = Pred.getSUnit()->getInstr()->getOpcode();
1627 return isBitPack(Opc);
1630 if (PackPred == (*TempMFMA)->Preds.end())
1638 return TII->isMFMAorWMMA(*Succ.getSUnit()->getInstr());
1642 MFMAEnablement *= PackSuccCount;
1647 return DAG->
IsReachable(PackPred->getSUnit(), ExpBase);
1650 ExpRequirement *= PackPredCount;
1660 MFMAChainSeeds.clear();
1667bool MFMAExpInterleaveOpt::applyIGLPStrategy(
1672 bool IsSmallKernelType =
1673 MFMAEnablement == 2 && ExpRequirement == 4 && TransPipeCount == 32;
1674 bool IsLargeKernelType =
1675 MFMAEnablement == 4 && ExpRequirement == 4 && TransPipeCount == 64;
1677 if (!(IsSmallKernelType || IsLargeKernelType))
1683 unsigned PipelineSyncID = 0;
1684 SchedGroup *SG =
nullptr;
1686 unsigned MFMAChain = 0;
1687 unsigned PositionInChain = 0;
1688 unsigned CurrMFMAForTransPosition = 0;
1690 auto incrementTransPosition = [&MFMAChain, &PositionInChain,
1691 &CurrMFMAForTransPosition]() {
1692 CurrMFMAForTransPosition += MFMAEnablement;
1693 PositionInChain = (CurrMFMAForTransPosition / MFMAChains);
1694 MFMAChain = CurrMFMAForTransPosition % MFMAChains;
1697 auto getNextTransPositionInChain = [&CurrMFMAForTransPosition]() {
1698 auto TempMFMAForTrans = CurrMFMAForTransPosition + MFMAEnablement;
1699 return (TempMFMAForTrans / MFMAChains);
1702 auto getNextTransMFMAChain = [&CurrMFMAForTransPosition]() {
1703 auto TempMFMAForTrans = CurrMFMAForTransPosition + MFMAEnablement;
1704 return TempMFMAForTrans % MFMAChains;
1707 unsigned CurrMFMAPosition = 0;
1708 unsigned MFMAChainForMFMA = 0;
1709 unsigned PositionInChainForMFMA = 0;
1711 auto incrementMFMAPosition = [&CurrMFMAPosition, &MFMAChainForMFMA,
1712 &PositionInChainForMFMA]() {
1714 MFMAChainForMFMA = CurrMFMAPosition % MFMAChains;
1715 PositionInChainForMFMA = CurrMFMAPosition / MFMAChains;
1719 assert(IsPostRA || MFMAChainSeeds.size() == MFMAChains);
1721 bool UsesFMA = IsSmallKernelType || !IsPostRA;
1722 bool UsesDSRead = IsLargeKernelType && !IsPostRA && FirstPipeDSR;
1723 bool UsesCvt = HasCvt && (IsSmallKernelType || !IsPostRA);
1724 bool UsesVALU = IsSmallKernelType;
1729 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1730 SchedGroupMask::VALU, ExpRequirement, PipelineSyncID, DAG,
TII);
1731 if (!IsPostRA && MFMAChains) {
1732 SG->addRule(std::make_shared<EnablesNthMFMAInChain>(
1733 PositionInChain, MFMAChainSeeds[MFMAChain],
TII, SG->getSGID(),
1737 std::make_shared<EnablesNthMFMA>(1,
TII, SG->getSGID(),
true));
1738 SG->addRule(std::make_shared<IsFMA>(
TII, SG->getSGID()));
1739 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1742 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1743 SchedGroupMask::VALU, ExpRequirement, PipelineSyncID, DAG,
TII);
1744 if (!IsPostRA && MFMAChains) {
1745 SG->addRule(std::make_shared<EnablesNthMFMAInChain>(
1746 getNextTransPositionInChain(),
1747 MFMAChainSeeds[getNextTransMFMAChain()],
TII, SG->getSGID(),
true));
1749 SG->addRule(std::make_shared<EnablesNthMFMA>(MFMAEnablement + 1,
TII,
1750 SG->getSGID(),
true));
1751 SG->addRule(std::make_shared<IsFMA>(
TII, SG->getSGID()));
1752 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1756 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1757 SchedGroupMask::DS_READ, 2, PipelineSyncID, DAG,
TII);
1758 SG->addRule(std::make_shared<OccursAtOrAfterNode>(*FirstPipeDSR,
TII,
1760 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1764 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1765 SchedGroupMask::TRANS, ExpRequirement, PipelineSyncID, DAG,
TII);
1766 if (!IsPostRA && MFMAChains)
1767 SG->addRule(std::make_shared<EnablesNthMFMAInChain>(
1768 PositionInChain, MFMAChainSeeds[MFMAChain],
TII, SG->getSGID(),
true));
1770 SG->addRule(std::make_shared<EnablesNthMFMA>(1,
TII, SG->getSGID(),
true));
1771 SG->addRule(std::make_shared<IsPipeExp>(
TII, SG->getSGID(),
true));
1772 SG->addRule(std::make_shared<LessThanNSuccs>(8,
TII, SG->getSGID(),
1773 HasChainBetweenCvt));
1774 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1776 incrementTransPosition();
1779 for (
unsigned I = 0;
I < ExpRequirement;
I++) {
1782 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1783 SchedGroupMask::VALU, 1, PipelineSyncID, DAG,
TII);
1784 SG->addRule(std::make_shared<IsCvt>(
TII, SG->getSGID()));
1785 if (HasChainBetweenCvt)
1786 SG->addRule(std::make_shared<IsReachableFromPrevNthGroup>(
1787 1 + (2 + UsesFMA) *
I,
TII, SG->getSGID()));
1789 SG->addRule(std::make_shared<IsSuccOfPrevNthGroup>(
1790 1 + (2 + UsesFMA) *
I,
TII, SG->getSGID()));
1791 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1796 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1797 SchedGroupMask::VALU, 1, PipelineSyncID, DAG,
TII);
1798 if (!IsPostRA && MFMAChains) {
1799 SG->addRule(std::make_shared<EnablesNthMFMAInChain>(
1800 getNextTransPositionInChain(),
1801 MFMAChainSeeds[getNextTransMFMAChain()],
TII, SG->getSGID(),
true));
1803 SG->addRule(std::make_shared<EnablesNthMFMA>(2 * MFMAEnablement + 1,
1804 TII, SG->getSGID(),
true));
1805 SG->addRule(std::make_shared<IsFMA>(
TII, SG->getSGID()));
1806 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1810 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1811 SchedGroupMask::TRANS, 1, PipelineSyncID, DAG,
TII);
1812 if (!IsPostRA && MFMAChains)
1813 SG->addRule(std::make_shared<EnablesNthMFMAInChain>(
1814 PositionInChain, MFMAChainSeeds[MFMAChain],
TII, SG->getSGID(),
1817 SG->addRule(std::make_shared<EnablesNthMFMA>(MFMAEnablement + 1,
TII,
1818 SG->getSGID(),
true));
1819 SG->addRule(std::make_shared<IsPipeExp>(
TII, SG->getSGID(),
true));
1820 SG->addRule(std::make_shared<LessThanNSuccs>(8,
TII, SG->getSGID(),
1821 HasChainBetweenCvt));
1822 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1827 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1828 SchedGroupMask::TRANS, 1, PipelineSyncID, DAG,
TII);
1829 SG->addRule(std::make_shared<IsPipeExp>(
TII, SG->getSGID(),
true));
1830 SG->addRule(std::make_shared<GreaterThanOrEqualToNSuccs>(
1831 8,
TII, SG->getSGID(), HasChainBetweenCvt));
1832 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1837 unsigned MFMARatio =
1838 MFMAEnablement > ExpRequirement ? MFMAEnablement / ExpRequirement : 1;
1841 MFMAEnablement > ExpRequirement ? 1 : ExpRequirement / MFMAEnablement;
1843 unsigned RemainingExp = TransPipeCount > (2 * ExpRequirement)
1844 ? TransPipeCount - (2 * ExpRequirement)
1846 unsigned ExpLoopCount = RemainingExp / ExpRatio;
1848 unsigned MFMAInLoop = MFMAPipeCount > (MFMAEnablement * 2)
1849 ? MFMAPipeCount - (MFMAEnablement * 2)
1851 unsigned MFMALoopCount = MFMAInLoop / MFMARatio;
1853 AddPipeCount < MFMAPipeCount ? 1 : AddPipeCount / MFMAPipeCount;
1854 unsigned LoopSize = std::min(ExpLoopCount, MFMALoopCount);
1856 for (
unsigned I = 0;
I < LoopSize;
I++) {
1857 if (!(
I * ExpRatio % ExpRequirement))
1858 incrementTransPosition();
1861 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1862 SchedGroupMask::MFMA, MFMARatio, PipelineSyncID, DAG,
TII);
1863 if (!IsPostRA && MFMAChains)
1864 SG->addRule(std::make_shared<IsExactMFMA>(
1865 PositionInChainForMFMA, MFMAChainSeeds[MFMAChainForMFMA],
TII,
1866 SG->getSGID(),
true));
1868 SG->addRule(std::make_shared<OccursAfterExp>(
TII, SG->getSGID(),
true));
1869 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1870 incrementMFMAPosition();
1873 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1874 SchedGroupMask::VALU, VALUOps, PipelineSyncID, DAG,
TII);
1875 SG->addRule(std::make_shared<IsPipeAdd>(
TII, SG->getSGID()));
1876 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1879 if (UsesDSRead && !(
I % 4)) {
1880 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1881 SchedGroupMask::DS_READ, 2, PipelineSyncID, DAG,
TII);
1882 SG->addRule(std::make_shared<OccursAtOrAfterNode>(*FirstPipeDSR,
TII,
1884 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1888 for (
unsigned J = 0; J < ExpRatio; J++) {
1889 auto MFMAOffset = (1 + UsesVALU) * MFMARatio * (
I + 1);
1890 auto MaxMFMAOffset =
1891 (1 + UsesVALU) * ExpRequirement * MFMARatio / ExpRatio;
1895 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1896 SchedGroupMask::VALU, 1, PipelineSyncID, DAG,
TII);
1897 SG->addRule(std::make_shared<IsCvt>(
TII, SG->getSGID()));
1898 auto BaseDiff = (2 + UsesFMA) * (ExpRequirement - 1) + 1;
1899 auto DSROffset =
I / 4 + 1;
1900 auto MaxDSROffset = MaxMFMAOffset / 4;
1902 auto ExpOffset =
I * ExpRatio + J >= ExpRequirement ? 0 : 1;
1903 auto CurrentOffset = UsesDSRead * std::min(MaxDSROffset, DSROffset) +
1904 std::min(MaxMFMAOffset, MFMAOffset) + BaseDiff +
1906 if (HasChainBetweenCvt)
1907 SG->addRule(std::make_shared<IsReachableFromPrevNthGroup>(
1908 CurrentOffset,
TII, SG->getSGID()));
1910 SG->addRule(std::make_shared<IsSuccOfPrevNthGroup>(CurrentOffset,
TII,
1912 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1917 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1918 SchedGroupMask::VALU, 1, PipelineSyncID, DAG,
TII);
1919 if (!IsPostRA && MFMAChains)
1920 SG->addRule(std::make_shared<EnablesNthMFMAInChain>(
1921 getNextTransPositionInChain(),
1922 MFMAChainSeeds[getNextTransMFMAChain()],
TII, SG->getSGID(),
1925 SG->addRule(std::make_shared<EnablesNthMFMA>(
1926 (((
I * ExpRatio + J) / ExpRequirement) + 3) * MFMAEnablement + 1,
1927 TII, SG->getSGID(),
true));
1928 SG->addRule(std::make_shared<IsFMA>(
TII, SG->getSGID()));
1929 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1933 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1934 SchedGroupMask::TRANS, 1, PipelineSyncID, DAG,
TII);
1935 if (!IsPostRA && MFMAChains)
1936 SG->addRule(std::make_shared<EnablesNthMFMAInChain>(
1937 PositionInChain, MFMAChainSeeds[MFMAChain],
TII, SG->getSGID(),
1940 SG->addRule(std::make_shared<EnablesNthMFMA>(
1941 (((
I * ExpRatio + J) / ExpRequirement) + 2) * MFMAEnablement + 1,
1942 TII, SG->getSGID(),
true));
1943 SG->addRule(std::make_shared<IsPipeExp>(
TII, SG->getSGID(),
true));
1944 SG->addRule(std::make_shared<LessThanNSuccs>(8,
TII, SG->getSGID(),
1945 HasChainBetweenCvt));
1946 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1951 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1952 SchedGroupMask::MFMA, MFMAEnablement * 2, PipelineSyncID, DAG,
TII);
1953 SG->addRule(std::make_shared<OccursAfterExp>(
TII, SG->getSGID(),
true));
1954 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1958class MFMAExpSimpleInterleaveOpt final :
public IGLPStrategy {
1960 bool applyIGLPStrategy(
1971 : IGLPStrategy(DAG,
TII) {
1976bool MFMAExpSimpleInterleaveOpt::applyIGLPStrategy(
1981 unsigned MFMACount = 0;
1983 if (
TII->isMFMAorWMMA(
I))
1986 const unsigned PipelineSyncID = 0;
1987 for (
unsigned I = 0;
I < MFMACount * 3; ++
I) {
1988 SchedGroup *SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1989 SchedGroupMask::TRANS, 1, PipelineSyncID, DAG,
TII);
1990 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1992 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1993 SchedGroupMask::MFMA, 1, PipelineSyncID, DAG,
TII);
1994 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2000class MFMASmallGemmSingleWaveOpt final :
public IGLPStrategy {
2003 class EnablesInitialMFMA final :
public InstructionRule {
2007 if (!SyncPipe.
size())
2010 if (!Cache->size()) {
2011 for (
auto &Elt : SyncPipe[0].DAG->
SUnits) {
2012 if (
TII->isMFMAorWMMA(*Elt.getInstr())) {
2016 Cache->push_back(&Elt);
2021 auto *DAG = SyncPipe[0].DAG;
2022 for (
auto &Elt : *Cache) {
2030 bool NeedsCache =
false)
2031 : InstructionRule(
TII, SGID, NeedsCache) {}
2035 class IsPermForDSW final :
public InstructionRule {
2040 if (
MI->getOpcode() != AMDGPU::V_PERM_B32_e64)
2043 bool FitsInGroup =
false;
2045 if (!Collection.
size()) {
2046 for (
auto &Succ : SU->
Succs) {
2047 SUnit *SuccUnit = Succ.getSUnit();
2050 Cache->push_back(SuccUnit);
2061 return ThisSucc.getSUnit() == Elt;
2066 IsPermForDSW(
const SIInstrInfo *
TII,
unsigned SGID,
bool NeedsCache =
false)
2067 : InstructionRule(
TII, SGID, NeedsCache) {}
2071 class IsSuccOfPrevGroup final :
public InstructionRule {
2075 SchedGroup *OtherGroup =
nullptr;
2076 for (
auto &PipeSG : SyncPipe) {
2077 if ((
unsigned)PipeSG.getSGID() == SGID - 1) {
2078 OtherGroup = &PipeSG;
2084 if (!OtherGroup->Collection.size())
2088 return any_of(OtherGroup->Collection, [&SU](
SUnit *Elt) {
2089 return any_of(Elt->Succs,
2090 [&SU](SDep &Succ) { return Succ.getSUnit() == SU; });
2094 bool NeedsCache =
false)
2095 : InstructionRule(
TII, SGID, NeedsCache) {}
2099 class VMEMSize final :
public InstructionRule {
2104 if (
MI->getOpcode() == TargetOpcode::BUNDLE)
2106 if (!Collection.
size())
2111 auto TRI =
TII->getRegisterInfo();
2112 auto &MRI =
MI->getMF()->getRegInfo();
2113 for (
auto &Elt : Collection) {
2114 auto Op = Elt->getInstr()->getOperand(0);
2116 TRI.getRegSizeInBits(*
TRI.getRegClassForOperandReg(MRI,
Op));
2120 if (NumBits < 128) {
2122 if (NumBits +
TRI.getRegSizeInBits(*
TRI.getRegClassForOperandReg(
2123 MRI,
MI->getOperand(0))) <=
2131 VMEMSize(
const SIInstrInfo *
TII,
unsigned SGID,
bool NeedsCache =
false)
2132 : InstructionRule(
TII, SGID, NeedsCache) {}
2137 class SharesPredWithPrevNthGroup final :
public InstructionRule {
2139 unsigned Distance = 1;
2144 SchedGroup *OtherGroup =
nullptr;
2145 if (!SyncPipe.
size())
2148 if (!Cache->size()) {
2150 for (
auto &PipeSG : SyncPipe) {
2151 if ((
unsigned)PipeSG.getSGID() == SGID - Distance) {
2152 OtherGroup = &PipeSG;
2158 if (!OtherGroup->Collection.size())
2161 for (
auto &OtherEle : OtherGroup->Collection) {
2162 for (
auto &Pred : OtherEle->Preds) {
2163 if (Pred.getSUnit()->getInstr()->getOpcode() ==
2164 AMDGPU::V_PERM_B32_e64)
2165 Cache->push_back(Pred.getSUnit());
2174 auto *DAG = SyncPipe[0].DAG;
2181 SharesPredWithPrevNthGroup(
unsigned Distance,
const SIInstrInfo *
TII,
2182 unsigned SGID,
bool NeedsCache =
false)
2183 : InstructionRule(
TII, SGID, NeedsCache), Distance(Distance) {}
2187 bool applyIGLPStrategy(
2198 : IGLPStrategy(DAG,
TII) {
2203static unsigned DSWCount = 0;
2204static unsigned DSWWithPermCount = 0;
2205static unsigned DSWWithSharedVMEMCount = 0;
2207bool MFMASmallGemmSingleWaveOpt::applyIGLPStrategy(
2208 DenseMap<int, SUnitsToCandidateSGsMap> &SyncedInstrs,
2211 unsigned MFMACount = 0;
2212 unsigned DSRCount = 0;
2214 bool IsInitial =
Phase == AMDGPU::SchedulingPhase::Initial;
2216 assert((!IsInitial || (DSWCount == 0 && DSWWithPermCount == 0 &&
2217 DSWWithSharedVMEMCount == 0)) &&
2218 "DSWCounters should be zero in pre-RA scheduling!");
2220 for (
auto &SU : DAG->
SUnits) {
2221 auto *
I = SU.getInstr();
2222 if (
TII->isMFMAorWMMA(*
I))
2224 else if (
TII->isDS(*
I)) {
2227 else if (
I->mayStore() && IsInitial) {
2229 for (
auto Pred : SU.Preds) {
2230 if (Pred.getSUnit()->getInstr()->getOpcode() ==
2231 AMDGPU::V_PERM_B32_e64) {
2241 DSWWithPermCount = DSWithPerms.
size();
2242 auto *
I = DSWithPerms.
begin();
2243 auto *
E = DSWithPerms.
end();
2251 DenseMap<MachineInstr *, SUnit *> VMEMLookup;
2253 for (;
I !=
E;
I++) {
2254 SUnit *Cand =
nullptr;
2255 bool MissedAny =
false;
2256 for (
auto &Pred : (*I)->Preds) {
2257 if (Pred.getSUnit()->getInstr()->getOpcode() != AMDGPU::V_PERM_B32_e64)
2263 for (
auto &Succ : Pred.getSUnit()->Succs) {
2264 auto *
MI = Succ.getSUnit()->getInstr();
2265 if (!
TII->isVMEM(*
MI) || !
MI->mayLoad())
2268 if (MissedAny || !VMEMLookup.
size()) {
2270 VMEMLookup[
MI] = *
I;
2287 if (!MissedAny && Cand) {
2288 DSWWithSharedVMEMCount += 2;
2295 assert(DSWWithSharedVMEMCount <= DSWWithPermCount);
2297 unsigned PipelineSyncID = 0;
2299 if (DSWWithPermCount) {
2300 for (
unsigned I = 0;
I < MFMACount;
I++) {
2301 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2302 SchedGroupMask::MFMA, 1, PipelineSyncID, DAG,
TII);
2303 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2305 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2306 SchedGroupMask::VALU, 2, PipelineSyncID, DAG,
TII);
2307 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2317 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2318 SchedGroupMask::DS_READ, 4, PipelineSyncID, DAG,
TII);
2319 SG->addRule(std::make_shared<EnablesInitialMFMA>(
TII, SG->getSGID(),
true));
2320 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2322 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2323 SchedGroupMask::MFMA, 1, PipelineSyncID, DAG,
TII);
2324 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2327 for (
unsigned I = 4;
I < DSRCount; ++
I) {
2328 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2329 SchedGroupMask::DS_READ, 1, PipelineSyncID, DAG,
TII);
2330 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2332 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2333 SchedGroupMask::MFMA, 1, PipelineSyncID, DAG,
TII);
2334 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2340 for (
unsigned I = DSWWithSharedVMEMCount;
I < DSWWithPermCount; ++
I) {
2341 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2342 SchedGroupMask::VALU, 4, PipelineSyncID, DAG,
TII);
2343 SG->addRule(std::make_shared<IsPermForDSW>(
TII, SG->getSGID(),
true));
2344 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2346 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2347 SchedGroupMask::DS_WRITE, 1, PipelineSyncID, DAG,
TII);
2348 SG->addRule(std::make_shared<IsSuccOfPrevGroup>(
TII, SG->getSGID()));
2349 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2351 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2352 SchedGroupMask::VMEM_READ, 4, PipelineSyncID, DAG,
TII);
2353 SG->addRule(std::make_shared<SharesPredWithPrevNthGroup>(
2354 1,
TII, SG->getSGID(),
true));
2355 SG->addRule(std::make_shared<VMEMSize>(
TII, SG->getSGID()));
2356 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2358 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2359 SchedGroupMask::MFMA, 1, PipelineSyncID, DAG,
TII);
2360 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2362 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2363 SchedGroupMask::VMEM_READ, 4, PipelineSyncID, DAG,
TII);
2364 SG->addRule(std::make_shared<SharesPredWithPrevNthGroup>(
2365 3,
TII, SG->getSGID(),
true));
2366 SG->addRule(std::make_shared<VMEMSize>(
TII, SG->getSGID()));
2367 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2369 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2370 SchedGroupMask::MFMA, 1, PipelineSyncID, DAG,
TII);
2371 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2377 for (
unsigned I = DSWWithPermCount;
I < DSWCount;
I++) {
2378 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2379 SchedGroupMask::DS_WRITE, 1, PipelineSyncID, DAG,
TII);
2380 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2382 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2383 SchedGroupMask::VMEM_READ, 4, PipelineSyncID, DAG,
TII);
2384 SG->addRule(std::make_shared<VMEMSize>(
TII, SG->getSGID()));
2385 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2387 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2388 SchedGroupMask::MFMA, 1, PipelineSyncID, DAG,
TII);
2389 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2397 for (
unsigned I = 0;
I < DSWWithSharedVMEMCount; ++
I) {
2398 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2399 SchedGroupMask::VALU, 4, PipelineSyncID, DAG,
TII);
2400 SG->addRule(std::make_shared<IsPermForDSW>(
TII, SG->getSGID(),
true));
2401 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2403 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2404 SchedGroupMask::DS_WRITE, 1, PipelineSyncID, DAG,
TII);
2405 SG->addRule(std::make_shared<IsSuccOfPrevGroup>(
TII, SG->getSGID()));
2406 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2408 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2409 SchedGroupMask::MFMA, 1, PipelineSyncID, DAG,
TII);
2410 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2412 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2413 SchedGroupMask::VALU, 4, PipelineSyncID, DAG,
TII);
2414 SG->addRule(std::make_shared<IsPermForDSW>(
TII, SG->getSGID(),
true));
2415 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2417 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2418 SchedGroupMask::DS_WRITE, 1, PipelineSyncID, DAG,
TII);
2419 SG->addRule(std::make_shared<IsSuccOfPrevGroup>(
TII, SG->getSGID()));
2420 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2422 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2423 SchedGroupMask::MFMA, 1, PipelineSyncID, DAG,
TII);
2424 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2426 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2427 SchedGroupMask::VMEM_READ, 4, PipelineSyncID, DAG,
TII);
2428 SG->addRule(std::make_shared<SharesPredWithPrevNthGroup>(
2429 2,
TII, SG->getSGID(),
true));
2430 SG->addRule(std::make_shared<VMEMSize>(
TII, SG->getSGID()));
2431 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2433 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2434 SchedGroupMask::MFMA, 1, PipelineSyncID, DAG,
TII);
2435 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2437 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2438 SchedGroupMask::VMEM_READ, 4, PipelineSyncID, DAG,
TII);
2439 SG->addRule(std::make_shared<SharesPredWithPrevNthGroup>(
2440 4,
TII, SG->getSGID(),
true));
2441 SG->addRule(std::make_shared<VMEMSize>(
TII, SG->getSGID()));
2442 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2444 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2445 SchedGroupMask::MFMA, 1, PipelineSyncID, DAG,
TII);
2446 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2452static std::unique_ptr<IGLPStrategy>
2454 const SIInstrInfo *
TII) {
2457 return std::make_unique<MFMASmallGemmOpt>(DAG,
TII);
2459 return std::make_unique<MFMASmallGemmSingleWaveOpt>(DAG,
TII);
2461 return std::make_unique<MFMAExpInterleaveOpt>(DAG,
TII);
2463 return std::make_unique<MFMAExpSimpleInterleaveOpt>(DAG,
TII);
2469class IGroupLPDAGMutation :
public ScheduleDAGMutation {
2471 const SIInstrInfo *
TII;
2478 DenseMap<int, SmallVector<SchedGroup, 4>> SyncedSchedGroups;
2481 DenseMap<int, SUnitsToCandidateSGsMap> SyncedInstrs;
2484 void addSchedBarrierEdges(SUnit &SU);
2495 SchedGroupMask invertSchedBarrierMask(SchedGroupMask Mask)
const;
2498 void initSchedGroupBarrierPipelineStage(
2499 std::vector<SUnit>::reverse_iterator RIter);
2501 bool initIGLPOpt(SUnit &SU);
2504 void apply(ScheduleDAGInstrs *DAGInstrs)
override;
2511 bool IsBottomUp =
true;
2516 IGroupLPDAGMutation() =
default;
2520unsigned SchedGroup::NumSchedGroups = 0;
2522bool SchedGroup::tryAddEdge(SUnit *
A, SUnit *
B) {
2526bool SchedGroup::canAddMI(
const MachineInstr &
MI)
const {
2528 if (
MI.isMetaInstruction())
2531 else if (
MI.isInlineAsm()) {
2533 auto &MRI =
MI.getParent()->getParent()->getRegInfo();
2534 bool SGPR_used =
false, SGPR_big_def =
false, VGPR_used =
false,
2535 VMFMA_used =
false, VReg32_used =
false,
MayLoad =
MI.mayLoad(),
2537 for (
const MachineOperand &Operand :
MI.operands())
2538 if (Operand.isReg()) {
2540 *
TRI.getRegClassForOperandReg(MRI, Operand);
2541 if (
TRI.hasVGPRs(&RegClass)) {
2543 if (Operand.isUse() &&
TRI.getRegSizeInBits(RegClass) == 32)
2549 if (
TRI.hasAGPRs(&RegClass) ||
TRI.getRegSizeInBits(RegClass) > 128)
2551 if (
TRI.hasSGPRs(&RegClass))
2553 if (
TRI.getRegSizeInBits(RegClass) > 64 && Operand.isDef())
2554 SGPR_big_def =
true;
2557 typedef std::underlying_type_t<SchedGroupMask> SGMask_t;
2558 SGMask_t InlineAsmMask = 0;
2559 if (VGPR_used && !VMFMA_used && !MayLoad && !MayStore)
2560 InlineAsmMask |= (SGMask_t)SchedGroupMask::VALU;
2561 if (SGPR_used && !VGPR_used && !MayLoad && !MayStore)
2562 InlineAsmMask |= (SGMask_t)SchedGroupMask::SALU;
2564 InlineAsmMask |= (SGMask_t)SchedGroupMask::MFMA;
2565 if (VGPR_used && MayLoad)
2566 InlineAsmMask |= (SGMask_t)(VReg32_used ? SchedGroupMask::DS_READ
2567 : SchedGroupMask::VMEM_READ);
2568 if (VGPR_used && MayStore)
2569 InlineAsmMask |= (SGMask_t)(VReg32_used ? SchedGroupMask::DS_WRITE
2570 : SchedGroupMask::VMEM_WRITE);
2572 InlineAsmMask |= (SGMask_t)SchedGroupMask::DS_READ;
2573 if (InlineAsmMask & (SGMask_t)SchedGroupMask::VALU ||
2574 InlineAsmMask & (SGMask_t)SchedGroupMask::SALU)
2575 InlineAsmMask |= (SGMask_t)SchedGroupMask::ALU;
2576 if (InlineAsmMask & (SGMask_t)SchedGroupMask::DS_READ ||
2577 InlineAsmMask & (SGMask_t)SchedGroupMask::DS_WRITE)
2578 InlineAsmMask |= (SGMask_t)SchedGroupMask::DS;
2579 if (InlineAsmMask & (SGMask_t)SchedGroupMask::VMEM_READ ||
2580 InlineAsmMask & (SGMask_t)SchedGroupMask::VMEM_WRITE)
2581 InlineAsmMask |= (SGMask_t)SchedGroupMask::VMEM;
2583 Result = ((SGMask_t)SGMask & InlineAsmMask) != 0;
2586 else if (((SGMask & SchedGroupMask::ALU) != SchedGroupMask::NONE) &&
2587 (
TII->isVALU(
MI,
true) ||
TII->isMFMAorWMMA(
MI) ||
2591 else if (((SGMask & SchedGroupMask::VALU) != SchedGroupMask::NONE) &&
2592 TII->isVALU(
MI,
true) && !
TII->isMFMAorWMMA(
MI) &&
2600 else if (((SGMask & SchedGroupMask::SALU) != SchedGroupMask::NONE) &&
2604 else if (((SGMask & SchedGroupMask::MFMA) != SchedGroupMask::NONE) &&
2605 TII->isMFMAorWMMA(
MI))
2608 else if (((SGMask & SchedGroupMask::VMEM) != SchedGroupMask::NONE) &&
2612 else if (((SGMask & SchedGroupMask::VMEM_READ) != SchedGroupMask::NONE) &&
2616 else if (((SGMask & SchedGroupMask::VMEM_WRITE) != SchedGroupMask::NONE) &&
2617 MI.mayStore() &&
TII->isVMEM(
MI) && !
TII->isLDSDMA(
MI))
2620 else if (((SGMask & SchedGroupMask::DS) != SchedGroupMask::NONE) &&
2624 else if (((SGMask & SchedGroupMask::DS_READ) != SchedGroupMask::NONE) &&
2625 MI.mayLoad() &&
TII->isDS(
MI))
2628 else if (((SGMask & SchedGroupMask::DS_WRITE) != SchedGroupMask::NONE) &&
2629 MI.mayStore() &&
TII->isDS(
MI))
2632 else if (((SGMask & SchedGroupMask::TRANS) != SchedGroupMask::NONE) &&
2636 else if (((SGMask & SchedGroupMask::LDSDMA) != SchedGroupMask::NONE) &&
2641 dbgs() <<
"For SchedGroup with mask " <<
format_hex((
int)SGMask, 10,
true)
2642 << (Result ?
" could classify " :
" unable to classify ") <<
MI);
2647int SchedGroup::link(SUnit &SU,
bool MakePred,
2648 std::list<std::pair<SUnit *, SUnit *>> &AddedEdges) {
2649 int MissedEdges = 0;
2650 for (
auto *
A : Collection) {
2652 if (
A ==
B ||
A->getInstr()->getOpcode() == AMDGPU::SCHED_GROUP_BARRIER)
2662 bool Added = tryAddEdge(
A,
B);
2664 AddedEdges.emplace_back(
A,
B);
2672void SchedGroup::link(SUnit &SU,
bool MakePred) {
2673 for (
auto *
A : Collection) {
2675 if (
A->getInstr()->getOpcode() == AMDGPU::SCHED_GROUP_BARRIER)
2684void SchedGroup::link(SUnit &SU,
2685 function_ref<
bool(
const SUnit *
A,
const SUnit *
B)>
P) {
2686 for (
auto *
A : Collection) {
2695void SchedGroup::link(SchedGroup &OtherGroup) {
2696 for (
auto *
B : OtherGroup.Collection)
2700bool SchedGroup::canAddSU(SUnit &SU)
const {
2702 if (
MI.getOpcode() != TargetOpcode::BUNDLE)
2703 return canAddMI(
MI);
2708 while (
E !=
MBB->
end() &&
E->isBundledWithPred())
2712 return std::all_of(
B,
E, [
this](MachineInstr &
MI) {
return canAddMI(
MI); });
2716void SchedGroup::findCandidateSUnits(
T Begin,
T End,
2717 SUnitsToCandidateSGsMap &SyncedInstrs) {
2720 SyncedInstrs[&SU].push_back(SGID);
2724void SchedGroup::findCandidateSUnits(SUnitsToCandidateSGsMap &SyncedInstrs) {
2725 findCandidateSUnits(DAG->
SUnits.rbegin(), DAG->
SUnits.rend(), SyncedInstrs);
2728void IGroupLPDAGMutation::apply(ScheduleDAGInstrs *DAGInstrs) {
2729 const TargetSchedModel *TSchedModel = DAGInstrs->
getSchedModel();
2730 if (!TSchedModel || DAGInstrs->
SUnits.empty())
2735 TII =
ST.getInstrInfo();
2736 DAG =
static_cast<ScheduleDAGMI *
>(DAGInstrs);
2737 SyncedSchedGroups.clear();
2738 SyncedInstrs.clear();
2739 bool FoundSB =
false;
2740 bool FoundIGLP =
false;
2741 bool ShouldApplyIGLP =
false;
2742 for (
auto R = DAG->
SUnits.rbegin(),
E = DAG->
SUnits.rend(); R !=
E; ++R) {
2743 unsigned Opc =
R->getInstr()->getOpcode();
2745 if (
Opc == AMDGPU::SCHED_BARRIER) {
2746 addSchedBarrierEdges(*R);
2748 }
else if (
Opc == AMDGPU::SCHED_GROUP_BARRIER) {
2749 initSchedGroupBarrierPipelineStage(R);
2751 }
else if (
Opc == AMDGPU::IGLP_OPT) {
2752 if (!FoundSB && !FoundIGLP) {
2754 ShouldApplyIGLP = initIGLPOpt(*R);
2759 if (FoundSB || (FoundIGLP && ShouldApplyIGLP)) {
2760 PipelineSolver PS(SyncedSchedGroups, SyncedInstrs, DAG, IsBottomUp);
2768void IGroupLPDAGMutation::addSchedBarrierEdges(SUnit &SchedBarrier) {
2770 assert(
MI.getOpcode() == AMDGPU::SCHED_BARRIER);
2771 LLVM_DEBUG(
dbgs() <<
"Building SchedGroup for SchedBarrier with Mask: "
2772 <<
MI.getOperand(0).getImm() <<
"\n");
2774 invertSchedBarrierMask((SchedGroupMask)
MI.getOperand(0).getImm());
2775 SchedGroup SG(InvertedMask, std::nullopt, DAG,
TII);
2777 for (SUnit &SU : DAG->
SUnits)
2778 if (SG.canAddSU(SU))
2784 (function_ref<
bool(
const SUnit *
A,
const SUnit *
B)>)[](
2785 const SUnit *
A,
const SUnit *
B) {
return A->NodeNum >
B->NodeNum; });
2789IGroupLPDAGMutation::invertSchedBarrierMask(SchedGroupMask Mask)
const {
2792 SchedGroupMask InvertedMask = ~Mask;
2794 static constexpr std::pair<SchedGroupMask, SchedGroupMask> ImpliedGroups[] = {
2795 {SchedGroupMask::ALU, SchedGroupMask::VALU | SchedGroupMask::SALU |
2796 SchedGroupMask::MFMA | SchedGroupMask::TRANS},
2797 {SchedGroupMask::VMEM, SchedGroupMask::VMEM_READ |
2798 SchedGroupMask::VMEM_WRITE |
2799 SchedGroupMask::LDSDMA},
2800 {SchedGroupMask::DS, SchedGroupMask::DS_READ | SchedGroupMask::DS_WRITE |
2801 SchedGroupMask::LDSDMA},
2804 for (
auto [Aggregate, Members] : ImpliedGroups) {
2806 if ((InvertedMask & Aggregate) == SchedGroupMask::NONE)
2807 InvertedMask &= ~Members;
2809 else if ((InvertedMask & Members) != Members)
2810 InvertedMask &= ~Aggregate;
2813 LLVM_DEBUG(
dbgs() <<
"After Inverting, SchedGroup Mask: " << (
int)InvertedMask
2816 return InvertedMask;
2819void IGroupLPDAGMutation::initSchedGroupBarrierPipelineStage(
2820 std::vector<SUnit>::reverse_iterator RIter) {
2821 MachineInstr &SGB = *RIter->getInstr();
2828 auto &SG = SyncedSchedGroups[SyncID].emplace_back((SchedGroupMask)SGMask,
2831 SG.findCandidateSUnits(RIter, SG.DAG->
SUnits.rend(),
2832 SyncedInstrs[SG.getSyncID()]);
2835bool IGroupLPDAGMutation::initIGLPOpt(SUnit &SU) {
2838 auto S = createIGLPStrategy(StrategyID, DAG,
TII);
2839 if (!S->shouldApplyStrategy(DAG,
Phase))
2842 IsBottomUp = S->IsBottomUp;
2843 return S->applyIGLPStrategy(SyncedInstrs, SyncedSchedGroups,
Phase);
2853std::unique_ptr<ScheduleDAGMutation>
2855 return std::make_unique<IGroupLPDAGMutation>(
Phase);
aarch64 falkor hwpf fix Falkor HW Prefetch Fix Late Phase
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU Rewrite AGPR Copy MFMA
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
const HexagonInstrInfo * TII
static std::pair< Value *, APInt > getMask(Value *WideMask, unsigned Factor, ElementCount LeafValueEC)
Register const TargetRegisterInfo * TRI
Interface definition for SIInstrInfo.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
Get the array size.
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
Implements a dense probed hash-table based set.
const HexagonRegisterInfo & getRegisterInfo() const
Instructions::iterator instr_iterator
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
bool mayStore(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly modify memory.
const MachineOperand & getOperand(unsigned i) const
@ Data
Regular data dependence (aka true-dependence).
@ Artificial
Arbitrary strong DAG edge (no real dependence).
Scheduling unit. This is a node in the scheduling DAG.
unsigned NodeNum
Entry # of node in the node vector.
LLVM_ABI void removePred(const SDep &D)
Removes the specified edge as a pred of the current node if it exists.
SmallVector< SDep, 4 > Succs
All sunit successors.
SmallVector< SDep, 4 > Preds
All sunit predecessors.
MachineInstr * getInstr() const
Returns the representative MachineInstr for this SUnit.
A ScheduleDAG for scheduling lists of MachineInstr.
const TargetSchedModel * getSchedModel() const
Gets the machine model for instruction scheduling.
bool addEdge(SUnit *SuccSU, const SDep &PredDep)
Add a DAG edge to the given SU with the given predecessor dependence data.
bool IsReachable(SUnit *SU, SUnit *TargetSU)
IsReachable - Checks if SU is reachable from TargetSU.
void dump() const override
ScheduleDAGMI is an implementation of ScheduleDAGInstrs that simply schedules machine instructions ac...
std::vector< SUnit > SUnits
The scheduling units.
MachineFunction & MF
Machine function.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
reverse_iterator rbegin()
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
An efficient, type-erasing, non-owning reference to a callable.
A range adaptor for a pair of iterators.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
IGLPStrategyID
Operand 0 immediate for IGLP_OPT pseudo instructions.
@ MFMASmallGemmSingleWaveOptID
@ MFMAExpSimpleInterleaveID
void apply(Opt *O, const Mod &M, const Mods &... Ms)
initializer< Ty > init(const Ty &Val)
LLVM_ABI void link(std::unique_ptr< LinkGraph > G, std::unique_ptr< JITLinkContext > Ctx)
Link the given graph.
This is an optimization pass for GlobalISel generic memory operations.
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
@ LLVM_MARK_AS_BITMASK_ENUM
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
std::unique_ptr< ScheduleDAGMutation > createIGroupLPDAGMutation(AMDGPU::SchedulingPhase Phase)
Phase specifes whether or not this is a reentry into the IGroupLPDAGMutation.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
auto reverse(ContainerTy &&C)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool none_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
FormattedNumber format_hex(uint64_t N, unsigned Width, bool Upper=false)
format_hex - Output N as a fixed width hexadecimal.
DWARFExpression::Operation Op
auto count_if(R &&Range, UnaryPredicate P)
Wrapper function around std::count_if to count the number of times an element satisfying a given pred...
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
MCRegisterClass TargetRegisterClass
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Function object to check whether the second component of a container supported by std::get (like std:...