27#define DEBUG_TYPE "igrouplp"
33 cl::desc(
"Whether to use the exponential time solver to fit "
34 "the instructions to the pipeline as closely as "
40 cl::desc(
"The maximum number of scheduling group conflicts "
41 "which we attempt to solve with the exponential time "
42 "exact solver. Problem sizes greater than this will"
43 "be solved by the less accurate greedy algorithm. Selecting "
44 "solver by size is superseded by manually selecting "
45 "the solver (e.g. by amdgpu-igrouplp-exact-solver"));
49 cl::desc(
"The amount of branches that we are willing to explore with"
50 "the exact algorithm before giving up."));
54 cl::desc(
"Whether to use the cost heuristic to make choices as we "
55 "traverse the search space using the exact solver. Defaulted "
56 "to on, and if turned off, we will use the node order -- "
57 "attempting to put the later nodes in the later sched groups. "
58 "Experimentally, results are mixed, so this should be set on a "
59 "case-by-case basis."));
66class InstructionRule {
72 std::optional<SmallVector<SUnit *, 4>> Cache;
82 bool NeedsCache =
false)
89 virtual ~InstructionRule() =
default;
105 std::optional<unsigned> MaxSize;
118 static unsigned NumSchedGroups;
135 bool canAddSU(
SUnit &SU)
const;
140 void link(
SUnit &SU,
bool MakePred =
false);
144 int link(
SUnit &SU,
bool MakePred,
145 std::list<std::pair<SUnit *, SUnit *>> &AddedEdges);
154 void link(SchedGroup &OtherGroup);
157 bool isFull()
const {
return MaxSize && Collection.
size() >= *MaxSize; }
163 void addRule(std::shared_ptr<InstructionRule> NewRule) {
168 bool allowedByRules(
const SUnit *SU,
170 for (
auto &Rule : Rules) {
171 if (!Rule->apply(SU, Collection, SyncPipe))
178 void add(
SUnit &SU) {
180 <<
format_hex((
int)SGMask, 10,
true) <<
" adding "
186 void pop() { Collection.
pop_back(); }
189 void findCandidateSUnits(
T Begin,
T End,
190 SUnitsToCandidateSGsMap &SyncedInstrs);
195 void findCandidateSUnits(SUnitsToCandidateSGsMap &SyncedInstrs);
197 int getSyncID() {
return SyncID; }
199 int getSGID() {
return SGID; }
203 SchedGroup(
SchedGroupMask SGMask, std::optional<unsigned> MaxSize,
205 : SGMask(SGMask), MaxSize(MaxSize), DAG(DAG),
TII(
TII) {
206 SGID = NumSchedGroups++;
209 SchedGroup(
SchedGroupMask SGMask, std::optional<unsigned> MaxSize,
int SyncID,
211 : SGMask(SGMask), MaxSize(MaxSize), SyncID(SyncID), DAG(DAG),
TII(
TII) {
212 SGID = NumSchedGroups++;
216using SUToCandSGsPair = std::pair<SUnit *, SmallVector<int, 4>>;
228class PipelineSolver {
241 bool NeedsSolver =
false;
245 unsigned computeProblemSize();
256 int CurrConflInstNo = 0;
258 int CurrSyncGroupIdx = 0;
260 int BeginSyncGroupIdx = 0;
266 bool IsBottomUp =
true;
269 void advancePosition();
272 void retreatPosition();
281 template <
typename T>
282 void greedyFind(std::list<std::pair<SUnit *, SUnit *>> &AddedEdges,
T I,
T E);
287 template <
typename T>
294 template <
typename T>
void linkSchedGroups(
T I,
T E);
298 std::list<std::pair<SUnit *, SUnit *>> &AddedEdges);
304 class EdgeSetBuilder {
310 bool Initialized =
false;
314 template <
bool ComputePreds>
328 : SU(SU), SyncPipeline(SyncPipeline), IsBottomUp(IsBottomUp) {}
334 int build(
int SGID, std::list<std::pair<SUnit *, SUnit *>> &NewEdges);
337 template <
typename T>
339 std::list<std::pair<SUnit *, SUnit *>> &NewEdges);
345 template <
typename T>
346 int linkSUnit(
SUnit *SU,
int SGID,
347 std::list<std::pair<SUnit *, SUnit *>> &AddedEdges,
T I,
T E);
349 void removeEdges(
const std::list<std::pair<SUnit *, SUnit *>> &AddedEdges);
351 void convertSyncMapsToArrays();
363 : DAG(DAG), SyncedInstrs(SyncedInstrs),
364 SyncedSchedGroups(SyncedSchedGroups), IsBottomUp(IsBottomUp) {
366 for (
auto &PipelineInstrs : SyncedInstrs) {
367 if (!PipelineInstrs.second.
empty()) {
376 convertSyncMapsToArrays();
378 CurrPipeline = BestPipeline;
380 while (
static_cast<size_t>(BeginSyncGroupIdx) < PipelineInstrs.
size() &&
381 PipelineInstrs[BeginSyncGroupIdx].
empty())
384 if (
static_cast<size_t>(BeginSyncGroupIdx) >= PipelineInstrs.
size())
389void PipelineSolver::reset() {
391 for (
auto &SyncPipeline : CurrPipeline) {
392 for (
auto &SG : SyncPipeline) {
394 SG.Collection.
clear();
398 if (SchedBarr != TempCollection.
end())
399 SG.Collection.push_back(*SchedBarr);
403 CurrSyncGroupIdx = BeginSyncGroupIdx;
408void PipelineSolver::convertSyncMapsToArrays() {
409 for (
auto &SyncPipe : SyncedSchedGroups) {
410 BestPipeline.insert(BestPipeline.begin(), SyncPipe.second);
413 int PipelineIDx = SyncedInstrs.size() - 1;
414 PipelineInstrs.resize(SyncedInstrs.size());
415 for (
auto &SyncInstrMap : SyncedInstrs) {
416 for (
auto &SUsToCandSGs : SyncInstrMap.second) {
417 if (PipelineInstrs[PipelineIDx].empty()) {
418 PipelineInstrs[PipelineIDx].push_back(
419 std::pair(SUsToCandSGs.first, SUsToCandSGs.second));
422 auto *SortPosition = PipelineInstrs[PipelineIDx].begin();
425 while (SortPosition != PipelineInstrs[PipelineIDx].end() &&
426 SUsToCandSGs.first->NodeNum > SortPosition->first->NodeNum)
428 PipelineInstrs[PipelineIDx].insert(
429 SortPosition, std::pair(SUsToCandSGs.first, SUsToCandSGs.second));
435template <
typename T>
void PipelineSolver::linkSchedGroups(
T I,
T E) {
436 for (;
I !=
E; ++
I) {
438 for (
auto J = std::next(
I); J !=
E; ++J) {
445void PipelineSolver::makePipeline() {
447 for (
auto &SyncPipeline : BestPipeline) {
449 for (
auto &SG : SyncPipeline) {
452 SUnit *SGBarr =
nullptr;
453 for (
auto &SU : SG.Collection) {
454 if (SU->getInstr()->getOpcode() == AMDGPU::SCHED_GROUP_BARRIER)
461 SG.link(*SGBarr,
false);
465 for (
auto &SyncPipeline : BestPipeline) {
466 IsBottomUp ? linkSchedGroups(SyncPipeline.rbegin(), SyncPipeline.rend())
467 : linkSchedGroups(SyncPipeline.begin(), SyncPipeline.end());
472int PipelineSolver::linkSUnit(
473 SUnit *SU,
int SGID, std::list<std::pair<SUnit *, SUnit *>> &AddedEdges,
475 bool MakePred =
false;
478 if (
I->getSGID() == SGID) {
483 AddedCost += Group.link(*SU, MakePred, AddedEdges);
489template <
bool ComputePreds>
490void PipelineSolver::EdgeSetBuilder::computeReachable(
492 if (!Reachable.insert(Start).second)
497 while (!WorkList.
empty()) {
500 for (
const SDep &Dep : ComputePreds ? Current->
Preds : Current->
Succs) {
501 if (Reachable.insert(Dep.getSUnit()).second)
509 computeReachable<
true>(Preds, Start);
514 computeReachable<
false>(Succs, Start);
517int PipelineSolver::EdgeSetBuilder::build(
518 int SGID, std::list<std::pair<SUnit *, SUnit *>> &NewEdges) {
520 computePreds(InitialPreds, SU);
521 computeSuccs(Succs, SU);
526 return IsBottomUp ? buildImpl(SGID,
reverse(SyncPipeline), NewEdges)
534int PipelineSolver::EdgeSetBuilder::buildImpl(
536 std::list<std::pair<SUnit *, SUnit *>> &NewEdges) {
554 bool MakePred =
false;
555 for (SchedGroup &SG : SchedGroups) {
556 if (SG.getSGID() == SGID) {
561 for (
SUnit *
A : SG.Collection) {
562 if (
A->getInstr()->getOpcode() == AMDGPU::SCHED_GROUP_BARRIER)
573 NewEdges.emplace_back(SU,
A);
582 NewEdges.emplace_back(
A, SU);
583 computePreds(Preds,
A);
590int PipelineSolver::addEdges(
592 std::list<std::pair<SUnit *, SUnit *>> &AddedEdges) {
602 return IsBottomUp ? linkSUnit(SU, SGID, AddedEdges, SyncPipeline.
rbegin(),
604 : linkSUnit(SU, SGID, AddedEdges, SyncPipeline.
begin(),
608void PipelineSolver::removeEdges(
609 const std::list<std::pair<SUnit *, SUnit *>> &EdgesToRemove) {
612 for (
auto &PredSuccPair : EdgesToRemove) {
613 SUnit *Pred = PredSuccPair.first;
614 SUnit *Succ = PredSuccPair.second;
617 return P.getSUnit() == Pred && P.isArtificial();
619 if (Match != Succ->
Preds.end())
624void PipelineSolver::advancePosition() {
627 if (
static_cast<size_t>(CurrConflInstNo) >=
628 PipelineInstrs[CurrSyncGroupIdx].
size()) {
632 while (
static_cast<size_t>(CurrSyncGroupIdx) < PipelineInstrs.size() &&
633 PipelineInstrs[CurrSyncGroupIdx].empty())
638void PipelineSolver::retreatPosition() {
639 assert(CurrConflInstNo >= 0);
640 assert(CurrSyncGroupIdx >= 0);
642 if (CurrConflInstNo > 0) {
647 if (CurrConflInstNo == 0) {
650 if (CurrSyncGroupIdx == BeginSyncGroupIdx)
655 while (PipelineInstrs[CurrSyncGroupIdx].empty())
659 static_cast<int>(PipelineInstrs[CurrSyncGroupIdx].size() - 1);
663bool PipelineSolver::checkOptimal() {
664 if (
static_cast<size_t>(CurrSyncGroupIdx) == PipelineInstrs.size()) {
665 if (BestCost == -1 || CurrCost < BestCost) {
666 BestPipeline = CurrPipeline;
673 bool DoneExploring =
false;
674 if (MaxBranchesExplored > 0 && BranchesExplored >= MaxBranchesExplored)
675 DoneExploring =
true;
677 return (DoneExploring || BestCost == 0);
681void PipelineSolver::populateReadyList(
683 SUToCandSGsPair CurrSU = PipelineInstrs[CurrSyncGroupIdx][CurrConflInstNo];
684 auto SyncPipeline = CurrPipeline[CurrSyncGroupIdx];
685 assert(CurrSU.second.size() >= 1);
687 for (;
I !=
E; ++
I) {
688 std::list<std::pair<SUnit *, SUnit *>> AddedEdges;
690 SchedGroup *Match =
llvm::find_if(SyncPipeline, [CandSGID](SchedGroup &SG) {
691 return SG.getSGID() == CandSGID;
696 if (Match->isFull()) {
697 ReadyList.push_back(std::pair(*
I, MissPenalty));
701 int TempCost = addEdges(SyncPipeline, CurrSU.first, CandSGID, AddedEdges);
702 ReadyList.push_back(std::pair(*
I, TempCost));
703 removeEdges(AddedEdges);
705 ReadyList.push_back(std::pair(*
I, -1));
711 assert(ReadyList.size() == CurrSU.second.size());
714bool PipelineSolver::solveExact() {
718 if (
static_cast<size_t>(CurrSyncGroupIdx) == PipelineInstrs.size())
721 assert(
static_cast<size_t>(CurrSyncGroupIdx) < PipelineInstrs.size());
722 assert(
static_cast<size_t>(CurrConflInstNo) <
723 PipelineInstrs[CurrSyncGroupIdx].
size());
724 SUToCandSGsPair CurrSU = PipelineInstrs[CurrSyncGroupIdx][CurrConflInstNo];
725 LLVM_DEBUG(
dbgs() <<
"Fitting " << *CurrSU.first <<
" in Pipeline # "
726 << CurrSyncGroupIdx <<
"\n");
731 IsBottomUp ? populateReadyList(ReadyList, CurrSU.second.
rbegin(),
732 CurrSU.second.rend())
733 : populateReadyList(ReadyList, CurrSU.second.
begin(),
734 CurrSU.second.end());
736 auto *
I = ReadyList.
begin();
737 auto *
E = ReadyList.
end();
738 for (;
I !=
E; ++
I) {
742 if (BestCost != -1 && (CurrCost +
I->second > BestCost))
745 int CandSGID =
I->first;
747 std::list<std::pair<SUnit *, SUnit *>> AddedEdges;
748 auto &SyncPipeline = CurrPipeline[CurrSyncGroupIdx];
749 SchedGroup *Match =
llvm::find_if(SyncPipeline, [CandSGID](SchedGroup &SG) {
750 return SG.getSGID() == CandSGID;
757 if (!Match->allowedByRules(CurrSU.first, SyncPipeline))
761 << (
int)Match->getMask() <<
"and ID " << CandSGID
763 Match->add(*CurrSU.first);
764 AddedCost = addEdges(SyncPipeline, CurrSU.first, CandSGID, AddedEdges);
765 LLVM_DEBUG(
dbgs() <<
"Cost of Assignment: " << AddedCost <<
"\n");
766 CurrCost += AddedCost;
769 bool FinishedExploring =
false;
772 if (CurrCost < BestCost || BestCost == -1) {
774 FinishedExploring = BestCost != 0;
775 if (!FinishedExploring)
781 CurrCost -= AddedCost;
782 removeEdges(AddedEdges);
784 CurrPipeline[CurrSyncGroupIdx] = SyncPipeline;
785 if (FinishedExploring)
792 CurrCost += MissPenalty;
797 bool FinishedExploring =
false;
798 if (CurrCost < BestCost || BestCost == -1) {
800 bool FinishedExploring = BestCost != 0;
801 if (!FinishedExploring)
807 CurrCost -= MissPenalty;
808 return FinishedExploring;
812void PipelineSolver::greedyFind(
813 std::list<std::pair<SUnit *, SUnit *>> &AddedEdges,
T I,
T E) {
814 SUToCandSGsPair CurrSU = PipelineInstrs[CurrSyncGroupIdx][CurrConflInstNo];
818 std::list<std::pair<SUnit *, SUnit *>> Edges;
821 std::optional<GroupInfo> Best;
823 auto &SyncPipeline = CurrPipeline[CurrSyncGroupIdx];
824 LLVM_DEBUG(
dbgs() <<
"Fitting " << *CurrSU.first <<
" in Pipeline # "
825 << CurrSyncGroupIdx <<
"\n");
827 EdgeSetBuilder Builder(CurrSU.first, SyncPipeline, IsBottomUp);
833 for (;
I !=
E; ++
I) {
835 SchedGroup *Match =
llvm::find_if(SyncPipeline, [CandSGID](SchedGroup &SG) {
836 return SG.getSGID() == CandSGID;
840 LLVM_DEBUG(
dbgs() <<
"Trying SGID # " << CandSGID <<
" with Mask "
841 << (
int)Match->getMask() <<
"\n");
843 if (Match->isFull()) {
847 if (!Match->allowedByRules(CurrSU.first, SyncPipeline)) {
848 LLVM_DEBUG(
dbgs() <<
"SGID # " << CandSGID <<
" has conflicting rule\n");
852 std::list<std::pair<SUnit *, SUnit *>> TempEdges;
853 int TempCost = Builder.build(CandSGID, TempEdges);
856 if (!Best || TempCost < Best->Cost) {
857 Best = {Match, TempEdges, TempCost};
864 SchedGroup *SG = Best->SG;
865 std::list<std::pair<SUnit *, SUnit *>> &Edges = Best->Edges;
867 SG->add(*CurrSU.first);
868 if (AddedEdges.empty())
871 AddedEdges.splice(std::prev(AddedEdges.cend()), Edges);
873 for (
const std::pair<SUnit *, SUnit *> &
E : Edges) {
874 if (!SG->tryAddEdge(
E.first,
E.second))
878 LLVM_DEBUG(
dbgs() <<
"Best Group has ID: " << SG->getSGID() <<
" and Mask"
879 << (
int)SG->getMask() <<
"\n");
880 BestCost += Best->Cost;
882 BestCost += MissPenalty;
885bool PipelineSolver::solveGreedy() {
887 std::list<std::pair<SUnit *, SUnit *>> AddedEdges;
889 while (
static_cast<size_t>(CurrSyncGroupIdx) < PipelineInstrs.size()) {
890 SUToCandSGsPair CurrSU = PipelineInstrs[CurrSyncGroupIdx][CurrConflInstNo];
892 ? greedyFind(AddedEdges, CurrSU.second.rbegin(), CurrSU.second.rend())
893 : greedyFind(AddedEdges, CurrSU.second.begin(), CurrSU.second.end());
896 BestPipeline = CurrPipeline;
897 removeEdges(AddedEdges);
901unsigned PipelineSolver::computeProblemSize() {
902 unsigned ProblemSize = 0;
903 for (
auto &PipeConflicts : PipelineInstrs) {
904 ProblemSize +=
static_cast<unsigned>(PipeConflicts.size());
910void PipelineSolver::solve() {
914 unsigned ProblemSize = computeProblemSize();
917 bool BelowCutoff = (CutoffForExact > 0) && ProblemSize <= CutoffForExact;
918 MissPenalty = (ProblemSize / 2) + 1;
921 if (EnableExactSolver || BelowCutoff) {
925 LLVM_DEBUG(
dbgs() <<
"Greedy produced best cost of " << BestCost <<
"\n");
929 LLVM_DEBUG(
dbgs() <<
"Exact produced best cost of " << BestCost <<
"\n");
934 LLVM_DEBUG(
dbgs() <<
"Greedy produced best cost of " << BestCost <<
"\n");
951 virtual bool applyIGLPStrategy(
960 bool IsBottomUp =
true;
965 virtual ~IGLPStrategy() =
default;
968class MFMASmallGemmOpt final :
public IGLPStrategy {
971 bool applyIGLPStrategy(
982 : IGLPStrategy(DAG,
TII) {
987bool MFMASmallGemmOpt::applyIGLPStrategy(
992 unsigned MFMACount = 0;
994 if (
TII->isMFMAorWMMA(
I))
997 const unsigned PipelineSyncID = 0;
998 SchedGroup *SG =
nullptr;
999 for (
unsigned I = 0;
I < MFMACount * 3; ++
I) {
1000 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1002 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1004 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1006 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1012class MFMAExpInterleaveOpt final :
public IGLPStrategy {
1015 static unsigned TransPipeCount;
1017 static unsigned MFMAPipeCount;
1019 static unsigned AddPipeCount;
1021 static unsigned MFMAEnablement;
1023 static unsigned ExpRequirement;
1025 static unsigned MFMAChains;
1030 static bool HasChainBetweenCvt;
1032 static std::optional<unsigned> FirstPipeDSR;
1041 class IsPipeExp final :
public InstructionRule {
1046 auto *DAG = SyncPipe[0].DAG;
1048 if (Cache->empty()) {
1049 auto I = DAG->SUnits.rbegin();
1050 auto E = DAG->SUnits.rend();
1051 for (;
I !=
E;
I++) {
1052 if (
TII->isMFMAorWMMA(*
I->getInstr()))
1053 Cache->push_back(&*
I);
1059 auto Reaches =
any_of(*Cache, [&SU, &DAG](
SUnit *TargetSU) {
1060 return DAG->IsReachable(TargetSU,
const_cast<SUnit *
>(SU));
1065 IsPipeExp(
const SIInstrInfo *
TII,
unsigned SGID,
bool NeedsCache =
false)
1066 : InstructionRule(
TII, SGID, NeedsCache) {}
1071 class EnablesNthMFMA final :
public InstructionRule {
1078 bool FoundTrans =
false;
1079 unsigned Counter = 1;
1080 auto *DAG = SyncPipe[0].DAG;
1082 if (Cache->empty()) {
1083 auto I = DAG->SUnits.begin();
1084 auto E = DAG->SUnits.end();
1085 for (;
I !=
E;
I++) {
1086 if (FoundTrans &&
TII->isMFMAorWMMA(*
I->getInstr())) {
1088 Cache->push_back(&*
I);
1093 if (!FoundTrans &&
TII->isTRANS(
I->getInstr()->getOpcode()))
1100 return DAG->IsReachable((*Cache)[0],
const_cast<SUnit *
>(SU));
1104 bool NeedsCache =
false)
1110 class EnablesNthMFMAInChain final :
public InstructionRule {
1118 auto *DAG = SyncPipe[0].DAG;
1120 if (!SU || !
TII->isMFMAorWMMA(*ChainSeed->
getInstr()))
1123 if (Cache->empty()) {
1124 auto *TempSU = ChainSeed;
1129 for (
auto &Succ : TempSU->Succs) {
1130 if (
TII->isMFMAorWMMA(*Succ.getSUnit()->getInstr())) {
1131 TempSU = Succ.getSUnit();
1140 Cache->push_back(TempSU);
1146 return DAG->IsReachable((*Cache)[0],
const_cast<SUnit *
>(SU));
1149 EnablesNthMFMAInChain(
unsigned Number,
SUnit *ChainSeed,
1151 bool NeedsCache =
false)
1153 ChainSeed(ChainSeed) {}
1159 class LessThanNSuccs final :
public InstructionRule {
1162 bool HasIntermediary =
false;
1167 if (!SyncPipe.
size())
1171 return Succ.getKind() == SDep::Data;
1173 if (SuccSize >=
Size)
1176 if (HasIntermediary) {
1177 for (
auto Succ : SU->
Succs) {
1180 return SuccSucc.getKind() == SDep::Data;
1182 if (SuccSize >=
Size)
1190 bool HasIntermediary =
false,
bool NeedsCache =
false)
1191 : InstructionRule(
TII, SGID, NeedsCache),
Size(
Size),
1192 HasIntermediary(HasIntermediary) {}
1199 class GreaterThanOrEqualToNSuccs final :
public InstructionRule {
1202 bool HasIntermediary =
false;
1207 if (!SyncPipe.
size())
1211 return Succ.getKind() == SDep::Data;
1213 if (SuccSize >=
Size)
1216 if (HasIntermediary) {
1217 for (
auto Succ : SU->
Succs) {
1220 return SuccSucc.getKind() == SDep::Data;
1222 if (SuccSize >=
Size)
1230 unsigned SGID,
bool HasIntermediary =
false,
1231 bool NeedsCache =
false)
1232 : InstructionRule(
TII, SGID, NeedsCache),
Size(
Size),
1233 HasIntermediary(HasIntermediary) {}
1237 class IsCvt final :
public InstructionRule {
1242 return Opc == AMDGPU::V_CVT_F16_F32_e32 ||
1243 Opc == AMDGPU::V_CVT_I32_F32_e32;
1245 IsCvt(
const SIInstrInfo *
TII,
unsigned SGID,
bool NeedsCache =
false)
1246 : InstructionRule(
TII, SGID, NeedsCache) {}
1250 class IsFMA final :
public InstructionRule {
1257 IsFMA(
const SIInstrInfo *
TII,
unsigned SGID,
bool NeedsCache =
false)
1258 : InstructionRule(
TII, SGID, NeedsCache) {}
1262 class IsPipeAdd final :
public InstructionRule {
1268 IsPipeAdd(
const SIInstrInfo *
TII,
unsigned SGID,
bool NeedsCache =
false)
1269 : InstructionRule(
TII, SGID, NeedsCache) {}
1274 class IsSuccOfPrevNthGroup final :
public InstructionRule {
1276 unsigned Distance = 1;
1281 SchedGroup *OtherGroup =
nullptr;
1282 if (!SyncPipe.
size())
1285 for (
auto &PipeSG : SyncPipe) {
1286 if ((
unsigned)PipeSG.getSGID() == SGID - Distance)
1287 OtherGroup = &PipeSG;
1292 if (!OtherGroup->Collection.size())
1295 for (
auto &OtherEle : OtherGroup->Collection) {
1296 for (
auto &Succ : OtherEle->Succs) {
1297 if (Succ.getSUnit() == SU && Succ.getKind() ==
SDep::Data)
1305 unsigned SGID,
bool NeedsCache =
false)
1306 : InstructionRule(
TII, SGID, NeedsCache), Distance(Distance) {}
1311 class IsReachableFromPrevNthGroup final :
public InstructionRule {
1313 unsigned Distance = 1;
1318 SchedGroup *OtherGroup =
nullptr;
1319 if (!SyncPipe.
size())
1322 for (
auto &PipeSG : SyncPipe) {
1323 if ((
unsigned)PipeSG.getSGID() == SGID - Distance)
1324 OtherGroup = &PipeSG;
1329 if (!OtherGroup->Collection.size())
1332 auto *DAG = SyncPipe[0].DAG;
1334 for (
auto &OtherEle : OtherGroup->Collection)
1335 if (DAG->IsReachable(
const_cast<SUnit *
>(SU), OtherEle))
1340 IsReachableFromPrevNthGroup(
unsigned Distance,
const SIInstrInfo *
TII,
1341 unsigned SGID,
bool NeedsCache =
false)
1342 : InstructionRule(
TII, SGID, NeedsCache), Distance(Distance) {}
1346 class OccursAtOrAfterNode final :
public InstructionRule {
1357 bool NeedsCache =
false)
1363 class IsExactMFMA final :
public InstructionRule {
1371 if (!SU || !
TII->isMFMAorWMMA(*ChainSeed->
getInstr()))
1374 if (Cache->empty()) {
1375 auto *TempSU = ChainSeed;
1380 for (
auto &Succ : TempSU->Succs) {
1381 if (
TII->isMFMAorWMMA(*Succ.getSUnit()->getInstr())) {
1382 TempSU = Succ.getSUnit();
1391 Cache->push_back(TempSU);
1397 return (*Cache)[0] == SU;
1401 unsigned SGID,
bool NeedsCache =
false)
1403 ChainSeed(ChainSeed) {}
1409 class OccursAfterExp final :
public InstructionRule {
1414 auto *DAG = SyncPipe[0].DAG;
1415 if (Cache->empty()) {
1416 for (
auto &SU : DAG->SUnits)
1418 Cache->push_back(&SU);
1425 return SU->
NodeNum > (*Cache)[0]->NodeNum;
1429 bool NeedsCache =
false)
1430 : InstructionRule(
TII, SGID, NeedsCache) {}
1434 bool applyIGLPStrategy(
1443 : IGLPStrategy(DAG,
TII) {
1448unsigned MFMAExpInterleaveOpt::TransPipeCount = 0;
1449unsigned MFMAExpInterleaveOpt::MFMAPipeCount = 0;
1450unsigned MFMAExpInterleaveOpt::AddPipeCount = 0;
1451unsigned MFMAExpInterleaveOpt::MFMAEnablement = 0;
1452unsigned MFMAExpInterleaveOpt::ExpRequirement = 0;
1453unsigned MFMAExpInterleaveOpt::MFMAChains = 0;
1454bool MFMAExpInterleaveOpt::HasCvt =
false;
1455bool MFMAExpInterleaveOpt::HasChainBetweenCvt =
false;
1456std::optional<unsigned> MFMAExpInterleaveOpt::FirstPipeDSR = std::nullopt;
1465 auto isBitPack = [](
unsigned Opc) {
1466 return Opc == AMDGPU::V_PACK_B32_F16_e64 ||
Opc == AMDGPU::V_PERM_B32_e64;
1469 auto isCvt = [](
unsigned Opc) {
1470 return Opc == AMDGPU::V_CVT_F16_F32_e32 ||
Opc == AMDGPU::V_CVT_I32_F32_e32;
1473 auto isAdd = [](
unsigned Opc) {
return Opc == AMDGPU::V_ADD_F32_e32; };
1480 if (SU.
Succs.size() >= 7)
1482 for (
auto &Succ : SU.
Succs) {
1483 if (Succ.getSUnit()->Succs.size() >= 7)
1502 if (!(PackSUs.
size() && MFMAPipeCands.
size() && ExpPipeCands.
size()))
1507 std::optional<SUnit *> TempMFMA;
1508 std::optional<SUnit *> TempExp;
1510 for (
auto &PredSU : ExpPipeCands) {
1511 for (
auto &SuccSU : MFMAPipeCands) {
1524 if (!(TempExp && TempMFMA))
1527 HasChainBetweenCvt =
none_of((*TempExp)->Succs, [&isCvt](
SDep &Succ) {
1528 return isCvt(Succ.getSUnit()->getInstr()->getOpcode());
1532 for (
auto &SuccSU : MFMAPipeCands) {
1533 if (MFMAPipeSUs.
size() &&
1534 any_of(MFMAPipeSUs, [&SuccSU](
SUnit *PotentialMatch) {
1535 return PotentialMatch->
NodeNum == SuccSU->NodeNum;
1539 for (
auto &PredSU : ExpPipeCands) {
1547 MFMAPipeCount =
static_cast<unsigned>(MFMAPipeSUs.
size());
1549 assert(TempExp && TempMFMA);
1550 assert(MFMAPipeCount > 0);
1552 std::optional<SUnit *> TempCvt;
1553 for (
auto &SuccSU : CvtSUs) {
1561 if (TempCvt.has_value()) {
1562 for (
auto &SuccSU : MFMAPipeSUs) {
1571 for (
auto &MFMAPipeSU : MFMAPipeSUs) {
1575 return TII->isMFMAorWMMA(*Succ.getSUnit()->getInstr());
1577 MFMAChainSeeds.push_back(MFMAPipeSU);
1585 for (
auto Pred : MFMAChainSeeds[0]->Preds) {
1586 if (
TII->isDS(Pred.getSUnit()->getInstr()->getOpcode()) &&
1587 Pred.getSUnit()->getInstr()->mayLoad())
1588 FirstPipeDSR = Pred.getSUnit()->NodeNum;
1592 unsigned PackSuccCount =
static_cast<unsigned>(
1598 unsigned PackPredCount =
static_cast<unsigned>(
1600 auto Opc = Pred.getSUnit()->getInstr()->getOpcode();
1601 return isBitPack(Opc);
1605 auto Opc = Pred.getSUnit()->getInstr()->getOpcode();
1606 return isBitPack(Opc);
1609 if (PackPred == (*TempMFMA)->Preds.end())
1615 MFMAEnablement =
static_cast<unsigned>(
1617 return TII->isMFMAorWMMA(*Succ.getSUnit()->getInstr());
1621 MFMAEnablement *= PackSuccCount;
1624 ExpRequirement =
static_cast<unsigned>(
1626 return DAG->
IsReachable(PackPred->getSUnit(), ExpBase);
1629 ExpRequirement *= PackPredCount;
1639 MFMAChainSeeds.clear();
1646bool MFMAExpInterleaveOpt::applyIGLPStrategy(
1651 bool IsSmallKernelType =
1652 MFMAEnablement == 2 && ExpRequirement == 4 && TransPipeCount == 32;
1653 bool IsLargeKernelType =
1654 MFMAEnablement == 4 && ExpRequirement == 4 && TransPipeCount == 64;
1656 if (!(IsSmallKernelType || IsLargeKernelType))
1662 unsigned PipelineSyncID = 0;
1663 SchedGroup *SG =
nullptr;
1665 unsigned MFMAChain = 0;
1666 unsigned PositionInChain = 0;
1667 unsigned CurrMFMAForTransPosition = 0;
1669 auto incrementTransPosition = [&MFMAChain, &PositionInChain,
1670 &CurrMFMAForTransPosition]() {
1671 CurrMFMAForTransPosition += MFMAEnablement;
1672 PositionInChain = (CurrMFMAForTransPosition / MFMAChains);
1673 MFMAChain = CurrMFMAForTransPosition % MFMAChains;
1676 auto getNextTransPositionInChain = [&CurrMFMAForTransPosition]() {
1677 auto TempMFMAForTrans = CurrMFMAForTransPosition + MFMAEnablement;
1678 return (TempMFMAForTrans / MFMAChains);
1681 auto getNextTransMFMAChain = [&CurrMFMAForTransPosition]() {
1682 auto TempMFMAForTrans = CurrMFMAForTransPosition + MFMAEnablement;
1683 return TempMFMAForTrans % MFMAChains;
1686 unsigned CurrMFMAPosition = 0;
1687 unsigned MFMAChainForMFMA = 0;
1688 unsigned PositionInChainForMFMA = 0;
1690 auto incrementMFMAPosition = [&CurrMFMAPosition, &MFMAChainForMFMA,
1691 &PositionInChainForMFMA]() {
1693 MFMAChainForMFMA = CurrMFMAPosition % MFMAChains;
1694 PositionInChainForMFMA = CurrMFMAPosition / MFMAChains;
1698 assert(IsPostRA || MFMAChainSeeds.size() == MFMAChains);
1700 bool UsesFMA = IsSmallKernelType || !IsPostRA;
1701 bool UsesDSRead = IsLargeKernelType && !IsPostRA && FirstPipeDSR;
1702 bool UsesCvt = HasCvt && (IsSmallKernelType || !IsPostRA);
1703 bool UsesVALU = IsSmallKernelType;
1708 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1710 if (!IsPostRA && MFMAChains) {
1711 SG->addRule(std::make_shared<EnablesNthMFMAInChain>(
1712 PositionInChain, MFMAChainSeeds[MFMAChain],
TII, SG->getSGID(),
1716 std::make_shared<EnablesNthMFMA>(1,
TII, SG->getSGID(),
true));
1717 SG->addRule(std::make_shared<IsFMA>(
TII, SG->getSGID()));
1718 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1721 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1723 if (!IsPostRA && MFMAChains) {
1724 SG->addRule(std::make_shared<EnablesNthMFMAInChain>(
1725 getNextTransPositionInChain(),
1726 MFMAChainSeeds[getNextTransMFMAChain()],
TII, SG->getSGID(),
true));
1728 SG->addRule(std::make_shared<EnablesNthMFMA>(MFMAEnablement + 1,
TII,
1729 SG->getSGID(),
true));
1730 SG->addRule(std::make_shared<IsFMA>(
TII, SG->getSGID()));
1731 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1735 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1737 SG->addRule(std::make_shared<OccursAtOrAfterNode>(*FirstPipeDSR,
TII,
1739 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1743 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1745 if (!IsPostRA && MFMAChains)
1746 SG->addRule(std::make_shared<EnablesNthMFMAInChain>(
1747 PositionInChain, MFMAChainSeeds[MFMAChain],
TII, SG->getSGID(),
true));
1749 SG->addRule(std::make_shared<EnablesNthMFMA>(1,
TII, SG->getSGID(),
true));
1750 SG->addRule(std::make_shared<IsPipeExp>(
TII, SG->getSGID(),
true));
1751 SG->addRule(std::make_shared<LessThanNSuccs>(8,
TII, SG->getSGID(),
1752 HasChainBetweenCvt));
1753 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1755 incrementTransPosition();
1758 for (
unsigned I = 0;
I < ExpRequirement;
I++) {
1761 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1763 SG->addRule(std::make_shared<IsCvt>(
TII, SG->getSGID()));
1764 if (HasChainBetweenCvt)
1765 SG->addRule(std::make_shared<IsReachableFromPrevNthGroup>(
1766 1 + (2 + UsesFMA) *
I,
TII, SG->getSGID()));
1768 SG->addRule(std::make_shared<IsSuccOfPrevNthGroup>(
1769 1 + (2 + UsesFMA) *
I,
TII, SG->getSGID()));
1770 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1775 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1777 if (!IsPostRA && MFMAChains) {
1778 SG->addRule(std::make_shared<EnablesNthMFMAInChain>(
1779 getNextTransPositionInChain(),
1780 MFMAChainSeeds[getNextTransMFMAChain()],
TII, SG->getSGID(),
true));
1782 SG->addRule(std::make_shared<EnablesNthMFMA>(2 * MFMAEnablement + 1,
1783 TII, SG->getSGID(),
true));
1784 SG->addRule(std::make_shared<IsFMA>(
TII, SG->getSGID()));
1785 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1789 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1791 if (!IsPostRA && MFMAChains)
1792 SG->addRule(std::make_shared<EnablesNthMFMAInChain>(
1793 PositionInChain, MFMAChainSeeds[MFMAChain],
TII, SG->getSGID(),
1796 SG->addRule(std::make_shared<EnablesNthMFMA>(MFMAEnablement + 1,
TII,
1797 SG->getSGID(),
true));
1798 SG->addRule(std::make_shared<IsPipeExp>(
TII, SG->getSGID(),
true));
1799 SG->addRule(std::make_shared<LessThanNSuccs>(8,
TII, SG->getSGID(),
1800 HasChainBetweenCvt));
1801 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1806 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1808 SG->addRule(std::make_shared<IsPipeExp>(
TII, SG->getSGID(),
true));
1809 SG->addRule(std::make_shared<GreaterThanOrEqualToNSuccs>(
1810 8,
TII, SG->getSGID(), HasChainBetweenCvt));
1811 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1816 unsigned MFMARatio =
1817 MFMAEnablement > ExpRequirement ? MFMAEnablement / ExpRequirement : 1;
1820 MFMAEnablement > ExpRequirement ? 1 : ExpRequirement / MFMAEnablement;
1822 unsigned RemainingExp = TransPipeCount > (2 * ExpRequirement)
1823 ? TransPipeCount - (2 * ExpRequirement)
1825 unsigned ExpLoopCount = RemainingExp / ExpRatio;
1827 unsigned MFMAInLoop = MFMAPipeCount > (MFMAEnablement * 2)
1828 ? MFMAPipeCount - (MFMAEnablement * 2)
1830 unsigned MFMALoopCount = MFMAInLoop / MFMARatio;
1832 AddPipeCount < MFMAPipeCount ? 1 : AddPipeCount / MFMAPipeCount;
1833 unsigned LoopSize = std::min(ExpLoopCount, MFMALoopCount);
1835 for (
unsigned I = 0;
I < LoopSize;
I++) {
1836 if (!(
I * ExpRatio % ExpRequirement))
1837 incrementTransPosition();
1840 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1842 if (!IsPostRA && MFMAChains)
1843 SG->addRule(std::make_shared<IsExactMFMA>(
1844 PositionInChainForMFMA, MFMAChainSeeds[MFMAChainForMFMA],
TII,
1845 SG->getSGID(),
true));
1847 SG->addRule(std::make_shared<OccursAfterExp>(
TII, SG->getSGID(),
true));
1848 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1849 incrementMFMAPosition();
1852 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1854 SG->addRule(std::make_shared<IsPipeAdd>(
TII, SG->getSGID()));
1855 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1858 if (UsesDSRead && !(
I % 4)) {
1859 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1861 SG->addRule(std::make_shared<OccursAtOrAfterNode>(*FirstPipeDSR,
TII,
1863 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1867 for (
unsigned J = 0; J < ExpRatio; J++) {
1868 auto MFMAOffset = (1 + UsesVALU) * MFMARatio * (
I + 1);
1869 auto MaxMFMAOffset =
1870 (1 + UsesVALU) * ExpRequirement * MFMARatio / ExpRatio;
1874 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1876 SG->addRule(std::make_shared<IsCvt>(
TII, SG->getSGID()));
1877 auto BaseDiff = (2 + UsesFMA) * (ExpRequirement - 1) + 1;
1878 auto DSROffset =
I / 4 + 1;
1879 auto MaxDSROffset = MaxMFMAOffset / 4;
1881 auto ExpOffset =
I * ExpRatio + J >= ExpRequirement ? 0 : 1;
1882 auto CurrentOffset = UsesDSRead * std::min(MaxDSROffset, DSROffset) +
1883 std::min(MaxMFMAOffset, MFMAOffset) + BaseDiff +
1885 if (HasChainBetweenCvt)
1886 SG->addRule(std::make_shared<IsReachableFromPrevNthGroup>(
1887 CurrentOffset,
TII, SG->getSGID()));
1889 SG->addRule(std::make_shared<IsSuccOfPrevNthGroup>(CurrentOffset,
TII,
1891 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1896 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1898 if (!IsPostRA && MFMAChains)
1899 SG->addRule(std::make_shared<EnablesNthMFMAInChain>(
1900 getNextTransPositionInChain(),
1901 MFMAChainSeeds[getNextTransMFMAChain()],
TII, SG->getSGID(),
1904 SG->addRule(std::make_shared<EnablesNthMFMA>(
1905 (((
I * ExpRatio + J) / ExpRequirement) + 3) * MFMAEnablement + 1,
1906 TII, SG->getSGID(),
true));
1907 SG->addRule(std::make_shared<IsFMA>(
TII, SG->getSGID()));
1908 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1912 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1914 if (!IsPostRA && MFMAChains)
1915 SG->addRule(std::make_shared<EnablesNthMFMAInChain>(
1916 PositionInChain, MFMAChainSeeds[MFMAChain],
TII, SG->getSGID(),
1919 SG->addRule(std::make_shared<EnablesNthMFMA>(
1920 (((
I * ExpRatio + J) / ExpRequirement) + 2) * MFMAEnablement + 1,
1921 TII, SG->getSGID(),
true));
1922 SG->addRule(std::make_shared<IsPipeExp>(
TII, SG->getSGID(),
true));
1923 SG->addRule(std::make_shared<LessThanNSuccs>(8,
TII, SG->getSGID(),
1924 HasChainBetweenCvt));
1925 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1930 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1932 SG->addRule(std::make_shared<OccursAfterExp>(
TII, SG->getSGID(),
true));
1933 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1937class MFMAExpSimpleInterleaveOpt final :
public IGLPStrategy {
1939 bool applyIGLPStrategy(
1950 : IGLPStrategy(DAG,
TII) {
1955bool MFMAExpSimpleInterleaveOpt::applyIGLPStrategy(
1960 unsigned MFMACount = 0;
1962 if (
TII->isMFMAorWMMA(
I))
1965 const unsigned PipelineSyncID = 0;
1966 for (
unsigned I = 0;
I < MFMACount * 3; ++
I) {
1967 SchedGroup *SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1969 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1971 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1973 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1979class MFMASmallGemmSingleWaveOpt final :
public IGLPStrategy {
1982 class EnablesInitialMFMA final :
public InstructionRule {
1986 if (!SyncPipe.
size())
1989 if (!Cache->size()) {
1990 for (
auto &Elt : SyncPipe[0].DAG->
SUnits) {
1991 if (
TII->isMFMAorWMMA(*Elt.getInstr())) {
1995 Cache->push_back(&Elt);
2000 auto *DAG = SyncPipe[0].DAG;
2001 for (
auto &Elt : *Cache) {
2009 bool NeedsCache =
false)
2010 : InstructionRule(
TII, SGID, NeedsCache) {}
2014 class IsPermForDSW final :
public InstructionRule {
2019 if (
MI->getOpcode() != AMDGPU::V_PERM_B32_e64)
2022 bool FitsInGroup =
false;
2024 if (!Collection.
size()) {
2025 for (
auto &Succ : SU->
Succs) {
2026 SUnit *SuccUnit = Succ.getSUnit();
2029 Cache->push_back(SuccUnit);
2040 return ThisSucc.getSUnit() == Elt;
2045 IsPermForDSW(
const SIInstrInfo *
TII,
unsigned SGID,
bool NeedsCache =
false)
2046 : InstructionRule(
TII, SGID, NeedsCache) {}
2050 class IsSuccOfPrevGroup final :
public InstructionRule {
2054 SchedGroup *OtherGroup =
nullptr;
2055 for (
auto &PipeSG : SyncPipe) {
2056 if ((
unsigned)PipeSG.getSGID() == SGID - 1) {
2057 OtherGroup = &PipeSG;
2063 if (!OtherGroup->Collection.size())
2067 return any_of(OtherGroup->Collection, [&SU](
SUnit *Elt) {
2068 return any_of(Elt->Succs,
2069 [&SU](SDep &Succ) { return Succ.getSUnit() == SU; });
2073 bool NeedsCache =
false)
2074 : InstructionRule(
TII, SGID, NeedsCache) {}
2078 class VMEMSize final :
public InstructionRule {
2083 if (
MI->getOpcode() == TargetOpcode::BUNDLE)
2085 if (!Collection.
size())
2090 auto TRI =
TII->getRegisterInfo();
2091 auto &
MRI =
MI->getMF()->getRegInfo();
2092 for (
auto &Elt : Collection) {
2093 auto Op = Elt->getInstr()->getOperand(0);
2095 TRI.getRegSizeInBits(*
TRI.getRegClassForOperandReg(
MRI,
Op));
2099 if (NumBits < 128) {
2101 if (NumBits +
TRI.getRegSizeInBits(*
TRI.getRegClassForOperandReg(
2102 MRI,
MI->getOperand(0))) <=
2110 VMEMSize(
const SIInstrInfo *
TII,
unsigned SGID,
bool NeedsCache =
false)
2111 : InstructionRule(
TII, SGID, NeedsCache) {}
2116 class SharesPredWithPrevNthGroup final :
public InstructionRule {
2118 unsigned Distance = 1;
2123 SchedGroup *OtherGroup =
nullptr;
2124 if (!SyncPipe.
size())
2127 if (!Cache->size()) {
2129 for (
auto &PipeSG : SyncPipe) {
2130 if ((
unsigned)PipeSG.getSGID() == SGID - Distance) {
2131 OtherGroup = &PipeSG;
2137 if (!OtherGroup->Collection.size())
2140 for (
auto &OtherEle : OtherGroup->Collection) {
2141 for (
auto &Pred : OtherEle->Preds) {
2142 if (Pred.getSUnit()->getInstr()->getOpcode() ==
2143 AMDGPU::V_PERM_B32_e64)
2144 Cache->push_back(Pred.getSUnit());
2153 auto *DAG = SyncPipe[0].DAG;
2160 SharesPredWithPrevNthGroup(
unsigned Distance,
const SIInstrInfo *
TII,
2161 unsigned SGID,
bool NeedsCache =
false)
2162 : InstructionRule(
TII, SGID, NeedsCache), Distance(Distance) {}
2166 bool applyIGLPStrategy(
2177 : IGLPStrategy(DAG,
TII) {
2182static unsigned DSWCount = 0;
2183static unsigned DSWWithPermCount = 0;
2184static unsigned DSWWithSharedVMEMCount = 0;
2186bool MFMASmallGemmSingleWaveOpt::applyIGLPStrategy(
2187 DenseMap<int, SUnitsToCandidateSGsMap> &SyncedInstrs,
2190 unsigned MFMACount = 0;
2191 unsigned DSRCount = 0;
2193 bool IsInitial =
Phase == AMDGPU::SchedulingPhase::Initial;
2195 assert((!IsInitial || (DSWCount == 0 && DSWWithPermCount == 0 &&
2196 DSWWithSharedVMEMCount == 0)) &&
2197 "DSWCounters should be zero in pre-RA scheduling!");
2199 for (
auto &SU : DAG->
SUnits) {
2200 auto *
I = SU.getInstr();
2201 if (
TII->isMFMAorWMMA(*
I))
2203 else if (
TII->isDS(*
I)) {
2206 else if (
I->mayStore() && IsInitial) {
2208 for (
auto Pred : SU.Preds) {
2209 if (Pred.getSUnit()->getInstr()->getOpcode() ==
2210 AMDGPU::V_PERM_B32_e64) {
2220 DSWWithPermCount =
static_cast<unsigned>(DSWithPerms.
size());
2221 auto *
I = DSWithPerms.
begin();
2222 auto *
E = DSWithPerms.
end();
2230 DenseMap<MachineInstr *, SUnit *> VMEMLookup;
2232 for (;
I !=
E;
I++) {
2233 SUnit *Cand =
nullptr;
2234 bool MissedAny =
false;
2235 for (
auto &Pred : (*I)->Preds) {
2236 if (Pred.getSUnit()->getInstr()->getOpcode() != AMDGPU::V_PERM_B32_e64)
2242 for (
auto &Succ : Pred.getSUnit()->Succs) {
2243 auto *
MI = Succ.getSUnit()->getInstr();
2244 if (!
TII->isVMEM(*
MI) || !
MI->mayLoad())
2247 if (MissedAny || !VMEMLookup.
size()) {
2249 VMEMLookup[
MI] = *
I;
2266 if (!MissedAny && Cand) {
2267 DSWWithSharedVMEMCount += 2;
2274 assert(DSWWithSharedVMEMCount <= DSWWithPermCount);
2276 unsigned PipelineSyncID = 0;
2278 if (DSWWithPermCount) {
2279 for (
unsigned I = 0;
I < MFMACount;
I++) {
2280 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2281 SchedGroupMask::MFMA, 1, PipelineSyncID, DAG,
TII);
2282 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2284 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2285 SchedGroupMask::VALU, 2, PipelineSyncID, DAG,
TII);
2286 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2296 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2297 SchedGroupMask::DS_READ, 4, PipelineSyncID, DAG,
TII);
2298 SG->addRule(std::make_shared<EnablesInitialMFMA>(
TII, SG->getSGID(),
true));
2299 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2301 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2302 SchedGroupMask::MFMA, 1, PipelineSyncID, DAG,
TII);
2303 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2306 for (
unsigned I = 4;
I < DSRCount; ++
I) {
2307 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2308 SchedGroupMask::DS_READ, 1, PipelineSyncID, DAG,
TII);
2309 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2311 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2312 SchedGroupMask::MFMA, 1, PipelineSyncID, DAG,
TII);
2313 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2319 for (
unsigned I = DSWWithSharedVMEMCount;
I < DSWWithPermCount; ++
I) {
2320 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2321 SchedGroupMask::VALU, 4, PipelineSyncID, DAG,
TII);
2322 SG->addRule(std::make_shared<IsPermForDSW>(
TII, SG->getSGID(),
true));
2323 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2325 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2326 SchedGroupMask::DS_WRITE, 1, PipelineSyncID, DAG,
TII);
2327 SG->addRule(std::make_shared<IsSuccOfPrevGroup>(
TII, SG->getSGID()));
2328 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2330 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2331 SchedGroupMask::VMEM_READ, 4, PipelineSyncID, DAG,
TII);
2332 SG->addRule(std::make_shared<SharesPredWithPrevNthGroup>(
2333 1,
TII, SG->getSGID(),
true));
2334 SG->addRule(std::make_shared<VMEMSize>(
TII, SG->getSGID()));
2335 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2337 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2338 SchedGroupMask::MFMA, 1, PipelineSyncID, DAG,
TII);
2339 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2341 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2342 SchedGroupMask::VMEM_READ, 4, PipelineSyncID, DAG,
TII);
2343 SG->addRule(std::make_shared<SharesPredWithPrevNthGroup>(
2344 3,
TII, SG->getSGID(),
true));
2345 SG->addRule(std::make_shared<VMEMSize>(
TII, SG->getSGID()));
2346 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2348 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2349 SchedGroupMask::MFMA, 1, PipelineSyncID, DAG,
TII);
2350 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2356 for (
unsigned I = DSWWithPermCount;
I < DSWCount;
I++) {
2357 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2358 SchedGroupMask::DS_WRITE, 1, PipelineSyncID, DAG,
TII);
2359 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2361 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2362 SchedGroupMask::VMEM_READ, 4, PipelineSyncID, DAG,
TII);
2363 SG->addRule(std::make_shared<VMEMSize>(
TII, SG->getSGID()));
2364 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2366 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2367 SchedGroupMask::MFMA, 1, PipelineSyncID, DAG,
TII);
2368 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2376 for (
unsigned I = 0;
I < DSWWithSharedVMEMCount; ++
I) {
2377 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2378 SchedGroupMask::VALU, 4, PipelineSyncID, DAG,
TII);
2379 SG->addRule(std::make_shared<IsPermForDSW>(
TII, SG->getSGID(),
true));
2380 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2382 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2383 SchedGroupMask::DS_WRITE, 1, PipelineSyncID, DAG,
TII);
2384 SG->addRule(std::make_shared<IsSuccOfPrevGroup>(
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()]);
2391 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2392 SchedGroupMask::VALU, 4, PipelineSyncID, DAG,
TII);
2393 SG->addRule(std::make_shared<IsPermForDSW>(
TII, SG->getSGID(),
true));
2394 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2396 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2397 SchedGroupMask::DS_WRITE, 1, PipelineSyncID, DAG,
TII);
2398 SG->addRule(std::make_shared<IsSuccOfPrevGroup>(
TII, SG->getSGID()));
2399 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2401 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2402 SchedGroupMask::MFMA, 1, PipelineSyncID, DAG,
TII);
2403 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2405 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2406 SchedGroupMask::VMEM_READ, 4, PipelineSyncID, DAG,
TII);
2407 SG->addRule(std::make_shared<SharesPredWithPrevNthGroup>(
2408 2,
TII, SG->getSGID(),
true));
2409 SG->addRule(std::make_shared<VMEMSize>(
TII, SG->getSGID()));
2410 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2412 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2413 SchedGroupMask::MFMA, 1, PipelineSyncID, DAG,
TII);
2414 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2416 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2417 SchedGroupMask::VMEM_READ, 4, PipelineSyncID, DAG,
TII);
2418 SG->addRule(std::make_shared<SharesPredWithPrevNthGroup>(
2419 4,
TII, SG->getSGID(),
true));
2420 SG->addRule(std::make_shared<VMEMSize>(
TII, SG->getSGID()));
2421 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2423 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2424 SchedGroupMask::MFMA, 1, PipelineSyncID, DAG,
TII);
2425 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2431static std::unique_ptr<IGLPStrategy>
2433 const SIInstrInfo *
TII) {
2436 return std::make_unique<MFMASmallGemmOpt>(DAG,
TII);
2438 return std::make_unique<MFMASmallGemmSingleWaveOpt>(DAG,
TII);
2440 return std::make_unique<MFMAExpInterleaveOpt>(DAG,
TII);
2442 return std::make_unique<MFMAExpSimpleInterleaveOpt>(DAG,
TII);
2448class IGroupLPDAGMutation :
public ScheduleDAGMutation {
2450 const SIInstrInfo *
TII;
2457 DenseMap<int, SmallVector<SchedGroup, 4>> SyncedSchedGroups;
2460 DenseMap<int, SUnitsToCandidateSGsMap> SyncedInstrs;
2463 void addSchedBarrierEdges(SUnit &SU);
2477 void initSchedGroupBarrierPipelineStage(
2478 std::vector<SUnit>::reverse_iterator RIter);
2480 bool initIGLPOpt(SUnit &SU);
2483 void apply(ScheduleDAGInstrs *DAGInstrs)
override;
2490 bool IsBottomUp =
true;
2495 IGroupLPDAGMutation() =
default;
2499unsigned SchedGroup::NumSchedGroups = 0;
2501bool SchedGroup::tryAddEdge(SUnit *
A, SUnit *
B) {
2505bool SchedGroup::canAddMI(
const MachineInstr &
MI)
const {
2507 if (
MI.isMetaInstruction())
2510 else if (
MI.isInlineAsm()) {
2512 auto &
MRI =
MI.getParent()->getParent()->getRegInfo();
2513 bool SGPR_used =
false, SGPR_big_def =
false, VGPR_used =
false,
2514 VMFMA_used =
false, VReg32_used =
false,
MayLoad =
MI.mayLoad(),
2516 for (
const MachineOperand &Operand :
MI.operands())
2517 if (Operand.isReg()) {
2519 *
TRI.getRegClassForOperandReg(
MRI, Operand);
2520 if (
TRI.hasVGPRs(&RegClass)) {
2522 if (Operand.isUse() &&
TRI.getRegSizeInBits(RegClass) == 32)
2528 if (
TRI.hasAGPRs(&RegClass) ||
TRI.getRegSizeInBits(RegClass) > 128)
2530 if (
TRI.hasSGPRs(&RegClass))
2532 if (
TRI.getRegSizeInBits(RegClass) > 64 && Operand.isDef())
2533 SGPR_big_def =
true;
2536 typedef std::underlying_type_t<SchedGroupMask> SGMask_t;
2537 SGMask_t InlineAsmMask = 0;
2538 if (VGPR_used && !VMFMA_used && !MayLoad && !MayStore)
2539 InlineAsmMask |= (SGMask_t)SchedGroupMask::VALU;
2540 if (SGPR_used && !VGPR_used && !MayLoad && !MayStore)
2541 InlineAsmMask |= (SGMask_t)SchedGroupMask::SALU;
2543 InlineAsmMask |= (SGMask_t)SchedGroupMask::MFMA;
2544 if (VGPR_used && MayLoad)
2545 InlineAsmMask |= (SGMask_t)(VReg32_used ? SchedGroupMask::DS_READ
2546 : SchedGroupMask::VMEM_READ);
2547 if (VGPR_used && MayStore)
2548 InlineAsmMask |= (SGMask_t)(VReg32_used ? SchedGroupMask::DS_WRITE
2549 : SchedGroupMask::VMEM_WRITE);
2551 InlineAsmMask |= (SGMask_t)SchedGroupMask::DS_READ;
2552 if (InlineAsmMask & (SGMask_t)SchedGroupMask::VALU ||
2553 InlineAsmMask & (SGMask_t)SchedGroupMask::SALU)
2554 InlineAsmMask |= (SGMask_t)SchedGroupMask::ALU;
2555 if (InlineAsmMask & (SGMask_t)SchedGroupMask::DS_READ ||
2556 InlineAsmMask & (SGMask_t)SchedGroupMask::DS_WRITE)
2557 InlineAsmMask |= (SGMask_t)SchedGroupMask::DS;
2558 if (InlineAsmMask & (SGMask_t)SchedGroupMask::VMEM_READ ||
2559 InlineAsmMask & (SGMask_t)SchedGroupMask::VMEM_WRITE)
2560 InlineAsmMask |= (SGMask_t)SchedGroupMask::VMEM;
2562 Result = ((SGMask_t)SGMask & InlineAsmMask) != 0;
2565 else if (((SGMask & SchedGroupMask::ALU) != SchedGroupMask::NONE) &&
2566 (
TII->isVALU(
MI,
true) ||
TII->isMFMAorWMMA(
MI) ||
2570 else if (((SGMask & SchedGroupMask::VALU) != SchedGroupMask::NONE) &&
2571 TII->isVALU(
MI,
false) && !
TII->isMFMAorWMMA(
MI) &&
2572 !
TII->isTRANS(
MI)) {
2579 else if (((SGMask & SchedGroupMask::SALU) != SchedGroupMask::NONE) &&
2583 else if (((SGMask & SchedGroupMask::MFMA) != SchedGroupMask::NONE) &&
2584 TII->isMFMAorWMMA(
MI))
2587 else if (((SGMask & SchedGroupMask::VMEM) != SchedGroupMask::NONE) &&
2591 else if (((SGMask & SchedGroupMask::VMEM_READ) != SchedGroupMask::NONE) &&
2595 else if (((SGMask & SchedGroupMask::VMEM_WRITE) != SchedGroupMask::NONE) &&
2596 MI.mayStore() &&
TII->isVMEM(
MI) && !
TII->isLDSDMA(
MI))
2599 else if (((SGMask & SchedGroupMask::DS) != SchedGroupMask::NONE) &&
2603 else if (((SGMask & SchedGroupMask::DS_READ) != SchedGroupMask::NONE) &&
2604 MI.mayLoad() &&
TII->isDS(
MI))
2607 else if (((SGMask & SchedGroupMask::DS_WRITE) != SchedGroupMask::NONE) &&
2608 MI.mayStore() &&
TII->isDS(
MI))
2611 else if (((SGMask & SchedGroupMask::TRANS) != SchedGroupMask::NONE) &&
2615 else if (((SGMask & SchedGroupMask::LDSDMA) != SchedGroupMask::NONE) &&
2620 dbgs() <<
"For SchedGroup with mask " <<
format_hex((
int)SGMask, 10,
true)
2621 << (Result ?
" could classify " :
" unable to classify ") <<
MI);
2626int SchedGroup::link(SUnit &SU,
bool MakePred,
2627 std::list<std::pair<SUnit *, SUnit *>> &AddedEdges) {
2628 int MissedEdges = 0;
2629 for (
auto *
A : Collection) {
2631 if (
A ==
B ||
A->getInstr()->getOpcode() == AMDGPU::SCHED_GROUP_BARRIER)
2641 bool Added = tryAddEdge(
A,
B);
2643 AddedEdges.emplace_back(
A,
B);
2651void SchedGroup::link(SUnit &SU,
bool MakePred) {
2652 for (
auto *
A : Collection) {
2654 if (
A->getInstr()->getOpcode() == AMDGPU::SCHED_GROUP_BARRIER)
2663void SchedGroup::link(SUnit &SU,
2664 function_ref<
bool(
const SUnit *
A,
const SUnit *
B)>
P) {
2665 for (
auto *
A : Collection) {
2674void SchedGroup::link(SchedGroup &OtherGroup) {
2675 for (
auto *
B : OtherGroup.Collection)
2679bool SchedGroup::canAddSU(SUnit &SU)
const {
2681 if (
MI.getOpcode() != TargetOpcode::BUNDLE)
2682 return canAddMI(
MI);
2687 while (
E !=
MBB->
end() &&
E->isBundledWithPred())
2691 return std::all_of(
B,
E, [
this](MachineInstr &
MI) {
return canAddMI(
MI); });
2695void SchedGroup::findCandidateSUnits(
T Begin,
T End,
2696 SUnitsToCandidateSGsMap &SyncedInstrs) {
2699 SyncedInstrs[&SU].push_back(SGID);
2703void SchedGroup::findCandidateSUnits(SUnitsToCandidateSGsMap &SyncedInstrs) {
2704 findCandidateSUnits(DAG->
SUnits.rbegin(), DAG->
SUnits.rend(), SyncedInstrs);
2707void IGroupLPDAGMutation::apply(ScheduleDAGInstrs *DAGInstrs) {
2708 const TargetSchedModel *TSchedModel = DAGInstrs->
getSchedModel();
2709 if (!TSchedModel || DAGInstrs->
SUnits.empty())
2714 TII =
ST.getInstrInfo();
2715 DAG =
static_cast<ScheduleDAGMI *
>(DAGInstrs);
2716 SyncedSchedGroups.clear();
2717 SyncedInstrs.clear();
2718 bool FoundSB =
false;
2719 bool FoundIGLP =
false;
2720 bool ShouldApplyIGLP =
false;
2721 for (
auto R = DAG->
SUnits.rbegin(),
E = DAG->
SUnits.rend(); R !=
E; ++R) {
2722 unsigned Opc =
R->getInstr()->getOpcode();
2724 if (
Opc == AMDGPU::SCHED_BARRIER) {
2725 addSchedBarrierEdges(*R);
2727 }
else if (
Opc == AMDGPU::SCHED_GROUP_BARRIER) {
2728 initSchedGroupBarrierPipelineStage(R);
2730 }
else if (
Opc == AMDGPU::IGLP_OPT) {
2731 if (!FoundSB && !FoundIGLP) {
2733 ShouldApplyIGLP = initIGLPOpt(*R);
2738 if (FoundSB || (FoundIGLP && ShouldApplyIGLP)) {
2739 PipelineSolver PS(SyncedSchedGroups, SyncedInstrs, DAG, IsBottomUp);
2747void IGroupLPDAGMutation::addSchedBarrierEdges(SUnit &SchedBarrier) {
2749 assert(
MI.getOpcode() == AMDGPU::SCHED_BARRIER);
2750 LLVM_DEBUG(
dbgs() <<
"Building SchedGroup for SchedBarrier with Mask: "
2751 <<
MI.getOperand(0).getImm() <<
"\n");
2754 SchedGroup SG(InvertedMask, std::nullopt, DAG,
TII);
2756 for (SUnit &SU : DAG->
SUnits)
2757 if (SG.canAddSU(SU))
2763 (function_ref<
bool(
const SUnit *
A,
const SUnit *
B)>)[](
2764 const SUnit *
A,
const SUnit *
B) {
return A->NodeNum >
B->NodeNum; });
2768IGroupLPDAGMutation::invertSchedBarrierMask(
SchedGroupMask Mask)
const {
2773 static constexpr std::pair<SchedGroupMask, SchedGroupMask> ImpliedGroups[] = {
2774 {SchedGroupMask::ALU, SchedGroupMask::VALU | SchedGroupMask::SALU |
2775 SchedGroupMask::MFMA | SchedGroupMask::TRANS},
2776 {SchedGroupMask::VMEM, SchedGroupMask::VMEM_READ |
2777 SchedGroupMask::VMEM_WRITE |
2778 SchedGroupMask::LDSDMA},
2779 {SchedGroupMask::DS, SchedGroupMask::DS_READ | SchedGroupMask::DS_WRITE |
2780 SchedGroupMask::LDSDMA},
2783 for (
auto [Aggregate, Members] : ImpliedGroups) {
2785 if ((InvertedMask & Aggregate) == SchedGroupMask::NONE)
2786 InvertedMask &= ~Members;
2788 else if ((InvertedMask & Members) != Members)
2789 InvertedMask &= ~Aggregate;
2792 LLVM_DEBUG(
dbgs() <<
"After Inverting, SchedGroup Mask: " << (
int)InvertedMask
2795 return InvertedMask;
2798void IGroupLPDAGMutation::initSchedGroupBarrierPipelineStage(
2799 std::vector<SUnit>::reverse_iterator RIter) {
2800 MachineInstr &SGB = *RIter->getInstr();
2807 auto &SG = SyncedSchedGroups[SyncID].emplace_back((
SchedGroupMask)SGMask,
2810 SG.findCandidateSUnits(RIter, SG.DAG->
SUnits.rend(),
2811 SyncedInstrs[SG.getSyncID()]);
2814bool IGroupLPDAGMutation::initIGLPOpt(SUnit &SU) {
2817 auto S = createIGLPStrategy(StrategyID, DAG,
TII);
2818 if (!S->shouldApplyStrategy(DAG,
Phase))
2821 IsBottomUp = S->IsBottomUp;
2822 return S->applyIGLPStrategy(SyncedInstrs, SyncedSchedGroups,
Phase);
2832std::unique_ptr<ScheduleDAGMutation>
2834 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!")
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
MachineRegisterInfo & MRI
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.
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)
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
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.
@ End
Run the machine verifier once, at the end of the pipeline.
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:...