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) {
1133 if (
I->isInlineAsm())
1136 WaitStates += GetNumWaitStates(*
I);
1138 if (IsExpired(*
I, WaitStates))
1139 return std::numeric_limits<int>::max();
1142 int MinWaitStates = std::numeric_limits<int>::max();
1144 if (!Visited.
insert(Pred).second)
1148 IsExpired, Visited, GetNumWaitStates);
1150 MinWaitStates = std::min(MinWaitStates, W);
1153 return MinWaitStates;
1164 std::next(
MI->getReverseIterator()), 0, IsExpired,
1165 Visited, GetNumWaitStates);
1168int GCNHazardRecognizer::getMaxWindowDeficit(
int MaxWindow,
1169 WindowForFn WindowFor)
const {
1171 return WindowDeficitSearch(WindowFor, MaxWindow).run(*CurrCycleInstr);
1175 int Deficit = 0, Distance = 0;
1176 for (MachineInstr *
MI : EmittedInstrs) {
1178 if (std::optional<int> Window = WindowFor(*
MI)) {
1179 assert(*Window >= 0 && *Window <= MaxWindow &&
"window out of bounds");
1180 Deficit = std::max(Deficit, *Window - Distance);
1187 if (Distance >= MaxWindow)
1193int GCNHazardRecognizer::getWaitStatesSince(
1194 IsHazardFn IsHazard,
int Limit, GetNumWaitStatesFn GetNumWaitStates)
const {
1196 auto IsExpiredFn = [Limit](
const MachineInstr &,
int WaitStates) {
1197 return WaitStates >= Limit;
1199 return ::getWaitStatesSince(IsHazard, CurrCycleInstr,
IsExpiredFn,
1204 for (MachineInstr *
MI : EmittedInstrs) {
1209 if (
MI->isInlineAsm())
1212 WaitStates +=
MI ? GetNumWaitStates(*
MI) : 1;
1214 if (WaitStates >= Limit)
1217 return std::numeric_limits<int>::max();
1220int GCNHazardRecognizer::getWaitStatesSince(IsHazardFn IsHazard,
1225int GCNHazardRecognizer::getMaxVALUWindowDeficit(
int MaxWindow,
1226 WindowForFn WindowFor)
const {
1228 auto GetVALUWaitStates = [](
const MachineInstr &
MI) ->
unsigned {
1231 return WindowDeficitSearch(WindowFor, MaxWindow, GetVALUWaitStates)
1232 .run(*CurrCycleInstr);
1238 assert(MaxWindow <=
static_cast<int>(MaxVALULookAhead) &&
1239 "MaxWindow exceeds the EmittedVALUInstrs lookahead window");
1241 for (MachineInstr *
MI : EmittedVALUInstrs) {
1243 if (std::optional<int> Window = WindowFor(*
MI)) {
1244 assert(*Window >= 0 && *Window <= MaxWindow &&
"window out of bounds");
1245 return *Window - WaitStates;
1251 if (WaitStates >= MaxWindow)
1257int GCNHazardRecognizer::getWaitStatesSinceDef(
unsigned Reg,
1258 IsHazardFn IsHazardDef,
1260 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1263 return IsHazardDef(
MI) &&
MI.modifiesRegister(
Reg, TRI);
1266 return getWaitStatesSince(
IsHazardFn, Limit);
1269int GCNHazardRecognizer::getWaitStatesSinceSetReg(IsHazardFn IsHazard,
1275 return getWaitStatesSince(
IsHazardFn, Limit);
1284 for (MCRegUnit Unit :
TRI.regunits(
Reg))
1285 BV.
set(
static_cast<unsigned>(Unit));
1297void GCNHazardRecognizer::addClauseInst(
const MachineInstr &
MI)
const {
1309int GCNHazardRecognizer::checkSoftClauseHazards(
MachineInstr *MEM)
const {
1312 if (!ST.isXNACKEnabled())
1315 bool IsSMRD = TII.isSMRD(*MEM);
1329 for (MachineInstr *
MI : EmittedInstrs) {
1341 if (ClauseDefs.none())
1347 if (
MEM->mayStore())
1350 addClauseInst(*MEM);
1354 return ClauseDefs.anyCommon(ClauseUses) ? 1 : 0;
1357int GCNHazardRecognizer::checkSMRDHazards(
MachineInstr *SMRD)
const {
1358 int WaitStatesNeeded = 0;
1360 WaitStatesNeeded = checkSoftClauseHazards(SMRD);
1363 if (!ST.hasSMRDReadVALUDefHazard())
1364 return WaitStatesNeeded;
1368 int SmrdSgprWaitStates = 4;
1369 auto IsHazardDefFn = [
this](
const MachineInstr &
MI) {
1370 return TII.isVALU(
MI,
true);
1372 auto IsBufferHazardDefFn = [
this](
const MachineInstr &
MI) {
1373 return TII.isSALU(
MI);
1376 bool IsBufferSMRD = TII.isBufferSMRD(*SMRD);
1378 for (
const MachineOperand &Use :
SMRD->uses()) {
1381 int WaitStatesNeededForUse =
1382 SmrdSgprWaitStates - getWaitStatesSinceDef(
Use.getReg(), IsHazardDefFn,
1383 SmrdSgprWaitStates);
1384 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1394 int WaitStatesNeededForUse =
1395 SmrdSgprWaitStates - getWaitStatesSinceDef(
Use.getReg(),
1396 IsBufferHazardDefFn,
1397 SmrdSgprWaitStates);
1398 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1402 return WaitStatesNeeded;
1405int GCNHazardRecognizer::checkVMEMHazards(
MachineInstr *VMEM)
const {
1406 if (!ST.hasVMEMReadSGPRVALUDefHazard())
1409 int WaitStatesNeeded = checkSoftClauseHazards(VMEM);
1413 const int VmemSgprWaitStates = 5;
1414 auto IsHazardDefFn = [
this](
const MachineInstr &
MI) {
1415 return TII.isVALU(
MI,
true);
1417 for (
const MachineOperand &Use :
VMEM->uses()) {
1418 if (!
Use.isReg() || TRI.isVectorRegister(MF.getRegInfo(),
Use.getReg()))
1421 int WaitStatesNeededForUse =
1422 VmemSgprWaitStates - getWaitStatesSinceDef(
Use.getReg(), IsHazardDefFn,
1423 VmemSgprWaitStates);
1424 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1426 return WaitStatesNeeded;
1430 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1431 const SIInstrInfo *TII = ST.getInstrInfo();
1434 int DppVgprWaitStates = 2;
1435 int DppExecWaitStates = 5;
1436 int WaitStatesNeeded = 0;
1437 auto IsHazardDefFn = [TII](
const MachineInstr &
MI) {
1438 return TII->isVALU(
MI,
true);
1441 for (
const MachineOperand &Use :
DPP->uses()) {
1442 if (!
Use.isReg() || !TRI->isVGPR(MF.getRegInfo(),
Use.getReg()))
1444 int WaitStatesNeededForUse =
1445 DppVgprWaitStates - getWaitStatesSinceDef(
1447 [](
const MachineInstr &) { return true; },
1449 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1452 WaitStatesNeeded = std::max(
1454 DppExecWaitStates - getWaitStatesSinceDef(AMDGPU::EXEC, IsHazardDefFn,
1455 DppExecWaitStates));
1457 return WaitStatesNeeded;
1460int GCNHazardRecognizer::checkDivFMasHazards(
MachineInstr *DivFMas)
const {
1461 const SIInstrInfo *TII = ST.getInstrInfo();
1465 const int DivFMasWaitStates = 4;
1466 auto IsHazardDefFn = [TII](
const MachineInstr &
MI) {
1467 return TII->isVALU(
MI,
true);
1469 int WaitStatesNeeded = getWaitStatesSinceDef(AMDGPU::VCC, IsHazardDefFn,
1472 return DivFMasWaitStates - WaitStatesNeeded;
1475int GCNHazardRecognizer::checkGetRegHazards(
MachineInstr *GetRegInstr)
const {
1476 const SIInstrInfo *TII = ST.getInstrInfo();
1477 unsigned GetRegHWReg =
getHWReg(TII, *GetRegInstr);
1479 const int GetRegWaitStates = 2;
1480 auto IsHazardFn = [TII, GetRegHWReg](
const MachineInstr &
MI) {
1483 int WaitStatesNeeded = getWaitStatesSinceSetReg(
IsHazardFn, GetRegWaitStates);
1485 return GetRegWaitStates - WaitStatesNeeded;
1488int GCNHazardRecognizer::checkSetRegHazards(
MachineInstr *SetRegInstr)
const {
1489 const SIInstrInfo *TII = ST.getInstrInfo();
1490 unsigned HWReg =
getHWReg(TII, *SetRegInstr);
1492 const int SetRegWaitStates = ST.getSetRegWaitStates();
1493 auto IsHazardFn = [TII, HWReg](
const MachineInstr &
MI) {
1496 int WaitStatesNeeded = getWaitStatesSinceSetReg(
IsHazardFn, SetRegWaitStates);
1497 return SetRegWaitStates - WaitStatesNeeded;
1500int GCNHazardRecognizer::createsVALUHazard(
const MachineInstr &
MI)
const {
1504 const SIInstrInfo *TII = ST.getInstrInfo();
1505 unsigned Opcode =
MI.getOpcode();
1506 const MCInstrDesc &
Desc =
MI.getDesc();
1508 int VDataIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::vdata);
1511 VDataRCID = TII->getOpRegClassID(
Desc.operands()[VDataIdx]);
1513 if (TII->isMUBUF(
MI) || TII->isMTBUF(
MI)) {
1523 if (ST.hasVDecCoExecHazard())
1525 const MachineOperand *SOffset =
1526 TII->getNamedOperand(
MI, AMDGPU::OpName::soffset);
1527 if (!SOffset || !SOffset->
isReg())
1536 if (TII->isMIMG(
MI)) {
1537 int SRsrcIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::srsrc);
1539 Desc.operands()[SRsrcIdx])) == 256);
1543 if (TII->isFLAT(
MI)) {
1555int GCNHazardRecognizer::checkUniformWindowVALUHazardsHelper(
1560 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1562 auto IsHazard = [&](
const MachineInstr &
MI) {
1563 int DataIdx = createsVALUHazard(
MI);
1564 return DataIdx >= 0 &&
1565 TRI->regsOverlap(
MI.getOperand(DataIdx).getReg(),
Reg);
1568 return std::max(0, 1 - getWaitStatesSince(IsHazard, 1));
1571int GCNHazardRecognizer::checkSOFFSETWindowVALUHazardsHelper(
1578 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1579 const SIInstrInfo *TII = ST.getInstrInfo();
1581 int WaitStatesNeeded = 0;
1585 for (
int Window = 1; Window <= 2; ++Window) {
1586 auto IsHazard = [&](
const MachineInstr &
MI) {
1587 int DataIdx = createsVALUHazard(
MI);
1589 !TRI->regsOverlap(
MI.getOperand(DataIdx).getReg(),
Reg))
1594 if (Window == 1 || !TII->isBUF(
MI))
1597 const MachineOperand *SOffset =
1598 TII->getNamedOperand(
MI, AMDGPU::OpName::soffset);
1599 return !SOffset || !SOffset->
isReg();
1601 WaitStatesNeeded = std::max(WaitStatesNeeded,
1602 Window - getWaitStatesSince(IsHazard, Window));
1605 return WaitStatesNeeded;
1608int GCNHazardRecognizer::checkVALUHazardsHelper(
1613 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1615 if (!TRI->isVectorRegister(MRI,
Def.getReg()))
1618 if (ST.hasVDecCoExecHazard())
1619 return checkSOFFSETWindowVALUHazardsHelper(
Def.getReg());
1621 return checkUniformWindowVALUHazardsHelper(
Def.getReg());
1637 unsigned Opcode =
MI.getOpcode();
1647 if (
auto *DstSel =
TII->getNamedOperand(
MI, AMDGPU::OpName::dst_sel))
1649 return TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
1657 (
TII->getNamedImmOperand(
MI, AMDGPU::OpName::src0_modifiers) &
1659 return TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
1667 return TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
1671 (
TII->getNamedImmOperand(
MI, AMDGPU::OpName::src2_modifiers) &
1673 return TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
1679 return TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
1700 for (
auto &Operand : VALU->operands()) {
1701 if (Operand.isReg() &&
TRI->regsOverlap(Dst->getReg(), Operand.getReg())) {
1708int GCNHazardRecognizer::checkVALUHazards(
MachineInstr *VALU)
const {
1709 int WaitStatesNeeded = 0;
1712 const int TransDefWaitstates = 1;
1714 auto IsTransDefFn = [
this,
VALU](
const MachineInstr &
MI) {
1717 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1718 const SIInstrInfo *TII = ST.getInstrInfo();
1719 Register Def = TII->getNamedOperand(
MI, AMDGPU::OpName::vdst)->getReg();
1721 for (
const MachineOperand &Use :
VALU->explicit_uses()) {
1722 if (
Use.isReg() && TRI->regsOverlap(Def,
Use.getReg()))
1729 int WaitStatesNeededForDef =
1730 TransDefWaitstates -
1731 getWaitStatesSince(IsTransDefFn, TransDefWaitstates);
1732 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1735 if (ST.hasDstSelForwardingHazard() || ST.hasCvtScaleForwardingHazard()) {
1736 const int Shift16DefWaitstates = 1;
1738 auto IsShift16BitDefFn = [
this,
VALU](
const MachineInstr &ProducerMI) {
1739 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1740 const MachineOperand *ForwardedDst =
1746 if (ProducerMI.isInlineAsm()) {
1748 for (
auto &Def : ProducerMI.all_defs()) {
1757 int WaitStatesNeededForDef =
1758 Shift16DefWaitstates -
1759 getWaitStatesSince(IsShift16BitDefFn, Shift16DefWaitstates);
1760 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1763 if (ST.hasVDecCoExecHazard()) {
1764 const int VALUWriteSGPRVALUReadWaitstates = 2;
1765 const int VALUWriteEXECRWLane = 4;
1766 const int VALUWriteVGPRReadlaneRead = 1;
1768 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1769 const MachineRegisterInfo &MRI = MF.getRegInfo();
1771 auto IsVALUDefSGPRFn = [&
UseReg, TRI](
const MachineInstr &
MI) {
1774 return MI.modifiesRegister(
UseReg, TRI);
1777 for (
const MachineOperand &Use :
VALU->explicit_uses()) {
1782 if (TRI->isSGPRReg(MRI,
UseReg)) {
1783 int WaitStatesNeededForDef =
1784 VALUWriteSGPRVALUReadWaitstates -
1785 getWaitStatesSince(IsVALUDefSGPRFn,
1786 VALUWriteSGPRVALUReadWaitstates);
1787 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1791 if (
VALU->readsRegister(AMDGPU::VCC, TRI)) {
1793 int WaitStatesNeededForDef =
1794 VALUWriteSGPRVALUReadWaitstates -
1795 getWaitStatesSince(IsVALUDefSGPRFn, VALUWriteSGPRVALUReadWaitstates);
1796 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1799 switch (
VALU->getOpcode()) {
1800 case AMDGPU::V_READLANE_B32:
1801 case AMDGPU::V_READFIRSTLANE_B32: {
1802 MachineOperand *Src = TII.getNamedOperand(*VALU, AMDGPU::OpName::src0);
1804 int WaitStatesNeededForDef =
1805 VALUWriteVGPRReadlaneRead -
1806 getWaitStatesSince(IsVALUDefSGPRFn, VALUWriteVGPRReadlaneRead);
1807 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1810 case AMDGPU::V_WRITELANE_B32: {
1812 int WaitStatesNeededForDef =
1813 VALUWriteEXECRWLane -
1814 getWaitStatesSince(IsVALUDefSGPRFn, VALUWriteEXECRWLane);
1815 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1825 if (!ST.has12DWordStoreHazard())
1826 return WaitStatesNeeded;
1828 const MachineRegisterInfo &MRI = MF.getRegInfo();
1830 for (
const MachineOperand &Def :
VALU->defs()) {
1831 WaitStatesNeeded = std::max(WaitStatesNeeded, checkVALUHazardsHelper(Def, MRI));
1834 return WaitStatesNeeded;
1837int GCNHazardRecognizer::checkInlineAsmHazards(
MachineInstr *IA)
const {
1846 if (!ST.has12DWordStoreHazard() && !ST.hasDstSelForwardingHazard() &&
1847 !ST.hasCvtScaleForwardingHazard())
1850 const MachineRegisterInfo &MRI = MF.getRegInfo();
1851 int WaitStatesNeeded = 0;
1853 for (
const MachineOperand &
Op :
1855 if (
Op.isReg() &&
Op.isDef()) {
1856 if (!TRI.isVectorRegister(MRI,
Op.getReg()))
1859 if (ST.has12DWordStoreHazard()) {
1861 std::max(WaitStatesNeeded, checkVALUHazardsHelper(
Op, MRI));
1866 if (ST.hasDstSelForwardingHazard()) {
1867 const int Shift16DefWaitstates = 1;
1869 auto IsShift16BitDefFn = [
this, &
IA](
const MachineInstr &ProducerMI) {
1873 return IA->modifiesRegister(Dst->getReg(), &TRI) ||
1874 IA->readsRegister(Dst->getReg(), &TRI);
1876 if (ProducerMI.isInlineAsm()) {
1878 for (
auto &Def : ProducerMI.all_defs()) {
1879 if (
IA->modifiesRegister(
Def.getReg(), &TRI) ||
1880 IA->readsRegister(
Def.getReg(), &TRI)) {
1889 int WaitStatesNeededForDef =
1890 Shift16DefWaitstates -
1891 getWaitStatesSince(IsShift16BitDefFn, Shift16DefWaitstates);
1892 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1895 return WaitStatesNeeded;
1898int GCNHazardRecognizer::checkRWLaneHazards(
MachineInstr *RWLane)
const {
1899 const SIInstrInfo *TII = ST.getInstrInfo();
1900 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1901 const MachineRegisterInfo &MRI = MF.getRegInfo();
1903 const MachineOperand *LaneSelectOp =
1904 TII->getNamedOperand(*RWLane, AMDGPU::OpName::src1);
1906 if (!LaneSelectOp->
isReg() || !TRI->isSGPRReg(MRI, LaneSelectOp->
getReg()))
1911 return TII->isVALU(
MI,
true);
1914 const int RWLaneWaitStates = 4;
1915 int WaitStatesSince = getWaitStatesSinceDef(LaneSelectReg,
IsHazardFn,
1917 return RWLaneWaitStates - WaitStatesSince;
1920int GCNHazardRecognizer::checkRFEHazards(
MachineInstr *RFE)
const {
1921 if (!ST.hasRFEHazards())
1924 const SIInstrInfo *TII = ST.getInstrInfo();
1926 const int RFEWaitStates = 1;
1931 int WaitStatesNeeded = getWaitStatesSinceSetReg(
IsHazardFn, RFEWaitStates);
1932 return RFEWaitStates - WaitStatesNeeded;
1935int GCNHazardRecognizer::checkReadM0Hazards(
MachineInstr *
MI)
const {
1936 const SIInstrInfo *TII = ST.getInstrInfo();
1937 const int ReadM0WaitStates = 1;
1938 auto IsHazardFn = [TII](
const MachineInstr &
MI) {
return TII->isSALU(
MI); };
1939 return ReadM0WaitStates -
1940 getWaitStatesSinceDef(AMDGPU::M0,
IsHazardFn, ReadM0WaitStates);
1945 int WaitStatesNeeded,
bool IsHoisting) {
1947 for (
int I = 0;
I < WaitStatesNeeded; ++
I)
1948 BuildMI(
MBB, InsertPt,
DL, TII.get(AMDGPU::V_NOP_e32));
1952 fixVMEMtoScalarWriteHazards(
MI);
1953 fixVcmpxPermlaneHazards(
MI);
1954 fixSMEMtoVectorWriteHazards(
MI);
1955 fixVcmpxExecWARHazard(
MI);
1956 fixLdsBranchVmemWARHazard(
MI);
1957 if (ST.hasLdsDirect()) {
1958 fixLdsDirectVALUHazard(
MI);
1959 fixLdsDirectVMEMHazard(
MI);
1961 fixVALUPartialForwardingHazard(
MI);
1962 fixVALUTransUseHazard(
MI);
1963 fixVALUTransCoexecutionHazards(
MI);
1965 fixWMMACoexecutionHazards(
MI);
1966 fixShift64HighRegBug(
MI);
1967 fixPkF32InvalidOpSel(
MI);
1968 fixVALUMaskWriteHazard(
MI);
1969 fixRequiredExportPriority(
MI);
1970 if (ST.hasVPermPk16Hazard())
1971 fixVPermPk16Hazard(
MI);
1972 if (ST.requiresWaitIdleBeforeGetReg())
1973 fixGetRegWaitIdle(
MI);
1974 if (ST.hasDsAtomicAsyncBarrierArriveB64PipeBug())
1975 fixDsAtomicAsyncBarrierArriveB64(
MI);
1976 if (ST.hasScratchBaseForwardingHazard())
1977 fixScratchBaseForwardingHazard(
MI);
1978 if (ST.setRegModeNeedsVNOPs())
1980 if (ST.hasNeedsTDMDrain())
1986 return (
TII.isVOPC(
MI) ||
1987 (
MI.isCompare() && (
TII.isVOP3(
MI) ||
TII.isSDWA(
MI)))) &&
1988 MI.modifiesRegister(AMDGPU::EXEC, &
TRI);
1991bool GCNHazardRecognizer::fixVcmpxPermlaneHazards(
MachineInstr *
MI) {
1995 const SIInstrInfo *TII = ST.getInstrInfo();
1996 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2002 unsigned Opc =
MI.getOpcode();
2004 Opc != AMDGPU::V_NOP_e32 &&
Opc != AMDGPU::V_NOP_e64 &&
2005 Opc != AMDGPU::V_NOP_sdwa;
2009 std::numeric_limits<int>::max())
2015 auto *
Src0 = TII->getNamedOperand(*
MI, AMDGPU::OpName::src0);
2017 bool IsUndef =
Src0->isUndef();
2019 TII->get(AMDGPU::V_MOV_B32_e32))
2026bool GCNHazardRecognizer::fixVMEMtoScalarWriteHazards(
MachineInstr *
MI) {
2027 if (!ST.hasVMEMtoScalarWriteHazard())
2029 assert(!ST.hasExtendedWaitCounts());
2034 if (
MI->getNumDefs() == 0)
2037 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2043 for (
const MachineOperand &Def :
MI->defs()) {
2044 const MachineOperand *
Op =
2045 I.findRegisterUseOperand(
Def.getReg(), TRI,
false);
2055 (
MI.getOpcode() == AMDGPU::S_WAITCNT &&
2056 !
MI.getOperand(0).getImm()) ||
2057 (
MI.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2059 static_cast<unsigned>(
MI.getOperand(0).getImm())) == 0);
2063 std::numeric_limits<int>::max())
2066 const SIInstrInfo *TII = ST.getInstrInfo();
2068 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
2073bool GCNHazardRecognizer::fixSMEMtoVectorWriteHazards(
MachineInstr *
MI) {
2074 if (!ST.hasSMEMtoVectorWriteHazard())
2076 assert(!ST.hasExtendedWaitCounts());
2081 AMDGPU::OpName SDSTName;
2082 switch (
MI->getOpcode()) {
2083 case AMDGPU::V_READLANE_B32:
2084 case AMDGPU::V_READFIRSTLANE_B32:
2085 SDSTName = AMDGPU::OpName::vdst;
2088 SDSTName = AMDGPU::OpName::sdst;
2092 const SIInstrInfo *TII = ST.getInstrInfo();
2093 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2095 const MachineOperand *SDST = TII->getNamedOperand(*
MI, SDSTName);
2097 for (
const auto &MO :
MI->implicit_operands()) {
2098 if (MO.isDef() && TRI->isSGPRClass(TRI->getPhysRegBaseClass(MO.getReg()))) {
2109 auto IsHazardFn = [SDSTReg, TRI](
const MachineInstr &
I) {
2114 if (TII->isSALU(
MI)) {
2115 switch (
MI.getOpcode()) {
2116 case AMDGPU::S_SETVSKIP:
2117 case AMDGPU::S_VERSION:
2118 case AMDGPU::S_WAITCNT_VSCNT:
2119 case AMDGPU::S_WAITCNT_VMCNT:
2120 case AMDGPU::S_WAITCNT_EXPCNT:
2123 case AMDGPU::S_WAITCNT_LGKMCNT:
2125 return (
MI.getOperand(1).getImm() == 0) &&
2126 (
MI.getOperand(0).
getReg() == AMDGPU::SGPR_NULL);
2127 case AMDGPU::S_WAITCNT: {
2128 const int64_t
Imm =
MI.getOperand(0).getImm();
2129 AMDGPU::Waitcnt Decoded =
2136 MI.getOpcode() == AMDGPU::S_WAIT_IDLE) &&
2137 "unexpected wait count instruction");
2139 if (TII->isSOPP(
MI))
2155 std::numeric_limits<int>::max())
2159 TII->get(AMDGPU::S_MOV_B32), AMDGPU::SGPR_NULL)
2164bool GCNHazardRecognizer::fixVcmpxExecWARHazard(
MachineInstr *
MI) {
2165 if (!ST.hasVcmpxExecWARHazard())
2167 assert(!ST.hasExtendedWaitCounts());
2172 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2173 if (!
MI->modifiesRegister(AMDGPU::EXEC, TRI))
2179 return I.readsRegister(AMDGPU::EXEC, TRI);
2182 const SIInstrInfo *TII = ST.getInstrInfo();
2183 auto IsExpiredFn = [TII, TRI](
const MachineInstr &
MI, int) {
2185 if (TII->getNamedOperand(
MI, AMDGPU::OpName::sdst))
2187 for (
auto MO :
MI.implicit_operands())
2188 if (MO.isDef() && TRI->isSGPRClass(TRI->getPhysRegBaseClass(MO.getReg())))
2191 if (
MI.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2193 static_cast<unsigned>(
MI.getOperand(0).getImm())) == 0)
2199 std::numeric_limits<int>::max())
2203 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
2210 if (!ST.hasLdsBranchVmemWARHazard())
2215 bool HasLds =
false;
2216 bool HasVmem =
false;
2217 for (
auto &
MBB : MF) {
2218 for (
auto &
MI :
MBB) {
2221 if (HasLds && HasVmem)
2229 return I.getOpcode() == AMDGPU::S_WAITCNT_VSCNT &&
2230 I.getOperand(0).getReg() == AMDGPU::SGPR_NULL &&
2231 !
I.getOperand(1).getImm();
2234bool GCNHazardRecognizer::fixLdsBranchVmemWARHazard(
MachineInstr *
MI) {
2235 if (!RunLdsBranchVmemWARHazardFixup)
2238 assert(ST.hasLdsBranchVmemWARHazard());
2239 assert(!ST.hasExtendedWaitCounts());
2241 auto IsHazardInst = [](
const MachineInstr &
MI) {
2249 auto InstType = IsHazardInst(*
MI);
2253 auto IsExpiredFn = [&IsHazardInst](
const MachineInstr &
I, int) {
2257 auto IsHazardFn = [InstType, &IsHazardInst](
const MachineInstr &
I) {
2261 auto IsHazardFn = [InstType, IsHazardInst](
const MachineInstr &
I) {
2262 auto InstType2 = IsHazardInst(
I);
2263 return InstType2 && InstType != InstType2;
2266 auto IsExpiredFn = [InstType, &IsHazardInst](
const MachineInstr &
I, int) {
2267 auto InstType2 = IsHazardInst(
I);
2268 if (InstType == InstType2)
2275 std::numeric_limits<int>::max();
2279 std::numeric_limits<int>::max())
2282 const SIInstrInfo *TII = ST.getInstrInfo();
2284 TII->get(AMDGPU::S_WAITCNT_VSCNT))
2291bool GCNHazardRecognizer::fixLdsDirectVALUHazard(
MachineInstr *
MI) {
2295 const int NoHazardWaitStates = 15;
2296 const MachineOperand *VDST = TII.getNamedOperand(*
MI, AMDGPU::OpName::vdst);
2299 bool VisitedTrans =
false;
2300 auto IsHazardFn = [
this, VDSTReg, &VisitedTrans](
const MachineInstr &
I) {
2305 return I.readsRegister(VDSTReg, &TRI) ||
I.modifiesRegister(VDSTReg, &TRI);
2307 auto IsExpiredFn = [&](
const MachineInstr &
I,
int WaitStates) {
2308 if (WaitStates >= NoHazardWaitStates)
2314 auto GetWaitStatesFn = [](
const MachineInstr &
MI) {
2318 DenseSet<const MachineBasicBlock *> Visited;
2320 std::next(
MI->getReverseIterator()), 0,
2328 MachineOperand *WaitVdstOp =
2329 TII.getNamedOperand(*
MI, AMDGPU::OpName::waitvdst);
2330 WaitVdstOp->
setImm(std::min(
Count, NoHazardWaitStates));
2335bool GCNHazardRecognizer::fixLdsDirectVMEMHazard(
MachineInstr *
MI) {
2339 const MachineOperand *VDST = TII.getNamedOperand(*
MI, AMDGPU::OpName::vdst);
2342 auto IsHazardFn = [
this, VDSTReg](
const MachineInstr &
I) {
2345 return I.readsRegister(VDSTReg, &TRI) ||
I.modifiesRegister(VDSTReg, &TRI);
2347 bool LdsdirCanWait = ST.hasLdsWaitVMSRC();
2350 auto IsExpiredFn = [
this, LdsdirCanWait](
const MachineInstr &
I, int) {
2353 (
I.getOpcode() == AMDGPU::S_WAITCNT && !
I.getOperand(0).getImm()) ||
2354 (
I.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2356 static_cast<unsigned>(
I.getOperand(0).getImm())) == 0) ||
2358 !TII.getNamedOperand(
I, AMDGPU::OpName::waitvsrc)->getImm());
2362 std::numeric_limits<int>::max())
2365 if (LdsdirCanWait) {
2366 TII.getNamedOperand(*
MI, AMDGPU::OpName::waitvsrc)->setImm(0);
2369 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
2376bool GCNHazardRecognizer::fixVALUPartialForwardingHazard(
MachineInstr *
MI) {
2377 if (!ST.hasVALUPartialForwardingHazard())
2379 assert(!ST.hasExtendedWaitCounts());
2384 SmallSetVector<Register, 4> SrcVGPRs;
2386 for (
const MachineOperand &Use :
MI->explicit_uses()) {
2387 if (
Use.isReg() && TRI.isVGPR(MF.getRegInfo(),
Use.getReg()))
2392 if (SrcVGPRs.
size() <= 1)
2410 const int Intv1plus2MaxVALUs = 2;
2411 const int Intv3MaxVALUs = 4;
2412 const int IntvMaxVALUs = 6;
2413 const int NoHazardVALUWaitStates = IntvMaxVALUs + 2;
2416 SmallDenseMap<Register, int, 4> DefPos;
2417 int ExecPos = std::numeric_limits<int>::max();
2420 static unsigned getHashValue(
const StateType &State) {
2422 for (
const auto &[
Reg, Pos] : State.DefPos)
2424 return static_cast<unsigned>(
H);
2426 static bool isEqual(
const StateType &
LHS,
const StateType &
RHS) {
2427 return LHS.DefPos ==
RHS.DefPos &&
LHS.ExecPos ==
RHS.ExecPos &&
2435 auto IsHazardFn = [&,
this](StateType &State,
const MachineInstr &
I) {
2437 if (State.VALUs > NoHazardVALUWaitStates)
2443 (
I.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2445 static_cast<unsigned>(
I.getOperand(0).getImm())) == 0))
2452 if (!State.DefPos.count(Src) &&
I.modifiesRegister(Src, &TRI)) {
2453 State.DefPos[Src] = State.VALUs;
2458 if (State.ExecPos == std::numeric_limits<int>::max()) {
2459 if (!State.DefPos.empty() &&
I.modifiesRegister(AMDGPU::EXEC, &TRI)) {
2460 State.ExecPos = State.VALUs;
2467 if (State.VALUs > Intv3MaxVALUs && State.DefPos.empty())
2475 if (State.ExecPos == std::numeric_limits<int>::max())
2478 int PreExecPos = std::numeric_limits<int>::max();
2479 int PostExecPos = std::numeric_limits<int>::max();
2481 for (
auto Entry : State.DefPos) {
2482 int DefVALUs =
Entry.second;
2483 if (DefVALUs != std::numeric_limits<int>::max()) {
2484 if (DefVALUs >= State.ExecPos)
2485 PreExecPos = std::min(PreExecPos, DefVALUs);
2487 PostExecPos = std::min(PostExecPos, DefVALUs);
2492 if (PostExecPos == std::numeric_limits<int>::max())
2496 int Intv3VALUs = PostExecPos;
2497 if (Intv3VALUs > Intv3MaxVALUs)
2501 int Intv2VALUs = (State.ExecPos - PostExecPos) - 1;
2502 if (Intv2VALUs > Intv1plus2MaxVALUs)
2506 if (PreExecPos == std::numeric_limits<int>::max())
2510 int Intv1VALUs = PreExecPos - State.ExecPos;
2511 if (Intv1VALUs > Intv1plus2MaxVALUs)
2515 if (Intv1VALUs + Intv2VALUs > Intv1plus2MaxVALUs)
2520 auto UpdateStateFn = [](StateType &State,
const MachineInstr &
MI) {
2526 std::next(
MI->getReverseIterator())))
2530 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
2536bool GCNHazardRecognizer::fixVALUTransUseHazard(
MachineInstr *
MI) {
2537 if (!ST.hasVALUTransUseHazard())
2539 assert(!ST.hasExtendedWaitCounts());
2544 SmallSet<Register, 4> SrcVGPRs;
2546 for (
const MachineOperand &Use :
MI->explicit_uses()) {
2547 if (
Use.isReg() && TRI.isVGPR(MF.getRegInfo(),
Use.getReg()))
2561 const int IntvMaxVALUs = 5;
2562 const int IntvMaxTRANS = 1;
2568 static unsigned getHashValue(
const StateType &State) {
2569 return static_cast<unsigned>(
hash_combine(State.VALUs, State.TRANS));
2571 static bool isEqual(
const StateType &
LHS,
const StateType &
RHS) {
2572 return LHS.VALUs ==
RHS.VALUs &&
LHS.TRANS ==
RHS.TRANS;
2579 auto IsHazardFn = [&,
this](StateType &State,
const MachineInstr &
I) {
2581 if (State.VALUs > IntvMaxVALUs || State.TRANS > IntvMaxTRANS)
2587 (
I.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2589 static_cast<unsigned>(
I.getOperand(0).getImm())) == 0))
2595 if (
I.modifiesRegister(Src, &TRI)) {
2603 auto UpdateStateFn = [](StateType &State,
const MachineInstr &
MI) {
2611 std::next(
MI->getReverseIterator())))
2617 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
2623bool GCNHazardRecognizer::fixVALUTransCoexecutionHazards(
MachineInstr *
MI) {
2624 if (!ST.hasTransCoexecutionHazard() ||
2629 const SIInstrInfo *TII = ST.getInstrInfo();
2630 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2632 auto IsTransHazardFn = [
MI, TII, TRI](
const MachineInstr &
I) {
2637 Register TransDef = TII->getNamedOperand(
I, AMDGPU::OpName::vdst)->getReg();
2638 for (
const MachineOperand &ValuUse :
MI->explicit_uses()) {
2639 if (ValuUse.isReg() && TRI->regsOverlap(TransDef, ValuUse.getReg()))
2645 for (
const MachineOperand &TransUse :
I.explicit_uses()) {
2646 if (TransUse.isReg() &&
MI->modifiesRegister(TransUse.getReg(), TRI))
2657 const int HasVALU = std::numeric_limits<int>::max();
2658 if (::getWaitStatesSince(IsTransHazardFn,
MI,
IsExpiredFn) == HasVALU)
2661 BuildMI(*
MI->getParent(),
MI,
MI->getDebugLoc(), TII->get(AMDGPU::V_NOP_e32));
2669 const SIInstrInfo *TII = ST.getInstrInfo();
2670 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2672 auto IsHazardFn = [
MI, TII, TRI,
this](
const MachineInstr &
I) {
2679 TII->getNamedOperand(*
MI, AMDGPU::OpName::src0)->getReg();
2681 TII->getNamedOperand(*
MI, AMDGPU::OpName::src1)->getReg();
2684 TII->getNamedOperand(
I, AMDGPU::OpName::vdst)->getReg();
2686 if (TRI->regsOverlap(PrevDstReg, CurSrc0Reg) ||
2687 TRI->regsOverlap(PrevDstReg, CurSrc1Reg)) {
2696 TII->getNamedOperand(*
MI, AMDGPU::OpName::src2)->getReg();
2697 if (TRI->regsOverlap(PrevDstReg, CurIndex))
2711 std::numeric_limits<int>::max())
2714 BuildMI(*
MI->getParent(),
MI,
MI->getDebugLoc(), TII->get(AMDGPU::V_NOP_e32));
2768 bool IsLowestRateWMMA = ST.hasGFX125xLowestRateWMMA();
2769 unsigned Category = 0;
2771 unsigned Latency = SchedModel.computeInstrLatency(&
MI);
2776 assert(!IsSWMMAC &&
"no 4-cycle SWMMAC expected");
2780 Category = IsSWMMAC ? 2 : 0;
2783 Category = IsLowestRateWMMA ? 4 : (IsSWMMAC ? 3 : 1);
2786 assert(IsLowestRateWMMA &&
"latency 32 is not expected");
2796int GCNHazardRecognizer::checkWMMACoexecutionHazards(
MachineInstr *
MI)
const {
2797 if (!ST.hasWMMACoexecutionHazards())
2800 const SIInstrInfo *TII = ST.getInstrInfo();
2809 const int WMMAWaitStates[] = {5, 9, 3, 5, 9, 17, 2};
2810 const int VALUWaitStates[] = {4, 8, 2, 4, 8, 16, 1};
2811 const bool IsWMMA = TII->isXDLWMMA(*
MI);
2812 const bool IsLowestRateWMMA = ST.hasGFX125xLowestRateWMMA();
2813 ArrayRef<int> RequiredWaitStates =
2814 IsWMMA ? ArrayRef<int>(WMMAWaitStates) :
ArrayRef<int>(VALUWaitStates);
2815 const int MaxWaitStates =
2816 IsWMMA ? (IsLowestRateWMMA ? 17 : 9) : (IsLowestRateWMMA ? 16 : 8);
2818 auto WindowFor = [=](
const MachineInstr &
I) -> std::optional<int> {
2819 if (!TII->isXDLWMMA(
I))
2820 return std::nullopt;
2821 if (IsWMMA ? !hasWMMAToWMMARegOverlap(
I, *
MI)
2822 : !hasWMMAToVALURegOverlap(
I, *
MI))
2823 return std::nullopt;
2828 return getMaxVALUWindowDeficit(MaxWaitStates, WindowFor);
2831bool GCNHazardRecognizer::hasWMMAToWMMARegOverlap(
2833 Register D0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::vdst)->getReg();
2834 Register A1 = TII.getNamedOperand(
MI, AMDGPU::OpName::src0)->getReg();
2835 Register B1 = TII.getNamedOperand(
MI, AMDGPU::OpName::src1)->getReg();
2838 if (TRI.regsOverlap(D0, A1) || TRI.regsOverlap(D0, B1))
2842 Register Idx1 = TII.getNamedOperand(
MI, AMDGPU::OpName::src2)->getReg();
2843 if (TRI.regsOverlap(D0, Idx1))
2849bool GCNHazardRecognizer::hasWMMAToVALURegOverlap(
2852 Register D0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::vdst)->getReg();
2853 for (
const MachineOperand &ValuUse :
MI.explicit_uses()) {
2854 if (ValuUse.isReg() && TRI.regsOverlap(D0, ValuUse.getReg()))
2859 Register A0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::src0)->getReg();
2860 Register B0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::src1)->getReg();
2863 const MachineOperand *
Src2 = TII.getNamedOperand(WMMA, AMDGPU::OpName::src2);
2865 WMMARegs.push_back(
Src2->getReg());
2867 for (
const MachineOperand &ValuDef :
MI.defs()) {
2868 Register VDstReg = ValuDef.getReg();
2869 for (
Register WMMAReg : WMMARegs) {
2870 if (TRI.regsOverlap(VDstReg, WMMAReg))
2877bool GCNHazardRecognizer::isCoexecutionHazardFor(
const MachineInstr &
I,
2881 if (!TII.isXDLWMMA(
I))
2885 if (TII.isXDLWMMA(
MI))
2886 return hasWMMAToWMMARegOverlap(
I,
MI);
2888 return hasWMMAToVALURegOverlap(
I,
MI);
2894 bool IncludeSubloops) {
2897 for (MachineBasicBlock *
MBB :
L->getBlocks()) {
2898 if (!IncludeSubloops && MLI->getLoopFor(
MBB) != L)
2900 for (MachineInstr &
I : *
MBB) {
2903 if (isCoexecutionHazardFor(
I, *
MI))
2910bool GCNHazardRecognizer::tryHoistWMMAVnopsFromLoop(
MachineInstr *
MI,
2911 int WaitStatesNeeded) {
2915 MachineLoop *
L = MLI->getLoopFor(
MI->getParent());
2917 ++NumWMMAHoistingBailed;
2922 if (hasWMMAHazardInLoop(L,
MI)) {
2923 ++NumWMMAHoistingBailed;
2928 MachineLoop *TargetLoop =
L;
2930 if (hasWMMAHazardInLoop(Parent,
MI,
false))
2932 TargetLoop = Parent;
2938 ++NumWMMAHoistingBailed;
2942 LLVM_DEBUG(
dbgs() <<
"WMMA V_NOP Hoisting: Moving " << WaitStatesNeeded
2948 NumWMMANopsHoisted += WaitStatesNeeded;
2952bool GCNHazardRecognizer::fixWMMACoexecutionHazards(
MachineInstr *
MI) {
2953 int WaitStatesNeeded = checkWMMACoexecutionHazards(
MI);
2954 if (WaitStatesNeeded <= 0)
2960 emitVNops(*
MI->getParent(),
MI->getIterator(), WaitStatesNeeded);
2964bool GCNHazardRecognizer::fixShift64HighRegBug(
MachineInstr *
MI) {
2965 if (!ST.hasShift64HighRegBug())
2967 assert(!ST.hasExtendedWaitCounts());
2969 switch (
MI->getOpcode()) {
2972 case AMDGPU::V_LSHLREV_B64_e64:
2973 case AMDGPU::V_LSHRREV_B64_e64:
2974 case AMDGPU::V_ASHRREV_I64_e64:
2978 MachineOperand *Amt = TII.getNamedOperand(*
MI, AMDGPU::OpName::src0);
2983 const MachineRegisterInfo &MRI = MF.getRegInfo();
2985 if (!TRI.isVGPR(MRI, AmtReg) || ((AmtReg - AMDGPU::VGPR0) & 7) != 7)
2988 if (AmtReg != AMDGPU::VGPR255 && MRI.
isPhysRegUsed(AmtReg + 1))
2991 assert(ST.needsAlignedVGPRs());
2992 static_assert(AMDGPU::VGPR0 + 1 == AMDGPU::VGPR1);
2996 MachineOperand *
Src1 = TII.getNamedOperand(*
MI, AMDGPU::OpName::src1);
3007 Register DstReg =
MI->getOperand(0).getReg();
3008 if (!
Src1->isReg() ||
Src1->getReg() != DstReg) {
3009 Register DstLo = TRI.getSubReg(DstReg, AMDGPU::sub0);
3017 bool Overlapped =
MI->modifiesRegister(AmtReg, &TRI);
3019 for (MCRegister
Reg : Overlapped ? AMDGPU::VReg_64_Align2RegClass
3020 : AMDGPU::VGPR_32RegClass) {
3021 if (!
MI->modifiesRegister(
Reg, &TRI) && !
MI->readsRegister(
Reg, &TRI)) {
3027 Register NewAmt = Overlapped ? (
Register)TRI.getSubReg(NewReg, AMDGPU::sub1)
3032 NewAmtLo = TRI.getSubReg(NewReg, AMDGPU::sub0);
3045 runOnInstruction(
BuildMI(*
MBB,
MI,
DL, TII.get(AMDGPU::V_SWAP_B32), NewAmt)
3052 BuildMI(*
MBB, std::next(
MI->getIterator()),
DL, TII.get(AMDGPU::V_SWAP_B32),
3058 BuildMI(*
MBB, std::next(
MI->getIterator()),
DL, TII.get(AMDGPU::V_SWAP_B32),
3072 MI->getOperand(0).setReg(NewReg);
3073 Src1->setReg(NewReg);
3074 Src1->setIsKill(
false);
3084bool GCNHazardRecognizer::fixPkF32InvalidOpSel(
MachineInstr *
MI) {
3085 if (!ST.hasPkF32InvalidOpSel())
3088 switch (
MI->getOpcode()) {
3091 case AMDGPU::V_PK_ADD_F32:
3092 case AMDGPU::V_PK_MUL_F32:
3093 case AMDGPU::V_PK_FMA_F32:
3097 const MachineOperand *Src0Mods =
3098 TII.getNamedOperand(*
MI, AMDGPU::OpName::src0_modifiers);
3099 const MachineOperand *Src1Mods =
3100 TII.getNamedOperand(*
MI, AMDGPU::OpName::src1_modifiers);
3101 if (!Src0Mods || !Src1Mods)
3104 if (
MI->getOpcode() != AMDGPU::V_PK_FMA_F32) {
3107 if (!TII.commuteInstruction(*
MI)) {
3109 "cannot swap the GFX950 v_pk_add/mul_f32 src0 and src1: " +
3110 Twine(TII.getName(
MI->getOpcode())));
3120 if (!TII.isLegalPkFMAF32OpSel(*
MI)) {
3122 "should have been legalized earlier in the "
3129int GCNHazardRecognizer::checkNSAtoVMEMHazard(
MachineInstr *
MI)
const {
3130 int NSAtoVMEMWaitStates = 1;
3132 if (!ST.hasNSAtoVMEMBug())
3138 const SIInstrInfo *TII = ST.getInstrInfo();
3139 const auto *
Offset = TII->getNamedOperand(*
MI, AMDGPU::OpName::offset);
3147 return Info->MIMGEncoding == AMDGPU::MIMGEncGfx10NSA &&
3148 TII->getInstSizeInBytes(
I) >= 16;
3151 return NSAtoVMEMWaitStates - getWaitStatesSince(
IsHazardFn, 1);
3154int GCNHazardRecognizer::checkFPAtomicToDenormModeHazard(
3156 int FPAtomicToDenormModeWaitStates = 3;
3158 if (!ST.hasFPAtomicToDenormModeHazard())
3160 assert(!ST.hasExtendedWaitCounts());
3162 if (
MI->getOpcode() != AMDGPU::S_DENORM_MODE)
3171 auto IsExpiredFn = [](
const MachineInstr &
MI,
int WaitStates) {
3178 return FPAtomicToDenormModeWaitStates -
3182int GCNHazardRecognizer::checkMAIHazards(
MachineInstr *
MI)
const {
3185 return ST.hasGFX90AInsts() ? checkMAIHazards90A(
MI) : checkMAIHazards908(
MI);
3188int GCNHazardRecognizer::checkMFMAPadding(
MachineInstr *
MI)
const {
3193 const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
3197 int NeighborMFMALatency = 0;
3198 auto IsNeighboringMFMA = [&NeighborMFMALatency,
3199 this](
const MachineInstr &
MI) {
3203 NeighborMFMALatency = this->getMFMAPipelineWaitStates(
MI);
3207 const int MaxMFMAPipelineWaitStates = 16;
3208 int WaitStatesSinceNeighborMFMA =
3209 getWaitStatesSince(IsNeighboringMFMA, MaxMFMAPipelineWaitStates);
3211 int NeighborMFMAPaddingNeeded =
3213 WaitStatesSinceNeighborMFMA;
3215 return std::max(0, NeighborMFMAPaddingNeeded);
3218int GCNHazardRecognizer::checkMAIHazards908(
MachineInstr *
MI)
const {
3219 int WaitStatesNeeded = 0;
3220 unsigned Opc =
MI->getOpcode();
3222 auto IsVALUFn = [](
const MachineInstr &
MI) {
3226 if (
Opc != AMDGPU::V_ACCVGPR_READ_B32_e64) {
3227 const int LegacyVALUWritesVGPRWaitStates = 2;
3228 const int VALUWritesExecWaitStates = 4;
3229 const int MaxWaitStates = 4;
3231 int WaitStatesNeededForUse = VALUWritesExecWaitStates -
3232 getWaitStatesSinceDef(AMDGPU::EXEC, IsVALUFn, MaxWaitStates);
3233 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3235 if (WaitStatesNeeded < MaxWaitStates) {
3236 for (
const MachineOperand &Use :
MI->explicit_uses()) {
3237 const int MaxWaitStates = 2;
3239 if (!
Use.isReg() || !TRI.isVGPR(MF.getRegInfo(),
Use.getReg()))
3242 int WaitStatesNeededForUse = LegacyVALUWritesVGPRWaitStates -
3243 getWaitStatesSinceDef(
Use.getReg(), IsVALUFn, MaxWaitStates);
3244 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3246 if (WaitStatesNeeded == MaxWaitStates)
3252 for (
const MachineOperand &
Op :
MI->explicit_operands()) {
3253 if (!
Op.isReg() || !TRI.isAGPR(MF.getRegInfo(),
Op.getReg()))
3256 if (
Op.isDef() &&
Opc != AMDGPU::V_ACCVGPR_WRITE_B32_e64)
3259 const int MFMAWritesAGPROverlappedSrcABWaitStates = 4;
3260 const int MFMAWritesAGPROverlappedSrcCWaitStates = 2;
3261 const int MFMA4x4WritesAGPRAccVgprReadWaitStates = 4;
3262 const int MFMA16x16WritesAGPRAccVgprReadWaitStates = 10;
3263 const int MFMA32x32WritesAGPRAccVgprReadWaitStates = 18;
3264 const int MFMA4x4WritesAGPRAccVgprWriteWaitStates = 1;
3265 const int MFMA16x16WritesAGPRAccVgprWriteWaitStates = 7;
3266 const int MFMA32x32WritesAGPRAccVgprWriteWaitStates = 15;
3267 const int MaxWaitStates = 18;
3269 unsigned HazardDefLatency = 0;
3271 auto IsOverlappedMFMAFn = [
Reg, &HazardDefLatency,
3272 this](
const MachineInstr &
MI) {
3279 std::max(HazardDefLatency, TSchedModel.computeInstrLatency(&
MI));
3280 return TRI.regsOverlap(DstReg,
Reg);
3283 int WaitStatesSinceDef = getWaitStatesSinceDef(
Reg, IsOverlappedMFMAFn,
3285 int NeedWaitStates = MFMAWritesAGPROverlappedSrcABWaitStates;
3286 int SrcCIdx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src2);
3287 int OpNo =
Op.getOperandNo();
3288 if (OpNo == SrcCIdx) {
3289 NeedWaitStates = MFMAWritesAGPROverlappedSrcCWaitStates;
3290 }
else if (
Opc == AMDGPU::V_ACCVGPR_READ_B32_e64) {
3291 switch (HazardDefLatency) {
3292 case 2: NeedWaitStates = MFMA4x4WritesAGPRAccVgprReadWaitStates;
3294 case 8: NeedWaitStates = MFMA16x16WritesAGPRAccVgprReadWaitStates;
3296 case 16: [[fallthrough]];
3297 default: NeedWaitStates = MFMA32x32WritesAGPRAccVgprReadWaitStates;
3300 }
else if (
Opc == AMDGPU::V_ACCVGPR_WRITE_B32_e64) {
3301 switch (HazardDefLatency) {
3302 case 2: NeedWaitStates = MFMA4x4WritesAGPRAccVgprWriteWaitStates;
3304 case 8: NeedWaitStates = MFMA16x16WritesAGPRAccVgprWriteWaitStates;
3306 case 16: [[fallthrough]];
3307 default: NeedWaitStates = MFMA32x32WritesAGPRAccVgprWriteWaitStates;
3312 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceDef;
3313 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3315 if (WaitStatesNeeded == MaxWaitStates)
3316 return WaitStatesNeeded;
3318 auto IsAccVgprWriteFn = [
Reg,
this](
const MachineInstr &
MI) {
3319 if (
MI.getOpcode() != AMDGPU::V_ACCVGPR_WRITE_B32_e64)
3322 return TRI.regsOverlap(
Reg, DstReg);
3325 const int AccVGPRWriteMFMAReadSrcCWaitStates = 1;
3326 const int AccVGPRWriteMFMAReadSrcABWaitStates = 3;
3327 const int AccVGPRWriteAccVgprReadWaitStates = 3;
3328 NeedWaitStates = AccVGPRWriteMFMAReadSrcABWaitStates;
3329 if (OpNo == SrcCIdx)
3330 NeedWaitStates = AccVGPRWriteMFMAReadSrcCWaitStates;
3331 else if (
Opc == AMDGPU::V_ACCVGPR_READ_B32_e64)
3332 NeedWaitStates = AccVGPRWriteAccVgprReadWaitStates;
3334 WaitStatesNeededForUse = NeedWaitStates -
3335 getWaitStatesSinceDef(
Reg, IsAccVgprWriteFn, MaxWaitStates);
3336 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3338 if (WaitStatesNeeded == MaxWaitStates)
3339 return WaitStatesNeeded;
3342 if (
Opc == AMDGPU::V_ACCVGPR_WRITE_B32_e64) {
3343 const int MFMA4x4ReadSrcCAccVgprWriteWaitStates = 0;
3344 const int MFMA16x16ReadSrcCAccVgprWriteWaitStates = 5;
3345 const int MFMA32x32ReadSrcCAccVgprWriteWaitStates = 13;
3346 const int MaxWaitStates = 13;
3347 Register DstReg =
MI->getOperand(0).getReg();
3348 unsigned HazardDefLatency = 0;
3350 auto IsSrcCMFMAFn = [DstReg, &HazardDefLatency,
3351 this](
const MachineInstr &
MI) {
3354 Register Reg = TII.getNamedOperand(
MI, AMDGPU::OpName::src2)->getReg();
3356 std::max(HazardDefLatency, TSchedModel.computeInstrLatency(&
MI));
3357 return TRI.regsOverlap(
Reg, DstReg);
3360 int WaitStatesSince = getWaitStatesSince(IsSrcCMFMAFn, MaxWaitStates);
3362 switch (HazardDefLatency) {
3363 case 2: NeedWaitStates = MFMA4x4ReadSrcCAccVgprWriteWaitStates;
3365 case 8: NeedWaitStates = MFMA16x16ReadSrcCAccVgprWriteWaitStates;
3367 case 16: [[fallthrough]];
3368 default: NeedWaitStates = MFMA32x32ReadSrcCAccVgprWriteWaitStates;
3372 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSince;
3373 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3377 WaitStatesNeeded = std::max(WaitStatesNeeded, checkMFMAPadding(
MI));
3379 return WaitStatesNeeded;
3408 return NumPasses + 1 + IsGFX950;
3419 return NumPasses + 1 + (NumPasses != 2 && IsGFX950);
3437 return NumPasses + 2;
3447 return NumPasses + 3 + (NumPasses != 2 && IsGFX950);
3450int GCNHazardRecognizer::getMFMAOverlappedSrcCWaitStates(
3452 constexpr int SMFMA4x4WritesVGPROverlappedSMFMASrcCWaitStates = 2;
3453 constexpr int SMFMA16x16WritesVGPROverlappedSMFMASrcCWaitStates = 8;
3454 constexpr int SMFMA32x32WritesVGPROverlappedSMFMASrcCWaitStates = 16;
3455 constexpr int SMFMA4x4WritesVGPROverlappedDMFMASrcCWaitStates = 3;
3456 constexpr int SMFMA16x16WritesVGPROverlappedDMFMASrcCWaitStates = 9;
3457 constexpr int SMFMA32x32WritesVGPROverlappedDMFMASrcCWaitStates = 17;
3458 constexpr int DMFMA16x16WritesVGPROverlappedSrcCWaitStates = 9;
3459 constexpr int GFX950_DMFMA16x16WritesVGPROverlappedSrcCWaitStates = 17;
3460 constexpr int DMFMA4x4WritesVGPROverlappedSrcCWaitStates = 4;
3464 if (TII.isXDL(*Reader) && !TII.isXDL(*Writer))
3468 case AMDGPU::V_MFMA_F64_16X16X4F64_e64:
3469 case AMDGPU::V_MFMA_F64_16X16X4F64_vgprcd_e64:
3470 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_e64:
3471 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_vgprcd_e64:
3472 return ST.hasGFX950Insts()
3473 ? GFX950_DMFMA16x16WritesVGPROverlappedSrcCWaitStates
3474 : DMFMA16x16WritesVGPROverlappedSrcCWaitStates;
3475 case AMDGPU::V_MFMA_F64_4X4X4F64_e64:
3476 case AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64:
3477 return DMFMA4x4WritesVGPROverlappedSrcCWaitStates;
3482 int NumPasses = TSchedModel.computeInstrLatency(Writer);
3483 if (ST.hasGFX940Insts()) {
3484 if (!TII.isXDL(*Writer))
3487 return TII.isXDL(*Reader)
3489 NumPasses, ST.hasGFX950Insts())
3491 NumPasses, ST.hasGFX950Insts());
3495 switch (NumPasses) {
3497 return IsDGEMM ? SMFMA4x4WritesVGPROverlappedDMFMASrcCWaitStates
3498 : SMFMA4x4WritesVGPROverlappedSMFMASrcCWaitStates;
3500 return IsDGEMM ? SMFMA16x16WritesVGPROverlappedDMFMASrcCWaitStates
3501 : SMFMA16x16WritesVGPROverlappedSMFMASrcCWaitStates;
3503 return IsDGEMM ? SMFMA32x32WritesVGPROverlappedDMFMASrcCWaitStates
3504 : SMFMA32x32WritesVGPROverlappedSMFMASrcCWaitStates;
3510int GCNHazardRecognizer::getMFMAReadWaitStates(
const MachineInstr &Consumer,
3513 bool IsSrcC)
const {
3515 const int SMFMA4x4WritesVGPROverlappedSrcABWaitStates = 5;
3516 const int SMFMA16x16WritesVGPROverlappedSrcABWaitStates = 11;
3517 const int SMFMA32x32WritesVGPROverlappedSrcABWaitStates = 19;
3518 const int DMFMA4x4WritesVGPROverlappedMFMASrcABWaitStates = 6;
3519 const int DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates = 11;
3520 const int GFX950_DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates = 19;
3521 const int DMFMA4x4WritesVGPRFullSrcCWaitStates = 4;
3522 const int GFX940_SMFMA4x4WritesVGPRFullSrcCWaitStates = 2;
3524 bool FullReg =
Producer.getOperand(0).getReg() ==
Reg;
3525 unsigned Opc1 =
Producer.getOpcode();
3526 int NeedWaitStates = 0;
3531 }
else if (FullReg) {
3532 if ((
Opc == AMDGPU::V_MFMA_F64_4X4X4F64_e64 ||
3533 Opc == AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64) &&
3534 (Opc1 == AMDGPU::V_MFMA_F64_4X4X4F64_e64 ||
3535 Opc1 == AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64))
3536 NeedWaitStates = DMFMA4x4WritesVGPRFullSrcCWaitStates;
3537 else if (ST.hasGFX940Insts() &&
3538 TSchedModel.computeInstrLatency(&Producer) == 2)
3539 NeedWaitStates = GFX940_SMFMA4x4WritesVGPRFullSrcCWaitStates;
3546 std::max(NeedWaitStates,
3547 getMFMAOverlappedSrcCWaitStates(&Consumer, &Producer));
3550 NeedWaitStates = getMFMAOverlappedSrcCWaitStates(&Consumer, &Producer);
3554 case AMDGPU::V_MFMA_F64_16X16X4F64_e64:
3555 case AMDGPU::V_MFMA_F64_16X16X4F64_vgprcd_e64:
3556 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_e64:
3557 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_vgprcd_e64:
3560 ? GFX950_DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates
3561 : DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates;
3563 case AMDGPU::V_MFMA_F64_4X4X4F64_e64:
3564 case AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64:
3565 NeedWaitStates = DMFMA4x4WritesVGPROverlappedMFMASrcABWaitStates;
3568 int NumPasses = TSchedModel.computeInstrLatency(&Producer);
3570 if (ST.hasGFX940Insts()) {
3574 NumPasses, ST.hasGFX950Insts())
3580 switch (NumPasses) {
3582 NeedWaitStates = SMFMA4x4WritesVGPROverlappedSrcABWaitStates;
3587 NeedWaitStates = SMFMA16x16WritesVGPROverlappedSrcABWaitStates;
3591 NeedWaitStates = SMFMA32x32WritesVGPROverlappedSrcABWaitStates;
3595 return NeedWaitStates;
3598int GCNHazardRecognizer::checkMAIHazards90A(
MachineInstr *
MI)
const {
3599 int WaitStatesNeeded = 0;
3600 unsigned Opc =
MI->getOpcode();
3602 auto IsLegacyVALUFn = [](
const MachineInstr &
MI) {
3607 auto IsLegacyVALUNotDotFn = [](
const MachineInstr &
MI) {
3613 return WaitStatesNeeded;
3615 const int VALUWritesExecWaitStates = 4;
3616 int WaitStatesNeededForUse = VALUWritesExecWaitStates -
3617 getWaitStatesSinceDef(AMDGPU::EXEC, IsLegacyVALUFn,
3618 VALUWritesExecWaitStates);
3619 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3621 int SrcCIdx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src2);
3624 for (
const MachineOperand &Use :
MI->explicit_uses()) {
3625 const int LegacyVALUNotDotWritesVGPRWaitStates = 2;
3626 const int MaxWaitStates =
3628 16, ST.hasGFX950Insts());
3634 WaitStatesNeededForUse = LegacyVALUNotDotWritesVGPRWaitStates -
3635 getWaitStatesSinceDef(
Reg, IsLegacyVALUNotDotFn, MaxWaitStates);
3636 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3638 int OpNo =
Use.getOperandNo();
3639 WaitStatesNeeded = std::max(
3641 getMaxWindowDeficit(
3642 MaxWaitStates, [&](
const MachineInstr &
P) -> std::optional<int> {
3644 !TRI.regsOverlap(
P.getOperand(0).getReg(),
Reg))
3645 return std::nullopt;
3646 return getMFMAReadWaitStates(*
MI,
P,
Reg, OpNo == SrcCIdx);
3649 if (WaitStatesNeeded == MaxWaitStates)
3654 WaitStatesNeeded = std::max(WaitStatesNeeded, checkMFMAPadding(
MI));
3656 return WaitStatesNeeded;
3659int GCNHazardRecognizer::checkMAILdStHazards(
MachineInstr *
MI)
const {
3661 if (!ST.hasMAIInsts() || ST.hasGFX90AInsts())
3664 int WaitStatesNeeded = 0;
3666 auto IsAccVgprReadFn = [](
const MachineInstr &
MI) {
3667 return MI.getOpcode() == AMDGPU::V_ACCVGPR_READ_B32_e64;
3670 for (
const MachineOperand &
Op :
MI->explicit_uses()) {
3671 if (!
Op.isReg() || !TRI.isVGPR(MF.getRegInfo(),
Op.getReg()))
3676 const int AccVgprReadLdStWaitStates = 2;
3677 const int VALUWriteAccVgprRdWrLdStDepVALUWaitStates = 1;
3678 const int MaxWaitStates = 2;
3680 int WaitStatesNeededForUse = AccVgprReadLdStWaitStates -
3681 getWaitStatesSinceDef(
Reg, IsAccVgprReadFn, MaxWaitStates);
3682 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3684 if (WaitStatesNeeded == MaxWaitStates)
3685 return WaitStatesNeeded;
3687 auto IsVALUAccVgprRdWrCheckFn = [
Reg,
this](
const MachineInstr &
MI) {
3688 if (
MI.getOpcode() != AMDGPU::V_ACCVGPR_READ_B32_e64 &&
3689 MI.getOpcode() != AMDGPU::V_ACCVGPR_WRITE_B32_e64)
3691 auto IsVALUFn = [](
const MachineInstr &
MI) {
3695 return getWaitStatesSinceDef(
Reg, IsVALUFn, 2 ) <
3696 std::numeric_limits<int>::max();
3699 WaitStatesNeededForUse = VALUWriteAccVgprRdWrLdStDepVALUWaitStates -
3700 getWaitStatesSince(IsVALUAccVgprRdWrCheckFn, MaxWaitStates);
3701 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3704 return WaitStatesNeeded;
3707int GCNHazardRecognizer::checkPermlaneHazards(
MachineInstr *
MI)
const {
3708 assert(!ST.hasVcmpxPermlaneHazard() &&
3709 "this is a different vcmpx+permlane hazard");
3710 const SIRegisterInfo *TRI = ST.getRegisterInfo();
3711 const SIInstrInfo *TII = ST.getInstrInfo();
3713 auto IsVCmpXWritesExecFn = [TII, TRI](
const MachineInstr &
MI) {
3717 auto IsVALUFn = [](
const MachineInstr &
MI) {
3721 const int VCmpXWritesExecWaitStates = 4;
3722 const int VALUWritesVDstWaitStates = 2;
3723 int WaitStatesNeeded = 0;
3725 for (
const MachineOperand &
Op :
MI->explicit_uses()) {
3726 if (!
Op.isReg() || !TRI->isVGPR(MF.getRegInfo(),
Op.getReg()))
3730 int WaitStatesSinceDef =
3731 VALUWritesVDstWaitStates -
3732 getWaitStatesSinceDef(
Reg, IsVALUFn,
3733 VALUWritesVDstWaitStates);
3734 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesSinceDef);
3735 if (WaitStatesNeeded >= VALUWritesVDstWaitStates)
3739 int VCmpXHazardWaits =
3740 VCmpXWritesExecWaitStates -
3741 getWaitStatesSince(IsVCmpXWritesExecFn, VCmpXWritesExecWaitStates);
3743 WaitStatesNeeded = std::max(WaitStatesNeeded, VCmpXHazardWaits);
3744 return WaitStatesNeeded;
3752 return NumPasses + 2;
3762 return NumPasses + 3 + (NumPasses != 2 && IsGFX950);
3772 return NumPasses + 3 + (NumPasses != 2 && IsGFX950);
3780 return NumPasses + 2;
3783int GCNHazardRecognizer::checkMAIVALUHazards(
MachineInstr *
MI)
const {
3784 if (!ST.hasGFX90AInsts())
3787 auto IsDGEMMFn = [](
const MachineInstr &
MI) ->
bool {
3795 const MachineRegisterInfo &MRI = MF.getRegInfo();
3797 int WaitStatesNeeded = 0;
3804 auto IsMFMAWriteFn = [&
Reg,
this](
const MachineInstr &
MI) {
3806 !TRI.regsOverlap(
MI.getOperand(0).getReg(),
Reg))
3811 const MachineInstr *
DOT =
nullptr;
3812 auto IsDotWriteFn = [&
Reg, &
DOT,
this](
const MachineInstr &
MI) {
3814 !TRI.regsOverlap(
MI.getOperand(0).getReg(),
Reg))
3820 bool DGEMMAfterVALUWrite =
false;
3821 auto IsDGEMMHazard = [&DGEMMAfterVALUWrite,
this](
const MachineInstr &
MI) {
3824 DGEMMAfterVALUWrite =
true;
3828 if (!TII.isVALU(
MI,
true) || !DGEMMAfterVALUWrite)
3834 int SrcCIdx = AMDGPU::getNamedOperandIdx(
MI->getOpcode(),
3835 AMDGPU::OpName::src2);
3837 if (IsMemOrExport || IsVALU) {
3838 const int SMFMA4x4WriteVgprVALUMemExpReadWaitStates = 5;
3839 const int SMFMA16x16WriteVgprVALUMemExpReadWaitStates = 11;
3840 const int SMFMA32x32WriteVgprVALUMemExpReadWaitStates = 19;
3841 const int DMFMA4x4WriteVgprMemExpReadWaitStates = 9;
3842 const int DMFMA16x16WriteVgprMemExpReadWaitStates = 18;
3843 const int DMFMA4x4WriteVgprVALUReadWaitStates = 6;
3844 const int DMFMA16x16WriteVgprVALUReadWaitStates = 11;
3845 const int GFX950_DMFMA16x16WriteVgprVALUReadWaitStates = 19;
3846 const int DotWriteSameDotReadSrcAB = 3;
3847 const int DotWriteDifferentVALURead = 3;
3848 const int DMFMABetweenVALUWriteVMEMRead = 2;
3849 const int MaxWaitStates =
3851 ST.hasGFX950Insts());
3853 for (
const MachineOperand &Use :
MI->explicit_uses()) {
3859 int WaitStatesSinceDef = getWaitStatesSinceDef(
Reg, IsDotWriteFn,
3862 int NeedWaitStates = 0;
3863 if (
DOT->getOpcode() ==
MI->getOpcode()) {
3864 if (&Use - &
MI->getOperand(0) != SrcCIdx)
3865 NeedWaitStates = DotWriteSameDotReadSrcAB;
3867 NeedWaitStates = DotWriteDifferentVALURead;
3870 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceDef;
3871 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3878 if (IsMem && ST.hasGFX90AInsts() && !ST.hasGFX940Insts()) {
3879 DGEMMAfterVALUWrite =
false;
3880 if (TRI.isVectorRegister(MRI,
Reg)) {
3881 int WaitStatesNeededForUse =
3882 DMFMABetweenVALUWriteVMEMRead -
3883 getWaitStatesSinceDef(
Reg, IsDGEMMHazard,
3884 DMFMABetweenVALUWriteVMEMRead);
3886 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3890 auto MFMAWindow = [&](
const MachineInstr &
Producer) {
3891 int NumPasses = TSchedModel.computeInstrLatency(&Producer);
3892 int NeedWaitStates = MaxWaitStates;
3895 switch (NumPasses) {
3897 NeedWaitStates = IsMemOrExport
3898 ? DMFMA4x4WriteVgprMemExpReadWaitStates
3899 : DMFMA4x4WriteVgprVALUReadWaitStates;
3905 ? DMFMA16x16WriteVgprMemExpReadWaitStates
3906 : (ST.hasGFX950Insts()
3907 ? GFX950_DMFMA16x16WriteVgprVALUReadWaitStates
3908 : DMFMA16x16WriteVgprVALUReadWaitStates);
3913 }
else if (ST.hasGFX940Insts()) {
3917 NumPasses, ST.hasGFX950Insts())
3921 switch (NumPasses) {
3923 NeedWaitStates = SMFMA4x4WriteVgprVALUMemExpReadWaitStates;
3926 NeedWaitStates = SMFMA16x16WriteVgprVALUMemExpReadWaitStates;
3929 NeedWaitStates = SMFMA32x32WriteVgprVALUMemExpReadWaitStates;
3936 assert(NeedWaitStates <= MaxWaitStates &&
3937 "hazard requirement exceeds the scan window");
3938 return NeedWaitStates;
3941 WaitStatesNeeded = std::max(
3943 getMaxWindowDeficit(MaxWaitStates,
3944 [&](
const MachineInstr &
P) -> std::optional<int> {
3945 if (!IsMFMAWriteFn(
P))
3946 return std::nullopt;
3947 return MFMAWindow(
P);
3950 if (WaitStatesNeeded >= MaxWaitStates)
3955 unsigned Opc =
MI->getOpcode();
3956 const int DMFMAToFMA64WaitStates = 2;
3957 if ((
Opc == AMDGPU::V_FMA_F64_e64 ||
3958 Opc == AMDGPU::V_FMAC_F64_e32 ||
Opc == AMDGPU::V_FMAC_F64_e64 ||
3959 Opc == AMDGPU::V_FMAC_F64_dpp) &&
3960 WaitStatesNeeded < DMFMAToFMA64WaitStates) {
3961 int WaitStatesNeededForUse = DMFMAToFMA64WaitStates -
3962 getWaitStatesSince(IsDGEMMFn, DMFMAToFMA64WaitStates);
3963 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3966 if (!IsVALU && !IsMemOrExport)
3967 return WaitStatesNeeded;
3969 for (
const MachineOperand &Def :
MI->defs()) {
3970 const int SMFMA4x4WriteVgprVALUWawWaitStates = 5;
3971 const int SMFMA16x16WriteVgprVALUWawWaitStates = 11;
3972 const int SMFMA32x32WriteVgprVALUWawWaitStates = 19;
3973 const int SMFMA4x4ReadVgprVALUWarWaitStates = 1;
3974 const int GFX940_XDL4PassReadVgprVALUWarWaitStates = 3;
3975 const int SMFMA16x16ReadVgprVALUWarWaitStates = 7;
3976 const int SMFMA32x32ReadVgprVALUWarWaitStates = 15;
3977 const int DMFMA4x4WriteVgprVALUWriteWaitStates = 6;
3978 const int DMFMA16x16WriteVgprVALUWriteWaitStates = 11;
3979 const int DotWriteDifferentVALUWrite = 3;
3980 const int MaxWaitStates =
3982 const int MaxWarWaitStates = 15;
3987 int WaitStatesSinceDef = getWaitStatesSinceDef(
Reg, IsDotWriteFn,
3989 if (DOT &&
DOT->getOpcode() !=
MI->getOpcode())
3990 WaitStatesNeeded = std::max(WaitStatesNeeded, DotWriteDifferentVALUWrite -
3991 WaitStatesSinceDef);
3993 auto MFMAWawWindow = [&](
const MachineInstr &
Producer) {
3994 int NeedWaitStates = MaxWaitStates;
3995 int NumPasses = TSchedModel.computeInstrLatency(&Producer);
3998 switch (NumPasses) {
4000 NeedWaitStates = DMFMA4x4WriteVgprVALUWriteWaitStates;
4004 NeedWaitStates = DMFMA16x16WriteVgprVALUWriteWaitStates;
4009 }
else if (ST.hasGFX940Insts()) {
4013 NumPasses, ST.hasGFX950Insts())
4016 switch (NumPasses) {
4018 NeedWaitStates = SMFMA4x4WriteVgprVALUWawWaitStates;
4021 NeedWaitStates = SMFMA16x16WriteVgprVALUWawWaitStates;
4024 NeedWaitStates = SMFMA32x32WriteVgprVALUWawWaitStates;
4031 assert(NeedWaitStates <= MaxWaitStates &&
4032 "hazard requirement exceeds the scan window");
4033 return NeedWaitStates;
4036 WaitStatesNeeded = std::max(
4038 getMaxWindowDeficit(MaxWaitStates,
4039 [&](
const MachineInstr &
P) -> std::optional<int> {
4040 if (!IsMFMAWriteFn(
P))
4041 return std::nullopt;
4042 return MFMAWawWindow(
P);
4045 if (WaitStatesNeeded >= MaxWaitStates)
4049 auto SMFMAReadAsCWindow =
4050 [&](
const MachineInstr &Reader) -> std::optional<int> {
4054 return std::nullopt;
4056 if (ST.hasGFX940Insts() && !TII.isXDL(Reader))
4057 return std::nullopt;
4059 const MachineOperand *SrcC =
4060 TII.getNamedOperand(Reader, AMDGPU::OpName::src2);
4061 assert(SrcC &&
"an MFMA must have a src2 operand");
4063 return std::nullopt;
4065 switch (TSchedModel.computeInstrLatency(&Reader)) {
4067 return SMFMA4x4ReadVgprVALUWarWaitStates;
4069 assert(ST.hasGFX940Insts() &&
"4-pass XDL is gfx940 or later");
4070 return GFX940_XDL4PassReadVgprVALUWarWaitStates;
4072 return SMFMA16x16ReadVgprVALUWarWaitStates;
4076 return SMFMA32x32ReadVgprVALUWarWaitStates;
4081 std::max(WaitStatesNeeded,
4082 getMaxWindowDeficit(MaxWarWaitStates, SMFMAReadAsCWindow));
4085 return WaitStatesNeeded;
4098 return MAI !=
nullptr;
4102 if (IsMFMAFn(*
MI)) {
4103 int W = getWaitStatesSince(IsMFMAFn, 16);
4105 return W < (int)TSchedModel.computeInstrLatency(MAI);
4119 while (
I->isBundledWithPred())
4125 if (
I->getOpcode() != AMDGPU::S_GETPC_B64)
4129 const unsigned NewBytes = 4;
4131 "Unexpected instruction insertion in bundle");
4134 while (NextMI !=
End && NextMI->isBundledWithPred()) {
4135 for (
auto &Operand : NextMI->operands()) {
4136 if (Operand.isGlobal())
4137 Operand.setOffset(Operand.getOffset() + NewBytes);
4143bool GCNHazardRecognizer::fixVALUMaskWriteHazard(
MachineInstr *
MI) {
4144 if (!ST.hasVALUMaskWriteHazard())
4146 assert(!ST.hasExtendedWaitCounts());
4153 if (!IsSALU && !IsVALU)
4165 const SIRegisterInfo *TRI = ST.getRegisterInfo();
4166 const MachineRegisterInfo &MRI = MF.getRegInfo();
4171 case AMDGPU::EXEC_LO:
4172 case AMDGPU::EXEC_HI:
4174 case AMDGPU::SGPR_NULL:
4175 case AMDGPU::SGPR_NULL64:
4183 return Reg == AMDGPU::VCC ||
Reg == AMDGPU::VCC_LO ||
Reg == AMDGPU::VCC_HI;
4187 SmallSet<Register, 2> HazardSGPRs;
4189 static unsigned getHashValue(
const StateType &State) {
4192 static bool isEqual(
const StateType &
LHS,
const StateType &
RHS) {
4193 return LHS.HazardSGPRs ==
RHS.HazardSGPRs;
4197 SmallVector<const MachineInstr *> WaitInstrs;
4198 StateType InitialState;
4201 MachineOperand *HazardDef =
nullptr;
4202 for (MachineOperand &
Op :
MI->all_defs()) {
4204 if (IgnoreableSGPR(
Reg))
4207 if (
Op.isImplicit())
4209 if (!TRI->isSGPRReg(MRI,
Reg))
4222 if (AMDGPU::SReg_32RegClass.
contains(HazardReg)) {
4223 InitialState.HazardSGPRs.insert(HazardReg);
4226 InitialState.HazardSGPRs.insert(TRI->getSubReg(HazardReg, AMDGPU::sub0));
4227 InitialState.HazardSGPRs.insert(TRI->getSubReg(HazardReg, AMDGPU::sub1));
4230 auto IsHazardFn = [&](StateType &State,
const MachineInstr &
I) {
4231 if (State.HazardSGPRs.empty())
4234 switch (
I.getOpcode()) {
4235 case AMDGPU::V_ADDC_U32_e32:
4236 case AMDGPU::V_ADDC_U32_dpp:
4237 case AMDGPU::V_CNDMASK_B16_t16_e32:
4238 case AMDGPU::V_CNDMASK_B16_fake16_e32:
4239 case AMDGPU::V_CNDMASK_B16_t16_dpp:
4240 case AMDGPU::V_CNDMASK_B16_fake16_dpp:
4241 case AMDGPU::V_CNDMASK_B32_e32:
4242 case AMDGPU::V_CNDMASK_B32_dpp:
4243 case AMDGPU::V_DIV_FMAS_F32_e64:
4244 case AMDGPU::V_DIV_FMAS_F64_e64:
4245 case AMDGPU::V_SUBB_U32_e32:
4246 case AMDGPU::V_SUBB_U32_dpp:
4247 case AMDGPU::V_SUBBREV_U32_e32:
4248 case AMDGPU::V_SUBBREV_U32_dpp: {
4252 case AMDGPU::V_ADDC_U32_e64:
4253 case AMDGPU::V_ADDC_U32_e64_dpp:
4254 case AMDGPU::V_CNDMASK_B16_t16_e64:
4255 case AMDGPU::V_CNDMASK_B16_fake16_e64:
4256 case AMDGPU::V_CNDMASK_B16_t16_e64_dpp:
4257 case AMDGPU::V_CNDMASK_B16_fake16_e64_dpp:
4258 case AMDGPU::V_CNDMASK_B32_e64:
4259 case AMDGPU::V_CNDMASK_B32_e64_dpp:
4260 case AMDGPU::V_SUBB_U32_e64:
4261 case AMDGPU::V_SUBB_U32_e64_dpp:
4262 case AMDGPU::V_SUBBREV_U32_e64:
4263 case AMDGPU::V_SUBBREV_U32_e64_dpp: {
4265 const MachineOperand *SSRCOp = TII.getNamedOperand(
I, AMDGPU::OpName::src2);
4267 bool Result = TRI->regsOverlap(SSRCOp->
getReg(), HazardReg);
4275 auto UpdateStateFn = [&](StateType &State,
const MachineInstr &
I) {
4277 for (
auto &
Op :
I.all_defs()) {
4279 if (IgnoreableSGPR(
Reg))
4282 if (
Op.isImplicit())
4284 if (!TRI->isSGPRReg(MRI,
Reg))
4291 for (
Register SGPR : State.HazardSGPRs) {
4292 if (
Reg == SGPR || TRI->regsOverlap(
Reg, SGPR))
4296 State.HazardSGPRs.erase(SGPR);
4303 std::next(
MI->getReverseIterator())))
4313 auto NextMI = std::next(
MI->getIterator());
4314 auto NewMI =
BuildMI(*
MI->getParent(), NextMI,
MI->getDebugLoc(),
4315 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
4327 if (EntryMBB.
begin() != EntryMBB.
end()) {
4328 auto &EntryMI = *EntryMBB.
begin();
4329 if (EntryMI.getOpcode() == AMDGPU::S_SETPRIO &&
4330 EntryMI.getOperand(0).getImm() >= Priority)
4339bool GCNHazardRecognizer::fixRequiredExportPriority(
MachineInstr *
MI) {
4340 if (!ST.hasRequiredExportPriority())
4358 const int MaxPriority = 3;
4359 const int NormalPriority = 2;
4360 const int PostExportPriority = 0;
4362 auto It =
MI->getIterator();
4363 switch (
MI->getOpcode()) {
4364 case AMDGPU::S_ENDPGM:
4365 case AMDGPU::S_ENDPGM_SAVED:
4366 case AMDGPU::S_ENDPGM_ORDERED_PS_DONE:
4367 case AMDGPU::SI_RETURN_TO_EPILOG:
4370 if (MF->getFrameInfo().hasCalls())
4373 case AMDGPU::S_SETPRIO: {
4375 auto &PrioOp =
MI->getOperand(0);
4376 int Prio =
static_cast<int>(PrioOp.getImm());
4377 bool InWA = (Prio == PostExportPriority) &&
4378 (It !=
MBB->
begin() && TII.isEXP(*std::prev(It)));
4379 if (InWA || Prio >= NormalPriority)
4381 PrioOp.setImm(std::min(Prio + NormalPriority, MaxPriority));
4385 if (!TII.isEXP(*
MI))
4396 auto NextMI = std::next(It);
4397 bool EndOfShader =
false;
4398 if (NextMI !=
MBB->
end()) {
4400 if (TII.isEXP(*NextMI))
4403 if (NextMI->getOpcode() == AMDGPU::S_SETPRIO &&
4404 NextMI->getOperand(0).getImm() == PostExportPriority)
4406 EndOfShader = NextMI->getOpcode() == AMDGPU::S_ENDPGM;
4413 .
addImm(PostExportPriority);
4417 BuildMI(*
MBB, NextMI,
DL, TII.get(AMDGPU::S_WAITCNT_EXPCNT))
4418 .
addReg(AMDGPU::SGPR_NULL)
4440 while (
I !=
End &&
I->isMetaInstruction())
4449 assert(ST.hasRequiresInitialUnclausedVmem() &&
4450 "V_PERM_PK16-hazard subtarget must provide the unclaused-VMEM entry "
4451 "prologue to satisfy the cross-wave entry mitigation");
4462 if (NextI !=
MBB->
end() && TII.isVPermPk16SafeInstr(*NextI))
4468 BuildMI(*
MBB, NextI,
MI->getDebugLoc(), TII.get(AMDGPU::V_NOP_e32));
4476 const SIInstrInfo *TII = ST.getInstrInfo();
4488 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4493bool GCNHazardRecognizer::fixDsAtomicAsyncBarrierArriveB64(
MachineInstr *
MI) {
4494 if (
MI->getOpcode() != AMDGPU::DS_ATOMIC_ASYNC_BARRIER_ARRIVE_B64)
4497 const SIInstrInfo *TII = ST.getInstrInfo();
4499 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4501 BuildMI(*
MI->getParent(), std::next(
MI->getIterator()),
MI->getDebugLoc(),
4502 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4508bool GCNHazardRecognizer::fixScratchBaseForwardingHazard(
MachineInstr *
MI) {
4514 const SIRegisterInfo *TRI = ST.getRegisterInfo();
4515 const SIInstrInfo *TII = ST.getInstrInfo();
4517 const int FlatScrBaseWaitStates = 10;
4519 bool ReadsFlatScrLo =
4521 bool ReadsFlatScrHi =
4522 MI->readsRegister(AMDGPU::SRC_FLAT_SCRATCH_BASE_HI, TRI);
4528 ReadsFlatScrLo =
true;
4531 ReadsFlatScrHi =
true;
4536 const MachineRegisterInfo &MRI = MF.getRegInfo();
4539 DenseSet<const MachineBasicBlock *> Visited;
4541 return MI.modifiesRegister(
Reg, TRI);
4546 auto IsSGPRDef = [TII, TRI, &MRI](
const MachineInstr &
MI) ->
unsigned {
4547 if (!TII->isSALU(
MI) && !TII->isVALU(
MI,
true))
4549 for (
const MachineOperand &MO :
MI.all_defs()) {
4550 if (TRI->isSGPRReg(MRI, MO.getReg()))
4556 auto IsExpiredFn = [=](
const MachineInstr &
MI,
int SgprWrites) {
4557 if (
MI.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR) {
4558 unsigned Wait =
static_cast<unsigned>(
MI.getOperand(0).
getImm());
4563 return SgprWrites >= FlatScrBaseWaitStates;
4566 return ::getWaitStatesSince(
4567 IsHazardFn,
MI->getParent(), std::next(
MI->getReverseIterator()),
4568 0,
IsExpiredFn, Visited, IsSGPRDef) < FlatScrBaseWaitStates;
4572 !IsRegDefHazard(AMDGPU::SGPR102)) &&
4574 !IsRegDefHazard(AMDGPU::SGPR103)))
4578 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4589 BuildMI(*
MI->getParent(),
MI,
MI->getDebugLoc(), TII.get(AMDGPU::V_NOP_e32));
4590 BuildMI(*
MI->getParent(),
MI,
MI->getDebugLoc(), TII.get(AMDGPU::V_NOP_e32));
4595 auto IsTDM = [&](
const MachineInstr &
MI) ->
bool {
4597 MI.getOpcode() != AMDGPU::S_WAIT_TENSORCNT;
4604 if (
MI.getOpcode() != AMDGPU::S_WAIT_TENSORCNT)
4606 return MI.getOperand(0).getImm() <= 10;
4610 std::numeric_limits<int>::max())
4614 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)
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)
LLVM_ABI void reportFatalInternalError(Error Err)
Report a fatal error that indicates a bug in LLVM.
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...