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 (
MI->isInlineAsm() && checkInlineAsmHazards(
MI) > 0)
643 while (Quantity > 0) {
644 unsigned Arg = std::min(Quantity, 8u);
652GCNHazardRecognizer::getMFMAPipelineWaitStates(
const MachineInstr &
MI)
const {
653 const MCSchedClassDesc *SC = TSchedModel.resolveSchedClass(&
MI);
654 assert(TSchedModel.getWriteProcResBegin(SC) !=
655 TSchedModel.getWriteProcResEnd(SC));
656 return TSchedModel.getWriteProcResBegin(SC)->ReleaseAtCycle;
659void GCNHazardRecognizer::processBundle() {
663 for (;
MI !=
E &&
MI->isInsideBundle(); ++
MI) {
664 CurrCycleInstr = &*
MI;
668 fixHazards(CurrCycleInstr);
676 for (
unsigned i = 0, e = std::min(WaitStates,
MaxLookAhead - 1); i <
e; ++i)
677 EmittedInstrs.push_front(
nullptr);
679 EmittedInstrs.push_front(CurrCycleInstr);
682 CurrCycleInstr =
nullptr;
690 if (
MI->isInsideBundle())
704 CurrCycleInstr =
nullptr;
713 W = checkWMMACoexecSlot(*
MI);
714 W = std::max(W, checkTRANSHazard(*
MI));
715 W = std::max(W, checkMultiCycleVALUHazard(*
MI));
716 W = std::max(W, checkMultiShadowHazard(*
MI));
732 return std::max(WaitStates, checkSMRDHazards(
MI));
734 if (ST.hasNSAtoVMEMBug())
735 WaitStates = std::max(WaitStates, checkNSAtoVMEMHazard(
MI));
737 WaitStates = std::max(WaitStates, checkFPAtomicToDenormModeHazard(
MI));
739 if (ST.hasNoDataDepHazard())
743 WaitStates = std::max(WaitStates, checkVMEMHazards(
MI));
746 WaitStates = std::max(WaitStates, checkVALUHazards(
MI));
749 WaitStates = std::max(WaitStates, checkDPPHazards(
MI));
752 WaitStates = std::max(WaitStates, checkDivFMasHazards(
MI));
755 WaitStates = std::max(WaitStates, checkRWLaneHazards(
MI));
760 checkMAIVALUHazards(
MI) > 0)
761 WaitStates = std::max(WaitStates, checkMAIVALUHazards(
MI));
763 if (
MI->isInlineAsm())
764 return std::max(WaitStates, checkInlineAsmHazards(
MI));
767 return std::max(WaitStates, checkGetRegHazards(
MI));
770 return std::max(WaitStates, checkSetRegHazards(
MI));
773 return std::max(WaitStates, checkRFEHazards(
MI));
775 if ((ST.hasReadM0MovRelInterpHazard() &&
777 MI->getOpcode() == AMDGPU::DS_WRITE_ADDTID_B32 ||
778 MI->getOpcode() == AMDGPU::DS_READ_ADDTID_B32)) ||
780 (ST.hasReadM0LdsDmaHazard() &&
isLdsDma(*
MI)) ||
781 (ST.hasReadM0LdsDirectHazard() &&
782 MI->readsRegister(AMDGPU::LDS_DIRECT,
nullptr)))
783 return std::max(WaitStates, checkReadM0Hazards(
MI));
786 return std::max(WaitStates, checkMAIHazards(
MI));
789 return std::max(WaitStates, checkMAILdStHazards(
MI));
792 return std::max(WaitStates, checkPermlaneHazards(
MI));
798 EmittedInstrs.push_front(
nullptr);
803 schedulerAdvanceCycle();
807 if (!CurrCycleInstr) {
808 EmittedInstrs.push_front(
nullptr);
810 if (HasPendingWMMACoexecHazard)
811 EmittedVALUInstrs.push_front(
nullptr);
815 HasPendingWMMACoexecHazard =
false;
817 if (CurrCycleInstr->isBundle()) {
822 unsigned NumWaitStates = TII.getNumWaitStates(*CurrCycleInstr);
823 if (!NumWaitStates) {
824 CurrCycleInstr =
nullptr;
829 EmittedInstrs.push_front(CurrCycleInstr);
836 EmittedVALUInstrs.push_front(CurrCycleInstr);
842 while (!EmittedVALUInstrs.empty() && EmittedVALUInstrs.front() ==
nullptr)
843 EmittedVALUInstrs.pop_front();
851 EmittedInstrs.push_front(
nullptr);
858 if (EmittedVALUInstrs.size() > MaxVALULookAhead)
859 EmittedVALUInstrs.resize(MaxVALULookAhead);
861 CurrCycleInstr =
nullptr;
866 "Bottom-up scheduling shouldn't run in hazard recognizer mode");
876template <
typename StateT>
886 static bool isEqual(
const StateMapKey &
LHS,
const StateMapKey &
RHS) {
891 static unsigned getHashValue(
const StateMapKey &
Key) {
892 return StateT::getHashValue((*
Key.States)[
Key.Idx]);
894 static unsigned getHashValue(
const StateT &State) {
895 return StateT::getHashValue(State);
897 static bool isEqual(
const StateMapKey &
LHS,
const StateMapKey &
RHS) {
898 return StateT::isEqual((*
LHS.States)[
LHS.Idx], (*
RHS.States)[
RHS.Idx]);
900 static bool isEqual(
const StateT &
LHS,
const StateMapKey &
RHS) {
901 return StateT::isEqual(
LHS, (*
RHS.States)[
RHS.Idx]);
910 StateT State = InitialState;
913 unsigned WorkIdx = 0;
915 bool Expired =
false;
916 for (
auto E =
MBB->instr_rend();
I !=
E; ++
I) {
921 auto Result = IsHazard(State, *
I);
929 if (
I->isInlineAsm() ||
I->isMetaInstruction())
932 UpdateState(State, *
I);
936 unsigned StateIdx = States.
size();
937 StateMapKey
Key = {&States, StateIdx};
938 auto Insertion = StateMap.
insert_as(std::pair(
Key, StateIdx), State);
939 if (Insertion.second) {
942 StateIdx = Insertion.first->second;
945 Worklist.
insert(std::pair(Pred, StateIdx));
948 if (WorkIdx == Worklist.
size())
952 std::tie(
MBB, StateIdx) = Worklist[WorkIdx++];
953 State = States[StateIdx];
954 I =
MBB->instr_rbegin();
971 for (
auto E =
MBB->instr_rend();
I !=
E; ++
I) {
979 if (
I->isInlineAsm())
982 WaitStates += GetNumWaitStates(*
I);
984 if (IsExpired(*
I, WaitStates))
985 return std::numeric_limits<int>::max();
988 int MinWaitStates = std::numeric_limits<int>::max();
990 if (!Visited.
insert(Pred).second)
994 IsExpired, Visited, GetNumWaitStates);
996 MinWaitStates = std::min(MinWaitStates, W);
999 return MinWaitStates;
1010 std::next(
MI->getReverseIterator()), 0, IsExpired,
1011 Visited, GetNumWaitStates);
1014int GCNHazardRecognizer::getWaitStatesSince(
1015 IsHazardFn IsHazard,
int Limit, GetNumWaitStatesFn GetNumWaitStates)
const {
1017 auto IsExpiredFn = [Limit](
const MachineInstr &,
int WaitStates) {
1018 return WaitStates >= Limit;
1020 return ::getWaitStatesSince(IsHazard, CurrCycleInstr,
IsExpiredFn,
1025 for (MachineInstr *
MI : EmittedInstrs) {
1030 if (
MI->isInlineAsm())
1033 WaitStates +=
MI ? GetNumWaitStates(*
MI) : 1;
1035 if (WaitStates >= Limit)
1038 return std::numeric_limits<int>::max();
1041int GCNHazardRecognizer::getWaitStatesSince(IsHazardFn IsHazard,
1046int GCNHazardRecognizer::getWaitStatesSinceVALU(IsHazardFn IsHazard,
1049 auto GetVALUWaitStates = [](
const MachineInstr &
MI) ->
unsigned {
1052 return getWaitStatesSince(IsHazard, Limit, GetVALUWaitStates);
1058 assert(Limit <= (
int)MaxVALULookAhead &&
1059 "Limit exceeds the EmittedVALUInstrs lookahead window");
1061 for (MachineInstr *
MI : EmittedVALUInstrs) {
1069 if (WaitStates >= Limit)
1072 return std::numeric_limits<int>::max();
1075int GCNHazardRecognizer::getWaitStatesSinceDef(
unsigned Reg,
1076 IsHazardFn IsHazardDef,
1078 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1081 return IsHazardDef(
MI) &&
MI.modifiesRegister(
Reg, TRI);
1084 return getWaitStatesSince(
IsHazardFn, Limit);
1087int GCNHazardRecognizer::getWaitStatesSinceSetReg(IsHazardFn IsHazard,
1093 return getWaitStatesSince(
IsHazardFn, Limit);
1102 for (MCRegUnit Unit :
TRI.regunits(
Reg))
1103 BV.
set(
static_cast<unsigned>(Unit));
1115void GCNHazardRecognizer::addClauseInst(
const MachineInstr &
MI)
const {
1127int GCNHazardRecognizer::checkSoftClauseHazards(
MachineInstr *MEM)
const {
1130 if (!ST.isXNACKEnabled())
1133 bool IsSMRD = TII.isSMRD(*MEM);
1147 for (MachineInstr *
MI : EmittedInstrs) {
1159 if (ClauseDefs.none())
1165 if (
MEM->mayStore())
1168 addClauseInst(*MEM);
1172 return ClauseDefs.anyCommon(ClauseUses) ? 1 : 0;
1175int GCNHazardRecognizer::checkSMRDHazards(
MachineInstr *SMRD)
const {
1176 int WaitStatesNeeded = 0;
1178 WaitStatesNeeded = checkSoftClauseHazards(SMRD);
1181 if (!ST.hasSMRDReadVALUDefHazard())
1182 return WaitStatesNeeded;
1186 int SmrdSgprWaitStates = 4;
1187 auto IsHazardDefFn = [
this](
const MachineInstr &
MI) {
1188 return TII.isVALU(
MI,
true);
1190 auto IsBufferHazardDefFn = [
this](
const MachineInstr &
MI) {
1191 return TII.isSALU(
MI);
1194 bool IsBufferSMRD = TII.isBufferSMRD(*SMRD);
1196 for (
const MachineOperand &Use :
SMRD->uses()) {
1199 int WaitStatesNeededForUse =
1200 SmrdSgprWaitStates - getWaitStatesSinceDef(
Use.getReg(), IsHazardDefFn,
1201 SmrdSgprWaitStates);
1202 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1212 int WaitStatesNeededForUse =
1213 SmrdSgprWaitStates - getWaitStatesSinceDef(
Use.getReg(),
1214 IsBufferHazardDefFn,
1215 SmrdSgprWaitStates);
1216 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1220 return WaitStatesNeeded;
1223int GCNHazardRecognizer::checkVMEMHazards(
MachineInstr *VMEM)
const {
1224 if (!ST.hasVMEMReadSGPRVALUDefHazard())
1227 int WaitStatesNeeded = checkSoftClauseHazards(VMEM);
1231 const int VmemSgprWaitStates = 5;
1232 auto IsHazardDefFn = [
this](
const MachineInstr &
MI) {
1233 return TII.isVALU(
MI,
true);
1235 for (
const MachineOperand &Use :
VMEM->uses()) {
1236 if (!
Use.isReg() || TRI.isVectorRegister(MF.getRegInfo(),
Use.getReg()))
1239 int WaitStatesNeededForUse =
1240 VmemSgprWaitStates - getWaitStatesSinceDef(
Use.getReg(), IsHazardDefFn,
1241 VmemSgprWaitStates);
1242 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1244 return WaitStatesNeeded;
1248 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1249 const SIInstrInfo *TII = ST.getInstrInfo();
1252 int DppVgprWaitStates = 2;
1253 int DppExecWaitStates = 5;
1254 int WaitStatesNeeded = 0;
1255 auto IsHazardDefFn = [TII](
const MachineInstr &
MI) {
1256 return TII->isVALU(
MI,
true);
1259 for (
const MachineOperand &Use :
DPP->uses()) {
1260 if (!
Use.isReg() || !TRI->isVGPR(MF.getRegInfo(),
Use.getReg()))
1262 int WaitStatesNeededForUse =
1263 DppVgprWaitStates - getWaitStatesSinceDef(
1265 [](
const MachineInstr &) { return true; },
1267 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1270 WaitStatesNeeded = std::max(
1272 DppExecWaitStates - getWaitStatesSinceDef(AMDGPU::EXEC, IsHazardDefFn,
1273 DppExecWaitStates));
1275 return WaitStatesNeeded;
1278int GCNHazardRecognizer::checkDivFMasHazards(
MachineInstr *DivFMas)
const {
1279 const SIInstrInfo *TII = ST.getInstrInfo();
1283 const int DivFMasWaitStates = 4;
1284 auto IsHazardDefFn = [TII](
const MachineInstr &
MI) {
1285 return TII->isVALU(
MI,
true);
1287 int WaitStatesNeeded = getWaitStatesSinceDef(AMDGPU::VCC, IsHazardDefFn,
1290 return DivFMasWaitStates - WaitStatesNeeded;
1293int GCNHazardRecognizer::checkGetRegHazards(
MachineInstr *GetRegInstr)
const {
1294 const SIInstrInfo *TII = ST.getInstrInfo();
1295 unsigned GetRegHWReg =
getHWReg(TII, *GetRegInstr);
1297 const int GetRegWaitStates = 2;
1298 auto IsHazardFn = [TII, GetRegHWReg](
const MachineInstr &
MI) {
1301 int WaitStatesNeeded = getWaitStatesSinceSetReg(
IsHazardFn, GetRegWaitStates);
1303 return GetRegWaitStates - WaitStatesNeeded;
1306int GCNHazardRecognizer::checkSetRegHazards(
MachineInstr *SetRegInstr)
const {
1307 const SIInstrInfo *TII = ST.getInstrInfo();
1308 unsigned HWReg =
getHWReg(TII, *SetRegInstr);
1310 const int SetRegWaitStates = ST.getSetRegWaitStates();
1311 auto IsHazardFn = [TII, HWReg](
const MachineInstr &
MI) {
1314 int WaitStatesNeeded = getWaitStatesSinceSetReg(
IsHazardFn, SetRegWaitStates);
1315 return SetRegWaitStates - WaitStatesNeeded;
1318int GCNHazardRecognizer::createsVALUHazard(
const MachineInstr &
MI)
const {
1322 const SIInstrInfo *TII = ST.getInstrInfo();
1323 unsigned Opcode =
MI.getOpcode();
1324 const MCInstrDesc &
Desc =
MI.getDesc();
1326 int VDataIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::vdata);
1329 VDataRCID = TII->getOpRegClassID(
Desc.operands()[VDataIdx]);
1331 if (TII->isMUBUF(
MI) || TII->isMTBUF(
MI)) {
1341 if (ST.hasVDecCoExecHazard())
1343 const MachineOperand *SOffset =
1344 TII->getNamedOperand(
MI, AMDGPU::OpName::soffset);
1345 if (!SOffset || !SOffset->
isReg())
1354 if (TII->isMIMG(
MI)) {
1355 int SRsrcIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::srsrc);
1357 Desc.operands()[SRsrcIdx])) == 256);
1361 if (TII->isFLAT(
MI)) {
1373int GCNHazardRecognizer::checkUniformWindowVALUHazardsHelper(
1378 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1380 auto IsHazard = [&](
const MachineInstr &
MI) {
1381 int DataIdx = createsVALUHazard(
MI);
1382 return DataIdx >= 0 &&
1383 TRI->regsOverlap(
MI.getOperand(DataIdx).getReg(),
Reg);
1386 return std::max(0, 1 - getWaitStatesSince(IsHazard, 1));
1389int GCNHazardRecognizer::checkSOFFSETWindowVALUHazardsHelper(
1396 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1397 const SIInstrInfo *TII = ST.getInstrInfo();
1399 int WaitStatesNeeded = 0;
1403 for (
int Window = 1; Window <= 2; ++Window) {
1404 auto IsHazard = [&](
const MachineInstr &
MI) {
1405 int DataIdx = createsVALUHazard(
MI);
1407 !TRI->regsOverlap(
MI.getOperand(DataIdx).getReg(),
Reg))
1412 if (Window == 1 || !TII->isBUF(
MI))
1415 const MachineOperand *SOffset =
1416 TII->getNamedOperand(
MI, AMDGPU::OpName::soffset);
1417 return !SOffset || !SOffset->
isReg();
1419 WaitStatesNeeded = std::max(WaitStatesNeeded,
1420 Window - getWaitStatesSince(IsHazard, Window));
1423 return WaitStatesNeeded;
1426int GCNHazardRecognizer::checkVALUHazardsHelper(
1431 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1433 if (!TRI->isVectorRegister(MRI,
Def.getReg()))
1436 if (ST.hasVDecCoExecHazard())
1437 return checkSOFFSETWindowVALUHazardsHelper(
Def.getReg());
1439 return checkUniformWindowVALUHazardsHelper(
Def.getReg());
1455 unsigned Opcode =
MI.getOpcode();
1465 if (
auto *DstSel =
TII->getNamedOperand(
MI, AMDGPU::OpName::dst_sel))
1467 return TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
1473 if (
TII->getNamedImmOperand(
MI, AMDGPU::OpName::src0_modifiers) &
1475 return TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
1479 (
TII->getNamedImmOperand(
MI, AMDGPU::OpName::src2_modifiers) &
1481 return TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
1487 return TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
1508 for (
auto &Operand : VALU->operands()) {
1509 if (Operand.isReg() &&
TRI->regsOverlap(Dst->getReg(), Operand.getReg())) {
1516int GCNHazardRecognizer::checkVALUHazards(
MachineInstr *VALU)
const {
1517 int WaitStatesNeeded = 0;
1520 const int TransDefWaitstates = 1;
1522 auto IsTransDefFn = [
this,
VALU](
const MachineInstr &
MI) {
1525 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1526 const SIInstrInfo *TII = ST.getInstrInfo();
1527 Register Def = TII->getNamedOperand(
MI, AMDGPU::OpName::vdst)->getReg();
1529 for (
const MachineOperand &Use :
VALU->explicit_uses()) {
1530 if (
Use.isReg() && TRI->regsOverlap(Def,
Use.getReg()))
1537 int WaitStatesNeededForDef =
1538 TransDefWaitstates -
1539 getWaitStatesSince(IsTransDefFn, TransDefWaitstates);
1540 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1543 if (ST.hasDstSelForwardingHazard() || ST.hasCvtScaleForwardingHazard()) {
1544 const int Shift16DefWaitstates = 1;
1546 auto IsShift16BitDefFn = [
this,
VALU](
const MachineInstr &ProducerMI) {
1547 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1548 const MachineOperand *ForwardedDst =
1554 if (ProducerMI.isInlineAsm()) {
1556 for (
auto &Def : ProducerMI.all_defs()) {
1565 int WaitStatesNeededForDef =
1566 Shift16DefWaitstates -
1567 getWaitStatesSince(IsShift16BitDefFn, Shift16DefWaitstates);
1568 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1571 if (ST.hasVDecCoExecHazard()) {
1572 const int VALUWriteSGPRVALUReadWaitstates = 2;
1573 const int VALUWriteEXECRWLane = 4;
1574 const int VALUWriteVGPRReadlaneRead = 1;
1576 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1577 const MachineRegisterInfo &MRI = MF.getRegInfo();
1579 auto IsVALUDefSGPRFn = [&
UseReg, TRI](
const MachineInstr &
MI) {
1582 return MI.modifiesRegister(
UseReg, TRI);
1585 for (
const MachineOperand &Use :
VALU->explicit_uses()) {
1590 if (TRI->isSGPRReg(MRI,
UseReg)) {
1591 int WaitStatesNeededForDef =
1592 VALUWriteSGPRVALUReadWaitstates -
1593 getWaitStatesSince(IsVALUDefSGPRFn,
1594 VALUWriteSGPRVALUReadWaitstates);
1595 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1599 if (
VALU->readsRegister(AMDGPU::VCC, TRI)) {
1601 int WaitStatesNeededForDef =
1602 VALUWriteSGPRVALUReadWaitstates -
1603 getWaitStatesSince(IsVALUDefSGPRFn, VALUWriteSGPRVALUReadWaitstates);
1604 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1607 switch (
VALU->getOpcode()) {
1608 case AMDGPU::V_READLANE_B32:
1609 case AMDGPU::V_READFIRSTLANE_B32: {
1610 MachineOperand *Src = TII.getNamedOperand(*VALU, AMDGPU::OpName::src0);
1612 int WaitStatesNeededForDef =
1613 VALUWriteVGPRReadlaneRead -
1614 getWaitStatesSince(IsVALUDefSGPRFn, VALUWriteVGPRReadlaneRead);
1615 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1618 case AMDGPU::V_WRITELANE_B32: {
1620 int WaitStatesNeededForDef =
1621 VALUWriteEXECRWLane -
1622 getWaitStatesSince(IsVALUDefSGPRFn, VALUWriteEXECRWLane);
1623 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1633 if (!ST.has12DWordStoreHazard())
1634 return WaitStatesNeeded;
1636 const MachineRegisterInfo &MRI = MF.getRegInfo();
1638 for (
const MachineOperand &Def :
VALU->defs()) {
1639 WaitStatesNeeded = std::max(WaitStatesNeeded, checkVALUHazardsHelper(Def, MRI));
1642 return WaitStatesNeeded;
1645int GCNHazardRecognizer::checkInlineAsmHazards(
MachineInstr *IA)
const {
1654 if (!ST.has12DWordStoreHazard() && !ST.hasDstSelForwardingHazard() &&
1655 !ST.hasCvtScaleForwardingHazard())
1658 const MachineRegisterInfo &MRI = MF.getRegInfo();
1659 int WaitStatesNeeded = 0;
1661 for (
const MachineOperand &
Op :
1663 if (
Op.isReg() &&
Op.isDef()) {
1664 if (!TRI.isVectorRegister(MRI,
Op.getReg()))
1667 if (ST.has12DWordStoreHazard()) {
1669 std::max(WaitStatesNeeded, checkVALUHazardsHelper(
Op, MRI));
1674 if (ST.hasDstSelForwardingHazard()) {
1675 const int Shift16DefWaitstates = 1;
1677 auto IsShift16BitDefFn = [
this, &
IA](
const MachineInstr &ProducerMI) {
1681 return IA->modifiesRegister(Dst->getReg(), &TRI) ||
1682 IA->readsRegister(Dst->getReg(), &TRI);
1684 if (ProducerMI.isInlineAsm()) {
1686 for (
auto &Def : ProducerMI.all_defs()) {
1687 if (
IA->modifiesRegister(
Def.getReg(), &TRI) ||
1688 IA->readsRegister(
Def.getReg(), &TRI)) {
1697 int WaitStatesNeededForDef =
1698 Shift16DefWaitstates -
1699 getWaitStatesSince(IsShift16BitDefFn, Shift16DefWaitstates);
1700 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1703 return WaitStatesNeeded;
1706int GCNHazardRecognizer::checkRWLaneHazards(
MachineInstr *RWLane)
const {
1707 const SIInstrInfo *TII = ST.getInstrInfo();
1708 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1709 const MachineRegisterInfo &MRI = MF.getRegInfo();
1711 const MachineOperand *LaneSelectOp =
1712 TII->getNamedOperand(*RWLane, AMDGPU::OpName::src1);
1714 if (!LaneSelectOp->
isReg() || !TRI->isSGPRReg(MRI, LaneSelectOp->
getReg()))
1719 return TII->isVALU(
MI,
true);
1722 const int RWLaneWaitStates = 4;
1723 int WaitStatesSince = getWaitStatesSinceDef(LaneSelectReg,
IsHazardFn,
1725 return RWLaneWaitStates - WaitStatesSince;
1728int GCNHazardRecognizer::checkRFEHazards(
MachineInstr *RFE)
const {
1729 if (!ST.hasRFEHazards())
1732 const SIInstrInfo *TII = ST.getInstrInfo();
1734 const int RFEWaitStates = 1;
1739 int WaitStatesNeeded = getWaitStatesSinceSetReg(
IsHazardFn, RFEWaitStates);
1740 return RFEWaitStates - WaitStatesNeeded;
1743int GCNHazardRecognizer::checkReadM0Hazards(
MachineInstr *
MI)
const {
1744 const SIInstrInfo *TII = ST.getInstrInfo();
1745 const int ReadM0WaitStates = 1;
1746 auto IsHazardFn = [TII](
const MachineInstr &
MI) {
return TII->isSALU(
MI); };
1747 return ReadM0WaitStates -
1748 getWaitStatesSinceDef(AMDGPU::M0,
IsHazardFn, ReadM0WaitStates);
1753 int WaitStatesNeeded,
bool IsHoisting) {
1755 for (
int I = 0;
I < WaitStatesNeeded; ++
I)
1756 BuildMI(
MBB, InsertPt,
DL, TII.get(AMDGPU::V_NOP_e32));
1760 fixVMEMtoScalarWriteHazards(
MI);
1761 fixVcmpxPermlaneHazards(
MI);
1762 fixSMEMtoVectorWriteHazards(
MI);
1763 fixVcmpxExecWARHazard(
MI);
1764 fixLdsBranchVmemWARHazard(
MI);
1765 if (ST.hasLdsDirect()) {
1766 fixLdsDirectVALUHazard(
MI);
1767 fixLdsDirectVMEMHazard(
MI);
1769 fixVALUPartialForwardingHazard(
MI);
1770 fixVALUTransUseHazard(
MI);
1771 fixVALUTransCoexecutionHazards(
MI);
1773 fixWMMACoexecutionHazards(
MI);
1774 fixShift64HighRegBug(
MI);
1775 fixVALUMaskWriteHazard(
MI);
1776 fixRequiredExportPriority(
MI);
1777 if (ST.hasVPermPk16Hazard())
1778 fixVPermPk16Hazard(
MI);
1779 if (ST.requiresWaitIdleBeforeGetReg())
1780 fixGetRegWaitIdle(
MI);
1781 if (ST.hasDsAtomicAsyncBarrierArriveB64PipeBug())
1782 fixDsAtomicAsyncBarrierArriveB64(
MI);
1783 if (ST.hasScratchBaseForwardingHazard())
1784 fixScratchBaseForwardingHazard(
MI);
1785 if (ST.setRegModeNeedsVNOPs())
1787 if (ST.hasNeedsTDMDrain())
1793 return (
TII.isVOPC(
MI) ||
1794 (
MI.isCompare() && (
TII.isVOP3(
MI) ||
TII.isSDWA(
MI)))) &&
1795 MI.modifiesRegister(AMDGPU::EXEC, &
TRI);
1798bool GCNHazardRecognizer::fixVcmpxPermlaneHazards(
MachineInstr *
MI) {
1802 const SIInstrInfo *TII = ST.getInstrInfo();
1803 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1809 unsigned Opc =
MI.getOpcode();
1811 Opc != AMDGPU::V_NOP_e32 &&
Opc != AMDGPU::V_NOP_e64 &&
1812 Opc != AMDGPU::V_NOP_sdwa;
1816 std::numeric_limits<int>::max())
1822 auto *Src0 = TII->getNamedOperand(*
MI, AMDGPU::OpName::src0);
1824 bool IsUndef = Src0->isUndef();
1826 TII->get(AMDGPU::V_MOV_B32_e32))
1833bool GCNHazardRecognizer::fixVMEMtoScalarWriteHazards(
MachineInstr *
MI) {
1834 if (!ST.hasVMEMtoScalarWriteHazard())
1836 assert(!ST.hasExtendedWaitCounts());
1841 if (
MI->getNumDefs() == 0)
1844 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1850 for (
const MachineOperand &Def :
MI->defs()) {
1851 const MachineOperand *
Op =
1852 I.findRegisterUseOperand(
Def.getReg(), TRI,
false);
1862 (
MI.getOpcode() == AMDGPU::S_WAITCNT &&
1863 !
MI.getOperand(0).getImm()) ||
1864 (
MI.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
1869 std::numeric_limits<int>::max())
1872 const SIInstrInfo *TII = ST.getInstrInfo();
1874 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
1879bool GCNHazardRecognizer::fixSMEMtoVectorWriteHazards(
MachineInstr *
MI) {
1880 if (!ST.hasSMEMtoVectorWriteHazard())
1882 assert(!ST.hasExtendedWaitCounts());
1887 AMDGPU::OpName SDSTName;
1888 switch (
MI->getOpcode()) {
1889 case AMDGPU::V_READLANE_B32:
1890 case AMDGPU::V_READFIRSTLANE_B32:
1891 SDSTName = AMDGPU::OpName::vdst;
1894 SDSTName = AMDGPU::OpName::sdst;
1898 const SIInstrInfo *TII = ST.getInstrInfo();
1899 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1901 const MachineOperand *SDST = TII->getNamedOperand(*
MI, SDSTName);
1903 for (
const auto &MO :
MI->implicit_operands()) {
1904 if (MO.isDef() && TRI->isSGPRClass(TRI->getPhysRegBaseClass(MO.getReg()))) {
1915 auto IsHazardFn = [SDSTReg, TRI](
const MachineInstr &
I) {
1920 if (TII->isSALU(
MI)) {
1921 switch (
MI.getOpcode()) {
1922 case AMDGPU::S_SETVSKIP:
1923 case AMDGPU::S_VERSION:
1924 case AMDGPU::S_WAITCNT_VSCNT:
1925 case AMDGPU::S_WAITCNT_VMCNT:
1926 case AMDGPU::S_WAITCNT_EXPCNT:
1929 case AMDGPU::S_WAITCNT_LGKMCNT:
1931 return (
MI.getOperand(1).getImm() == 0) &&
1932 (
MI.getOperand(0).
getReg() == AMDGPU::SGPR_NULL);
1933 case AMDGPU::S_WAITCNT: {
1934 const int64_t
Imm =
MI.getOperand(0).getImm();
1941 MI.getOpcode() == AMDGPU::S_WAIT_IDLE) &&
1942 "unexpected wait count instruction");
1944 if (TII->isSOPP(
MI))
1960 std::numeric_limits<int>::max())
1964 TII->get(AMDGPU::S_MOV_B32), AMDGPU::SGPR_NULL)
1969bool GCNHazardRecognizer::fixVcmpxExecWARHazard(
MachineInstr *
MI) {
1970 if (!ST.hasVcmpxExecWARHazard())
1972 assert(!ST.hasExtendedWaitCounts());
1977 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1978 if (!
MI->modifiesRegister(AMDGPU::EXEC, TRI))
1984 return I.readsRegister(AMDGPU::EXEC, TRI);
1987 const SIInstrInfo *TII = ST.getInstrInfo();
1988 auto IsExpiredFn = [TII, TRI](
const MachineInstr &
MI, int) {
1990 if (TII->getNamedOperand(
MI, AMDGPU::OpName::sdst))
1992 for (
auto MO :
MI.implicit_operands())
1993 if (MO.isDef() && TRI->isSGPRClass(TRI->getPhysRegBaseClass(MO.getReg())))
1996 if (
MI.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2003 std::numeric_limits<int>::max())
2007 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
2014 if (!ST.hasLdsBranchVmemWARHazard())
2019 bool HasLds =
false;
2020 bool HasVmem =
false;
2021 for (
auto &
MBB : MF) {
2022 for (
auto &
MI :
MBB) {
2025 if (HasLds && HasVmem)
2033 return I.getOpcode() == AMDGPU::S_WAITCNT_VSCNT &&
2034 I.getOperand(0).getReg() == AMDGPU::SGPR_NULL &&
2035 !
I.getOperand(1).getImm();
2038bool GCNHazardRecognizer::fixLdsBranchVmemWARHazard(
MachineInstr *
MI) {
2039 if (!RunLdsBranchVmemWARHazardFixup)
2042 assert(ST.hasLdsBranchVmemWARHazard());
2043 assert(!ST.hasExtendedWaitCounts());
2045 auto IsHazardInst = [](
const MachineInstr &
MI) {
2053 auto InstType = IsHazardInst(*
MI);
2057 auto IsExpiredFn = [&IsHazardInst](
const MachineInstr &
I, int) {
2061 auto IsHazardFn = [InstType, &IsHazardInst](
const MachineInstr &
I) {
2065 auto IsHazardFn = [InstType, IsHazardInst](
const MachineInstr &
I) {
2066 auto InstType2 = IsHazardInst(
I);
2067 return InstType2 && InstType != InstType2;
2070 auto IsExpiredFn = [InstType, &IsHazardInst](
const MachineInstr &
I, int) {
2071 auto InstType2 = IsHazardInst(
I);
2072 if (InstType == InstType2)
2079 std::numeric_limits<int>::max();
2083 std::numeric_limits<int>::max())
2086 const SIInstrInfo *TII = ST.getInstrInfo();
2088 TII->get(AMDGPU::S_WAITCNT_VSCNT))
2095bool GCNHazardRecognizer::fixLdsDirectVALUHazard(
MachineInstr *
MI) {
2099 const int NoHazardWaitStates = 15;
2100 const MachineOperand *VDST = TII.getNamedOperand(*
MI, AMDGPU::OpName::vdst);
2103 bool VisitedTrans =
false;
2104 auto IsHazardFn = [
this, VDSTReg, &VisitedTrans](
const MachineInstr &
I) {
2109 return I.readsRegister(VDSTReg, &TRI) ||
I.modifiesRegister(VDSTReg, &TRI);
2111 auto IsExpiredFn = [&](
const MachineInstr &
I,
int WaitStates) {
2112 if (WaitStates >= NoHazardWaitStates)
2118 auto GetWaitStatesFn = [](
const MachineInstr &
MI) {
2122 DenseSet<const MachineBasicBlock *> Visited;
2124 std::next(
MI->getReverseIterator()), 0,
2132 MachineOperand *WaitVdstOp =
2133 TII.getNamedOperand(*
MI, AMDGPU::OpName::waitvdst);
2134 WaitVdstOp->
setImm(std::min(
Count, NoHazardWaitStates));
2139bool GCNHazardRecognizer::fixLdsDirectVMEMHazard(
MachineInstr *
MI) {
2143 const MachineOperand *VDST = TII.getNamedOperand(*
MI, AMDGPU::OpName::vdst);
2146 auto IsHazardFn = [
this, VDSTReg](
const MachineInstr &
I) {
2149 return I.readsRegister(VDSTReg, &TRI) ||
I.modifiesRegister(VDSTReg, &TRI);
2151 bool LdsdirCanWait = ST.hasLdsWaitVMSRC();
2154 auto IsExpiredFn = [
this, LdsdirCanWait](
const MachineInstr &
I, int) {
2157 (
I.getOpcode() == AMDGPU::S_WAITCNT && !
I.getOperand(0).getImm()) ||
2158 (
I.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2161 !TII.getNamedOperand(
I, AMDGPU::OpName::waitvsrc)->getImm());
2165 std::numeric_limits<int>::max())
2168 if (LdsdirCanWait) {
2169 TII.getNamedOperand(*
MI, AMDGPU::OpName::waitvsrc)->setImm(0);
2172 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
2179bool GCNHazardRecognizer::fixVALUPartialForwardingHazard(
MachineInstr *
MI) {
2180 if (!ST.hasVALUPartialForwardingHazard())
2182 assert(!ST.hasExtendedWaitCounts());
2187 SmallSetVector<Register, 4> SrcVGPRs;
2189 for (
const MachineOperand &Use :
MI->explicit_uses()) {
2190 if (
Use.isReg() && TRI.isVGPR(MF.getRegInfo(),
Use.getReg()))
2195 if (SrcVGPRs.
size() <= 1)
2213 const int Intv1plus2MaxVALUs = 2;
2214 const int Intv3MaxVALUs = 4;
2215 const int IntvMaxVALUs = 6;
2216 const int NoHazardVALUWaitStates = IntvMaxVALUs + 2;
2219 SmallDenseMap<Register, int, 4> DefPos;
2220 int ExecPos = std::numeric_limits<int>::max();
2223 static unsigned getHashValue(
const StateType &State) {
2225 for (
const auto &[
Reg, Pos] : State.DefPos)
2229 static bool isEqual(
const StateType &
LHS,
const StateType &
RHS) {
2230 return LHS.DefPos ==
RHS.DefPos &&
LHS.ExecPos ==
RHS.ExecPos &&
2238 auto IsHazardFn = [&,
this](StateType &State,
const MachineInstr &
I) {
2240 if (State.VALUs > NoHazardVALUWaitStates)
2246 (
I.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2254 if (!State.DefPos.count(Src) &&
I.modifiesRegister(Src, &TRI)) {
2255 State.DefPos[Src] = State.VALUs;
2260 if (State.ExecPos == std::numeric_limits<int>::max()) {
2261 if (!State.DefPos.empty() &&
I.modifiesRegister(AMDGPU::EXEC, &TRI)) {
2262 State.ExecPos = State.VALUs;
2269 if (State.VALUs > Intv3MaxVALUs && State.DefPos.empty())
2277 if (State.ExecPos == std::numeric_limits<int>::max())
2280 int PreExecPos = std::numeric_limits<int>::max();
2281 int PostExecPos = std::numeric_limits<int>::max();
2283 for (
auto Entry : State.DefPos) {
2284 int DefVALUs =
Entry.second;
2285 if (DefVALUs != std::numeric_limits<int>::max()) {
2286 if (DefVALUs >= State.ExecPos)
2287 PreExecPos = std::min(PreExecPos, DefVALUs);
2289 PostExecPos = std::min(PostExecPos, DefVALUs);
2294 if (PostExecPos == std::numeric_limits<int>::max())
2298 int Intv3VALUs = PostExecPos;
2299 if (Intv3VALUs > Intv3MaxVALUs)
2303 int Intv2VALUs = (State.ExecPos - PostExecPos) - 1;
2304 if (Intv2VALUs > Intv1plus2MaxVALUs)
2308 if (PreExecPos == std::numeric_limits<int>::max())
2312 int Intv1VALUs = PreExecPos - State.ExecPos;
2313 if (Intv1VALUs > Intv1plus2MaxVALUs)
2317 if (Intv1VALUs + Intv2VALUs > Intv1plus2MaxVALUs)
2322 auto UpdateStateFn = [](StateType &State,
const MachineInstr &
MI) {
2328 std::next(
MI->getReverseIterator())))
2332 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
2338bool GCNHazardRecognizer::fixVALUTransUseHazard(
MachineInstr *
MI) {
2339 if (!ST.hasVALUTransUseHazard())
2341 assert(!ST.hasExtendedWaitCounts());
2346 SmallSet<Register, 4> SrcVGPRs;
2348 for (
const MachineOperand &Use :
MI->explicit_uses()) {
2349 if (
Use.isReg() && TRI.isVGPR(MF.getRegInfo(),
Use.getReg()))
2363 const int IntvMaxVALUs = 5;
2364 const int IntvMaxTRANS = 1;
2370 static unsigned getHashValue(
const StateType &State) {
2373 static bool isEqual(
const StateType &
LHS,
const StateType &
RHS) {
2374 return LHS.VALUs ==
RHS.VALUs &&
LHS.TRANS ==
RHS.TRANS;
2381 auto IsHazardFn = [&,
this](StateType &State,
const MachineInstr &
I) {
2383 if (State.VALUs > IntvMaxVALUs || State.TRANS > IntvMaxTRANS)
2389 (
I.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2396 if (
I.modifiesRegister(Src, &TRI)) {
2404 auto UpdateStateFn = [](StateType &State,
const MachineInstr &
MI) {
2412 std::next(
MI->getReverseIterator())))
2418 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
2424bool GCNHazardRecognizer::fixVALUTransCoexecutionHazards(
MachineInstr *
MI) {
2425 if (!ST.hasTransCoexecutionHazard() ||
2430 const SIInstrInfo *TII = ST.getInstrInfo();
2431 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2433 auto IsTransHazardFn = [
MI, TII, TRI](
const MachineInstr &
I) {
2438 Register TransDef = TII->getNamedOperand(
I, AMDGPU::OpName::vdst)->getReg();
2439 for (
const MachineOperand &ValuUse :
MI->explicit_uses()) {
2440 if (ValuUse.isReg() && TRI->regsOverlap(TransDef, ValuUse.getReg()))
2444 auto *ValuDst = TII->getNamedOperand(*
MI, AMDGPU::OpName::vdst);
2445 if (!ValuDst || !ValuDst->isReg())
2449 Register ValuDef = ValuDst->getReg();
2450 for (
const MachineOperand &TransUse :
I.explicit_uses()) {
2451 if (TransUse.isReg() && TRI->regsOverlap(ValuDef, TransUse.getReg()))
2462 const int HasVALU = std::numeric_limits<int>::max();
2463 if (::getWaitStatesSince(IsTransHazardFn,
MI,
IsExpiredFn) == HasVALU)
2466 BuildMI(*
MI->getParent(),
MI,
MI->getDebugLoc(), TII->get(AMDGPU::V_NOP_e32));
2474 const SIInstrInfo *TII = ST.getInstrInfo();
2475 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2477 auto IsHazardFn = [
MI, TII, TRI,
this](
const MachineInstr &
I) {
2484 TII->getNamedOperand(*
MI, AMDGPU::OpName::src0)->getReg();
2486 TII->getNamedOperand(*
MI, AMDGPU::OpName::src1)->getReg();
2489 TII->getNamedOperand(
I, AMDGPU::OpName::vdst)->getReg();
2491 if (TRI->regsOverlap(PrevDstReg, CurSrc0Reg) ||
2492 TRI->regsOverlap(PrevDstReg, CurSrc1Reg)) {
2501 TII->getNamedOperand(*
MI, AMDGPU::OpName::src2)->getReg();
2502 if (TRI->regsOverlap(PrevDstReg, CurIndex))
2516 std::numeric_limits<int>::max())
2519 BuildMI(*
MI->getParent(),
MI,
MI->getDebugLoc(), TII->get(AMDGPU::V_NOP_e32));
2573 bool IsLowestRateWMMA = ST.hasGFX125xLowestRateWMMA();
2574 unsigned Category = 0;
2576 unsigned Latency = SchedModel.computeInstrLatency(&
MI);
2581 assert(!IsSWMMAC &&
"no 4-cycle SWMMAC expected");
2585 Category = IsSWMMAC ? 2 : 0;
2588 Category = IsLowestRateWMMA ? 4 : (IsSWMMAC ? 3 : 1);
2591 assert(IsLowestRateWMMA &&
"latency 32 is not expected");
2601int GCNHazardRecognizer::checkWMMACoexecutionHazards(
MachineInstr *
MI)
const {
2602 if (!ST.hasWMMACoexecutionHazards())
2605 const SIInstrInfo *TII = ST.getInstrInfo();
2614 const int WMMAWaitStates[] = {5, 9, 3, 5, 9, 17, 2};
2615 const int VALUWaitStates[] = {4, 8, 2, 4, 8, 16, 1};
2616 unsigned Category = 0;
2618 auto IsWMMAHazardFn = [
MI, TII, &Category,
this](
const MachineInstr &
I) {
2619 if (!TII->isXDLWMMA(
I))
2623 return hasWMMAToWMMARegOverlap(
I, *
MI);
2626 auto IsVALUHazardFn = [
MI, TII, &Category,
this](
const MachineInstr &
I) {
2627 if (!TII->isXDLWMMA(
I))
2631 return hasWMMAToVALURegOverlap(
I, *
MI);
2634 int WaitStatesNeeded = -1;
2635 int ExistingVALUs = 0;
2636 bool IsLowestRateWMMA = ST.hasGFX125xLowestRateWMMA();
2644 if (TII->isXDLWMMA(*
MI)) {
2646 const int WMMAWaitsLimit = IsLowestRateWMMA ? 17 : 9;
2647 ExistingVALUs = getWaitStatesSinceVALU(IsWMMAHazardFn, WMMAWaitsLimit);
2648 WaitStatesNeeded = WMMAWaitStates[Category] - ExistingVALUs;
2651 const int VALUWaitsLimit = IsLowestRateWMMA ? 16 : 8;
2652 ExistingVALUs = getWaitStatesSinceVALU(IsVALUHazardFn, VALUWaitsLimit);
2653 WaitStatesNeeded = VALUWaitStates[Category] - ExistingVALUs;
2656 return WaitStatesNeeded;
2659bool GCNHazardRecognizer::hasWMMAToWMMARegOverlap(
2661 Register D0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::vdst)->getReg();
2662 Register A1 = TII.getNamedOperand(
MI, AMDGPU::OpName::src0)->getReg();
2663 Register B1 = TII.getNamedOperand(
MI, AMDGPU::OpName::src1)->getReg();
2666 if (TRI.regsOverlap(D0, A1) || TRI.regsOverlap(D0, B1))
2670 Register Idx1 = TII.getNamedOperand(
MI, AMDGPU::OpName::src2)->getReg();
2671 if (TRI.regsOverlap(D0, Idx1))
2677bool GCNHazardRecognizer::hasWMMAToVALURegOverlap(
2680 Register D0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::vdst)->getReg();
2681 for (
const MachineOperand &ValuUse :
MI.explicit_uses()) {
2682 if (ValuUse.isReg() && TRI.regsOverlap(D0, ValuUse.getReg()))
2687 Register A0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::src0)->getReg();
2688 Register B0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::src1)->getReg();
2692 Register Idx0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::src2)->getReg();
2693 WMMARegs.push_back(Idx0);
2696 for (
const MachineOperand &ValuDef :
MI.defs()) {
2697 Register VDstReg = ValuDef.getReg();
2698 for (
Register WMMAReg : WMMARegs) {
2699 if (TRI.regsOverlap(VDstReg, WMMAReg))
2706bool GCNHazardRecognizer::isCoexecutionHazardFor(
const MachineInstr &
I,
2710 if (!TII.isXDLWMMA(
I))
2714 if (TII.isXDLWMMA(
MI))
2715 return hasWMMAToWMMARegOverlap(
I,
MI);
2717 return hasWMMAToVALURegOverlap(
I,
MI);
2723 bool IncludeSubloops) {
2726 for (MachineBasicBlock *
MBB :
L->getBlocks()) {
2727 if (!IncludeSubloops && MLI->getLoopFor(
MBB) != L)
2729 for (MachineInstr &
I : *
MBB) {
2732 if (isCoexecutionHazardFor(
I, *
MI))
2739bool GCNHazardRecognizer::tryHoistWMMAVnopsFromLoop(
MachineInstr *
MI,
2740 int WaitStatesNeeded) {
2744 MachineLoop *
L = MLI->getLoopFor(
MI->getParent());
2746 ++NumWMMAHoistingBailed;
2751 if (hasWMMAHazardInLoop(L,
MI)) {
2752 ++NumWMMAHoistingBailed;
2757 MachineLoop *TargetLoop =
L;
2759 if (hasWMMAHazardInLoop(Parent,
MI,
false))
2761 TargetLoop = Parent;
2767 ++NumWMMAHoistingBailed;
2771 LLVM_DEBUG(
dbgs() <<
"WMMA V_NOP Hoisting: Moving " << WaitStatesNeeded
2777 NumWMMANopsHoisted += WaitStatesNeeded;
2781bool GCNHazardRecognizer::fixWMMACoexecutionHazards(
MachineInstr *
MI) {
2782 int WaitStatesNeeded = checkWMMACoexecutionHazards(
MI);
2783 if (WaitStatesNeeded <= 0)
2789 emitVNops(*
MI->getParent(),
MI->getIterator(), WaitStatesNeeded);
2793bool GCNHazardRecognizer::fixShift64HighRegBug(
MachineInstr *
MI) {
2794 if (!ST.hasShift64HighRegBug())
2796 assert(!ST.hasExtendedWaitCounts());
2798 switch (
MI->getOpcode()) {
2801 case AMDGPU::V_LSHLREV_B64_e64:
2802 case AMDGPU::V_LSHRREV_B64_e64:
2803 case AMDGPU::V_ASHRREV_I64_e64:
2807 MachineOperand *Amt = TII.getNamedOperand(*
MI, AMDGPU::OpName::src0);
2812 const MachineRegisterInfo &MRI = MF.getRegInfo();
2814 if (!TRI.isVGPR(MRI, AmtReg) || ((AmtReg - AMDGPU::VGPR0) & 7) != 7)
2817 if (AmtReg != AMDGPU::VGPR255 && MRI.
isPhysRegUsed(AmtReg + 1))
2820 assert(ST.needsAlignedVGPRs());
2821 static_assert(AMDGPU::VGPR0 + 1 == AMDGPU::VGPR1);
2825 MachineOperand *Src1 = TII.getNamedOperand(*
MI, AMDGPU::OpName::src1);
2836 Register DstReg =
MI->getOperand(0).getReg();
2838 Register DstLo = TRI.getSubReg(DstReg, AMDGPU::sub0);
2846 bool Overlapped =
MI->modifiesRegister(AmtReg, &TRI);
2848 for (MCRegister
Reg : Overlapped ? AMDGPU::VReg_64_Align2RegClass
2849 : AMDGPU::VGPR_32RegClass) {
2850 if (!
MI->modifiesRegister(
Reg, &TRI) && !
MI->readsRegister(
Reg, &TRI)) {
2856 Register NewAmt = Overlapped ? (
Register)TRI.getSubReg(NewReg, AMDGPU::sub1)
2861 NewAmtLo = TRI.getSubReg(NewReg, AMDGPU::sub0);
2874 runOnInstruction(
BuildMI(*
MBB,
MI,
DL, TII.get(AMDGPU::V_SWAP_B32), NewAmt)
2881 BuildMI(*
MBB, std::next(
MI->getIterator()),
DL, TII.get(AMDGPU::V_SWAP_B32),
2887 BuildMI(*
MBB, std::next(
MI->getIterator()),
DL, TII.get(AMDGPU::V_SWAP_B32),
2901 MI->getOperand(0).setReg(NewReg);
2910int GCNHazardRecognizer::checkNSAtoVMEMHazard(
MachineInstr *
MI)
const {
2911 int NSAtoVMEMWaitStates = 1;
2913 if (!ST.hasNSAtoVMEMBug())
2919 const SIInstrInfo *TII = ST.getInstrInfo();
2920 const auto *
Offset = TII->getNamedOperand(*
MI, AMDGPU::OpName::offset);
2928 return Info->MIMGEncoding == AMDGPU::MIMGEncGfx10NSA &&
2929 TII->getInstSizeInBytes(
I) >= 16;
2932 return NSAtoVMEMWaitStates - getWaitStatesSince(
IsHazardFn, 1);
2935int GCNHazardRecognizer::checkFPAtomicToDenormModeHazard(
2937 int FPAtomicToDenormModeWaitStates = 3;
2939 if (!ST.hasFPAtomicToDenormModeHazard())
2941 assert(!ST.hasExtendedWaitCounts());
2943 if (
MI->getOpcode() != AMDGPU::S_DENORM_MODE)
2952 auto IsExpiredFn = [](
const MachineInstr &
MI,
int WaitStates) {
2959 return FPAtomicToDenormModeWaitStates -
2963int GCNHazardRecognizer::checkMAIHazards(
MachineInstr *
MI)
const {
2966 return ST.hasGFX90AInsts() ? checkMAIHazards90A(
MI) : checkMAIHazards908(
MI);
2969int GCNHazardRecognizer::checkMFMAPadding(
MachineInstr *
MI)
const {
2974 const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
2978 int NeighborMFMALatency = 0;
2979 auto IsNeighboringMFMA = [&NeighborMFMALatency,
2980 this](
const MachineInstr &
MI) {
2984 NeighborMFMALatency = this->getMFMAPipelineWaitStates(
MI);
2988 const int MaxMFMAPipelineWaitStates = 16;
2989 int WaitStatesSinceNeighborMFMA =
2990 getWaitStatesSince(IsNeighboringMFMA, MaxMFMAPipelineWaitStates);
2992 int NeighborMFMAPaddingNeeded =
2994 WaitStatesSinceNeighborMFMA;
2996 return std::max(0, NeighborMFMAPaddingNeeded);
2999int GCNHazardRecognizer::checkMAIHazards908(
MachineInstr *
MI)
const {
3000 int WaitStatesNeeded = 0;
3001 unsigned Opc =
MI->getOpcode();
3003 auto IsVALUFn = [](
const MachineInstr &
MI) {
3007 if (
Opc != AMDGPU::V_ACCVGPR_READ_B32_e64) {
3008 const int LegacyVALUWritesVGPRWaitStates = 2;
3009 const int VALUWritesExecWaitStates = 4;
3010 const int MaxWaitStates = 4;
3012 int WaitStatesNeededForUse = VALUWritesExecWaitStates -
3013 getWaitStatesSinceDef(AMDGPU::EXEC, IsVALUFn, MaxWaitStates);
3014 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3016 if (WaitStatesNeeded < MaxWaitStates) {
3017 for (
const MachineOperand &Use :
MI->explicit_uses()) {
3018 const int MaxWaitStates = 2;
3020 if (!
Use.isReg() || !TRI.isVGPR(MF.getRegInfo(),
Use.getReg()))
3023 int WaitStatesNeededForUse = LegacyVALUWritesVGPRWaitStates -
3024 getWaitStatesSinceDef(
Use.getReg(), IsVALUFn, MaxWaitStates);
3025 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3027 if (WaitStatesNeeded == MaxWaitStates)
3033 for (
const MachineOperand &
Op :
MI->explicit_operands()) {
3034 if (!
Op.isReg() || !TRI.isAGPR(MF.getRegInfo(),
Op.getReg()))
3037 if (
Op.isDef() &&
Opc != AMDGPU::V_ACCVGPR_WRITE_B32_e64)
3040 const int MFMAWritesAGPROverlappedSrcABWaitStates = 4;
3041 const int MFMAWritesAGPROverlappedSrcCWaitStates = 2;
3042 const int MFMA4x4WritesAGPRAccVgprReadWaitStates = 4;
3043 const int MFMA16x16WritesAGPRAccVgprReadWaitStates = 10;
3044 const int MFMA32x32WritesAGPRAccVgprReadWaitStates = 18;
3045 const int MFMA4x4WritesAGPRAccVgprWriteWaitStates = 1;
3046 const int MFMA16x16WritesAGPRAccVgprWriteWaitStates = 7;
3047 const int MFMA32x32WritesAGPRAccVgprWriteWaitStates = 15;
3048 const int MaxWaitStates = 18;
3050 unsigned HazardDefLatency = 0;
3052 auto IsOverlappedMFMAFn = [
Reg, &HazardDefLatency,
3053 this](
const MachineInstr &
MI) {
3060 std::max(HazardDefLatency, TSchedModel.computeInstrLatency(&
MI));
3061 return TRI.regsOverlap(DstReg,
Reg);
3064 int WaitStatesSinceDef = getWaitStatesSinceDef(
Reg, IsOverlappedMFMAFn,
3066 int NeedWaitStates = MFMAWritesAGPROverlappedSrcABWaitStates;
3067 int SrcCIdx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src2);
3068 int OpNo =
Op.getOperandNo();
3069 if (OpNo == SrcCIdx) {
3070 NeedWaitStates = MFMAWritesAGPROverlappedSrcCWaitStates;
3071 }
else if (
Opc == AMDGPU::V_ACCVGPR_READ_B32_e64) {
3072 switch (HazardDefLatency) {
3073 case 2: NeedWaitStates = MFMA4x4WritesAGPRAccVgprReadWaitStates;
3075 case 8: NeedWaitStates = MFMA16x16WritesAGPRAccVgprReadWaitStates;
3077 case 16: [[fallthrough]];
3078 default: NeedWaitStates = MFMA32x32WritesAGPRAccVgprReadWaitStates;
3081 }
else if (
Opc == AMDGPU::V_ACCVGPR_WRITE_B32_e64) {
3082 switch (HazardDefLatency) {
3083 case 2: NeedWaitStates = MFMA4x4WritesAGPRAccVgprWriteWaitStates;
3085 case 8: NeedWaitStates = MFMA16x16WritesAGPRAccVgprWriteWaitStates;
3087 case 16: [[fallthrough]];
3088 default: NeedWaitStates = MFMA32x32WritesAGPRAccVgprWriteWaitStates;
3093 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceDef;
3094 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3096 if (WaitStatesNeeded == MaxWaitStates)
3097 return WaitStatesNeeded;
3099 auto IsAccVgprWriteFn = [
Reg,
this](
const MachineInstr &
MI) {
3100 if (
MI.getOpcode() != AMDGPU::V_ACCVGPR_WRITE_B32_e64)
3103 return TRI.regsOverlap(
Reg, DstReg);
3106 const int AccVGPRWriteMFMAReadSrcCWaitStates = 1;
3107 const int AccVGPRWriteMFMAReadSrcABWaitStates = 3;
3108 const int AccVGPRWriteAccVgprReadWaitStates = 3;
3109 NeedWaitStates = AccVGPRWriteMFMAReadSrcABWaitStates;
3110 if (OpNo == SrcCIdx)
3111 NeedWaitStates = AccVGPRWriteMFMAReadSrcCWaitStates;
3112 else if (
Opc == AMDGPU::V_ACCVGPR_READ_B32_e64)
3113 NeedWaitStates = AccVGPRWriteAccVgprReadWaitStates;
3115 WaitStatesNeededForUse = NeedWaitStates -
3116 getWaitStatesSinceDef(
Reg, IsAccVgprWriteFn, MaxWaitStates);
3117 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3119 if (WaitStatesNeeded == MaxWaitStates)
3120 return WaitStatesNeeded;
3123 if (
Opc == AMDGPU::V_ACCVGPR_WRITE_B32_e64) {
3124 const int MFMA4x4ReadSrcCAccVgprWriteWaitStates = 0;
3125 const int MFMA16x16ReadSrcCAccVgprWriteWaitStates = 5;
3126 const int MFMA32x32ReadSrcCAccVgprWriteWaitStates = 13;
3127 const int MaxWaitStates = 13;
3128 Register DstReg =
MI->getOperand(0).getReg();
3129 unsigned HazardDefLatency = 0;
3131 auto IsSrcCMFMAFn = [DstReg, &HazardDefLatency,
3132 this](
const MachineInstr &
MI) {
3135 Register Reg = TII.getNamedOperand(
MI, AMDGPU::OpName::src2)->getReg();
3137 std::max(HazardDefLatency, TSchedModel.computeInstrLatency(&
MI));
3138 return TRI.regsOverlap(
Reg, DstReg);
3141 int WaitStatesSince = getWaitStatesSince(IsSrcCMFMAFn, MaxWaitStates);
3143 switch (HazardDefLatency) {
3144 case 2: NeedWaitStates = MFMA4x4ReadSrcCAccVgprWriteWaitStates;
3146 case 8: NeedWaitStates = MFMA16x16ReadSrcCAccVgprWriteWaitStates;
3148 case 16: [[fallthrough]];
3149 default: NeedWaitStates = MFMA32x32ReadSrcCAccVgprWriteWaitStates;
3153 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSince;
3154 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3158 WaitStatesNeeded = std::max(WaitStatesNeeded, checkMFMAPadding(
MI));
3160 return WaitStatesNeeded;
3189 return NumPasses + 1 + IsGFX950;
3200 return NumPasses + 1 + (NumPasses != 2 && IsGFX950);
3218 return NumPasses + 2;
3228 return NumPasses + 3 + (NumPasses != 2 && IsGFX950);
3231int GCNHazardRecognizer::getMFMAOverlappedSrcCWaitStates(
3233 constexpr int SMFMA4x4WritesVGPROverlappedSMFMASrcCWaitStates = 2;
3234 constexpr int SMFMA16x16WritesVGPROverlappedSMFMASrcCWaitStates = 8;
3235 constexpr int SMFMA32x32WritesVGPROverlappedSMFMASrcCWaitStates = 16;
3236 constexpr int SMFMA4x4WritesVGPROverlappedDMFMASrcCWaitStates = 3;
3237 constexpr int SMFMA16x16WritesVGPROverlappedDMFMASrcCWaitStates = 9;
3238 constexpr int SMFMA32x32WritesVGPROverlappedDMFMASrcCWaitStates = 17;
3239 constexpr int DMFMA16x16WritesVGPROverlappedSrcCWaitStates = 9;
3240 constexpr int GFX950_DMFMA16x16WritesVGPROverlappedSrcCWaitStates = 17;
3241 constexpr int DMFMA4x4WritesVGPROverlappedSrcCWaitStates = 4;
3245 if (TII.isXDL(*Reader) && !TII.isXDL(*Writer))
3249 case AMDGPU::V_MFMA_F64_16X16X4F64_e64:
3250 case AMDGPU::V_MFMA_F64_16X16X4F64_vgprcd_e64:
3251 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_e64:
3252 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_vgprcd_e64:
3253 return ST.hasGFX950Insts()
3254 ? GFX950_DMFMA16x16WritesVGPROverlappedSrcCWaitStates
3255 : DMFMA16x16WritesVGPROverlappedSrcCWaitStates;
3256 case AMDGPU::V_MFMA_F64_4X4X4F64_e64:
3257 case AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64:
3258 return DMFMA4x4WritesVGPROverlappedSrcCWaitStates;
3263 int NumPasses = TSchedModel.computeInstrLatency(Writer);
3264 if (ST.hasGFX940Insts()) {
3265 if (!TII.isXDL(*Writer))
3268 return TII.isXDL(*Reader)
3270 NumPasses, ST.hasGFX950Insts())
3272 NumPasses, ST.hasGFX950Insts());
3276 switch (NumPasses) {
3278 return IsDGEMM ? SMFMA4x4WritesVGPROverlappedDMFMASrcCWaitStates
3279 : SMFMA4x4WritesVGPROverlappedSMFMASrcCWaitStates;
3281 return IsDGEMM ? SMFMA16x16WritesVGPROverlappedDMFMASrcCWaitStates
3282 : SMFMA16x16WritesVGPROverlappedSMFMASrcCWaitStates;
3284 return IsDGEMM ? SMFMA32x32WritesVGPROverlappedDMFMASrcCWaitStates
3285 : SMFMA32x32WritesVGPROverlappedSMFMASrcCWaitStates;
3291int GCNHazardRecognizer::checkMAIHazards90A(
MachineInstr *
MI)
const {
3292 int WaitStatesNeeded = 0;
3293 unsigned Opc =
MI->getOpcode();
3295 auto IsLegacyVALUFn = [](
const MachineInstr &
MI) {
3300 auto IsLegacyVALUNotDotFn = [](
const MachineInstr &
MI) {
3306 return WaitStatesNeeded;
3308 const int VALUWritesExecWaitStates = 4;
3309 int WaitStatesNeededForUse = VALUWritesExecWaitStates -
3310 getWaitStatesSinceDef(AMDGPU::EXEC, IsLegacyVALUFn,
3311 VALUWritesExecWaitStates);
3312 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3314 int SrcCIdx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src2);
3317 for (
const MachineOperand &Use :
MI->explicit_uses()) {
3318 const int LegacyVALUNotDotWritesVGPRWaitStates = 2;
3319 const int SMFMA4x4WritesVGPROverlappedSrcABWaitStates = 5;
3320 const int SMFMA16x16WritesVGPROverlappedSrcABWaitStates = 11;
3321 const int SMFMA32x32WritesVGPROverlappedSrcABWaitStates = 19;
3322 const int DMFMA4x4WritesVGPROverlappedMFMASrcABWaitStates = 6;
3323 const int DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates = 11;
3324 const int GFX950_DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates = 19;
3325 const int DMFMA4x4WritesVGPRFullSrcCWaitStates = 4;
3326 const int GFX940_SMFMA4x4WritesVGPRFullSrcCWaitStates = 2;
3327 const int MaxWaitStates =
3329 16, ST.hasGFX950Insts());
3335 const MachineInstr *MI1;
3337 auto IsOverlappedMFMAFn = [
Reg, &FullReg, &MI1,
3338 this](
const MachineInstr &
MI) {
3342 FullReg = (DstReg ==
Reg);
3344 return TRI.regsOverlap(DstReg,
Reg);
3347 WaitStatesNeededForUse = LegacyVALUNotDotWritesVGPRWaitStates -
3348 getWaitStatesSinceDef(
Reg, IsLegacyVALUNotDotFn, MaxWaitStates);
3349 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3352 getWaitStatesSinceDef(
Reg, IsOverlappedMFMAFn, MaxWaitStates);
3353 if (NumWaitStates == std::numeric_limits<int>::max())
3356 int OpNo =
Use.getOperandNo();
3358 int NeedWaitStates = 0;
3359 if (OpNo == SrcCIdx) {
3363 }
else if (FullReg) {
3364 if ((
Opc == AMDGPU::V_MFMA_F64_4X4X4F64_e64 ||
3365 Opc == AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64) &&
3366 (Opc1 == AMDGPU::V_MFMA_F64_4X4X4F64_e64 ||
3367 Opc1 == AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64))
3368 NeedWaitStates = DMFMA4x4WritesVGPRFullSrcCWaitStates;
3369 else if (ST.hasGFX940Insts() &&
3370 TSchedModel.computeInstrLatency(MI1) == 2)
3371 NeedWaitStates = GFX940_SMFMA4x4WritesVGPRFullSrcCWaitStates;
3377 NeedWaitStates = std::max(NeedWaitStates,
3378 getMFMAOverlappedSrcCWaitStates(
MI, MI1));
3381 NeedWaitStates = getMFMAOverlappedSrcCWaitStates(
MI, MI1);
3385 case AMDGPU::V_MFMA_F64_16X16X4F64_e64:
3386 case AMDGPU::V_MFMA_F64_16X16X4F64_vgprcd_e64:
3387 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_e64:
3388 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_vgprcd_e64:
3391 ? GFX950_DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates
3392 : DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates;
3394 case AMDGPU::V_MFMA_F64_4X4X4F64_e64:
3395 case AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64:
3396 NeedWaitStates = DMFMA4x4WritesVGPROverlappedMFMASrcABWaitStates;
3399 int NumPasses = TSchedModel.computeInstrLatency(MI1);
3401 if (ST.hasGFX940Insts()) {
3405 NumPasses, ST.hasGFX950Insts())
3411 switch (NumPasses) {
3413 NeedWaitStates = SMFMA4x4WritesVGPROverlappedSrcABWaitStates;
3418 NeedWaitStates = SMFMA16x16WritesVGPROverlappedSrcABWaitStates;
3422 NeedWaitStates = SMFMA32x32WritesVGPROverlappedSrcABWaitStates;
3426 assert(NeedWaitStates <= MaxWaitStates &&
3427 "hazard requirement exceeds the scan window");
3428 if (WaitStatesNeeded >= NeedWaitStates)
3431 WaitStatesNeededForUse = NeedWaitStates - NumWaitStates;
3432 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3434 if (WaitStatesNeeded == MaxWaitStates)
3439 WaitStatesNeeded = std::max(WaitStatesNeeded, checkMFMAPadding(
MI));
3441 return WaitStatesNeeded;
3444int GCNHazardRecognizer::checkMAILdStHazards(
MachineInstr *
MI)
const {
3446 if (!ST.hasMAIInsts() || ST.hasGFX90AInsts())
3449 int WaitStatesNeeded = 0;
3451 auto IsAccVgprReadFn = [](
const MachineInstr &
MI) {
3452 return MI.getOpcode() == AMDGPU::V_ACCVGPR_READ_B32_e64;
3455 for (
const MachineOperand &
Op :
MI->explicit_uses()) {
3456 if (!
Op.isReg() || !TRI.isVGPR(MF.getRegInfo(),
Op.getReg()))
3461 const int AccVgprReadLdStWaitStates = 2;
3462 const int VALUWriteAccVgprRdWrLdStDepVALUWaitStates = 1;
3463 const int MaxWaitStates = 2;
3465 int WaitStatesNeededForUse = AccVgprReadLdStWaitStates -
3466 getWaitStatesSinceDef(
Reg, IsAccVgprReadFn, MaxWaitStates);
3467 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3469 if (WaitStatesNeeded == MaxWaitStates)
3470 return WaitStatesNeeded;
3472 auto IsVALUAccVgprRdWrCheckFn = [
Reg,
this](
const MachineInstr &
MI) {
3473 if (
MI.getOpcode() != AMDGPU::V_ACCVGPR_READ_B32_e64 &&
3474 MI.getOpcode() != AMDGPU::V_ACCVGPR_WRITE_B32_e64)
3476 auto IsVALUFn = [](
const MachineInstr &
MI) {
3480 return getWaitStatesSinceDef(
Reg, IsVALUFn, 2 ) <
3481 std::numeric_limits<int>::max();
3484 WaitStatesNeededForUse = VALUWriteAccVgprRdWrLdStDepVALUWaitStates -
3485 getWaitStatesSince(IsVALUAccVgprRdWrCheckFn, MaxWaitStates);
3486 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3489 return WaitStatesNeeded;
3492int GCNHazardRecognizer::checkPermlaneHazards(
MachineInstr *
MI)
const {
3493 assert(!ST.hasVcmpxPermlaneHazard() &&
3494 "this is a different vcmpx+permlane hazard");
3495 const SIRegisterInfo *TRI = ST.getRegisterInfo();
3496 const SIInstrInfo *TII = ST.getInstrInfo();
3498 auto IsVCmpXWritesExecFn = [TII, TRI](
const MachineInstr &
MI) {
3502 auto IsVALUFn = [](
const MachineInstr &
MI) {
3506 const int VCmpXWritesExecWaitStates = 4;
3507 const int VALUWritesVDstWaitStates = 2;
3508 int WaitStatesNeeded = 0;
3510 for (
const MachineOperand &
Op :
MI->explicit_uses()) {
3511 if (!
Op.isReg() || !TRI->isVGPR(MF.getRegInfo(),
Op.getReg()))
3515 int WaitStatesSinceDef =
3516 VALUWritesVDstWaitStates -
3517 getWaitStatesSinceDef(
Reg, IsVALUFn,
3518 VALUWritesVDstWaitStates);
3519 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesSinceDef);
3520 if (WaitStatesNeeded >= VALUWritesVDstWaitStates)
3524 int VCmpXHazardWaits =
3525 VCmpXWritesExecWaitStates -
3526 getWaitStatesSince(IsVCmpXWritesExecFn, VCmpXWritesExecWaitStates);
3528 WaitStatesNeeded = std::max(WaitStatesNeeded, VCmpXHazardWaits);
3529 return WaitStatesNeeded;
3537 return NumPasses + 2;
3547 return NumPasses + 3 + (NumPasses != 2 && IsGFX950);
3557 return NumPasses + 3 + (NumPasses != 2 && IsGFX950);
3565 return NumPasses + 2;
3568int GCNHazardRecognizer::checkMAIVALUHazards(
MachineInstr *
MI)
const {
3569 if (!ST.hasGFX90AInsts())
3572 auto IsDGEMMFn = [](
const MachineInstr &
MI) ->
bool {
3580 const MachineRegisterInfo &MRI = MF.getRegInfo();
3582 int WaitStatesNeeded = 0;
3588 const MachineInstr *
MFMA =
nullptr;
3590 auto IsMFMAWriteFn = [&
Reg, &
MFMA,
this](
const MachineInstr &
MI) {
3592 !TRI.regsOverlap(
MI.getOperand(0).getReg(),
Reg))
3598 const MachineInstr *
DOT =
nullptr;
3599 auto IsDotWriteFn = [&
Reg, &
DOT,
this](
const MachineInstr &
MI) {
3601 !TRI.regsOverlap(
MI.getOperand(0).getReg(),
Reg))
3607 bool DGEMMAfterVALUWrite =
false;
3608 auto IsDGEMMHazard = [&DGEMMAfterVALUWrite,
this](
const MachineInstr &
MI) {
3611 DGEMMAfterVALUWrite =
true;
3615 if (!TII.isVALU(
MI,
true) || !DGEMMAfterVALUWrite)
3621 int SrcCIdx = AMDGPU::getNamedOperandIdx(
MI->getOpcode(),
3622 AMDGPU::OpName::src2);
3624 if (IsMemOrExport || IsVALU) {
3625 const int SMFMA4x4WriteVgprVALUMemExpReadWaitStates = 5;
3626 const int SMFMA16x16WriteVgprVALUMemExpReadWaitStates = 11;
3627 const int SMFMA32x32WriteVgprVALUMemExpReadWaitStates = 19;
3628 const int DMFMA4x4WriteVgprMemExpReadWaitStates = 9;
3629 const int DMFMA16x16WriteVgprMemExpReadWaitStates = 18;
3630 const int DMFMA4x4WriteVgprVALUReadWaitStates = 6;
3631 const int DMFMA16x16WriteVgprVALUReadWaitStates = 11;
3632 const int GFX950_DMFMA16x16WriteVgprVALUReadWaitStates = 19;
3633 const int DotWriteSameDotReadSrcAB = 3;
3634 const int DotWriteDifferentVALURead = 3;
3635 const int DMFMABetweenVALUWriteVMEMRead = 2;
3636 const int MaxWaitStates =
3638 ST.hasGFX950Insts());
3640 for (
const MachineOperand &Use :
MI->explicit_uses()) {
3646 int WaitStatesSinceDef = getWaitStatesSinceDef(
Reg, IsDotWriteFn,
3649 int NeedWaitStates = 0;
3650 if (
DOT->getOpcode() ==
MI->getOpcode()) {
3651 if (&Use - &
MI->getOperand(0) != SrcCIdx)
3652 NeedWaitStates = DotWriteSameDotReadSrcAB;
3654 NeedWaitStates = DotWriteDifferentVALURead;
3657 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceDef;
3658 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3665 if (IsMem && ST.hasGFX90AInsts() && !ST.hasGFX940Insts()) {
3666 DGEMMAfterVALUWrite =
false;
3667 if (TRI.isVectorRegister(MRI,
Reg)) {
3668 int WaitStatesNeededForUse =
3669 DMFMABetweenVALUWriteVMEMRead -
3670 getWaitStatesSinceDef(
Reg, IsDGEMMHazard,
3671 DMFMABetweenVALUWriteVMEMRead);
3673 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3678 WaitStatesSinceDef =
3679 getWaitStatesSinceDef(
Reg, IsMFMAWriteFn, MaxWaitStates);
3683 unsigned HazardDefLatency = TSchedModel.computeInstrLatency(
MFMA);
3684 int NumPasses = HazardDefLatency;
3685 int NeedWaitStates = MaxWaitStates;
3688 switch (HazardDefLatency) {
3690 NeedWaitStates = IsMemOrExport ? DMFMA4x4WriteVgprMemExpReadWaitStates
3691 : DMFMA4x4WriteVgprVALUReadWaitStates;
3697 ? DMFMA16x16WriteVgprMemExpReadWaitStates
3698 : (ST.hasGFX950Insts()
3699 ? GFX950_DMFMA16x16WriteVgprVALUReadWaitStates
3700 : DMFMA16x16WriteVgprVALUReadWaitStates);
3705 }
else if (ST.hasGFX940Insts()) {
3709 NumPasses, ST.hasGFX950Insts())
3713 switch (HazardDefLatency) {
3715 NeedWaitStates = SMFMA4x4WriteVgprVALUMemExpReadWaitStates;
3718 NeedWaitStates = SMFMA16x16WriteVgprVALUMemExpReadWaitStates;
3721 NeedWaitStates = SMFMA32x32WriteVgprVALUMemExpReadWaitStates;
3728 assert(NeedWaitStates <= MaxWaitStates &&
3729 "hazard requirement exceeds the scan window");
3730 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceDef;
3731 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3733 if (WaitStatesNeeded == MaxWaitStates)
3738 unsigned Opc =
MI->getOpcode();
3739 const int DMFMAToFMA64WaitStates = 2;
3740 if ((
Opc == AMDGPU::V_FMA_F64_e64 ||
3741 Opc == AMDGPU::V_FMAC_F64_e32 ||
Opc == AMDGPU::V_FMAC_F64_e64 ||
3742 Opc == AMDGPU::V_FMAC_F64_dpp) &&
3743 WaitStatesNeeded < DMFMAToFMA64WaitStates) {
3744 int WaitStatesNeededForUse = DMFMAToFMA64WaitStates -
3745 getWaitStatesSince(IsDGEMMFn, DMFMAToFMA64WaitStates);
3746 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3749 if (!IsVALU && !IsMemOrExport)
3750 return WaitStatesNeeded;
3752 for (
const MachineOperand &Def :
MI->defs()) {
3753 const int SMFMA4x4WriteVgprVALUWawWaitStates = 5;
3754 const int SMFMA16x16WriteVgprVALUWawWaitStates = 11;
3755 const int SMFMA32x32WriteVgprVALUWawWaitStates = 19;
3756 const int SMFMA4x4ReadVgprVALUWarWaitStates = 1;
3757 const int GFX940_XDL4PassReadVgprVALUWarWaitStates = 3;
3758 const int SMFMA16x16ReadVgprVALUWarWaitStates = 7;
3759 const int SMFMA32x32ReadVgprVALUWarWaitStates = 15;
3760 const int DMFMA4x4WriteVgprVALUWriteWaitStates = 6;
3761 const int DMFMA16x16WriteVgprVALUWriteWaitStates = 11;
3762 const int DotWriteDifferentVALUWrite = 3;
3763 const int MaxWaitStates =
3765 const int MaxWarWaitStates = 15;
3770 int WaitStatesSinceDef = getWaitStatesSinceDef(
Reg, IsDotWriteFn,
3772 if (DOT &&
DOT->getOpcode() !=
MI->getOpcode())
3773 WaitStatesNeeded = std::max(WaitStatesNeeded, DotWriteDifferentVALUWrite -
3774 WaitStatesSinceDef);
3777 WaitStatesSinceDef =
3778 getWaitStatesSinceDef(
Reg, IsMFMAWriteFn, MaxWaitStates);
3780 int NeedWaitStates = MaxWaitStates;
3781 int NumPasses = TSchedModel.computeInstrLatency(
MFMA);
3784 switch (NumPasses) {
3786 NeedWaitStates = DMFMA4x4WriteVgprVALUWriteWaitStates;
3790 NeedWaitStates = DMFMA16x16WriteVgprVALUWriteWaitStates;
3795 }
else if (ST.hasGFX940Insts()) {
3799 NumPasses, ST.hasGFX950Insts())
3802 switch (NumPasses) {
3804 NeedWaitStates = SMFMA4x4WriteVgprVALUWawWaitStates;
3807 NeedWaitStates = SMFMA16x16WriteVgprVALUWawWaitStates;
3810 NeedWaitStates = SMFMA32x32WriteVgprVALUWawWaitStates;
3817 assert(NeedWaitStates <= MaxWaitStates &&
3818 "hazard requirement exceeds the scan window");
3819 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceDef;
3820 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3822 if (WaitStatesNeeded == MaxWaitStates)
3826 auto IsSMFMAReadAsCFn = [&
Reg, &
MFMA,
this](
const MachineInstr &
MI) {
3828 !
MI.readsRegister(
Reg, &TRI))
3831 if (ST.hasGFX940Insts() && !TII.isXDL(
MI))
3834 const MachineOperand *SrcC =
3835 TII.getNamedOperand(
MI, AMDGPU::OpName::src2);
3845 int WaitStatesSinceUse = getWaitStatesSince(IsSMFMAReadAsCFn,
3850 unsigned HazardDefLatency = TSchedModel.computeInstrLatency(
MFMA);
3851 int NeedWaitStates = MaxWaitStates;
3852 switch (HazardDefLatency) {
3853 case 2: NeedWaitStates = SMFMA4x4ReadVgprVALUWarWaitStates;
3855 case 4:
assert(ST.hasGFX940Insts());
3856 NeedWaitStates = GFX940_XDL4PassReadVgprVALUWarWaitStates;
3858 case 8: NeedWaitStates = SMFMA16x16ReadVgprVALUWarWaitStates;
3860 case 16: [[fallthrough]];
3861 default: NeedWaitStates = SMFMA32x32ReadVgprVALUWarWaitStates;
3865 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceUse;
3866 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3869 return WaitStatesNeeded;
3882 return MAI !=
nullptr;
3886 if (IsMFMAFn(*
MI)) {
3887 int W = getWaitStatesSince(IsMFMAFn, 16);
3889 return W < (int)TSchedModel.computeInstrLatency(MAI);
3903 while (
I->isBundledWithPred())
3909 if (
I->getOpcode() != AMDGPU::S_GETPC_B64)
3913 const unsigned NewBytes = 4;
3915 "Unexpected instruction insertion in bundle");
3918 while (NextMI != End && NextMI->isBundledWithPred()) {
3919 for (
auto &Operand : NextMI->operands()) {
3920 if (Operand.isGlobal())
3921 Operand.setOffset(Operand.getOffset() + NewBytes);
3927bool GCNHazardRecognizer::fixVALUMaskWriteHazard(
MachineInstr *
MI) {
3928 if (!ST.hasVALUMaskWriteHazard())
3930 assert(!ST.hasExtendedWaitCounts());
3937 if (!IsSALU && !IsVALU)
3949 const SIRegisterInfo *TRI = ST.getRegisterInfo();
3950 const MachineRegisterInfo &MRI = MF.getRegInfo();
3955 case AMDGPU::EXEC_LO:
3956 case AMDGPU::EXEC_HI:
3958 case AMDGPU::SGPR_NULL:
3959 case AMDGPU::SGPR_NULL64:
3967 return Reg == AMDGPU::VCC ||
Reg == AMDGPU::VCC_LO ||
Reg == AMDGPU::VCC_HI;
3971 SmallSet<Register, 2> HazardSGPRs;
3973 static unsigned getHashValue(
const StateType &State) {
3976 static bool isEqual(
const StateType &
LHS,
const StateType &
RHS) {
3977 return LHS.HazardSGPRs ==
RHS.HazardSGPRs;
3981 SmallVector<const MachineInstr *> WaitInstrs;
3982 StateType InitialState;
3985 MachineOperand *HazardDef =
nullptr;
3986 for (MachineOperand &
Op :
MI->all_defs()) {
3988 if (IgnoreableSGPR(
Reg))
3991 if (
Op.isImplicit())
3993 if (!TRI->isSGPRReg(MRI,
Reg))
4006 if (AMDGPU::SReg_32RegClass.
contains(HazardReg)) {
4007 InitialState.HazardSGPRs.insert(HazardReg);
4010 InitialState.HazardSGPRs.insert(TRI->getSubReg(HazardReg, AMDGPU::sub0));
4011 InitialState.HazardSGPRs.insert(TRI->getSubReg(HazardReg, AMDGPU::sub1));
4014 auto IsHazardFn = [&](StateType &State,
const MachineInstr &
I) {
4015 if (State.HazardSGPRs.empty())
4018 switch (
I.getOpcode()) {
4019 case AMDGPU::V_ADDC_U32_e32:
4020 case AMDGPU::V_ADDC_U32_dpp:
4021 case AMDGPU::V_CNDMASK_B16_t16_e32:
4022 case AMDGPU::V_CNDMASK_B16_fake16_e32:
4023 case AMDGPU::V_CNDMASK_B16_t16_dpp:
4024 case AMDGPU::V_CNDMASK_B16_fake16_dpp:
4025 case AMDGPU::V_CNDMASK_B32_e32:
4026 case AMDGPU::V_CNDMASK_B32_dpp:
4027 case AMDGPU::V_DIV_FMAS_F32_e64:
4028 case AMDGPU::V_DIV_FMAS_F64_e64:
4029 case AMDGPU::V_SUBB_U32_e32:
4030 case AMDGPU::V_SUBB_U32_dpp:
4031 case AMDGPU::V_SUBBREV_U32_e32:
4032 case AMDGPU::V_SUBBREV_U32_dpp: {
4036 case AMDGPU::V_ADDC_U32_e64:
4037 case AMDGPU::V_ADDC_U32_e64_dpp:
4038 case AMDGPU::V_CNDMASK_B16_t16_e64:
4039 case AMDGPU::V_CNDMASK_B16_fake16_e64:
4040 case AMDGPU::V_CNDMASK_B16_t16_e64_dpp:
4041 case AMDGPU::V_CNDMASK_B16_fake16_e64_dpp:
4042 case AMDGPU::V_CNDMASK_B32_e64:
4043 case AMDGPU::V_CNDMASK_B32_e64_dpp:
4044 case AMDGPU::V_SUBB_U32_e64:
4045 case AMDGPU::V_SUBB_U32_e64_dpp:
4046 case AMDGPU::V_SUBBREV_U32_e64:
4047 case AMDGPU::V_SUBBREV_U32_e64_dpp: {
4049 const MachineOperand *SSRCOp = TII.getNamedOperand(
I, AMDGPU::OpName::src2);
4051 bool Result = TRI->regsOverlap(SSRCOp->
getReg(), HazardReg);
4059 auto UpdateStateFn = [&](StateType &State,
const MachineInstr &
I) {
4061 for (
auto &
Op :
I.all_defs()) {
4063 if (IgnoreableSGPR(
Reg))
4066 if (
Op.isImplicit())
4068 if (!TRI->isSGPRReg(MRI,
Reg))
4075 for (
Register SGPR : State.HazardSGPRs) {
4076 if (
Reg == SGPR || TRI->regsOverlap(
Reg, SGPR))
4080 State.HazardSGPRs.erase(SGPR);
4087 std::next(
MI->getReverseIterator())))
4097 auto NextMI = std::next(
MI->getIterator());
4098 auto NewMI =
BuildMI(*
MI->getParent(), NextMI,
MI->getDebugLoc(),
4099 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
4111 if (EntryMBB.
begin() != EntryMBB.
end()) {
4112 auto &EntryMI = *EntryMBB.
begin();
4113 if (EntryMI.getOpcode() == AMDGPU::S_SETPRIO &&
4114 EntryMI.getOperand(0).getImm() >= Priority)
4123bool GCNHazardRecognizer::fixRequiredExportPriority(
MachineInstr *
MI) {
4124 if (!ST.hasRequiredExportPriority())
4142 const int MaxPriority = 3;
4143 const int NormalPriority = 2;
4144 const int PostExportPriority = 0;
4146 auto It =
MI->getIterator();
4147 switch (
MI->getOpcode()) {
4148 case AMDGPU::S_ENDPGM:
4149 case AMDGPU::S_ENDPGM_SAVED:
4150 case AMDGPU::S_ENDPGM_ORDERED_PS_DONE:
4151 case AMDGPU::SI_RETURN_TO_EPILOG:
4154 if (MF->getFrameInfo().hasCalls())
4157 case AMDGPU::S_SETPRIO: {
4159 auto &PrioOp =
MI->getOperand(0);
4160 int Prio = PrioOp.getImm();
4161 bool InWA = (Prio == PostExportPriority) &&
4162 (It !=
MBB->
begin() && TII.isEXP(*std::prev(It)));
4163 if (InWA || Prio >= NormalPriority)
4165 PrioOp.setImm(std::min(Prio + NormalPriority, MaxPriority));
4169 if (!TII.isEXP(*
MI))
4180 auto NextMI = std::next(It);
4181 bool EndOfShader =
false;
4182 if (NextMI !=
MBB->
end()) {
4184 if (TII.isEXP(*NextMI))
4187 if (NextMI->getOpcode() == AMDGPU::S_SETPRIO &&
4188 NextMI->getOperand(0).getImm() == PostExportPriority)
4190 EndOfShader = NextMI->getOpcode() == AMDGPU::S_ENDPGM;
4197 .
addImm(PostExportPriority);
4201 BuildMI(*
MBB, NextMI,
DL, TII.get(AMDGPU::S_WAITCNT_EXPCNT))
4202 .
addReg(AMDGPU::SGPR_NULL)
4224 while (
I != End &&
I->isMetaInstruction())
4233 assert(ST.hasRequiresInitialUnclausedVmem() &&
4234 "V_PERM_PK16-hazard subtarget must provide the unclaused-VMEM entry "
4235 "prologue to satisfy the cross-wave entry mitigation");
4246 if (NextI !=
MBB->
end() && TII.isVPermPk16SafeInstr(*NextI))
4252 BuildMI(*
MBB, NextI,
MI->getDebugLoc(), TII.get(AMDGPU::V_NOP_e32));
4260 const SIInstrInfo *TII = ST.getInstrInfo();
4272 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4277bool GCNHazardRecognizer::fixDsAtomicAsyncBarrierArriveB64(
MachineInstr *
MI) {
4278 if (
MI->getOpcode() != AMDGPU::DS_ATOMIC_ASYNC_BARRIER_ARRIVE_B64)
4281 const SIInstrInfo *TII = ST.getInstrInfo();
4283 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4285 BuildMI(*
MI->getParent(), std::next(
MI->getIterator()),
MI->getDebugLoc(),
4286 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4292bool GCNHazardRecognizer::fixScratchBaseForwardingHazard(
MachineInstr *
MI) {
4298 const SIRegisterInfo *TRI = ST.getRegisterInfo();
4299 const SIInstrInfo *TII = ST.getInstrInfo();
4301 const int FlatScrBaseWaitStates = 10;
4303 bool ReadsFlatScrLo =
4305 bool ReadsFlatScrHi =
4306 MI->readsRegister(AMDGPU::SRC_FLAT_SCRATCH_BASE_HI, TRI);
4312 ReadsFlatScrLo =
true;
4315 ReadsFlatScrHi =
true;
4320 const MachineRegisterInfo &MRI = MF.getRegInfo();
4323 DenseSet<const MachineBasicBlock *> Visited;
4325 return MI.modifiesRegister(
Reg, TRI);
4330 auto IsSGPRDef = [TII, TRI, &MRI](
const MachineInstr &
MI) ->
unsigned {
4331 if (!TII->isSALU(
MI) && !TII->isVALU(
MI,
true))
4333 for (
const MachineOperand &MO :
MI.all_defs()) {
4334 if (TRI->isSGPRReg(MRI, MO.getReg()))
4340 auto IsExpiredFn = [=](
const MachineInstr &
MI,
int SgprWrites) {
4341 if (
MI.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR) {
4342 unsigned Wait =
MI.getOperand(0).getImm();
4347 return SgprWrites >= FlatScrBaseWaitStates;
4350 return ::getWaitStatesSince(
4351 IsHazardFn,
MI->getParent(), std::next(
MI->getReverseIterator()),
4352 0,
IsExpiredFn, Visited, IsSGPRDef) < FlatScrBaseWaitStates;
4356 !IsRegDefHazard(AMDGPU::SGPR102)) &&
4358 !IsRegDefHazard(AMDGPU::SGPR103)))
4362 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4373 BuildMI(*
MI->getParent(),
MI,
MI->getDebugLoc(), TII.get(AMDGPU::V_NOP_e32));
4374 BuildMI(*
MI->getParent(),
MI,
MI->getDebugLoc(), TII.get(AMDGPU::V_NOP_e32));
4379 auto IsTDM = [&](
const MachineInstr &
MI) ->
bool {
4381 MI.getOpcode() != AMDGPU::S_WAIT_TENSORCNT;
4388 if (
MI.getOpcode() != AMDGPU::S_WAIT_TENSORCNT)
4390 return MI.getOperand(0).getImm() <= 10;
4394 std::numeric_limits<int>::max())
4398 TII.get(AMDGPU::S_WAIT_TENSORCNT))
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU Rewrite AGPR Copy MFMA
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< 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 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 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.
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 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 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(uint64_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...
constexpr 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)
NodeAddr< DefNode * > Def
NodeAddr< UseNode * > Use
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
@ Kill
The last use of a register.
@ Undef
Value of the register doesn't matter.
@ Define
Register definition.
constexpr RegState getDeadRegState(bool B)
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
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
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Next
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
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...