27#define DEBUG_TYPE "igrouplp"
36class InstructionRule {
42 std::optional<SmallVector<SUnit *, 4>> Cache;
52 bool NeedsCache =
false)
59 virtual ~InstructionRule() =
default;
75 std::optional<unsigned> MaxSize;
88 static unsigned NumSchedGroups;
105 bool canAddSU(
SUnit &SU)
const;
110 void link(
SUnit &SU,
bool MakePred =
false);
114 int link(
SUnit &SU,
bool MakePred,
115 std::list<std::pair<SUnit *, SUnit *>> &AddedEdges);
124 void link(SchedGroup &OtherGroup);
127 bool isFull()
const {
return MaxSize && Collection.
size() >= *MaxSize; }
133 void addRule(std::shared_ptr<InstructionRule> NewRule) {
138 bool allowedByRules(
const SUnit *SU,
140 for (
auto &Rule : Rules) {
141 if (!Rule->apply(SU, Collection, SyncPipe))
148 void add(
SUnit &SU) {
150 <<
format_hex((
int)SGMask, 10,
true) <<
" adding "
156 void pop() { Collection.
pop_back(); }
159 void findCandidateSUnits(
T Begin,
T End,
160 SUnitsToCandidateSGsMap &SyncedInstrs);
165 void findCandidateSUnits(SUnitsToCandidateSGsMap &SyncedInstrs);
167 int getSyncID() {
return SyncID; }
169 int getSGID() {
return SGID; }
173 SchedGroup(
SchedGroupMask SGMask, std::optional<unsigned> MaxSize,
175 : SGMask(SGMask), MaxSize(MaxSize), DAG(DAG),
TII(
TII) {
176 SGID = NumSchedGroups++;
179 SchedGroup(
SchedGroupMask SGMask, std::optional<unsigned> MaxSize,
int SyncID,
181 : SGMask(SGMask), MaxSize(MaxSize), SyncID(SyncID), DAG(DAG),
TII(
TII) {
182 SGID = NumSchedGroups++;
186using SUToCandSGsPair = std::pair<SUnit *, SmallVector<int, 4>>;
198class PipelineSolver {
199 const AMDGPUOptions &CLOpts;
212 bool NeedsSolver =
false;
216 unsigned computeProblemSize();
227 int CurrConflInstNo = 0;
229 int CurrSyncGroupIdx = 0;
231 int BeginSyncGroupIdx = 0;
237 bool IsBottomUp =
true;
240 void advancePosition();
243 void retreatPosition();
252 template <
typename T>
253 void greedyFind(std::list<std::pair<SUnit *, SUnit *>> &AddedEdges,
T I,
T E);
258 template <
typename T>
265 template <
typename T>
void linkSchedGroups(
T I,
T E);
269 std::list<std::pair<SUnit *, SUnit *>> &AddedEdges);
275 class EdgeSetBuilder {
281 bool Initialized =
false;
285 template <
bool ComputePreds>
299 : SU(SU), SyncPipeline(SyncPipeline), IsBottomUp(IsBottomUp) {}
305 int build(
int SGID, std::list<std::pair<SUnit *, SUnit *>> &NewEdges);
308 template <
typename T>
310 std::list<std::pair<SUnit *, SUnit *>> &NewEdges);
316 template <
typename T>
317 int linkSUnit(
SUnit *SU,
int SGID,
318 std::list<std::pair<SUnit *, SUnit *>> &AddedEdges,
T I,
T E);
320 void removeEdges(
const std::list<std::pair<SUnit *, SUnit *>> &AddedEdges);
322 void convertSyncMapsToArrays();
335 SyncedInstrs(SyncedInstrs), SyncedSchedGroups(SyncedSchedGroups),
336 IsBottomUp(IsBottomUp) {
338 for (
auto &PipelineInstrs : SyncedInstrs) {
339 if (!PipelineInstrs.second.
empty()) {
348 convertSyncMapsToArrays();
350 CurrPipeline = BestPipeline;
352 while (
static_cast<size_t>(BeginSyncGroupIdx) < PipelineInstrs.
size() &&
353 PipelineInstrs[BeginSyncGroupIdx].
empty())
356 if (
static_cast<size_t>(BeginSyncGroupIdx) >= PipelineInstrs.
size())
361void PipelineSolver::reset() {
363 for (
auto &SyncPipeline : CurrPipeline) {
364 for (
auto &SG : SyncPipeline) {
366 SG.Collection.
clear();
370 if (SchedBarr != TempCollection.
end())
371 SG.Collection.push_back(*SchedBarr);
375 CurrSyncGroupIdx = BeginSyncGroupIdx;
380void PipelineSolver::convertSyncMapsToArrays() {
381 for (
auto &SyncPipe : SyncedSchedGroups) {
382 BestPipeline.insert(BestPipeline.begin(), SyncPipe.second);
385 int PipelineIDx = SyncedInstrs.size() - 1;
386 PipelineInstrs.resize(SyncedInstrs.size());
387 for (
auto &SyncInstrMap : SyncedInstrs) {
388 for (
auto &SUsToCandSGs : SyncInstrMap.second) {
389 if (PipelineInstrs[PipelineIDx].empty()) {
390 PipelineInstrs[PipelineIDx].push_back(
391 std::pair(SUsToCandSGs.first, SUsToCandSGs.second));
394 auto *SortPosition = PipelineInstrs[PipelineIDx].begin();
397 while (SortPosition != PipelineInstrs[PipelineIDx].end() &&
398 SUsToCandSGs.first->NodeNum > SortPosition->first->NodeNum)
400 PipelineInstrs[PipelineIDx].insert(
401 SortPosition, std::pair(SUsToCandSGs.first, SUsToCandSGs.second));
407template <
typename T>
void PipelineSolver::linkSchedGroups(
T I,
T E) {
408 for (;
I !=
E; ++
I) {
410 for (
auto J = std::next(
I); J !=
E; ++J) {
417void PipelineSolver::makePipeline() {
419 for (
auto &SyncPipeline : BestPipeline) {
421 for (
auto &SG : SyncPipeline) {
424 SUnit *SGBarr =
nullptr;
425 for (
auto &SU : SG.Collection) {
426 if (SU->getInstr()->getOpcode() == AMDGPU::SCHED_GROUP_BARRIER)
433 SG.link(*SGBarr,
false);
437 for (
auto &SyncPipeline : BestPipeline) {
438 IsBottomUp ? linkSchedGroups(SyncPipeline.rbegin(), SyncPipeline.rend())
439 : linkSchedGroups(SyncPipeline.begin(), SyncPipeline.end());
444int PipelineSolver::linkSUnit(
445 SUnit *SU,
int SGID, std::list<std::pair<SUnit *, SUnit *>> &AddedEdges,
447 bool MakePred =
false;
450 if (
I->getSGID() == SGID) {
455 AddedCost += Group.link(*SU, MakePred, AddedEdges);
461template <
bool ComputePreds>
462void PipelineSolver::EdgeSetBuilder::computeReachable(
464 if (!Reachable.insert(Start).second)
469 while (!WorkList.
empty()) {
472 for (
const SDep &Dep : ComputePreds ? Current->
Preds : Current->
Succs) {
473 if (Reachable.insert(Dep.getSUnit()).second)
481 computeReachable<
true>(Preds, Start);
486 computeReachable<
false>(Succs, Start);
489int PipelineSolver::EdgeSetBuilder::build(
490 int SGID, std::list<std::pair<SUnit *, SUnit *>> &NewEdges) {
492 computePreds(InitialPreds, SU);
493 computeSuccs(Succs, SU);
498 return IsBottomUp ? buildImpl(SGID,
reverse(SyncPipeline), NewEdges)
506int PipelineSolver::EdgeSetBuilder::buildImpl(
508 std::list<std::pair<SUnit *, SUnit *>> &NewEdges) {
526 bool MakePred =
false;
527 for (SchedGroup &SG : SchedGroups) {
528 if (SG.getSGID() == SGID) {
533 for (
SUnit *
A : SG.Collection) {
534 if (
A->getInstr()->getOpcode() == AMDGPU::SCHED_GROUP_BARRIER)
545 NewEdges.emplace_back(SU,
A);
554 NewEdges.emplace_back(
A, SU);
555 computePreds(Preds,
A);
562int PipelineSolver::addEdges(
564 std::list<std::pair<SUnit *, SUnit *>> &AddedEdges) {
574 return IsBottomUp ? linkSUnit(SU, SGID, AddedEdges, SyncPipeline.
rbegin(),
576 : linkSUnit(SU, SGID, AddedEdges, SyncPipeline.
begin(),
580void PipelineSolver::removeEdges(
581 const std::list<std::pair<SUnit *, SUnit *>> &EdgesToRemove) {
584 for (
auto &PredSuccPair : EdgesToRemove) {
586 SUnit *Succ = PredSuccPair.second;
589 return P.getSUnit() == Pred && P.isArtificial();
591 if (Match != Succ->
Preds.end())
596void PipelineSolver::advancePosition() {
599 if (
static_cast<size_t>(CurrConflInstNo) >=
600 PipelineInstrs[CurrSyncGroupIdx].
size()) {
604 while (
static_cast<size_t>(CurrSyncGroupIdx) < PipelineInstrs.size() &&
605 PipelineInstrs[CurrSyncGroupIdx].empty())
610void PipelineSolver::retreatPosition() {
611 assert(CurrConflInstNo >= 0);
612 assert(CurrSyncGroupIdx >= 0);
614 if (CurrConflInstNo > 0) {
619 if (CurrConflInstNo == 0) {
622 if (CurrSyncGroupIdx == BeginSyncGroupIdx)
627 while (PipelineInstrs[CurrSyncGroupIdx].empty())
631 static_cast<int>(PipelineInstrs[CurrSyncGroupIdx].size() - 1);
635bool PipelineSolver::checkOptimal() {
636 if (
static_cast<size_t>(CurrSyncGroupIdx) == PipelineInstrs.size()) {
637 if (BestCost == -1 || CurrCost < BestCost) {
638 BestPipeline = CurrPipeline;
645 bool DoneExploring =
false;
646 if (CLOpts.igrouplp_exact_solver_max_branches > 0 &&
647 BranchesExplored >= CLOpts.igrouplp_exact_solver_max_branches)
648 DoneExploring =
true;
650 return (DoneExploring || BestCost == 0);
654void PipelineSolver::populateReadyList(
656 SUToCandSGsPair CurrSU = PipelineInstrs[CurrSyncGroupIdx][CurrConflInstNo];
657 auto SyncPipeline = CurrPipeline[CurrSyncGroupIdx];
658 assert(CurrSU.second.size() >= 1);
660 for (;
I !=
E; ++
I) {
661 std::list<std::pair<SUnit *, SUnit *>> AddedEdges;
663 SchedGroup *Match =
llvm::find_if(SyncPipeline, [CandSGID](SchedGroup &SG) {
664 return SG.getSGID() == CandSGID;
668 if (CLOpts.igrouplp_exact_solver_cost_heur) {
669 if (Match->isFull()) {
670 ReadyList.push_back(std::pair(*
I, MissPenalty));
674 int TempCost = addEdges(SyncPipeline, CurrSU.first, CandSGID, AddedEdges);
675 ReadyList.push_back(std::pair(*
I, TempCost));
676 removeEdges(AddedEdges);
678 ReadyList.push_back(std::pair(*
I, -1));
681 if (CLOpts.igrouplp_exact_solver_cost_heur)
684 assert(ReadyList.size() == CurrSU.second.size());
687bool PipelineSolver::solveExact() {
691 if (
static_cast<size_t>(CurrSyncGroupIdx) == PipelineInstrs.size())
694 assert(
static_cast<size_t>(CurrSyncGroupIdx) < PipelineInstrs.size());
695 assert(
static_cast<size_t>(CurrConflInstNo) <
696 PipelineInstrs[CurrSyncGroupIdx].
size());
697 SUToCandSGsPair CurrSU = PipelineInstrs[CurrSyncGroupIdx][CurrConflInstNo];
698 LLVM_DEBUG(
dbgs() <<
"Fitting " << *CurrSU.first <<
" in Pipeline # "
699 << CurrSyncGroupIdx <<
"\n");
704 IsBottomUp ? populateReadyList(ReadyList, CurrSU.second.
rbegin(),
705 CurrSU.second.rend())
706 : populateReadyList(ReadyList, CurrSU.second.
begin(),
707 CurrSU.second.end());
709 auto *
I = ReadyList.
begin();
710 auto *
E = ReadyList.
end();
711 for (;
I !=
E; ++
I) {
715 if (BestCost != -1 && (CurrCost +
I->second > BestCost))
718 int CandSGID =
I->first;
720 std::list<std::pair<SUnit *, SUnit *>> AddedEdges;
721 auto &SyncPipeline = CurrPipeline[CurrSyncGroupIdx];
722 SchedGroup *Match =
llvm::find_if(SyncPipeline, [CandSGID](SchedGroup &SG) {
723 return SG.getSGID() == CandSGID;
730 if (!Match->allowedByRules(CurrSU.first, SyncPipeline))
734 << (
int)Match->getMask() <<
"and ID " << CandSGID
736 Match->add(*CurrSU.first);
737 AddedCost = addEdges(SyncPipeline, CurrSU.first, CandSGID, AddedEdges);
738 LLVM_DEBUG(
dbgs() <<
"Cost of Assignment: " << AddedCost <<
"\n");
739 CurrCost += AddedCost;
742 bool FinishedExploring =
false;
745 if (CurrCost < BestCost || BestCost == -1) {
747 FinishedExploring = BestCost != 0;
748 if (!FinishedExploring)
754 CurrCost -= AddedCost;
755 removeEdges(AddedEdges);
757 CurrPipeline[CurrSyncGroupIdx] = SyncPipeline;
758 if (FinishedExploring)
765 CurrCost += MissPenalty;
770 bool FinishedExploring =
false;
771 if (CurrCost < BestCost || BestCost == -1) {
773 bool FinishedExploring = BestCost != 0;
774 if (!FinishedExploring)
780 CurrCost -= MissPenalty;
781 return FinishedExploring;
785void PipelineSolver::greedyFind(
786 std::list<std::pair<SUnit *, SUnit *>> &AddedEdges,
T I,
T E) {
787 SUToCandSGsPair CurrSU = PipelineInstrs[CurrSyncGroupIdx][CurrConflInstNo];
791 std::list<std::pair<SUnit *, SUnit *>> Edges;
794 std::optional<GroupInfo> Best;
796 auto &SyncPipeline = CurrPipeline[CurrSyncGroupIdx];
797 LLVM_DEBUG(
dbgs() <<
"Fitting " << *CurrSU.first <<
" in Pipeline # "
798 << CurrSyncGroupIdx <<
"\n");
800 EdgeSetBuilder Builder(CurrSU.first, SyncPipeline, IsBottomUp);
806 for (;
I !=
E; ++
I) {
808 SchedGroup *Match =
llvm::find_if(SyncPipeline, [CandSGID](SchedGroup &SG) {
809 return SG.getSGID() == CandSGID;
813 LLVM_DEBUG(
dbgs() <<
"Trying SGID # " << CandSGID <<
" with Mask "
814 << (
int)Match->getMask() <<
"\n");
816 if (Match->isFull()) {
820 if (!Match->allowedByRules(CurrSU.first, SyncPipeline)) {
821 LLVM_DEBUG(
dbgs() <<
"SGID # " << CandSGID <<
" has conflicting rule\n");
825 std::list<std::pair<SUnit *, SUnit *>> TempEdges;
826 int TempCost = Builder.build(CandSGID, TempEdges);
829 if (!Best || TempCost < Best->Cost) {
830 Best = {Match, TempEdges, TempCost};
837 SchedGroup *SG = Best->SG;
838 std::list<std::pair<SUnit *, SUnit *>> &Edges = Best->Edges;
840 SG->add(*CurrSU.first);
841 if (AddedEdges.empty())
844 AddedEdges.splice(std::prev(AddedEdges.cend()), Edges);
846 for (
const std::pair<SUnit *, SUnit *> &
E : Edges) {
847 if (!SG->tryAddEdge(
E.first,
E.second))
851 LLVM_DEBUG(
dbgs() <<
"Best Group has ID: " << SG->getSGID() <<
" and Mask"
852 << (
int)SG->getMask() <<
"\n");
853 BestCost += Best->Cost;
855 BestCost += MissPenalty;
858bool PipelineSolver::solveGreedy() {
860 std::list<std::pair<SUnit *, SUnit *>> AddedEdges;
862 while (
static_cast<size_t>(CurrSyncGroupIdx) < PipelineInstrs.size()) {
863 SUToCandSGsPair CurrSU = PipelineInstrs[CurrSyncGroupIdx][CurrConflInstNo];
865 ? greedyFind(AddedEdges, CurrSU.second.rbegin(), CurrSU.second.rend())
866 : greedyFind(AddedEdges, CurrSU.second.begin(), CurrSU.second.end());
869 BestPipeline = CurrPipeline;
870 removeEdges(AddedEdges);
874unsigned PipelineSolver::computeProblemSize() {
875 unsigned ProblemSize = 0;
876 for (
auto &PipeConflicts : PipelineInstrs) {
877 ProblemSize +=
static_cast<unsigned>(PipeConflicts.size());
883void PipelineSolver::solve() {
887 unsigned ProblemSize = computeProblemSize();
890 bool BelowCutoff = (CLOpts.igrouplp_exact_solver_cutoff > 0) &&
891 ProblemSize <= CLOpts.igrouplp_exact_solver_cutoff;
892 MissPenalty = (ProblemSize / 2) + 1;
895 if (CLOpts.igrouplp_exact_solver || BelowCutoff) {
899 LLVM_DEBUG(
dbgs() <<
"Greedy produced best cost of " << BestCost <<
"\n");
903 LLVM_DEBUG(
dbgs() <<
"Exact produced best cost of " << BestCost <<
"\n");
908 LLVM_DEBUG(
dbgs() <<
"Greedy produced best cost of " << BestCost <<
"\n");
931 bool hasIGLPOptData(
unsigned NumValues)
const {
941 if (hasIGLPOptData(
Data.size())) {
948 for (int64_t
V :
Data)
954 template <
unsigned NumValues>
955 std::optional<std::array<int64_t, NumValues>> getIGLPOptData()
const {
956 if (!hasIGLPOptData(NumValues))
958 std::array<int64_t, NumValues>
Data;
966 virtual bool applyIGLPStrategy(
975 bool IsBottomUp =
true;
979 : DAG(DAG),
TII(
TII), IGLPOptMI(IGLPOptMI) {}
981 virtual ~IGLPStrategy() =
default;
984class MFMASmallGemmOpt final :
public IGLPStrategy {
987 bool applyIGLPStrategy(
999 : IGLPStrategy(DAG,
TII, IGLPOptMI) {
1004bool MFMASmallGemmOpt::applyIGLPStrategy(
1009 unsigned MFMACount = 0;
1011 if (
TII->isMFMAorWMMA(
I))
1014 const unsigned PipelineSyncID = 0;
1015 SchedGroup *SG =
nullptr;
1016 for (
unsigned I = 0;
I < MFMACount * 3; ++
I) {
1017 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1019 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1021 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1023 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1029class MFMAExpInterleaveOpt final :
public IGLPStrategy {
1032 unsigned TransPipeCount = 0;
1034 unsigned MFMAPipeCount = 0;
1036 unsigned AddPipeCount = 0;
1038 unsigned MFMAEnablement = 0;
1040 unsigned ExpRequirement = 0;
1042 unsigned MFMAChains = 0;
1044 bool HasCvt =
false;
1047 bool HasChainBetweenCvt =
false;
1049 std::optional<unsigned> FirstPipeDSR;
1058 static constexpr unsigned NumAnalysisValues = 8;
1061 void storeAnalysisData() {
1062 setIGLPOptData({TransPipeCount, MFMAPipeCount, AddPipeCount, MFMAEnablement,
1063 ExpRequirement, MFMAChains, HasCvt, HasChainBetweenCvt});
1067 bool loadAnalysisData() {
1068 std::optional<std::array<int64_t, NumAnalysisValues>>
Data =
1069 getIGLPOptData<NumAnalysisValues>();
1072 TransPipeCount = (*Data)[0];
1073 MFMAPipeCount = (*Data)[1];
1074 AddPipeCount = (*Data)[2];
1075 MFMAEnablement = (*Data)[3];
1076 ExpRequirement = (*Data)[4];
1077 MFMAChains = (*Data)[5];
1078 HasCvt = (*Data)[6];
1079 HasChainBetweenCvt = (*Data)[7];
1080 assert(TransPipeCount > 0 && MFMAPipeCount > 0 && MFMAChains > 0 &&
1081 "guaranteed by a successful analyzeDAG");
1087 class IsPipeExp final :
public InstructionRule {
1092 auto *DAG = SyncPipe[0].DAG;
1094 if (Cache->empty()) {
1095 auto I = DAG->SUnits.rbegin();
1096 auto E = DAG->SUnits.rend();
1097 for (;
I !=
E;
I++) {
1098 if (
TII->isMFMAorWMMA(*
I->getInstr()))
1099 Cache->push_back(&*
I);
1105 auto Reaches =
any_of(*Cache, [&SU, &DAG](
SUnit *TargetSU) {
1106 return DAG->IsReachable(TargetSU,
const_cast<SUnit *
>(SU));
1111 IsPipeExp(
const SIInstrInfo *
TII,
unsigned SGID,
bool NeedsCache =
false)
1112 : InstructionRule(
TII, SGID, NeedsCache) {}
1117 class EnablesNthMFMA final :
public InstructionRule {
1124 bool FoundTrans =
false;
1125 unsigned Counter = 1;
1126 auto *DAG = SyncPipe[0].DAG;
1128 if (Cache->empty()) {
1129 auto I = DAG->SUnits.begin();
1130 auto E = DAG->SUnits.end();
1131 for (;
I !=
E;
I++) {
1132 if (FoundTrans &&
TII->isMFMAorWMMA(*
I->getInstr())) {
1134 Cache->push_back(&*
I);
1139 if (!FoundTrans &&
TII->isTRANS(
I->getInstr()->getOpcode()))
1146 return DAG->IsReachable((*Cache)[0],
const_cast<SUnit *
>(SU));
1150 bool NeedsCache =
false)
1156 class EnablesNthMFMAInChain final :
public InstructionRule {
1164 auto *DAG = SyncPipe[0].DAG;
1166 if (!SU || !
TII->isMFMAorWMMA(*ChainSeed->
getInstr()))
1169 if (Cache->empty()) {
1170 auto *TempSU = ChainSeed;
1175 for (
auto &Succ : TempSU->Succs) {
1176 if (
TII->isMFMAorWMMA(*Succ.getSUnit()->getInstr())) {
1177 TempSU = Succ.getSUnit();
1186 Cache->push_back(TempSU);
1192 return DAG->IsReachable((*Cache)[0],
const_cast<SUnit *
>(SU));
1195 EnablesNthMFMAInChain(
unsigned Number,
SUnit *ChainSeed,
1197 bool NeedsCache =
false)
1199 ChainSeed(ChainSeed) {}
1205 class LessThanNSuccs final :
public InstructionRule {
1208 bool HasIntermediary =
false;
1213 if (!SyncPipe.
size())
1217 return Succ.getKind() == SDep::Data;
1219 if (SuccSize >=
Size)
1222 if (HasIntermediary) {
1223 for (
auto Succ : SU->
Succs) {
1226 return SuccSucc.getKind() == SDep::Data;
1228 if (SuccSize >=
Size)
1236 bool HasIntermediary =
false,
bool NeedsCache =
false)
1237 : InstructionRule(
TII, SGID, NeedsCache),
Size(
Size),
1238 HasIntermediary(HasIntermediary) {}
1245 class GreaterThanOrEqualToNSuccs final :
public InstructionRule {
1248 bool HasIntermediary =
false;
1253 if (!SyncPipe.
size())
1257 return Succ.getKind() == SDep::Data;
1259 if (SuccSize >=
Size)
1262 if (HasIntermediary) {
1263 for (
auto Succ : SU->
Succs) {
1266 return SuccSucc.getKind() == SDep::Data;
1268 if (SuccSize >=
Size)
1276 unsigned SGID,
bool HasIntermediary =
false,
1277 bool NeedsCache =
false)
1278 : InstructionRule(
TII, SGID, NeedsCache),
Size(
Size),
1279 HasIntermediary(HasIntermediary) {}
1283 class IsCvt final :
public InstructionRule {
1288 return Opc == AMDGPU::V_CVT_F16_F32_e32 ||
1289 Opc == AMDGPU::V_CVT_I32_F32_e32;
1291 IsCvt(
const SIInstrInfo *
TII,
unsigned SGID,
bool NeedsCache =
false)
1292 : InstructionRule(
TII, SGID, NeedsCache) {}
1296 class IsFMA final :
public InstructionRule {
1303 IsFMA(
const SIInstrInfo *
TII,
unsigned SGID,
bool NeedsCache =
false)
1304 : InstructionRule(
TII, SGID, NeedsCache) {}
1308 class IsPipeAdd final :
public InstructionRule {
1314 IsPipeAdd(
const SIInstrInfo *
TII,
unsigned SGID,
bool NeedsCache =
false)
1315 : InstructionRule(
TII, SGID, NeedsCache) {}
1320 class IsSuccOfPrevNthGroup final :
public InstructionRule {
1322 unsigned Distance = 1;
1327 SchedGroup *OtherGroup =
nullptr;
1328 if (!SyncPipe.
size())
1331 for (
auto &PipeSG : SyncPipe) {
1332 if ((
unsigned)PipeSG.getSGID() == SGID - Distance)
1333 OtherGroup = &PipeSG;
1338 if (!OtherGroup->Collection.size())
1341 for (
auto &OtherEle : OtherGroup->Collection) {
1342 for (
auto &Succ : OtherEle->Succs) {
1343 if (Succ.getSUnit() == SU && Succ.getKind() ==
SDep::Data)
1351 unsigned SGID,
bool NeedsCache =
false)
1352 : InstructionRule(
TII, SGID, NeedsCache), Distance(Distance) {}
1357 class IsReachableFromPrevNthGroup final :
public InstructionRule {
1359 unsigned Distance = 1;
1364 SchedGroup *OtherGroup =
nullptr;
1365 if (!SyncPipe.
size())
1368 for (
auto &PipeSG : SyncPipe) {
1369 if ((
unsigned)PipeSG.getSGID() == SGID - Distance)
1370 OtherGroup = &PipeSG;
1375 if (!OtherGroup->Collection.size())
1378 auto *DAG = SyncPipe[0].DAG;
1380 for (
auto &OtherEle : OtherGroup->Collection)
1381 if (DAG->IsReachable(
const_cast<SUnit *
>(SU), OtherEle))
1386 IsReachableFromPrevNthGroup(
unsigned Distance,
const SIInstrInfo *
TII,
1387 unsigned SGID,
bool NeedsCache =
false)
1388 : InstructionRule(
TII, SGID, NeedsCache), Distance(Distance) {}
1392 class OccursAtOrAfterNode final :
public InstructionRule {
1403 bool NeedsCache =
false)
1409 class IsExactMFMA final :
public InstructionRule {
1417 if (!SU || !
TII->isMFMAorWMMA(*ChainSeed->
getInstr()))
1420 if (Cache->empty()) {
1421 auto *TempSU = ChainSeed;
1426 for (
auto &Succ : TempSU->Succs) {
1427 if (
TII->isMFMAorWMMA(*Succ.getSUnit()->getInstr())) {
1428 TempSU = Succ.getSUnit();
1437 Cache->push_back(TempSU);
1443 return (*Cache)[0] == SU;
1447 unsigned SGID,
bool NeedsCache =
false)
1449 ChainSeed(ChainSeed) {}
1455 class OccursAfterExp final :
public InstructionRule {
1460 auto *DAG = SyncPipe[0].DAG;
1461 if (Cache->empty()) {
1462 for (
auto &SU : DAG->SUnits)
1464 Cache->push_back(&SU);
1471 return SU->
NodeNum > (*Cache)[0]->NodeNum;
1475 bool NeedsCache =
false)
1476 : InstructionRule(
TII, SGID, NeedsCache) {}
1480 bool applyIGLPStrategy(
1490 : IGLPStrategy(DAG,
TII, IGLPOptMI) {
1502 auto isBitPack = [](
unsigned Opc) {
1503 return Opc == AMDGPU::V_PACK_B32_F16_e64 ||
Opc == AMDGPU::V_PERM_B32_e64;
1506 auto isCvt = [](
unsigned Opc) {
1507 return Opc == AMDGPU::V_CVT_F16_F32_e32 ||
Opc == AMDGPU::V_CVT_I32_F32_e32;
1510 auto isAdd = [](
unsigned Opc) {
return Opc == AMDGPU::V_ADD_F32_e32; };
1516 if (SU.
Succs.size() >= 7)
1518 for (
auto &Succ : SU.
Succs) {
1519 if (Succ.getSUnit()->Succs.size() >= 7)
1538 if (!(PackSUs.
size() && MFMAPipeCands.
size() && ExpPipeCands.
size()))
1541 std::optional<SUnit *> TempMFMA;
1542 std::optional<SUnit *> TempExp;
1544 for (
auto &PredSU : ExpPipeCands) {
1545 for (
auto &SuccSU : MFMAPipeCands) {
1558 if (!(TempExp && TempMFMA))
1561 HasChainBetweenCvt =
none_of((*TempExp)->Succs, [&isCvt](
SDep &Succ) {
1562 return isCvt(Succ.getSUnit()->getInstr()->getOpcode());
1566 for (
auto &SuccSU : MFMAPipeCands) {
1567 if (MFMAPipeSUs.
size() &&
1568 any_of(MFMAPipeSUs, [&SuccSU](
SUnit *PotentialMatch) {
1569 return PotentialMatch->
NodeNum == SuccSU->NodeNum;
1573 for (
auto &PredSU : ExpPipeCands) {
1581 MFMAPipeCount =
static_cast<unsigned>(MFMAPipeSUs.
size());
1583 assert(TempExp && TempMFMA);
1584 assert(MFMAPipeCount > 0);
1586 std::optional<SUnit *> TempCvt;
1587 for (
auto &SuccSU : CvtSUs) {
1594 if (TempCvt.has_value()) {
1595 for (
auto &SuccSU : MFMAPipeSUs) {
1603 for (
auto &MFMAPipeSU : MFMAPipeSUs) {
1607 return TII->isMFMAorWMMA(*Succ.getSUnit()->getInstr());
1609 MFMAChainSeeds.push_back(MFMAPipeSU);
1617 for (
auto Pred : MFMAChainSeeds[0]->Preds) {
1618 if (
TII->isDS(
Pred.getSUnit()->getInstr()->getOpcode()) &&
1619 Pred.getSUnit()->getInstr()->mayLoad())
1620 FirstPipeDSR =
Pred.getSUnit()->NodeNum;
1624 unsigned PackSuccCount =
static_cast<unsigned>(
1630 unsigned PackPredCount =
static_cast<unsigned>(
1632 auto Opc = Pred.getSUnit()->getInstr()->getOpcode();
1633 return isBitPack(Opc);
1637 auto Opc = Pred.getSUnit()->getInstr()->getOpcode();
1638 return isBitPack(Opc);
1641 if (PackPred == (*TempMFMA)->Preds.end())
1645 MFMAEnablement =
static_cast<unsigned>(
1647 return TII->isMFMAorWMMA(*Succ.getSUnit()->getInstr());
1651 MFMAEnablement *= PackSuccCount;
1654 ExpRequirement =
static_cast<unsigned>(
1656 return DAG->
IsReachable(PackPred->getSUnit(), ExpBase);
1659 ExpRequirement *= PackPredCount;
1669 return loadAnalysisData();
1671 if (!analyzeDAG(
TII)) {
1677 storeAnalysisData();
1681bool MFMAExpInterleaveOpt::applyIGLPStrategy(
1686 bool IsSmallKernelType =
1687 MFMAEnablement == 2 && ExpRequirement == 4 && TransPipeCount == 32;
1688 bool IsLargeKernelType =
1689 MFMAEnablement == 4 && ExpRequirement == 4 && TransPipeCount == 64;
1691 if (!(IsSmallKernelType || IsLargeKernelType))
1697 unsigned PipelineSyncID = 0;
1698 SchedGroup *SG =
nullptr;
1700 unsigned MFMAChain = 0;
1701 unsigned PositionInChain = 0;
1702 unsigned CurrMFMAForTransPosition = 0;
1704 auto incrementTransPosition = [&MFMAChain, &PositionInChain,
1705 &CurrMFMAForTransPosition,
this]() {
1706 CurrMFMAForTransPosition += MFMAEnablement;
1707 PositionInChain = (CurrMFMAForTransPosition / MFMAChains);
1708 MFMAChain = CurrMFMAForTransPosition % MFMAChains;
1711 auto getNextTransPositionInChain = [&CurrMFMAForTransPosition,
this]() {
1712 auto TempMFMAForTrans = CurrMFMAForTransPosition + MFMAEnablement;
1713 return (TempMFMAForTrans / MFMAChains);
1716 auto getNextTransMFMAChain = [&CurrMFMAForTransPosition,
this]() {
1717 auto TempMFMAForTrans = CurrMFMAForTransPosition + MFMAEnablement;
1718 return TempMFMAForTrans % MFMAChains;
1721 unsigned CurrMFMAPosition = 0;
1722 unsigned MFMAChainForMFMA = 0;
1723 unsigned PositionInChainForMFMA = 0;
1725 auto incrementMFMAPosition = [&CurrMFMAPosition, &MFMAChainForMFMA,
1726 &PositionInChainForMFMA,
this]() {
1728 MFMAChainForMFMA = CurrMFMAPosition % MFMAChains;
1729 PositionInChainForMFMA = CurrMFMAPosition / MFMAChains;
1733 assert(IsPostRA || MFMAChainSeeds.size() == MFMAChains);
1735 bool UsesFMA = IsSmallKernelType || !IsPostRA;
1736 bool UsesDSRead = IsLargeKernelType && !IsPostRA && FirstPipeDSR;
1737 bool UsesCvt = HasCvt && (IsSmallKernelType || !IsPostRA);
1738 bool UsesVALU = IsSmallKernelType;
1743 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1745 if (!IsPostRA && MFMAChains) {
1746 SG->addRule(std::make_shared<EnablesNthMFMAInChain>(
1747 PositionInChain, MFMAChainSeeds[MFMAChain],
TII, SG->getSGID(),
1751 std::make_shared<EnablesNthMFMA>(1,
TII, SG->getSGID(),
true));
1752 SG->addRule(std::make_shared<IsFMA>(
TII, SG->getSGID()));
1753 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1756 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1758 if (!IsPostRA && MFMAChains) {
1759 SG->addRule(std::make_shared<EnablesNthMFMAInChain>(
1760 getNextTransPositionInChain(),
1761 MFMAChainSeeds[getNextTransMFMAChain()],
TII, SG->getSGID(),
true));
1763 SG->addRule(std::make_shared<EnablesNthMFMA>(MFMAEnablement + 1,
TII,
1764 SG->getSGID(),
true));
1765 SG->addRule(std::make_shared<IsFMA>(
TII, SG->getSGID()));
1766 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1770 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1772 SG->addRule(std::make_shared<OccursAtOrAfterNode>(*FirstPipeDSR,
TII,
1774 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1778 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1780 if (!IsPostRA && MFMAChains)
1781 SG->addRule(std::make_shared<EnablesNthMFMAInChain>(
1782 PositionInChain, MFMAChainSeeds[MFMAChain],
TII, SG->getSGID(),
true));
1784 SG->addRule(std::make_shared<EnablesNthMFMA>(1,
TII, SG->getSGID(),
true));
1785 SG->addRule(std::make_shared<IsPipeExp>(
TII, SG->getSGID(),
true));
1786 SG->addRule(std::make_shared<LessThanNSuccs>(8,
TII, SG->getSGID(),
1787 HasChainBetweenCvt));
1788 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1790 incrementTransPosition();
1793 for (
unsigned I = 0;
I < ExpRequirement;
I++) {
1796 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1798 SG->addRule(std::make_shared<IsCvt>(
TII, SG->getSGID()));
1799 if (HasChainBetweenCvt)
1800 SG->addRule(std::make_shared<IsReachableFromPrevNthGroup>(
1801 1 + (2 + UsesFMA) *
I,
TII, SG->getSGID()));
1803 SG->addRule(std::make_shared<IsSuccOfPrevNthGroup>(
1804 1 + (2 + UsesFMA) *
I,
TII, SG->getSGID()));
1805 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1810 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1812 if (!IsPostRA && MFMAChains) {
1813 SG->addRule(std::make_shared<EnablesNthMFMAInChain>(
1814 getNextTransPositionInChain(),
1815 MFMAChainSeeds[getNextTransMFMAChain()],
TII, SG->getSGID(),
true));
1817 SG->addRule(std::make_shared<EnablesNthMFMA>(2 * MFMAEnablement + 1,
1818 TII, SG->getSGID(),
true));
1819 SG->addRule(std::make_shared<IsFMA>(
TII, SG->getSGID()));
1820 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1824 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1826 if (!IsPostRA && MFMAChains)
1827 SG->addRule(std::make_shared<EnablesNthMFMAInChain>(
1828 PositionInChain, MFMAChainSeeds[MFMAChain],
TII, SG->getSGID(),
1831 SG->addRule(std::make_shared<EnablesNthMFMA>(MFMAEnablement + 1,
TII,
1832 SG->getSGID(),
true));
1833 SG->addRule(std::make_shared<IsPipeExp>(
TII, SG->getSGID(),
true));
1834 SG->addRule(std::make_shared<LessThanNSuccs>(8,
TII, SG->getSGID(),
1835 HasChainBetweenCvt));
1836 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1841 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1843 SG->addRule(std::make_shared<IsPipeExp>(
TII, SG->getSGID(),
true));
1844 SG->addRule(std::make_shared<GreaterThanOrEqualToNSuccs>(
1845 8,
TII, SG->getSGID(), HasChainBetweenCvt));
1846 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1851 unsigned MFMARatio =
1852 MFMAEnablement > ExpRequirement ? MFMAEnablement / ExpRequirement : 1;
1855 MFMAEnablement > ExpRequirement ? 1 : ExpRequirement / MFMAEnablement;
1857 unsigned RemainingExp = TransPipeCount > (2 * ExpRequirement)
1858 ? TransPipeCount - (2 * ExpRequirement)
1860 unsigned ExpLoopCount = RemainingExp / ExpRatio;
1862 unsigned MFMAInLoop = MFMAPipeCount > (MFMAEnablement * 2)
1863 ? MFMAPipeCount - (MFMAEnablement * 2)
1865 unsigned MFMALoopCount = MFMAInLoop / MFMARatio;
1867 AddPipeCount < MFMAPipeCount ? 1 : AddPipeCount / MFMAPipeCount;
1868 unsigned LoopSize = std::min(ExpLoopCount, MFMALoopCount);
1870 for (
unsigned I = 0;
I < LoopSize;
I++) {
1871 if (!(
I * ExpRatio % ExpRequirement))
1872 incrementTransPosition();
1875 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1877 if (!IsPostRA && MFMAChains)
1878 SG->addRule(std::make_shared<IsExactMFMA>(
1879 PositionInChainForMFMA, MFMAChainSeeds[MFMAChainForMFMA],
TII,
1880 SG->getSGID(),
true));
1882 SG->addRule(std::make_shared<OccursAfterExp>(
TII, SG->getSGID(),
true));
1883 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1884 incrementMFMAPosition();
1887 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1889 SG->addRule(std::make_shared<IsPipeAdd>(
TII, SG->getSGID()));
1890 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1893 if (UsesDSRead && !(
I % 4)) {
1894 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1896 SG->addRule(std::make_shared<OccursAtOrAfterNode>(*FirstPipeDSR,
TII,
1898 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1902 for (
unsigned J = 0; J < ExpRatio; J++) {
1903 auto MFMAOffset = (1 + UsesVALU) * MFMARatio * (
I + 1);
1904 auto MaxMFMAOffset =
1905 (1 + UsesVALU) * ExpRequirement * MFMARatio / ExpRatio;
1909 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1911 SG->addRule(std::make_shared<IsCvt>(
TII, SG->getSGID()));
1912 auto BaseDiff = (2 + UsesFMA) * (ExpRequirement - 1) + 1;
1913 auto DSROffset =
I / 4 + 1;
1914 auto MaxDSROffset = MaxMFMAOffset / 4;
1916 auto ExpOffset =
I * ExpRatio + J >= ExpRequirement ? 0 : 1;
1917 auto CurrentOffset = UsesDSRead * std::min(MaxDSROffset, DSROffset) +
1918 std::min(MaxMFMAOffset, MFMAOffset) + BaseDiff +
1920 if (HasChainBetweenCvt)
1921 SG->addRule(std::make_shared<IsReachableFromPrevNthGroup>(
1922 CurrentOffset,
TII, SG->getSGID()));
1924 SG->addRule(std::make_shared<IsSuccOfPrevNthGroup>(CurrentOffset,
TII,
1926 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1931 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1933 if (!IsPostRA && MFMAChains)
1934 SG->addRule(std::make_shared<EnablesNthMFMAInChain>(
1935 getNextTransPositionInChain(),
1936 MFMAChainSeeds[getNextTransMFMAChain()],
TII, SG->getSGID(),
1939 SG->addRule(std::make_shared<EnablesNthMFMA>(
1940 (((
I * ExpRatio + J) / ExpRequirement) + 3) * MFMAEnablement + 1,
1941 TII, SG->getSGID(),
true));
1942 SG->addRule(std::make_shared<IsFMA>(
TII, SG->getSGID()));
1943 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1947 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1949 if (!IsPostRA && MFMAChains)
1950 SG->addRule(std::make_shared<EnablesNthMFMAInChain>(
1951 PositionInChain, MFMAChainSeeds[MFMAChain],
TII, SG->getSGID(),
1954 SG->addRule(std::make_shared<EnablesNthMFMA>(
1955 (((
I * ExpRatio + J) / ExpRequirement) + 2) * MFMAEnablement + 1,
1956 TII, SG->getSGID(),
true));
1957 SG->addRule(std::make_shared<IsPipeExp>(
TII, SG->getSGID(),
true));
1958 SG->addRule(std::make_shared<LessThanNSuccs>(8,
TII, SG->getSGID(),
1959 HasChainBetweenCvt));
1960 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1965 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
1967 SG->addRule(std::make_shared<OccursAfterExp>(
TII, SG->getSGID(),
true));
1968 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
1972class MFMAExpSimpleInterleaveOpt final :
public IGLPStrategy {
1974 bool applyIGLPStrategy(
1986 : IGLPStrategy(DAG,
TII, IGLPOptMI) {
1991bool MFMAExpSimpleInterleaveOpt::applyIGLPStrategy(
1996 unsigned MFMACount = 0;
1998 if (
TII->isMFMAorWMMA(
I))
2001 const unsigned PipelineSyncID = 0;
2002 for (
unsigned I = 0;
I < MFMACount * 3; ++
I) {
2003 SchedGroup *SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2005 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2007 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2009 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2015class MFMASmallGemmSingleWaveOpt final :
public IGLPStrategy {
2018 class EnablesInitialMFMA final :
public InstructionRule {
2022 if (!SyncPipe.
size())
2025 if (!Cache->size()) {
2026 for (
auto &Elt : SyncPipe[0].DAG->
SUnits) {
2027 if (
TII->isMFMAorWMMA(*Elt.getInstr())) {
2031 Cache->push_back(&Elt);
2036 auto *DAG = SyncPipe[0].DAG;
2037 for (
auto &Elt : *Cache) {
2045 bool NeedsCache =
false)
2046 : InstructionRule(
TII, SGID, NeedsCache) {}
2050 class IsPermForDSW final :
public InstructionRule {
2055 if (
MI->getOpcode() != AMDGPU::V_PERM_B32_e64)
2058 bool FitsInGroup =
false;
2060 if (!Collection.
size()) {
2061 for (
auto &Succ : SU->
Succs) {
2062 SUnit *SuccUnit = Succ.getSUnit();
2065 Cache->push_back(SuccUnit);
2076 return ThisSucc.getSUnit() == Elt;
2081 IsPermForDSW(
const SIInstrInfo *
TII,
unsigned SGID,
bool NeedsCache =
false)
2082 : InstructionRule(
TII, SGID, NeedsCache) {}
2086 class IsSuccOfPrevGroup final :
public InstructionRule {
2090 SchedGroup *OtherGroup =
nullptr;
2091 for (
auto &PipeSG : SyncPipe) {
2092 if ((
unsigned)PipeSG.getSGID() == SGID - 1) {
2093 OtherGroup = &PipeSG;
2099 if (!OtherGroup->Collection.size())
2103 return any_of(OtherGroup->Collection, [&SU](
SUnit *Elt) {
2104 return any_of(Elt->Succs,
2105 [&SU](SDep &Succ) { return Succ.getSUnit() == SU; });
2109 bool NeedsCache =
false)
2110 : InstructionRule(
TII, SGID, NeedsCache) {}
2114 class VMEMSize final :
public InstructionRule {
2119 if (
MI->getOpcode() == TargetOpcode::BUNDLE)
2121 if (!Collection.
size())
2126 auto TRI =
TII->getRegisterInfo();
2127 auto &
MRI =
MI->getMF()->getRegInfo();
2128 for (
auto &Elt : Collection) {
2129 auto Op = Elt->getInstr()->getOperand(0);
2131 TRI.getRegSizeInBits(*
TRI.getRegClassForOperandReg(
MRI,
Op));
2135 if (NumBits < 128) {
2137 if (NumBits +
TRI.getRegSizeInBits(*
TRI.getRegClassForOperandReg(
2138 MRI,
MI->getOperand(0))) <=
2146 VMEMSize(
const SIInstrInfo *
TII,
unsigned SGID,
bool NeedsCache =
false)
2147 : InstructionRule(
TII, SGID, NeedsCache) {}
2152 class SharesPredWithPrevNthGroup final :
public InstructionRule {
2154 unsigned Distance = 1;
2159 SchedGroup *OtherGroup =
nullptr;
2160 if (!SyncPipe.
size())
2163 if (!Cache->size()) {
2165 for (
auto &PipeSG : SyncPipe) {
2166 if ((
unsigned)PipeSG.getSGID() == SGID - Distance) {
2167 OtherGroup = &PipeSG;
2173 if (!OtherGroup->Collection.size())
2176 for (
auto &OtherEle : OtherGroup->Collection) {
2177 for (
auto &
Pred : OtherEle->Preds) {
2178 if (
Pred.getSUnit()->getInstr()->getOpcode() ==
2179 AMDGPU::V_PERM_B32_e64)
2180 Cache->push_back(
Pred.getSUnit());
2189 auto *DAG = SyncPipe[0].DAG;
2196 SharesPredWithPrevNthGroup(
unsigned Distance,
const SIInstrInfo *
TII,
2197 unsigned SGID,
bool NeedsCache =
false)
2198 : InstructionRule(
TII, SGID, NeedsCache), Distance(Distance) {}
2202 bool applyIGLPStrategy(
2208 static constexpr unsigned NumDSWCounts = 3;
2214 hasIGLPOptData(NumDSWCounts);
2219 : IGLPStrategy(DAG,
TII, IGLPOptMI) {
2224bool MFMASmallGemmSingleWaveOpt::applyIGLPStrategy(
2225 DenseMap<int, SUnitsToCandidateSGsMap> &SyncedInstrs,
2228 unsigned MFMACount = 0;
2229 unsigned DSRCount = 0;
2232 unsigned DSWCount = 0;
2233 unsigned DSWWithPermCount = 0;
2234 unsigned DSWWithSharedVMEMCount = 0;
2236 bool IsInitial =
Phase == AMDGPU::SchedulingPhase::Initial;
2239 std::optional<std::array<int64_t, NumDSWCounts>>
Data =
2240 getIGLPOptData<NumDSWCounts>();
2241 assert(
Data &&
"checked by shouldApplyStrategy");
2242 DSWCount = (*Data)[0];
2243 DSWWithPermCount = (*Data)[1];
2244 DSWWithSharedVMEMCount = (*Data)[2];
2248 for (
auto &SU : DAG->
SUnits) {
2249 auto *
I = SU.getInstr();
2250 if (
TII->isMFMAorWMMA(*
I))
2252 else if (
TII->isDS(*
I)) {
2255 else if (
I->mayStore() && IsInitial) {
2257 for (
auto Pred : SU.Preds) {
2259 AMDGPU::V_PERM_B32_e64) {
2269 DSWWithPermCount =
static_cast<unsigned>(DSWithPerms.
size());
2270 auto *
I = DSWithPerms.
begin();
2271 auto *
E = DSWithPerms.
end();
2279 DenseMap<MachineInstr *, SUnit *> VMEMLookup;
2281 for (;
I !=
E;
I++) {
2282 SUnit *Cand =
nullptr;
2283 bool MissedAny =
false;
2284 for (
auto &
Pred : (*I)->Preds) {
2285 if (
Pred.getSUnit()->getInstr()->
getOpcode() != AMDGPU::V_PERM_B32_e64)
2291 for (
auto &Succ :
Pred.getSUnit()->Succs) {
2292 auto *
MI = Succ.getSUnit()->getInstr();
2293 if (!
TII->isVMEM(*
MI) || !
MI->mayLoad())
2296 if (MissedAny || !VMEMLookup.
size()) {
2298 VMEMLookup[
MI] = *
I;
2315 if (!MissedAny && Cand) {
2316 DSWWithSharedVMEMCount += 2;
2322 setIGLPOptData({DSWCount, DSWWithPermCount, DSWWithSharedVMEMCount});
2325 assert(DSWWithSharedVMEMCount <= DSWWithPermCount);
2327 unsigned PipelineSyncID = 0;
2329 if (DSWWithPermCount) {
2330 for (
unsigned I = 0;
I < MFMACount;
I++) {
2331 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2332 SchedGroupMask::MFMA, 1, PipelineSyncID, DAG,
TII);
2333 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2335 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2336 SchedGroupMask::VALU, 2, PipelineSyncID, DAG,
TII);
2337 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2347 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2348 SchedGroupMask::DS_READ, 4, PipelineSyncID, DAG,
TII);
2349 SG->addRule(std::make_shared<EnablesInitialMFMA>(
TII, SG->getSGID(),
true));
2350 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2352 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2353 SchedGroupMask::MFMA, 1, PipelineSyncID, DAG,
TII);
2354 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2357 for (
unsigned I = 4;
I < DSRCount; ++
I) {
2358 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2359 SchedGroupMask::DS_READ, 1, PipelineSyncID, DAG,
TII);
2360 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2362 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2363 SchedGroupMask::MFMA, 1, PipelineSyncID, DAG,
TII);
2364 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2370 for (
unsigned I = DSWWithSharedVMEMCount;
I < DSWWithPermCount; ++
I) {
2371 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2372 SchedGroupMask::VALU, 4, PipelineSyncID, DAG,
TII);
2373 SG->addRule(std::make_shared<IsPermForDSW>(
TII, SG->getSGID(),
true));
2374 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2376 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2377 SchedGroupMask::DS_WRITE, 1, PipelineSyncID, DAG,
TII);
2378 SG->addRule(std::make_shared<IsSuccOfPrevGroup>(
TII, SG->getSGID()));
2379 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2381 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2382 SchedGroupMask::VMEM_READ, 4, PipelineSyncID, DAG,
TII);
2383 SG->addRule(std::make_shared<SharesPredWithPrevNthGroup>(
2384 1,
TII, SG->getSGID(),
true));
2385 SG->addRule(std::make_shared<VMEMSize>(
TII, SG->getSGID()));
2386 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2388 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2389 SchedGroupMask::MFMA, 1, PipelineSyncID, DAG,
TII);
2390 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2392 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2393 SchedGroupMask::VMEM_READ, 4, PipelineSyncID, DAG,
TII);
2394 SG->addRule(std::make_shared<SharesPredWithPrevNthGroup>(
2395 3,
TII, SG->getSGID(),
true));
2396 SG->addRule(std::make_shared<VMEMSize>(
TII, SG->getSGID()));
2397 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2399 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2400 SchedGroupMask::MFMA, 1, PipelineSyncID, DAG,
TII);
2401 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2407 for (
unsigned I = DSWWithPermCount;
I < DSWCount;
I++) {
2408 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2409 SchedGroupMask::DS_WRITE, 1, PipelineSyncID, DAG,
TII);
2410 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2412 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2413 SchedGroupMask::VMEM_READ, 4, PipelineSyncID, DAG,
TII);
2414 SG->addRule(std::make_shared<VMEMSize>(
TII, SG->getSGID()));
2415 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2417 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2418 SchedGroupMask::MFMA, 1, PipelineSyncID, DAG,
TII);
2419 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2427 for (
unsigned I = 0;
I < DSWWithSharedVMEMCount; ++
I) {
2428 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2429 SchedGroupMask::VALU, 4, PipelineSyncID, DAG,
TII);
2430 SG->addRule(std::make_shared<IsPermForDSW>(
TII, SG->getSGID(),
true));
2431 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2433 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2434 SchedGroupMask::DS_WRITE, 1, PipelineSyncID, DAG,
TII);
2435 SG->addRule(std::make_shared<IsSuccOfPrevGroup>(
TII, SG->getSGID()));
2436 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2438 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2439 SchedGroupMask::MFMA, 1, PipelineSyncID, DAG,
TII);
2440 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2442 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2443 SchedGroupMask::VALU, 4, PipelineSyncID, DAG,
TII);
2444 SG->addRule(std::make_shared<IsPermForDSW>(
TII, SG->getSGID(),
true));
2445 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2447 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2448 SchedGroupMask::DS_WRITE, 1, PipelineSyncID, DAG,
TII);
2449 SG->addRule(std::make_shared<IsSuccOfPrevGroup>(
TII, SG->getSGID()));
2450 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2452 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2453 SchedGroupMask::MFMA, 1, PipelineSyncID, DAG,
TII);
2454 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2456 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2457 SchedGroupMask::VMEM_READ, 4, PipelineSyncID, DAG,
TII);
2458 SG->addRule(std::make_shared<SharesPredWithPrevNthGroup>(
2459 2,
TII, SG->getSGID(),
true));
2460 SG->addRule(std::make_shared<VMEMSize>(
TII, SG->getSGID()));
2461 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2463 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2464 SchedGroupMask::MFMA, 1, PipelineSyncID, DAG,
TII);
2465 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2467 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2468 SchedGroupMask::VMEM_READ, 4, PipelineSyncID, DAG,
TII);
2469 SG->addRule(std::make_shared<SharesPredWithPrevNthGroup>(
2470 4,
TII, SG->getSGID(),
true));
2471 SG->addRule(std::make_shared<VMEMSize>(
TII, SG->getSGID()));
2472 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2474 SG = &SyncedSchedGroups[PipelineSyncID].emplace_back(
2475 SchedGroupMask::MFMA, 1, PipelineSyncID, DAG,
TII);
2476 SG->findCandidateSUnits(SyncedInstrs[SG->getSyncID()]);
2482static std::unique_ptr<IGLPStrategy>
2484 const SIInstrInfo *
TII, MachineInstr *IGLPOptMI) {
2487 return std::make_unique<MFMASmallGemmOpt>(DAG,
TII, IGLPOptMI);
2489 return std::make_unique<MFMASmallGemmSingleWaveOpt>(DAG,
TII, IGLPOptMI);
2491 return std::make_unique<MFMAExpInterleaveOpt>(DAG,
TII, IGLPOptMI);
2493 return std::make_unique<MFMAExpSimpleInterleaveOpt>(DAG,
TII, IGLPOptMI);
2499class IGroupLPDAGMutation :
public ScheduleDAGMutation {
2501 const SIInstrInfo *
TII;
2508 DenseMap<int, SmallVector<SchedGroup, 4>> SyncedSchedGroups;
2511 DenseMap<int, SUnitsToCandidateSGsMap> SyncedInstrs;
2514 void addSchedBarrierEdges(SUnit &SU);
2528 void initSchedGroupBarrierPipelineStage(
2529 std::vector<SUnit>::reverse_iterator RIter);
2531 bool initIGLPOpt(SUnit &SU);
2534 void apply(ScheduleDAGInstrs *DAGInstrs)
override;
2541 bool IsBottomUp =
true;
2546 IGroupLPDAGMutation() =
default;
2550unsigned SchedGroup::NumSchedGroups = 0;
2552bool SchedGroup::tryAddEdge(SUnit *
A, SUnit *
B) {
2556bool SchedGroup::canAddMI(
const MachineInstr &
MI)
const {
2558 if (
MI.isMetaInstruction())
2561 else if (
MI.isInlineAsm()) {
2563 auto &
MRI =
MI.getParent()->getParent()->getRegInfo();
2564 bool SGPR_used =
false, SGPR_big_def =
false, VGPR_used =
false,
2565 VMFMA_used =
false, VReg32_used =
false,
MayLoad =
MI.mayLoad(),
2567 for (
const MachineOperand &Operand :
MI.operands())
2568 if (Operand.isReg()) {
2570 *
TRI.getRegClassForOperandReg(
MRI, Operand);
2571 if (
TRI.hasVGPRs(&RegClass)) {
2573 if (Operand.isUse() &&
TRI.getRegSizeInBits(RegClass) == 32)
2579 if (
TRI.hasAGPRs(&RegClass) ||
TRI.getRegSizeInBits(RegClass) > 128)
2581 if (
TRI.hasSGPRs(&RegClass))
2583 if (
TRI.getRegSizeInBits(RegClass) > 64 && Operand.isDef())
2584 SGPR_big_def =
true;
2587 typedef std::underlying_type_t<SchedGroupMask> SGMask_t;
2588 SGMask_t InlineAsmMask = 0;
2589 if (VGPR_used && !VMFMA_used && !MayLoad && !MayStore)
2590 InlineAsmMask |= (SGMask_t)SchedGroupMask::VALU;
2591 if (SGPR_used && !VGPR_used && !MayLoad && !MayStore)
2592 InlineAsmMask |= (SGMask_t)SchedGroupMask::SALU;
2594 InlineAsmMask |= (SGMask_t)SchedGroupMask::MFMA;
2595 if (VGPR_used && MayLoad)
2596 InlineAsmMask |= (SGMask_t)(VReg32_used ? SchedGroupMask::DS_READ
2597 : SchedGroupMask::VMEM_READ);
2598 if (VGPR_used && MayStore)
2599 InlineAsmMask |= (SGMask_t)(VReg32_used ? SchedGroupMask::DS_WRITE
2600 : SchedGroupMask::VMEM_WRITE);
2602 InlineAsmMask |= (SGMask_t)SchedGroupMask::DS_READ;
2603 if (InlineAsmMask & (SGMask_t)SchedGroupMask::VALU ||
2604 InlineAsmMask & (SGMask_t)SchedGroupMask::SALU)
2605 InlineAsmMask |= (SGMask_t)SchedGroupMask::ALU;
2606 if (InlineAsmMask & (SGMask_t)SchedGroupMask::DS_READ ||
2607 InlineAsmMask & (SGMask_t)SchedGroupMask::DS_WRITE)
2608 InlineAsmMask |= (SGMask_t)SchedGroupMask::DS;
2609 if (InlineAsmMask & (SGMask_t)SchedGroupMask::VMEM_READ ||
2610 InlineAsmMask & (SGMask_t)SchedGroupMask::VMEM_WRITE)
2611 InlineAsmMask |= (SGMask_t)SchedGroupMask::VMEM;
2613 Result = ((SGMask_t)SGMask & InlineAsmMask) != 0;
2616 else if (((SGMask & SchedGroupMask::ALU) != SchedGroupMask::NONE) &&
2617 (
TII->isVALU(
MI,
true) ||
TII->isMFMAorWMMA(
MI) ||
2621 else if (((SGMask & SchedGroupMask::VALU) != SchedGroupMask::NONE) &&
2622 TII->isVALU(
MI,
false) && !
TII->isMFMAorWMMA(
MI) &&
2623 !
TII->isTRANS(
MI)) {
2630 else if (((SGMask & SchedGroupMask::SALU) != SchedGroupMask::NONE) &&
2634 else if (((SGMask & SchedGroupMask::MFMA) != SchedGroupMask::NONE) &&
2635 TII->isMFMAorWMMA(
MI))
2638 else if (((SGMask & SchedGroupMask::VMEM) != SchedGroupMask::NONE) &&
2642 else if (((SGMask & SchedGroupMask::VMEM_READ) != SchedGroupMask::NONE) &&
2646 else if (((SGMask & SchedGroupMask::VMEM_WRITE) != SchedGroupMask::NONE) &&
2647 MI.mayStore() &&
TII->isVMEM(
MI) && !
TII->isLDSDMA(
MI))
2650 else if (((SGMask & SchedGroupMask::DS) != SchedGroupMask::NONE) &&
2654 else if (((SGMask & SchedGroupMask::DS_READ) != SchedGroupMask::NONE) &&
2655 MI.mayLoad() &&
TII->isDS(
MI))
2658 else if (((SGMask & SchedGroupMask::DS_WRITE) != SchedGroupMask::NONE) &&
2659 MI.mayStore() &&
TII->isDS(
MI))
2662 else if (((SGMask & SchedGroupMask::TRANS) != SchedGroupMask::NONE) &&
2666 else if (((SGMask & SchedGroupMask::LDSDMA) != SchedGroupMask::NONE) &&
2671 dbgs() <<
"For SchedGroup with mask " <<
format_hex((
int)SGMask, 10,
true)
2672 << (Result ?
" could classify " :
" unable to classify ") <<
MI);
2677int SchedGroup::link(SUnit &SU,
bool MakePred,
2678 std::list<std::pair<SUnit *, SUnit *>> &AddedEdges) {
2679 int MissedEdges = 0;
2680 for (
auto *
A : Collection) {
2682 if (
A ==
B ||
A->getInstr()->getOpcode() == AMDGPU::SCHED_GROUP_BARRIER)
2692 bool Added = tryAddEdge(
A,
B);
2694 AddedEdges.emplace_back(
A,
B);
2702void SchedGroup::link(SUnit &SU,
bool MakePred) {
2703 for (
auto *
A : Collection) {
2705 if (
A->getInstr()->getOpcode() == AMDGPU::SCHED_GROUP_BARRIER)
2714void SchedGroup::link(SUnit &SU,
2715 function_ref<
bool(
const SUnit *
A,
const SUnit *
B)>
P) {
2716 for (
auto *
A : Collection) {
2725void SchedGroup::link(SchedGroup &OtherGroup) {
2726 for (
auto *
B : OtherGroup.Collection)
2730bool SchedGroup::canAddSU(SUnit &SU)
const {
2732 if (
MI.getOpcode() != TargetOpcode::BUNDLE)
2733 return canAddMI(
MI);
2738 while (
E !=
MBB->
end() &&
E->isBundledWithPred())
2742 return std::all_of(
B,
E, [
this](MachineInstr &
MI) {
return canAddMI(
MI); });
2746void SchedGroup::findCandidateSUnits(
T Begin,
T End,
2747 SUnitsToCandidateSGsMap &SyncedInstrs) {
2750 SyncedInstrs[&SU].push_back(SGID);
2754void SchedGroup::findCandidateSUnits(SUnitsToCandidateSGsMap &SyncedInstrs) {
2755 findCandidateSUnits(DAG->
SUnits.rbegin(), DAG->
SUnits.rend(), SyncedInstrs);
2758void IGroupLPDAGMutation::apply(ScheduleDAGInstrs *DAGInstrs) {
2759 const TargetSchedModel *TSchedModel = DAGInstrs->
getSchedModel();
2760 if (!TSchedModel || DAGInstrs->
SUnits.empty())
2765 TII =
ST.getInstrInfo();
2766 DAG =
static_cast<ScheduleDAGMI *
>(DAGInstrs);
2767 SyncedSchedGroups.clear();
2768 SyncedInstrs.clear();
2769 bool FoundSB =
false;
2770 bool FoundIGLP =
false;
2771 bool ShouldApplyIGLP =
false;
2772 for (
auto R = DAG->
SUnits.rbegin(),
E = DAG->
SUnits.rend(); R !=
E; ++R) {
2773 unsigned Opc =
R->getInstr()->getOpcode();
2775 if (
Opc == AMDGPU::SCHED_BARRIER) {
2776 addSchedBarrierEdges(*R);
2778 }
else if (
Opc == AMDGPU::SCHED_GROUP_BARRIER) {
2779 initSchedGroupBarrierPipelineStage(R);
2781 }
else if (
Opc == AMDGPU::IGLP_OPT) {
2782 if (!FoundSB && !FoundIGLP) {
2784 ShouldApplyIGLP = initIGLPOpt(*R);
2789 if (FoundSB || (FoundIGLP && ShouldApplyIGLP)) {
2790 PipelineSolver PS(SyncedSchedGroups, SyncedInstrs, DAG, IsBottomUp);
2798void IGroupLPDAGMutation::addSchedBarrierEdges(SUnit &SchedBarrier) {
2800 assert(
MI.getOpcode() == AMDGPU::SCHED_BARRIER);
2801 LLVM_DEBUG(
dbgs() <<
"Building SchedGroup for SchedBarrier with Mask: "
2802 <<
MI.getOperand(0).getImm() <<
"\n");
2805 SchedGroup SG(InvertedMask, std::nullopt, DAG,
TII);
2807 for (SUnit &SU : DAG->
SUnits)
2808 if (SG.canAddSU(SU))
2814 (function_ref<
bool(
const SUnit *
A,
const SUnit *
B)>)[](
2815 const SUnit *
A,
const SUnit *
B) {
return A->NodeNum >
B->NodeNum; });
2819IGroupLPDAGMutation::invertSchedBarrierMask(
SchedGroupMask Mask)
const {
2824 static constexpr std::pair<SchedGroupMask, SchedGroupMask> ImpliedGroups[] = {
2825 {SchedGroupMask::ALU, SchedGroupMask::VALU | SchedGroupMask::SALU |
2826 SchedGroupMask::MFMA | SchedGroupMask::TRANS},
2827 {SchedGroupMask::VMEM, SchedGroupMask::VMEM_READ |
2828 SchedGroupMask::VMEM_WRITE |
2829 SchedGroupMask::LDSDMA},
2830 {SchedGroupMask::DS, SchedGroupMask::DS_READ | SchedGroupMask::DS_WRITE |
2831 SchedGroupMask::LDSDMA},
2834 for (
auto [Aggregate, Members] : ImpliedGroups) {
2836 if ((InvertedMask & Aggregate) == SchedGroupMask::NONE)
2837 InvertedMask &= ~Members;
2839 else if ((InvertedMask & Members) != Members)
2840 InvertedMask &= ~Aggregate;
2843 LLVM_DEBUG(
dbgs() <<
"After Inverting, SchedGroup Mask: " << (
int)InvertedMask
2846 return InvertedMask;
2849void IGroupLPDAGMutation::initSchedGroupBarrierPipelineStage(
2850 std::vector<SUnit>::reverse_iterator RIter) {
2851 MachineInstr &SGB = *RIter->getInstr();
2858 auto &SG = SyncedSchedGroups[SyncID].emplace_back((
SchedGroupMask)SGMask,
2861 SG.findCandidateSUnits(RIter, SG.DAG->
SUnits.rend(),
2862 SyncedInstrs[SG.getSyncID()]);
2865bool IGroupLPDAGMutation::initIGLPOpt(SUnit &SU) {
2868 auto S = createIGLPStrategy(StrategyID, DAG,
TII, SU.
getInstr());
2869 if (!S->shouldApplyStrategy(DAG,
Phase))
2872 IsBottomUp = S->IsBottomUp;
2873 return S->applyIGLPStrategy(SyncedInstrs, SyncedSchedGroups,
Phase);
2883std::unique_ptr<ScheduleDAGMutation>
2885 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.
const AMDGPUOptions & getCLOpts() const
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.
unsigned getNumOperands() const
Retuns the total number of operands.
LLVM_ABI void addOperand(MachineFunction &MF, const MachineOperand &Op)
Add the specified operand to the instruction.
bool mayStore(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly modify memory.
LLVM_ABI void removeOperand(unsigned OpNo)
Erase an operand from an instruction, leaving it with one fewer operand than it started with.
const MachineOperand & getOperand(unsigned i) const
MachineOperand class - Representation of each machine instruction operand.
static MachineOperand CreateImm(int64_t Val)
unsigned getOpcode() const
Return the SelectionDAG opcode value for this node.
@ 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)
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 drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
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.
detail::zippy< detail::zip_first, T, U, Args... > zip_equal(T &&t, U &&u, Args &&...args)
zip iterator that assumes that all iteratees have the same length.
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:...