28#define DEBUG_TYPE "gcn-hazard-recognizer"
31#define DEBUG_TYPE_VERBOSE "gcn-hazard-recognizer-verbose"
34 "Number of WMMA hazard V_NOPs hoisted from loops");
36 "Number of WMMA hazards where V_NOP hoisting was not possible");
40struct MFMAPaddingRatioParser :
public cl::parser<unsigned> {
43 bool parse(cl::Option &O, StringRef ArgName, StringRef Arg,
unsigned &
Value) {
45 return O.error(
"'" + Arg +
"' value invalid for uint argument!");
48 return O.error(
"'" + Arg +
"' value must be in the range [0, 100]!");
58 cl::desc(
"Fill a percentage of the latency between "
59 "neighboring MFMA with s_nops."));
64 cl::desc(
"Insert a s_nop x before every instruction"));
68 cl::desc(
"Hoist WMMA hazard V_NOPs from loops to preheaders"));
80 : Mode(Mode), CurrCycleInstr(nullptr), MF(MF),
81 ST(MF.getSubtarget<
GCNSubtarget>()), TII(*ST.getInstrInfo()),
82 TRI(TII.getRegisterInfo()), TSchedModel(TII.getSchedModel()), MLI(MLI),
83 ClauseUses(TRI.getNumRegUnits()), ClauseDefs(TRI.getNumRegUnits()) {
84 MaxLookAhead = MF.getRegInfo().isPhysRegUsed(AMDGPU::AGPR0) ? 19 : 5;
88 dbgs() <<
" PreRA hazard recognizer: " << MF.getName() <<
"\n";
100 if (CurrentCoExecStage.has_value()) {
101 unsigned Stage = *CurrentCoExecStage;
103 CoExecWindowLog[Stage] = ActiveCoExecInfo.Pattern[Stage];
104 dbgs() <<
" CoExec window ended at stage " << Stage <<
":\n";
111 EmittedInstrs.clear();
112 EmittedVALUInstrs.clear();
113 HasPendingWMMACoexecHazard =
false;
118void GCNHazardRecognizer::schedulerReset() {
120 if (CurrentCoExecStage.has_value() || CyclesUntilTRANS > 0 ||
122 dbgs() <<
" Scheduler Reset: clearing co-exec window, TRANS="
123 << CyclesUntilTRANS <<
", VALU=" << CyclesUntilVALU <<
"\n";
125 CurrentCoExecStage = std::nullopt;
126 CoExecWindowStartCycle = 0;
127 CyclesUntilTRANS = 0;
130 CoExecWindowLog.fill(
'.');
133void GCNHazardRecognizer::dumpCoExecWindow()
const {
134 unsigned W = ActiveCoExecInfo.TotalWindow;
139 dbgs() <<
" Stages: ";
140 for (
unsigned I = 0;
I <
W; ++
I)
141 dbgs() <<
I % 10 <<
' ';
145 dbgs() <<
" Slots: ";
146 for (
unsigned I = 0;
I <
W; ++
I)
147 dbgs() << ActiveCoExecInfo.Pattern[
I] <<
' ';
151 dbgs() <<
" Scheduled: ";
152 for (
unsigned I = 0;
I <
W; ++
I)
153 dbgs() << CoExecWindowLog[
I] <<
' ';
157void GCNHazardRecognizer::schedulerAdvanceCycle() {
159 if (CurrentCoExecStage.has_value()) {
160 unsigned Stage = *CurrentCoExecStage;
163 CoExecWindowLog[Stage] = ActiveCoExecInfo.Pattern[Stage];
165 CoExecWindowLog[Stage] =
'-';
170 bool HasState = CurrentCoExecStage.has_value() || CyclesUntilTRANS > 0 ||
173 dbgs() <<
" Scheduler AdvanceCycle:";
174 if (CurrentCoExecStage.has_value()) {
175 unsigned Stage = *CurrentCoExecStage;
176 unsigned Next = Stage + 1;
177 if (
Next >= ActiveCoExecInfo.TotalWindow)
178 dbgs() <<
" stage " << Stage <<
"->expired";
180 dbgs() <<
" stage " << Stage <<
"->" <<
Next;
182 if (CyclesUntilTRANS > 0)
183 dbgs() <<
" TRANS=" << CyclesUntilTRANS <<
"->"
184 << (CyclesUntilTRANS - 1);
185 if (CyclesUntilVALU > 0)
186 dbgs() <<
" VALU=" << CyclesUntilVALU <<
"->" << (CyclesUntilVALU - 1);
192 if (CyclesUntilTRANS > 0)
194 if (CyclesUntilVALU > 0)
198 if (CurrentCoExecStage.has_value()) {
199 unsigned Stage = *CurrentCoExecStage + 1;
200 if (Stage >= ActiveCoExecInfo.TotalWindow) {
203 dbgs() <<
" CoExec window complete:\n";
206 CurrentCoExecStage = std::nullopt;
208 CurrentCoExecStage = Stage;
213bool GCNHazardRecognizer::hasCoExecWindowModel()
const {
219 if (ST.hasWMMACoexecutionHazards() && ST.hasTransCoexecutionHazard() &&
223 if (ST.hasGFX950Insts() &&
230void GCNHazardRecognizer::updateWMMAWindowState(
const MachineInstr &
MI) {
231 if (!hasCoExecWindowModel())
241 if (CurrentCoExecStage.has_value()) {
242 unsigned Stage = *CurrentCoExecStage;
244 CoExecWindowLog[Stage] = ActiveCoExecInfo.Pattern[Stage];
245 dbgs() <<
" CoExec window interrupted at stage " << Stage <<
":\n";
252 CurrentCoExecStage = 0;
253 CoExecWindowLog.fill(
'.');
255 LLVM_DEBUG(
dbgs() <<
" WMMA window started: " << ActiveCoExecInfo.Pattern
256 <<
" (window=" << ActiveCoExecInfo.TotalWindow <<
")\n"
260void GCNHazardRecognizer::updateTRANSState(
const MachineInstr &
MI) {
261 if (!hasCoExecWindowModel())
275 CyclesUntilTRANS = 2;
279void GCNHazardRecognizer::updateMultiCycleVALUState(
const MachineInstr &
MI) {
280 if (!hasCoExecWindowModel())
291 unsigned RepeatRate = TII.getRepeatRate(
MI);
292 if (RepeatRate > 1) {
296 CyclesUntilVALU = RepeatRate;
298 <<
", CyclesUntilVALU=" << CyclesUntilVALU <<
"\n");
308unsigned GCNHazardRecognizer::checkTRANSHazard(
const MachineInstr &
MI)
const {
309 if (!CyclesUntilTRANS)
314 return CyclesUntilTRANS;
318 TII.getRepeatRate(
MI) > 1)
319 return CyclesUntilTRANS;
325GCNHazardRecognizer::checkMultiCycleVALUHazard(
const MachineInstr &
MI)
const {
326 if (!CyclesUntilVALU)
337 return CyclesUntilVALU;
341GCNHazardRecognizer::checkWMMACoexecSlot(
const MachineInstr &
MI)
const {
343 if (!CurrentCoExecStage.has_value())
346 unsigned Stage = *CurrentCoExecStage;
348 unsigned StallCycles = ActiveCoExecInfo.getStallCycles(InstMask, Stage);
351 if (StallCycles == 0)
355 unsigned NextStage = Stage + StallCycles;
356 if (NextStage < ActiveCoExecInfo.TotalWindow) {
359 dbgs() <<
" CoExec stall: stage=" << Stage <<
"("
362 <<
" -> stall " << StallCycles <<
" (next allowed=" << NextStage
371 dbgs() <<
" CoExec stall: stage=" << Stage <<
"("
374 << StallCycles <<
" (window ends)\n"
380GCNHazardRecognizer::checkMultiShadowHazard(
const MachineInstr &
MI)
const {
382 if (!hasCoExecWindowModel())
386 if (!CurrentCoExecStage.has_value())
389 if (!CyclesUntilTRANS)
399 unsigned LookAheadStage = *CurrentCoExecStage + CyclesUntilTRANS;
401 return CyclesUntilTRANS +
402 ActiveCoExecInfo.getStallCycles(InstMask, LookAheadStage);
405void GCNHazardRecognizer::schedulerEmitInstruction(
MachineInstr *
MI) {
407 bool InWindow = CurrentCoExecStage.has_value();
408 bool HasActiveState =
409 InWindow || CyclesUntilTRANS > 0 || CyclesUntilVALU > 0;
410 if (HasActiveState) {
412 unsigned Stage = *CurrentCoExecStage;
413 dbgs() <<
" Stage " << Stage <<
"("
426 bool HasActiveState = CurrentCoExecStage.has_value() ||
427 CyclesUntilTRANS > 0 || CyclesUntilVALU > 0;
433 updateWMMAWindowState(*
MI);
434 updateTRANSState(*
MI);
435 updateMultiCycleVALUState(*
MI);
445 schedulerEmitInstruction(
MI);
449 return Opcode == AMDGPU::V_DIV_FMAS_F32_e64 || Opcode == AMDGPU::V_DIV_FMAS_F64_e64;
453 return Opcode == AMDGPU::S_GETREG_B32 || Opcode == AMDGPU::S_GETREG_B32_const;
458 case AMDGPU::S_SETREG_B32:
459 case AMDGPU::S_SETREG_B32_mode:
460 case AMDGPU::S_SETREG_IMM32_B32:
461 case AMDGPU::S_SETREG_IMM32_B32_mode:
468 return Opcode == AMDGPU::V_READLANE_B32 || Opcode == AMDGPU::V_WRITELANE_B32;
472 return Opcode == AMDGPU::S_RFE_B64;
477 case AMDGPU::S_MOVRELS_B32:
478 case AMDGPU::S_MOVRELS_B64:
479 case AMDGPU::S_MOVRELD_B32:
480 case AMDGPU::S_MOVRELD_B64:
489 if (
TII.isAlwaysGDS(
MI.getOpcode()))
492 switch (
MI.getOpcode()) {
493 case AMDGPU::S_SENDMSG:
494 case AMDGPU::S_SENDMSGHALT:
495 case AMDGPU::S_TTRACEDATA:
499 case AMDGPU::DS_PERMUTE_B32:
500 case AMDGPU::DS_BPERMUTE_B32:
503 if (
TII.isDS(
MI.getOpcode())) {
504 int GDS = AMDGPU::getNamedOperandIdx(
MI.getOpcode(),
505 AMDGPU::OpName::gds);
506 if (
MI.getOperand(GDS).getImm())
514 unsigned Opcode =
MI.getOpcode();
515 return Opcode == AMDGPU::V_PERMLANE16_B32_e64 ||
516 Opcode == AMDGPU::V_PERMLANE64_B32 ||
517 Opcode == AMDGPU::V_PERMLANEX16_B32_e64 ||
518 Opcode == AMDGPU::V_PERMLANE16_VAR_B32_e64 ||
519 Opcode == AMDGPU::V_PERMLANEX16_VAR_B32_e64 ||
520 Opcode == AMDGPU::V_PERMLANE16_SWAP_B32_e32 ||
521 Opcode == AMDGPU::V_PERMLANE16_SWAP_B32_e64 ||
522 Opcode == AMDGPU::V_PERMLANE32_SWAP_B32_e32 ||
523 Opcode == AMDGPU::V_PERMLANE32_SWAP_B32_e64 ||
524 Opcode == AMDGPU::V_PERMLANE_BCAST_B32_e64 ||
525 Opcode == AMDGPU::V_PERMLANE_UP_B32_e64 ||
526 Opcode == AMDGPU::V_PERMLANE_DOWN_B32_e64 ||
527 Opcode == AMDGPU::V_PERMLANE_XOR_B32_e64 ||
528 Opcode == AMDGPU::V_PERMLANE_IDX_GEN_B32_e64;
537 AMDGPU::OpName::simm16);
553 if (checkMultiShadowHazard(*
MI) > 0)
555 if (checkWMMACoexecSlot(*
MI) > 0)
557 if (checkTRANSHazard(*
MI) > 0)
559 if (checkMultiCycleVALUHazard(*
MI) > 0)
569 if (ST.hasNSAtoVMEMBug() && checkNSAtoVMEMHazard(
MI) > 0)
572 if (checkFPAtomicToDenormModeHazard(
MI) > 0)
577 if (checkWMMACoexecutionHazards(
MI) > 0) {
578 HasPendingWMMACoexecHazard =
true;
583 if (ST.hasNoDataDepHazard())
590 checkVALUHazards(
MI) > 0)
596 if (
isDivFMas(
MI->getOpcode()) && checkDivFMasHazards(
MI) > 0)
599 if (
isRWLane(
MI->getOpcode()) && checkRWLaneHazards(
MI) > 0)
605 checkMAIVALUHazards(
MI) > 0)
608 if (
isSGetReg(
MI->getOpcode()) && checkGetRegHazards(
MI) > 0)
611 if (
isSSetReg(
MI->getOpcode()) && checkSetRegHazards(
MI) > 0)
614 if (
isRFE(
MI->getOpcode()) && checkRFEHazards(
MI) > 0)
617 if (((ST.hasReadM0MovRelInterpHazard() &&
619 MI->getOpcode() == AMDGPU::DS_WRITE_ADDTID_B32 ||
620 MI->getOpcode() == AMDGPU::DS_READ_ADDTID_B32)) ||
622 (ST.hasReadM0LdsDmaHazard() &&
isLdsDma(*
MI)) ||
623 (ST.hasReadM0LdsDirectHazard() &&
624 MI->readsRegister(AMDGPU::LDS_DIRECT,
nullptr))) &&
625 checkReadM0Hazards(
MI) > 0)
632 checkMAILdStHazards(
MI) > 0)
635 if (ST.hasPermlaneForwardingHazard() &&
isPermlane(*
MI) &&
636 checkPermlaneHazards(
MI) > 0)
639 if (
MI->isInlineAsm() && checkInlineAsmHazards(
MI) > 0)
647 while (Quantity > 0) {
648 unsigned Arg = std::min(Quantity, 8u);
656GCNHazardRecognizer::getMFMAPipelineWaitStates(
const MachineInstr &
MI)
const {
657 const MCSchedClassDesc *SC = TSchedModel.resolveSchedClass(&
MI);
658 assert(TSchedModel.getWriteProcResBegin(SC) !=
659 TSchedModel.getWriteProcResEnd(SC));
660 return TSchedModel.getWriteProcResBegin(SC)->ReleaseAtCycle;
663void GCNHazardRecognizer::processBundle() {
667 for (;
MI !=
E &&
MI->isInsideBundle(); ++
MI) {
668 CurrCycleInstr = &*
MI;
672 fixHazards(CurrCycleInstr);
680 for (
unsigned i = 0, e = std::min(WaitStates,
MaxLookAhead - 1); i <
e; ++i)
681 EmittedInstrs.push_front(
nullptr);
683 EmittedInstrs.push_front(CurrCycleInstr);
686 CurrCycleInstr =
nullptr;
694 if (
MI->isInsideBundle())
708 CurrCycleInstr =
nullptr;
717 W = checkWMMACoexecSlot(*
MI);
718 W = std::max(W, checkTRANSHazard(*
MI));
719 W = std::max(W, checkMultiCycleVALUHazard(*
MI));
720 W = std::max(W, checkMultiShadowHazard(*
MI));
736 return std::max(WaitStates, checkSMRDHazards(
MI));
738 if (ST.hasNSAtoVMEMBug())
739 WaitStates = std::max(WaitStates, checkNSAtoVMEMHazard(
MI));
741 WaitStates = std::max(WaitStates, checkFPAtomicToDenormModeHazard(
MI));
743 if (ST.hasNoDataDepHazard())
747 WaitStates = std::max(WaitStates, checkVMEMHazards(
MI));
750 WaitStates = std::max(WaitStates, checkVALUHazards(
MI));
753 WaitStates = std::max(WaitStates, checkDPPHazards(
MI));
756 WaitStates = std::max(WaitStates, checkDivFMasHazards(
MI));
759 WaitStates = std::max(WaitStates, checkRWLaneHazards(
MI));
764 WaitStates = std::max(WaitStates, checkMAIVALUHazards(
MI));
766 if (
MI->isInlineAsm())
767 return std::max(WaitStates, checkInlineAsmHazards(
MI));
770 return std::max(WaitStates, checkGetRegHazards(
MI));
773 return std::max(WaitStates, checkSetRegHazards(
MI));
776 return std::max(WaitStates, checkRFEHazards(
MI));
778 if ((ST.hasReadM0MovRelInterpHazard() &&
780 MI->getOpcode() == AMDGPU::DS_WRITE_ADDTID_B32 ||
781 MI->getOpcode() == AMDGPU::DS_READ_ADDTID_B32)) ||
783 (ST.hasReadM0LdsDmaHazard() &&
isLdsDma(*
MI)) ||
784 (ST.hasReadM0LdsDirectHazard() &&
785 MI->readsRegister(AMDGPU::LDS_DIRECT,
nullptr)))
786 return std::max(WaitStates, checkReadM0Hazards(
MI));
789 return std::max(WaitStates, checkMAIHazards(
MI));
792 return std::max(WaitStates, checkMAILdStHazards(
MI));
794 if (ST.hasPermlaneForwardingHazard() &&
isPermlane(*
MI))
795 return std::max(WaitStates, checkPermlaneHazards(
MI));
801 EmittedInstrs.push_front(
nullptr);
806 schedulerAdvanceCycle();
810 if (!CurrCycleInstr) {
811 EmittedInstrs.push_front(
nullptr);
813 if (HasPendingWMMACoexecHazard)
814 EmittedVALUInstrs.push_front(
nullptr);
818 HasPendingWMMACoexecHazard =
false;
820 if (CurrCycleInstr->isBundle()) {
825 unsigned NumWaitStates = TII.getNumWaitStates(*CurrCycleInstr);
826 if (!NumWaitStates) {
827 CurrCycleInstr =
nullptr;
832 EmittedInstrs.push_front(CurrCycleInstr);
839 EmittedVALUInstrs.push_front(CurrCycleInstr);
845 while (!EmittedVALUInstrs.empty() && EmittedVALUInstrs.front() ==
nullptr)
846 EmittedVALUInstrs.pop_front();
854 EmittedInstrs.push_front(
nullptr);
861 if (EmittedVALUInstrs.size() > MaxVALULookAhead)
862 EmittedVALUInstrs.resize(MaxVALULookAhead);
864 CurrCycleInstr =
nullptr;
869 "Bottom-up scheduling shouldn't run in hazard recognizer mode");
879template <
typename StateT>
889 static bool isEqual(
const StateMapKey &
LHS,
const StateMapKey &
RHS) {
894 static unsigned getHashValue(
const StateMapKey &
Key) {
895 return StateT::getHashValue((*
Key.States)[
Key.Idx]);
897 static unsigned getHashValue(
const StateT &State) {
898 return StateT::getHashValue(State);
900 static bool isEqual(
const StateMapKey &
LHS,
const StateMapKey &
RHS) {
901 return StateT::isEqual((*
LHS.States)[
LHS.Idx], (*
RHS.States)[
RHS.Idx]);
903 static bool isEqual(
const StateT &
LHS,
const StateMapKey &
RHS) {
904 return StateT::isEqual(
LHS, (*
RHS.States)[
RHS.Idx]);
913 StateT State = InitialState;
916 unsigned WorkIdx = 0;
918 bool Expired =
false;
919 for (
auto E =
MBB->instr_rend();
I !=
E; ++
I) {
924 auto Result = IsHazard(State, *
I);
932 if (
I->isInlineAsm() ||
I->isMetaInstruction())
935 UpdateState(State, *
I);
939 size_t StateIdx = States.
size();
940 StateMapKey
Key = {&States, StateIdx};
941 auto Insertion = StateMap.
insert_as(std::pair(
Key, StateIdx), State);
942 if (Insertion.second) {
945 StateIdx = Insertion.first->second;
948 Worklist.
insert(std::pair(Pred, StateIdx));
951 if (WorkIdx == Worklist.
size())
955 std::tie(
MBB, StateIdx) = Worklist[WorkIdx++];
956 State = States[StateIdx];
957 I =
MBB->instr_rbegin();
969 *Pred.getParent()->getSubtarget<
GCNSubtarget>().getInstrInfo();
970 unsigned Unexecuted = 0, Passed = 0;
971 for (
auto I = Pred.instr_rbegin(),
E = Pred.instr_rend();
972 I !=
E &&
I->isTerminator(); ++
I, ++Passed) {
975 if (
I->isBranch() &&
I->getNumOperands() > 0 &&
I->getOperand(0).isMBB() &&
976 TII.getBranchDestBlock(*
I) ==
MBB)
987 return MI.isInlineAsm() ? 0 : GetNumWaitStates(
MI);
996class WindowDeficitSearch {
999 function_ref<std::optional<int>(
const MachineInstr &)> WindowFor,
1003 : WindowFor(WindowFor), GetNumWaitStates(GetNumWaitStates),
1004 MaxWindow(MaxWindow) {}
1006 int run(
const MachineInstr &
MI);
1013 const MachineBasicBlock *
MBB;
1018 void arrive(
const MachineBasicBlock *
MBB,
1021 void scan(Arrival
A);
1023 const function_ref<std::optional<int>(
const MachineInstr &)> WindowFor;
1025 const int MaxWindow;
1032 DenseMap<const MachineBasicBlock *, int> Best;
1037void WindowDeficitSearch::arrive(
1042 if (MaxWindow - Distance <= Deficit)
1045 if (Pending.empty())
1046 Pending.resize(MaxWindow);
1048 auto [It,
Inserted] = Best.try_emplace(
MBB, Distance);
1050 if (It->second <= Distance)
1052 It->second = Distance;
1055 assert(Distance < MaxWindow &&
"arrival outside the window");
1056 Pending[Distance].push_back({
MBB,
Start, Distance});
1061void WindowDeficitSearch::scan(Arrival
A) {
1063 if (Best.lookup(
A.MBB) <
A.Distance)
1066 int Distance =
A.Distance;
1067 for (
auto I =
A.Start,
E =
A.MBB->instr_rend();
I !=
E; ++
I) {
1071 if (std::optional<int> Window = WindowFor(*
I)) {
1072 assert(*Window >= 0 && *Window <= MaxWindow &&
"window out of bounds");
1073 Deficit = std::max(Deficit, *Window - Distance);
1078 if (Distance >= MaxWindow)
1083 auto Start = Pred->instr_rbegin(),
End = Pred->instr_rend();
1089 assert(!WindowFor(*Start) &&
"terminators must not ask for a window");
1093 arrive(Pred, Start, Distance + Executed);
1100 scan({
MI.getParent(), std::next(
MI.getReverseIterator()), 0});
1106 for (
int Distance = 0; Distance < static_cast<int>(Pending.size());
1108 for (
unsigned I = 0;
I != Pending[Distance].size(); ++
I)
1109 scan(Pending[Distance][
I]);
1125 for (
auto E =
MBB->instr_rend();
I !=
E; ++
I) {
1130 if (
I->isMetaInstruction())
1136 if (
I->isInlineAsm())
1139 WaitStates += GetNumWaitStates(*
I);
1141 if (IsExpired(*
I, WaitStates))
1142 return std::numeric_limits<int>::max();
1145 int MinWaitStates = std::numeric_limits<int>::max();
1147 if (!Visited.
insert(Pred).second)
1151 IsExpired, Visited, GetNumWaitStates);
1153 MinWaitStates = std::min(MinWaitStates, W);
1156 return MinWaitStates;
1167 std::next(
MI->getReverseIterator()), 0, IsExpired,
1168 Visited, GetNumWaitStates);
1171int GCNHazardRecognizer::getMaxWindowDeficit(
int MaxWindow,
1172 WindowForFn WindowFor)
const {
1174 return WindowDeficitSearch(WindowFor, MaxWindow).run(*CurrCycleInstr);
1178 int Deficit = 0, Distance = 0;
1179 for (MachineInstr *
MI : EmittedInstrs) {
1181 if (std::optional<int> Window = WindowFor(*
MI)) {
1182 assert(*Window >= 0 && *Window <= MaxWindow &&
"window out of bounds");
1183 Deficit = std::max(Deficit, *Window - Distance);
1190 if (Distance >= MaxWindow)
1196int GCNHazardRecognizer::getWaitStatesSince(
1197 IsHazardFn IsHazard,
int Limit, GetNumWaitStatesFn GetNumWaitStates)
const {
1199 auto IsExpiredFn = [Limit](
const MachineInstr &,
int WaitStates) {
1200 return WaitStates >= Limit;
1202 return ::getWaitStatesSince(IsHazard, CurrCycleInstr,
IsExpiredFn,
1207 for (MachineInstr *
MI : EmittedInstrs) {
1212 if (
MI->isInlineAsm())
1215 WaitStates +=
MI ? GetNumWaitStates(*
MI) : 1;
1217 if (WaitStates >= Limit)
1220 return std::numeric_limits<int>::max();
1223int GCNHazardRecognizer::getWaitStatesSince(IsHazardFn IsHazard,
1228int GCNHazardRecognizer::getMaxVALUWindowDeficit(
int MaxWindow,
1229 WindowForFn WindowFor)
const {
1231 auto GetVALUWaitStates = [](
const MachineInstr &
MI) ->
unsigned {
1234 return WindowDeficitSearch(WindowFor, MaxWindow, GetVALUWaitStates)
1235 .run(*CurrCycleInstr);
1241 assert(MaxWindow <=
static_cast<int>(MaxVALULookAhead) &&
1242 "MaxWindow exceeds the EmittedVALUInstrs lookahead window");
1244 for (MachineInstr *
MI : EmittedVALUInstrs) {
1246 if (std::optional<int> Window = WindowFor(*
MI)) {
1247 assert(*Window >= 0 && *Window <= MaxWindow &&
"window out of bounds");
1248 return *Window - WaitStates;
1254 if (WaitStates >= MaxWindow)
1260int GCNHazardRecognizer::getWaitStatesSinceDef(
unsigned Reg,
1261 IsHazardFn IsHazardDef,
1263 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1266 return IsHazardDef(
MI) &&
MI.modifiesRegister(
Reg, TRI);
1269 return getWaitStatesSince(
IsHazardFn, Limit);
1272int GCNHazardRecognizer::getWaitStatesSinceSetReg(IsHazardFn IsHazard,
1278 return getWaitStatesSince(
IsHazardFn, Limit);
1287 for (MCRegUnit Unit :
TRI.regunits(
Reg))
1288 BV.
set(
static_cast<unsigned>(Unit));
1300void GCNHazardRecognizer::addClauseInst(
const MachineInstr &
MI)
const {
1312int GCNHazardRecognizer::checkSoftClauseHazards(
MachineInstr *MEM)
const {
1315 if (!ST.isXNACKEnabled())
1318 bool IsSMRD = TII.isSMRD(*MEM);
1332 for (MachineInstr *
MI : EmittedInstrs) {
1344 if (ClauseDefs.none())
1350 if (
MEM->mayStore())
1353 addClauseInst(*MEM);
1357 return ClauseDefs.anyCommon(ClauseUses) ? 1 : 0;
1360int GCNHazardRecognizer::checkSMRDHazards(
MachineInstr *SMRD)
const {
1361 int WaitStatesNeeded = 0;
1363 WaitStatesNeeded = checkSoftClauseHazards(SMRD);
1366 if (!ST.hasSMRDReadVALUDefHazard())
1367 return WaitStatesNeeded;
1371 int SmrdSgprWaitStates = 4;
1372 auto IsHazardDefFn = [
this](
const MachineInstr &
MI) {
1373 return TII.isVALU(
MI,
true);
1375 auto IsBufferHazardDefFn = [
this](
const MachineInstr &
MI) {
1376 return TII.isSALU(
MI);
1379 bool IsBufferSMRD = TII.isBufferSMRD(*SMRD);
1381 for (
const MachineOperand &Use :
SMRD->uses()) {
1384 int WaitStatesNeededForUse =
1385 SmrdSgprWaitStates - getWaitStatesSinceDef(
Use.getReg(), IsHazardDefFn,
1386 SmrdSgprWaitStates);
1387 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1397 int WaitStatesNeededForUse =
1398 SmrdSgprWaitStates - getWaitStatesSinceDef(
Use.getReg(),
1399 IsBufferHazardDefFn,
1400 SmrdSgprWaitStates);
1401 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1405 return WaitStatesNeeded;
1408int GCNHazardRecognizer::checkVMEMHazards(
MachineInstr *VMEM)
const {
1409 if (!ST.hasVMEMReadSGPRVALUDefHazard())
1412 int WaitStatesNeeded = checkSoftClauseHazards(VMEM);
1416 const int VmemSgprWaitStates = 5;
1417 auto IsHazardDefFn = [
this](
const MachineInstr &
MI) {
1418 return TII.isVALU(
MI,
true);
1420 for (
const MachineOperand &Use :
VMEM->uses()) {
1421 if (!
Use.isReg() || TRI.isVectorRegister(MF.getRegInfo(),
Use.getReg()))
1424 int WaitStatesNeededForUse =
1425 VmemSgprWaitStates - getWaitStatesSinceDef(
Use.getReg(), IsHazardDefFn,
1426 VmemSgprWaitStates);
1427 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1429 return WaitStatesNeeded;
1433 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1434 const SIInstrInfo *TII = ST.getInstrInfo();
1437 int DppVgprWaitStates = 2;
1438 int DppExecWaitStates = 5;
1439 int WaitStatesNeeded = 0;
1440 auto IsHazardDefFn = [TII](
const MachineInstr &
MI) {
1441 return TII->isVALU(
MI,
true);
1444 for (
const MachineOperand &Use :
DPP->uses()) {
1445 if (!
Use.isReg() || !TRI->isVGPR(MF.getRegInfo(),
Use.getReg()))
1447 int WaitStatesNeededForUse =
1448 DppVgprWaitStates - getWaitStatesSinceDef(
1450 [](
const MachineInstr &) { return true; },
1452 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1455 WaitStatesNeeded = std::max(
1457 DppExecWaitStates - getWaitStatesSinceDef(AMDGPU::EXEC, IsHazardDefFn,
1458 DppExecWaitStates));
1460 return WaitStatesNeeded;
1463int GCNHazardRecognizer::checkDivFMasHazards(
MachineInstr *DivFMas)
const {
1464 const SIInstrInfo *TII = ST.getInstrInfo();
1468 const int DivFMasWaitStates = 4;
1469 auto IsHazardDefFn = [TII](
const MachineInstr &
MI) {
1470 return TII->isVALU(
MI,
true);
1472 int WaitStatesNeeded = getWaitStatesSinceDef(AMDGPU::VCC, IsHazardDefFn,
1475 return DivFMasWaitStates - WaitStatesNeeded;
1478int GCNHazardRecognizer::checkGetRegHazards(
MachineInstr *GetRegInstr)
const {
1479 const SIInstrInfo *TII = ST.getInstrInfo();
1480 unsigned GetRegHWReg =
getHWReg(TII, *GetRegInstr);
1482 const int GetRegWaitStates = 2;
1483 auto IsHazardFn = [TII, GetRegHWReg](
const MachineInstr &
MI) {
1486 int WaitStatesNeeded = getWaitStatesSinceSetReg(
IsHazardFn, GetRegWaitStates);
1488 return GetRegWaitStates - WaitStatesNeeded;
1491int GCNHazardRecognizer::checkSetRegHazards(
MachineInstr *SetRegInstr)
const {
1492 const SIInstrInfo *TII = ST.getInstrInfo();
1493 unsigned HWReg =
getHWReg(TII, *SetRegInstr);
1495 const int SetRegWaitStates = ST.getSetRegWaitStates();
1496 auto IsHazardFn = [TII, HWReg](
const MachineInstr &
MI) {
1499 int WaitStatesNeeded = getWaitStatesSinceSetReg(
IsHazardFn, SetRegWaitStates);
1500 return SetRegWaitStates - WaitStatesNeeded;
1503int GCNHazardRecognizer::createsVALUHazard(
const MachineInstr &
MI)
const {
1507 const SIInstrInfo *TII = ST.getInstrInfo();
1508 unsigned Opcode =
MI.getOpcode();
1509 const MCInstrDesc &
Desc =
MI.getDesc();
1511 int VDataIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::vdata);
1514 VDataRCID = TII->getOpRegClassID(
Desc.operands()[VDataIdx]);
1516 if (TII->isMUBUF(
MI) || TII->isMTBUF(
MI)) {
1526 if (ST.hasVDecCoExecHazard())
1528 const MachineOperand *SOffset =
1529 TII->getNamedOperand(
MI, AMDGPU::OpName::soffset);
1530 if (!SOffset || !SOffset->
isReg())
1539 if (TII->isMIMG(
MI)) {
1540 int SRsrcIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::srsrc);
1542 Desc.operands()[SRsrcIdx])) == 256);
1546 if (TII->isFLAT(
MI)) {
1558int GCNHazardRecognizer::checkUniformWindowVALUHazardsHelper(
1563 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1565 auto IsHazard = [&](
const MachineInstr &
MI) {
1566 int DataIdx = createsVALUHazard(
MI);
1567 return DataIdx >= 0 &&
1568 TRI->regsOverlap(
MI.getOperand(DataIdx).getReg(),
Reg);
1571 return std::max(0, 1 - getWaitStatesSince(IsHazard, 1));
1574int GCNHazardRecognizer::checkSOFFSETWindowVALUHazardsHelper(
1581 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1582 const SIInstrInfo *TII = ST.getInstrInfo();
1584 int WaitStatesNeeded = 0;
1588 for (
int Window = 1; Window <= 2; ++Window) {
1589 auto IsHazard = [&](
const MachineInstr &
MI) {
1590 int DataIdx = createsVALUHazard(
MI);
1592 !TRI->regsOverlap(
MI.getOperand(DataIdx).getReg(),
Reg))
1597 if (Window == 1 || !TII->isBUF(
MI))
1600 const MachineOperand *SOffset =
1601 TII->getNamedOperand(
MI, AMDGPU::OpName::soffset);
1602 return !SOffset || !SOffset->
isReg();
1604 WaitStatesNeeded = std::max(WaitStatesNeeded,
1605 Window - getWaitStatesSince(IsHazard, Window));
1608 return WaitStatesNeeded;
1611int GCNHazardRecognizer::checkVALUHazardsHelper(
1616 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1618 if (!TRI->isVectorRegister(MRI,
Def.getReg()))
1621 if (ST.hasVDecCoExecHazard())
1622 return checkSOFFSETWindowVALUHazardsHelper(
Def.getReg());
1624 return checkUniformWindowVALUHazardsHelper(
Def.getReg());
1640 unsigned Opcode =
MI.getOpcode();
1650 if (
auto *DstSel =
TII->getNamedOperand(
MI, AMDGPU::OpName::dst_sel))
1652 return TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
1660 (
TII->getNamedImmOperand(
MI, AMDGPU::OpName::src0_modifiers) &
1662 return TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
1670 return TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
1674 (
TII->getNamedImmOperand(
MI, AMDGPU::OpName::src2_modifiers) &
1676 return TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
1682 return TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
1703 for (
auto &Operand : VALU->operands()) {
1704 if (Operand.isReg() &&
TRI->regsOverlap(Dst->getReg(), Operand.getReg())) {
1711int GCNHazardRecognizer::checkVALUHazards(
MachineInstr *VALU)
const {
1712 int WaitStatesNeeded = 0;
1715 const int TransDefWaitstates = 1;
1717 auto IsTransDefFn = [
this,
VALU](
const MachineInstr &
MI) {
1720 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1721 const SIInstrInfo *TII = ST.getInstrInfo();
1722 Register Def = TII->getNamedOperand(
MI, AMDGPU::OpName::vdst)->getReg();
1724 for (
const MachineOperand &Use :
VALU->explicit_uses()) {
1725 if (
Use.isReg() && TRI->regsOverlap(Def,
Use.getReg()))
1732 int WaitStatesNeededForDef =
1733 TransDefWaitstates -
1734 getWaitStatesSince(IsTransDefFn, TransDefWaitstates);
1735 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1738 if (ST.hasDstSelForwardingHazard() || ST.hasCvtScaleForwardingHazard()) {
1739 const int Shift16DefWaitstates = 1;
1741 auto IsShift16BitDefFn = [
this,
VALU](
const MachineInstr &ProducerMI) {
1742 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1743 const MachineOperand *ForwardedDst =
1749 if (ProducerMI.isInlineAsm()) {
1751 for (
auto &Def : ProducerMI.all_defs()) {
1760 int WaitStatesNeededForDef =
1761 Shift16DefWaitstates -
1762 getWaitStatesSince(IsShift16BitDefFn, Shift16DefWaitstates);
1763 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1766 if (ST.hasVDecCoExecHazard()) {
1767 const int VALUWriteSGPRVALUReadWaitstates = 2;
1768 const int VALUWriteEXECRWLane = 4;
1769 const int VALUWriteVGPRReadlaneRead = 1;
1771 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1772 const MachineRegisterInfo &MRI = MF.getRegInfo();
1774 auto IsVALUDefSGPRFn = [&
UseReg, TRI](
const MachineInstr &
MI) {
1777 return MI.modifiesRegister(
UseReg, TRI);
1780 for (
const MachineOperand &Use :
VALU->explicit_uses()) {
1785 if (TRI->isSGPRReg(MRI,
UseReg)) {
1786 int WaitStatesNeededForDef =
1787 VALUWriteSGPRVALUReadWaitstates -
1788 getWaitStatesSince(IsVALUDefSGPRFn,
1789 VALUWriteSGPRVALUReadWaitstates);
1790 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1794 if (
VALU->readsRegister(AMDGPU::VCC, TRI)) {
1796 int WaitStatesNeededForDef =
1797 VALUWriteSGPRVALUReadWaitstates -
1798 getWaitStatesSince(IsVALUDefSGPRFn, VALUWriteSGPRVALUReadWaitstates);
1799 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1802 switch (
VALU->getOpcode()) {
1803 case AMDGPU::V_READLANE_B32:
1804 case AMDGPU::V_READFIRSTLANE_B32: {
1805 MachineOperand *Src = TII.getNamedOperand(*VALU, AMDGPU::OpName::src0);
1807 int WaitStatesNeededForDef =
1808 VALUWriteVGPRReadlaneRead -
1809 getWaitStatesSince(IsVALUDefSGPRFn, VALUWriteVGPRReadlaneRead);
1810 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1813 case AMDGPU::V_WRITELANE_B32: {
1815 int WaitStatesNeededForDef =
1816 VALUWriteEXECRWLane -
1817 getWaitStatesSince(IsVALUDefSGPRFn, VALUWriteEXECRWLane);
1818 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1828 if (!ST.has12DWordStoreHazard())
1829 return WaitStatesNeeded;
1831 const MachineRegisterInfo &MRI = MF.getRegInfo();
1833 for (
const MachineOperand &Def :
VALU->defs()) {
1834 WaitStatesNeeded = std::max(WaitStatesNeeded, checkVALUHazardsHelper(Def, MRI));
1837 return WaitStatesNeeded;
1840int GCNHazardRecognizer::checkInlineAsmHazards(
MachineInstr *IA)
const {
1849 if (!ST.has12DWordStoreHazard() && !ST.hasDstSelForwardingHazard() &&
1850 !ST.hasCvtScaleForwardingHazard())
1853 const MachineRegisterInfo &MRI = MF.getRegInfo();
1854 int WaitStatesNeeded = 0;
1856 for (
const MachineOperand &
Op :
1858 if (
Op.isReg() &&
Op.isDef()) {
1859 if (!TRI.isVectorRegister(MRI,
Op.getReg()))
1862 if (ST.has12DWordStoreHazard()) {
1864 std::max(WaitStatesNeeded, checkVALUHazardsHelper(
Op, MRI));
1869 if (ST.hasDstSelForwardingHazard()) {
1870 const int Shift16DefWaitstates = 1;
1872 auto IsShift16BitDefFn = [
this, &
IA](
const MachineInstr &ProducerMI) {
1876 return IA->modifiesRegister(Dst->getReg(), &TRI) ||
1877 IA->readsRegister(Dst->getReg(), &TRI);
1879 if (ProducerMI.isInlineAsm()) {
1881 for (
auto &Def : ProducerMI.all_defs()) {
1882 if (
IA->modifiesRegister(
Def.getReg(), &TRI) ||
1883 IA->readsRegister(
Def.getReg(), &TRI)) {
1892 int WaitStatesNeededForDef =
1893 Shift16DefWaitstates -
1894 getWaitStatesSince(IsShift16BitDefFn, Shift16DefWaitstates);
1895 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1898 return WaitStatesNeeded;
1901int GCNHazardRecognizer::checkRWLaneHazards(
MachineInstr *RWLane)
const {
1902 const SIInstrInfo *TII = ST.getInstrInfo();
1903 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1904 const MachineRegisterInfo &MRI = MF.getRegInfo();
1906 const MachineOperand *LaneSelectOp =
1907 TII->getNamedOperand(*RWLane, AMDGPU::OpName::src1);
1909 if (!LaneSelectOp->
isReg() || !TRI->isSGPRReg(MRI, LaneSelectOp->
getReg()))
1914 return TII->isVALU(
MI,
true);
1917 const int RWLaneWaitStates = 4;
1918 int WaitStatesSince = getWaitStatesSinceDef(LaneSelectReg,
IsHazardFn,
1920 return RWLaneWaitStates - WaitStatesSince;
1923int GCNHazardRecognizer::checkRFEHazards(
MachineInstr *RFE)
const {
1924 if (!ST.hasRFEHazards())
1927 const SIInstrInfo *TII = ST.getInstrInfo();
1929 const int RFEWaitStates = 1;
1934 int WaitStatesNeeded = getWaitStatesSinceSetReg(
IsHazardFn, RFEWaitStates);
1935 return RFEWaitStates - WaitStatesNeeded;
1938int GCNHazardRecognizer::checkReadM0Hazards(
MachineInstr *
MI)
const {
1939 const SIInstrInfo *TII = ST.getInstrInfo();
1940 const int ReadM0WaitStates = 1;
1941 auto IsHazardFn = [TII](
const MachineInstr &
MI) {
return TII->isSALU(
MI); };
1942 return ReadM0WaitStates -
1943 getWaitStatesSinceDef(AMDGPU::M0,
IsHazardFn, ReadM0WaitStates);
1948 int WaitStatesNeeded,
bool IsHoisting) {
1950 for (
int I = 0;
I < WaitStatesNeeded; ++
I)
1951 BuildMI(
MBB, InsertPt,
DL, TII.get(AMDGPU::V_NOP_e32));
1955 fixVMEMtoScalarWriteHazards(
MI);
1956 fixVcmpxPermlaneHazards(
MI);
1957 fixSMEMtoVectorWriteHazards(
MI);
1958 fixVcmpxExecWARHazard(
MI);
1959 fixLdsBranchVmemWARHazard(
MI);
1960 if (ST.hasLdsDirect()) {
1961 fixLdsDirectVALUHazard(
MI);
1962 fixLdsDirectVMEMHazard(
MI);
1964 fixVALUPartialForwardingHazard(
MI);
1965 fixVALUTransUseHazard(
MI);
1966 fixVALUTransCoexecutionHazards(
MI);
1968 fixWMMACoexecutionHazards(
MI);
1969 fixShift64HighRegBug(
MI);
1970 fixPkF32InvalidOpSel(
MI);
1971 fixVALUMaskWriteHazard(
MI);
1972 fixRequiredExportPriority(
MI);
1973 if (ST.hasVPermPk16Hazard())
1974 fixVPermPk16Hazard(
MI);
1975 if (ST.requiresWaitIdleBeforeGetReg())
1976 fixGetRegWaitIdle(
MI);
1977 if (ST.hasDsAtomicAsyncBarrierArriveB64PipeBug())
1978 fixDsAtomicAsyncBarrierArriveB64(
MI);
1979 if (ST.hasScratchBaseForwardingHazard())
1980 fixScratchBaseForwardingHazard(
MI);
1981 if (ST.setRegModeNeedsVNOPs())
1983 if (ST.hasNeedsTDMDrain())
1989 return (
TII.isVOPC(
MI) ||
1990 (
MI.isCompare() && (
TII.isVOP3(
MI) ||
TII.isSDWA(
MI)))) &&
1991 MI.modifiesRegister(AMDGPU::EXEC, &
TRI);
1994bool GCNHazardRecognizer::fixVcmpxPermlaneHazards(
MachineInstr *
MI) {
1998 const SIInstrInfo *TII = ST.getInstrInfo();
1999 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2005 unsigned Opc =
MI.getOpcode();
2007 Opc != AMDGPU::V_NOP_e32 &&
Opc != AMDGPU::V_NOP_e64 &&
2008 Opc != AMDGPU::V_NOP_sdwa;
2012 std::numeric_limits<int>::max())
2018 auto *
Src0 = TII->getNamedOperand(*
MI, AMDGPU::OpName::src0);
2020 bool IsUndef =
Src0->isUndef();
2022 TII->get(AMDGPU::V_MOV_B32_e32))
2029bool GCNHazardRecognizer::fixVMEMtoScalarWriteHazards(
MachineInstr *
MI) {
2030 if (!ST.hasVMEMtoScalarWriteHazard())
2032 assert(!ST.hasExtendedWaitCounts());
2037 if (
MI->getNumDefs() == 0)
2040 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2046 for (
const MachineOperand &Def :
MI->defs()) {
2047 const MachineOperand *
Op =
2048 I.findRegisterUseOperand(
Def.getReg(), TRI,
false);
2058 (
MI.getOpcode() == AMDGPU::S_WAITCNT &&
2059 !
MI.getOperand(0).getImm()) ||
2060 (
MI.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2062 static_cast<unsigned>(
MI.getOperand(0).getImm())) == 0);
2066 std::numeric_limits<int>::max())
2069 const SIInstrInfo *TII = ST.getInstrInfo();
2071 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
2076bool GCNHazardRecognizer::fixSMEMtoVectorWriteHazards(
MachineInstr *
MI) {
2077 if (!ST.hasSMEMtoVectorWriteHazard())
2079 assert(!ST.hasExtendedWaitCounts());
2084 AMDGPU::OpName SDSTName;
2085 switch (
MI->getOpcode()) {
2086 case AMDGPU::V_READLANE_B32:
2087 case AMDGPU::V_READFIRSTLANE_B32:
2088 SDSTName = AMDGPU::OpName::vdst;
2091 SDSTName = AMDGPU::OpName::sdst;
2095 const SIInstrInfo *TII = ST.getInstrInfo();
2096 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2098 const MachineOperand *SDST = TII->getNamedOperand(*
MI, SDSTName);
2100 for (
const auto &MO :
MI->implicit_operands()) {
2101 if (MO.isDef() && TRI->isSGPRClass(TRI->getPhysRegBaseClass(MO.getReg()))) {
2112 auto IsHazardFn = [SDSTReg, TRI](
const MachineInstr &
I) {
2117 if (TII->isSALU(
MI)) {
2118 switch (
MI.getOpcode()) {
2119 case AMDGPU::S_SETVSKIP:
2120 case AMDGPU::S_VERSION:
2121 case AMDGPU::S_WAITCNT_VSCNT:
2122 case AMDGPU::S_WAITCNT_VMCNT:
2123 case AMDGPU::S_WAITCNT_EXPCNT:
2126 case AMDGPU::S_WAITCNT_LGKMCNT:
2128 return (
MI.getOperand(1).getImm() == 0) &&
2129 (
MI.getOperand(0).
getReg() == AMDGPU::SGPR_NULL);
2130 case AMDGPU::S_WAITCNT: {
2131 const int64_t
Imm =
MI.getOperand(0).getImm();
2132 AMDGPU::Waitcnt Decoded =
2139 MI.getOpcode() == AMDGPU::S_WAIT_IDLE) &&
2140 "unexpected wait count instruction");
2142 if (TII->isSOPP(
MI))
2158 std::numeric_limits<int>::max())
2162 TII->get(AMDGPU::S_MOV_B32), AMDGPU::SGPR_NULL)
2167bool GCNHazardRecognizer::fixVcmpxExecWARHazard(
MachineInstr *
MI) {
2168 if (!ST.hasVcmpxExecWARHazard())
2170 assert(!ST.hasExtendedWaitCounts());
2175 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2176 if (!
MI->modifiesRegister(AMDGPU::EXEC, TRI))
2182 return I.readsRegister(AMDGPU::EXEC, TRI);
2185 const SIInstrInfo *TII = ST.getInstrInfo();
2186 auto IsExpiredFn = [TII, TRI](
const MachineInstr &
MI, int) {
2188 if (TII->getNamedOperand(
MI, AMDGPU::OpName::sdst))
2190 for (
auto MO :
MI.implicit_operands())
2191 if (MO.isDef() && TRI->isSGPRClass(TRI->getPhysRegBaseClass(MO.getReg())))
2194 if (
MI.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2196 static_cast<unsigned>(
MI.getOperand(0).getImm())) == 0)
2202 std::numeric_limits<int>::max())
2206 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
2213 if (!ST.hasLdsBranchVmemWARHazard())
2218 bool HasLds =
false;
2219 bool HasVmem =
false;
2220 for (
auto &
MBB : MF) {
2221 for (
auto &
MI :
MBB) {
2224 if (HasLds && HasVmem)
2232 return I.getOpcode() == AMDGPU::S_WAITCNT_VSCNT &&
2233 I.getOperand(0).getReg() == AMDGPU::SGPR_NULL &&
2234 !
I.getOperand(1).getImm();
2237bool GCNHazardRecognizer::fixLdsBranchVmemWARHazard(
MachineInstr *
MI) {
2238 if (!RunLdsBranchVmemWARHazardFixup)
2241 assert(ST.hasLdsBranchVmemWARHazard());
2242 assert(!ST.hasExtendedWaitCounts());
2244 auto IsHazardInst = [](
const MachineInstr &
MI) {
2252 auto InstType = IsHazardInst(*
MI);
2256 auto IsExpiredFn = [&IsHazardInst](
const MachineInstr &
I, int) {
2260 auto IsHazardFn = [InstType, &IsHazardInst](
const MachineInstr &
I) {
2264 auto IsHazardFn = [InstType, IsHazardInst](
const MachineInstr &
I) {
2265 auto InstType2 = IsHazardInst(
I);
2266 return InstType2 && InstType != InstType2;
2269 auto IsExpiredFn = [InstType, &IsHazardInst](
const MachineInstr &
I, int) {
2270 auto InstType2 = IsHazardInst(
I);
2271 if (InstType == InstType2)
2278 std::numeric_limits<int>::max();
2282 std::numeric_limits<int>::max())
2285 const SIInstrInfo *TII = ST.getInstrInfo();
2287 TII->get(AMDGPU::S_WAITCNT_VSCNT))
2294bool GCNHazardRecognizer::fixLdsDirectVALUHazard(
MachineInstr *
MI) {
2298 const int NoHazardWaitStates = 15;
2299 const MachineOperand *VDST = TII.getNamedOperand(*
MI, AMDGPU::OpName::vdst);
2302 bool VisitedTrans =
false;
2303 auto IsHazardFn = [
this, VDSTReg, &VisitedTrans](
const MachineInstr &
I) {
2308 return I.readsRegister(VDSTReg, &TRI) ||
I.modifiesRegister(VDSTReg, &TRI);
2310 auto IsExpiredFn = [&](
const MachineInstr &
I,
int WaitStates) {
2311 if (WaitStates >= NoHazardWaitStates)
2317 auto GetWaitStatesFn = [](
const MachineInstr &
MI) {
2321 DenseSet<const MachineBasicBlock *> Visited;
2323 std::next(
MI->getReverseIterator()), 0,
2331 MachineOperand *WaitVdstOp =
2332 TII.getNamedOperand(*
MI, AMDGPU::OpName::waitvdst);
2333 WaitVdstOp->
setImm(std::min(
Count, NoHazardWaitStates));
2338bool GCNHazardRecognizer::fixLdsDirectVMEMHazard(
MachineInstr *
MI) {
2342 const MachineOperand *VDST = TII.getNamedOperand(*
MI, AMDGPU::OpName::vdst);
2345 auto IsHazardFn = [
this, VDSTReg](
const MachineInstr &
I) {
2348 return I.readsRegister(VDSTReg, &TRI) ||
I.modifiesRegister(VDSTReg, &TRI);
2350 bool LdsdirCanWait = ST.hasLdsWaitVMSRC();
2353 auto IsExpiredFn = [
this, LdsdirCanWait](
const MachineInstr &
I, int) {
2356 (
I.getOpcode() == AMDGPU::S_WAITCNT && !
I.getOperand(0).getImm()) ||
2357 (
I.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2359 static_cast<unsigned>(
I.getOperand(0).getImm())) == 0) ||
2361 !TII.getNamedOperand(
I, AMDGPU::OpName::waitvsrc)->getImm());
2365 std::numeric_limits<int>::max())
2368 if (LdsdirCanWait) {
2369 TII.getNamedOperand(*
MI, AMDGPU::OpName::waitvsrc)->setImm(0);
2372 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
2379bool GCNHazardRecognizer::fixVALUPartialForwardingHazard(
MachineInstr *
MI) {
2380 if (!ST.hasVALUPartialForwardingHazard())
2382 assert(!ST.hasExtendedWaitCounts());
2387 SmallSetVector<Register, 4> SrcVGPRs;
2389 for (
const MachineOperand &Use :
MI->explicit_uses()) {
2390 if (
Use.isReg() && TRI.isVGPR(MF.getRegInfo(),
Use.getReg()))
2395 if (SrcVGPRs.
size() <= 1)
2413 const int Intv1plus2MaxVALUs = 2;
2414 const int Intv3MaxVALUs = 4;
2415 const int IntvMaxVALUs = 6;
2416 const int NoHazardVALUWaitStates = IntvMaxVALUs + 2;
2419 SmallDenseMap<Register, int, 4> DefPos;
2420 int ExecPos = std::numeric_limits<int>::max();
2423 static unsigned getHashValue(
const StateType &State) {
2425 for (
const auto &[
Reg, Pos] : State.DefPos)
2427 return static_cast<unsigned>(
H);
2429 static bool isEqual(
const StateType &
LHS,
const StateType &
RHS) {
2430 return LHS.DefPos ==
RHS.DefPos &&
LHS.ExecPos ==
RHS.ExecPos &&
2438 auto IsHazardFn = [&,
this](StateType &State,
const MachineInstr &
I) {
2440 if (State.VALUs > NoHazardVALUWaitStates)
2446 (
I.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2448 static_cast<unsigned>(
I.getOperand(0).getImm())) == 0))
2455 if (!State.DefPos.count(Src) &&
I.modifiesRegister(Src, &TRI)) {
2456 State.DefPos[Src] = State.VALUs;
2461 if (State.ExecPos == std::numeric_limits<int>::max()) {
2462 if (!State.DefPos.empty() &&
I.modifiesRegister(AMDGPU::EXEC, &TRI)) {
2463 State.ExecPos = State.VALUs;
2470 if (State.VALUs > Intv3MaxVALUs && State.DefPos.empty())
2478 if (State.ExecPos == std::numeric_limits<int>::max())
2481 int PreExecPos = std::numeric_limits<int>::max();
2482 int PostExecPos = std::numeric_limits<int>::max();
2484 for (
auto Entry : State.DefPos) {
2485 int DefVALUs =
Entry.second;
2486 if (DefVALUs != std::numeric_limits<int>::max()) {
2487 if (DefVALUs >= State.ExecPos)
2488 PreExecPos = std::min(PreExecPos, DefVALUs);
2490 PostExecPos = std::min(PostExecPos, DefVALUs);
2495 if (PostExecPos == std::numeric_limits<int>::max())
2499 int Intv3VALUs = PostExecPos;
2500 if (Intv3VALUs > Intv3MaxVALUs)
2504 int Intv2VALUs = (State.ExecPos - PostExecPos) - 1;
2505 if (Intv2VALUs > Intv1plus2MaxVALUs)
2509 if (PreExecPos == std::numeric_limits<int>::max())
2513 int Intv1VALUs = PreExecPos - State.ExecPos;
2514 if (Intv1VALUs > Intv1plus2MaxVALUs)
2518 if (Intv1VALUs + Intv2VALUs > Intv1plus2MaxVALUs)
2523 auto UpdateStateFn = [](StateType &State,
const MachineInstr &
MI) {
2529 std::next(
MI->getReverseIterator())))
2533 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
2539bool GCNHazardRecognizer::fixVALUTransUseHazard(
MachineInstr *
MI) {
2540 if (!ST.hasVALUTransUseHazard())
2542 assert(!ST.hasExtendedWaitCounts());
2547 SmallSet<Register, 4> SrcVGPRs;
2549 for (
const MachineOperand &Use :
MI->explicit_uses()) {
2550 if (
Use.isReg() && TRI.isVGPR(MF.getRegInfo(),
Use.getReg()))
2564 const int IntvMaxVALUs = 5;
2565 const int IntvMaxTRANS = 1;
2571 static unsigned getHashValue(
const StateType &State) {
2572 return static_cast<unsigned>(
hash_combine(State.VALUs, State.TRANS));
2574 static bool isEqual(
const StateType &
LHS,
const StateType &
RHS) {
2575 return LHS.VALUs ==
RHS.VALUs &&
LHS.TRANS ==
RHS.TRANS;
2582 auto IsHazardFn = [&,
this](StateType &State,
const MachineInstr &
I) {
2584 if (State.VALUs > IntvMaxVALUs || State.TRANS > IntvMaxTRANS)
2590 (
I.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2592 static_cast<unsigned>(
I.getOperand(0).getImm())) == 0))
2598 if (
I.modifiesRegister(Src, &TRI)) {
2606 auto UpdateStateFn = [](StateType &State,
const MachineInstr &
MI) {
2614 std::next(
MI->getReverseIterator())))
2620 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
2626bool GCNHazardRecognizer::fixVALUTransCoexecutionHazards(
MachineInstr *
MI) {
2627 if (!ST.hasTransCoexecutionHazard() ||
2632 const SIInstrInfo *TII = ST.getInstrInfo();
2633 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2635 auto IsTransHazardFn = [
MI, TII, TRI](
const MachineInstr &
I) {
2640 Register TransDef = TII->getNamedOperand(
I, AMDGPU::OpName::vdst)->getReg();
2641 for (
const MachineOperand &ValuUse :
MI->explicit_uses()) {
2642 if (ValuUse.isReg() && TRI->regsOverlap(TransDef, ValuUse.getReg()))
2648 for (
const MachineOperand &TransUse :
I.explicit_uses()) {
2649 if (TransUse.isReg() &&
MI->modifiesRegister(TransUse.getReg(), TRI))
2660 const int HasVALU = std::numeric_limits<int>::max();
2661 if (::getWaitStatesSince(IsTransHazardFn,
MI,
IsExpiredFn) == HasVALU)
2664 BuildMI(*
MI->getParent(),
MI,
MI->getDebugLoc(), TII->get(AMDGPU::V_NOP_e32));
2672 const SIInstrInfo *TII = ST.getInstrInfo();
2673 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2675 auto IsHazardFn = [
MI, TII, TRI,
this](
const MachineInstr &
I) {
2682 TII->getNamedOperand(*
MI, AMDGPU::OpName::src0)->getReg();
2684 TII->getNamedOperand(*
MI, AMDGPU::OpName::src1)->getReg();
2687 TII->getNamedOperand(
I, AMDGPU::OpName::vdst)->getReg();
2689 if (TRI->regsOverlap(PrevDstReg, CurSrc0Reg) ||
2690 TRI->regsOverlap(PrevDstReg, CurSrc1Reg)) {
2699 TII->getNamedOperand(*
MI, AMDGPU::OpName::src2)->getReg();
2700 if (TRI->regsOverlap(PrevDstReg, CurIndex))
2714 std::numeric_limits<int>::max())
2717 BuildMI(*
MI->getParent(),
MI,
MI->getDebugLoc(), TII->get(AMDGPU::V_NOP_e32));
2771 bool IsLowestRateWMMA = ST.hasGFX125xLowestRateWMMA();
2772 unsigned Category = 0;
2774 unsigned Latency = SchedModel.computeInstrLatency(&
MI);
2779 assert(!IsSWMMAC &&
"no 4-cycle SWMMAC expected");
2783 Category = IsSWMMAC ? 2 : 0;
2786 Category = IsLowestRateWMMA ? 4 : (IsSWMMAC ? 3 : 1);
2789 assert(IsLowestRateWMMA &&
"latency 32 is not expected");
2799int GCNHazardRecognizer::checkWMMACoexecutionHazards(
MachineInstr *
MI)
const {
2800 if (!ST.hasWMMACoexecutionHazards())
2803 const SIInstrInfo *TII = ST.getInstrInfo();
2812 const int WMMAWaitStates[] = {5, 9, 3, 5, 9, 17, 2};
2813 const int VALUWaitStates[] = {4, 8, 2, 4, 8, 16, 1};
2814 const bool IsWMMA = TII->isXDLWMMA(*
MI);
2815 const bool IsLowestRateWMMA = ST.hasGFX125xLowestRateWMMA();
2816 ArrayRef<int> RequiredWaitStates =
2817 IsWMMA ? ArrayRef<int>(WMMAWaitStates) :
ArrayRef<int>(VALUWaitStates);
2818 const int MaxWaitStates =
2819 IsWMMA ? (IsLowestRateWMMA ? 17 : 9) : (IsLowestRateWMMA ? 16 : 8);
2821 auto WindowFor = [=](
const MachineInstr &
I) -> std::optional<int> {
2822 if (!TII->isXDLWMMA(
I))
2823 return std::nullopt;
2824 if (IsWMMA ? !hasWMMAToWMMARegOverlap(
I, *
MI)
2825 : !hasWMMAToVALURegOverlap(
I, *
MI))
2826 return std::nullopt;
2831 return getMaxVALUWindowDeficit(MaxWaitStates, WindowFor);
2834bool GCNHazardRecognizer::hasWMMAToWMMARegOverlap(
2836 Register D0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::vdst)->getReg();
2837 Register A1 = TII.getNamedOperand(
MI, AMDGPU::OpName::src0)->getReg();
2838 Register B1 = TII.getNamedOperand(
MI, AMDGPU::OpName::src1)->getReg();
2841 if (TRI.regsOverlap(D0, A1) || TRI.regsOverlap(D0, B1))
2845 Register Idx1 = TII.getNamedOperand(
MI, AMDGPU::OpName::src2)->getReg();
2846 if (TRI.regsOverlap(D0, Idx1))
2852bool GCNHazardRecognizer::hasWMMAToVALURegOverlap(
2855 Register D0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::vdst)->getReg();
2856 for (
const MachineOperand &ValuUse :
MI.explicit_uses()) {
2857 if (ValuUse.isReg() && TRI.regsOverlap(D0, ValuUse.getReg()))
2862 Register A0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::src0)->getReg();
2863 Register B0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::src1)->getReg();
2866 const MachineOperand *
Src2 = TII.getNamedOperand(WMMA, AMDGPU::OpName::src2);
2868 WMMARegs.push_back(
Src2->getReg());
2870 for (
const MachineOperand &ValuDef :
MI.defs()) {
2871 Register VDstReg = ValuDef.getReg();
2872 for (
Register WMMAReg : WMMARegs) {
2873 if (TRI.regsOverlap(VDstReg, WMMAReg))
2880bool GCNHazardRecognizer::isCoexecutionHazardFor(
const MachineInstr &
I,
2884 if (!TII.isXDLWMMA(
I))
2888 if (TII.isXDLWMMA(
MI))
2889 return hasWMMAToWMMARegOverlap(
I,
MI);
2891 return hasWMMAToVALURegOverlap(
I,
MI);
2897 bool IncludeSubloops) {
2900 for (MachineBasicBlock *
MBB :
L->getBlocks()) {
2901 if (!IncludeSubloops && MLI->getLoopFor(
MBB) != L)
2903 for (MachineInstr &
I : *
MBB) {
2906 if (isCoexecutionHazardFor(
I, *
MI))
2913bool GCNHazardRecognizer::tryHoistWMMAVnopsFromLoop(
MachineInstr *
MI,
2914 int WaitStatesNeeded) {
2918 MachineLoop *
L = MLI->getLoopFor(
MI->getParent());
2920 ++NumWMMAHoistingBailed;
2925 if (hasWMMAHazardInLoop(L,
MI)) {
2926 ++NumWMMAHoistingBailed;
2931 MachineLoop *TargetLoop =
L;
2933 if (hasWMMAHazardInLoop(Parent,
MI,
false))
2935 TargetLoop = Parent;
2941 ++NumWMMAHoistingBailed;
2945 LLVM_DEBUG(
dbgs() <<
"WMMA V_NOP Hoisting: Moving " << WaitStatesNeeded
2951 NumWMMANopsHoisted += WaitStatesNeeded;
2955bool GCNHazardRecognizer::fixWMMACoexecutionHazards(
MachineInstr *
MI) {
2956 int WaitStatesNeeded = checkWMMACoexecutionHazards(
MI);
2957 if (WaitStatesNeeded <= 0)
2963 emitVNops(*
MI->getParent(),
MI->getIterator(), WaitStatesNeeded);
2967bool GCNHazardRecognizer::fixShift64HighRegBug(
MachineInstr *
MI) {
2968 if (!ST.hasShift64HighRegBug())
2970 assert(!ST.hasExtendedWaitCounts());
2972 switch (
MI->getOpcode()) {
2975 case AMDGPU::V_LSHLREV_B64_e64:
2976 case AMDGPU::V_LSHRREV_B64_e64:
2977 case AMDGPU::V_ASHRREV_I64_e64:
2981 MachineOperand *Amt = TII.getNamedOperand(*
MI, AMDGPU::OpName::src0);
2986 const MachineRegisterInfo &MRI = MF.getRegInfo();
2988 if (!TRI.isVGPR(MRI, AmtReg) || ((AmtReg - AMDGPU::VGPR0) & 7) != 7)
2991 if (AmtReg != AMDGPU::VGPR255 && MRI.
isPhysRegUsed(AmtReg + 1))
2994 assert(ST.needsAlignedVGPRs());
2995 static_assert(AMDGPU::VGPR0 + 1 == AMDGPU::VGPR1);
2999 MachineOperand *
Src1 = TII.getNamedOperand(*
MI, AMDGPU::OpName::src1);
3010 Register DstReg =
MI->getOperand(0).getReg();
3011 if (!
Src1->isReg() ||
Src1->getReg() != DstReg) {
3012 Register DstLo = TRI.getSubReg(DstReg, AMDGPU::sub0);
3020 bool Overlapped =
MI->modifiesRegister(AmtReg, &TRI);
3022 for (MCRegister
Reg : Overlapped ? AMDGPU::VReg_64_Align2RegClass
3023 : AMDGPU::VGPR_32RegClass) {
3024 if (!
MI->modifiesRegister(
Reg, &TRI) && !
MI->readsRegister(
Reg, &TRI)) {
3030 Register NewAmt = Overlapped ? (
Register)TRI.getSubReg(NewReg, AMDGPU::sub1)
3035 NewAmtLo = TRI.getSubReg(NewReg, AMDGPU::sub0);
3048 runOnInstruction(
BuildMI(*
MBB,
MI,
DL, TII.get(AMDGPU::V_SWAP_B32), NewAmt)
3055 BuildMI(*
MBB, std::next(
MI->getIterator()),
DL, TII.get(AMDGPU::V_SWAP_B32),
3061 BuildMI(*
MBB, std::next(
MI->getIterator()),
DL, TII.get(AMDGPU::V_SWAP_B32),
3075 MI->getOperand(0).setReg(NewReg);
3076 Src1->setReg(NewReg);
3077 Src1->setIsKill(
false);
3087bool GCNHazardRecognizer::fixPkF32InvalidOpSel(
MachineInstr *
MI) {
3088 if (!ST.hasPkF32InvalidOpSel())
3091 switch (
MI->getOpcode()) {
3094 case AMDGPU::V_PK_ADD_F32:
3095 case AMDGPU::V_PK_MUL_F32:
3096 case AMDGPU::V_PK_FMA_F32:
3100 const MachineOperand *Src0Mods =
3101 TII.getNamedOperand(*
MI, AMDGPU::OpName::src0_modifiers);
3102 const MachineOperand *Src1Mods =
3103 TII.getNamedOperand(*
MI, AMDGPU::OpName::src1_modifiers);
3104 if (!Src0Mods || !Src1Mods)
3107 if (
MI->getOpcode() != AMDGPU::V_PK_FMA_F32) {
3110 if (!TII.commuteInstruction(*
MI)) {
3112 "cannot swap the GFX950 v_pk_add/mul_f32 src0 and src1: " +
3113 Twine(TII.getName(
MI->getOpcode())));
3123 if (!TII.isLegalPkFMAF32OpSel(*
MI)) {
3125 "should have been legalized earlier in the "
3132int GCNHazardRecognizer::checkNSAtoVMEMHazard(
MachineInstr *
MI)
const {
3133 int NSAtoVMEMWaitStates = 1;
3135 if (!ST.hasNSAtoVMEMBug())
3141 const SIInstrInfo *TII = ST.getInstrInfo();
3142 const auto *
Offset = TII->getNamedOperand(*
MI, AMDGPU::OpName::offset);
3150 return Info->MIMGEncoding == AMDGPU::MIMGEncGfx10NSA &&
3151 TII->getInstSizeInBytes(
I) >= 16;
3154 return NSAtoVMEMWaitStates - getWaitStatesSince(
IsHazardFn, 1);
3157int GCNHazardRecognizer::checkFPAtomicToDenormModeHazard(
3159 int FPAtomicToDenormModeWaitStates = 3;
3161 if (!ST.hasFPAtomicToDenormModeHazard())
3163 assert(!ST.hasExtendedWaitCounts());
3165 if (
MI->getOpcode() != AMDGPU::S_DENORM_MODE)
3174 auto IsExpiredFn = [](
const MachineInstr &
MI,
int WaitStates) {
3181 return FPAtomicToDenormModeWaitStates -
3185int GCNHazardRecognizer::checkMAIHazards(
MachineInstr *
MI)
const {
3188 return ST.hasGFX90AInsts() ? checkMAIHazards90A(
MI) : checkMAIHazards908(
MI);
3191int GCNHazardRecognizer::checkMFMAPadding(
MachineInstr *
MI)
const {
3196 const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
3200 int NeighborMFMALatency = 0;
3201 auto IsNeighboringMFMA = [&NeighborMFMALatency,
3202 this](
const MachineInstr &
MI) {
3206 NeighborMFMALatency = this->getMFMAPipelineWaitStates(
MI);
3210 const int MaxMFMAPipelineWaitStates = 16;
3211 int WaitStatesSinceNeighborMFMA =
3212 getWaitStatesSince(IsNeighboringMFMA, MaxMFMAPipelineWaitStates);
3214 int NeighborMFMAPaddingNeeded =
3216 WaitStatesSinceNeighborMFMA;
3218 return std::max(0, NeighborMFMAPaddingNeeded);
3221int GCNHazardRecognizer::checkMAIHazards908(
MachineInstr *
MI)
const {
3222 int WaitStatesNeeded = 0;
3223 unsigned Opc =
MI->getOpcode();
3225 auto IsVALUFn = [](
const MachineInstr &
MI) {
3229 if (
Opc != AMDGPU::V_ACCVGPR_READ_B32_e64) {
3230 const int LegacyVALUWritesVGPRWaitStates = 2;
3231 const int VALUWritesExecWaitStates = 4;
3232 const int MaxWaitStates = 4;
3234 int WaitStatesNeededForUse = VALUWritesExecWaitStates -
3235 getWaitStatesSinceDef(AMDGPU::EXEC, IsVALUFn, MaxWaitStates);
3236 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3238 if (WaitStatesNeeded < MaxWaitStates) {
3239 for (
const MachineOperand &Use :
MI->explicit_uses()) {
3240 const int MaxWaitStates = 2;
3242 if (!
Use.isReg() || !TRI.isVGPR(MF.getRegInfo(),
Use.getReg()))
3245 int WaitStatesNeededForUse = LegacyVALUWritesVGPRWaitStates -
3246 getWaitStatesSinceDef(
Use.getReg(), IsVALUFn, MaxWaitStates);
3247 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3249 if (WaitStatesNeeded == MaxWaitStates)
3255 for (
const MachineOperand &
Op :
MI->explicit_operands()) {
3256 if (!
Op.isReg() || !TRI.isAGPR(MF.getRegInfo(),
Op.getReg()))
3259 if (
Op.isDef() &&
Opc != AMDGPU::V_ACCVGPR_WRITE_B32_e64)
3262 const int MFMAWritesAGPROverlappedSrcABWaitStates = 4;
3263 const int MFMAWritesAGPROverlappedSrcCWaitStates = 2;
3264 const int MFMA4x4WritesAGPRAccVgprReadWaitStates = 4;
3265 const int MFMA16x16WritesAGPRAccVgprReadWaitStates = 10;
3266 const int MFMA32x32WritesAGPRAccVgprReadWaitStates = 18;
3267 const int MFMA4x4WritesAGPRAccVgprWriteWaitStates = 1;
3268 const int MFMA16x16WritesAGPRAccVgprWriteWaitStates = 7;
3269 const int MFMA32x32WritesAGPRAccVgprWriteWaitStates = 15;
3270 const int MaxWaitStates = 18;
3272 unsigned HazardDefLatency = 0;
3274 auto IsOverlappedMFMAFn = [
Reg, &HazardDefLatency,
3275 this](
const MachineInstr &
MI) {
3282 std::max(HazardDefLatency, TSchedModel.computeInstrLatency(&
MI));
3283 return TRI.regsOverlap(DstReg,
Reg);
3286 int WaitStatesSinceDef = getWaitStatesSinceDef(
Reg, IsOverlappedMFMAFn,
3288 int NeedWaitStates = MFMAWritesAGPROverlappedSrcABWaitStates;
3289 int SrcCIdx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src2);
3290 int OpNo =
Op.getOperandNo();
3291 if (OpNo == SrcCIdx) {
3292 NeedWaitStates = MFMAWritesAGPROverlappedSrcCWaitStates;
3293 }
else if (
Opc == AMDGPU::V_ACCVGPR_READ_B32_e64) {
3294 switch (HazardDefLatency) {
3295 case 2: NeedWaitStates = MFMA4x4WritesAGPRAccVgprReadWaitStates;
3297 case 8: NeedWaitStates = MFMA16x16WritesAGPRAccVgprReadWaitStates;
3299 case 16: [[fallthrough]];
3300 default: NeedWaitStates = MFMA32x32WritesAGPRAccVgprReadWaitStates;
3303 }
else if (
Opc == AMDGPU::V_ACCVGPR_WRITE_B32_e64) {
3304 switch (HazardDefLatency) {
3305 case 2: NeedWaitStates = MFMA4x4WritesAGPRAccVgprWriteWaitStates;
3307 case 8: NeedWaitStates = MFMA16x16WritesAGPRAccVgprWriteWaitStates;
3309 case 16: [[fallthrough]];
3310 default: NeedWaitStates = MFMA32x32WritesAGPRAccVgprWriteWaitStates;
3315 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceDef;
3316 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3318 if (WaitStatesNeeded == MaxWaitStates)
3319 return WaitStatesNeeded;
3321 auto IsAccVgprWriteFn = [
Reg,
this](
const MachineInstr &
MI) {
3322 if (
MI.getOpcode() != AMDGPU::V_ACCVGPR_WRITE_B32_e64)
3325 return TRI.regsOverlap(
Reg, DstReg);
3328 const int AccVGPRWriteMFMAReadSrcCWaitStates = 1;
3329 const int AccVGPRWriteMFMAReadSrcABWaitStates = 3;
3330 const int AccVGPRWriteAccVgprReadWaitStates = 3;
3331 NeedWaitStates = AccVGPRWriteMFMAReadSrcABWaitStates;
3332 if (OpNo == SrcCIdx)
3333 NeedWaitStates = AccVGPRWriteMFMAReadSrcCWaitStates;
3334 else if (
Opc == AMDGPU::V_ACCVGPR_READ_B32_e64)
3335 NeedWaitStates = AccVGPRWriteAccVgprReadWaitStates;
3337 WaitStatesNeededForUse = NeedWaitStates -
3338 getWaitStatesSinceDef(
Reg, IsAccVgprWriteFn, MaxWaitStates);
3339 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3341 if (WaitStatesNeeded == MaxWaitStates)
3342 return WaitStatesNeeded;
3345 if (
Opc == AMDGPU::V_ACCVGPR_WRITE_B32_e64) {
3346 const int MFMA4x4ReadSrcCAccVgprWriteWaitStates = 0;
3347 const int MFMA16x16ReadSrcCAccVgprWriteWaitStates = 5;
3348 const int MFMA32x32ReadSrcCAccVgprWriteWaitStates = 13;
3349 const int MaxWaitStates = 13;
3350 Register DstReg =
MI->getOperand(0).getReg();
3351 unsigned HazardDefLatency = 0;
3353 auto IsSrcCMFMAFn = [DstReg, &HazardDefLatency,
3354 this](
const MachineInstr &
MI) {
3357 Register Reg = TII.getNamedOperand(
MI, AMDGPU::OpName::src2)->getReg();
3359 std::max(HazardDefLatency, TSchedModel.computeInstrLatency(&
MI));
3360 return TRI.regsOverlap(
Reg, DstReg);
3363 int WaitStatesSince = getWaitStatesSince(IsSrcCMFMAFn, MaxWaitStates);
3365 switch (HazardDefLatency) {
3366 case 2: NeedWaitStates = MFMA4x4ReadSrcCAccVgprWriteWaitStates;
3368 case 8: NeedWaitStates = MFMA16x16ReadSrcCAccVgprWriteWaitStates;
3370 case 16: [[fallthrough]];
3371 default: NeedWaitStates = MFMA32x32ReadSrcCAccVgprWriteWaitStates;
3375 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSince;
3376 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3380 WaitStatesNeeded = std::max(WaitStatesNeeded, checkMFMAPadding(
MI));
3382 return WaitStatesNeeded;
3411 return NumPasses + 1 + IsGFX950;
3422 return NumPasses + 1 + (NumPasses != 2 && IsGFX950);
3440 return NumPasses + 2;
3450 return NumPasses + 3 + (NumPasses != 2 && IsGFX950);
3453int GCNHazardRecognizer::getMFMAOverlappedSrcCWaitStates(
3455 constexpr int SMFMA4x4WritesVGPROverlappedSMFMASrcCWaitStates = 2;
3456 constexpr int SMFMA16x16WritesVGPROverlappedSMFMASrcCWaitStates = 8;
3457 constexpr int SMFMA32x32WritesVGPROverlappedSMFMASrcCWaitStates = 16;
3458 constexpr int SMFMA4x4WritesVGPROverlappedDMFMASrcCWaitStates = 3;
3459 constexpr int SMFMA16x16WritesVGPROverlappedDMFMASrcCWaitStates = 9;
3460 constexpr int SMFMA32x32WritesVGPROverlappedDMFMASrcCWaitStates = 17;
3461 constexpr int DMFMA16x16WritesVGPROverlappedSrcCWaitStates = 9;
3462 constexpr int GFX950_DMFMA16x16WritesVGPROverlappedSrcCWaitStates = 17;
3463 constexpr int DMFMA4x4WritesVGPROverlappedSrcCWaitStates = 4;
3467 if (TII.isXDL(*Reader) && !TII.isXDL(*Writer))
3471 case AMDGPU::V_MFMA_F64_16X16X4F64_e64:
3472 case AMDGPU::V_MFMA_F64_16X16X4F64_vgprcd_e64:
3473 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_e64:
3474 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_vgprcd_e64:
3475 return ST.hasGFX950Insts()
3476 ? GFX950_DMFMA16x16WritesVGPROverlappedSrcCWaitStates
3477 : DMFMA16x16WritesVGPROverlappedSrcCWaitStates;
3478 case AMDGPU::V_MFMA_F64_4X4X4F64_e64:
3479 case AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64:
3480 return DMFMA4x4WritesVGPROverlappedSrcCWaitStates;
3485 int NumPasses = TSchedModel.computeInstrLatency(Writer);
3486 if (ST.hasGFX940Insts()) {
3487 if (!TII.isXDL(*Writer))
3490 return TII.isXDL(*Reader)
3492 NumPasses, ST.hasGFX950Insts())
3494 NumPasses, ST.hasGFX950Insts());
3498 switch (NumPasses) {
3500 return IsDGEMM ? SMFMA4x4WritesVGPROverlappedDMFMASrcCWaitStates
3501 : SMFMA4x4WritesVGPROverlappedSMFMASrcCWaitStates;
3503 return IsDGEMM ? SMFMA16x16WritesVGPROverlappedDMFMASrcCWaitStates
3504 : SMFMA16x16WritesVGPROverlappedSMFMASrcCWaitStates;
3506 return IsDGEMM ? SMFMA32x32WritesVGPROverlappedDMFMASrcCWaitStates
3507 : SMFMA32x32WritesVGPROverlappedSMFMASrcCWaitStates;
3513int GCNHazardRecognizer::getMFMAReadWaitStates(
const MachineInstr &Consumer,
3516 bool IsSrcC)
const {
3518 const int SMFMA4x4WritesVGPROverlappedSrcABWaitStates = 5;
3519 const int SMFMA16x16WritesVGPROverlappedSrcABWaitStates = 11;
3520 const int SMFMA32x32WritesVGPROverlappedSrcABWaitStates = 19;
3521 const int DMFMA4x4WritesVGPROverlappedMFMASrcABWaitStates = 6;
3522 const int DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates = 11;
3523 const int GFX950_DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates = 19;
3524 const int DMFMA4x4WritesVGPRFullSrcCWaitStates = 4;
3525 const int GFX940_SMFMA4x4WritesVGPRFullSrcCWaitStates = 2;
3527 bool FullReg =
Producer.getOperand(0).getReg() ==
Reg;
3528 unsigned Opc1 =
Producer.getOpcode();
3529 int NeedWaitStates = 0;
3534 }
else if (FullReg) {
3535 if ((
Opc == AMDGPU::V_MFMA_F64_4X4X4F64_e64 ||
3536 Opc == AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64) &&
3537 (Opc1 == AMDGPU::V_MFMA_F64_4X4X4F64_e64 ||
3538 Opc1 == AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64))
3539 NeedWaitStates = DMFMA4x4WritesVGPRFullSrcCWaitStates;
3540 else if (ST.hasGFX940Insts() &&
3541 TSchedModel.computeInstrLatency(&Producer) == 2)
3542 NeedWaitStates = GFX940_SMFMA4x4WritesVGPRFullSrcCWaitStates;
3549 std::max(NeedWaitStates,
3550 getMFMAOverlappedSrcCWaitStates(&Consumer, &Producer));
3553 NeedWaitStates = getMFMAOverlappedSrcCWaitStates(&Consumer, &Producer);
3557 case AMDGPU::V_MFMA_F64_16X16X4F64_e64:
3558 case AMDGPU::V_MFMA_F64_16X16X4F64_vgprcd_e64:
3559 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_e64:
3560 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_vgprcd_e64:
3563 ? GFX950_DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates
3564 : DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates;
3566 case AMDGPU::V_MFMA_F64_4X4X4F64_e64:
3567 case AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64:
3568 NeedWaitStates = DMFMA4x4WritesVGPROverlappedMFMASrcABWaitStates;
3571 int NumPasses = TSchedModel.computeInstrLatency(&Producer);
3573 if (ST.hasGFX940Insts()) {
3577 NumPasses, ST.hasGFX950Insts())
3583 switch (NumPasses) {
3585 NeedWaitStates = SMFMA4x4WritesVGPROverlappedSrcABWaitStates;
3590 NeedWaitStates = SMFMA16x16WritesVGPROverlappedSrcABWaitStates;
3594 NeedWaitStates = SMFMA32x32WritesVGPROverlappedSrcABWaitStates;
3598 return NeedWaitStates;
3601int GCNHazardRecognizer::checkMAIHazards90A(
MachineInstr *
MI)
const {
3602 int WaitStatesNeeded = 0;
3603 unsigned Opc =
MI->getOpcode();
3605 auto IsLegacyVALUFn = [](
const MachineInstr &
MI) {
3610 auto IsLegacyVALUNotDotFn = [](
const MachineInstr &
MI) {
3616 return WaitStatesNeeded;
3618 const int VALUWritesExecWaitStates = 4;
3619 int WaitStatesNeededForUse = VALUWritesExecWaitStates -
3620 getWaitStatesSinceDef(AMDGPU::EXEC, IsLegacyVALUFn,
3621 VALUWritesExecWaitStates);
3622 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3624 int SrcCIdx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src2);
3627 for (
const MachineOperand &Use :
MI->explicit_uses()) {
3628 const int LegacyVALUNotDotWritesVGPRWaitStates = 2;
3629 const int MaxWaitStates =
3631 16, ST.hasGFX950Insts());
3637 WaitStatesNeededForUse = LegacyVALUNotDotWritesVGPRWaitStates -
3638 getWaitStatesSinceDef(
Reg, IsLegacyVALUNotDotFn, MaxWaitStates);
3639 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3641 int OpNo =
Use.getOperandNo();
3642 WaitStatesNeeded = std::max(
3644 getMaxWindowDeficit(
3645 MaxWaitStates, [&](
const MachineInstr &
P) -> std::optional<int> {
3647 !TRI.regsOverlap(
P.getOperand(0).getReg(),
Reg))
3648 return std::nullopt;
3649 return getMFMAReadWaitStates(*
MI,
P,
Reg, OpNo == SrcCIdx);
3652 if (WaitStatesNeeded == MaxWaitStates)
3657 WaitStatesNeeded = std::max(WaitStatesNeeded, checkMFMAPadding(
MI));
3659 return WaitStatesNeeded;
3662int GCNHazardRecognizer::checkMAILdStHazards(
MachineInstr *
MI)
const {
3664 if (!ST.hasMAIInsts() || ST.hasGFX90AInsts())
3667 int WaitStatesNeeded = 0;
3669 auto IsAccVgprReadFn = [](
const MachineInstr &
MI) {
3670 return MI.getOpcode() == AMDGPU::V_ACCVGPR_READ_B32_e64;
3673 for (
const MachineOperand &
Op :
MI->explicit_uses()) {
3674 if (!
Op.isReg() || !TRI.isVGPR(MF.getRegInfo(),
Op.getReg()))
3679 const int AccVgprReadLdStWaitStates = 2;
3680 const int VALUWriteAccVgprRdWrLdStDepVALUWaitStates = 1;
3681 const int MaxWaitStates = 2;
3683 int WaitStatesNeededForUse = AccVgprReadLdStWaitStates -
3684 getWaitStatesSinceDef(
Reg, IsAccVgprReadFn, MaxWaitStates);
3685 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3687 if (WaitStatesNeeded == MaxWaitStates)
3688 return WaitStatesNeeded;
3690 auto IsVALUAccVgprRdWrCheckFn = [
Reg,
this](
const MachineInstr &
MI) {
3691 if (
MI.getOpcode() != AMDGPU::V_ACCVGPR_READ_B32_e64 &&
3692 MI.getOpcode() != AMDGPU::V_ACCVGPR_WRITE_B32_e64)
3694 auto IsVALUFn = [](
const MachineInstr &
MI) {
3698 return getWaitStatesSinceDef(
Reg, IsVALUFn, 2 ) <
3699 std::numeric_limits<int>::max();
3702 WaitStatesNeededForUse = VALUWriteAccVgprRdWrLdStDepVALUWaitStates -
3703 getWaitStatesSince(IsVALUAccVgprRdWrCheckFn, MaxWaitStates);
3704 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3707 return WaitStatesNeeded;
3710int GCNHazardRecognizer::checkPermlaneHazards(
MachineInstr *
MI)
const {
3711 assert(!ST.hasVcmpxPermlaneHazard() &&
3712 "this is a different vcmpx+permlane hazard");
3713 const SIRegisterInfo *TRI = ST.getRegisterInfo();
3714 const SIInstrInfo *TII = ST.getInstrInfo();
3716 auto IsVCmpXWritesExecFn = [TII, TRI](
const MachineInstr &
MI) {
3720 auto IsVALUFn = [](
const MachineInstr &
MI) {
3724 const int VCmpXWritesExecWaitStates = 4;
3725 const int VALUWritesVDstWaitStates = 2;
3726 int WaitStatesNeeded = 0;
3728 for (
const MachineOperand &
Op :
MI->explicit_uses()) {
3729 if (!
Op.isReg() || !TRI->isVGPR(MF.getRegInfo(),
Op.getReg()))
3733 int WaitStatesSinceDef =
3734 VALUWritesVDstWaitStates -
3735 getWaitStatesSinceDef(
Reg, IsVALUFn,
3736 VALUWritesVDstWaitStates);
3737 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesSinceDef);
3738 if (WaitStatesNeeded >= VALUWritesVDstWaitStates)
3742 int VCmpXHazardWaits =
3743 VCmpXWritesExecWaitStates -
3744 getWaitStatesSince(IsVCmpXWritesExecFn, VCmpXWritesExecWaitStates);
3746 WaitStatesNeeded = std::max(WaitStatesNeeded, VCmpXHazardWaits);
3747 return WaitStatesNeeded;
3755 return NumPasses + 2;
3765 return NumPasses + 3 + (NumPasses != 2 && IsGFX950);
3775 return NumPasses + 3 + (NumPasses != 2 && IsGFX950);
3783 return NumPasses + 2;
3786int GCNHazardRecognizer::checkMAIVALUHazards(
MachineInstr *
MI)
const {
3787 if (!ST.hasGFX90AInsts())
3790 auto IsDGEMMFn = [](
const MachineInstr &
MI) ->
bool {
3798 const MachineRegisterInfo &MRI = MF.getRegInfo();
3800 int WaitStatesNeeded = 0;
3807 auto IsMFMAWriteFn = [&
Reg,
this](
const MachineInstr &
MI) {
3809 !TRI.regsOverlap(
MI.getOperand(0).getReg(),
Reg))
3814 const MachineInstr *
DOT =
nullptr;
3815 auto IsDotWriteFn = [&
Reg, &
DOT,
this](
const MachineInstr &
MI) {
3817 !TRI.regsOverlap(
MI.getOperand(0).getReg(),
Reg))
3823 bool DGEMMAfterVALUWrite =
false;
3824 auto IsDGEMMHazard = [&DGEMMAfterVALUWrite,
this](
const MachineInstr &
MI) {
3827 DGEMMAfterVALUWrite =
true;
3831 if (!TII.isVALU(
MI,
true) || !DGEMMAfterVALUWrite)
3837 int SrcCIdx = AMDGPU::getNamedOperandIdx(
MI->getOpcode(),
3838 AMDGPU::OpName::src2);
3840 if (IsMemOrExport || IsVALU) {
3841 const int SMFMA4x4WriteVgprVALUMemExpReadWaitStates = 5;
3842 const int SMFMA16x16WriteVgprVALUMemExpReadWaitStates = 11;
3843 const int SMFMA32x32WriteVgprVALUMemExpReadWaitStates = 19;
3844 const int DMFMA4x4WriteVgprMemExpReadWaitStates = 9;
3845 const int DMFMA16x16WriteVgprMemExpReadWaitStates = 18;
3846 const int DMFMA4x4WriteVgprVALUReadWaitStates = 6;
3847 const int DMFMA16x16WriteVgprVALUReadWaitStates = 11;
3848 const int GFX950_DMFMA16x16WriteVgprVALUReadWaitStates = 19;
3849 const int DotWriteSameDotReadSrcAB = 3;
3850 const int DotWriteDifferentVALURead = 3;
3851 const int DMFMABetweenVALUWriteVMEMRead = 2;
3852 const int MaxWaitStates =
3854 ST.hasGFX950Insts());
3856 for (
const MachineOperand &Use :
MI->explicit_uses()) {
3862 int WaitStatesSinceDef = getWaitStatesSinceDef(
Reg, IsDotWriteFn,
3865 int NeedWaitStates = 0;
3866 if (
DOT->getOpcode() ==
MI->getOpcode()) {
3867 if (&Use - &
MI->getOperand(0) != SrcCIdx)
3868 NeedWaitStates = DotWriteSameDotReadSrcAB;
3870 NeedWaitStates = DotWriteDifferentVALURead;
3873 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceDef;
3874 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3881 if (IsMem && ST.hasGFX90AInsts() && !ST.hasGFX940Insts()) {
3882 DGEMMAfterVALUWrite =
false;
3883 if (TRI.isVectorRegister(MRI,
Reg)) {
3884 int WaitStatesNeededForUse =
3885 DMFMABetweenVALUWriteVMEMRead -
3886 getWaitStatesSinceDef(
Reg, IsDGEMMHazard,
3887 DMFMABetweenVALUWriteVMEMRead);
3889 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3893 auto MFMAWindow = [&](
const MachineInstr &
Producer) {
3894 int NumPasses = TSchedModel.computeInstrLatency(&Producer);
3895 int NeedWaitStates = MaxWaitStates;
3898 switch (NumPasses) {
3900 NeedWaitStates = IsMemOrExport
3901 ? DMFMA4x4WriteVgprMemExpReadWaitStates
3902 : DMFMA4x4WriteVgprVALUReadWaitStates;
3908 ? DMFMA16x16WriteVgprMemExpReadWaitStates
3909 : (ST.hasGFX950Insts()
3910 ? GFX950_DMFMA16x16WriteVgprVALUReadWaitStates
3911 : DMFMA16x16WriteVgprVALUReadWaitStates);
3916 }
else if (ST.hasGFX940Insts()) {
3920 NumPasses, ST.hasGFX950Insts())
3924 switch (NumPasses) {
3926 NeedWaitStates = SMFMA4x4WriteVgprVALUMemExpReadWaitStates;
3929 NeedWaitStates = SMFMA16x16WriteVgprVALUMemExpReadWaitStates;
3932 NeedWaitStates = SMFMA32x32WriteVgprVALUMemExpReadWaitStates;
3939 assert(NeedWaitStates <= MaxWaitStates &&
3940 "hazard requirement exceeds the scan window");
3941 return NeedWaitStates;
3944 WaitStatesNeeded = std::max(
3946 getMaxWindowDeficit(MaxWaitStates,
3947 [&](
const MachineInstr &
P) -> std::optional<int> {
3948 if (!IsMFMAWriteFn(
P))
3949 return std::nullopt;
3950 return MFMAWindow(
P);
3953 if (WaitStatesNeeded >= MaxWaitStates)
3958 unsigned Opc =
MI->getOpcode();
3959 const int DMFMAToFMA64WaitStates = 2;
3960 if ((
Opc == AMDGPU::V_FMA_F64_e64 ||
3961 Opc == AMDGPU::V_FMAC_F64_e32 ||
Opc == AMDGPU::V_FMAC_F64_e64 ||
3962 Opc == AMDGPU::V_FMAC_F64_dpp) &&
3963 WaitStatesNeeded < DMFMAToFMA64WaitStates) {
3964 int WaitStatesNeededForUse = DMFMAToFMA64WaitStates -
3965 getWaitStatesSince(IsDGEMMFn, DMFMAToFMA64WaitStates);
3966 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3969 if (!IsVALU && !IsMemOrExport)
3970 return WaitStatesNeeded;
3972 for (
const MachineOperand &Def :
MI->defs()) {
3973 const int SMFMA4x4WriteVgprVALUWawWaitStates = 5;
3974 const int SMFMA16x16WriteVgprVALUWawWaitStates = 11;
3975 const int SMFMA32x32WriteVgprVALUWawWaitStates = 19;
3976 const int SMFMA4x4ReadVgprVALUWarWaitStates = 1;
3977 const int GFX940_XDL4PassReadVgprVALUWarWaitStates = 3;
3978 const int SMFMA16x16ReadVgprVALUWarWaitStates = 7;
3979 const int SMFMA32x32ReadVgprVALUWarWaitStates = 15;
3980 const int DMFMA4x4WriteVgprVALUWriteWaitStates = 6;
3981 const int DMFMA16x16WriteVgprVALUWriteWaitStates = 11;
3982 const int DotWriteDifferentVALUWrite = 3;
3983 const int MaxWaitStates =
3985 const int MaxWarWaitStates = 15;
3990 int WaitStatesSinceDef = getWaitStatesSinceDef(
Reg, IsDotWriteFn,
3992 if (DOT &&
DOT->getOpcode() !=
MI->getOpcode())
3993 WaitStatesNeeded = std::max(WaitStatesNeeded, DotWriteDifferentVALUWrite -
3994 WaitStatesSinceDef);
3996 auto MFMAWawWindow = [&](
const MachineInstr &
Producer) {
3997 int NeedWaitStates = MaxWaitStates;
3998 int NumPasses = TSchedModel.computeInstrLatency(&Producer);
4001 switch (NumPasses) {
4003 NeedWaitStates = DMFMA4x4WriteVgprVALUWriteWaitStates;
4007 NeedWaitStates = DMFMA16x16WriteVgprVALUWriteWaitStates;
4012 }
else if (ST.hasGFX940Insts()) {
4016 NumPasses, ST.hasGFX950Insts())
4019 switch (NumPasses) {
4021 NeedWaitStates = SMFMA4x4WriteVgprVALUWawWaitStates;
4024 NeedWaitStates = SMFMA16x16WriteVgprVALUWawWaitStates;
4027 NeedWaitStates = SMFMA32x32WriteVgprVALUWawWaitStates;
4034 assert(NeedWaitStates <= MaxWaitStates &&
4035 "hazard requirement exceeds the scan window");
4036 return NeedWaitStates;
4039 WaitStatesNeeded = std::max(
4041 getMaxWindowDeficit(MaxWaitStates,
4042 [&](
const MachineInstr &
P) -> std::optional<int> {
4043 if (!IsMFMAWriteFn(
P))
4044 return std::nullopt;
4045 return MFMAWawWindow(
P);
4048 if (WaitStatesNeeded >= MaxWaitStates)
4052 auto SMFMAReadAsCWindow =
4053 [&](
const MachineInstr &Reader) -> std::optional<int> {
4057 return std::nullopt;
4059 if (ST.hasGFX940Insts() && !TII.isXDL(Reader))
4060 return std::nullopt;
4062 const MachineOperand *SrcC =
4063 TII.getNamedOperand(Reader, AMDGPU::OpName::src2);
4064 assert(SrcC &&
"an MFMA must have a src2 operand");
4066 return std::nullopt;
4068 switch (TSchedModel.computeInstrLatency(&Reader)) {
4070 return SMFMA4x4ReadVgprVALUWarWaitStates;
4072 assert(ST.hasGFX940Insts() &&
"4-pass XDL is gfx940 or later");
4073 return GFX940_XDL4PassReadVgprVALUWarWaitStates;
4075 return SMFMA16x16ReadVgprVALUWarWaitStates;
4079 return SMFMA32x32ReadVgprVALUWarWaitStates;
4084 std::max(WaitStatesNeeded,
4085 getMaxWindowDeficit(MaxWarWaitStates, SMFMAReadAsCWindow));
4088 return WaitStatesNeeded;
4101 return MAI !=
nullptr;
4105 if (IsMFMAFn(*
MI)) {
4106 int W = getWaitStatesSince(IsMFMAFn, 16);
4108 return W < (int)TSchedModel.computeInstrLatency(MAI);
4122 while (
I->isBundledWithPred())
4128 if (
I->getOpcode() != AMDGPU::S_GETPC_B64)
4132 const unsigned NewBytes = 4;
4134 "Unexpected instruction insertion in bundle");
4137 while (NextMI !=
End && NextMI->isBundledWithPred()) {
4138 for (
auto &Operand : NextMI->operands()) {
4139 if (Operand.isGlobal())
4140 Operand.setOffset(Operand.getOffset() + NewBytes);
4146bool GCNHazardRecognizer::fixVALUMaskWriteHazard(
MachineInstr *
MI) {
4147 if (!ST.hasVALUMaskWriteHazard())
4149 assert(!ST.hasExtendedWaitCounts());
4156 if (!IsSALU && !IsVALU)
4168 const SIRegisterInfo *TRI = ST.getRegisterInfo();
4169 const MachineRegisterInfo &MRI = MF.getRegInfo();
4174 case AMDGPU::EXEC_LO:
4175 case AMDGPU::EXEC_HI:
4177 case AMDGPU::SGPR_NULL:
4178 case AMDGPU::SGPR_NULL64:
4186 return Reg == AMDGPU::VCC ||
Reg == AMDGPU::VCC_LO ||
Reg == AMDGPU::VCC_HI;
4190 SmallSet<Register, 2> HazardSGPRs;
4192 static unsigned getHashValue(
const StateType &State) {
4195 static bool isEqual(
const StateType &
LHS,
const StateType &
RHS) {
4196 return LHS.HazardSGPRs ==
RHS.HazardSGPRs;
4200 SmallVector<const MachineInstr *> WaitInstrs;
4201 StateType InitialState;
4204 MachineOperand *HazardDef =
nullptr;
4205 for (MachineOperand &
Op :
MI->all_defs()) {
4207 if (IgnoreableSGPR(
Reg))
4210 if (
Op.isImplicit())
4212 if (!TRI->isSGPRReg(MRI,
Reg))
4225 if (AMDGPU::SReg_32RegClass.
contains(HazardReg)) {
4226 InitialState.HazardSGPRs.insert(HazardReg);
4229 InitialState.HazardSGPRs.insert(TRI->getSubReg(HazardReg, AMDGPU::sub0));
4230 InitialState.HazardSGPRs.insert(TRI->getSubReg(HazardReg, AMDGPU::sub1));
4233 auto IsHazardFn = [&](StateType &State,
const MachineInstr &
I) {
4234 if (State.HazardSGPRs.empty())
4237 switch (
I.getOpcode()) {
4238 case AMDGPU::V_ADDC_U32_e32:
4239 case AMDGPU::V_ADDC_U32_dpp:
4240 case AMDGPU::V_CNDMASK_B16_t16_e32:
4241 case AMDGPU::V_CNDMASK_B16_fake16_e32:
4242 case AMDGPU::V_CNDMASK_B16_t16_dpp:
4243 case AMDGPU::V_CNDMASK_B16_fake16_dpp:
4244 case AMDGPU::V_CNDMASK_B32_e32:
4245 case AMDGPU::V_CNDMASK_B32_dpp:
4246 case AMDGPU::V_DIV_FMAS_F32_e64:
4247 case AMDGPU::V_DIV_FMAS_F64_e64:
4248 case AMDGPU::V_SUBB_U32_e32:
4249 case AMDGPU::V_SUBB_U32_dpp:
4250 case AMDGPU::V_SUBBREV_U32_e32:
4251 case AMDGPU::V_SUBBREV_U32_dpp: {
4255 case AMDGPU::V_ADDC_U32_e64:
4256 case AMDGPU::V_ADDC_U32_e64_dpp:
4257 case AMDGPU::V_CNDMASK_B16_t16_e64:
4258 case AMDGPU::V_CNDMASK_B16_fake16_e64:
4259 case AMDGPU::V_CNDMASK_B16_t16_e64_dpp:
4260 case AMDGPU::V_CNDMASK_B16_fake16_e64_dpp:
4261 case AMDGPU::V_CNDMASK_B32_e64:
4262 case AMDGPU::V_CNDMASK_B32_e64_dpp:
4263 case AMDGPU::V_SUBB_U32_e64:
4264 case AMDGPU::V_SUBB_U32_e64_dpp:
4265 case AMDGPU::V_SUBBREV_U32_e64:
4266 case AMDGPU::V_SUBBREV_U32_e64_dpp: {
4268 const MachineOperand *SSRCOp = TII.getNamedOperand(
I, AMDGPU::OpName::src2);
4270 bool Result = TRI->regsOverlap(SSRCOp->
getReg(), HazardReg);
4278 auto UpdateStateFn = [&](StateType &State,
const MachineInstr &
I) {
4280 for (
auto &
Op :
I.all_defs()) {
4282 if (IgnoreableSGPR(
Reg))
4285 if (
Op.isImplicit())
4287 if (!TRI->isSGPRReg(MRI,
Reg))
4294 for (
Register SGPR : State.HazardSGPRs) {
4295 if (
Reg == SGPR || TRI->regsOverlap(
Reg, SGPR))
4299 State.HazardSGPRs.erase(SGPR);
4306 std::next(
MI->getReverseIterator())))
4316 auto NextMI = std::next(
MI->getIterator());
4317 auto NewMI =
BuildMI(*
MI->getParent(), NextMI,
MI->getDebugLoc(),
4318 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
4330 if (EntryMBB.
begin() != EntryMBB.
end()) {
4331 auto &EntryMI = *EntryMBB.
begin();
4332 if (EntryMI.getOpcode() == AMDGPU::S_SETPRIO &&
4333 EntryMI.getOperand(0).getImm() >= Priority)
4342bool GCNHazardRecognizer::fixRequiredExportPriority(
MachineInstr *
MI) {
4343 if (!ST.hasRequiredExportPriority())
4361 const int MaxPriority = 3;
4362 const int NormalPriority = 2;
4363 const int PostExportPriority = 0;
4365 auto It =
MI->getIterator();
4366 switch (
MI->getOpcode()) {
4367 case AMDGPU::S_ENDPGM:
4368 case AMDGPU::S_ENDPGM_SAVED:
4369 case AMDGPU::S_ENDPGM_ORDERED_PS_DONE:
4370 case AMDGPU::SI_RETURN_TO_EPILOG:
4373 if (MF->getFrameInfo().hasCalls())
4376 case AMDGPU::S_SETPRIO: {
4378 auto &PrioOp =
MI->getOperand(0);
4379 int Prio =
static_cast<int>(PrioOp.getImm());
4380 bool InWA = (Prio == PostExportPriority) &&
4381 (It !=
MBB->
begin() && TII.isEXP(*std::prev(It)));
4382 if (InWA || Prio >= NormalPriority)
4384 PrioOp.setImm(std::min(Prio + NormalPriority, MaxPriority));
4388 if (!TII.isEXP(*
MI))
4399 auto NextMI = std::next(It);
4400 bool EndOfShader =
false;
4401 if (NextMI !=
MBB->
end()) {
4403 if (TII.isEXP(*NextMI))
4406 if (NextMI->getOpcode() == AMDGPU::S_SETPRIO &&
4407 NextMI->getOperand(0).getImm() == PostExportPriority)
4409 EndOfShader = NextMI->getOpcode() == AMDGPU::S_ENDPGM;
4416 .
addImm(PostExportPriority);
4420 BuildMI(*
MBB, NextMI,
DL, TII.get(AMDGPU::S_WAITCNT_EXPCNT))
4421 .
addReg(AMDGPU::SGPR_NULL)
4443 while (
I !=
End &&
I->isMetaInstruction())
4452 assert(ST.hasRequiresInitialUnclausedVmem() &&
4453 "V_PERM_PK16-hazard subtarget must provide the unclaused-VMEM entry "
4454 "prologue to satisfy the cross-wave entry mitigation");
4465 if (NextI !=
MBB->
end() && TII.isVPermPk16SafeInstr(*NextI))
4471 BuildMI(*
MBB, NextI,
MI->getDebugLoc(), TII.get(AMDGPU::V_NOP_e32));
4479 const SIInstrInfo *TII = ST.getInstrInfo();
4491 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4496bool GCNHazardRecognizer::fixDsAtomicAsyncBarrierArriveB64(
MachineInstr *
MI) {
4497 if (
MI->getOpcode() != AMDGPU::DS_ATOMIC_ASYNC_BARRIER_ARRIVE_B64)
4500 const SIInstrInfo *TII = ST.getInstrInfo();
4502 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4504 BuildMI(*
MI->getParent(), std::next(
MI->getIterator()),
MI->getDebugLoc(),
4505 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4511bool GCNHazardRecognizer::fixScratchBaseForwardingHazard(
MachineInstr *
MI) {
4517 const SIRegisterInfo *TRI = ST.getRegisterInfo();
4518 const SIInstrInfo *TII = ST.getInstrInfo();
4520 const int FlatScrBaseWaitStates = 10;
4522 bool ReadsFlatScrLo =
4524 bool ReadsFlatScrHi =
4525 MI->readsRegister(AMDGPU::SRC_FLAT_SCRATCH_BASE_HI, TRI);
4531 ReadsFlatScrLo =
true;
4534 ReadsFlatScrHi =
true;
4539 const MachineRegisterInfo &MRI = MF.getRegInfo();
4542 DenseSet<const MachineBasicBlock *> Visited;
4544 return MI.modifiesRegister(
Reg, TRI);
4549 auto IsSGPRDef = [TII, TRI, &MRI](
const MachineInstr &
MI) ->
unsigned {
4550 if (!TII->isSALU(
MI) && !TII->isVALU(
MI,
true))
4552 for (
const MachineOperand &MO :
MI.all_defs()) {
4553 if (TRI->isSGPRReg(MRI, MO.getReg()))
4559 auto IsExpiredFn = [=](
const MachineInstr &
MI,
int SgprWrites) {
4560 if (
MI.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR) {
4561 unsigned Wait =
static_cast<unsigned>(
MI.getOperand(0).
getImm());
4566 return SgprWrites >= FlatScrBaseWaitStates;
4569 return ::getWaitStatesSince(
4570 IsHazardFn,
MI->getParent(), std::next(
MI->getReverseIterator()),
4571 0,
IsExpiredFn, Visited, IsSGPRDef) < FlatScrBaseWaitStates;
4575 !IsRegDefHazard(AMDGPU::SGPR102)) &&
4577 !IsRegDefHazard(AMDGPU::SGPR103)))
4581 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4592 BuildMI(*
MI->getParent(),
MI,
MI->getDebugLoc(), TII.get(AMDGPU::V_NOP_e32));
4593 BuildMI(*
MI->getParent(),
MI,
MI->getDebugLoc(), TII.get(AMDGPU::V_NOP_e32));
4598 auto IsTDM = [&](
const MachineInstr &
MI) ->
bool {
4600 MI.getOpcode() != AMDGPU::S_WAIT_TENSORCNT;
4607 if (
MI.getOpcode() != AMDGPU::S_WAIT_TENSORCNT)
4609 return MI.getOperand(0).getImm() <= 10;
4613 std::numeric_limits<int>::max())
4617 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...