28#define DEBUG_TYPE "gcn-hazard-recognizer"
31#define DEBUG_TYPE_VERBOSE "gcn-hazard-recognizer-verbose"
34 "Number of WMMA hazard V_NOPs hoisted from loops");
36 "Number of WMMA hazards where V_NOP hoisting was not possible");
40struct MFMAPaddingRatioParser :
public cl::parser<unsigned> {
43 bool parse(cl::Option &O, StringRef ArgName, StringRef Arg,
unsigned &
Value) {
45 return O.error(
"'" + Arg +
"' value invalid for uint argument!");
48 return O.error(
"'" + Arg +
"' value must be in the range [0, 100]!");
58 cl::desc(
"Fill a percentage of the latency between "
59 "neighboring MFMA with s_nops."));
64 cl::desc(
"Insert a s_nop x before every instruction"));
68 cl::desc(
"Hoist WMMA hazard V_NOPs from loops to preheaders"));
80 : Mode(Mode), CurrCycleInstr(nullptr), MF(MF),
81 ST(MF.getSubtarget<
GCNSubtarget>()), TII(*ST.getInstrInfo()),
82 TRI(TII.getRegisterInfo()), TSchedModel(TII.getSchedModel()), MLI(MLI),
83 ClauseUses(TRI.getNumRegUnits()), ClauseDefs(TRI.getNumRegUnits()) {
84 MaxLookAhead = MF.getRegInfo().isPhysRegUsed(AMDGPU::AGPR0) ? 19 : 5;
88 dbgs() <<
" PreRA hazard recognizer: " << MF.getName() <<
"\n";
100 if (CurrentCoExecStage.has_value()) {
101 unsigned Stage = *CurrentCoExecStage;
103 CoExecWindowLog[Stage] = ActiveCoExecInfo.Pattern[Stage];
104 dbgs() <<
" CoExec window ended at stage " << Stage <<
":\n";
111 EmittedInstrs.clear();
112 EmittedVALUInstrs.clear();
113 HasPendingWMMACoexecHazard =
false;
118void GCNHazardRecognizer::schedulerReset() {
120 if (CurrentCoExecStage.has_value() || CyclesUntilTRANS > 0 ||
122 dbgs() <<
" Scheduler Reset: clearing co-exec window, TRANS="
123 << CyclesUntilTRANS <<
", VALU=" << CyclesUntilVALU <<
"\n";
125 CurrentCoExecStage = std::nullopt;
126 CoExecWindowStartCycle = 0;
127 CyclesUntilTRANS = 0;
130 CoExecWindowLog.fill(
'.');
133void GCNHazardRecognizer::dumpCoExecWindow()
const {
134 unsigned W = ActiveCoExecInfo.TotalWindow;
139 dbgs() <<
" Stages: ";
140 for (
unsigned I = 0;
I <
W; ++
I)
141 dbgs() <<
I % 10 <<
' ';
145 dbgs() <<
" Slots: ";
146 for (
unsigned I = 0;
I <
W; ++
I)
147 dbgs() << ActiveCoExecInfo.Pattern[
I] <<
' ';
151 dbgs() <<
" Scheduled: ";
152 for (
unsigned I = 0;
I <
W; ++
I)
153 dbgs() << CoExecWindowLog[
I] <<
' ';
157void GCNHazardRecognizer::schedulerAdvanceCycle() {
159 if (CurrentCoExecStage.has_value()) {
160 unsigned Stage = *CurrentCoExecStage;
163 CoExecWindowLog[Stage] = ActiveCoExecInfo.Pattern[Stage];
165 CoExecWindowLog[Stage] =
'-';
170 bool HasState = CurrentCoExecStage.has_value() || CyclesUntilTRANS > 0 ||
173 dbgs() <<
" Scheduler AdvanceCycle:";
174 if (CurrentCoExecStage.has_value()) {
175 unsigned Stage = *CurrentCoExecStage;
176 unsigned Next = Stage + 1;
177 if (
Next >= ActiveCoExecInfo.TotalWindow)
178 dbgs() <<
" stage " << Stage <<
"->expired";
180 dbgs() <<
" stage " << Stage <<
"->" <<
Next;
182 if (CyclesUntilTRANS > 0)
183 dbgs() <<
" TRANS=" << CyclesUntilTRANS <<
"->"
184 << (CyclesUntilTRANS - 1);
185 if (CyclesUntilVALU > 0)
186 dbgs() <<
" VALU=" << CyclesUntilVALU <<
"->" << (CyclesUntilVALU - 1);
192 if (CyclesUntilTRANS > 0)
194 if (CyclesUntilVALU > 0)
198 if (CurrentCoExecStage.has_value()) {
199 unsigned Stage = *CurrentCoExecStage + 1;
200 if (Stage >= ActiveCoExecInfo.TotalWindow) {
203 dbgs() <<
" CoExec window complete:\n";
206 CurrentCoExecStage = std::nullopt;
208 CurrentCoExecStage = Stage;
213bool GCNHazardRecognizer::hasCoExecWindowModel()
const {
219 if (ST.hasWMMACoexecutionHazards() && ST.hasTransCoexecutionHazard() &&
223 if (ST.hasGFX950Insts() &&
230void GCNHazardRecognizer::updateWMMAWindowState(
const MachineInstr &
MI) {
231 if (!hasCoExecWindowModel())
241 if (CurrentCoExecStage.has_value()) {
242 unsigned Stage = *CurrentCoExecStage;
244 CoExecWindowLog[Stage] = ActiveCoExecInfo.Pattern[Stage];
245 dbgs() <<
" CoExec window interrupted at stage " << Stage <<
":\n";
252 CurrentCoExecStage = 0;
253 CoExecWindowLog.fill(
'.');
255 LLVM_DEBUG(
dbgs() <<
" WMMA window started: " << ActiveCoExecInfo.Pattern
256 <<
" (window=" << ActiveCoExecInfo.TotalWindow <<
")\n"
260void GCNHazardRecognizer::updateTRANSState(
const MachineInstr &
MI) {
261 if (!hasCoExecWindowModel())
275 CyclesUntilTRANS = 2;
279void GCNHazardRecognizer::updateMultiCycleVALUState(
const MachineInstr &
MI) {
280 if (!hasCoExecWindowModel())
291 unsigned RepeatRate = TII.getRepeatRate(
MI);
292 if (RepeatRate > 1) {
296 CyclesUntilVALU = RepeatRate;
298 <<
", CyclesUntilVALU=" << CyclesUntilVALU <<
"\n");
308unsigned GCNHazardRecognizer::checkTRANSHazard(
const MachineInstr &
MI)
const {
309 if (!CyclesUntilTRANS)
314 return CyclesUntilTRANS;
318 TII.getRepeatRate(
MI) > 1)
319 return CyclesUntilTRANS;
325GCNHazardRecognizer::checkMultiCycleVALUHazard(
const MachineInstr &
MI)
const {
326 if (!CyclesUntilVALU)
337 return CyclesUntilVALU;
341GCNHazardRecognizer::checkWMMACoexecSlot(
const MachineInstr &
MI)
const {
343 if (!CurrentCoExecStage.has_value())
346 unsigned Stage = *CurrentCoExecStage;
348 unsigned StallCycles = ActiveCoExecInfo.getStallCycles(InstMask, Stage);
351 if (StallCycles == 0)
355 unsigned NextStage = Stage + StallCycles;
356 if (NextStage < ActiveCoExecInfo.TotalWindow) {
359 dbgs() <<
" CoExec stall: stage=" << Stage <<
"("
362 <<
" -> stall " << StallCycles <<
" (next allowed=" << NextStage
371 dbgs() <<
" CoExec stall: stage=" << Stage <<
"("
374 << StallCycles <<
" (window ends)\n"
380GCNHazardRecognizer::checkMultiShadowHazard(
const MachineInstr &
MI)
const {
382 if (!hasCoExecWindowModel())
386 if (!CurrentCoExecStage.has_value())
389 if (!CyclesUntilTRANS)
399 unsigned LookAheadStage = *CurrentCoExecStage + CyclesUntilTRANS;
401 return CyclesUntilTRANS +
402 ActiveCoExecInfo.getStallCycles(InstMask, LookAheadStage);
405void GCNHazardRecognizer::schedulerEmitInstruction(
MachineInstr *
MI) {
407 bool InWindow = CurrentCoExecStage.has_value();
408 bool HasActiveState =
409 InWindow || CyclesUntilTRANS > 0 || CyclesUntilVALU > 0;
410 if (HasActiveState) {
412 unsigned Stage = *CurrentCoExecStage;
413 dbgs() <<
" Stage " << Stage <<
"("
426 bool HasActiveState = CurrentCoExecStage.has_value() ||
427 CyclesUntilTRANS > 0 || CyclesUntilVALU > 0;
433 updateWMMAWindowState(*
MI);
434 updateTRANSState(*
MI);
435 updateMultiCycleVALUState(*
MI);
445 schedulerEmitInstruction(
MI);
449 return Opcode == AMDGPU::V_DIV_FMAS_F32_e64 || Opcode == AMDGPU::V_DIV_FMAS_F64_e64;
453 return Opcode == AMDGPU::S_GETREG_B32 || Opcode == AMDGPU::S_GETREG_B32_const;
458 case AMDGPU::S_SETREG_B32:
459 case AMDGPU::S_SETREG_B32_mode:
460 case AMDGPU::S_SETREG_IMM32_B32:
461 case AMDGPU::S_SETREG_IMM32_B32_mode:
468 return Opcode == AMDGPU::V_READLANE_B32 || Opcode == AMDGPU::V_WRITELANE_B32;
472 return Opcode == AMDGPU::S_RFE_B64;
477 case AMDGPU::S_MOVRELS_B32:
478 case AMDGPU::S_MOVRELS_B64:
479 case AMDGPU::S_MOVRELD_B32:
480 case AMDGPU::S_MOVRELD_B64:
489 if (
TII.isAlwaysGDS(
MI.getOpcode()))
492 switch (
MI.getOpcode()) {
493 case AMDGPU::S_SENDMSG:
494 case AMDGPU::S_SENDMSGHALT:
495 case AMDGPU::S_TTRACEDATA:
499 case AMDGPU::DS_PERMUTE_B32:
500 case AMDGPU::DS_BPERMUTE_B32:
503 if (
TII.isDS(
MI.getOpcode())) {
504 int GDS = AMDGPU::getNamedOperandIdx(
MI.getOpcode(),
505 AMDGPU::OpName::gds);
506 if (
MI.getOperand(GDS).getImm())
514 unsigned Opcode =
MI.getOpcode();
515 return Opcode == AMDGPU::V_PERMLANE16_B32_e64 ||
516 Opcode == AMDGPU::V_PERMLANE64_B32 ||
517 Opcode == AMDGPU::V_PERMLANEX16_B32_e64 ||
518 Opcode == AMDGPU::V_PERMLANE16_VAR_B32_e64 ||
519 Opcode == AMDGPU::V_PERMLANEX16_VAR_B32_e64 ||
520 Opcode == AMDGPU::V_PERMLANE16_SWAP_B32_e32 ||
521 Opcode == AMDGPU::V_PERMLANE16_SWAP_B32_e64 ||
522 Opcode == AMDGPU::V_PERMLANE32_SWAP_B32_e32 ||
523 Opcode == AMDGPU::V_PERMLANE32_SWAP_B32_e64 ||
524 Opcode == AMDGPU::V_PERMLANE_BCAST_B32_e64 ||
525 Opcode == AMDGPU::V_PERMLANE_UP_B32_e64 ||
526 Opcode == AMDGPU::V_PERMLANE_DOWN_B32_e64 ||
527 Opcode == AMDGPU::V_PERMLANE_XOR_B32_e64 ||
528 Opcode == AMDGPU::V_PERMLANE_IDX_GEN_B32_e64;
537 AMDGPU::OpName::simm16);
553 if (checkMultiShadowHazard(*
MI) > 0)
555 if (checkWMMACoexecSlot(*
MI) > 0)
557 if (checkTRANSHazard(*
MI) > 0)
559 if (checkMultiCycleVALUHazard(*
MI) > 0)
569 if (ST.hasNSAtoVMEMBug() && checkNSAtoVMEMHazard(
MI) > 0)
572 if (checkFPAtomicToDenormModeHazard(
MI) > 0)
577 if (checkWMMACoexecutionHazards(
MI) > 0) {
578 HasPendingWMMACoexecHazard =
true;
583 if (ST.hasNoDataDepHazard())
590 checkVALUHazards(
MI) > 0)
596 if (
isDivFMas(
MI->getOpcode()) && checkDivFMasHazards(
MI) > 0)
599 if (
isRWLane(
MI->getOpcode()) && checkRWLaneHazards(
MI) > 0)
605 checkMAIVALUHazards(
MI) > 0)
608 if (
isSGetReg(
MI->getOpcode()) && checkGetRegHazards(
MI) > 0)
611 if (
isSSetReg(
MI->getOpcode()) && checkSetRegHazards(
MI) > 0)
614 if (
isRFE(
MI->getOpcode()) && checkRFEHazards(
MI) > 0)
617 if (((ST.hasReadM0MovRelInterpHazard() &&
619 MI->getOpcode() == AMDGPU::DS_WRITE_ADDTID_B32 ||
620 MI->getOpcode() == AMDGPU::DS_READ_ADDTID_B32)) ||
622 (ST.hasReadM0LdsDmaHazard() &&
isLdsDma(*
MI)) ||
623 (ST.hasReadM0LdsDirectHazard() &&
624 MI->readsRegister(AMDGPU::LDS_DIRECT,
nullptr))) &&
625 checkReadM0Hazards(
MI) > 0)
632 checkMAILdStHazards(
MI) > 0)
635 if (ST.hasPermlaneForwardingHazard() &&
isPermlane(*
MI) &&
636 checkPermlaneHazards(
MI) > 0)
639 if (
MI->isInlineAsm() && checkInlineAsmHazards(
MI) > 0)
647 while (Quantity > 0) {
648 unsigned Arg = std::min(Quantity, 8u);
656GCNHazardRecognizer::getMFMAPipelineWaitStates(
const MachineInstr &
MI)
const {
657 const MCSchedClassDesc *SC = TSchedModel.resolveSchedClass(&
MI);
658 assert(TSchedModel.getWriteProcResBegin(SC) !=
659 TSchedModel.getWriteProcResEnd(SC));
660 return TSchedModel.getWriteProcResBegin(SC)->ReleaseAtCycle;
663void GCNHazardRecognizer::processBundle() {
667 for (;
MI !=
E &&
MI->isInsideBundle(); ++
MI) {
668 CurrCycleInstr = &*
MI;
672 fixHazards(CurrCycleInstr);
680 for (
unsigned i = 0, e = std::min(WaitStates,
MaxLookAhead - 1); i <
e; ++i)
681 EmittedInstrs.push_front(
nullptr);
683 EmittedInstrs.push_front(CurrCycleInstr);
686 CurrCycleInstr =
nullptr;
694 if (
MI->isInsideBundle())
708 CurrCycleInstr =
nullptr;
717 W = checkWMMACoexecSlot(*
MI);
718 W = std::max(W, checkTRANSHazard(*
MI));
719 W = std::max(W, checkMultiCycleVALUHazard(*
MI));
720 W = std::max(W, checkMultiShadowHazard(*
MI));
736 return std::max(WaitStates, checkSMRDHazards(
MI));
738 if (ST.hasNSAtoVMEMBug())
739 WaitStates = std::max(WaitStates, checkNSAtoVMEMHazard(
MI));
741 WaitStates = std::max(WaitStates, checkFPAtomicToDenormModeHazard(
MI));
743 if (ST.hasNoDataDepHazard())
747 WaitStates = std::max(WaitStates, checkVMEMHazards(
MI));
750 WaitStates = std::max(WaitStates, checkVALUHazards(
MI));
753 WaitStates = std::max(WaitStates, checkDPPHazards(
MI));
756 WaitStates = std::max(WaitStates, checkDivFMasHazards(
MI));
759 WaitStates = std::max(WaitStates, checkRWLaneHazards(
MI));
764 WaitStates = std::max(WaitStates, checkMAIVALUHazards(
MI));
766 if (
MI->isInlineAsm())
767 return std::max(WaitStates, checkInlineAsmHazards(
MI));
770 return std::max(WaitStates, checkGetRegHazards(
MI));
773 return std::max(WaitStates, checkSetRegHazards(
MI));
776 return std::max(WaitStates, checkRFEHazards(
MI));
778 if ((ST.hasReadM0MovRelInterpHazard() &&
780 MI->getOpcode() == AMDGPU::DS_WRITE_ADDTID_B32 ||
781 MI->getOpcode() == AMDGPU::DS_READ_ADDTID_B32)) ||
783 (ST.hasReadM0LdsDmaHazard() &&
isLdsDma(*
MI)) ||
784 (ST.hasReadM0LdsDirectHazard() &&
785 MI->readsRegister(AMDGPU::LDS_DIRECT,
nullptr)))
786 return std::max(WaitStates, checkReadM0Hazards(
MI));
789 return std::max(WaitStates, checkMAIHazards(
MI));
792 return std::max(WaitStates, checkMAILdStHazards(
MI));
794 if (ST.hasPermlaneForwardingHazard() &&
isPermlane(*
MI))
795 return std::max(WaitStates, checkPermlaneHazards(
MI));
801 EmittedInstrs.push_front(
nullptr);
806 schedulerAdvanceCycle();
810 if (!CurrCycleInstr) {
811 EmittedInstrs.push_front(
nullptr);
813 if (HasPendingWMMACoexecHazard)
814 EmittedVALUInstrs.push_front(
nullptr);
818 HasPendingWMMACoexecHazard =
false;
820 if (CurrCycleInstr->isBundle()) {
825 unsigned NumWaitStates = TII.getNumWaitStates(*CurrCycleInstr);
826 if (!NumWaitStates) {
827 CurrCycleInstr =
nullptr;
832 EmittedInstrs.push_front(CurrCycleInstr);
839 EmittedVALUInstrs.push_front(CurrCycleInstr);
845 while (!EmittedVALUInstrs.empty() && EmittedVALUInstrs.front() ==
nullptr)
846 EmittedVALUInstrs.pop_front();
854 EmittedInstrs.push_front(
nullptr);
861 if (EmittedVALUInstrs.size() > MaxVALULookAhead)
862 EmittedVALUInstrs.resize(MaxVALULookAhead);
864 CurrCycleInstr =
nullptr;
869 "Bottom-up scheduling shouldn't run in hazard recognizer mode");
879template <
typename StateT>
889 static bool isEqual(
const StateMapKey &
LHS,
const StateMapKey &
RHS) {
894 static unsigned getHashValue(
const StateMapKey &
Key) {
895 return StateT::getHashValue((*
Key.States)[
Key.Idx]);
897 static unsigned getHashValue(
const StateT &State) {
898 return StateT::getHashValue(State);
900 static bool isEqual(
const StateMapKey &
LHS,
const StateMapKey &
RHS) {
901 return StateT::isEqual((*
LHS.States)[
LHS.Idx], (*
RHS.States)[
RHS.Idx]);
903 static bool isEqual(
const StateT &
LHS,
const StateMapKey &
RHS) {
904 return StateT::isEqual(
LHS, (*
RHS.States)[
RHS.Idx]);
913 StateT State = InitialState;
916 unsigned WorkIdx = 0;
918 bool Expired =
false;
919 for (
auto E =
MBB->instr_rend();
I !=
E; ++
I) {
924 auto Result = IsHazard(State, *
I);
932 if (
I->isInlineAsm() ||
I->isMetaInstruction())
935 UpdateState(State, *
I);
939 size_t StateIdx = States.
size();
940 StateMapKey
Key = {&States, StateIdx};
941 auto Insertion = StateMap.
insert_as(std::pair(
Key, StateIdx), State);
942 if (Insertion.second) {
945 StateIdx = Insertion.first->second;
948 Worklist.
insert(std::pair(Pred, StateIdx));
951 if (WorkIdx == Worklist.
size())
955 std::tie(
MBB, StateIdx) = Worklist[WorkIdx++];
956 State = States[StateIdx];
957 I =
MBB->instr_rbegin();
969 *Pred.getParent()->getSubtarget<
GCNSubtarget>().getInstrInfo();
970 unsigned Unexecuted = 0, Passed = 0;
971 for (
auto I = Pred.instr_rbegin(),
E = Pred.instr_rend();
972 I !=
E &&
I->isTerminator(); ++
I, ++Passed) {
975 if (
I->isBranch() &&
I->getNumOperands() > 0 &&
I->getOperand(0).isMBB() &&
976 TII.getBranchDestBlock(*
I) ==
MBB)
987 return MI.isInlineAsm() ? 0 : GetNumWaitStates(
MI);
996class WindowDeficitSearch {
999 function_ref<std::optional<int>(
const MachineInstr &)> WindowFor,
1003 : WindowFor(WindowFor), GetNumWaitStates(GetNumWaitStates),
1004 MaxWindow(MaxWindow) {}
1006 int run(
const MachineInstr &
MI);
1013 const MachineBasicBlock *
MBB;
1018 void arrive(
const MachineBasicBlock *
MBB,
1021 void scan(Arrival
A);
1023 const function_ref<std::optional<int>(
const MachineInstr &)> WindowFor;
1025 const int MaxWindow;
1032 DenseMap<const MachineBasicBlock *, int> Best;
1037void WindowDeficitSearch::arrive(
1042 if (MaxWindow - Distance <= Deficit)
1045 if (Pending.empty())
1046 Pending.resize(MaxWindow);
1048 auto [It,
Inserted] = Best.try_emplace(
MBB, Distance);
1050 if (It->second <= Distance)
1052 It->second = Distance;
1055 assert(Distance < MaxWindow &&
"arrival outside the window");
1056 Pending[Distance].push_back({
MBB,
Start, Distance});
1061void WindowDeficitSearch::scan(Arrival
A) {
1063 if (Best.lookup(
A.MBB) <
A.Distance)
1066 int Distance =
A.Distance;
1067 for (
auto I =
A.Start,
E =
A.MBB->instr_rend();
I !=
E; ++
I) {
1071 if (std::optional<int> Window = WindowFor(*
I)) {
1072 assert(*Window >= 0 && *Window <= MaxWindow &&
"window out of bounds");
1073 Deficit = std::max(Deficit, *Window - Distance);
1078 if (Distance >= MaxWindow)
1083 auto Start = Pred->instr_rbegin(),
End = Pred->instr_rend();
1089 assert(!WindowFor(*Start) &&
"terminators must not ask for a window");
1093 arrive(Pred, Start, Distance + Executed);
1100 scan({
MI.getParent(), std::next(
MI.getReverseIterator()), 0});
1106 for (
int Distance = 0; Distance < static_cast<int>(Pending.size());
1108 for (
unsigned I = 0;
I != Pending[Distance].size(); ++
I)
1109 scan(Pending[Distance][
I]);
1125 for (
auto E =
MBB->instr_rend();
I !=
E; ++
I) {
1130 if (
I->isMetaInstruction())
1136 if (
I->isInlineAsm())
1139 WaitStates += GetNumWaitStates(*
I);
1141 if (IsExpired(*
I, WaitStates))
1142 return std::numeric_limits<int>::max();
1145 int MinWaitStates = std::numeric_limits<int>::max();
1147 if (!Visited.
insert(Pred).second)
1151 IsExpired, Visited, GetNumWaitStates);
1153 MinWaitStates = std::min(MinWaitStates, W);
1156 return MinWaitStates;
1167 std::next(
MI->getReverseIterator()), 0, IsExpired,
1168 Visited, GetNumWaitStates);
1171int GCNHazardRecognizer::getMaxWindowDeficit(
int MaxWindow,
1172 WindowForFn WindowFor)
const {
1174 return WindowDeficitSearch(WindowFor, MaxWindow).run(*CurrCycleInstr);
1178 int Deficit = 0, Distance = 0;
1179 for (MachineInstr *
MI : EmittedInstrs) {
1181 if (std::optional<int> Window = WindowFor(*
MI)) {
1182 assert(*Window >= 0 && *Window <= MaxWindow &&
"window out of bounds");
1183 Deficit = std::max(Deficit, *Window - Distance);
1190 if (Distance >= MaxWindow)
1196int GCNHazardRecognizer::getWaitStatesSince(
1197 IsHazardFn IsHazard,
int Limit, GetNumWaitStatesFn GetNumWaitStates)
const {
1199 auto IsExpiredFn = [Limit](
const MachineInstr &,
int WaitStates) {
1200 return WaitStates >= Limit;
1202 return ::getWaitStatesSince(IsHazard, CurrCycleInstr,
IsExpiredFn,
1207 for (MachineInstr *
MI : EmittedInstrs) {
1212 if (
MI->isInlineAsm())
1215 WaitStates +=
MI ? GetNumWaitStates(*
MI) : 1;
1217 if (WaitStates >= Limit)
1220 return std::numeric_limits<int>::max();
1223int GCNHazardRecognizer::getWaitStatesSince(IsHazardFn IsHazard,
1228int GCNHazardRecognizer::getMaxVALUWindowDeficit(
int MaxWindow,
1229 WindowForFn WindowFor)
const {
1231 auto GetVALUWaitStates = [](
const MachineInstr &
MI) ->
unsigned {
1234 return WindowDeficitSearch(WindowFor, MaxWindow, GetVALUWaitStates)
1235 .run(*CurrCycleInstr);
1241 assert(MaxWindow <=
static_cast<int>(MaxVALULookAhead) &&
1242 "MaxWindow exceeds the EmittedVALUInstrs lookahead window");
1244 for (MachineInstr *
MI : EmittedVALUInstrs) {
1246 if (std::optional<int> Window = WindowFor(*
MI)) {
1247 assert(*Window >= 0 && *Window <= MaxWindow &&
"window out of bounds");
1248 return *Window - WaitStates;
1254 if (WaitStates >= MaxWindow)
1260int GCNHazardRecognizer::getWaitStatesSinceDef(
unsigned Reg,
1261 IsHazardFn IsHazardDef,
1263 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1266 return IsHazardDef(
MI) &&
MI.modifiesRegister(
Reg, TRI);
1269 return getWaitStatesSince(
IsHazardFn, Limit);
1272int GCNHazardRecognizer::getWaitStatesSinceSetReg(IsHazardFn IsHazard,
1278 return getWaitStatesSince(
IsHazardFn, Limit);
1287 for (MCRegUnit Unit :
TRI.regunits(
Reg))
1288 BV.
set(
static_cast<unsigned>(Unit));
1300void GCNHazardRecognizer::addClauseInst(
const MachineInstr &
MI)
const {
1312int GCNHazardRecognizer::checkSoftClauseHazards(
MachineInstr *MEM)
const {
1315 if (!ST.isXNACKEnabled())
1318 bool IsSMRD = TII.isSMRD(*MEM);
1332 for (MachineInstr *
MI : EmittedInstrs) {
1344 if (ClauseDefs.none())
1350 if (
MEM->mayStore())
1353 addClauseInst(*MEM);
1357 return ClauseDefs.anyCommon(ClauseUses) ? 1 : 0;
1360int GCNHazardRecognizer::checkSMRDHazards(
MachineInstr *SMRD)
const {
1361 int WaitStatesNeeded = 0;
1363 WaitStatesNeeded = checkSoftClauseHazards(SMRD);
1366 if (!ST.hasSMRDReadVALUDefHazard())
1367 return WaitStatesNeeded;
1371 int SmrdSgprWaitStates = 4;
1372 auto IsHazardDefFn = [
this](
const MachineInstr &
MI) {
1373 return TII.isVALU(
MI,
true);
1375 auto IsBufferHazardDefFn = [
this](
const MachineInstr &
MI) {
1376 return TII.isSALU(
MI);
1379 bool IsBufferSMRD = TII.isBufferSMRD(*SMRD);
1381 for (
const MachineOperand &Use :
SMRD->uses()) {
1384 int WaitStatesNeededForUse =
1385 SmrdSgprWaitStates - getWaitStatesSinceDef(
Use.getReg(), IsHazardDefFn,
1386 SmrdSgprWaitStates);
1387 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1397 int WaitStatesNeededForUse =
1398 SmrdSgprWaitStates - getWaitStatesSinceDef(
Use.getReg(),
1399 IsBufferHazardDefFn,
1400 SmrdSgprWaitStates);
1401 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1405 return WaitStatesNeeded;
1408int GCNHazardRecognizer::checkVMEMHazards(
MachineInstr *VMEM)
const {
1409 if (!ST.hasVMEMReadSGPRVALUDefHazard())
1412 int WaitStatesNeeded = checkSoftClauseHazards(VMEM);
1416 const int VmemSgprWaitStates = 5;
1417 auto IsHazardDefFn = [
this](
const MachineInstr &
MI) {
1418 return TII.isVALU(
MI,
true);
1420 for (
const MachineOperand &Use :
VMEM->uses()) {
1421 if (!
Use.isReg() || TRI.isVectorRegister(MF.getRegInfo(),
Use.getReg()))
1424 int WaitStatesNeededForUse =
1425 VmemSgprWaitStates - getWaitStatesSinceDef(
Use.getReg(), IsHazardDefFn,
1426 VmemSgprWaitStates);
1427 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1429 return WaitStatesNeeded;
1433 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1434 const SIInstrInfo *TII = ST.getInstrInfo();
1437 int DppVgprWaitStates = 2;
1438 int DppExecWaitStates = 5;
1439 int WaitStatesNeeded = 0;
1440 auto IsHazardDefFn = [TII](
const MachineInstr &
MI) {
1441 return TII->isVALU(
MI,
true);
1444 for (
const MachineOperand &Use :
DPP->uses()) {
1445 if (!
Use.isReg() || !TRI->isVGPR(MF.getRegInfo(),
Use.getReg()))
1447 int WaitStatesNeededForUse =
1448 DppVgprWaitStates - getWaitStatesSinceDef(
1450 [](
const MachineInstr &) { return true; },
1452 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1455 WaitStatesNeeded = std::max(
1457 DppExecWaitStates - getWaitStatesSinceDef(AMDGPU::EXEC, IsHazardDefFn,
1458 DppExecWaitStates));
1460 return WaitStatesNeeded;
1463int GCNHazardRecognizer::checkDivFMasHazards(
MachineInstr *DivFMas)
const {
1464 const SIInstrInfo *TII = ST.getInstrInfo();
1468 const int DivFMasWaitStates = 4;
1469 auto IsHazardDefFn = [TII](
const MachineInstr &
MI) {
1470 return TII->isVALU(
MI,
true);
1472 int WaitStatesNeeded = getWaitStatesSinceDef(AMDGPU::VCC, IsHazardDefFn,
1475 return DivFMasWaitStates - WaitStatesNeeded;
1478int GCNHazardRecognizer::checkGetRegHazards(
MachineInstr *GetRegInstr)
const {
1479 const SIInstrInfo *TII = ST.getInstrInfo();
1480 unsigned GetRegHWReg =
getHWReg(TII, *GetRegInstr);
1482 const int GetRegWaitStates = 2;
1483 auto IsHazardFn = [TII, GetRegHWReg](
const MachineInstr &
MI) {
1486 int WaitStatesNeeded = getWaitStatesSinceSetReg(
IsHazardFn, GetRegWaitStates);
1488 return GetRegWaitStates - WaitStatesNeeded;
1491int GCNHazardRecognizer::checkSetRegHazards(
MachineInstr *SetRegInstr)
const {
1492 const SIInstrInfo *TII = ST.getInstrInfo();
1493 unsigned HWReg =
getHWReg(TII, *SetRegInstr);
1495 const int SetRegWaitStates = ST.getSetRegWaitStates();
1496 auto IsHazardFn = [TII, HWReg](
const MachineInstr &
MI) {
1499 int WaitStatesNeeded = getWaitStatesSinceSetReg(
IsHazardFn, SetRegWaitStates);
1500 return SetRegWaitStates - WaitStatesNeeded;
1503int GCNHazardRecognizer::createsVALUHazard(
const MachineInstr &
MI)
const {
1507 const SIInstrInfo *TII = ST.getInstrInfo();
1508 unsigned Opcode =
MI.getOpcode();
1509 const MCInstrDesc &
Desc =
MI.getDesc();
1511 int VDataIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::vdata);
1514 VDataRCID = TII->getOpRegClassID(
Desc.operands()[VDataIdx]);
1516 if (TII->isMUBUF(
MI) || TII->isMTBUF(
MI)) {
1526 if (ST.hasVDecCoExecHazard())
1528 const MachineOperand *SOffset =
1529 TII->getNamedOperand(
MI, AMDGPU::OpName::soffset);
1530 if (!SOffset || !SOffset->
isReg())
1539 if (TII->isMIMG(
MI)) {
1540 int SRsrcIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::srsrc);
1542 Desc.operands()[SRsrcIdx])) == 256);
1546 if (TII->isFLAT(
MI)) {
1558int GCNHazardRecognizer::checkUniformWindowVALUHazardsHelper(
1563 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1565 auto IsHazard = [&](
const MachineInstr &
MI) {
1566 int DataIdx = createsVALUHazard(
MI);
1567 return DataIdx >= 0 &&
1568 TRI->regsOverlap(
MI.getOperand(DataIdx).getReg(),
Reg);
1571 return std::max(0, 1 - getWaitStatesSince(IsHazard, 1));
1574int GCNHazardRecognizer::checkSOFFSETWindowVALUHazardsHelper(
1581 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1582 const SIInstrInfo *TII = ST.getInstrInfo();
1584 int WaitStatesNeeded = 0;
1588 for (
int Window = 1; Window <= 2; ++Window) {
1589 auto IsHazard = [&](
const MachineInstr &
MI) {
1590 int DataIdx = createsVALUHazard(
MI);
1592 !TRI->regsOverlap(
MI.getOperand(DataIdx).getReg(),
Reg))
1597 if (Window == 1 || !TII->isBUF(
MI))
1600 const MachineOperand *SOffset =
1601 TII->getNamedOperand(
MI, AMDGPU::OpName::soffset);
1602 return !SOffset || !SOffset->
isReg();
1604 WaitStatesNeeded = std::max(WaitStatesNeeded,
1605 Window - getWaitStatesSince(IsHazard, Window));
1608 return WaitStatesNeeded;
1611int GCNHazardRecognizer::checkVALUHazardsHelper(
1616 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1618 if (!TRI->isVectorRegister(
MRI,
Def.getReg()))
1621 if (ST.hasVDecCoExecHazard())
1622 return checkSOFFSETWindowVALUHazardsHelper(
Def.getReg());
1624 return checkUniformWindowVALUHazardsHelper(
Def.getReg());
1640 unsigned Opcode =
MI.getOpcode();
1650 if (
auto *DstSel =
TII->getNamedOperand(
MI, AMDGPU::OpName::dst_sel))
1652 return TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
1660 (
TII->getNamedImmOperand(
MI, AMDGPU::OpName::src0_modifiers) &
1662 return TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
1670 return TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
1674 (
TII->getNamedImmOperand(
MI, AMDGPU::OpName::src2_modifiers) &
1676 return TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
1682 return TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
1703 for (
auto &Operand : VALU->operands()) {
1704 if (Operand.isReg() &&
TRI->regsOverlap(Dst->getReg(), Operand.getReg())) {
1711int GCNHazardRecognizer::checkVALUHazards(
MachineInstr *VALU)
const {
1712 int WaitStatesNeeded = 0;
1715 const int TransDefWaitstates = 1;
1717 auto IsTransDefFn = [
this,
VALU](
const MachineInstr &
MI) {
1720 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1721 const SIInstrInfo *TII = ST.getInstrInfo();
1722 Register Def = TII->getNamedOperand(
MI, AMDGPU::OpName::vdst)->getReg();
1724 for (
const MachineOperand &Use :
VALU->explicit_uses()) {
1725 if (
Use.isReg() && TRI->regsOverlap(Def,
Use.getReg()))
1732 int WaitStatesNeededForDef =
1733 TransDefWaitstates -
1734 getWaitStatesSince(IsTransDefFn, TransDefWaitstates);
1735 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1738 if (ST.hasDstSelForwardingHazard() || ST.hasCvtScaleForwardingHazard()) {
1739 const int Shift16DefWaitstates = 1;
1741 auto IsShift16BitDefFn = [
this,
VALU](
const MachineInstr &ProducerMI) {
1742 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1743 const MachineOperand *ForwardedDst =
1749 if (ProducerMI.isInlineAsm()) {
1751 for (
auto &Def : ProducerMI.all_defs()) {
1760 int WaitStatesNeededForDef =
1761 Shift16DefWaitstates -
1762 getWaitStatesSince(IsShift16BitDefFn, Shift16DefWaitstates);
1763 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1766 if (ST.hasVDecCoExecHazard()) {
1767 const int VALUWriteSGPRVALUReadWaitstates = 2;
1768 const int VALUWriteEXECRWLane = 4;
1769 const int VALUWriteVGPRReadlaneRead = 1;
1771 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1772 const MachineRegisterInfo &
MRI = MF.getRegInfo();
1774 auto IsVALUDefSGPRFn = [&
UseReg, TRI](
const MachineInstr &
MI) {
1777 return MI.modifiesRegister(
UseReg, TRI);
1780 for (
const MachineOperand &Use :
VALU->explicit_uses()) {
1786 int WaitStatesNeededForDef =
1787 VALUWriteSGPRVALUReadWaitstates -
1788 getWaitStatesSince(IsVALUDefSGPRFn,
1789 VALUWriteSGPRVALUReadWaitstates);
1790 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1794 if (
VALU->readsRegister(AMDGPU::VCC, TRI)) {
1796 int WaitStatesNeededForDef =
1797 VALUWriteSGPRVALUReadWaitstates -
1798 getWaitStatesSince(IsVALUDefSGPRFn, VALUWriteSGPRVALUReadWaitstates);
1799 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1802 switch (
VALU->getOpcode()) {
1803 case AMDGPU::V_READLANE_B32:
1804 case AMDGPU::V_READFIRSTLANE_B32: {
1805 MachineOperand *Src = TII.getNamedOperand(*VALU, AMDGPU::OpName::src0);
1807 int WaitStatesNeededForDef =
1808 VALUWriteVGPRReadlaneRead -
1809 getWaitStatesSince(IsVALUDefSGPRFn, VALUWriteVGPRReadlaneRead);
1810 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1813 case AMDGPU::V_WRITELANE_B32: {
1815 int WaitStatesNeededForDef =
1816 VALUWriteEXECRWLane -
1817 getWaitStatesSince(IsVALUDefSGPRFn, VALUWriteEXECRWLane);
1818 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1828 if (!ST.has12DWordStoreHazard())
1829 return WaitStatesNeeded;
1831 const MachineRegisterInfo &
MRI = MF.getRegInfo();
1833 for (
const MachineOperand &Def :
VALU->defs()) {
1834 WaitStatesNeeded = std::max(WaitStatesNeeded, checkVALUHazardsHelper(Def,
MRI));
1837 return WaitStatesNeeded;
1840int GCNHazardRecognizer::checkInlineAsmHazards(
MachineInstr *IA)
const {
1849 if (!ST.has12DWordStoreHazard() && !ST.hasDstSelForwardingHazard() &&
1850 !ST.hasCvtScaleForwardingHazard())
1853 const MachineRegisterInfo &
MRI = MF.getRegInfo();
1854 int WaitStatesNeeded = 0;
1856 for (
const MachineOperand &
Op :
1858 if (
Op.isReg() &&
Op.isDef()) {
1859 if (!TRI.isVectorRegister(
MRI,
Op.getReg()))
1862 if (ST.has12DWordStoreHazard()) {
1864 std::max(WaitStatesNeeded, checkVALUHazardsHelper(
Op,
MRI));
1869 if (ST.hasDstSelForwardingHazard()) {
1870 const int Shift16DefWaitstates = 1;
1872 auto IsShift16BitDefFn = [
this, &
IA](
const MachineInstr &ProducerMI) {
1876 return IA->modifiesRegister(Dst->getReg(), &TRI) ||
1877 IA->readsRegister(Dst->getReg(), &TRI);
1879 if (ProducerMI.isInlineAsm()) {
1881 for (
auto &Def : ProducerMI.all_defs()) {
1882 if (
IA->modifiesRegister(
Def.getReg(), &TRI) ||
1883 IA->readsRegister(
Def.getReg(), &TRI)) {
1892 int WaitStatesNeededForDef =
1893 Shift16DefWaitstates -
1894 getWaitStatesSince(IsShift16BitDefFn, Shift16DefWaitstates);
1895 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1898 return WaitStatesNeeded;
1901int GCNHazardRecognizer::checkRWLaneHazards(
MachineInstr *RWLane)
const {
1902 const SIInstrInfo *TII = ST.getInstrInfo();
1903 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1904 const MachineRegisterInfo &
MRI = MF.getRegInfo();
1906 const MachineOperand *LaneSelectOp =
1907 TII->getNamedOperand(*RWLane, AMDGPU::OpName::src1);
1909 if (!LaneSelectOp->
isReg() || !TRI->isSGPRReg(
MRI, LaneSelectOp->
getReg()))
1914 return TII->isVALU(
MI,
true);
1917 const int RWLaneWaitStates = 4;
1918 int WaitStatesSince = getWaitStatesSinceDef(LaneSelectReg,
IsHazardFn,
1920 return RWLaneWaitStates - WaitStatesSince;
1923int GCNHazardRecognizer::checkRFEHazards(
MachineInstr *RFE)
const {
1924 if (!ST.hasRFEHazards())
1927 const SIInstrInfo *TII = ST.getInstrInfo();
1929 const int RFEWaitStates = 1;
1934 int WaitStatesNeeded = getWaitStatesSinceSetReg(
IsHazardFn, RFEWaitStates);
1935 return RFEWaitStates - WaitStatesNeeded;
1938int GCNHazardRecognizer::checkReadM0Hazards(
MachineInstr *
MI)
const {
1939 const SIInstrInfo *TII = ST.getInstrInfo();
1940 const int ReadM0WaitStates = 1;
1941 auto IsHazardFn = [TII](
const MachineInstr &
MI) {
return TII->isSALU(
MI); };
1942 return ReadM0WaitStates -
1943 getWaitStatesSinceDef(AMDGPU::M0,
IsHazardFn, ReadM0WaitStates);
1948 int WaitStatesNeeded,
bool IsHoisting) {
1950 for (
int I = 0;
I < WaitStatesNeeded; ++
I)
1951 BuildMI(
MBB, InsertPt,
DL, TII.get(AMDGPU::V_NOP_e32));
1955 fixVMEMtoScalarWriteHazards(
MI);
1956 fixVcmpxPermlaneHazards(
MI);
1957 fixSMEMtoVectorWriteHazards(
MI);
1958 fixVcmpxExecWARHazard(
MI);
1959 fixLdsBranchVmemWARHazard(
MI);
1960 if (ST.hasLdsDirect()) {
1961 fixLdsDirectVALUHazard(
MI);
1962 fixLdsDirectVMEMHazard(
MI);
1964 fixVALUPartialForwardingHazard(
MI);
1965 fixVALUTransUseHazard(
MI);
1966 fixVALUTransCoexecutionHazards(
MI);
1968 fixWMMACoexecutionHazards(
MI);
1969 fixShift64HighRegBug(
MI);
1970 fixVALUMaskWriteHazard(
MI);
1971 fixRequiredExportPriority(
MI);
1972 if (ST.hasVPermPk16Hazard())
1973 fixVPermPk16Hazard(
MI);
1974 if (ST.requiresWaitIdleBeforeGetReg())
1975 fixGetRegWaitIdle(
MI);
1976 if (ST.hasDsAtomicAsyncBarrierArriveB64PipeBug())
1977 fixDsAtomicAsyncBarrierArriveB64(
MI);
1978 if (ST.hasScratchBaseForwardingHazard())
1979 fixScratchBaseForwardingHazard(
MI);
1980 if (ST.setRegModeNeedsVNOPs())
1982 if (ST.hasNeedsTDMDrain())
1988 return (
TII.isVOPC(
MI) ||
1989 (
MI.isCompare() && (
TII.isVOP3(
MI) ||
TII.isSDWA(
MI)))) &&
1990 MI.modifiesRegister(AMDGPU::EXEC, &
TRI);
1993bool GCNHazardRecognizer::fixVcmpxPermlaneHazards(
MachineInstr *
MI) {
1997 const SIInstrInfo *TII = ST.getInstrInfo();
1998 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2004 unsigned Opc =
MI.getOpcode();
2006 Opc != AMDGPU::V_NOP_e32 &&
Opc != AMDGPU::V_NOP_e64 &&
2007 Opc != AMDGPU::V_NOP_sdwa;
2011 std::numeric_limits<int>::max())
2017 auto *
Src0 = TII->getNamedOperand(*
MI, AMDGPU::OpName::src0);
2019 bool IsUndef =
Src0->isUndef();
2021 TII->get(AMDGPU::V_MOV_B32_e32))
2028bool GCNHazardRecognizer::fixVMEMtoScalarWriteHazards(
MachineInstr *
MI) {
2029 if (!ST.hasVMEMtoScalarWriteHazard())
2031 assert(!ST.hasExtendedWaitCounts());
2036 if (
MI->getNumDefs() == 0)
2039 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2045 for (
const MachineOperand &Def :
MI->defs()) {
2046 const MachineOperand *
Op =
2047 I.findRegisterUseOperand(
Def.getReg(), TRI,
false);
2057 (
MI.getOpcode() == AMDGPU::S_WAITCNT &&
2058 !
MI.getOperand(0).getImm()) ||
2059 (
MI.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2061 static_cast<unsigned>(
MI.getOperand(0).getImm())) == 0);
2065 std::numeric_limits<int>::max())
2068 const SIInstrInfo *TII = ST.getInstrInfo();
2070 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
2075bool GCNHazardRecognizer::fixSMEMtoVectorWriteHazards(
MachineInstr *
MI) {
2076 if (!ST.hasSMEMtoVectorWriteHazard())
2078 assert(!ST.hasExtendedWaitCounts());
2083 AMDGPU::OpName SDSTName;
2084 switch (
MI->getOpcode()) {
2085 case AMDGPU::V_READLANE_B32:
2086 case AMDGPU::V_READFIRSTLANE_B32:
2087 SDSTName = AMDGPU::OpName::vdst;
2090 SDSTName = AMDGPU::OpName::sdst;
2094 const SIInstrInfo *TII = ST.getInstrInfo();
2095 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2097 const MachineOperand *SDST = TII->getNamedOperand(*
MI, SDSTName);
2099 for (
const auto &MO :
MI->implicit_operands()) {
2100 if (MO.isDef() && TRI->isSGPRClass(TRI->getPhysRegBaseClass(MO.getReg()))) {
2111 auto IsHazardFn = [SDSTReg, TRI](
const MachineInstr &
I) {
2116 if (TII->isSALU(
MI)) {
2117 switch (
MI.getOpcode()) {
2118 case AMDGPU::S_SETVSKIP:
2119 case AMDGPU::S_VERSION:
2120 case AMDGPU::S_WAITCNT_VSCNT:
2121 case AMDGPU::S_WAITCNT_VMCNT:
2122 case AMDGPU::S_WAITCNT_EXPCNT:
2125 case AMDGPU::S_WAITCNT_LGKMCNT:
2127 return (
MI.getOperand(1).getImm() == 0) &&
2128 (
MI.getOperand(0).
getReg() == AMDGPU::SGPR_NULL);
2129 case AMDGPU::S_WAITCNT: {
2130 const int64_t
Imm =
MI.getOperand(0).getImm();
2131 AMDGPU::Waitcnt Decoded =
2138 MI.getOpcode() == AMDGPU::S_WAIT_IDLE) &&
2139 "unexpected wait count instruction");
2141 if (TII->isSOPP(
MI))
2157 std::numeric_limits<int>::max())
2161 TII->get(AMDGPU::S_MOV_B32), AMDGPU::SGPR_NULL)
2166bool GCNHazardRecognizer::fixVcmpxExecWARHazard(
MachineInstr *
MI) {
2167 if (!ST.hasVcmpxExecWARHazard())
2169 assert(!ST.hasExtendedWaitCounts());
2174 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2175 if (!
MI->modifiesRegister(AMDGPU::EXEC, TRI))
2181 return I.readsRegister(AMDGPU::EXEC, TRI);
2184 const SIInstrInfo *TII = ST.getInstrInfo();
2185 auto IsExpiredFn = [TII, TRI](
const MachineInstr &
MI, int) {
2187 if (TII->getNamedOperand(
MI, AMDGPU::OpName::sdst))
2189 for (
auto MO :
MI.implicit_operands())
2190 if (MO.isDef() && TRI->isSGPRClass(TRI->getPhysRegBaseClass(MO.getReg())))
2193 if (
MI.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2195 static_cast<unsigned>(
MI.getOperand(0).getImm())) == 0)
2201 std::numeric_limits<int>::max())
2205 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
2212 if (!ST.hasLdsBranchVmemWARHazard())
2217 bool HasLds =
false;
2218 bool HasVmem =
false;
2219 for (
auto &
MBB : MF) {
2220 for (
auto &
MI :
MBB) {
2223 if (HasLds && HasVmem)
2231 return I.getOpcode() == AMDGPU::S_WAITCNT_VSCNT &&
2232 I.getOperand(0).getReg() == AMDGPU::SGPR_NULL &&
2233 !
I.getOperand(1).getImm();
2236bool GCNHazardRecognizer::fixLdsBranchVmemWARHazard(
MachineInstr *
MI) {
2237 if (!RunLdsBranchVmemWARHazardFixup)
2240 assert(ST.hasLdsBranchVmemWARHazard());
2241 assert(!ST.hasExtendedWaitCounts());
2243 auto IsHazardInst = [](
const MachineInstr &
MI) {
2251 auto InstType = IsHazardInst(*
MI);
2255 auto IsExpiredFn = [&IsHazardInst](
const MachineInstr &
I, int) {
2259 auto IsHazardFn = [InstType, &IsHazardInst](
const MachineInstr &
I) {
2263 auto IsHazardFn = [InstType, IsHazardInst](
const MachineInstr &
I) {
2264 auto InstType2 = IsHazardInst(
I);
2265 return InstType2 && InstType != InstType2;
2268 auto IsExpiredFn = [InstType, &IsHazardInst](
const MachineInstr &
I, int) {
2269 auto InstType2 = IsHazardInst(
I);
2270 if (InstType == InstType2)
2277 std::numeric_limits<int>::max();
2281 std::numeric_limits<int>::max())
2284 const SIInstrInfo *TII = ST.getInstrInfo();
2286 TII->get(AMDGPU::S_WAITCNT_VSCNT))
2293bool GCNHazardRecognizer::fixLdsDirectVALUHazard(
MachineInstr *
MI) {
2297 const int NoHazardWaitStates = 15;
2298 const MachineOperand *VDST = TII.getNamedOperand(*
MI, AMDGPU::OpName::vdst);
2301 bool VisitedTrans =
false;
2302 auto IsHazardFn = [
this, VDSTReg, &VisitedTrans](
const MachineInstr &
I) {
2307 return I.readsRegister(VDSTReg, &TRI) ||
I.modifiesRegister(VDSTReg, &TRI);
2309 auto IsExpiredFn = [&](
const MachineInstr &
I,
int WaitStates) {
2310 if (WaitStates >= NoHazardWaitStates)
2316 auto GetWaitStatesFn = [](
const MachineInstr &
MI) {
2320 DenseSet<const MachineBasicBlock *> Visited;
2322 std::next(
MI->getReverseIterator()), 0,
2330 MachineOperand *WaitVdstOp =
2331 TII.getNamedOperand(*
MI, AMDGPU::OpName::waitvdst);
2332 WaitVdstOp->
setImm(std::min(
Count, NoHazardWaitStates));
2337bool GCNHazardRecognizer::fixLdsDirectVMEMHazard(
MachineInstr *
MI) {
2341 const MachineOperand *VDST = TII.getNamedOperand(*
MI, AMDGPU::OpName::vdst);
2344 auto IsHazardFn = [
this, VDSTReg](
const MachineInstr &
I) {
2347 return I.readsRegister(VDSTReg, &TRI) ||
I.modifiesRegister(VDSTReg, &TRI);
2349 bool LdsdirCanWait = ST.hasLdsWaitVMSRC();
2352 auto IsExpiredFn = [
this, LdsdirCanWait](
const MachineInstr &
I, int) {
2355 (
I.getOpcode() == AMDGPU::S_WAITCNT && !
I.getOperand(0).getImm()) ||
2356 (
I.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2358 static_cast<unsigned>(
I.getOperand(0).getImm())) == 0) ||
2360 !TII.getNamedOperand(
I, AMDGPU::OpName::waitvsrc)->getImm());
2364 std::numeric_limits<int>::max())
2367 if (LdsdirCanWait) {
2368 TII.getNamedOperand(*
MI, AMDGPU::OpName::waitvsrc)->setImm(0);
2371 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
2378bool GCNHazardRecognizer::fixVALUPartialForwardingHazard(
MachineInstr *
MI) {
2379 if (!ST.hasVALUPartialForwardingHazard())
2381 assert(!ST.hasExtendedWaitCounts());
2386 SmallSetVector<Register, 4> SrcVGPRs;
2388 for (
const MachineOperand &Use :
MI->explicit_uses()) {
2389 if (
Use.isReg() && TRI.isVGPR(MF.getRegInfo(),
Use.getReg()))
2394 if (SrcVGPRs.
size() <= 1)
2412 const int Intv1plus2MaxVALUs = 2;
2413 const int Intv3MaxVALUs = 4;
2414 const int IntvMaxVALUs = 6;
2415 const int NoHazardVALUWaitStates = IntvMaxVALUs + 2;
2418 SmallDenseMap<Register, int, 4> DefPos;
2419 int ExecPos = std::numeric_limits<int>::max();
2422 static unsigned getHashValue(
const StateType &State) {
2424 for (
const auto &[
Reg, Pos] : State.DefPos)
2426 return static_cast<unsigned>(
H);
2428 static bool isEqual(
const StateType &
LHS,
const StateType &
RHS) {
2429 return LHS.DefPos ==
RHS.DefPos &&
LHS.ExecPos ==
RHS.ExecPos &&
2437 auto IsHazardFn = [&,
this](StateType &State,
const MachineInstr &
I) {
2439 if (State.VALUs > NoHazardVALUWaitStates)
2445 (
I.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2447 static_cast<unsigned>(
I.getOperand(0).getImm())) == 0))
2454 if (!State.DefPos.count(Src) &&
I.modifiesRegister(Src, &TRI)) {
2455 State.DefPos[Src] = State.VALUs;
2460 if (State.ExecPos == std::numeric_limits<int>::max()) {
2461 if (!State.DefPos.empty() &&
I.modifiesRegister(AMDGPU::EXEC, &TRI)) {
2462 State.ExecPos = State.VALUs;
2469 if (State.VALUs > Intv3MaxVALUs && State.DefPos.empty())
2477 if (State.ExecPos == std::numeric_limits<int>::max())
2480 int PreExecPos = std::numeric_limits<int>::max();
2481 int PostExecPos = std::numeric_limits<int>::max();
2483 for (
auto Entry : State.DefPos) {
2484 int DefVALUs =
Entry.second;
2485 if (DefVALUs != std::numeric_limits<int>::max()) {
2486 if (DefVALUs >= State.ExecPos)
2487 PreExecPos = std::min(PreExecPos, DefVALUs);
2489 PostExecPos = std::min(PostExecPos, DefVALUs);
2494 if (PostExecPos == std::numeric_limits<int>::max())
2498 int Intv3VALUs = PostExecPos;
2499 if (Intv3VALUs > Intv3MaxVALUs)
2503 int Intv2VALUs = (State.ExecPos - PostExecPos) - 1;
2504 if (Intv2VALUs > Intv1plus2MaxVALUs)
2508 if (PreExecPos == std::numeric_limits<int>::max())
2512 int Intv1VALUs = PreExecPos - State.ExecPos;
2513 if (Intv1VALUs > Intv1plus2MaxVALUs)
2517 if (Intv1VALUs + Intv2VALUs > Intv1plus2MaxVALUs)
2522 auto UpdateStateFn = [](StateType &State,
const MachineInstr &
MI) {
2528 std::next(
MI->getReverseIterator())))
2532 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
2538bool GCNHazardRecognizer::fixVALUTransUseHazard(
MachineInstr *
MI) {
2539 if (!ST.hasVALUTransUseHazard())
2541 assert(!ST.hasExtendedWaitCounts());
2546 SmallSet<Register, 4> SrcVGPRs;
2548 for (
const MachineOperand &Use :
MI->explicit_uses()) {
2549 if (
Use.isReg() && TRI.isVGPR(MF.getRegInfo(),
Use.getReg()))
2563 const int IntvMaxVALUs = 5;
2564 const int IntvMaxTRANS = 1;
2570 static unsigned getHashValue(
const StateType &State) {
2571 return static_cast<unsigned>(
hash_combine(State.VALUs, State.TRANS));
2573 static bool isEqual(
const StateType &
LHS,
const StateType &
RHS) {
2574 return LHS.VALUs ==
RHS.VALUs &&
LHS.TRANS ==
RHS.TRANS;
2581 auto IsHazardFn = [&,
this](StateType &State,
const MachineInstr &
I) {
2583 if (State.VALUs > IntvMaxVALUs || State.TRANS > IntvMaxTRANS)
2589 (
I.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2591 static_cast<unsigned>(
I.getOperand(0).getImm())) == 0))
2597 if (
I.modifiesRegister(Src, &TRI)) {
2605 auto UpdateStateFn = [](StateType &State,
const MachineInstr &
MI) {
2613 std::next(
MI->getReverseIterator())))
2619 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
2625bool GCNHazardRecognizer::fixVALUTransCoexecutionHazards(
MachineInstr *
MI) {
2626 if (!ST.hasTransCoexecutionHazard() ||
2631 const SIInstrInfo *TII = ST.getInstrInfo();
2632 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2634 auto IsTransHazardFn = [
MI, TII, TRI](
const MachineInstr &
I) {
2639 Register TransDef = TII->getNamedOperand(
I, AMDGPU::OpName::vdst)->getReg();
2640 for (
const MachineOperand &ValuUse :
MI->explicit_uses()) {
2641 if (ValuUse.isReg() && TRI->regsOverlap(TransDef, ValuUse.getReg()))
2647 for (
const MachineOperand &TransUse :
I.explicit_uses()) {
2648 if (TransUse.isReg() &&
MI->modifiesRegister(TransUse.getReg(), TRI))
2659 const int HasVALU = std::numeric_limits<int>::max();
2660 if (::getWaitStatesSince(IsTransHazardFn,
MI,
IsExpiredFn) == HasVALU)
2663 BuildMI(*
MI->getParent(),
MI,
MI->getDebugLoc(), TII->get(AMDGPU::V_NOP_e32));
2671 const SIInstrInfo *TII = ST.getInstrInfo();
2672 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2674 auto IsHazardFn = [
MI, TII, TRI,
this](
const MachineInstr &
I) {
2681 TII->getNamedOperand(*
MI, AMDGPU::OpName::src0)->getReg();
2683 TII->getNamedOperand(*
MI, AMDGPU::OpName::src1)->getReg();
2686 TII->getNamedOperand(
I, AMDGPU::OpName::vdst)->getReg();
2688 if (TRI->regsOverlap(PrevDstReg, CurSrc0Reg) ||
2689 TRI->regsOverlap(PrevDstReg, CurSrc1Reg)) {
2698 TII->getNamedOperand(*
MI, AMDGPU::OpName::src2)->getReg();
2699 if (TRI->regsOverlap(PrevDstReg, CurIndex))
2713 std::numeric_limits<int>::max())
2716 BuildMI(*
MI->getParent(),
MI,
MI->getDebugLoc(), TII->get(AMDGPU::V_NOP_e32));
2770 bool IsLowestRateWMMA = ST.hasGFX125xLowestRateWMMA();
2771 unsigned Category = 0;
2773 unsigned Latency = SchedModel.computeInstrLatency(&
MI);
2778 assert(!IsSWMMAC &&
"no 4-cycle SWMMAC expected");
2782 Category = IsSWMMAC ? 2 : 0;
2785 Category = IsLowestRateWMMA ? 4 : (IsSWMMAC ? 3 : 1);
2788 assert(IsLowestRateWMMA &&
"latency 32 is not expected");
2798int GCNHazardRecognizer::checkWMMACoexecutionHazards(
MachineInstr *
MI)
const {
2799 if (!ST.hasWMMACoexecutionHazards())
2802 const SIInstrInfo *TII = ST.getInstrInfo();
2811 const int WMMAWaitStates[] = {5, 9, 3, 5, 9, 17, 2};
2812 const int VALUWaitStates[] = {4, 8, 2, 4, 8, 16, 1};
2813 const bool IsWMMA = TII->isXDLWMMA(*
MI);
2814 const bool IsLowestRateWMMA = ST.hasGFX125xLowestRateWMMA();
2815 ArrayRef<int> RequiredWaitStates =
2816 IsWMMA ? ArrayRef<int>(WMMAWaitStates) :
ArrayRef<int>(VALUWaitStates);
2817 const int MaxWaitStates =
2818 IsWMMA ? (IsLowestRateWMMA ? 17 : 9) : (IsLowestRateWMMA ? 16 : 8);
2820 auto WindowFor = [=](
const MachineInstr &
I) -> std::optional<int> {
2821 if (!TII->isXDLWMMA(
I))
2822 return std::nullopt;
2823 if (IsWMMA ? !hasWMMAToWMMARegOverlap(
I, *
MI)
2824 : !hasWMMAToVALURegOverlap(
I, *
MI))
2825 return std::nullopt;
2830 return getMaxVALUWindowDeficit(MaxWaitStates, WindowFor);
2833bool GCNHazardRecognizer::hasWMMAToWMMARegOverlap(
2835 Register D0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::vdst)->getReg();
2836 Register A1 = TII.getNamedOperand(
MI, AMDGPU::OpName::src0)->getReg();
2837 Register B1 = TII.getNamedOperand(
MI, AMDGPU::OpName::src1)->getReg();
2840 if (TRI.regsOverlap(D0, A1) || TRI.regsOverlap(D0, B1))
2844 Register Idx1 = TII.getNamedOperand(
MI, AMDGPU::OpName::src2)->getReg();
2845 if (TRI.regsOverlap(D0, Idx1))
2851bool GCNHazardRecognizer::hasWMMAToVALURegOverlap(
2854 Register D0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::vdst)->getReg();
2855 for (
const MachineOperand &ValuUse :
MI.explicit_uses()) {
2856 if (ValuUse.isReg() && TRI.regsOverlap(D0, ValuUse.getReg()))
2861 Register A0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::src0)->getReg();
2862 Register B0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::src1)->getReg();
2865 const MachineOperand *
Src2 = TII.getNamedOperand(WMMA, AMDGPU::OpName::src2);
2867 WMMARegs.push_back(
Src2->getReg());
2869 for (
const MachineOperand &ValuDef :
MI.defs()) {
2870 Register VDstReg = ValuDef.getReg();
2871 for (
Register WMMAReg : WMMARegs) {
2872 if (TRI.regsOverlap(VDstReg, WMMAReg))
2879bool GCNHazardRecognizer::isCoexecutionHazardFor(
const MachineInstr &
I,
2883 if (!TII.isXDLWMMA(
I))
2887 if (TII.isXDLWMMA(
MI))
2888 return hasWMMAToWMMARegOverlap(
I,
MI);
2890 return hasWMMAToVALURegOverlap(
I,
MI);
2896 bool IncludeSubloops) {
2899 for (MachineBasicBlock *
MBB :
L->getBlocks()) {
2900 if (!IncludeSubloops && MLI->getLoopFor(
MBB) != L)
2902 for (MachineInstr &
I : *
MBB) {
2905 if (isCoexecutionHazardFor(
I, *
MI))
2912bool GCNHazardRecognizer::tryHoistWMMAVnopsFromLoop(
MachineInstr *
MI,
2913 int WaitStatesNeeded) {
2917 MachineLoop *
L = MLI->getLoopFor(
MI->getParent());
2919 ++NumWMMAHoistingBailed;
2924 if (hasWMMAHazardInLoop(L,
MI)) {
2925 ++NumWMMAHoistingBailed;
2930 MachineLoop *TargetLoop =
L;
2932 if (hasWMMAHazardInLoop(Parent,
MI,
false))
2934 TargetLoop = Parent;
2940 ++NumWMMAHoistingBailed;
2944 LLVM_DEBUG(
dbgs() <<
"WMMA V_NOP Hoisting: Moving " << WaitStatesNeeded
2950 NumWMMANopsHoisted += WaitStatesNeeded;
2954bool GCNHazardRecognizer::fixWMMACoexecutionHazards(
MachineInstr *
MI) {
2955 int WaitStatesNeeded = checkWMMACoexecutionHazards(
MI);
2956 if (WaitStatesNeeded <= 0)
2962 emitVNops(*
MI->getParent(),
MI->getIterator(), WaitStatesNeeded);
2966bool GCNHazardRecognizer::fixShift64HighRegBug(
MachineInstr *
MI) {
2967 if (!ST.hasShift64HighRegBug())
2969 assert(!ST.hasExtendedWaitCounts());
2971 switch (
MI->getOpcode()) {
2974 case AMDGPU::V_LSHLREV_B64_e64:
2975 case AMDGPU::V_LSHRREV_B64_e64:
2976 case AMDGPU::V_ASHRREV_I64_e64:
2980 MachineOperand *Amt = TII.getNamedOperand(*
MI, AMDGPU::OpName::src0);
2985 const MachineRegisterInfo &
MRI = MF.getRegInfo();
2987 if (!TRI.isVGPR(
MRI, AmtReg) || ((AmtReg - AMDGPU::VGPR0) & 7) != 7)
2993 assert(ST.needsAlignedVGPRs());
2994 static_assert(AMDGPU::VGPR0 + 1 == AMDGPU::VGPR1);
2998 MachineOperand *
Src1 = TII.getNamedOperand(*
MI, AMDGPU::OpName::src1);
3009 Register DstReg =
MI->getOperand(0).getReg();
3010 if (!
Src1->isReg() ||
Src1->getReg() != DstReg) {
3011 Register DstLo = TRI.getSubReg(DstReg, AMDGPU::sub0);
3019 bool Overlapped =
MI->modifiesRegister(AmtReg, &TRI);
3021 for (MCRegister
Reg : Overlapped ? AMDGPU::VReg_64_Align2RegClass
3022 : AMDGPU::VGPR_32RegClass) {
3023 if (!
MI->modifiesRegister(
Reg, &TRI) && !
MI->readsRegister(
Reg, &TRI)) {
3029 Register NewAmt = Overlapped ? (
Register)TRI.getSubReg(NewReg, AMDGPU::sub1)
3034 NewAmtLo = TRI.getSubReg(NewReg, AMDGPU::sub0);
3047 runOnInstruction(
BuildMI(*
MBB,
MI,
DL, TII.get(AMDGPU::V_SWAP_B32), NewAmt)
3054 BuildMI(*
MBB, std::next(
MI->getIterator()),
DL, TII.get(AMDGPU::V_SWAP_B32),
3060 BuildMI(*
MBB, std::next(
MI->getIterator()),
DL, TII.get(AMDGPU::V_SWAP_B32),
3074 MI->getOperand(0).setReg(NewReg);
3075 Src1->setReg(NewReg);
3076 Src1->setIsKill(
false);
3083int GCNHazardRecognizer::checkNSAtoVMEMHazard(
MachineInstr *
MI)
const {
3084 int NSAtoVMEMWaitStates = 1;
3086 if (!ST.hasNSAtoVMEMBug())
3092 const SIInstrInfo *TII = ST.getInstrInfo();
3093 const auto *
Offset = TII->getNamedOperand(*
MI, AMDGPU::OpName::offset);
3101 return Info->MIMGEncoding == AMDGPU::MIMGEncGfx10NSA &&
3102 TII->getInstSizeInBytes(
I) >= 16;
3105 return NSAtoVMEMWaitStates - getWaitStatesSince(
IsHazardFn, 1);
3108int GCNHazardRecognizer::checkFPAtomicToDenormModeHazard(
3110 int FPAtomicToDenormModeWaitStates = 3;
3112 if (!ST.hasFPAtomicToDenormModeHazard())
3114 assert(!ST.hasExtendedWaitCounts());
3116 if (
MI->getOpcode() != AMDGPU::S_DENORM_MODE)
3125 auto IsExpiredFn = [](
const MachineInstr &
MI,
int WaitStates) {
3132 return FPAtomicToDenormModeWaitStates -
3136int GCNHazardRecognizer::checkMAIHazards(
MachineInstr *
MI)
const {
3139 return ST.hasGFX90AInsts() ? checkMAIHazards90A(
MI) : checkMAIHazards908(
MI);
3142int GCNHazardRecognizer::checkMFMAPadding(
MachineInstr *
MI)
const {
3147 const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
3151 int NeighborMFMALatency = 0;
3152 auto IsNeighboringMFMA = [&NeighborMFMALatency,
3153 this](
const MachineInstr &
MI) {
3157 NeighborMFMALatency = this->getMFMAPipelineWaitStates(
MI);
3161 const int MaxMFMAPipelineWaitStates = 16;
3162 int WaitStatesSinceNeighborMFMA =
3163 getWaitStatesSince(IsNeighboringMFMA, MaxMFMAPipelineWaitStates);
3165 int NeighborMFMAPaddingNeeded =
3167 WaitStatesSinceNeighborMFMA;
3169 return std::max(0, NeighborMFMAPaddingNeeded);
3172int GCNHazardRecognizer::checkMAIHazards908(
MachineInstr *
MI)
const {
3173 int WaitStatesNeeded = 0;
3174 unsigned Opc =
MI->getOpcode();
3176 auto IsVALUFn = [](
const MachineInstr &
MI) {
3180 if (
Opc != AMDGPU::V_ACCVGPR_READ_B32_e64) {
3181 const int LegacyVALUWritesVGPRWaitStates = 2;
3182 const int VALUWritesExecWaitStates = 4;
3183 const int MaxWaitStates = 4;
3185 int WaitStatesNeededForUse = VALUWritesExecWaitStates -
3186 getWaitStatesSinceDef(AMDGPU::EXEC, IsVALUFn, MaxWaitStates);
3187 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3189 if (WaitStatesNeeded < MaxWaitStates) {
3190 for (
const MachineOperand &Use :
MI->explicit_uses()) {
3191 const int MaxWaitStates = 2;
3193 if (!
Use.isReg() || !TRI.isVGPR(MF.getRegInfo(),
Use.getReg()))
3196 int WaitStatesNeededForUse = LegacyVALUWritesVGPRWaitStates -
3197 getWaitStatesSinceDef(
Use.getReg(), IsVALUFn, MaxWaitStates);
3198 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3200 if (WaitStatesNeeded == MaxWaitStates)
3206 for (
const MachineOperand &
Op :
MI->explicit_operands()) {
3207 if (!
Op.isReg() || !TRI.isAGPR(MF.getRegInfo(),
Op.getReg()))
3210 if (
Op.isDef() &&
Opc != AMDGPU::V_ACCVGPR_WRITE_B32_e64)
3213 const int MFMAWritesAGPROverlappedSrcABWaitStates = 4;
3214 const int MFMAWritesAGPROverlappedSrcCWaitStates = 2;
3215 const int MFMA4x4WritesAGPRAccVgprReadWaitStates = 4;
3216 const int MFMA16x16WritesAGPRAccVgprReadWaitStates = 10;
3217 const int MFMA32x32WritesAGPRAccVgprReadWaitStates = 18;
3218 const int MFMA4x4WritesAGPRAccVgprWriteWaitStates = 1;
3219 const int MFMA16x16WritesAGPRAccVgprWriteWaitStates = 7;
3220 const int MFMA32x32WritesAGPRAccVgprWriteWaitStates = 15;
3221 const int MaxWaitStates = 18;
3223 unsigned HazardDefLatency = 0;
3225 auto IsOverlappedMFMAFn = [
Reg, &HazardDefLatency,
3226 this](
const MachineInstr &
MI) {
3233 std::max(HazardDefLatency, TSchedModel.computeInstrLatency(&
MI));
3234 return TRI.regsOverlap(DstReg,
Reg);
3237 int WaitStatesSinceDef = getWaitStatesSinceDef(
Reg, IsOverlappedMFMAFn,
3239 int NeedWaitStates = MFMAWritesAGPROverlappedSrcABWaitStates;
3240 int SrcCIdx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src2);
3241 int OpNo =
Op.getOperandNo();
3242 if (OpNo == SrcCIdx) {
3243 NeedWaitStates = MFMAWritesAGPROverlappedSrcCWaitStates;
3244 }
else if (
Opc == AMDGPU::V_ACCVGPR_READ_B32_e64) {
3245 switch (HazardDefLatency) {
3246 case 2: NeedWaitStates = MFMA4x4WritesAGPRAccVgprReadWaitStates;
3248 case 8: NeedWaitStates = MFMA16x16WritesAGPRAccVgprReadWaitStates;
3250 case 16: [[fallthrough]];
3251 default: NeedWaitStates = MFMA32x32WritesAGPRAccVgprReadWaitStates;
3254 }
else if (
Opc == AMDGPU::V_ACCVGPR_WRITE_B32_e64) {
3255 switch (HazardDefLatency) {
3256 case 2: NeedWaitStates = MFMA4x4WritesAGPRAccVgprWriteWaitStates;
3258 case 8: NeedWaitStates = MFMA16x16WritesAGPRAccVgprWriteWaitStates;
3260 case 16: [[fallthrough]];
3261 default: NeedWaitStates = MFMA32x32WritesAGPRAccVgprWriteWaitStates;
3266 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceDef;
3267 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3269 if (WaitStatesNeeded == MaxWaitStates)
3270 return WaitStatesNeeded;
3272 auto IsAccVgprWriteFn = [
Reg,
this](
const MachineInstr &
MI) {
3273 if (
MI.getOpcode() != AMDGPU::V_ACCVGPR_WRITE_B32_e64)
3276 return TRI.regsOverlap(
Reg, DstReg);
3279 const int AccVGPRWriteMFMAReadSrcCWaitStates = 1;
3280 const int AccVGPRWriteMFMAReadSrcABWaitStates = 3;
3281 const int AccVGPRWriteAccVgprReadWaitStates = 3;
3282 NeedWaitStates = AccVGPRWriteMFMAReadSrcABWaitStates;
3283 if (OpNo == SrcCIdx)
3284 NeedWaitStates = AccVGPRWriteMFMAReadSrcCWaitStates;
3285 else if (
Opc == AMDGPU::V_ACCVGPR_READ_B32_e64)
3286 NeedWaitStates = AccVGPRWriteAccVgprReadWaitStates;
3288 WaitStatesNeededForUse = NeedWaitStates -
3289 getWaitStatesSinceDef(
Reg, IsAccVgprWriteFn, MaxWaitStates);
3290 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3292 if (WaitStatesNeeded == MaxWaitStates)
3293 return WaitStatesNeeded;
3296 if (
Opc == AMDGPU::V_ACCVGPR_WRITE_B32_e64) {
3297 const int MFMA4x4ReadSrcCAccVgprWriteWaitStates = 0;
3298 const int MFMA16x16ReadSrcCAccVgprWriteWaitStates = 5;
3299 const int MFMA32x32ReadSrcCAccVgprWriteWaitStates = 13;
3300 const int MaxWaitStates = 13;
3301 Register DstReg =
MI->getOperand(0).getReg();
3302 unsigned HazardDefLatency = 0;
3304 auto IsSrcCMFMAFn = [DstReg, &HazardDefLatency,
3305 this](
const MachineInstr &
MI) {
3308 Register Reg = TII.getNamedOperand(
MI, AMDGPU::OpName::src2)->getReg();
3310 std::max(HazardDefLatency, TSchedModel.computeInstrLatency(&
MI));
3311 return TRI.regsOverlap(
Reg, DstReg);
3314 int WaitStatesSince = getWaitStatesSince(IsSrcCMFMAFn, MaxWaitStates);
3316 switch (HazardDefLatency) {
3317 case 2: NeedWaitStates = MFMA4x4ReadSrcCAccVgprWriteWaitStates;
3319 case 8: NeedWaitStates = MFMA16x16ReadSrcCAccVgprWriteWaitStates;
3321 case 16: [[fallthrough]];
3322 default: NeedWaitStates = MFMA32x32ReadSrcCAccVgprWriteWaitStates;
3326 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSince;
3327 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3331 WaitStatesNeeded = std::max(WaitStatesNeeded, checkMFMAPadding(
MI));
3333 return WaitStatesNeeded;
3362 return NumPasses + 1 + IsGFX950;
3373 return NumPasses + 1 + (NumPasses != 2 && IsGFX950);
3391 return NumPasses + 2;
3401 return NumPasses + 3 + (NumPasses != 2 && IsGFX950);
3404int GCNHazardRecognizer::getMFMAOverlappedSrcCWaitStates(
3406 constexpr int SMFMA4x4WritesVGPROverlappedSMFMASrcCWaitStates = 2;
3407 constexpr int SMFMA16x16WritesVGPROverlappedSMFMASrcCWaitStates = 8;
3408 constexpr int SMFMA32x32WritesVGPROverlappedSMFMASrcCWaitStates = 16;
3409 constexpr int SMFMA4x4WritesVGPROverlappedDMFMASrcCWaitStates = 3;
3410 constexpr int SMFMA16x16WritesVGPROverlappedDMFMASrcCWaitStates = 9;
3411 constexpr int SMFMA32x32WritesVGPROverlappedDMFMASrcCWaitStates = 17;
3412 constexpr int DMFMA16x16WritesVGPROverlappedSrcCWaitStates = 9;
3413 constexpr int GFX950_DMFMA16x16WritesVGPROverlappedSrcCWaitStates = 17;
3414 constexpr int DMFMA4x4WritesVGPROverlappedSrcCWaitStates = 4;
3418 if (TII.isXDL(*Reader) && !TII.isXDL(*Writer))
3422 case AMDGPU::V_MFMA_F64_16X16X4F64_e64:
3423 case AMDGPU::V_MFMA_F64_16X16X4F64_vgprcd_e64:
3424 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_e64:
3425 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_vgprcd_e64:
3426 return ST.hasGFX950Insts()
3427 ? GFX950_DMFMA16x16WritesVGPROverlappedSrcCWaitStates
3428 : DMFMA16x16WritesVGPROverlappedSrcCWaitStates;
3429 case AMDGPU::V_MFMA_F64_4X4X4F64_e64:
3430 case AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64:
3431 return DMFMA4x4WritesVGPROverlappedSrcCWaitStates;
3436 int NumPasses = TSchedModel.computeInstrLatency(Writer);
3437 if (ST.hasGFX940Insts()) {
3438 if (!TII.isXDL(*Writer))
3441 return TII.isXDL(*Reader)
3443 NumPasses, ST.hasGFX950Insts())
3445 NumPasses, ST.hasGFX950Insts());
3449 switch (NumPasses) {
3451 return IsDGEMM ? SMFMA4x4WritesVGPROverlappedDMFMASrcCWaitStates
3452 : SMFMA4x4WritesVGPROverlappedSMFMASrcCWaitStates;
3454 return IsDGEMM ? SMFMA16x16WritesVGPROverlappedDMFMASrcCWaitStates
3455 : SMFMA16x16WritesVGPROverlappedSMFMASrcCWaitStates;
3457 return IsDGEMM ? SMFMA32x32WritesVGPROverlappedDMFMASrcCWaitStates
3458 : SMFMA32x32WritesVGPROverlappedSMFMASrcCWaitStates;
3464int GCNHazardRecognizer::getMFMAReadWaitStates(
const MachineInstr &Consumer,
3467 bool IsSrcC)
const {
3469 const int SMFMA4x4WritesVGPROverlappedSrcABWaitStates = 5;
3470 const int SMFMA16x16WritesVGPROverlappedSrcABWaitStates = 11;
3471 const int SMFMA32x32WritesVGPROverlappedSrcABWaitStates = 19;
3472 const int DMFMA4x4WritesVGPROverlappedMFMASrcABWaitStates = 6;
3473 const int DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates = 11;
3474 const int GFX950_DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates = 19;
3475 const int DMFMA4x4WritesVGPRFullSrcCWaitStates = 4;
3476 const int GFX940_SMFMA4x4WritesVGPRFullSrcCWaitStates = 2;
3478 bool FullReg =
Producer.getOperand(0).getReg() ==
Reg;
3479 unsigned Opc1 =
Producer.getOpcode();
3480 int NeedWaitStates = 0;
3485 }
else if (FullReg) {
3486 if ((
Opc == AMDGPU::V_MFMA_F64_4X4X4F64_e64 ||
3487 Opc == AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64) &&
3488 (Opc1 == AMDGPU::V_MFMA_F64_4X4X4F64_e64 ||
3489 Opc1 == AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64))
3490 NeedWaitStates = DMFMA4x4WritesVGPRFullSrcCWaitStates;
3491 else if (ST.hasGFX940Insts() &&
3492 TSchedModel.computeInstrLatency(&Producer) == 2)
3493 NeedWaitStates = GFX940_SMFMA4x4WritesVGPRFullSrcCWaitStates;
3500 std::max(NeedWaitStates,
3501 getMFMAOverlappedSrcCWaitStates(&Consumer, &Producer));
3504 NeedWaitStates = getMFMAOverlappedSrcCWaitStates(&Consumer, &Producer);
3508 case AMDGPU::V_MFMA_F64_16X16X4F64_e64:
3509 case AMDGPU::V_MFMA_F64_16X16X4F64_vgprcd_e64:
3510 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_e64:
3511 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_vgprcd_e64:
3514 ? GFX950_DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates
3515 : DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates;
3517 case AMDGPU::V_MFMA_F64_4X4X4F64_e64:
3518 case AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64:
3519 NeedWaitStates = DMFMA4x4WritesVGPROverlappedMFMASrcABWaitStates;
3522 int NumPasses = TSchedModel.computeInstrLatency(&Producer);
3524 if (ST.hasGFX940Insts()) {
3528 NumPasses, ST.hasGFX950Insts())
3534 switch (NumPasses) {
3536 NeedWaitStates = SMFMA4x4WritesVGPROverlappedSrcABWaitStates;
3541 NeedWaitStates = SMFMA16x16WritesVGPROverlappedSrcABWaitStates;
3545 NeedWaitStates = SMFMA32x32WritesVGPROverlappedSrcABWaitStates;
3549 return NeedWaitStates;
3552int GCNHazardRecognizer::checkMAIHazards90A(
MachineInstr *
MI)
const {
3553 int WaitStatesNeeded = 0;
3554 unsigned Opc =
MI->getOpcode();
3556 auto IsLegacyVALUFn = [](
const MachineInstr &
MI) {
3561 auto IsLegacyVALUNotDotFn = [](
const MachineInstr &
MI) {
3567 return WaitStatesNeeded;
3569 const int VALUWritesExecWaitStates = 4;
3570 int WaitStatesNeededForUse = VALUWritesExecWaitStates -
3571 getWaitStatesSinceDef(AMDGPU::EXEC, IsLegacyVALUFn,
3572 VALUWritesExecWaitStates);
3573 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3575 int SrcCIdx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src2);
3578 for (
const MachineOperand &Use :
MI->explicit_uses()) {
3579 const int LegacyVALUNotDotWritesVGPRWaitStates = 2;
3580 const int MaxWaitStates =
3582 16, ST.hasGFX950Insts());
3588 WaitStatesNeededForUse = LegacyVALUNotDotWritesVGPRWaitStates -
3589 getWaitStatesSinceDef(
Reg, IsLegacyVALUNotDotFn, MaxWaitStates);
3590 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3592 int OpNo =
Use.getOperandNo();
3593 WaitStatesNeeded = std::max(
3595 getMaxWindowDeficit(
3596 MaxWaitStates, [&](
const MachineInstr &
P) -> std::optional<int> {
3598 !TRI.regsOverlap(
P.getOperand(0).getReg(),
Reg))
3599 return std::nullopt;
3600 return getMFMAReadWaitStates(*
MI,
P,
Reg, OpNo == SrcCIdx);
3603 if (WaitStatesNeeded == MaxWaitStates)
3608 WaitStatesNeeded = std::max(WaitStatesNeeded, checkMFMAPadding(
MI));
3610 return WaitStatesNeeded;
3613int GCNHazardRecognizer::checkMAILdStHazards(
MachineInstr *
MI)
const {
3615 if (!ST.hasMAIInsts() || ST.hasGFX90AInsts())
3618 int WaitStatesNeeded = 0;
3620 auto IsAccVgprReadFn = [](
const MachineInstr &
MI) {
3621 return MI.getOpcode() == AMDGPU::V_ACCVGPR_READ_B32_e64;
3624 for (
const MachineOperand &
Op :
MI->explicit_uses()) {
3625 if (!
Op.isReg() || !TRI.isVGPR(MF.getRegInfo(),
Op.getReg()))
3630 const int AccVgprReadLdStWaitStates = 2;
3631 const int VALUWriteAccVgprRdWrLdStDepVALUWaitStates = 1;
3632 const int MaxWaitStates = 2;
3634 int WaitStatesNeededForUse = AccVgprReadLdStWaitStates -
3635 getWaitStatesSinceDef(
Reg, IsAccVgprReadFn, MaxWaitStates);
3636 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3638 if (WaitStatesNeeded == MaxWaitStates)
3639 return WaitStatesNeeded;
3641 auto IsVALUAccVgprRdWrCheckFn = [
Reg,
this](
const MachineInstr &
MI) {
3642 if (
MI.getOpcode() != AMDGPU::V_ACCVGPR_READ_B32_e64 &&
3643 MI.getOpcode() != AMDGPU::V_ACCVGPR_WRITE_B32_e64)
3645 auto IsVALUFn = [](
const MachineInstr &
MI) {
3649 return getWaitStatesSinceDef(
Reg, IsVALUFn, 2 ) <
3650 std::numeric_limits<int>::max();
3653 WaitStatesNeededForUse = VALUWriteAccVgprRdWrLdStDepVALUWaitStates -
3654 getWaitStatesSince(IsVALUAccVgprRdWrCheckFn, MaxWaitStates);
3655 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3658 return WaitStatesNeeded;
3661int GCNHazardRecognizer::checkPermlaneHazards(
MachineInstr *
MI)
const {
3662 assert(!ST.hasVcmpxPermlaneHazard() &&
3663 "this is a different vcmpx+permlane hazard");
3664 const SIRegisterInfo *TRI = ST.getRegisterInfo();
3665 const SIInstrInfo *TII = ST.getInstrInfo();
3667 auto IsVCmpXWritesExecFn = [TII, TRI](
const MachineInstr &
MI) {
3671 auto IsVALUFn = [](
const MachineInstr &
MI) {
3675 const int VCmpXWritesExecWaitStates = 4;
3676 const int VALUWritesVDstWaitStates = 2;
3677 int WaitStatesNeeded = 0;
3679 for (
const MachineOperand &
Op :
MI->explicit_uses()) {
3680 if (!
Op.isReg() || !TRI->isVGPR(MF.getRegInfo(),
Op.getReg()))
3684 int WaitStatesSinceDef =
3685 VALUWritesVDstWaitStates -
3686 getWaitStatesSinceDef(
Reg, IsVALUFn,
3687 VALUWritesVDstWaitStates);
3688 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesSinceDef);
3689 if (WaitStatesNeeded >= VALUWritesVDstWaitStates)
3693 int VCmpXHazardWaits =
3694 VCmpXWritesExecWaitStates -
3695 getWaitStatesSince(IsVCmpXWritesExecFn, VCmpXWritesExecWaitStates);
3697 WaitStatesNeeded = std::max(WaitStatesNeeded, VCmpXHazardWaits);
3698 return WaitStatesNeeded;
3706 return NumPasses + 2;
3716 return NumPasses + 3 + (NumPasses != 2 && IsGFX950);
3726 return NumPasses + 3 + (NumPasses != 2 && IsGFX950);
3734 return NumPasses + 2;
3737int GCNHazardRecognizer::checkMAIVALUHazards(
MachineInstr *
MI)
const {
3738 if (!ST.hasGFX90AInsts())
3741 auto IsDGEMMFn = [](
const MachineInstr &
MI) ->
bool {
3749 const MachineRegisterInfo &
MRI = MF.getRegInfo();
3751 int WaitStatesNeeded = 0;
3758 auto IsMFMAWriteFn = [&
Reg,
this](
const MachineInstr &
MI) {
3760 !TRI.regsOverlap(
MI.getOperand(0).getReg(),
Reg))
3765 const MachineInstr *
DOT =
nullptr;
3766 auto IsDotWriteFn = [&
Reg, &
DOT,
this](
const MachineInstr &
MI) {
3768 !TRI.regsOverlap(
MI.getOperand(0).getReg(),
Reg))
3774 bool DGEMMAfterVALUWrite =
false;
3775 auto IsDGEMMHazard = [&DGEMMAfterVALUWrite,
this](
const MachineInstr &
MI) {
3778 DGEMMAfterVALUWrite =
true;
3782 if (!TII.isVALU(
MI,
true) || !DGEMMAfterVALUWrite)
3788 int SrcCIdx = AMDGPU::getNamedOperandIdx(
MI->getOpcode(),
3789 AMDGPU::OpName::src2);
3791 if (IsMemOrExport || IsVALU) {
3792 const int SMFMA4x4WriteVgprVALUMemExpReadWaitStates = 5;
3793 const int SMFMA16x16WriteVgprVALUMemExpReadWaitStates = 11;
3794 const int SMFMA32x32WriteVgprVALUMemExpReadWaitStates = 19;
3795 const int DMFMA4x4WriteVgprMemExpReadWaitStates = 9;
3796 const int DMFMA16x16WriteVgprMemExpReadWaitStates = 18;
3797 const int DMFMA4x4WriteVgprVALUReadWaitStates = 6;
3798 const int DMFMA16x16WriteVgprVALUReadWaitStates = 11;
3799 const int GFX950_DMFMA16x16WriteVgprVALUReadWaitStates = 19;
3800 const int DotWriteSameDotReadSrcAB = 3;
3801 const int DotWriteDifferentVALURead = 3;
3802 const int DMFMABetweenVALUWriteVMEMRead = 2;
3803 const int MaxWaitStates =
3805 ST.hasGFX950Insts());
3807 for (
const MachineOperand &Use :
MI->explicit_uses()) {
3813 int WaitStatesSinceDef = getWaitStatesSinceDef(
Reg, IsDotWriteFn,
3816 int NeedWaitStates = 0;
3817 if (
DOT->getOpcode() ==
MI->getOpcode()) {
3818 if (&Use - &
MI->getOperand(0) != SrcCIdx)
3819 NeedWaitStates = DotWriteSameDotReadSrcAB;
3821 NeedWaitStates = DotWriteDifferentVALURead;
3824 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceDef;
3825 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3832 if (IsMem && ST.hasGFX90AInsts() && !ST.hasGFX940Insts()) {
3833 DGEMMAfterVALUWrite =
false;
3834 if (TRI.isVectorRegister(
MRI,
Reg)) {
3835 int WaitStatesNeededForUse =
3836 DMFMABetweenVALUWriteVMEMRead -
3837 getWaitStatesSinceDef(
Reg, IsDGEMMHazard,
3838 DMFMABetweenVALUWriteVMEMRead);
3840 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3844 auto MFMAWindow = [&](
const MachineInstr &
Producer) {
3845 int NumPasses = TSchedModel.computeInstrLatency(&Producer);
3846 int NeedWaitStates = MaxWaitStates;
3849 switch (NumPasses) {
3851 NeedWaitStates = IsMemOrExport
3852 ? DMFMA4x4WriteVgprMemExpReadWaitStates
3853 : DMFMA4x4WriteVgprVALUReadWaitStates;
3859 ? DMFMA16x16WriteVgprMemExpReadWaitStates
3860 : (ST.hasGFX950Insts()
3861 ? GFX950_DMFMA16x16WriteVgprVALUReadWaitStates
3862 : DMFMA16x16WriteVgprVALUReadWaitStates);
3867 }
else if (ST.hasGFX940Insts()) {
3871 NumPasses, ST.hasGFX950Insts())
3875 switch (NumPasses) {
3877 NeedWaitStates = SMFMA4x4WriteVgprVALUMemExpReadWaitStates;
3880 NeedWaitStates = SMFMA16x16WriteVgprVALUMemExpReadWaitStates;
3883 NeedWaitStates = SMFMA32x32WriteVgprVALUMemExpReadWaitStates;
3890 assert(NeedWaitStates <= MaxWaitStates &&
3891 "hazard requirement exceeds the scan window");
3892 return NeedWaitStates;
3895 WaitStatesNeeded = std::max(
3897 getMaxWindowDeficit(MaxWaitStates,
3898 [&](
const MachineInstr &
P) -> std::optional<int> {
3899 if (!IsMFMAWriteFn(
P))
3900 return std::nullopt;
3901 return MFMAWindow(
P);
3904 if (WaitStatesNeeded >= MaxWaitStates)
3909 unsigned Opc =
MI->getOpcode();
3910 const int DMFMAToFMA64WaitStates = 2;
3911 if ((
Opc == AMDGPU::V_FMA_F64_e64 ||
3912 Opc == AMDGPU::V_FMAC_F64_e32 ||
Opc == AMDGPU::V_FMAC_F64_e64 ||
3913 Opc == AMDGPU::V_FMAC_F64_dpp) &&
3914 WaitStatesNeeded < DMFMAToFMA64WaitStates) {
3915 int WaitStatesNeededForUse = DMFMAToFMA64WaitStates -
3916 getWaitStatesSince(IsDGEMMFn, DMFMAToFMA64WaitStates);
3917 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3920 if (!IsVALU && !IsMemOrExport)
3921 return WaitStatesNeeded;
3923 for (
const MachineOperand &Def :
MI->defs()) {
3924 const int SMFMA4x4WriteVgprVALUWawWaitStates = 5;
3925 const int SMFMA16x16WriteVgprVALUWawWaitStates = 11;
3926 const int SMFMA32x32WriteVgprVALUWawWaitStates = 19;
3927 const int SMFMA4x4ReadVgprVALUWarWaitStates = 1;
3928 const int GFX940_XDL4PassReadVgprVALUWarWaitStates = 3;
3929 const int SMFMA16x16ReadVgprVALUWarWaitStates = 7;
3930 const int SMFMA32x32ReadVgprVALUWarWaitStates = 15;
3931 const int DMFMA4x4WriteVgprVALUWriteWaitStates = 6;
3932 const int DMFMA16x16WriteVgprVALUWriteWaitStates = 11;
3933 const int DotWriteDifferentVALUWrite = 3;
3934 const int MaxWaitStates =
3936 const int MaxWarWaitStates = 15;
3941 int WaitStatesSinceDef = getWaitStatesSinceDef(
Reg, IsDotWriteFn,
3943 if (DOT &&
DOT->getOpcode() !=
MI->getOpcode())
3944 WaitStatesNeeded = std::max(WaitStatesNeeded, DotWriteDifferentVALUWrite -
3945 WaitStatesSinceDef);
3947 auto MFMAWawWindow = [&](
const MachineInstr &
Producer) {
3948 int NeedWaitStates = MaxWaitStates;
3949 int NumPasses = TSchedModel.computeInstrLatency(&Producer);
3952 switch (NumPasses) {
3954 NeedWaitStates = DMFMA4x4WriteVgprVALUWriteWaitStates;
3958 NeedWaitStates = DMFMA16x16WriteVgprVALUWriteWaitStates;
3963 }
else if (ST.hasGFX940Insts()) {
3967 NumPasses, ST.hasGFX950Insts())
3970 switch (NumPasses) {
3972 NeedWaitStates = SMFMA4x4WriteVgprVALUWawWaitStates;
3975 NeedWaitStates = SMFMA16x16WriteVgprVALUWawWaitStates;
3978 NeedWaitStates = SMFMA32x32WriteVgprVALUWawWaitStates;
3985 assert(NeedWaitStates <= MaxWaitStates &&
3986 "hazard requirement exceeds the scan window");
3987 return NeedWaitStates;
3990 WaitStatesNeeded = std::max(
3992 getMaxWindowDeficit(MaxWaitStates,
3993 [&](
const MachineInstr &
P) -> std::optional<int> {
3994 if (!IsMFMAWriteFn(
P))
3995 return std::nullopt;
3996 return MFMAWawWindow(
P);
3999 if (WaitStatesNeeded >= MaxWaitStates)
4003 auto SMFMAReadAsCWindow =
4004 [&](
const MachineInstr &Reader) -> std::optional<int> {
4008 return std::nullopt;
4010 if (ST.hasGFX940Insts() && !TII.isXDL(Reader))
4011 return std::nullopt;
4013 const MachineOperand *SrcC =
4014 TII.getNamedOperand(Reader, AMDGPU::OpName::src2);
4015 assert(SrcC &&
"an MFMA must have a src2 operand");
4017 return std::nullopt;
4019 switch (TSchedModel.computeInstrLatency(&Reader)) {
4021 return SMFMA4x4ReadVgprVALUWarWaitStates;
4023 assert(ST.hasGFX940Insts() &&
"4-pass XDL is gfx940 or later");
4024 return GFX940_XDL4PassReadVgprVALUWarWaitStates;
4026 return SMFMA16x16ReadVgprVALUWarWaitStates;
4030 return SMFMA32x32ReadVgprVALUWarWaitStates;
4035 std::max(WaitStatesNeeded,
4036 getMaxWindowDeficit(MaxWarWaitStates, SMFMAReadAsCWindow));
4039 return WaitStatesNeeded;
4052 return MAI !=
nullptr;
4056 if (IsMFMAFn(*
MI)) {
4057 int W = getWaitStatesSince(IsMFMAFn, 16);
4059 return W < (int)TSchedModel.computeInstrLatency(MAI);
4073 while (
I->isBundledWithPred())
4079 if (
I->getOpcode() != AMDGPU::S_GETPC_B64)
4083 const unsigned NewBytes = 4;
4085 "Unexpected instruction insertion in bundle");
4088 while (NextMI !=
End && NextMI->isBundledWithPred()) {
4089 for (
auto &Operand : NextMI->operands()) {
4090 if (Operand.isGlobal())
4091 Operand.setOffset(Operand.getOffset() + NewBytes);
4097bool GCNHazardRecognizer::fixVALUMaskWriteHazard(
MachineInstr *
MI) {
4098 if (!ST.hasVALUMaskWriteHazard())
4100 assert(!ST.hasExtendedWaitCounts());
4107 if (!IsSALU && !IsVALU)
4119 const SIRegisterInfo *TRI = ST.getRegisterInfo();
4120 const MachineRegisterInfo &
MRI = MF.getRegInfo();
4125 case AMDGPU::EXEC_LO:
4126 case AMDGPU::EXEC_HI:
4128 case AMDGPU::SGPR_NULL:
4129 case AMDGPU::SGPR_NULL64:
4137 return Reg == AMDGPU::VCC ||
Reg == AMDGPU::VCC_LO ||
Reg == AMDGPU::VCC_HI;
4141 SmallSet<Register, 2> HazardSGPRs;
4143 static unsigned getHashValue(
const StateType &State) {
4146 static bool isEqual(
const StateType &
LHS,
const StateType &
RHS) {
4147 return LHS.HazardSGPRs ==
RHS.HazardSGPRs;
4151 StateType InitialState;
4154 MachineOperand *HazardDef =
nullptr;
4155 for (MachineOperand &
Op :
MI->all_defs()) {
4157 if (IgnoreableSGPR(
Reg))
4160 if (
Op.isImplicit())
4162 if (!TRI->isSGPRReg(
MRI,
Reg))
4175 if (AMDGPU::SReg_32RegClass.
contains(HazardReg)) {
4176 InitialState.HazardSGPRs.insert(HazardReg);
4179 InitialState.HazardSGPRs.insert(TRI->getSubReg(HazardReg, AMDGPU::sub0));
4180 InitialState.HazardSGPRs.insert(TRI->getSubReg(HazardReg, AMDGPU::sub1));
4183 auto IsHazardFn = [&](StateType &State,
const MachineInstr &
I) {
4184 if (State.HazardSGPRs.empty())
4187 switch (
I.getOpcode()) {
4188 case AMDGPU::V_ADDC_U32_e32:
4189 case AMDGPU::V_ADDC_U32_dpp:
4190 case AMDGPU::V_CNDMASK_B16_t16_e32:
4191 case AMDGPU::V_CNDMASK_B16_fake16_e32:
4192 case AMDGPU::V_CNDMASK_B16_t16_dpp:
4193 case AMDGPU::V_CNDMASK_B16_fake16_dpp:
4194 case AMDGPU::V_CNDMASK_B32_e32:
4195 case AMDGPU::V_CNDMASK_B32_dpp:
4196 case AMDGPU::V_DIV_FMAS_F32_e64:
4197 case AMDGPU::V_DIV_FMAS_F64_e64:
4198 case AMDGPU::V_SUBB_U32_e32:
4199 case AMDGPU::V_SUBB_U32_dpp:
4200 case AMDGPU::V_SUBBREV_U32_e32:
4201 case AMDGPU::V_SUBBREV_U32_dpp: {
4205 case AMDGPU::V_ADDC_U32_e64:
4206 case AMDGPU::V_ADDC_U32_e64_dpp:
4207 case AMDGPU::V_CNDMASK_B16_t16_e64:
4208 case AMDGPU::V_CNDMASK_B16_fake16_e64:
4209 case AMDGPU::V_CNDMASK_B16_t16_e64_dpp:
4210 case AMDGPU::V_CNDMASK_B16_fake16_e64_dpp:
4211 case AMDGPU::V_CNDMASK_B32_e64:
4212 case AMDGPU::V_CNDMASK_B32_e64_dpp:
4213 case AMDGPU::V_SUBB_U32_e64:
4214 case AMDGPU::V_SUBB_U32_e64_dpp:
4215 case AMDGPU::V_SUBBREV_U32_e64:
4216 case AMDGPU::V_SUBBREV_U32_e64_dpp: {
4218 const MachineOperand *SSRCOp = TII.getNamedOperand(
I, AMDGPU::OpName::src2);
4220 bool Result = TRI->regsOverlap(SSRCOp->
getReg(), HazardReg);
4228 auto UpdateStateFn = [&](StateType &State,
const MachineInstr &
I) {
4230 for (
auto &
Op :
I.all_defs()) {
4232 if (IgnoreableSGPR(
Reg))
4235 if (
Op.isImplicit())
4237 if (!TRI->isSGPRReg(
MRI,
Reg))
4244 for (
Register SGPR : State.HazardSGPRs) {
4245 if (
Reg == SGPR || TRI->regsOverlap(
Reg, SGPR))
4249 State.HazardSGPRs.erase(SGPR);
4256 std::next(
MI->getReverseIterator())))
4266 auto NextMI = std::next(
MI->getIterator());
4267 auto NewMI =
BuildMI(*
MI->getParent(), NextMI,
MI->getDebugLoc(),
4268 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
4280 if (EntryMBB.
begin() != EntryMBB.
end()) {
4281 auto &EntryMI = *EntryMBB.
begin();
4282 if (EntryMI.getOpcode() == AMDGPU::S_SETPRIO &&
4283 EntryMI.getOperand(0).getImm() >= Priority)
4292bool GCNHazardRecognizer::fixRequiredExportPriority(
MachineInstr *
MI) {
4293 if (!ST.hasRequiredExportPriority())
4311 const int MaxPriority = 3;
4312 const int NormalPriority = 2;
4313 const int PostExportPriority = 0;
4315 auto It =
MI->getIterator();
4316 switch (
MI->getOpcode()) {
4317 case AMDGPU::S_ENDPGM:
4318 case AMDGPU::S_ENDPGM_SAVED:
4319 case AMDGPU::S_ENDPGM_ORDERED_PS_DONE:
4320 case AMDGPU::SI_RETURN_TO_EPILOG:
4323 if (MF->getFrameInfo().hasCalls())
4326 case AMDGPU::S_SETPRIO: {
4328 auto &PrioOp =
MI->getOperand(0);
4329 int Prio =
static_cast<int>(PrioOp.getImm());
4330 bool InWA = (Prio == PostExportPriority) &&
4331 (It !=
MBB->
begin() && TII.isEXP(*std::prev(It)));
4332 if (InWA || Prio >= NormalPriority)
4334 PrioOp.setImm(std::min(Prio + NormalPriority, MaxPriority));
4338 if (!TII.isEXP(*
MI))
4349 auto NextMI = std::next(It);
4350 bool EndOfShader =
false;
4351 if (NextMI !=
MBB->
end()) {
4353 if (TII.isEXP(*NextMI))
4356 if (NextMI->getOpcode() == AMDGPU::S_SETPRIO &&
4357 NextMI->getOperand(0).getImm() == PostExportPriority)
4359 EndOfShader = NextMI->getOpcode() == AMDGPU::S_ENDPGM;
4366 .
addImm(PostExportPriority);
4370 BuildMI(*
MBB, NextMI,
DL, TII.get(AMDGPU::S_WAITCNT_EXPCNT))
4371 .
addReg(AMDGPU::SGPR_NULL)
4393 while (
I !=
End &&
I->isMetaInstruction())
4402 assert(ST.hasRequiresInitialUnclausedVmem() &&
4403 "V_PERM_PK16-hazard subtarget must provide the unclaused-VMEM entry "
4404 "prologue to satisfy the cross-wave entry mitigation");
4415 if (NextI !=
MBB->
end() && TII.isVPermPk16SafeInstr(*NextI))
4421 BuildMI(*
MBB, NextI,
MI->getDebugLoc(), TII.get(AMDGPU::V_NOP_e32));
4429 const SIInstrInfo *TII = ST.getInstrInfo();
4441 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4446bool GCNHazardRecognizer::fixDsAtomicAsyncBarrierArriveB64(
MachineInstr *
MI) {
4447 if (
MI->getOpcode() != AMDGPU::DS_ATOMIC_ASYNC_BARRIER_ARRIVE_B64)
4450 const SIInstrInfo *TII = ST.getInstrInfo();
4452 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4454 BuildMI(*
MI->getParent(), std::next(
MI->getIterator()),
MI->getDebugLoc(),
4455 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4461bool GCNHazardRecognizer::fixScratchBaseForwardingHazard(
MachineInstr *
MI) {
4467 const SIRegisterInfo *TRI = ST.getRegisterInfo();
4468 const SIInstrInfo *TII = ST.getInstrInfo();
4470 const int FlatScrBaseWaitStates = 10;
4472 bool ReadsFlatScrLo =
4474 bool ReadsFlatScrHi =
4475 MI->readsRegister(AMDGPU::SRC_FLAT_SCRATCH_BASE_HI, TRI);
4481 ReadsFlatScrLo =
true;
4484 ReadsFlatScrHi =
true;
4489 const MachineRegisterInfo &
MRI = MF.getRegInfo();
4492 DenseSet<const MachineBasicBlock *> Visited;
4494 return MI.modifiesRegister(
Reg, TRI);
4499 auto IsSGPRDef = [TII, TRI, &
MRI](
const MachineInstr &
MI) ->
unsigned {
4500 if (!TII->isSALU(
MI) && !TII->isVALU(
MI,
true))
4502 for (
const MachineOperand &MO :
MI.all_defs()) {
4503 if (TRI->isSGPRReg(
MRI, MO.getReg()))
4509 auto IsExpiredFn = [=](
const MachineInstr &
MI,
int SgprWrites) {
4510 if (
MI.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR) {
4511 unsigned Wait =
static_cast<unsigned>(
MI.getOperand(0).
getImm());
4516 return SgprWrites >= FlatScrBaseWaitStates;
4519 return ::getWaitStatesSince(
4520 IsHazardFn,
MI->getParent(), std::next(
MI->getReverseIterator()),
4521 0,
IsExpiredFn, Visited, IsSGPRDef) < FlatScrBaseWaitStates;
4525 !IsRegDefHazard(AMDGPU::SGPR102)) &&
4527 !IsRegDefHazard(AMDGPU::SGPR103)))
4531 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4542 BuildMI(*
MI->getParent(),
MI,
MI->getDebugLoc(), TII.get(AMDGPU::V_NOP_e32));
4543 BuildMI(*
MI->getParent(),
MI,
MI->getDebugLoc(), TII.get(AMDGPU::V_NOP_e32));
4548 auto IsTDM = [&](
const MachineInstr &
MI) ->
bool {
4550 MI.getOpcode() != AMDGPU::S_WAIT_TENSORCNT;
4557 if (
MI.getOpcode() != AMDGPU::S_WAIT_TENSORCNT)
4559 return MI.getOperand(0).getImm() <= 10;
4563 std::numeric_limits<int>::max())
4567 TII.get(AMDGPU::S_WAIT_TENSORCNT))
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
The AMDGPU TargetMachine interface definition for hw codegen targets.
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static bool isEqual(const Function &Caller, const Function &Callee)
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static cl::opt< unsigned, false, MFMAPaddingRatioParser > MFMAPaddingRatio("amdgpu-mfma-padding-ratio", cl::init(0), cl::Hidden, cl::desc("Fill a percentage of the latency between " "neighboring MFMA with s_nops."))
static bool shouldRunLdsBranchVmemWARHazardFixup(const MachineFunction &MF, const GCNSubtarget &ST)
static cl::opt< bool > EnableWMMAVnopHoisting("amdgpu-wmma-vnop-hoisting", cl::init(true), cl::Hidden, cl::desc("Hoist WMMA hazard V_NOPs from loops to preheaders"))
static bool consumesDstSelForwardingOperand(const MachineInstr *VALU, const MachineOperand *Dst, const SIRegisterInfo *TRI)
Checks whether the provided MI "consumes" the operand with a Dest sel fowarding issue Dst .
static bool isSGetReg(unsigned Opcode)
static bool breaksSMEMSoftClause(MachineInstr *MI)
static bool isLdsDma(const MachineInstr &MI)
static int GFX940_XDL_N_PassWritesVGPROverlappedSrcABWaitStates(int NumPasses, bool IsGFX950)
static unsigned getWMMAHazardInstInCategory(const MachineInstr &MI, const SIInstrInfo *TII, const TargetSchedModel &SchedModel, const GCNSubtarget &ST)
static bool isRFE(unsigned Opcode)
static bool isRWLane(unsigned Opcode)
static bool isSMovRel(unsigned Opcode)
static unsigned getMFMANonMacAGPRFormOp(unsigned Opc)
One MFMA can be written with up to four opcodes that differ only in how vdst and src2 are encoded: bo...
#define DEBUG_TYPE_VERBOSE
static const MachineOperand * getDstSelForwardingOperand(const MachineInstr &MI, const GCNSubtarget &ST)
Dest sel forwarding issue occurs if additional logic is needed to swizzle / pack the computed value i...
static int GFX940_XDL_N_PassWritesVGPROverlappedSGEMMDGEMMSrcCWaitStates(int NumPasses, bool IsGFX950)
static void updateGetPCBundle(MachineInstr *NewMI)
static int GFX940_XDL_N_PassWriteVgprVALUMemExpReadWaitStates(int NumPasses, bool IsGFX950)
static bool isStoreCountWaitZero(const MachineInstr &I)
static bool breaksVMEMSoftClause(MachineInstr *MI)
static bool isVCmpXWritesExec(const SIInstrInfo &TII, const SIRegisterInfo &TRI, const MachineInstr &MI)
static bool isSSetReg(unsigned Opcode)
static void addRegUnits(const SIRegisterInfo &TRI, BitVector &BV, MCRegister Reg)
static unsigned getHWReg(const SIInstrInfo *TII, const MachineInstr &RegInstr)
static bool isSameMFMA(unsigned Opc0, unsigned Opc1)
static bool isDivFMas(unsigned Opcode)
static unsigned getCountedWaitStates(const MachineInstr &MI, GCNHazardRecognizer::GetNumWaitStatesFn GetNumWaitStates)
static bool hasHazard(StateT InitialState, function_ref< HazardFnResult(StateT &, const MachineInstr &)> IsHazard, function_ref< void(StateT &, const MachineInstr &)> UpdateState, const MachineBasicBlock *InitialMBB, MachineBasicBlock::const_reverse_instr_iterator InitialI)
static int getWaitStatesSince(GCNHazardRecognizer::IsHazardFn IsHazard, const MachineBasicBlock *MBB, MachineBasicBlock::const_reverse_instr_iterator I, int WaitStates, GCNHazardRecognizer::IsExpiredFn IsExpired, DenseSet< const MachineBasicBlock * > &Visited, GCNHazardRecognizer::GetNumWaitStatesFn GetNumWaitStates=SIInstrInfo::getNumWaitStates)
static int GFX940_SMFMA_N_PassWritesVGPROverlappedSrcABWaitStates(int NumPasses)
static int GFX940_XDL_N_PassWriteVgprVALUWawWaitStates(int NumPasses, bool IsGFX950)
static int GFX940_SMFMA_N_PassWriteVgprVALUMemExpReadWaitStates(int NumPasses)
static MachineBasicBlock::iterator skipMetaInstructionsForward(MachineBasicBlock::iterator I, MachineBasicBlock::iterator End)
static int GFX940_SMFMA_N_PassWritesVGPROverlappedSMFMASrcCWaitStates(int NumPasses)
static bool isCoexecutableVALUInst(const MachineInstr &MI)
static bool ensureEntrySetPrio(MachineFunction *MF, int Priority, const SIInstrInfo &TII)
static void addRegsToSet(const SIRegisterInfo &TRI, iterator_range< MachineInstr::const_mop_iterator > Ops, BitVector &DefSet, BitVector &UseSet)
static void insertNoopsInBundle(MachineInstr *MI, const SIInstrInfo &TII, unsigned Quantity)
static bool isSendMsgTraceDataOrGDS(const SIInstrInfo &TII, const MachineInstr &MI)
static unsigned countUnexecutedTerminators(const MachineBasicBlock &Pred, const MachineBasicBlock *MBB)
static cl::opt< unsigned > NopPadding("amdgpu-snop-padding", cl::init(0), cl::Hidden, cl::desc("Insert a s_nop x before every instruction"))
static bool isPermlane(const MachineInstr &MI)
static int GFX940_SMFMA_N_PassWriteVgprVALUWawWaitStates(int NumPasses)
static int GFX940_XDL_N_PassWritesVGPROverlappedXDLOrSMFMASrcCWaitStates(int NumPasses, bool IsGFX950)
AMD GCN specific subclass of TargetSubtarget.
static Register UseReg(const MachineOperand &MO)
const HexagonInstrInfo * TII
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
static llvm::Error parse(GsymDataExtractor &Data, uint64_t BaseAddr, LineEntryCallback const &Callback)
Register const TargetRegisterInfo * TRI
Promote Memory to Register
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
MachineRegisterInfo & MRI
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
#define DEBUG_WITH_TYPE(TYPE,...)
DEBUG_WITH_TYPE macro - This macro should be used by passes to emit debug information.
static const uint32_t IV[8]
unsigned get(InstCounterType T) const
BitVector & set()
Set all bits in the bitvector.
std::pair< iterator, bool > insert_as(std::pair< KeyT, ValueT > &&KV, const LookupKeyT &Val)
Alternate version of insert() which allows a different, and possibly less expensive,...
Implements a dense probed hash-table based set.
CallingConv::ID getCallingConv() const
getCallingConv()/setCallingConv(CC) - These method get and set the calling convention of this functio...
unsigned getHazardWaitStates(MachineInstr *MI) const
Returns the number of wait states until all hazards for MI are resolved.
unsigned PreEmitNoopsCommon(MachineInstr *) const
OperatingMode
Operating mode for the hazard recognizer.
void EmitNoop() override
EmitNoop - This callback is invoked when a noop was added to the instruction stream.
void Reset() override
Reset - This callback is invoked when a new block of instructions is about to be schedule.
unsigned PreEmitNoops(MachineInstr *) override
This overload will be used when the hazard recognizer is being used by a non-scheduling pass,...
void EmitInstruction(SUnit *SU) override
EmitInstruction - This callback is invoked when an instruction is emitted, to advance the hazard stat...
function_ref< bool(const MachineInstr &)> IsHazardFn
void AdvanceCycle() override
AdvanceCycle - This callback is invoked whenever the next top-down instruction to be scheduled cannot...
function_ref< unsigned int(const MachineInstr &)> GetNumWaitStatesFn
bool ShouldPreferAnother(SUnit *SU) const override
ShouldPreferAnother - This callback may be invoked if getHazardType returns NoHazard.
bool hasPhysRegs() const
Returns true if instruction operands are physical registers, so that hazards defined by register depe...
function_ref< bool(const MachineInstr &, int WaitStates)> IsExpiredFn
bool isSchedulerMode() const
Returns true if running as a scheduler (pre-RA or post-RA).
GCNHazardRecognizer(const MachineFunction &MF, OperatingMode Mode, MachineLoopInfo *MLI=nullptr)
Construct with explicit operating mode.
static AMDGPU::CoExecMaskT getCoExecMaskForMI(const MachineInstr &MI, const SIInstrInfo &TII)
Get the CoExecMask for a given instruction.
HazardType getHazardType(SUnit *SU, int Stalls) override
getHazardType - Return the hazard type of emitting this node.
void RecedeCycle() override
RecedeCycle - This callback is invoked whenever the next bottom-up instruction to be scheduled cannot...
bool isHazardRecognizerMode() const
Returns true if running as the standalone hazard recognizer pass.
bool isPreRA() const
Returns true if running in pre-RA scheduling mode.
BlockT * getLoopPreheader() const
If there is a preheader for this loop, return it.
LoopT * getParentLoop() const
Return the parent loop if it exists or nullptr for top level loops.
Wrapper class representing physical registers. Should be passed by value.
Instructions::const_reverse_iterator const_reverse_instr_iterator
LLVM_ABI iterator getFirstTerminator()
Returns an iterator to the first terminator instruction of this basic block.
Instructions::iterator instr_iterator
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
iterator_range< pred_iterator > predecessors()
MachineInstrBundleIterator< MachineInstr > iterator
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineBasicBlock & front() const
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & addDef(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register definition operand.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
bool readsRegister(Register Reg, const TargetRegisterInfo *TRI) const
Return true if the MachineInstr reads the specified register.
bool isBundled() const
Return true if this instruction part of a bundle.
MachineOperand class - Representation of each machine instruction operand.
void setImm(int64_t immVal)
bool isReg() const
isReg - Tests if this is a MO_Register operand.
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
void setIsKill(bool Val=true)
void setIsUndef(bool Val=true)
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI bool isConstantPhysReg(MCRegister PhysReg) const
Returns true if PhysReg is unallocatable and constant throughout the function.
LLVM_ABI bool isPhysRegUsed(MCRegister PhysReg, bool SkipRegMaskTest=false) const
Return true if the specified register is modified or read in this function.
Wrapper class representing virtual and physical registers.
static bool isDS(const MachineInstr &MI)
static bool isVMEM(const MachineInstr &MI)
static bool isSMRD(const MachineInstr &MI)
static bool isMTBUF(const MachineInstr &MI)
static bool isDGEMM(unsigned Opcode)
static bool isEXP(const MachineInstr &MI)
static bool isSALU(const MachineInstr &MI)
static bool isSDWA(const MachineInstr &MI)
static bool isDOT(const MachineInstr &MI)
static bool usesTENSOR_CNT(const MachineInstr &MI)
static bool isSWMMAC(const MachineInstr &MI)
static bool isLDSDIR(const MachineInstr &MI)
static bool isVPermPk16(unsigned Opcode)
static bool isVALU(const MachineInstr &MI, bool AllowLDSDMA)
static bool isTRANS(const MachineInstr &MI)
static bool isMUBUF(const MachineInstr &MI)
static bool isWaitcnt(unsigned Opcode)
static bool isVOP3(const MCInstrDesc &Desc)
static bool isDPP(const MachineInstr &MI)
static bool isMFMA(const MachineInstr &MI)
static bool isMAI(const MCInstrDesc &Desc)
static bool isFPAtomic(const MachineInstr &MI)
static bool isMIMG(const MachineInstr &MI)
static unsigned getNumWaitStates(const MachineInstr &MI)
Return the number of wait states that result from executing this instruction.
static bool isVOP3P(const MachineInstr &MI)
static bool isWMMA(const MachineInstr &MI)
static bool isLDSDMA(const MachineInstr &MI)
unsigned getOccupancy() const
Scheduling unit. This is a node in the scheduling DAG.
bool isInstr() const
Returns true if this SUnit refers to a machine instruction as opposed to an SDNode.
MachineInstr * getInstr() const
Returns the representative MachineInstr for this SUnit.
unsigned getMaxLookAhead() const
unsigned MaxLookAhead
MaxLookAhead - Indicate the number of cycles in the scoreboard state.
virtual void EmitNoops(unsigned Quantity)
EmitNoops - This callback is invoked when noops were added to the instruction stream.
size_type size() const
Determine the number of elements in the SetVector.
bool insert(const value_type &X)
Insert a new element into the SetVector.
A SetVector that performs no allocations if smaller than a certain size.
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
bool getAsInteger(unsigned Radix, T &Result) const
Parse the current string as an integer of the specified radix.
Provide an instruction scheduling machine model to CodeGen passes.
std::pair< iterator, bool > insert(const ValueT &V)
An efficient, type-erasing, non-owning reference to a callable.
self_iterator getIterator()
A range adaptor for a pair of iterators.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned encodeFieldVaVcc(unsigned Encoded, unsigned VaVcc)
unsigned encodeFieldVaVdst(unsigned Encoded, unsigned VaVdst)
unsigned decodeFieldSaSdst(unsigned Encoded)
unsigned decodeFieldVaSdst(unsigned Encoded)
unsigned encodeFieldVmVsrc(unsigned Encoded, unsigned VmVsrc)
unsigned encodeFieldSaSdst(unsigned Encoded, unsigned SaSdst)
unsigned decodeFieldVaVdst(unsigned Encoded)
unsigned decodeFieldVmVsrc(unsigned Encoded)
unsigned encodeFieldVaSdst(unsigned Encoded, unsigned VaSdst)
const char * getCoExecMaskName(CoExecMaskT Mask)
Return a human-readable name for a mask holding a single instruction class, as produced by getCoExecM...
LLVM_READONLY const MIMGInfo * getMIMGInfo(unsigned Opc)
StringRef getSchedStrategy(const Function &F)
constexpr unsigned MaxCoExecStages
Max stages: INT8 16x16x64 = 17 cycles, round up for safety.
FPType getFPDstSelType(unsigned Opc)
bool isGFX12Plus(const MCSubtargetInfo &STI)
const char * getStageTypeName(CoExecStageType T)
LLVM_ABI IsaVersion getIsaVersion(StringRef GPU)
unsigned getRegBitWidth(unsigned RCID)
Get the size in bits of a register from the register class RC.
LLVM_READONLY int32_t getMFMAEarlyClobberOp(uint32_t Opcode)
Waitcnt decodeWaitcnt(const IsaVersion &Version, unsigned Encoded)
CoExecInfo getCoExecInfo(const MachineInstr &MI, const SIInstrInfo &TII)
Get co-execution info for a WMMA instruction, selecting the per-cycle slot pattern from the opcode (a...
LLVM_READONLY bool hasNamedOperand(uint32_t Opcode, OpName NamedIdx)
LLVM_READONLY int32_t getAGPRFormOp(uint32_t Opcode)
InstructionFlavor classifyFlavor(const MachineInstr &MI, const SIInstrInfo &SII)
Classify MI into the execution flavor that drives both the scheduler's slot preferences and the hazar...
CoExecMaskT getCoExecMask(InstructionFlavor F)
Map a flavor to the co-execution class it occupies in a window slot.
bool isGFX1250(const MCSubtargetInfo &STI)
@ AMDGPU_CS
Used for Mesa/AMDPAL compute shaders.
@ AMDGPU_KERNEL
Used for AMDGPU code object kernels.
@ AMDGPU_Gfx
Used for AMD graphics targets.
@ AMDGPU_CS_ChainPreserve
Used on AMDGPUs to give the middle-end more control over argument placement.
@ AMDGPU_CS_Chain
Used on AMDGPUs to give the middle-end more control over argument placement.
This namespace contains all of the command line option processing machinery.
initializer< Ty > init(const Ty &Val)
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
NodeAddr< DefNode * > Def
NodeAddr< UseNode * > Use
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.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
@ Kill
The last use of a register.
@ Undef
Value of the register doesn't matter.
@ Define
Register definition.
constexpr RegState getDeadRegState(bool B)
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
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.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Next
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
@ End
Run the machine verifier once, at the end of the pipeline.
LLVM_ABI Printable printMBBReference(const MachineBasicBlock &MBB)
Prints a machine basic block reference.
hash_code hash_combine_range(InputIteratorT first, InputIteratorT last)
Compute a hash_code for a sequence of values.
Co-execution characteristics for a multi-cycle instruction.
static std::tuple< typename Fields::ValueType... > decode(uint64_t Encoded)
An information struct used to provide DenseMap with the various necessary components for a given valu...