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.requiresWaitIdleBeforeGetReg())
1778 fixGetRegWaitIdle(
MI);
1779 if (ST.hasDsAtomicAsyncBarrierArriveB64PipeBug())
1780 fixDsAtomicAsyncBarrierArriveB64(
MI);
1781 if (ST.hasScratchBaseForwardingHazard())
1782 fixScratchBaseForwardingHazard(
MI);
1783 if (ST.setRegModeNeedsVNOPs())
1785 if (ST.hasNeedsTDMDrain())
1791 return (
TII.isVOPC(
MI) ||
1792 (
MI.isCompare() && (
TII.isVOP3(
MI) ||
TII.isSDWA(
MI)))) &&
1793 MI.modifiesRegister(AMDGPU::EXEC, &
TRI);
1796bool GCNHazardRecognizer::fixVcmpxPermlaneHazards(
MachineInstr *
MI) {
1800 const SIInstrInfo *TII = ST.getInstrInfo();
1801 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1807 unsigned Opc =
MI.getOpcode();
1809 Opc != AMDGPU::V_NOP_e32 &&
Opc != AMDGPU::V_NOP_e64 &&
1810 Opc != AMDGPU::V_NOP_sdwa;
1814 std::numeric_limits<int>::max())
1820 auto *Src0 = TII->getNamedOperand(*
MI, AMDGPU::OpName::src0);
1822 bool IsUndef = Src0->isUndef();
1824 TII->get(AMDGPU::V_MOV_B32_e32))
1831bool GCNHazardRecognizer::fixVMEMtoScalarWriteHazards(
MachineInstr *
MI) {
1832 if (!ST.hasVMEMtoScalarWriteHazard())
1834 assert(!ST.hasExtendedWaitCounts());
1839 if (
MI->getNumDefs() == 0)
1842 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1848 for (
const MachineOperand &Def :
MI->defs()) {
1849 const MachineOperand *
Op =
1850 I.findRegisterUseOperand(
Def.getReg(), TRI,
false);
1860 (
MI.getOpcode() == AMDGPU::S_WAITCNT &&
1861 !
MI.getOperand(0).getImm()) ||
1862 (
MI.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
1867 std::numeric_limits<int>::max())
1870 const SIInstrInfo *TII = ST.getInstrInfo();
1872 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
1877bool GCNHazardRecognizer::fixSMEMtoVectorWriteHazards(
MachineInstr *
MI) {
1878 if (!ST.hasSMEMtoVectorWriteHazard())
1880 assert(!ST.hasExtendedWaitCounts());
1885 AMDGPU::OpName SDSTName;
1886 switch (
MI->getOpcode()) {
1887 case AMDGPU::V_READLANE_B32:
1888 case AMDGPU::V_READFIRSTLANE_B32:
1889 SDSTName = AMDGPU::OpName::vdst;
1892 SDSTName = AMDGPU::OpName::sdst;
1896 const SIInstrInfo *TII = ST.getInstrInfo();
1897 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1899 const MachineOperand *SDST = TII->getNamedOperand(*
MI, SDSTName);
1901 for (
const auto &MO :
MI->implicit_operands()) {
1902 if (MO.isDef() && TRI->isSGPRClass(TRI->getPhysRegBaseClass(MO.getReg()))) {
1913 auto IsHazardFn = [SDSTReg, TRI](
const MachineInstr &
I) {
1918 if (TII->isSALU(
MI)) {
1919 switch (
MI.getOpcode()) {
1920 case AMDGPU::S_SETVSKIP:
1921 case AMDGPU::S_VERSION:
1922 case AMDGPU::S_WAITCNT_VSCNT:
1923 case AMDGPU::S_WAITCNT_VMCNT:
1924 case AMDGPU::S_WAITCNT_EXPCNT:
1927 case AMDGPU::S_WAITCNT_LGKMCNT:
1929 return (
MI.getOperand(1).getImm() == 0) &&
1930 (
MI.getOperand(0).
getReg() == AMDGPU::SGPR_NULL);
1931 case AMDGPU::S_WAITCNT: {
1932 const int64_t
Imm =
MI.getOperand(0).getImm();
1939 MI.getOpcode() == AMDGPU::S_WAIT_IDLE) &&
1940 "unexpected wait count instruction");
1942 if (TII->isSOPP(
MI))
1958 std::numeric_limits<int>::max())
1962 TII->get(AMDGPU::S_MOV_B32), AMDGPU::SGPR_NULL)
1967bool GCNHazardRecognizer::fixVcmpxExecWARHazard(
MachineInstr *
MI) {
1968 if (!ST.hasVcmpxExecWARHazard())
1970 assert(!ST.hasExtendedWaitCounts());
1975 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1976 if (!
MI->modifiesRegister(AMDGPU::EXEC, TRI))
1982 return I.readsRegister(AMDGPU::EXEC, TRI);
1985 const SIInstrInfo *TII = ST.getInstrInfo();
1986 auto IsExpiredFn = [TII, TRI](
const MachineInstr &
MI, int) {
1988 if (TII->getNamedOperand(
MI, AMDGPU::OpName::sdst))
1990 for (
auto MO :
MI.implicit_operands())
1991 if (MO.isDef() && TRI->isSGPRClass(TRI->getPhysRegBaseClass(MO.getReg())))
1994 if (
MI.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2001 std::numeric_limits<int>::max())
2005 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
2012 if (!ST.hasLdsBranchVmemWARHazard())
2017 bool HasLds =
false;
2018 bool HasVmem =
false;
2019 for (
auto &
MBB : MF) {
2020 for (
auto &
MI :
MBB) {
2023 if (HasLds && HasVmem)
2031 return I.getOpcode() == AMDGPU::S_WAITCNT_VSCNT &&
2032 I.getOperand(0).getReg() == AMDGPU::SGPR_NULL &&
2033 !
I.getOperand(1).getImm();
2036bool GCNHazardRecognizer::fixLdsBranchVmemWARHazard(
MachineInstr *
MI) {
2037 if (!RunLdsBranchVmemWARHazardFixup)
2040 assert(ST.hasLdsBranchVmemWARHazard());
2041 assert(!ST.hasExtendedWaitCounts());
2043 auto IsHazardInst = [](
const MachineInstr &
MI) {
2051 auto InstType = IsHazardInst(*
MI);
2055 auto IsExpiredFn = [&IsHazardInst](
const MachineInstr &
I, int) {
2059 auto IsHazardFn = [InstType, &IsHazardInst](
const MachineInstr &
I) {
2063 auto IsHazardFn = [InstType, IsHazardInst](
const MachineInstr &
I) {
2064 auto InstType2 = IsHazardInst(
I);
2065 return InstType2 && InstType != InstType2;
2068 auto IsExpiredFn = [InstType, &IsHazardInst](
const MachineInstr &
I, int) {
2069 auto InstType2 = IsHazardInst(
I);
2070 if (InstType == InstType2)
2077 std::numeric_limits<int>::max();
2081 std::numeric_limits<int>::max())
2084 const SIInstrInfo *TII = ST.getInstrInfo();
2086 TII->get(AMDGPU::S_WAITCNT_VSCNT))
2093bool GCNHazardRecognizer::fixLdsDirectVALUHazard(
MachineInstr *
MI) {
2097 const int NoHazardWaitStates = 15;
2098 const MachineOperand *VDST = TII.getNamedOperand(*
MI, AMDGPU::OpName::vdst);
2101 bool VisitedTrans =
false;
2102 auto IsHazardFn = [
this, VDSTReg, &VisitedTrans](
const MachineInstr &
I) {
2107 return I.readsRegister(VDSTReg, &TRI) ||
I.modifiesRegister(VDSTReg, &TRI);
2109 auto IsExpiredFn = [&](
const MachineInstr &
I,
int WaitStates) {
2110 if (WaitStates >= NoHazardWaitStates)
2116 auto GetWaitStatesFn = [](
const MachineInstr &
MI) {
2120 DenseSet<const MachineBasicBlock *> Visited;
2122 std::next(
MI->getReverseIterator()), 0,
2130 MachineOperand *WaitVdstOp =
2131 TII.getNamedOperand(*
MI, AMDGPU::OpName::waitvdst);
2132 WaitVdstOp->
setImm(std::min(
Count, NoHazardWaitStates));
2137bool GCNHazardRecognizer::fixLdsDirectVMEMHazard(
MachineInstr *
MI) {
2141 const MachineOperand *VDST = TII.getNamedOperand(*
MI, AMDGPU::OpName::vdst);
2144 auto IsHazardFn = [
this, VDSTReg](
const MachineInstr &
I) {
2147 return I.readsRegister(VDSTReg, &TRI) ||
I.modifiesRegister(VDSTReg, &TRI);
2149 bool LdsdirCanWait = ST.hasLdsWaitVMSRC();
2152 auto IsExpiredFn = [
this, LdsdirCanWait](
const MachineInstr &
I, int) {
2155 (
I.getOpcode() == AMDGPU::S_WAITCNT && !
I.getOperand(0).getImm()) ||
2156 (
I.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2159 !TII.getNamedOperand(
I, AMDGPU::OpName::waitvsrc)->getImm());
2163 std::numeric_limits<int>::max())
2166 if (LdsdirCanWait) {
2167 TII.getNamedOperand(*
MI, AMDGPU::OpName::waitvsrc)->setImm(0);
2170 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
2177bool GCNHazardRecognizer::fixVALUPartialForwardingHazard(
MachineInstr *
MI) {
2178 if (!ST.hasVALUPartialForwardingHazard())
2180 assert(!ST.hasExtendedWaitCounts());
2185 SmallSetVector<Register, 4> SrcVGPRs;
2187 for (
const MachineOperand &Use :
MI->explicit_uses()) {
2188 if (
Use.isReg() && TRI.isVGPR(MF.getRegInfo(),
Use.getReg()))
2193 if (SrcVGPRs.
size() <= 1)
2211 const int Intv1plus2MaxVALUs = 2;
2212 const int Intv3MaxVALUs = 4;
2213 const int IntvMaxVALUs = 6;
2214 const int NoHazardVALUWaitStates = IntvMaxVALUs + 2;
2217 SmallDenseMap<Register, int, 4> DefPos;
2218 int ExecPos = std::numeric_limits<int>::max();
2221 static unsigned getHashValue(
const StateType &State) {
2223 for (
const auto &[
Reg, Pos] : State.DefPos)
2227 static bool isEqual(
const StateType &
LHS,
const StateType &
RHS) {
2228 return LHS.DefPos ==
RHS.DefPos &&
LHS.ExecPos ==
RHS.ExecPos &&
2236 auto IsHazardFn = [&,
this](StateType &State,
const MachineInstr &
I) {
2238 if (State.VALUs > NoHazardVALUWaitStates)
2244 (
I.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2252 if (!State.DefPos.count(Src) &&
I.modifiesRegister(Src, &TRI)) {
2253 State.DefPos[Src] = State.VALUs;
2258 if (State.ExecPos == std::numeric_limits<int>::max()) {
2259 if (!State.DefPos.empty() &&
I.modifiesRegister(AMDGPU::EXEC, &TRI)) {
2260 State.ExecPos = State.VALUs;
2267 if (State.VALUs > Intv3MaxVALUs && State.DefPos.empty())
2275 if (State.ExecPos == std::numeric_limits<int>::max())
2278 int PreExecPos = std::numeric_limits<int>::max();
2279 int PostExecPos = std::numeric_limits<int>::max();
2281 for (
auto Entry : State.DefPos) {
2282 int DefVALUs =
Entry.second;
2283 if (DefVALUs != std::numeric_limits<int>::max()) {
2284 if (DefVALUs >= State.ExecPos)
2285 PreExecPos = std::min(PreExecPos, DefVALUs);
2287 PostExecPos = std::min(PostExecPos, DefVALUs);
2292 if (PostExecPos == std::numeric_limits<int>::max())
2296 int Intv3VALUs = PostExecPos;
2297 if (Intv3VALUs > Intv3MaxVALUs)
2301 int Intv2VALUs = (State.ExecPos - PostExecPos) - 1;
2302 if (Intv2VALUs > Intv1plus2MaxVALUs)
2306 if (PreExecPos == std::numeric_limits<int>::max())
2310 int Intv1VALUs = PreExecPos - State.ExecPos;
2311 if (Intv1VALUs > Intv1plus2MaxVALUs)
2315 if (Intv1VALUs + Intv2VALUs > Intv1plus2MaxVALUs)
2320 auto UpdateStateFn = [](StateType &State,
const MachineInstr &
MI) {
2326 std::next(
MI->getReverseIterator())))
2330 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
2336bool GCNHazardRecognizer::fixVALUTransUseHazard(
MachineInstr *
MI) {
2337 if (!ST.hasVALUTransUseHazard())
2339 assert(!ST.hasExtendedWaitCounts());
2344 SmallSet<Register, 4> SrcVGPRs;
2346 for (
const MachineOperand &Use :
MI->explicit_uses()) {
2347 if (
Use.isReg() && TRI.isVGPR(MF.getRegInfo(),
Use.getReg()))
2361 const int IntvMaxVALUs = 5;
2362 const int IntvMaxTRANS = 1;
2368 static unsigned getHashValue(
const StateType &State) {
2371 static bool isEqual(
const StateType &
LHS,
const StateType &
RHS) {
2372 return LHS.VALUs ==
RHS.VALUs &&
LHS.TRANS ==
RHS.TRANS;
2379 auto IsHazardFn = [&,
this](StateType &State,
const MachineInstr &
I) {
2381 if (State.VALUs > IntvMaxVALUs || State.TRANS > IntvMaxTRANS)
2387 (
I.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2394 if (
I.modifiesRegister(Src, &TRI)) {
2402 auto UpdateStateFn = [](StateType &State,
const MachineInstr &
MI) {
2410 std::next(
MI->getReverseIterator())))
2416 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
2422bool GCNHazardRecognizer::fixVALUTransCoexecutionHazards(
MachineInstr *
MI) {
2423 if (!ST.hasTransCoexecutionHazard() ||
2428 const SIInstrInfo *TII = ST.getInstrInfo();
2429 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2431 auto IsTransHazardFn = [
MI, TII, TRI](
const MachineInstr &
I) {
2436 Register TransDef = TII->getNamedOperand(
I, AMDGPU::OpName::vdst)->getReg();
2437 for (
const MachineOperand &ValuUse :
MI->explicit_uses()) {
2438 if (ValuUse.isReg() && TRI->regsOverlap(TransDef, ValuUse.getReg()))
2442 auto *ValuDst = TII->getNamedOperand(*
MI, AMDGPU::OpName::vdst);
2443 if (!ValuDst || !ValuDst->isReg())
2447 Register ValuDef = ValuDst->getReg();
2448 for (
const MachineOperand &TransUse :
I.explicit_uses()) {
2449 if (TransUse.isReg() && TRI->regsOverlap(ValuDef, TransUse.getReg()))
2460 const int HasVALU = std::numeric_limits<int>::max();
2461 if (::getWaitStatesSince(IsTransHazardFn,
MI,
IsExpiredFn) == HasVALU)
2464 BuildMI(*
MI->getParent(),
MI,
MI->getDebugLoc(), TII->get(AMDGPU::V_NOP_e32));
2472 const SIInstrInfo *TII = ST.getInstrInfo();
2473 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2475 auto IsHazardFn = [
MI, TII, TRI,
this](
const MachineInstr &
I) {
2482 TII->getNamedOperand(*
MI, AMDGPU::OpName::src0)->getReg();
2484 TII->getNamedOperand(*
MI, AMDGPU::OpName::src1)->getReg();
2487 TII->getNamedOperand(
I, AMDGPU::OpName::vdst)->getReg();
2489 if (TRI->regsOverlap(PrevDstReg, CurSrc0Reg) ||
2490 TRI->regsOverlap(PrevDstReg, CurSrc1Reg)) {
2499 TII->getNamedOperand(*
MI, AMDGPU::OpName::src2)->getReg();
2500 if (TRI->regsOverlap(PrevDstReg, CurIndex))
2514 std::numeric_limits<int>::max())
2517 BuildMI(*
MI->getParent(),
MI,
MI->getDebugLoc(), TII->get(AMDGPU::V_NOP_e32));
2571 bool IsLowestRateWMMA = ST.hasGFX125xLowestRateWMMA();
2572 unsigned Category = 0;
2574 unsigned Latency = SchedModel.computeInstrLatency(&
MI);
2579 assert(!IsSWMMAC &&
"no 4-cycle SWMMAC expected");
2583 Category = IsSWMMAC ? 2 : 0;
2586 Category = IsLowestRateWMMA ? 4 : (IsSWMMAC ? 3 : 1);
2589 assert(IsLowestRateWMMA &&
"latency 32 is not expected");
2599int GCNHazardRecognizer::checkWMMACoexecutionHazards(
MachineInstr *
MI)
const {
2600 if (!ST.hasWMMACoexecutionHazards())
2603 const SIInstrInfo *TII = ST.getInstrInfo();
2612 const int WMMAWaitStates[] = {5, 9, 3, 5, 9, 17, 2};
2613 const int VALUWaitStates[] = {4, 8, 2, 4, 8, 16, 1};
2614 unsigned Category = 0;
2616 auto IsWMMAHazardFn = [
MI, TII, &Category,
this](
const MachineInstr &
I) {
2617 if (!TII->isXDLWMMA(
I))
2621 return hasWMMAToWMMARegOverlap(
I, *
MI);
2624 auto IsVALUHazardFn = [
MI, TII, &Category,
this](
const MachineInstr &
I) {
2625 if (!TII->isXDLWMMA(
I))
2629 return hasWMMAToVALURegOverlap(
I, *
MI);
2632 int WaitStatesNeeded = -1;
2633 int ExistingVALUs = 0;
2634 bool IsLowestRateWMMA = ST.hasGFX125xLowestRateWMMA();
2642 if (TII->isXDLWMMA(*
MI)) {
2644 const int WMMAWaitsLimit = IsLowestRateWMMA ? 17 : 9;
2645 ExistingVALUs = getWaitStatesSinceVALU(IsWMMAHazardFn, WMMAWaitsLimit);
2646 WaitStatesNeeded = WMMAWaitStates[Category] - ExistingVALUs;
2649 const int VALUWaitsLimit = IsLowestRateWMMA ? 16 : 8;
2650 ExistingVALUs = getWaitStatesSinceVALU(IsVALUHazardFn, VALUWaitsLimit);
2651 WaitStatesNeeded = VALUWaitStates[Category] - ExistingVALUs;
2654 return WaitStatesNeeded;
2657bool GCNHazardRecognizer::hasWMMAToWMMARegOverlap(
2659 Register D0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::vdst)->getReg();
2660 Register A1 = TII.getNamedOperand(
MI, AMDGPU::OpName::src0)->getReg();
2661 Register B1 = TII.getNamedOperand(
MI, AMDGPU::OpName::src1)->getReg();
2664 if (TRI.regsOverlap(D0, A1) || TRI.regsOverlap(D0, B1))
2668 Register Idx1 = TII.getNamedOperand(
MI, AMDGPU::OpName::src2)->getReg();
2669 if (TRI.regsOverlap(D0, Idx1))
2675bool GCNHazardRecognizer::hasWMMAToVALURegOverlap(
2678 Register D0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::vdst)->getReg();
2679 for (
const MachineOperand &ValuUse :
MI.explicit_uses()) {
2680 if (ValuUse.isReg() && TRI.regsOverlap(D0, ValuUse.getReg()))
2685 Register A0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::src0)->getReg();
2686 Register B0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::src1)->getReg();
2690 Register Idx0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::src2)->getReg();
2691 WMMARegs.push_back(Idx0);
2694 for (
const MachineOperand &ValuDef :
MI.defs()) {
2695 Register VDstReg = ValuDef.getReg();
2696 for (
Register WMMAReg : WMMARegs) {
2697 if (TRI.regsOverlap(VDstReg, WMMAReg))
2704bool GCNHazardRecognizer::isCoexecutionHazardFor(
const MachineInstr &
I,
2708 if (!TII.isXDLWMMA(
I))
2712 if (TII.isXDLWMMA(
MI))
2713 return hasWMMAToWMMARegOverlap(
I,
MI);
2715 return hasWMMAToVALURegOverlap(
I,
MI);
2721 bool IncludeSubloops) {
2724 for (MachineBasicBlock *
MBB :
L->getBlocks()) {
2725 if (!IncludeSubloops && MLI->getLoopFor(
MBB) != L)
2727 for (MachineInstr &
I : *
MBB) {
2730 if (isCoexecutionHazardFor(
I, *
MI))
2737bool GCNHazardRecognizer::tryHoistWMMAVnopsFromLoop(
MachineInstr *
MI,
2738 int WaitStatesNeeded) {
2742 MachineLoop *
L = MLI->getLoopFor(
MI->getParent());
2744 ++NumWMMAHoistingBailed;
2749 if (hasWMMAHazardInLoop(L,
MI)) {
2750 ++NumWMMAHoistingBailed;
2755 MachineLoop *TargetLoop =
L;
2757 if (hasWMMAHazardInLoop(Parent,
MI,
false))
2759 TargetLoop = Parent;
2765 ++NumWMMAHoistingBailed;
2769 LLVM_DEBUG(
dbgs() <<
"WMMA V_NOP Hoisting: Moving " << WaitStatesNeeded
2775 NumWMMANopsHoisted += WaitStatesNeeded;
2779bool GCNHazardRecognizer::fixWMMACoexecutionHazards(
MachineInstr *
MI) {
2780 int WaitStatesNeeded = checkWMMACoexecutionHazards(
MI);
2781 if (WaitStatesNeeded <= 0)
2787 emitVNops(*
MI->getParent(),
MI->getIterator(), WaitStatesNeeded);
2791bool GCNHazardRecognizer::fixShift64HighRegBug(
MachineInstr *
MI) {
2792 if (!ST.hasShift64HighRegBug())
2794 assert(!ST.hasExtendedWaitCounts());
2796 switch (
MI->getOpcode()) {
2799 case AMDGPU::V_LSHLREV_B64_e64:
2800 case AMDGPU::V_LSHRREV_B64_e64:
2801 case AMDGPU::V_ASHRREV_I64_e64:
2805 MachineOperand *Amt = TII.getNamedOperand(*
MI, AMDGPU::OpName::src0);
2810 const MachineRegisterInfo &MRI = MF.getRegInfo();
2812 if (!TRI.isVGPR(MRI, AmtReg) || ((AmtReg - AMDGPU::VGPR0) & 7) != 7)
2815 if (AmtReg != AMDGPU::VGPR255 && MRI.
isPhysRegUsed(AmtReg + 1))
2818 assert(ST.needsAlignedVGPRs());
2819 static_assert(AMDGPU::VGPR0 + 1 == AMDGPU::VGPR1);
2823 MachineOperand *Src1 = TII.getNamedOperand(*
MI, AMDGPU::OpName::src1);
2834 Register DstReg =
MI->getOperand(0).getReg();
2836 Register DstLo = TRI.getSubReg(DstReg, AMDGPU::sub0);
2844 bool Overlapped =
MI->modifiesRegister(AmtReg, &TRI);
2846 for (MCRegister
Reg : Overlapped ? AMDGPU::VReg_64_Align2RegClass
2847 : AMDGPU::VGPR_32RegClass) {
2848 if (!
MI->modifiesRegister(
Reg, &TRI) && !
MI->readsRegister(
Reg, &TRI)) {
2854 Register NewAmt = Overlapped ? (
Register)TRI.getSubReg(NewReg, AMDGPU::sub1)
2859 NewAmtLo = TRI.getSubReg(NewReg, AMDGPU::sub0);
2872 runOnInstruction(
BuildMI(*
MBB,
MI,
DL, TII.get(AMDGPU::V_SWAP_B32), NewAmt)
2879 BuildMI(*
MBB, std::next(
MI->getIterator()),
DL, TII.get(AMDGPU::V_SWAP_B32),
2885 BuildMI(*
MBB, std::next(
MI->getIterator()),
DL, TII.get(AMDGPU::V_SWAP_B32),
2899 MI->getOperand(0).setReg(NewReg);
2908int GCNHazardRecognizer::checkNSAtoVMEMHazard(
MachineInstr *
MI)
const {
2909 int NSAtoVMEMWaitStates = 1;
2911 if (!ST.hasNSAtoVMEMBug())
2917 const SIInstrInfo *TII = ST.getInstrInfo();
2918 const auto *
Offset = TII->getNamedOperand(*
MI, AMDGPU::OpName::offset);
2926 return Info->MIMGEncoding == AMDGPU::MIMGEncGfx10NSA &&
2927 TII->getInstSizeInBytes(
I) >= 16;
2930 return NSAtoVMEMWaitStates - getWaitStatesSince(
IsHazardFn, 1);
2933int GCNHazardRecognizer::checkFPAtomicToDenormModeHazard(
2935 int FPAtomicToDenormModeWaitStates = 3;
2937 if (!ST.hasFPAtomicToDenormModeHazard())
2939 assert(!ST.hasExtendedWaitCounts());
2941 if (
MI->getOpcode() != AMDGPU::S_DENORM_MODE)
2950 auto IsExpiredFn = [](
const MachineInstr &
MI,
int WaitStates) {
2957 return FPAtomicToDenormModeWaitStates -
2961int GCNHazardRecognizer::checkMAIHazards(
MachineInstr *
MI)
const {
2964 return ST.hasGFX90AInsts() ? checkMAIHazards90A(
MI) : checkMAIHazards908(
MI);
2967int GCNHazardRecognizer::checkMFMAPadding(
MachineInstr *
MI)
const {
2972 const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
2976 int NeighborMFMALatency = 0;
2977 auto IsNeighboringMFMA = [&NeighborMFMALatency,
2978 this](
const MachineInstr &
MI) {
2982 NeighborMFMALatency = this->getMFMAPipelineWaitStates(
MI);
2986 const int MaxMFMAPipelineWaitStates = 16;
2987 int WaitStatesSinceNeighborMFMA =
2988 getWaitStatesSince(IsNeighboringMFMA, MaxMFMAPipelineWaitStates);
2990 int NeighborMFMAPaddingNeeded =
2992 WaitStatesSinceNeighborMFMA;
2994 return std::max(0, NeighborMFMAPaddingNeeded);
2997int GCNHazardRecognizer::checkMAIHazards908(
MachineInstr *
MI)
const {
2998 int WaitStatesNeeded = 0;
2999 unsigned Opc =
MI->getOpcode();
3001 auto IsVALUFn = [](
const MachineInstr &
MI) {
3005 if (
Opc != AMDGPU::V_ACCVGPR_READ_B32_e64) {
3006 const int LegacyVALUWritesVGPRWaitStates = 2;
3007 const int VALUWritesExecWaitStates = 4;
3008 const int MaxWaitStates = 4;
3010 int WaitStatesNeededForUse = VALUWritesExecWaitStates -
3011 getWaitStatesSinceDef(AMDGPU::EXEC, IsVALUFn, MaxWaitStates);
3012 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3014 if (WaitStatesNeeded < MaxWaitStates) {
3015 for (
const MachineOperand &Use :
MI->explicit_uses()) {
3016 const int MaxWaitStates = 2;
3018 if (!
Use.isReg() || !TRI.isVGPR(MF.getRegInfo(),
Use.getReg()))
3021 int WaitStatesNeededForUse = LegacyVALUWritesVGPRWaitStates -
3022 getWaitStatesSinceDef(
Use.getReg(), IsVALUFn, MaxWaitStates);
3023 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3025 if (WaitStatesNeeded == MaxWaitStates)
3031 for (
const MachineOperand &
Op :
MI->explicit_operands()) {
3032 if (!
Op.isReg() || !TRI.isAGPR(MF.getRegInfo(),
Op.getReg()))
3035 if (
Op.isDef() &&
Opc != AMDGPU::V_ACCVGPR_WRITE_B32_e64)
3038 const int MFMAWritesAGPROverlappedSrcABWaitStates = 4;
3039 const int MFMAWritesAGPROverlappedSrcCWaitStates = 2;
3040 const int MFMA4x4WritesAGPRAccVgprReadWaitStates = 4;
3041 const int MFMA16x16WritesAGPRAccVgprReadWaitStates = 10;
3042 const int MFMA32x32WritesAGPRAccVgprReadWaitStates = 18;
3043 const int MFMA4x4WritesAGPRAccVgprWriteWaitStates = 1;
3044 const int MFMA16x16WritesAGPRAccVgprWriteWaitStates = 7;
3045 const int MFMA32x32WritesAGPRAccVgprWriteWaitStates = 15;
3046 const int MaxWaitStates = 18;
3048 unsigned HazardDefLatency = 0;
3050 auto IsOverlappedMFMAFn = [
Reg, &HazardDefLatency,
3051 this](
const MachineInstr &
MI) {
3058 std::max(HazardDefLatency, TSchedModel.computeInstrLatency(&
MI));
3059 return TRI.regsOverlap(DstReg,
Reg);
3062 int WaitStatesSinceDef = getWaitStatesSinceDef(
Reg, IsOverlappedMFMAFn,
3064 int NeedWaitStates = MFMAWritesAGPROverlappedSrcABWaitStates;
3065 int SrcCIdx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src2);
3066 int OpNo =
Op.getOperandNo();
3067 if (OpNo == SrcCIdx) {
3068 NeedWaitStates = MFMAWritesAGPROverlappedSrcCWaitStates;
3069 }
else if (
Opc == AMDGPU::V_ACCVGPR_READ_B32_e64) {
3070 switch (HazardDefLatency) {
3071 case 2: NeedWaitStates = MFMA4x4WritesAGPRAccVgprReadWaitStates;
3073 case 8: NeedWaitStates = MFMA16x16WritesAGPRAccVgprReadWaitStates;
3075 case 16: [[fallthrough]];
3076 default: NeedWaitStates = MFMA32x32WritesAGPRAccVgprReadWaitStates;
3079 }
else if (
Opc == AMDGPU::V_ACCVGPR_WRITE_B32_e64) {
3080 switch (HazardDefLatency) {
3081 case 2: NeedWaitStates = MFMA4x4WritesAGPRAccVgprWriteWaitStates;
3083 case 8: NeedWaitStates = MFMA16x16WritesAGPRAccVgprWriteWaitStates;
3085 case 16: [[fallthrough]];
3086 default: NeedWaitStates = MFMA32x32WritesAGPRAccVgprWriteWaitStates;
3091 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceDef;
3092 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3094 if (WaitStatesNeeded == MaxWaitStates)
3095 return WaitStatesNeeded;
3097 auto IsAccVgprWriteFn = [
Reg,
this](
const MachineInstr &
MI) {
3098 if (
MI.getOpcode() != AMDGPU::V_ACCVGPR_WRITE_B32_e64)
3101 return TRI.regsOverlap(
Reg, DstReg);
3104 const int AccVGPRWriteMFMAReadSrcCWaitStates = 1;
3105 const int AccVGPRWriteMFMAReadSrcABWaitStates = 3;
3106 const int AccVGPRWriteAccVgprReadWaitStates = 3;
3107 NeedWaitStates = AccVGPRWriteMFMAReadSrcABWaitStates;
3108 if (OpNo == SrcCIdx)
3109 NeedWaitStates = AccVGPRWriteMFMAReadSrcCWaitStates;
3110 else if (
Opc == AMDGPU::V_ACCVGPR_READ_B32_e64)
3111 NeedWaitStates = AccVGPRWriteAccVgprReadWaitStates;
3113 WaitStatesNeededForUse = NeedWaitStates -
3114 getWaitStatesSinceDef(
Reg, IsAccVgprWriteFn, MaxWaitStates);
3115 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3117 if (WaitStatesNeeded == MaxWaitStates)
3118 return WaitStatesNeeded;
3121 if (
Opc == AMDGPU::V_ACCVGPR_WRITE_B32_e64) {
3122 const int MFMA4x4ReadSrcCAccVgprWriteWaitStates = 0;
3123 const int MFMA16x16ReadSrcCAccVgprWriteWaitStates = 5;
3124 const int MFMA32x32ReadSrcCAccVgprWriteWaitStates = 13;
3125 const int MaxWaitStates = 13;
3126 Register DstReg =
MI->getOperand(0).getReg();
3127 unsigned HazardDefLatency = 0;
3129 auto IsSrcCMFMAFn = [DstReg, &HazardDefLatency,
3130 this](
const MachineInstr &
MI) {
3133 Register Reg = TII.getNamedOperand(
MI, AMDGPU::OpName::src2)->getReg();
3135 std::max(HazardDefLatency, TSchedModel.computeInstrLatency(&
MI));
3136 return TRI.regsOverlap(
Reg, DstReg);
3139 int WaitStatesSince = getWaitStatesSince(IsSrcCMFMAFn, MaxWaitStates);
3141 switch (HazardDefLatency) {
3142 case 2: NeedWaitStates = MFMA4x4ReadSrcCAccVgprWriteWaitStates;
3144 case 8: NeedWaitStates = MFMA16x16ReadSrcCAccVgprWriteWaitStates;
3146 case 16: [[fallthrough]];
3147 default: NeedWaitStates = MFMA32x32ReadSrcCAccVgprWriteWaitStates;
3151 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSince;
3152 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3156 WaitStatesNeeded = std::max(WaitStatesNeeded, checkMFMAPadding(
MI));
3158 return WaitStatesNeeded;
3169 return NumPasses + 1 + IsGFX950;
3180 return NumPasses + 1 + (NumPasses != 2 && IsGFX950);
3198 return NumPasses + 2;
3208 return NumPasses + 3 + (NumPasses != 2 && IsGFX950);
3211int GCNHazardRecognizer::checkMAIHazards90A(
MachineInstr *
MI)
const {
3212 int WaitStatesNeeded = 0;
3213 unsigned Opc =
MI->getOpcode();
3215 auto IsLegacyVALUFn = [](
const MachineInstr &
MI) {
3220 auto IsLegacyVALUNotDotFn = [](
const MachineInstr &
MI) {
3226 return WaitStatesNeeded;
3228 const int VALUWritesExecWaitStates = 4;
3229 int WaitStatesNeededForUse = VALUWritesExecWaitStates -
3230 getWaitStatesSinceDef(AMDGPU::EXEC, IsLegacyVALUFn,
3231 VALUWritesExecWaitStates);
3232 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3234 int SrcCIdx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src2);
3237 for (
const MachineOperand &Use :
MI->explicit_uses()) {
3238 const int LegacyVALUNotDotWritesVGPRWaitStates = 2;
3239 const int SMFMA4x4WritesVGPROverlappedSMFMASrcCWaitStates = 2;
3240 const int SMFMA16x16WritesVGPROverlappedSMFMASrcCWaitStates = 8;
3241 const int SMFMA32x32WritesVGPROverlappedSMFMASrcCWaitStates = 16;
3242 const int SMFMA4x4WritesVGPROverlappedDMFMASrcCWaitStates = 3;
3243 const int SMFMA16x16WritesVGPROverlappedDMFMASrcCWaitStates = 9;
3244 const int SMFMA32x32WritesVGPROverlappedDMFMASrcCWaitStates = 17;
3245 const int DMFMA16x16WritesVGPROverlappedSrcCWaitStates = 9;
3246 const int GFX950_DMFMA16x16WritesVGPROverlappedSrcCWaitStates = 17;
3247 const int DMFMA4x4WritesVGPROverlappedSrcCWaitStates = 4;
3248 const int SMFMA4x4WritesVGPROverlappedSrcABWaitStates = 5;
3249 const int SMFMA16x16WritesVGPROverlappedSrcABWaitStates = 11;
3250 const int SMFMA32x32WritesVGPROverlappedSrcABWaitStates = 19;
3251 const int DMFMA4x4WritesVGPROverlappedMFMASrcABWaitStates = 6;
3252 const int DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates = 11;
3253 const int GFX950_DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates = 19;
3254 const int DMFMA4x4WritesVGPRFullSrcCWaitStates = 4;
3255 const int GFX940_SMFMA4x4WritesVGPRFullSrcCWaitStates = 2;
3256 const int MaxWaitStates =
3258 16, ST.hasGFX950Insts());
3264 const MachineInstr *MI1;
3266 auto IsOverlappedMFMAFn = [
Reg, &FullReg, &MI1,
3267 this](
const MachineInstr &
MI) {
3271 FullReg = (DstReg ==
Reg);
3273 return TRI.regsOverlap(DstReg,
Reg);
3276 WaitStatesNeededForUse = LegacyVALUNotDotWritesVGPRWaitStates -
3277 getWaitStatesSinceDef(
Reg, IsLegacyVALUNotDotFn, MaxWaitStates);
3278 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3281 getWaitStatesSinceDef(
Reg, IsOverlappedMFMAFn, MaxWaitStates);
3282 if (NumWaitStates == std::numeric_limits<int>::max())
3285 int OpNo =
Use.getOperandNo();
3287 int NeedWaitStates = 0;
3288 if (OpNo == SrcCIdx) {
3292 }
else if (FullReg) {
3293 if ((
Opc == AMDGPU::V_MFMA_F64_4X4X4F64_e64 ||
3294 Opc == AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64) &&
3295 (Opc1 == AMDGPU::V_MFMA_F64_4X4X4F64_e64 ||
3296 Opc1 == AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64))
3297 NeedWaitStates = DMFMA4x4WritesVGPRFullSrcCWaitStates;
3298 else if (ST.hasGFX940Insts() &&
3299 TSchedModel.computeInstrLatency(MI1) == 2)
3300 NeedWaitStates = GFX940_SMFMA4x4WritesVGPRFullSrcCWaitStates;
3303 case AMDGPU::V_MFMA_F64_16X16X4F64_e64:
3304 case AMDGPU::V_MFMA_F64_16X16X4F64_vgprcd_e64:
3305 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_e64:
3306 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_vgprcd_e64:
3307 if (!TII.isXDL(*
MI))
3310 ? GFX950_DMFMA16x16WritesVGPROverlappedSrcCWaitStates
3311 : DMFMA16x16WritesVGPROverlappedSrcCWaitStates;
3313 case AMDGPU::V_MFMA_F64_4X4X4F64_e64:
3314 case AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64:
3315 if (!TII.isXDL(*
MI))
3316 NeedWaitStates = DMFMA4x4WritesVGPROverlappedSrcCWaitStates;
3319 int NumPasses = TSchedModel.computeInstrLatency(MI1);
3320 if (ST.hasGFX940Insts()) {
3321 if (TII.isXDL(*
MI) && !TII.isXDL(*MI1))
3328 NumPasses, ST.hasGFX950Insts())
3330 NumPasses, ST.hasGFX950Insts()))
3336 switch (NumPasses) {
3340 ? SMFMA4x4WritesVGPROverlappedDMFMASrcCWaitStates
3341 : SMFMA4x4WritesVGPROverlappedSMFMASrcCWaitStates;
3346 ? SMFMA16x16WritesVGPROverlappedDMFMASrcCWaitStates
3347 : SMFMA16x16WritesVGPROverlappedSMFMASrcCWaitStates;
3352 ? SMFMA32x32WritesVGPROverlappedDMFMASrcCWaitStates
3353 : SMFMA32x32WritesVGPROverlappedSMFMASrcCWaitStates;
3362 case AMDGPU::V_MFMA_F64_16X16X4F64_e64:
3363 case AMDGPU::V_MFMA_F64_16X16X4F64_vgprcd_e64:
3364 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_e64:
3365 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_vgprcd_e64:
3368 ? GFX950_DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates
3369 : DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates;
3371 case AMDGPU::V_MFMA_F64_4X4X4F64_e64:
3372 case AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64:
3373 NeedWaitStates = DMFMA4x4WritesVGPROverlappedMFMASrcABWaitStates;
3376 int NumPasses = TSchedModel.computeInstrLatency(MI1);
3378 if (ST.hasGFX940Insts()) {
3382 NumPasses, ST.hasGFX950Insts())
3388 switch (NumPasses) {
3390 NeedWaitStates = SMFMA4x4WritesVGPROverlappedSrcABWaitStates;
3395 NeedWaitStates = SMFMA16x16WritesVGPROverlappedSrcABWaitStates;
3399 NeedWaitStates = SMFMA32x32WritesVGPROverlappedSrcABWaitStates;
3403 assert(NeedWaitStates <= MaxWaitStates &&
3404 "hazard requirement exceeds the scan window");
3405 if (WaitStatesNeeded >= NeedWaitStates)
3408 WaitStatesNeededForUse = NeedWaitStates - NumWaitStates;
3409 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3411 if (WaitStatesNeeded == MaxWaitStates)
3416 WaitStatesNeeded = std::max(WaitStatesNeeded, checkMFMAPadding(
MI));
3418 return WaitStatesNeeded;
3421int GCNHazardRecognizer::checkMAILdStHazards(
MachineInstr *
MI)
const {
3423 if (!ST.hasMAIInsts() || ST.hasGFX90AInsts())
3426 int WaitStatesNeeded = 0;
3428 auto IsAccVgprReadFn = [](
const MachineInstr &
MI) {
3429 return MI.getOpcode() == AMDGPU::V_ACCVGPR_READ_B32_e64;
3432 for (
const MachineOperand &
Op :
MI->explicit_uses()) {
3433 if (!
Op.isReg() || !TRI.isVGPR(MF.getRegInfo(),
Op.getReg()))
3438 const int AccVgprReadLdStWaitStates = 2;
3439 const int VALUWriteAccVgprRdWrLdStDepVALUWaitStates = 1;
3440 const int MaxWaitStates = 2;
3442 int WaitStatesNeededForUse = AccVgprReadLdStWaitStates -
3443 getWaitStatesSinceDef(
Reg, IsAccVgprReadFn, MaxWaitStates);
3444 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3446 if (WaitStatesNeeded == MaxWaitStates)
3447 return WaitStatesNeeded;
3449 auto IsVALUAccVgprRdWrCheckFn = [
Reg,
this](
const MachineInstr &
MI) {
3450 if (
MI.getOpcode() != AMDGPU::V_ACCVGPR_READ_B32_e64 &&
3451 MI.getOpcode() != AMDGPU::V_ACCVGPR_WRITE_B32_e64)
3453 auto IsVALUFn = [](
const MachineInstr &
MI) {
3457 return getWaitStatesSinceDef(
Reg, IsVALUFn, 2 ) <
3458 std::numeric_limits<int>::max();
3461 WaitStatesNeededForUse = VALUWriteAccVgprRdWrLdStDepVALUWaitStates -
3462 getWaitStatesSince(IsVALUAccVgprRdWrCheckFn, MaxWaitStates);
3463 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3466 return WaitStatesNeeded;
3469int GCNHazardRecognizer::checkPermlaneHazards(
MachineInstr *
MI)
const {
3470 assert(!ST.hasVcmpxPermlaneHazard() &&
3471 "this is a different vcmpx+permlane hazard");
3472 const SIRegisterInfo *TRI = ST.getRegisterInfo();
3473 const SIInstrInfo *TII = ST.getInstrInfo();
3475 auto IsVCmpXWritesExecFn = [TII, TRI](
const MachineInstr &
MI) {
3479 auto IsVALUFn = [](
const MachineInstr &
MI) {
3483 const int VCmpXWritesExecWaitStates = 4;
3484 const int VALUWritesVDstWaitStates = 2;
3485 int WaitStatesNeeded = 0;
3487 for (
const MachineOperand &
Op :
MI->explicit_uses()) {
3488 if (!
Op.isReg() || !TRI->isVGPR(MF.getRegInfo(),
Op.getReg()))
3492 int WaitStatesSinceDef =
3493 VALUWritesVDstWaitStates -
3494 getWaitStatesSinceDef(
Reg, IsVALUFn,
3495 VALUWritesVDstWaitStates);
3496 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesSinceDef);
3497 if (WaitStatesNeeded >= VALUWritesVDstWaitStates)
3501 int VCmpXHazardWaits =
3502 VCmpXWritesExecWaitStates -
3503 getWaitStatesSince(IsVCmpXWritesExecFn, VCmpXWritesExecWaitStates);
3505 WaitStatesNeeded = std::max(WaitStatesNeeded, VCmpXHazardWaits);
3506 return WaitStatesNeeded;
3514 return NumPasses + 2;
3524 return NumPasses + 3 + (NumPasses != 2 && IsGFX950);
3534 return NumPasses + 3 + (NumPasses != 2 && IsGFX950);
3542 return NumPasses + 2;
3545int GCNHazardRecognizer::checkMAIVALUHazards(
MachineInstr *
MI)
const {
3546 if (!ST.hasGFX90AInsts())
3549 auto IsDGEMMFn = [](
const MachineInstr &
MI) ->
bool {
3557 const MachineRegisterInfo &MRI = MF.getRegInfo();
3559 int WaitStatesNeeded = 0;
3565 const MachineInstr *
MFMA =
nullptr;
3567 auto IsMFMAWriteFn = [&
Reg, &
MFMA,
this](
const MachineInstr &
MI) {
3569 !TRI.regsOverlap(
MI.getOperand(0).getReg(),
Reg))
3575 const MachineInstr *
DOT =
nullptr;
3576 auto IsDotWriteFn = [&
Reg, &
DOT,
this](
const MachineInstr &
MI) {
3578 !TRI.regsOverlap(
MI.getOperand(0).getReg(),
Reg))
3584 bool DGEMMAfterVALUWrite =
false;
3585 auto IsDGEMMHazard = [&DGEMMAfterVALUWrite,
this](
const MachineInstr &
MI) {
3588 DGEMMAfterVALUWrite =
true;
3592 if (!TII.isVALU(
MI,
true) || !DGEMMAfterVALUWrite)
3598 int SrcCIdx = AMDGPU::getNamedOperandIdx(
MI->getOpcode(),
3599 AMDGPU::OpName::src2);
3601 if (IsMemOrExport || IsVALU) {
3602 const int SMFMA4x4WriteVgprVALUMemExpReadWaitStates = 5;
3603 const int SMFMA16x16WriteVgprVALUMemExpReadWaitStates = 11;
3604 const int SMFMA32x32WriteVgprVALUMemExpReadWaitStates = 19;
3605 const int DMFMA4x4WriteVgprMemExpReadWaitStates = 9;
3606 const int DMFMA16x16WriteVgprMemExpReadWaitStates = 18;
3607 const int DMFMA4x4WriteVgprVALUReadWaitStates = 6;
3608 const int DMFMA16x16WriteVgprVALUReadWaitStates = 11;
3609 const int GFX950_DMFMA16x16WriteVgprVALUReadWaitStates = 19;
3610 const int DotWriteSameDotReadSrcAB = 3;
3611 const int DotWriteDifferentVALURead = 3;
3612 const int DMFMABetweenVALUWriteVMEMRead = 2;
3613 const int MaxWaitStates =
3615 ST.hasGFX950Insts());
3617 for (
const MachineOperand &Use :
MI->explicit_uses()) {
3623 int WaitStatesSinceDef = getWaitStatesSinceDef(
Reg, IsDotWriteFn,
3626 int NeedWaitStates = 0;
3627 if (
DOT->getOpcode() ==
MI->getOpcode()) {
3628 if (&Use - &
MI->getOperand(0) != SrcCIdx)
3629 NeedWaitStates = DotWriteSameDotReadSrcAB;
3631 NeedWaitStates = DotWriteDifferentVALURead;
3634 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceDef;
3635 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3642 if (IsMem && ST.hasGFX90AInsts() && !ST.hasGFX940Insts()) {
3643 DGEMMAfterVALUWrite =
false;
3644 if (TRI.isVectorRegister(MRI,
Reg)) {
3645 int WaitStatesNeededForUse =
3646 DMFMABetweenVALUWriteVMEMRead -
3647 getWaitStatesSinceDef(
Reg, IsDGEMMHazard,
3648 DMFMABetweenVALUWriteVMEMRead);
3650 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3655 WaitStatesSinceDef =
3656 getWaitStatesSinceDef(
Reg, IsMFMAWriteFn, MaxWaitStates);
3660 unsigned HazardDefLatency = TSchedModel.computeInstrLatency(
MFMA);
3661 int NumPasses = HazardDefLatency;
3662 int NeedWaitStates = MaxWaitStates;
3665 switch (HazardDefLatency) {
3667 NeedWaitStates = IsMemOrExport ? DMFMA4x4WriteVgprMemExpReadWaitStates
3668 : DMFMA4x4WriteVgprVALUReadWaitStates;
3674 ? DMFMA16x16WriteVgprMemExpReadWaitStates
3675 : (ST.hasGFX950Insts()
3676 ? GFX950_DMFMA16x16WriteVgprVALUReadWaitStates
3677 : DMFMA16x16WriteVgprVALUReadWaitStates);
3682 }
else if (ST.hasGFX940Insts()) {
3686 NumPasses, ST.hasGFX950Insts())
3690 switch (HazardDefLatency) {
3692 NeedWaitStates = SMFMA4x4WriteVgprVALUMemExpReadWaitStates;
3695 NeedWaitStates = SMFMA16x16WriteVgprVALUMemExpReadWaitStates;
3698 NeedWaitStates = SMFMA32x32WriteVgprVALUMemExpReadWaitStates;
3705 assert(NeedWaitStates <= MaxWaitStates &&
3706 "hazard requirement exceeds the scan window");
3707 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceDef;
3708 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3710 if (WaitStatesNeeded == MaxWaitStates)
3715 unsigned Opc =
MI->getOpcode();
3716 const int DMFMAToFMA64WaitStates = 2;
3717 if ((
Opc == AMDGPU::V_FMA_F64_e64 ||
3718 Opc == AMDGPU::V_FMAC_F64_e32 ||
Opc == AMDGPU::V_FMAC_F64_e64 ||
3719 Opc == AMDGPU::V_FMAC_F64_dpp) &&
3720 WaitStatesNeeded < DMFMAToFMA64WaitStates) {
3721 int WaitStatesNeededForUse = DMFMAToFMA64WaitStates -
3722 getWaitStatesSince(IsDGEMMFn, DMFMAToFMA64WaitStates);
3723 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3726 if (!IsVALU && !IsMemOrExport)
3727 return WaitStatesNeeded;
3729 for (
const MachineOperand &Def :
MI->defs()) {
3730 const int SMFMA4x4WriteVgprVALUWawWaitStates = 5;
3731 const int SMFMA16x16WriteVgprVALUWawWaitStates = 11;
3732 const int SMFMA32x32WriteVgprVALUWawWaitStates = 19;
3733 const int SMFMA4x4ReadVgprVALUWarWaitStates = 1;
3734 const int GFX940_XDL4PassReadVgprVALUWarWaitStates = 3;
3735 const int SMFMA16x16ReadVgprVALUWarWaitStates = 7;
3736 const int SMFMA32x32ReadVgprVALUWarWaitStates = 15;
3737 const int DMFMA4x4WriteVgprVALUWriteWaitStates = 6;
3738 const int DMFMA16x16WriteVgprVALUWriteWaitStates = 11;
3739 const int DotWriteDifferentVALUWrite = 3;
3740 const int MaxWaitStates =
3742 const int MaxWarWaitStates = 15;
3747 int WaitStatesSinceDef = getWaitStatesSinceDef(
Reg, IsDotWriteFn,
3749 if (DOT &&
DOT->getOpcode() !=
MI->getOpcode())
3750 WaitStatesNeeded = std::max(WaitStatesNeeded, DotWriteDifferentVALUWrite -
3751 WaitStatesSinceDef);
3754 WaitStatesSinceDef =
3755 getWaitStatesSinceDef(
Reg, IsMFMAWriteFn, MaxWaitStates);
3757 int NeedWaitStates = MaxWaitStates;
3758 int NumPasses = TSchedModel.computeInstrLatency(
MFMA);
3761 switch (NumPasses) {
3763 NeedWaitStates = DMFMA4x4WriteVgprVALUWriteWaitStates;
3767 NeedWaitStates = DMFMA16x16WriteVgprVALUWriteWaitStates;
3772 }
else if (ST.hasGFX940Insts()) {
3776 NumPasses, ST.hasGFX950Insts())
3779 switch (NumPasses) {
3781 NeedWaitStates = SMFMA4x4WriteVgprVALUWawWaitStates;
3784 NeedWaitStates = SMFMA16x16WriteVgprVALUWawWaitStates;
3787 NeedWaitStates = SMFMA32x32WriteVgprVALUWawWaitStates;
3794 assert(NeedWaitStates <= MaxWaitStates &&
3795 "hazard requirement exceeds the scan window");
3796 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceDef;
3797 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3799 if (WaitStatesNeeded == MaxWaitStates)
3803 auto IsSMFMAReadAsCFn = [&
Reg, &
MFMA,
this](
const MachineInstr &
MI) {
3805 !
MI.readsRegister(
Reg, &TRI))
3808 if (ST.hasGFX940Insts() && !TII.isXDL(
MI))
3811 const MachineOperand *SrcC =
3812 TII.getNamedOperand(
MI, AMDGPU::OpName::src2);
3822 int WaitStatesSinceUse = getWaitStatesSince(IsSMFMAReadAsCFn,
3827 unsigned HazardDefLatency = TSchedModel.computeInstrLatency(
MFMA);
3828 int NeedWaitStates = MaxWaitStates;
3829 switch (HazardDefLatency) {
3830 case 2: NeedWaitStates = SMFMA4x4ReadVgprVALUWarWaitStates;
3832 case 4:
assert(ST.hasGFX940Insts());
3833 NeedWaitStates = GFX940_XDL4PassReadVgprVALUWarWaitStates;
3835 case 8: NeedWaitStates = SMFMA16x16ReadVgprVALUWarWaitStates;
3837 case 16: [[fallthrough]];
3838 default: NeedWaitStates = SMFMA32x32ReadVgprVALUWarWaitStates;
3842 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceUse;
3843 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3846 return WaitStatesNeeded;
3859 return MAI !=
nullptr;
3863 if (IsMFMAFn(*
MI)) {
3864 int W = getWaitStatesSince(IsMFMAFn, 16);
3866 return W < (int)TSchedModel.computeInstrLatency(MAI);
3880 while (
I->isBundledWithPred())
3886 if (
I->getOpcode() != AMDGPU::S_GETPC_B64)
3890 const unsigned NewBytes = 4;
3892 "Unexpected instruction insertion in bundle");
3895 while (NextMI != End && NextMI->isBundledWithPred()) {
3896 for (
auto &Operand : NextMI->operands()) {
3897 if (Operand.isGlobal())
3898 Operand.setOffset(Operand.getOffset() + NewBytes);
3904bool GCNHazardRecognizer::fixVALUMaskWriteHazard(
MachineInstr *
MI) {
3905 if (!ST.hasVALUMaskWriteHazard())
3907 assert(!ST.hasExtendedWaitCounts());
3914 if (!IsSALU && !IsVALU)
3926 const SIRegisterInfo *TRI = ST.getRegisterInfo();
3927 const MachineRegisterInfo &MRI = MF.getRegInfo();
3932 case AMDGPU::EXEC_LO:
3933 case AMDGPU::EXEC_HI:
3935 case AMDGPU::SGPR_NULL:
3936 case AMDGPU::SGPR_NULL64:
3944 return Reg == AMDGPU::VCC ||
Reg == AMDGPU::VCC_LO ||
Reg == AMDGPU::VCC_HI;
3948 SmallSet<Register, 2> HazardSGPRs;
3950 static unsigned getHashValue(
const StateType &State) {
3953 static bool isEqual(
const StateType &
LHS,
const StateType &
RHS) {
3954 return LHS.HazardSGPRs ==
RHS.HazardSGPRs;
3958 SmallVector<const MachineInstr *> WaitInstrs;
3959 StateType InitialState;
3962 MachineOperand *HazardDef =
nullptr;
3963 for (MachineOperand &
Op :
MI->all_defs()) {
3965 if (IgnoreableSGPR(
Reg))
3968 if (
Op.isImplicit())
3970 if (!TRI->isSGPRReg(MRI,
Reg))
3983 if (AMDGPU::SReg_32RegClass.
contains(HazardReg)) {
3984 InitialState.HazardSGPRs.insert(HazardReg);
3987 InitialState.HazardSGPRs.insert(TRI->getSubReg(HazardReg, AMDGPU::sub0));
3988 InitialState.HazardSGPRs.insert(TRI->getSubReg(HazardReg, AMDGPU::sub1));
3991 auto IsHazardFn = [&](StateType &State,
const MachineInstr &
I) {
3992 if (State.HazardSGPRs.empty())
3995 switch (
I.getOpcode()) {
3996 case AMDGPU::V_ADDC_U32_e32:
3997 case AMDGPU::V_ADDC_U32_dpp:
3998 case AMDGPU::V_CNDMASK_B16_t16_e32:
3999 case AMDGPU::V_CNDMASK_B16_fake16_e32:
4000 case AMDGPU::V_CNDMASK_B16_t16_dpp:
4001 case AMDGPU::V_CNDMASK_B16_fake16_dpp:
4002 case AMDGPU::V_CNDMASK_B32_e32:
4003 case AMDGPU::V_CNDMASK_B32_dpp:
4004 case AMDGPU::V_DIV_FMAS_F32_e64:
4005 case AMDGPU::V_DIV_FMAS_F64_e64:
4006 case AMDGPU::V_SUBB_U32_e32:
4007 case AMDGPU::V_SUBB_U32_dpp:
4008 case AMDGPU::V_SUBBREV_U32_e32:
4009 case AMDGPU::V_SUBBREV_U32_dpp: {
4013 case AMDGPU::V_ADDC_U32_e64:
4014 case AMDGPU::V_ADDC_U32_e64_dpp:
4015 case AMDGPU::V_CNDMASK_B16_t16_e64:
4016 case AMDGPU::V_CNDMASK_B16_fake16_e64:
4017 case AMDGPU::V_CNDMASK_B16_t16_e64_dpp:
4018 case AMDGPU::V_CNDMASK_B16_fake16_e64_dpp:
4019 case AMDGPU::V_CNDMASK_B32_e64:
4020 case AMDGPU::V_CNDMASK_B32_e64_dpp:
4021 case AMDGPU::V_SUBB_U32_e64:
4022 case AMDGPU::V_SUBB_U32_e64_dpp:
4023 case AMDGPU::V_SUBBREV_U32_e64:
4024 case AMDGPU::V_SUBBREV_U32_e64_dpp: {
4026 const MachineOperand *SSRCOp = TII.getNamedOperand(
I, AMDGPU::OpName::src2);
4028 bool Result = TRI->regsOverlap(SSRCOp->
getReg(), HazardReg);
4036 auto UpdateStateFn = [&](StateType &State,
const MachineInstr &
I) {
4038 for (
auto &
Op :
I.all_defs()) {
4040 if (IgnoreableSGPR(
Reg))
4043 if (
Op.isImplicit())
4045 if (!TRI->isSGPRReg(MRI,
Reg))
4052 for (
Register SGPR : State.HazardSGPRs) {
4053 if (
Reg == SGPR || TRI->regsOverlap(
Reg, SGPR))
4057 State.HazardSGPRs.erase(SGPR);
4064 std::next(
MI->getReverseIterator())))
4074 auto NextMI = std::next(
MI->getIterator());
4075 auto NewMI =
BuildMI(*
MI->getParent(), NextMI,
MI->getDebugLoc(),
4076 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
4088 if (EntryMBB.
begin() != EntryMBB.
end()) {
4089 auto &EntryMI = *EntryMBB.
begin();
4090 if (EntryMI.getOpcode() == AMDGPU::S_SETPRIO &&
4091 EntryMI.getOperand(0).getImm() >= Priority)
4100bool GCNHazardRecognizer::fixRequiredExportPriority(
MachineInstr *
MI) {
4101 if (!ST.hasRequiredExportPriority())
4119 const int MaxPriority = 3;
4120 const int NormalPriority = 2;
4121 const int PostExportPriority = 0;
4123 auto It =
MI->getIterator();
4124 switch (
MI->getOpcode()) {
4125 case AMDGPU::S_ENDPGM:
4126 case AMDGPU::S_ENDPGM_SAVED:
4127 case AMDGPU::S_ENDPGM_ORDERED_PS_DONE:
4128 case AMDGPU::SI_RETURN_TO_EPILOG:
4131 if (MF->getFrameInfo().hasCalls())
4134 case AMDGPU::S_SETPRIO: {
4136 auto &PrioOp =
MI->getOperand(0);
4137 int Prio = PrioOp.getImm();
4138 bool InWA = (Prio == PostExportPriority) &&
4139 (It !=
MBB->
begin() && TII.isEXP(*std::prev(It)));
4140 if (InWA || Prio >= NormalPriority)
4142 PrioOp.setImm(std::min(Prio + NormalPriority, MaxPriority));
4146 if (!TII.isEXP(*
MI))
4157 auto NextMI = std::next(It);
4158 bool EndOfShader =
false;
4159 if (NextMI !=
MBB->
end()) {
4161 if (TII.isEXP(*NextMI))
4164 if (NextMI->getOpcode() == AMDGPU::S_SETPRIO &&
4165 NextMI->getOperand(0).getImm() == PostExportPriority)
4167 EndOfShader = NextMI->getOpcode() == AMDGPU::S_ENDPGM;
4174 .
addImm(PostExportPriority);
4178 BuildMI(*
MBB, NextMI,
DL, TII.get(AMDGPU::S_WAITCNT_EXPCNT))
4179 .
addReg(AMDGPU::SGPR_NULL)
4199 const SIInstrInfo *TII = ST.getInstrInfo();
4211 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4216bool GCNHazardRecognizer::fixDsAtomicAsyncBarrierArriveB64(
MachineInstr *
MI) {
4217 if (
MI->getOpcode() != AMDGPU::DS_ATOMIC_ASYNC_BARRIER_ARRIVE_B64)
4220 const SIInstrInfo *TII = ST.getInstrInfo();
4222 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4224 BuildMI(*
MI->getParent(), std::next(
MI->getIterator()),
MI->getDebugLoc(),
4225 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4231bool GCNHazardRecognizer::fixScratchBaseForwardingHazard(
MachineInstr *
MI) {
4237 const SIRegisterInfo *TRI = ST.getRegisterInfo();
4238 const SIInstrInfo *TII = ST.getInstrInfo();
4240 const int FlatScrBaseWaitStates = 10;
4242 bool ReadsFlatScrLo =
4244 bool ReadsFlatScrHi =
4245 MI->readsRegister(AMDGPU::SRC_FLAT_SCRATCH_BASE_HI, TRI);
4251 ReadsFlatScrLo =
true;
4254 ReadsFlatScrHi =
true;
4259 const MachineRegisterInfo &MRI = MF.getRegInfo();
4262 DenseSet<const MachineBasicBlock *> Visited;
4264 return MI.modifiesRegister(
Reg, TRI);
4269 auto IsSGPRDef = [TII, TRI, &MRI](
const MachineInstr &
MI) ->
unsigned {
4270 if (!TII->isSALU(
MI) && !TII->isVALU(
MI,
true))
4272 for (
const MachineOperand &MO :
MI.all_defs()) {
4273 if (TRI->isSGPRReg(MRI, MO.getReg()))
4279 auto IsExpiredFn = [=](
const MachineInstr &
MI,
int SgprWrites) {
4280 if (
MI.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR) {
4281 unsigned Wait =
MI.getOperand(0).getImm();
4286 return SgprWrites >= FlatScrBaseWaitStates;
4289 return ::getWaitStatesSince(
4290 IsHazardFn,
MI->getParent(), std::next(
MI->getReverseIterator()),
4291 0,
IsExpiredFn, Visited, IsSGPRDef) < FlatScrBaseWaitStates;
4295 !IsRegDefHazard(AMDGPU::SGPR102)) &&
4297 !IsRegDefHazard(AMDGPU::SGPR103)))
4301 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4312 BuildMI(*
MI->getParent(),
MI,
MI->getDebugLoc(), TII.get(AMDGPU::V_NOP_e32));
4313 BuildMI(*
MI->getParent(),
MI,
MI->getDebugLoc(), TII.get(AMDGPU::V_NOP_e32));
4318 auto IsTDM = [&](
const MachineInstr &
MI) ->
bool {
4320 MI.getOpcode() != AMDGPU::S_WAIT_TENSORCNT;
4327 if (
MI.getOpcode() != AMDGPU::S_WAIT_TENSORCNT)
4329 return MI.getOperand(0).getImm() <= 10;
4333 std::numeric_limits<int>::max())
4337 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)
#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 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 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 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.
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)
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...