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;
349 if (ActiveCoExecInfo.canCoExec(InstMask, Stage))
353 auto NextStage = ActiveCoExecInfo.findNextAllowedStage(InstMask, Stage);
354 if (NextStage.has_value()) {
355 unsigned StallCycles = *NextStage - Stage;
358 dbgs() <<
" CoExec stall: stage=" << Stage <<
"("
361 <<
" -> stall " << StallCycles <<
" (next allowed=" << *NextStage
368 unsigned StallCycles = ActiveCoExecInfo.TotalWindow - Stage;
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;
402 if (ActiveCoExecInfo.canCoExec(InstMask, LookAheadStage))
403 return CyclesUntilTRANS;
407 ActiveCoExecInfo.findNextAllowedStage(InstMask, LookAheadStage);
408 if (NextStage.has_value()) {
409 unsigned StallCycles = *NextStage - *CurrentCoExecStage;
414 unsigned StallCycles = ActiveCoExecInfo.TotalWindow - *CurrentCoExecStage;
418void GCNHazardRecognizer::schedulerEmitInstruction(
MachineInstr *
MI) {
420 bool InWindow = CurrentCoExecStage.has_value();
421 bool HasActiveState =
422 InWindow || CyclesUntilTRANS > 0 || CyclesUntilVALU > 0;
423 if (HasActiveState) {
425 unsigned Stage = *CurrentCoExecStage;
426 dbgs() <<
" Stage " << Stage <<
"("
439 bool HasActiveState = CurrentCoExecStage.has_value() ||
440 CyclesUntilTRANS > 0 || CyclesUntilVALU > 0;
446 updateWMMAWindowState(*
MI);
447 updateTRANSState(*
MI);
448 updateMultiCycleVALUState(*
MI);
458 schedulerEmitInstruction(
MI);
462 return Opcode == AMDGPU::V_DIV_FMAS_F32_e64 || Opcode == AMDGPU::V_DIV_FMAS_F64_e64;
466 return Opcode == AMDGPU::S_GETREG_B32 || Opcode == AMDGPU::S_GETREG_B32_const;
471 case AMDGPU::S_SETREG_B32:
472 case AMDGPU::S_SETREG_B32_mode:
473 case AMDGPU::S_SETREG_IMM32_B32:
474 case AMDGPU::S_SETREG_IMM32_B32_mode:
481 return Opcode == AMDGPU::V_READLANE_B32 || Opcode == AMDGPU::V_WRITELANE_B32;
485 return Opcode == AMDGPU::S_RFE_B64;
490 case AMDGPU::S_MOVRELS_B32:
491 case AMDGPU::S_MOVRELS_B64:
492 case AMDGPU::S_MOVRELD_B32:
493 case AMDGPU::S_MOVRELD_B64:
502 if (
TII.isAlwaysGDS(
MI.getOpcode()))
505 switch (
MI.getOpcode()) {
506 case AMDGPU::S_SENDMSG:
507 case AMDGPU::S_SENDMSGHALT:
508 case AMDGPU::S_TTRACEDATA:
512 case AMDGPU::DS_PERMUTE_B32:
513 case AMDGPU::DS_BPERMUTE_B32:
516 if (
TII.isDS(
MI.getOpcode())) {
517 int GDS = AMDGPU::getNamedOperandIdx(
MI.getOpcode(),
518 AMDGPU::OpName::gds);
519 if (
MI.getOperand(GDS).getImm())
527 unsigned Opcode =
MI.getOpcode();
528 return Opcode == AMDGPU::V_PERMLANE16_B32_e64 ||
529 Opcode == AMDGPU::V_PERMLANE64_B32 ||
530 Opcode == AMDGPU::V_PERMLANEX16_B32_e64 ||
531 Opcode == AMDGPU::V_PERMLANE16_VAR_B32_e64 ||
532 Opcode == AMDGPU::V_PERMLANEX16_VAR_B32_e64 ||
533 Opcode == AMDGPU::V_PERMLANE16_SWAP_B32_e32 ||
534 Opcode == AMDGPU::V_PERMLANE16_SWAP_B32_e64 ||
535 Opcode == AMDGPU::V_PERMLANE32_SWAP_B32_e32 ||
536 Opcode == AMDGPU::V_PERMLANE32_SWAP_B32_e64 ||
537 Opcode == AMDGPU::V_PERMLANE_BCAST_B32_e64 ||
538 Opcode == AMDGPU::V_PERMLANE_UP_B32_e64 ||
539 Opcode == AMDGPU::V_PERMLANE_DOWN_B32_e64 ||
540 Opcode == AMDGPU::V_PERMLANE_XOR_B32_e64 ||
541 Opcode == AMDGPU::V_PERMLANE_IDX_GEN_B32_e64;
550 AMDGPU::OpName::simm16);
566 if (checkMultiShadowHazard(*
MI) > 0)
568 if (checkWMMACoexecSlot(*
MI) > 0)
570 if (checkTRANSHazard(*
MI) > 0)
572 if (checkMultiCycleVALUHazard(*
MI) > 0)
582 if (ST.hasNSAtoVMEMBug() && checkNSAtoVMEMHazard(
MI) > 0)
585 if (checkFPAtomicToDenormModeHazard(
MI) > 0)
590 if (checkWMMACoexecutionHazards(
MI) > 0) {
591 HasPendingWMMACoexecHazard =
true;
596 if (ST.hasNoDataDepHazard())
603 checkVALUHazards(
MI) > 0)
609 if (
isDivFMas(
MI->getOpcode()) && checkDivFMasHazards(
MI) > 0)
612 if (
isRWLane(
MI->getOpcode()) && checkRWLaneHazards(
MI) > 0)
618 checkMAIVALUHazards(
MI) > 0)
621 if (
isSGetReg(
MI->getOpcode()) && checkGetRegHazards(
MI) > 0)
624 if (
isSSetReg(
MI->getOpcode()) && checkSetRegHazards(
MI) > 0)
627 if (
isRFE(
MI->getOpcode()) && checkRFEHazards(
MI) > 0)
630 if (((ST.hasReadM0MovRelInterpHazard() &&
632 MI->getOpcode() == AMDGPU::DS_WRITE_ADDTID_B32 ||
633 MI->getOpcode() == AMDGPU::DS_READ_ADDTID_B32)) ||
635 (ST.hasReadM0LdsDmaHazard() &&
isLdsDma(*
MI)) ||
636 (ST.hasReadM0LdsDirectHazard() &&
637 MI->readsRegister(AMDGPU::LDS_DIRECT,
nullptr))) &&
638 checkReadM0Hazards(
MI) > 0)
645 checkMAILdStHazards(
MI) > 0)
648 if (
MI->isInlineAsm() && checkInlineAsmHazards(
MI) > 0)
656 while (Quantity > 0) {
657 unsigned Arg = std::min(Quantity, 8u);
665GCNHazardRecognizer::getMFMAPipelineWaitStates(
const MachineInstr &
MI)
const {
666 const MCSchedClassDesc *SC = TSchedModel.resolveSchedClass(&
MI);
667 assert(TSchedModel.getWriteProcResBegin(SC) !=
668 TSchedModel.getWriteProcResEnd(SC));
669 return TSchedModel.getWriteProcResBegin(SC)->ReleaseAtCycle;
672void GCNHazardRecognizer::processBundle() {
676 for (;
MI !=
E &&
MI->isInsideBundle(); ++
MI) {
677 CurrCycleInstr = &*
MI;
681 fixHazards(CurrCycleInstr);
689 for (
unsigned i = 0, e = std::min(WaitStates,
MaxLookAhead - 1); i <
e; ++i)
690 EmittedInstrs.push_front(
nullptr);
692 EmittedInstrs.push_front(CurrCycleInstr);
695 CurrCycleInstr =
nullptr;
703 if (
MI->isInsideBundle())
717 CurrCycleInstr =
nullptr;
726 W = checkWMMACoexecSlot(*
MI);
727 W = std::max(W, checkTRANSHazard(*
MI));
728 W = std::max(W, checkMultiCycleVALUHazard(*
MI));
729 W = std::max(W, checkMultiShadowHazard(*
MI));
745 return std::max(WaitStates, checkSMRDHazards(
MI));
747 if (ST.hasNSAtoVMEMBug())
748 WaitStates = std::max(WaitStates, checkNSAtoVMEMHazard(
MI));
750 WaitStates = std::max(WaitStates, checkFPAtomicToDenormModeHazard(
MI));
752 if (ST.hasNoDataDepHazard())
756 WaitStates = std::max(WaitStates, checkVMEMHazards(
MI));
759 WaitStates = std::max(WaitStates, checkVALUHazards(
MI));
762 WaitStates = std::max(WaitStates, checkDPPHazards(
MI));
765 WaitStates = std::max(WaitStates, checkDivFMasHazards(
MI));
768 WaitStates = std::max(WaitStates, checkRWLaneHazards(
MI));
773 checkMAIVALUHazards(
MI) > 0)
774 WaitStates = std::max(WaitStates, checkMAIVALUHazards(
MI));
776 if (
MI->isInlineAsm())
777 return std::max(WaitStates, checkInlineAsmHazards(
MI));
780 return std::max(WaitStates, checkGetRegHazards(
MI));
783 return std::max(WaitStates, checkSetRegHazards(
MI));
786 return std::max(WaitStates, checkRFEHazards(
MI));
788 if ((ST.hasReadM0MovRelInterpHazard() &&
790 MI->getOpcode() == AMDGPU::DS_WRITE_ADDTID_B32 ||
791 MI->getOpcode() == AMDGPU::DS_READ_ADDTID_B32)) ||
793 (ST.hasReadM0LdsDmaHazard() &&
isLdsDma(*
MI)) ||
794 (ST.hasReadM0LdsDirectHazard() &&
795 MI->readsRegister(AMDGPU::LDS_DIRECT,
nullptr)))
796 return std::max(WaitStates, checkReadM0Hazards(
MI));
799 return std::max(WaitStates, checkMAIHazards(
MI));
802 return std::max(WaitStates, checkMAILdStHazards(
MI));
805 return std::max(WaitStates, checkPermlaneHazards(
MI));
811 EmittedInstrs.push_front(
nullptr);
816 schedulerAdvanceCycle();
820 if (!CurrCycleInstr) {
821 EmittedInstrs.push_front(
nullptr);
823 if (HasPendingWMMACoexecHazard)
824 EmittedVALUInstrs.push_front(
nullptr);
828 HasPendingWMMACoexecHazard =
false;
830 if (CurrCycleInstr->isBundle()) {
835 unsigned NumWaitStates = TII.getNumWaitStates(*CurrCycleInstr);
836 if (!NumWaitStates) {
837 CurrCycleInstr =
nullptr;
842 EmittedInstrs.push_front(CurrCycleInstr);
849 EmittedVALUInstrs.push_front(CurrCycleInstr);
855 while (!EmittedVALUInstrs.empty() && EmittedVALUInstrs.front() ==
nullptr)
856 EmittedVALUInstrs.pop_front();
864 EmittedInstrs.push_front(
nullptr);
871 if (EmittedVALUInstrs.size() > MaxVALULookAhead)
872 EmittedVALUInstrs.resize(MaxVALULookAhead);
874 CurrCycleInstr =
nullptr;
879 "Bottom-up scheduling shouldn't run in hazard recognizer mode");
889template <
typename StateT>
899 static bool isEqual(
const StateMapKey &
LHS,
const StateMapKey &
RHS) {
904 static unsigned getHashValue(
const StateMapKey &
Key) {
905 return StateT::getHashValue((*
Key.States)[
Key.Idx]);
907 static unsigned getHashValue(
const StateT &State) {
908 return StateT::getHashValue(State);
910 static bool isEqual(
const StateMapKey &
LHS,
const StateMapKey &
RHS) {
911 return StateT::isEqual((*
LHS.States)[
LHS.Idx], (*
RHS.States)[
RHS.Idx]);
913 static bool isEqual(
const StateT &
LHS,
const StateMapKey &
RHS) {
914 return StateT::isEqual(
LHS, (*
RHS.States)[
RHS.Idx]);
923 StateT State = InitialState;
926 unsigned WorkIdx = 0;
928 bool Expired =
false;
929 for (
auto E =
MBB->instr_rend();
I !=
E; ++
I) {
934 auto Result = IsHazard(State, *
I);
942 if (
I->isInlineAsm() ||
I->isMetaInstruction())
945 UpdateState(State, *
I);
949 unsigned StateIdx = States.
size();
950 StateMapKey
Key = {&States, StateIdx};
951 auto Insertion = StateMap.
insert_as(std::pair(
Key, StateIdx), State);
952 if (Insertion.second) {
955 StateIdx = Insertion.first->second;
958 Worklist.
insert(std::pair(Pred, StateIdx));
961 if (WorkIdx == Worklist.
size())
965 std::tie(
MBB, StateIdx) = Worklist[WorkIdx++];
966 State = States[StateIdx];
967 I =
MBB->instr_rbegin();
984 for (
auto E =
MBB->instr_rend();
I !=
E; ++
I) {
992 if (
I->isInlineAsm())
995 WaitStates += GetNumWaitStates(*
I);
997 if (IsExpired(*
I, WaitStates))
998 return std::numeric_limits<int>::max();
1001 int MinWaitStates = std::numeric_limits<int>::max();
1003 if (!Visited.
insert(Pred).second)
1007 IsExpired, Visited, GetNumWaitStates);
1009 MinWaitStates = std::min(MinWaitStates, W);
1012 return MinWaitStates;
1023 std::next(
MI->getReverseIterator()), 0, IsExpired,
1024 Visited, GetNumWaitStates);
1027int GCNHazardRecognizer::getWaitStatesSince(
1028 IsHazardFn IsHazard,
int Limit, GetNumWaitStatesFn GetNumWaitStates)
const {
1030 auto IsExpiredFn = [Limit](
const MachineInstr &,
int WaitStates) {
1031 return WaitStates >= Limit;
1033 return ::getWaitStatesSince(IsHazard, CurrCycleInstr,
IsExpiredFn,
1038 for (MachineInstr *
MI : EmittedInstrs) {
1043 if (
MI->isInlineAsm())
1046 WaitStates +=
MI ? GetNumWaitStates(*
MI) : 1;
1048 if (WaitStates >= Limit)
1051 return std::numeric_limits<int>::max();
1054int GCNHazardRecognizer::getWaitStatesSince(IsHazardFn IsHazard,
1059int GCNHazardRecognizer::getWaitStatesSinceVALU(IsHazardFn IsHazard,
1062 auto GetVALUWaitStates = [](
const MachineInstr &
MI) ->
unsigned {
1065 return getWaitStatesSince(IsHazard, Limit, GetVALUWaitStates);
1071 assert(Limit <= (
int)MaxVALULookAhead &&
1072 "Limit exceeds the EmittedVALUInstrs lookahead window");
1074 for (MachineInstr *
MI : EmittedVALUInstrs) {
1082 if (WaitStates >= Limit)
1085 return std::numeric_limits<int>::max();
1088int GCNHazardRecognizer::getWaitStatesSinceDef(
unsigned Reg,
1089 IsHazardFn IsHazardDef,
1091 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1094 return IsHazardDef(
MI) &&
MI.modifiesRegister(
Reg, TRI);
1097 return getWaitStatesSince(
IsHazardFn, Limit);
1100int GCNHazardRecognizer::getWaitStatesSinceSetReg(IsHazardFn IsHazard,
1106 return getWaitStatesSince(
IsHazardFn, Limit);
1115 for (MCRegUnit Unit :
TRI.regunits(
Reg))
1116 BV.
set(
static_cast<unsigned>(Unit));
1128void GCNHazardRecognizer::addClauseInst(
const MachineInstr &
MI)
const {
1140int GCNHazardRecognizer::checkSoftClauseHazards(
MachineInstr *MEM)
const {
1143 if (!ST.isXNACKEnabled())
1146 bool IsSMRD = TII.isSMRD(*MEM);
1160 for (MachineInstr *
MI : EmittedInstrs) {
1172 if (ClauseDefs.none())
1178 if (
MEM->mayStore())
1181 addClauseInst(*MEM);
1185 return ClauseDefs.anyCommon(ClauseUses) ? 1 : 0;
1188int GCNHazardRecognizer::checkSMRDHazards(
MachineInstr *SMRD)
const {
1189 int WaitStatesNeeded = 0;
1191 WaitStatesNeeded = checkSoftClauseHazards(SMRD);
1194 if (!ST.hasSMRDReadVALUDefHazard())
1195 return WaitStatesNeeded;
1199 int SmrdSgprWaitStates = 4;
1200 auto IsHazardDefFn = [
this](
const MachineInstr &
MI) {
1201 return TII.isVALU(
MI,
true);
1203 auto IsBufferHazardDefFn = [
this](
const MachineInstr &
MI) {
1204 return TII.isSALU(
MI);
1207 bool IsBufferSMRD = TII.isBufferSMRD(*SMRD);
1209 for (
const MachineOperand &Use :
SMRD->uses()) {
1212 int WaitStatesNeededForUse =
1213 SmrdSgprWaitStates - getWaitStatesSinceDef(
Use.getReg(), IsHazardDefFn,
1214 SmrdSgprWaitStates);
1215 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1225 int WaitStatesNeededForUse =
1226 SmrdSgprWaitStates - getWaitStatesSinceDef(
Use.getReg(),
1227 IsBufferHazardDefFn,
1228 SmrdSgprWaitStates);
1229 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1233 return WaitStatesNeeded;
1236int GCNHazardRecognizer::checkVMEMHazards(
MachineInstr *VMEM)
const {
1237 if (!ST.hasVMEMReadSGPRVALUDefHazard())
1240 int WaitStatesNeeded = checkSoftClauseHazards(VMEM);
1244 const int VmemSgprWaitStates = 5;
1245 auto IsHazardDefFn = [
this](
const MachineInstr &
MI) {
1246 return TII.isVALU(
MI,
true);
1248 for (
const MachineOperand &Use :
VMEM->uses()) {
1249 if (!
Use.isReg() || TRI.isVectorRegister(MF.getRegInfo(),
Use.getReg()))
1252 int WaitStatesNeededForUse =
1253 VmemSgprWaitStates - getWaitStatesSinceDef(
Use.getReg(), IsHazardDefFn,
1254 VmemSgprWaitStates);
1255 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1257 return WaitStatesNeeded;
1261 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1262 const SIInstrInfo *TII = ST.getInstrInfo();
1265 int DppVgprWaitStates = 2;
1266 int DppExecWaitStates = 5;
1267 int WaitStatesNeeded = 0;
1268 auto IsHazardDefFn = [TII](
const MachineInstr &
MI) {
1269 return TII->isVALU(
MI,
true);
1272 for (
const MachineOperand &Use :
DPP->uses()) {
1273 if (!
Use.isReg() || !TRI->isVGPR(MF.getRegInfo(),
Use.getReg()))
1275 int WaitStatesNeededForUse =
1276 DppVgprWaitStates - getWaitStatesSinceDef(
1278 [](
const MachineInstr &) { return true; },
1280 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1283 WaitStatesNeeded = std::max(
1285 DppExecWaitStates - getWaitStatesSinceDef(AMDGPU::EXEC, IsHazardDefFn,
1286 DppExecWaitStates));
1288 return WaitStatesNeeded;
1291int GCNHazardRecognizer::checkDivFMasHazards(
MachineInstr *DivFMas)
const {
1292 const SIInstrInfo *TII = ST.getInstrInfo();
1296 const int DivFMasWaitStates = 4;
1297 auto IsHazardDefFn = [TII](
const MachineInstr &
MI) {
1298 return TII->isVALU(
MI,
true);
1300 int WaitStatesNeeded = getWaitStatesSinceDef(AMDGPU::VCC, IsHazardDefFn,
1303 return DivFMasWaitStates - WaitStatesNeeded;
1306int GCNHazardRecognizer::checkGetRegHazards(
MachineInstr *GetRegInstr)
const {
1307 const SIInstrInfo *TII = ST.getInstrInfo();
1308 unsigned GetRegHWReg =
getHWReg(TII, *GetRegInstr);
1310 const int GetRegWaitStates = 2;
1311 auto IsHazardFn = [TII, GetRegHWReg](
const MachineInstr &
MI) {
1314 int WaitStatesNeeded = getWaitStatesSinceSetReg(
IsHazardFn, GetRegWaitStates);
1316 return GetRegWaitStates - WaitStatesNeeded;
1319int GCNHazardRecognizer::checkSetRegHazards(
MachineInstr *SetRegInstr)
const {
1320 const SIInstrInfo *TII = ST.getInstrInfo();
1321 unsigned HWReg =
getHWReg(TII, *SetRegInstr);
1323 const int SetRegWaitStates = ST.getSetRegWaitStates();
1324 auto IsHazardFn = [TII, HWReg](
const MachineInstr &
MI) {
1327 int WaitStatesNeeded = getWaitStatesSinceSetReg(
IsHazardFn, SetRegWaitStates);
1328 return SetRegWaitStates - WaitStatesNeeded;
1331int GCNHazardRecognizer::createsVALUHazard(
const MachineInstr &
MI)
const {
1335 const SIInstrInfo *TII = ST.getInstrInfo();
1336 unsigned Opcode =
MI.getOpcode();
1337 const MCInstrDesc &
Desc =
MI.getDesc();
1339 int VDataIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::vdata);
1342 VDataRCID = TII->getOpRegClassID(
Desc.operands()[VDataIdx]);
1344 if (TII->isMUBUF(
MI) || TII->isMTBUF(
MI)) {
1354 if (ST.hasVDecCoExecHazard())
1356 const MachineOperand *SOffset =
1357 TII->getNamedOperand(
MI, AMDGPU::OpName::soffset);
1358 if (!SOffset || !SOffset->
isReg())
1367 if (TII->isMIMG(
MI)) {
1368 int SRsrcIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::srsrc);
1370 Desc.operands()[SRsrcIdx])) == 256);
1374 if (TII->isFLAT(
MI)) {
1386int GCNHazardRecognizer::checkUniformWindowVALUHazardsHelper(
1391 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1393 auto IsHazard = [&](
const MachineInstr &
MI) {
1394 int DataIdx = createsVALUHazard(
MI);
1395 return DataIdx >= 0 &&
1396 TRI->regsOverlap(
MI.getOperand(DataIdx).getReg(),
Reg);
1399 return std::max(0, 1 - getWaitStatesSince(IsHazard, 1));
1402int GCNHazardRecognizer::checkSOFFSETWindowVALUHazardsHelper(
1409 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1410 const SIInstrInfo *TII = ST.getInstrInfo();
1412 int WaitStatesNeeded = 0;
1416 for (
int Window = 1; Window <= 2; ++Window) {
1417 auto IsHazard = [&](
const MachineInstr &
MI) {
1418 int DataIdx = createsVALUHazard(
MI);
1420 !TRI->regsOverlap(
MI.getOperand(DataIdx).getReg(),
Reg))
1425 if (Window == 1 || !TII->isBUF(
MI))
1428 const MachineOperand *SOffset =
1429 TII->getNamedOperand(
MI, AMDGPU::OpName::soffset);
1430 return !SOffset || !SOffset->
isReg();
1432 WaitStatesNeeded = std::max(WaitStatesNeeded,
1433 Window - getWaitStatesSince(IsHazard, Window));
1436 return WaitStatesNeeded;
1439int GCNHazardRecognizer::checkVALUHazardsHelper(
1444 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1446 if (!TRI->isVectorRegister(MRI,
Def.getReg()))
1449 if (ST.hasVDecCoExecHazard())
1450 return checkSOFFSETWindowVALUHazardsHelper(
Def.getReg());
1452 return checkUniformWindowVALUHazardsHelper(
Def.getReg());
1468 unsigned Opcode =
MI.getOpcode();
1478 if (
auto *DstSel =
TII->getNamedOperand(
MI, AMDGPU::OpName::dst_sel))
1480 return TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
1486 if (
TII->getNamedImmOperand(
MI, AMDGPU::OpName::src0_modifiers) &
1488 return TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
1492 (
TII->getNamedImmOperand(
MI, AMDGPU::OpName::src2_modifiers) &
1494 return TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
1500 return TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
1521 for (
auto &Operand : VALU->operands()) {
1522 if (Operand.isReg() &&
TRI->regsOverlap(Dst->getReg(), Operand.getReg())) {
1529int GCNHazardRecognizer::checkVALUHazards(
MachineInstr *VALU)
const {
1530 int WaitStatesNeeded = 0;
1533 const int TransDefWaitstates = 1;
1535 auto IsTransDefFn = [
this,
VALU](
const MachineInstr &
MI) {
1538 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1539 const SIInstrInfo *TII = ST.getInstrInfo();
1540 Register Def = TII->getNamedOperand(
MI, AMDGPU::OpName::vdst)->getReg();
1542 for (
const MachineOperand &Use :
VALU->explicit_uses()) {
1543 if (
Use.isReg() && TRI->regsOverlap(Def,
Use.getReg()))
1550 int WaitStatesNeededForDef =
1551 TransDefWaitstates -
1552 getWaitStatesSince(IsTransDefFn, TransDefWaitstates);
1553 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1556 if (ST.hasDstSelForwardingHazard() || ST.hasCvtScaleForwardingHazard()) {
1557 const int Shift16DefWaitstates = 1;
1559 auto IsShift16BitDefFn = [
this,
VALU](
const MachineInstr &ProducerMI) {
1560 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1561 const MachineOperand *ForwardedDst =
1567 if (ProducerMI.isInlineAsm()) {
1569 for (
auto &Def : ProducerMI.all_defs()) {
1578 int WaitStatesNeededForDef =
1579 Shift16DefWaitstates -
1580 getWaitStatesSince(IsShift16BitDefFn, Shift16DefWaitstates);
1581 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1584 if (ST.hasVDecCoExecHazard()) {
1585 const int VALUWriteSGPRVALUReadWaitstates = 2;
1586 const int VALUWriteEXECRWLane = 4;
1587 const int VALUWriteVGPRReadlaneRead = 1;
1589 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1590 const MachineRegisterInfo &MRI = MF.getRegInfo();
1592 auto IsVALUDefSGPRFn = [&
UseReg, TRI](
const MachineInstr &
MI) {
1595 return MI.modifiesRegister(
UseReg, TRI);
1598 for (
const MachineOperand &Use :
VALU->explicit_uses()) {
1603 if (TRI->isSGPRReg(MRI,
UseReg)) {
1604 int WaitStatesNeededForDef =
1605 VALUWriteSGPRVALUReadWaitstates -
1606 getWaitStatesSince(IsVALUDefSGPRFn,
1607 VALUWriteSGPRVALUReadWaitstates);
1608 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1612 if (
VALU->readsRegister(AMDGPU::VCC, TRI)) {
1614 int WaitStatesNeededForDef =
1615 VALUWriteSGPRVALUReadWaitstates -
1616 getWaitStatesSince(IsVALUDefSGPRFn, VALUWriteSGPRVALUReadWaitstates);
1617 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1620 switch (
VALU->getOpcode()) {
1621 case AMDGPU::V_READLANE_B32:
1622 case AMDGPU::V_READFIRSTLANE_B32: {
1623 MachineOperand *Src = TII.getNamedOperand(*VALU, AMDGPU::OpName::src0);
1625 int WaitStatesNeededForDef =
1626 VALUWriteVGPRReadlaneRead -
1627 getWaitStatesSince(IsVALUDefSGPRFn, VALUWriteVGPRReadlaneRead);
1628 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1631 case AMDGPU::V_WRITELANE_B32: {
1633 int WaitStatesNeededForDef =
1634 VALUWriteEXECRWLane -
1635 getWaitStatesSince(IsVALUDefSGPRFn, VALUWriteEXECRWLane);
1636 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1646 if (!ST.has12DWordStoreHazard())
1647 return WaitStatesNeeded;
1649 const MachineRegisterInfo &MRI = MF.getRegInfo();
1651 for (
const MachineOperand &Def :
VALU->defs()) {
1652 WaitStatesNeeded = std::max(WaitStatesNeeded, checkVALUHazardsHelper(Def, MRI));
1655 return WaitStatesNeeded;
1658int GCNHazardRecognizer::checkInlineAsmHazards(
MachineInstr *IA)
const {
1667 if (!ST.has12DWordStoreHazard() && !ST.hasDstSelForwardingHazard() &&
1668 !ST.hasCvtScaleForwardingHazard())
1671 const MachineRegisterInfo &MRI = MF.getRegInfo();
1672 int WaitStatesNeeded = 0;
1674 for (
const MachineOperand &
Op :
1676 if (
Op.isReg() &&
Op.isDef()) {
1677 if (!TRI.isVectorRegister(MRI,
Op.getReg()))
1680 if (ST.has12DWordStoreHazard()) {
1682 std::max(WaitStatesNeeded, checkVALUHazardsHelper(
Op, MRI));
1687 if (ST.hasDstSelForwardingHazard()) {
1688 const int Shift16DefWaitstates = 1;
1690 auto IsShift16BitDefFn = [
this, &
IA](
const MachineInstr &ProducerMI) {
1694 return IA->modifiesRegister(Dst->getReg(), &TRI) ||
1695 IA->readsRegister(Dst->getReg(), &TRI);
1697 if (ProducerMI.isInlineAsm()) {
1699 for (
auto &Def : ProducerMI.all_defs()) {
1700 if (
IA->modifiesRegister(
Def.getReg(), &TRI) ||
1701 IA->readsRegister(
Def.getReg(), &TRI)) {
1710 int WaitStatesNeededForDef =
1711 Shift16DefWaitstates -
1712 getWaitStatesSince(IsShift16BitDefFn, Shift16DefWaitstates);
1713 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1716 return WaitStatesNeeded;
1719int GCNHazardRecognizer::checkRWLaneHazards(
MachineInstr *RWLane)
const {
1720 const SIInstrInfo *TII = ST.getInstrInfo();
1721 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1722 const MachineRegisterInfo &MRI = MF.getRegInfo();
1724 const MachineOperand *LaneSelectOp =
1725 TII->getNamedOperand(*RWLane, AMDGPU::OpName::src1);
1727 if (!LaneSelectOp->
isReg() || !TRI->isSGPRReg(MRI, LaneSelectOp->
getReg()))
1732 return TII->isVALU(
MI,
true);
1735 const int RWLaneWaitStates = 4;
1736 int WaitStatesSince = getWaitStatesSinceDef(LaneSelectReg,
IsHazardFn,
1738 return RWLaneWaitStates - WaitStatesSince;
1741int GCNHazardRecognizer::checkRFEHazards(
MachineInstr *RFE)
const {
1742 if (!ST.hasRFEHazards())
1745 const SIInstrInfo *TII = ST.getInstrInfo();
1747 const int RFEWaitStates = 1;
1752 int WaitStatesNeeded = getWaitStatesSinceSetReg(
IsHazardFn, RFEWaitStates);
1753 return RFEWaitStates - WaitStatesNeeded;
1756int GCNHazardRecognizer::checkReadM0Hazards(
MachineInstr *
MI)
const {
1757 const SIInstrInfo *TII = ST.getInstrInfo();
1758 const int ReadM0WaitStates = 1;
1759 auto IsHazardFn = [TII](
const MachineInstr &
MI) {
return TII->isSALU(
MI); };
1760 return ReadM0WaitStates -
1761 getWaitStatesSinceDef(AMDGPU::M0,
IsHazardFn, ReadM0WaitStates);
1766 int WaitStatesNeeded,
bool IsHoisting) {
1768 for (
int I = 0;
I < WaitStatesNeeded; ++
I)
1769 BuildMI(
MBB, InsertPt,
DL, TII.get(AMDGPU::V_NOP_e32));
1773 fixVMEMtoScalarWriteHazards(
MI);
1774 fixVcmpxPermlaneHazards(
MI);
1775 fixSMEMtoVectorWriteHazards(
MI);
1776 fixVcmpxExecWARHazard(
MI);
1777 fixLdsBranchVmemWARHazard(
MI);
1778 if (ST.hasLdsDirect()) {
1779 fixLdsDirectVALUHazard(
MI);
1780 fixLdsDirectVMEMHazard(
MI);
1782 fixVALUPartialForwardingHazard(
MI);
1783 fixVALUTransUseHazard(
MI);
1784 fixVALUTransCoexecutionHazards(
MI);
1786 fixWMMACoexecutionHazards(
MI);
1787 fixShift64HighRegBug(
MI);
1788 fixVALUMaskWriteHazard(
MI);
1789 fixRequiredExportPriority(
MI);
1790 if (ST.requiresWaitIdleBeforeGetReg())
1791 fixGetRegWaitIdle(
MI);
1792 if (ST.hasDsAtomicAsyncBarrierArriveB64PipeBug())
1793 fixDsAtomicAsyncBarrierArriveB64(
MI);
1794 if (ST.hasScratchBaseForwardingHazard())
1795 fixScratchBaseForwardingHazard(
MI);
1796 if (ST.setRegModeNeedsVNOPs())
1798 if (ST.hasNeedsTDMDrain())
1804 return (
TII.isVOPC(
MI) ||
1805 (
MI.isCompare() && (
TII.isVOP3(
MI) ||
TII.isSDWA(
MI)))) &&
1806 MI.modifiesRegister(AMDGPU::EXEC, &
TRI);
1809bool GCNHazardRecognizer::fixVcmpxPermlaneHazards(
MachineInstr *
MI) {
1813 const SIInstrInfo *TII = ST.getInstrInfo();
1814 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1820 unsigned Opc =
MI.getOpcode();
1822 Opc != AMDGPU::V_NOP_e32 &&
Opc != AMDGPU::V_NOP_e64 &&
1823 Opc != AMDGPU::V_NOP_sdwa;
1827 std::numeric_limits<int>::max())
1833 auto *Src0 = TII->getNamedOperand(*
MI, AMDGPU::OpName::src0);
1835 bool IsUndef = Src0->isUndef();
1837 TII->get(AMDGPU::V_MOV_B32_e32))
1844bool GCNHazardRecognizer::fixVMEMtoScalarWriteHazards(
MachineInstr *
MI) {
1845 if (!ST.hasVMEMtoScalarWriteHazard())
1847 assert(!ST.hasExtendedWaitCounts());
1852 if (
MI->getNumDefs() == 0)
1855 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1861 for (
const MachineOperand &Def :
MI->defs()) {
1862 const MachineOperand *
Op =
1863 I.findRegisterUseOperand(
Def.getReg(), TRI,
false);
1873 (
MI.getOpcode() == AMDGPU::S_WAITCNT &&
1874 !
MI.getOperand(0).getImm()) ||
1875 (
MI.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
1880 std::numeric_limits<int>::max())
1883 const SIInstrInfo *TII = ST.getInstrInfo();
1885 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
1890bool GCNHazardRecognizer::fixSMEMtoVectorWriteHazards(
MachineInstr *
MI) {
1891 if (!ST.hasSMEMtoVectorWriteHazard())
1893 assert(!ST.hasExtendedWaitCounts());
1898 AMDGPU::OpName SDSTName;
1899 switch (
MI->getOpcode()) {
1900 case AMDGPU::V_READLANE_B32:
1901 case AMDGPU::V_READFIRSTLANE_B32:
1902 SDSTName = AMDGPU::OpName::vdst;
1905 SDSTName = AMDGPU::OpName::sdst;
1909 const SIInstrInfo *TII = ST.getInstrInfo();
1910 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1912 const MachineOperand *SDST = TII->getNamedOperand(*
MI, SDSTName);
1914 for (
const auto &MO :
MI->implicit_operands()) {
1915 if (MO.isDef() && TRI->isSGPRClass(TRI->getPhysRegBaseClass(MO.getReg()))) {
1926 auto IsHazardFn = [SDSTReg, TRI](
const MachineInstr &
I) {
1931 if (TII->isSALU(
MI)) {
1932 switch (
MI.getOpcode()) {
1933 case AMDGPU::S_SETVSKIP:
1934 case AMDGPU::S_VERSION:
1935 case AMDGPU::S_WAITCNT_VSCNT:
1936 case AMDGPU::S_WAITCNT_VMCNT:
1937 case AMDGPU::S_WAITCNT_EXPCNT:
1940 case AMDGPU::S_WAITCNT_LGKMCNT:
1942 return (
MI.getOperand(1).getImm() == 0) &&
1943 (
MI.getOperand(0).
getReg() == AMDGPU::SGPR_NULL);
1944 case AMDGPU::S_WAITCNT: {
1945 const int64_t
Imm =
MI.getOperand(0).getImm();
1952 MI.getOpcode() == AMDGPU::S_WAIT_IDLE) &&
1953 "unexpected wait count instruction");
1955 if (TII->isSOPP(
MI))
1971 std::numeric_limits<int>::max())
1975 TII->get(AMDGPU::S_MOV_B32), AMDGPU::SGPR_NULL)
1980bool GCNHazardRecognizer::fixVcmpxExecWARHazard(
MachineInstr *
MI) {
1981 if (!ST.hasVcmpxExecWARHazard())
1983 assert(!ST.hasExtendedWaitCounts());
1988 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1989 if (!
MI->modifiesRegister(AMDGPU::EXEC, TRI))
1995 return I.readsRegister(AMDGPU::EXEC, TRI);
1998 const SIInstrInfo *TII = ST.getInstrInfo();
1999 auto IsExpiredFn = [TII, TRI](
const MachineInstr &
MI, int) {
2001 if (TII->getNamedOperand(
MI, AMDGPU::OpName::sdst))
2003 for (
auto MO :
MI.implicit_operands())
2004 if (MO.isDef() && TRI->isSGPRClass(TRI->getPhysRegBaseClass(MO.getReg())))
2007 if (
MI.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2014 std::numeric_limits<int>::max())
2018 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
2025 if (!ST.hasLdsBranchVmemWARHazard())
2030 bool HasLds =
false;
2031 bool HasVmem =
false;
2032 for (
auto &
MBB : MF) {
2033 for (
auto &
MI :
MBB) {
2036 if (HasLds && HasVmem)
2044 return I.getOpcode() == AMDGPU::S_WAITCNT_VSCNT &&
2045 I.getOperand(0).getReg() == AMDGPU::SGPR_NULL &&
2046 !
I.getOperand(1).getImm();
2049bool GCNHazardRecognizer::fixLdsBranchVmemWARHazard(
MachineInstr *
MI) {
2050 if (!RunLdsBranchVmemWARHazardFixup)
2053 assert(ST.hasLdsBranchVmemWARHazard());
2054 assert(!ST.hasExtendedWaitCounts());
2056 auto IsHazardInst = [](
const MachineInstr &
MI) {
2064 auto InstType = IsHazardInst(*
MI);
2068 auto IsExpiredFn = [&IsHazardInst](
const MachineInstr &
I, int) {
2072 auto IsHazardFn = [InstType, &IsHazardInst](
const MachineInstr &
I) {
2076 auto IsHazardFn = [InstType, IsHazardInst](
const MachineInstr &
I) {
2077 auto InstType2 = IsHazardInst(
I);
2078 return InstType2 && InstType != InstType2;
2081 auto IsExpiredFn = [InstType, &IsHazardInst](
const MachineInstr &
I, int) {
2082 auto InstType2 = IsHazardInst(
I);
2083 if (InstType == InstType2)
2090 std::numeric_limits<int>::max();
2094 std::numeric_limits<int>::max())
2097 const SIInstrInfo *TII = ST.getInstrInfo();
2099 TII->get(AMDGPU::S_WAITCNT_VSCNT))
2106bool GCNHazardRecognizer::fixLdsDirectVALUHazard(
MachineInstr *
MI) {
2110 const int NoHazardWaitStates = 15;
2111 const MachineOperand *VDST = TII.getNamedOperand(*
MI, AMDGPU::OpName::vdst);
2114 bool VisitedTrans =
false;
2115 auto IsHazardFn = [
this, VDSTReg, &VisitedTrans](
const MachineInstr &
I) {
2120 return I.readsRegister(VDSTReg, &TRI) ||
I.modifiesRegister(VDSTReg, &TRI);
2122 auto IsExpiredFn = [&](
const MachineInstr &
I,
int WaitStates) {
2123 if (WaitStates >= NoHazardWaitStates)
2129 auto GetWaitStatesFn = [](
const MachineInstr &
MI) {
2133 DenseSet<const MachineBasicBlock *> Visited;
2135 std::next(
MI->getReverseIterator()), 0,
2143 MachineOperand *WaitVdstOp =
2144 TII.getNamedOperand(*
MI, AMDGPU::OpName::waitvdst);
2145 WaitVdstOp->
setImm(std::min(
Count, NoHazardWaitStates));
2150bool GCNHazardRecognizer::fixLdsDirectVMEMHazard(
MachineInstr *
MI) {
2154 const MachineOperand *VDST = TII.getNamedOperand(*
MI, AMDGPU::OpName::vdst);
2157 auto IsHazardFn = [
this, VDSTReg](
const MachineInstr &
I) {
2160 return I.readsRegister(VDSTReg, &TRI) ||
I.modifiesRegister(VDSTReg, &TRI);
2162 bool LdsdirCanWait = ST.hasLdsWaitVMSRC();
2165 auto IsExpiredFn = [
this, LdsdirCanWait](
const MachineInstr &
I, int) {
2168 (
I.getOpcode() == AMDGPU::S_WAITCNT && !
I.getOperand(0).getImm()) ||
2169 (
I.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2172 !TII.getNamedOperand(
I, AMDGPU::OpName::waitvsrc)->getImm());
2176 std::numeric_limits<int>::max())
2179 if (LdsdirCanWait) {
2180 TII.getNamedOperand(*
MI, AMDGPU::OpName::waitvsrc)->setImm(0);
2183 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
2190bool GCNHazardRecognizer::fixVALUPartialForwardingHazard(
MachineInstr *
MI) {
2191 if (!ST.hasVALUPartialForwardingHazard())
2193 assert(!ST.hasExtendedWaitCounts());
2198 SmallSetVector<Register, 4> SrcVGPRs;
2200 for (
const MachineOperand &Use :
MI->explicit_uses()) {
2201 if (
Use.isReg() && TRI.isVGPR(MF.getRegInfo(),
Use.getReg()))
2206 if (SrcVGPRs.
size() <= 1)
2224 const int Intv1plus2MaxVALUs = 2;
2225 const int Intv3MaxVALUs = 4;
2226 const int IntvMaxVALUs = 6;
2227 const int NoHazardVALUWaitStates = IntvMaxVALUs + 2;
2230 SmallDenseMap<Register, int, 4> DefPos;
2231 int ExecPos = std::numeric_limits<int>::max();
2234 static unsigned getHashValue(
const StateType &State) {
2236 for (
const auto &[
Reg, Pos] : State.DefPos)
2240 static bool isEqual(
const StateType &
LHS,
const StateType &
RHS) {
2241 return LHS.DefPos ==
RHS.DefPos &&
LHS.ExecPos ==
RHS.ExecPos &&
2249 auto IsHazardFn = [&,
this](StateType &State,
const MachineInstr &
I) {
2251 if (State.VALUs > NoHazardVALUWaitStates)
2257 (
I.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2265 if (!State.DefPos.count(Src) &&
I.modifiesRegister(Src, &TRI)) {
2266 State.DefPos[Src] = State.VALUs;
2271 if (State.ExecPos == std::numeric_limits<int>::max()) {
2272 if (!State.DefPos.empty() &&
I.modifiesRegister(AMDGPU::EXEC, &TRI)) {
2273 State.ExecPos = State.VALUs;
2280 if (State.VALUs > Intv3MaxVALUs && State.DefPos.empty())
2288 if (State.ExecPos == std::numeric_limits<int>::max())
2291 int PreExecPos = std::numeric_limits<int>::max();
2292 int PostExecPos = std::numeric_limits<int>::max();
2294 for (
auto Entry : State.DefPos) {
2295 int DefVALUs =
Entry.second;
2296 if (DefVALUs != std::numeric_limits<int>::max()) {
2297 if (DefVALUs >= State.ExecPos)
2298 PreExecPos = std::min(PreExecPos, DefVALUs);
2300 PostExecPos = std::min(PostExecPos, DefVALUs);
2305 if (PostExecPos == std::numeric_limits<int>::max())
2309 int Intv3VALUs = PostExecPos;
2310 if (Intv3VALUs > Intv3MaxVALUs)
2314 int Intv2VALUs = (State.ExecPos - PostExecPos) - 1;
2315 if (Intv2VALUs > Intv1plus2MaxVALUs)
2319 if (PreExecPos == std::numeric_limits<int>::max())
2323 int Intv1VALUs = PreExecPos - State.ExecPos;
2324 if (Intv1VALUs > Intv1plus2MaxVALUs)
2328 if (Intv1VALUs + Intv2VALUs > Intv1plus2MaxVALUs)
2333 auto UpdateStateFn = [](StateType &State,
const MachineInstr &
MI) {
2339 std::next(
MI->getReverseIterator())))
2343 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
2349bool GCNHazardRecognizer::fixVALUTransUseHazard(
MachineInstr *
MI) {
2350 if (!ST.hasVALUTransUseHazard())
2352 assert(!ST.hasExtendedWaitCounts());
2357 SmallSet<Register, 4> SrcVGPRs;
2359 for (
const MachineOperand &Use :
MI->explicit_uses()) {
2360 if (
Use.isReg() && TRI.isVGPR(MF.getRegInfo(),
Use.getReg()))
2374 const int IntvMaxVALUs = 5;
2375 const int IntvMaxTRANS = 1;
2381 static unsigned getHashValue(
const StateType &State) {
2384 static bool isEqual(
const StateType &
LHS,
const StateType &
RHS) {
2385 return LHS.VALUs ==
RHS.VALUs &&
LHS.TRANS ==
RHS.TRANS;
2392 auto IsHazardFn = [&,
this](StateType &State,
const MachineInstr &
I) {
2394 if (State.VALUs > IntvMaxVALUs || State.TRANS > IntvMaxTRANS)
2400 (
I.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2407 if (
I.modifiesRegister(Src, &TRI)) {
2415 auto UpdateStateFn = [](StateType &State,
const MachineInstr &
MI) {
2423 std::next(
MI->getReverseIterator())))
2429 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
2435bool GCNHazardRecognizer::fixVALUTransCoexecutionHazards(
MachineInstr *
MI) {
2436 if (!ST.hasTransCoexecutionHazard() ||
2441 const SIInstrInfo *TII = ST.getInstrInfo();
2442 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2444 auto IsTransHazardFn = [
MI, TII, TRI](
const MachineInstr &
I) {
2449 Register TransDef = TII->getNamedOperand(
I, AMDGPU::OpName::vdst)->getReg();
2450 for (
const MachineOperand &ValuUse :
MI->explicit_uses()) {
2451 if (ValuUse.isReg() && TRI->regsOverlap(TransDef, ValuUse.getReg()))
2455 auto *ValuDst = TII->getNamedOperand(*
MI, AMDGPU::OpName::vdst);
2456 if (!ValuDst || !ValuDst->isReg())
2460 Register ValuDef = ValuDst->getReg();
2461 for (
const MachineOperand &TransUse :
I.explicit_uses()) {
2462 if (TransUse.isReg() && TRI->regsOverlap(ValuDef, TransUse.getReg()))
2473 const int HasVALU = std::numeric_limits<int>::max();
2474 if (::getWaitStatesSince(IsTransHazardFn,
MI,
IsExpiredFn) == HasVALU)
2477 BuildMI(*
MI->getParent(),
MI,
MI->getDebugLoc(), TII->get(AMDGPU::V_NOP_e32));
2485 const SIInstrInfo *TII = ST.getInstrInfo();
2486 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2488 auto IsHazardFn = [
MI, TII, TRI,
this](
const MachineInstr &
I) {
2495 TII->getNamedOperand(*
MI, AMDGPU::OpName::src0)->getReg();
2497 TII->getNamedOperand(*
MI, AMDGPU::OpName::src1)->getReg();
2500 TII->getNamedOperand(
I, AMDGPU::OpName::vdst)->getReg();
2502 if (TRI->regsOverlap(PrevDstReg, CurSrc0Reg) ||
2503 TRI->regsOverlap(PrevDstReg, CurSrc1Reg)) {
2512 TII->getNamedOperand(*
MI, AMDGPU::OpName::src2)->getReg();
2513 if (TRI->regsOverlap(PrevDstReg, CurIndex))
2527 std::numeric_limits<int>::max())
2530 BuildMI(*
MI->getParent(),
MI,
MI->getDebugLoc(), TII->get(AMDGPU::V_NOP_e32));
2584 bool IsLowestRateWMMA = ST.hasGFX125xLowestRateWMMA();
2585 unsigned Category = 0;
2587 unsigned Latency = SchedModel.computeInstrLatency(&
MI);
2592 assert(!IsSWMMAC &&
"no 4-cycle SWMMAC expected");
2596 Category = IsSWMMAC ? 2 : 0;
2599 Category = IsLowestRateWMMA ? 4 : (IsSWMMAC ? 3 : 1);
2602 assert(IsLowestRateWMMA &&
"latency 32 is not expected");
2612int GCNHazardRecognizer::checkWMMACoexecutionHazards(
MachineInstr *
MI)
const {
2613 if (!ST.hasWMMACoexecutionHazards())
2616 const SIInstrInfo *TII = ST.getInstrInfo();
2625 const int WMMAWaitStates[] = {5, 9, 3, 5, 9, 17, 2};
2626 const int VALUWaitStates[] = {4, 8, 2, 4, 8, 16, 1};
2627 unsigned Category = 0;
2629 auto IsWMMAHazardFn = [
MI, TII, &Category,
this](
const MachineInstr &
I) {
2630 if (!TII->isXDLWMMA(
I))
2634 return hasWMMAToWMMARegOverlap(
I, *
MI);
2637 auto IsVALUHazardFn = [
MI, TII, &Category,
this](
const MachineInstr &
I) {
2638 if (!TII->isXDLWMMA(
I))
2642 return hasWMMAToVALURegOverlap(
I, *
MI);
2645 int WaitStatesNeeded = -1;
2646 int ExistingVALUs = 0;
2647 bool IsLowestRateWMMA = ST.hasGFX125xLowestRateWMMA();
2655 if (TII->isXDLWMMA(*
MI)) {
2657 const int WMMAWaitsLimit = IsLowestRateWMMA ? 17 : 9;
2658 ExistingVALUs = getWaitStatesSinceVALU(IsWMMAHazardFn, WMMAWaitsLimit);
2659 WaitStatesNeeded = WMMAWaitStates[Category] - ExistingVALUs;
2662 const int VALUWaitsLimit = IsLowestRateWMMA ? 16 : 8;
2663 ExistingVALUs = getWaitStatesSinceVALU(IsVALUHazardFn, VALUWaitsLimit);
2664 WaitStatesNeeded = VALUWaitStates[Category] - ExistingVALUs;
2667 return WaitStatesNeeded;
2670bool GCNHazardRecognizer::hasWMMAToWMMARegOverlap(
2672 Register D0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::vdst)->getReg();
2673 Register A1 = TII.getNamedOperand(
MI, AMDGPU::OpName::src0)->getReg();
2674 Register B1 = TII.getNamedOperand(
MI, AMDGPU::OpName::src1)->getReg();
2677 if (TRI.regsOverlap(D0, A1) || TRI.regsOverlap(D0, B1))
2681 Register Idx1 = TII.getNamedOperand(
MI, AMDGPU::OpName::src2)->getReg();
2682 if (TRI.regsOverlap(D0, Idx1))
2688bool GCNHazardRecognizer::hasWMMAToVALURegOverlap(
2691 Register D0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::vdst)->getReg();
2692 for (
const MachineOperand &ValuUse :
MI.explicit_uses()) {
2693 if (ValuUse.isReg() && TRI.regsOverlap(D0, ValuUse.getReg()))
2698 Register A0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::src0)->getReg();
2699 Register B0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::src1)->getReg();
2703 Register Idx0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::src2)->getReg();
2704 WMMARegs.push_back(Idx0);
2707 for (
const MachineOperand &ValuDef :
MI.defs()) {
2708 Register VDstReg = ValuDef.getReg();
2709 for (
Register WMMAReg : WMMARegs) {
2710 if (TRI.regsOverlap(VDstReg, WMMAReg))
2717bool GCNHazardRecognizer::isCoexecutionHazardFor(
const MachineInstr &
I,
2721 if (!TII.isXDLWMMA(
I))
2725 if (TII.isXDLWMMA(
MI))
2726 return hasWMMAToWMMARegOverlap(
I,
MI);
2728 return hasWMMAToVALURegOverlap(
I,
MI);
2734 bool IncludeSubloops) {
2737 for (MachineBasicBlock *
MBB :
L->getBlocks()) {
2738 if (!IncludeSubloops && MLI->getLoopFor(
MBB) != L)
2740 for (MachineInstr &
I : *
MBB) {
2743 if (isCoexecutionHazardFor(
I, *
MI))
2750bool GCNHazardRecognizer::tryHoistWMMAVnopsFromLoop(
MachineInstr *
MI,
2751 int WaitStatesNeeded) {
2755 MachineLoop *
L = MLI->getLoopFor(
MI->getParent());
2757 ++NumWMMAHoistingBailed;
2762 if (hasWMMAHazardInLoop(L,
MI)) {
2763 ++NumWMMAHoistingBailed;
2768 MachineLoop *TargetLoop =
L;
2770 if (hasWMMAHazardInLoop(Parent,
MI,
false))
2772 TargetLoop = Parent;
2778 ++NumWMMAHoistingBailed;
2782 LLVM_DEBUG(
dbgs() <<
"WMMA V_NOP Hoisting: Moving " << WaitStatesNeeded
2788 NumWMMANopsHoisted += WaitStatesNeeded;
2792bool GCNHazardRecognizer::fixWMMACoexecutionHazards(
MachineInstr *
MI) {
2793 int WaitStatesNeeded = checkWMMACoexecutionHazards(
MI);
2794 if (WaitStatesNeeded <= 0)
2800 emitVNops(*
MI->getParent(),
MI->getIterator(), WaitStatesNeeded);
2804bool GCNHazardRecognizer::fixShift64HighRegBug(
MachineInstr *
MI) {
2805 if (!ST.hasShift64HighRegBug())
2807 assert(!ST.hasExtendedWaitCounts());
2809 switch (
MI->getOpcode()) {
2812 case AMDGPU::V_LSHLREV_B64_e64:
2813 case AMDGPU::V_LSHRREV_B64_e64:
2814 case AMDGPU::V_ASHRREV_I64_e64:
2818 MachineOperand *Amt = TII.getNamedOperand(*
MI, AMDGPU::OpName::src0);
2823 const MachineRegisterInfo &MRI = MF.getRegInfo();
2825 if (!TRI.isVGPR(MRI, AmtReg) || ((AmtReg - AMDGPU::VGPR0) & 7) != 7)
2828 if (AmtReg != AMDGPU::VGPR255 && MRI.
isPhysRegUsed(AmtReg + 1))
2831 assert(ST.needsAlignedVGPRs());
2832 static_assert(AMDGPU::VGPR0 + 1 == AMDGPU::VGPR1);
2836 MachineOperand *Src1 = TII.getNamedOperand(*
MI, AMDGPU::OpName::src1);
2847 Register DstReg =
MI->getOperand(0).getReg();
2849 Register DstLo = TRI.getSubReg(DstReg, AMDGPU::sub0);
2857 bool Overlapped =
MI->modifiesRegister(AmtReg, &TRI);
2859 for (MCRegister
Reg : Overlapped ? AMDGPU::VReg_64_Align2RegClass
2860 : AMDGPU::VGPR_32RegClass) {
2861 if (!
MI->modifiesRegister(
Reg, &TRI) && !
MI->readsRegister(
Reg, &TRI)) {
2867 Register NewAmt = Overlapped ? (
Register)TRI.getSubReg(NewReg, AMDGPU::sub1)
2872 NewAmtLo = TRI.getSubReg(NewReg, AMDGPU::sub0);
2885 runOnInstruction(
BuildMI(*
MBB,
MI,
DL, TII.get(AMDGPU::V_SWAP_B32), NewAmt)
2892 BuildMI(*
MBB, std::next(
MI->getIterator()),
DL, TII.get(AMDGPU::V_SWAP_B32),
2898 BuildMI(*
MBB, std::next(
MI->getIterator()),
DL, TII.get(AMDGPU::V_SWAP_B32),
2912 MI->getOperand(0).setReg(NewReg);
2921int GCNHazardRecognizer::checkNSAtoVMEMHazard(
MachineInstr *
MI)
const {
2922 int NSAtoVMEMWaitStates = 1;
2924 if (!ST.hasNSAtoVMEMBug())
2930 const SIInstrInfo *TII = ST.getInstrInfo();
2931 const auto *
Offset = TII->getNamedOperand(*
MI, AMDGPU::OpName::offset);
2939 return Info->MIMGEncoding == AMDGPU::MIMGEncGfx10NSA &&
2940 TII->getInstSizeInBytes(
I) >= 16;
2943 return NSAtoVMEMWaitStates - getWaitStatesSince(
IsHazardFn, 1);
2946int GCNHazardRecognizer::checkFPAtomicToDenormModeHazard(
2948 int FPAtomicToDenormModeWaitStates = 3;
2950 if (!ST.hasFPAtomicToDenormModeHazard())
2952 assert(!ST.hasExtendedWaitCounts());
2954 if (
MI->getOpcode() != AMDGPU::S_DENORM_MODE)
2963 auto IsExpiredFn = [](
const MachineInstr &
MI,
int WaitStates) {
2970 return FPAtomicToDenormModeWaitStates -
2974int GCNHazardRecognizer::checkMAIHazards(
MachineInstr *
MI)
const {
2977 return ST.hasGFX90AInsts() ? checkMAIHazards90A(
MI) : checkMAIHazards908(
MI);
2980int GCNHazardRecognizer::checkMFMAPadding(
MachineInstr *
MI)
const {
2985 const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
2989 int NeighborMFMALatency = 0;
2990 auto IsNeighboringMFMA = [&NeighborMFMALatency,
2991 this](
const MachineInstr &
MI) {
2995 NeighborMFMALatency = this->getMFMAPipelineWaitStates(
MI);
2999 const int MaxMFMAPipelineWaitStates = 16;
3000 int WaitStatesSinceNeighborMFMA =
3001 getWaitStatesSince(IsNeighboringMFMA, MaxMFMAPipelineWaitStates);
3003 int NeighborMFMAPaddingNeeded =
3005 WaitStatesSinceNeighborMFMA;
3007 return std::max(0, NeighborMFMAPaddingNeeded);
3010int GCNHazardRecognizer::checkMAIHazards908(
MachineInstr *
MI)
const {
3011 int WaitStatesNeeded = 0;
3012 unsigned Opc =
MI->getOpcode();
3014 auto IsVALUFn = [](
const MachineInstr &
MI) {
3018 if (
Opc != AMDGPU::V_ACCVGPR_READ_B32_e64) {
3019 const int LegacyVALUWritesVGPRWaitStates = 2;
3020 const int VALUWritesExecWaitStates = 4;
3021 const int MaxWaitStates = 4;
3023 int WaitStatesNeededForUse = VALUWritesExecWaitStates -
3024 getWaitStatesSinceDef(AMDGPU::EXEC, IsVALUFn, MaxWaitStates);
3025 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3027 if (WaitStatesNeeded < MaxWaitStates) {
3028 for (
const MachineOperand &Use :
MI->explicit_uses()) {
3029 const int MaxWaitStates = 2;
3031 if (!
Use.isReg() || !TRI.isVGPR(MF.getRegInfo(),
Use.getReg()))
3034 int WaitStatesNeededForUse = LegacyVALUWritesVGPRWaitStates -
3035 getWaitStatesSinceDef(
Use.getReg(), IsVALUFn, MaxWaitStates);
3036 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3038 if (WaitStatesNeeded == MaxWaitStates)
3044 for (
const MachineOperand &
Op :
MI->explicit_operands()) {
3045 if (!
Op.isReg() || !TRI.isAGPR(MF.getRegInfo(),
Op.getReg()))
3048 if (
Op.isDef() &&
Opc != AMDGPU::V_ACCVGPR_WRITE_B32_e64)
3051 const int MFMAWritesAGPROverlappedSrcABWaitStates = 4;
3052 const int MFMAWritesAGPROverlappedSrcCWaitStates = 2;
3053 const int MFMA4x4WritesAGPRAccVgprReadWaitStates = 4;
3054 const int MFMA16x16WritesAGPRAccVgprReadWaitStates = 10;
3055 const int MFMA32x32WritesAGPRAccVgprReadWaitStates = 18;
3056 const int MFMA4x4WritesAGPRAccVgprWriteWaitStates = 1;
3057 const int MFMA16x16WritesAGPRAccVgprWriteWaitStates = 7;
3058 const int MFMA32x32WritesAGPRAccVgprWriteWaitStates = 15;
3059 const int MaxWaitStates = 18;
3061 unsigned HazardDefLatency = 0;
3063 auto IsOverlappedMFMAFn = [
Reg, &HazardDefLatency,
3064 this](
const MachineInstr &
MI) {
3071 std::max(HazardDefLatency, TSchedModel.computeInstrLatency(&
MI));
3072 return TRI.regsOverlap(DstReg,
Reg);
3075 int WaitStatesSinceDef = getWaitStatesSinceDef(
Reg, IsOverlappedMFMAFn,
3077 int NeedWaitStates = MFMAWritesAGPROverlappedSrcABWaitStates;
3078 int SrcCIdx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src2);
3079 int OpNo =
Op.getOperandNo();
3080 if (OpNo == SrcCIdx) {
3081 NeedWaitStates = MFMAWritesAGPROverlappedSrcCWaitStates;
3082 }
else if (
Opc == AMDGPU::V_ACCVGPR_READ_B32_e64) {
3083 switch (HazardDefLatency) {
3084 case 2: NeedWaitStates = MFMA4x4WritesAGPRAccVgprReadWaitStates;
3086 case 8: NeedWaitStates = MFMA16x16WritesAGPRAccVgprReadWaitStates;
3088 case 16: [[fallthrough]];
3089 default: NeedWaitStates = MFMA32x32WritesAGPRAccVgprReadWaitStates;
3092 }
else if (
Opc == AMDGPU::V_ACCVGPR_WRITE_B32_e64) {
3093 switch (HazardDefLatency) {
3094 case 2: NeedWaitStates = MFMA4x4WritesAGPRAccVgprWriteWaitStates;
3096 case 8: NeedWaitStates = MFMA16x16WritesAGPRAccVgprWriteWaitStates;
3098 case 16: [[fallthrough]];
3099 default: NeedWaitStates = MFMA32x32WritesAGPRAccVgprWriteWaitStates;
3104 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceDef;
3105 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3107 if (WaitStatesNeeded == MaxWaitStates)
3108 return WaitStatesNeeded;
3110 auto IsAccVgprWriteFn = [
Reg,
this](
const MachineInstr &
MI) {
3111 if (
MI.getOpcode() != AMDGPU::V_ACCVGPR_WRITE_B32_e64)
3114 return TRI.regsOverlap(
Reg, DstReg);
3117 const int AccVGPRWriteMFMAReadSrcCWaitStates = 1;
3118 const int AccVGPRWriteMFMAReadSrcABWaitStates = 3;
3119 const int AccVGPRWriteAccVgprReadWaitStates = 3;
3120 NeedWaitStates = AccVGPRWriteMFMAReadSrcABWaitStates;
3121 if (OpNo == SrcCIdx)
3122 NeedWaitStates = AccVGPRWriteMFMAReadSrcCWaitStates;
3123 else if (
Opc == AMDGPU::V_ACCVGPR_READ_B32_e64)
3124 NeedWaitStates = AccVGPRWriteAccVgprReadWaitStates;
3126 WaitStatesNeededForUse = NeedWaitStates -
3127 getWaitStatesSinceDef(
Reg, IsAccVgprWriteFn, MaxWaitStates);
3128 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3130 if (WaitStatesNeeded == MaxWaitStates)
3131 return WaitStatesNeeded;
3134 if (
Opc == AMDGPU::V_ACCVGPR_WRITE_B32_e64) {
3135 const int MFMA4x4ReadSrcCAccVgprWriteWaitStates = 0;
3136 const int MFMA16x16ReadSrcCAccVgprWriteWaitStates = 5;
3137 const int MFMA32x32ReadSrcCAccVgprWriteWaitStates = 13;
3138 const int MaxWaitStates = 13;
3139 Register DstReg =
MI->getOperand(0).getReg();
3140 unsigned HazardDefLatency = 0;
3142 auto IsSrcCMFMAFn = [DstReg, &HazardDefLatency,
3143 this](
const MachineInstr &
MI) {
3146 Register Reg = TII.getNamedOperand(
MI, AMDGPU::OpName::src2)->getReg();
3148 std::max(HazardDefLatency, TSchedModel.computeInstrLatency(&
MI));
3149 return TRI.regsOverlap(
Reg, DstReg);
3152 int WaitStatesSince = getWaitStatesSince(IsSrcCMFMAFn, MaxWaitStates);
3154 switch (HazardDefLatency) {
3155 case 2: NeedWaitStates = MFMA4x4ReadSrcCAccVgprWriteWaitStates;
3157 case 8: NeedWaitStates = MFMA16x16ReadSrcCAccVgprWriteWaitStates;
3159 case 16: [[fallthrough]];
3160 default: NeedWaitStates = MFMA32x32ReadSrcCAccVgprWriteWaitStates;
3164 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSince;
3165 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3169 WaitStatesNeeded = std::max(WaitStatesNeeded, checkMFMAPadding(
MI));
3171 return WaitStatesNeeded;
3182 return NumPasses + 1 + IsGFX950;
3193 return NumPasses + 1 + (NumPasses != 2 && IsGFX950);
3211 return NumPasses + 2;
3221 return NumPasses + 3 + (NumPasses != 2 && IsGFX950);
3224int GCNHazardRecognizer::checkMAIHazards90A(
MachineInstr *
MI)
const {
3225 int WaitStatesNeeded = 0;
3226 unsigned Opc =
MI->getOpcode();
3228 auto IsLegacyVALUFn = [](
const MachineInstr &
MI) {
3233 auto IsLegacyVALUNotDotFn = [](
const MachineInstr &
MI) {
3239 return WaitStatesNeeded;
3241 const int VALUWritesExecWaitStates = 4;
3242 int WaitStatesNeededForUse = VALUWritesExecWaitStates -
3243 getWaitStatesSinceDef(AMDGPU::EXEC, IsLegacyVALUFn,
3244 VALUWritesExecWaitStates);
3245 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3247 int SrcCIdx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src2);
3250 for (
const MachineOperand &Use :
MI->explicit_uses()) {
3251 const int LegacyVALUNotDotWritesVGPRWaitStates = 2;
3252 const int SMFMA4x4WritesVGPROverlappedSMFMASrcCWaitStates = 2;
3253 const int SMFMA16x16WritesVGPROverlappedSMFMASrcCWaitStates = 8;
3254 const int SMFMA32x32WritesVGPROverlappedSMFMASrcCWaitStates = 16;
3255 const int SMFMA4x4WritesVGPROverlappedDMFMASrcCWaitStates = 3;
3256 const int SMFMA16x16WritesVGPROverlappedDMFMASrcCWaitStates = 9;
3257 const int SMFMA32x32WritesVGPROverlappedDMFMASrcCWaitStates = 17;
3258 const int DMFMA16x16WritesVGPROverlappedSrcCWaitStates = 9;
3259 const int GFX950_DMFMA16x16WritesVGPROverlappedSrcCWaitStates = 17;
3260 const int DMFMA4x4WritesVGPROverlappedSrcCWaitStates = 4;
3261 const int SMFMA4x4WritesVGPROverlappedSrcABWaitStates = 5;
3262 const int SMFMA16x16WritesVGPROverlappedSrcABWaitStates = 11;
3263 const int SMFMA32x32WritesVGPROverlappedSrcABWaitStates = 19;
3264 const int DMFMA4x4WritesVGPROverlappedMFMASrcABWaitStates = 6;
3265 const int DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates = 11;
3266 const int GFX950_DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates = 19;
3267 const int DMFMA4x4WritesVGPRFullSrcCWaitStates = 4;
3268 const int GFX940_SMFMA4x4WritesVGPRFullSrcCWaitStates = 2;
3269 const int MaxWaitStates = 19;
3275 const MachineInstr *MI1;
3277 auto IsOverlappedMFMAFn = [
Reg, &FullReg, &MI1,
3278 this](
const MachineInstr &
MI) {
3282 FullReg = (DstReg ==
Reg);
3284 return TRI.regsOverlap(DstReg,
Reg);
3287 WaitStatesNeededForUse = LegacyVALUNotDotWritesVGPRWaitStates -
3288 getWaitStatesSinceDef(
Reg, IsLegacyVALUNotDotFn, MaxWaitStates);
3289 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3292 getWaitStatesSinceDef(
Reg, IsOverlappedMFMAFn, MaxWaitStates);
3293 if (NumWaitStates == std::numeric_limits<int>::max())
3296 int OpNo =
Use.getOperandNo();
3298 int NeedWaitStates = 0;
3299 if (OpNo == SrcCIdx) {
3303 }
else if (FullReg) {
3304 if ((
Opc == AMDGPU::V_MFMA_F64_4X4X4F64_e64 ||
3305 Opc == AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64) &&
3306 (Opc1 == AMDGPU::V_MFMA_F64_4X4X4F64_e64 ||
3307 Opc1 == AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64))
3308 NeedWaitStates = DMFMA4x4WritesVGPRFullSrcCWaitStates;
3309 else if (ST.hasGFX940Insts() &&
3310 TSchedModel.computeInstrLatency(MI1) == 2)
3311 NeedWaitStates = GFX940_SMFMA4x4WritesVGPRFullSrcCWaitStates;
3314 case AMDGPU::V_MFMA_F64_16X16X4F64_e64:
3315 case AMDGPU::V_MFMA_F64_16X16X4F64_vgprcd_e64:
3316 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_e64:
3317 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_vgprcd_e64:
3318 if (!TII.isXDL(*
MI))
3321 ? GFX950_DMFMA16x16WritesVGPROverlappedSrcCWaitStates
3322 : DMFMA16x16WritesVGPROverlappedSrcCWaitStates;
3324 case AMDGPU::V_MFMA_F64_4X4X4F64_e64:
3325 case AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64:
3326 if (!TII.isXDL(*
MI))
3327 NeedWaitStates = DMFMA4x4WritesVGPROverlappedSrcCWaitStates;
3330 int NumPasses = TSchedModel.computeInstrLatency(MI1);
3331 if (ST.hasGFX940Insts()) {
3332 if (TII.isXDL(*
MI) && !TII.isXDL(*MI1))
3339 NumPasses, ST.hasGFX950Insts())
3341 NumPasses, ST.hasGFX950Insts()))
3347 switch (NumPasses) {
3351 ? SMFMA4x4WritesVGPROverlappedDMFMASrcCWaitStates
3352 : SMFMA4x4WritesVGPROverlappedSMFMASrcCWaitStates;
3357 ? SMFMA16x16WritesVGPROverlappedDMFMASrcCWaitStates
3358 : SMFMA16x16WritesVGPROverlappedSMFMASrcCWaitStates;
3363 ? SMFMA32x32WritesVGPROverlappedDMFMASrcCWaitStates
3364 : SMFMA32x32WritesVGPROverlappedSMFMASrcCWaitStates;
3373 case AMDGPU::V_MFMA_F64_16X16X4F64_e64:
3374 case AMDGPU::V_MFMA_F64_16X16X4F64_vgprcd_e64:
3375 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_e64:
3376 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_vgprcd_e64:
3379 ? GFX950_DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates
3380 : DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates;
3382 case AMDGPU::V_MFMA_F64_4X4X4F64_e64:
3383 case AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64:
3384 NeedWaitStates = DMFMA4x4WritesVGPROverlappedMFMASrcABWaitStates;
3387 int NumPasses = TSchedModel.computeInstrLatency(MI1);
3389 if (ST.hasGFX940Insts()) {
3393 NumPasses, ST.hasGFX950Insts())
3399 switch (NumPasses) {
3401 NeedWaitStates = SMFMA4x4WritesVGPROverlappedSrcABWaitStates;
3406 NeedWaitStates = SMFMA16x16WritesVGPROverlappedSrcABWaitStates;
3410 NeedWaitStates = SMFMA32x32WritesVGPROverlappedSrcABWaitStates;
3414 if (WaitStatesNeeded >= NeedWaitStates)
3417 WaitStatesNeededForUse = NeedWaitStates - NumWaitStates;
3418 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3420 if (WaitStatesNeeded == MaxWaitStates)
3425 WaitStatesNeeded = std::max(WaitStatesNeeded, checkMFMAPadding(
MI));
3427 return WaitStatesNeeded;
3430int GCNHazardRecognizer::checkMAILdStHazards(
MachineInstr *
MI)
const {
3432 if (!ST.hasMAIInsts() || ST.hasGFX90AInsts())
3435 int WaitStatesNeeded = 0;
3437 auto IsAccVgprReadFn = [](
const MachineInstr &
MI) {
3438 return MI.getOpcode() == AMDGPU::V_ACCVGPR_READ_B32_e64;
3441 for (
const MachineOperand &
Op :
MI->explicit_uses()) {
3442 if (!
Op.isReg() || !TRI.isVGPR(MF.getRegInfo(),
Op.getReg()))
3447 const int AccVgprReadLdStWaitStates = 2;
3448 const int VALUWriteAccVgprRdWrLdStDepVALUWaitStates = 1;
3449 const int MaxWaitStates = 2;
3451 int WaitStatesNeededForUse = AccVgprReadLdStWaitStates -
3452 getWaitStatesSinceDef(
Reg, IsAccVgprReadFn, MaxWaitStates);
3453 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3455 if (WaitStatesNeeded == MaxWaitStates)
3456 return WaitStatesNeeded;
3458 auto IsVALUAccVgprRdWrCheckFn = [
Reg,
this](
const MachineInstr &
MI) {
3459 if (
MI.getOpcode() != AMDGPU::V_ACCVGPR_READ_B32_e64 &&
3460 MI.getOpcode() != AMDGPU::V_ACCVGPR_WRITE_B32_e64)
3462 auto IsVALUFn = [](
const MachineInstr &
MI) {
3466 return getWaitStatesSinceDef(
Reg, IsVALUFn, 2 ) <
3467 std::numeric_limits<int>::max();
3470 WaitStatesNeededForUse = VALUWriteAccVgprRdWrLdStDepVALUWaitStates -
3471 getWaitStatesSince(IsVALUAccVgprRdWrCheckFn, MaxWaitStates);
3472 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3475 return WaitStatesNeeded;
3478int GCNHazardRecognizer::checkPermlaneHazards(
MachineInstr *
MI)
const {
3479 assert(!ST.hasVcmpxPermlaneHazard() &&
3480 "this is a different vcmpx+permlane hazard");
3481 const SIRegisterInfo *TRI = ST.getRegisterInfo();
3482 const SIInstrInfo *TII = ST.getInstrInfo();
3484 auto IsVCmpXWritesExecFn = [TII, TRI](
const MachineInstr &
MI) {
3488 auto IsVALUFn = [](
const MachineInstr &
MI) {
3492 const int VCmpXWritesExecWaitStates = 4;
3493 const int VALUWritesVDstWaitStates = 2;
3494 int WaitStatesNeeded = 0;
3496 for (
const MachineOperand &
Op :
MI->explicit_uses()) {
3497 if (!
Op.isReg() || !TRI->isVGPR(MF.getRegInfo(),
Op.getReg()))
3501 int WaitStatesSinceDef =
3502 VALUWritesVDstWaitStates -
3503 getWaitStatesSinceDef(
Reg, IsVALUFn,
3504 VALUWritesVDstWaitStates);
3505 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesSinceDef);
3506 if (WaitStatesNeeded >= VALUWritesVDstWaitStates)
3510 int VCmpXHazardWaits =
3511 VCmpXWritesExecWaitStates -
3512 getWaitStatesSince(IsVCmpXWritesExecFn, VCmpXWritesExecWaitStates);
3514 WaitStatesNeeded = std::max(WaitStatesNeeded, VCmpXHazardWaits);
3515 return WaitStatesNeeded;
3523 return NumPasses + 2;
3533 return NumPasses + 3 + (NumPasses != 2 && IsGFX950);
3543 return NumPasses + 3 + (NumPasses != 2 && IsGFX950);
3551 return NumPasses + 2;
3554int GCNHazardRecognizer::checkMAIVALUHazards(
MachineInstr *
MI)
const {
3555 if (!ST.hasGFX90AInsts())
3558 auto IsDGEMMFn = [](
const MachineInstr &
MI) ->
bool {
3566 const MachineRegisterInfo &MRI = MF.getRegInfo();
3568 int WaitStatesNeeded = 0;
3574 const MachineInstr *
MFMA =
nullptr;
3576 auto IsMFMAWriteFn = [&
Reg, &
MFMA,
this](
const MachineInstr &
MI) {
3578 !TRI.regsOverlap(
MI.getOperand(0).getReg(),
Reg))
3584 const MachineInstr *
DOT =
nullptr;
3585 auto IsDotWriteFn = [&
Reg, &
DOT,
this](
const MachineInstr &
MI) {
3587 !TRI.regsOverlap(
MI.getOperand(0).getReg(),
Reg))
3593 bool DGEMMAfterVALUWrite =
false;
3594 auto IsDGEMMHazard = [&DGEMMAfterVALUWrite,
this](
const MachineInstr &
MI) {
3597 DGEMMAfterVALUWrite =
true;
3601 if (!TII.isVALU(
MI,
true) || !DGEMMAfterVALUWrite)
3607 int SrcCIdx = AMDGPU::getNamedOperandIdx(
MI->getOpcode(),
3608 AMDGPU::OpName::src2);
3610 if (IsMemOrExport || IsVALU) {
3611 const int SMFMA4x4WriteVgprVALUMemExpReadWaitStates = 5;
3612 const int SMFMA16x16WriteVgprVALUMemExpReadWaitStates = 11;
3613 const int SMFMA32x32WriteVgprVALUMemExpReadWaitStates = 19;
3614 const int DMFMA4x4WriteVgprMemExpReadWaitStates = 9;
3615 const int DMFMA16x16WriteVgprMemExpReadWaitStates = 18;
3616 const int DMFMA4x4WriteVgprVALUReadWaitStates = 6;
3617 const int DMFMA16x16WriteVgprVALUReadWaitStates = 11;
3618 const int GFX950_DMFMA16x16WriteVgprVALUReadWaitStates = 19;
3619 const int DotWriteSameDotReadSrcAB = 3;
3620 const int DotWriteDifferentVALURead = 3;
3621 const int DMFMABetweenVALUWriteVMEMRead = 2;
3622 const int MaxWaitStates = 19;
3624 for (
const MachineOperand &Use :
MI->explicit_uses()) {
3630 int WaitStatesSinceDef = getWaitStatesSinceDef(
Reg, IsDotWriteFn,
3633 int NeedWaitStates = 0;
3634 if (
DOT->getOpcode() ==
MI->getOpcode()) {
3635 if (&Use - &
MI->getOperand(0) != SrcCIdx)
3636 NeedWaitStates = DotWriteSameDotReadSrcAB;
3638 NeedWaitStates = DotWriteDifferentVALURead;
3641 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceDef;
3642 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3649 if (IsMem && ST.hasGFX90AInsts() && !ST.hasGFX940Insts()) {
3650 DGEMMAfterVALUWrite =
false;
3651 if (TRI.isVectorRegister(MRI,
Reg)) {
3652 int WaitStatesNeededForUse =
3653 DMFMABetweenVALUWriteVMEMRead -
3654 getWaitStatesSinceDef(
Reg, IsDGEMMHazard,
3655 DMFMABetweenVALUWriteVMEMRead);
3657 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3662 WaitStatesSinceDef =
3663 getWaitStatesSinceDef(
Reg, IsMFMAWriteFn, MaxWaitStates);
3667 unsigned HazardDefLatency = TSchedModel.computeInstrLatency(
MFMA);
3668 int NumPasses = HazardDefLatency;
3669 int NeedWaitStates = MaxWaitStates;
3672 switch (HazardDefLatency) {
3674 NeedWaitStates = IsMemOrExport ? DMFMA4x4WriteVgprMemExpReadWaitStates
3675 : DMFMA4x4WriteVgprVALUReadWaitStates;
3681 ? DMFMA16x16WriteVgprMemExpReadWaitStates
3682 : (ST.hasGFX950Insts()
3683 ? GFX950_DMFMA16x16WriteVgprVALUReadWaitStates
3684 : DMFMA16x16WriteVgprVALUReadWaitStates);
3689 }
else if (ST.hasGFX940Insts()) {
3693 NumPasses, ST.hasGFX950Insts())
3697 switch (HazardDefLatency) {
3699 NeedWaitStates = SMFMA4x4WriteVgprVALUMemExpReadWaitStates;
3702 NeedWaitStates = SMFMA16x16WriteVgprVALUMemExpReadWaitStates;
3705 NeedWaitStates = SMFMA32x32WriteVgprVALUMemExpReadWaitStates;
3712 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceDef;
3713 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3715 if (WaitStatesNeeded == MaxWaitStates)
3720 unsigned Opc =
MI->getOpcode();
3721 const int DMFMAToFMA64WaitStates = 2;
3722 if ((
Opc == AMDGPU::V_FMA_F64_e64 ||
3723 Opc == AMDGPU::V_FMAC_F64_e32 ||
Opc == AMDGPU::V_FMAC_F64_e64 ||
3724 Opc == AMDGPU::V_FMAC_F64_dpp) &&
3725 WaitStatesNeeded < DMFMAToFMA64WaitStates) {
3726 int WaitStatesNeededForUse = DMFMAToFMA64WaitStates -
3727 getWaitStatesSince(IsDGEMMFn, DMFMAToFMA64WaitStates);
3728 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3731 if (!IsVALU && !IsMemOrExport)
3732 return WaitStatesNeeded;
3734 for (
const MachineOperand &Def :
MI->defs()) {
3735 const int SMFMA4x4WriteVgprVALUWawWaitStates = 5;
3736 const int SMFMA16x16WriteVgprVALUWawWaitStates = 11;
3737 const int SMFMA32x32WriteVgprVALUWawWaitStates = 19;
3738 const int SMFMA4x4ReadVgprVALUWarWaitStates = 1;
3739 const int GFX940_XDL4PassReadVgprVALUWarWaitStates = 3;
3740 const int SMFMA16x16ReadVgprVALUWarWaitStates = 7;
3741 const int SMFMA32x32ReadVgprVALUWarWaitStates = 15;
3742 const int DMFMA4x4WriteVgprVALUWriteWaitStates = 6;
3743 const int DMFMA16x16WriteVgprVALUWriteWaitStates = 11;
3744 const int DotWriteDifferentVALUWrite = 3;
3745 const int MaxWaitStates = 19;
3746 const int MaxWarWaitStates = 15;
3751 int WaitStatesSinceDef = getWaitStatesSinceDef(
Reg, IsDotWriteFn,
3753 if (DOT &&
DOT->getOpcode() !=
MI->getOpcode())
3754 WaitStatesNeeded = std::max(WaitStatesNeeded, DotWriteDifferentVALUWrite -
3755 WaitStatesSinceDef);
3758 WaitStatesSinceDef =
3759 getWaitStatesSinceDef(
Reg, IsMFMAWriteFn, MaxWaitStates);
3761 int NeedWaitStates = MaxWaitStates;
3762 int NumPasses = TSchedModel.computeInstrLatency(
MFMA);
3765 switch (NumPasses) {
3767 NeedWaitStates = DMFMA4x4WriteVgprVALUWriteWaitStates;
3771 NeedWaitStates = DMFMA16x16WriteVgprVALUWriteWaitStates;
3776 }
else if (ST.hasGFX940Insts()) {
3780 NumPasses, ST.hasGFX950Insts())
3783 switch (NumPasses) {
3785 NeedWaitStates = SMFMA4x4WriteVgprVALUWawWaitStates;
3788 NeedWaitStates = SMFMA16x16WriteVgprVALUWawWaitStates;
3791 NeedWaitStates = SMFMA32x32WriteVgprVALUWawWaitStates;
3798 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceDef;
3799 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3801 if (WaitStatesNeeded == MaxWaitStates)
3805 auto IsSMFMAReadAsCFn = [&
Reg, &
MFMA,
this](
const MachineInstr &
MI) {
3807 !
MI.readsRegister(
Reg, &TRI))
3810 if (ST.hasGFX940Insts() && !TII.isXDL(
MI))
3813 const MachineOperand *SrcC =
3814 TII.getNamedOperand(
MI, AMDGPU::OpName::src2);
3824 int WaitStatesSinceUse = getWaitStatesSince(IsSMFMAReadAsCFn,
3829 unsigned HazardDefLatency = TSchedModel.computeInstrLatency(
MFMA);
3830 int NeedWaitStates = MaxWaitStates;
3831 switch (HazardDefLatency) {
3832 case 2: NeedWaitStates = SMFMA4x4ReadVgprVALUWarWaitStates;
3834 case 4:
assert(ST.hasGFX940Insts());
3835 NeedWaitStates = GFX940_XDL4PassReadVgprVALUWarWaitStates;
3837 case 8: NeedWaitStates = SMFMA16x16ReadVgprVALUWarWaitStates;
3839 case 16: [[fallthrough]];
3840 default: NeedWaitStates = SMFMA32x32ReadVgprVALUWarWaitStates;
3844 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceUse;
3845 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3848 return WaitStatesNeeded;
3861 return MAI !=
nullptr;
3865 if (IsMFMAFn(*
MI)) {
3866 int W = getWaitStatesSince(IsMFMAFn, 16);
3868 return W < (int)TSchedModel.computeInstrLatency(MAI);
3882 while (
I->isBundledWithPred())
3888 if (
I->getOpcode() != AMDGPU::S_GETPC_B64)
3892 const unsigned NewBytes = 4;
3894 "Unexpected instruction insertion in bundle");
3897 while (NextMI != End && NextMI->isBundledWithPred()) {
3898 for (
auto &Operand : NextMI->operands()) {
3899 if (Operand.isGlobal())
3900 Operand.setOffset(Operand.getOffset() + NewBytes);
3906bool GCNHazardRecognizer::fixVALUMaskWriteHazard(
MachineInstr *
MI) {
3907 if (!ST.hasVALUMaskWriteHazard())
3909 assert(!ST.hasExtendedWaitCounts());
3916 if (!IsSALU && !IsVALU)
3928 const SIRegisterInfo *TRI = ST.getRegisterInfo();
3929 const MachineRegisterInfo &MRI = MF.getRegInfo();
3934 case AMDGPU::EXEC_LO:
3935 case AMDGPU::EXEC_HI:
3937 case AMDGPU::SGPR_NULL:
3938 case AMDGPU::SGPR_NULL64:
3946 return Reg == AMDGPU::VCC ||
Reg == AMDGPU::VCC_LO ||
Reg == AMDGPU::VCC_HI;
3950 SmallSet<Register, 2> HazardSGPRs;
3952 static unsigned getHashValue(
const StateType &State) {
3955 static bool isEqual(
const StateType &
LHS,
const StateType &
RHS) {
3956 return LHS.HazardSGPRs ==
RHS.HazardSGPRs;
3960 SmallVector<const MachineInstr *> WaitInstrs;
3961 StateType InitialState;
3964 MachineOperand *HazardDef =
nullptr;
3965 for (MachineOperand &
Op :
MI->all_defs()) {
3967 if (IgnoreableSGPR(
Reg))
3970 if (
Op.isImplicit())
3972 if (!TRI->isSGPRReg(MRI,
Reg))
3985 if (AMDGPU::SReg_32RegClass.
contains(HazardReg)) {
3986 InitialState.HazardSGPRs.insert(HazardReg);
3989 InitialState.HazardSGPRs.insert(TRI->getSubReg(HazardReg, AMDGPU::sub0));
3990 InitialState.HazardSGPRs.insert(TRI->getSubReg(HazardReg, AMDGPU::sub1));
3993 auto IsHazardFn = [&](StateType &State,
const MachineInstr &
I) {
3994 if (State.HazardSGPRs.empty())
3997 switch (
I.getOpcode()) {
3998 case AMDGPU::V_ADDC_U32_e32:
3999 case AMDGPU::V_ADDC_U32_dpp:
4000 case AMDGPU::V_CNDMASK_B16_t16_e32:
4001 case AMDGPU::V_CNDMASK_B16_fake16_e32:
4002 case AMDGPU::V_CNDMASK_B16_t16_dpp:
4003 case AMDGPU::V_CNDMASK_B16_fake16_dpp:
4004 case AMDGPU::V_CNDMASK_B32_e32:
4005 case AMDGPU::V_CNDMASK_B32_dpp:
4006 case AMDGPU::V_DIV_FMAS_F32_e64:
4007 case AMDGPU::V_DIV_FMAS_F64_e64:
4008 case AMDGPU::V_SUBB_U32_e32:
4009 case AMDGPU::V_SUBB_U32_dpp:
4010 case AMDGPU::V_SUBBREV_U32_e32:
4011 case AMDGPU::V_SUBBREV_U32_dpp: {
4015 case AMDGPU::V_ADDC_U32_e64:
4016 case AMDGPU::V_ADDC_U32_e64_dpp:
4017 case AMDGPU::V_CNDMASK_B16_t16_e64:
4018 case AMDGPU::V_CNDMASK_B16_fake16_e64:
4019 case AMDGPU::V_CNDMASK_B16_t16_e64_dpp:
4020 case AMDGPU::V_CNDMASK_B16_fake16_e64_dpp:
4021 case AMDGPU::V_CNDMASK_B32_e64:
4022 case AMDGPU::V_CNDMASK_B32_e64_dpp:
4023 case AMDGPU::V_SUBB_U32_e64:
4024 case AMDGPU::V_SUBB_U32_e64_dpp:
4025 case AMDGPU::V_SUBBREV_U32_e64:
4026 case AMDGPU::V_SUBBREV_U32_e64_dpp: {
4028 const MachineOperand *SSRCOp = TII.getNamedOperand(
I, AMDGPU::OpName::src2);
4030 bool Result = TRI->regsOverlap(SSRCOp->
getReg(), HazardReg);
4038 auto UpdateStateFn = [&](StateType &State,
const MachineInstr &
I) {
4040 for (
auto &
Op :
I.all_defs()) {
4042 if (IgnoreableSGPR(
Reg))
4045 if (
Op.isImplicit())
4047 if (!TRI->isSGPRReg(MRI,
Reg))
4054 for (
Register SGPR : State.HazardSGPRs) {
4055 if (
Reg == SGPR || TRI->regsOverlap(
Reg, SGPR))
4059 State.HazardSGPRs.erase(SGPR);
4066 std::next(
MI->getReverseIterator())))
4076 auto NextMI = std::next(
MI->getIterator());
4077 auto NewMI =
BuildMI(*
MI->getParent(), NextMI,
MI->getDebugLoc(),
4078 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
4090 if (EntryMBB.
begin() != EntryMBB.
end()) {
4091 auto &EntryMI = *EntryMBB.
begin();
4092 if (EntryMI.getOpcode() == AMDGPU::S_SETPRIO &&
4093 EntryMI.getOperand(0).getImm() >= Priority)
4102bool GCNHazardRecognizer::fixRequiredExportPriority(
MachineInstr *
MI) {
4103 if (!ST.hasRequiredExportPriority())
4121 const int MaxPriority = 3;
4122 const int NormalPriority = 2;
4123 const int PostExportPriority = 0;
4125 auto It =
MI->getIterator();
4126 switch (
MI->getOpcode()) {
4127 case AMDGPU::S_ENDPGM:
4128 case AMDGPU::S_ENDPGM_SAVED:
4129 case AMDGPU::S_ENDPGM_ORDERED_PS_DONE:
4130 case AMDGPU::SI_RETURN_TO_EPILOG:
4133 if (MF->getFrameInfo().hasCalls())
4136 case AMDGPU::S_SETPRIO: {
4138 auto &PrioOp =
MI->getOperand(0);
4139 int Prio = PrioOp.getImm();
4140 bool InWA = (Prio == PostExportPriority) &&
4141 (It !=
MBB->
begin() && TII.isEXP(*std::prev(It)));
4142 if (InWA || Prio >= NormalPriority)
4144 PrioOp.setImm(std::min(Prio + NormalPriority, MaxPriority));
4148 if (!TII.isEXP(*
MI))
4159 auto NextMI = std::next(It);
4160 bool EndOfShader =
false;
4161 if (NextMI !=
MBB->
end()) {
4163 if (TII.isEXP(*NextMI))
4166 if (NextMI->getOpcode() == AMDGPU::S_SETPRIO &&
4167 NextMI->getOperand(0).getImm() == PostExportPriority)
4169 EndOfShader = NextMI->getOpcode() == AMDGPU::S_ENDPGM;
4176 .
addImm(PostExportPriority);
4180 BuildMI(*
MBB, NextMI,
DL, TII.get(AMDGPU::S_WAITCNT_EXPCNT))
4181 .
addReg(AMDGPU::SGPR_NULL)
4201 const SIInstrInfo *TII = ST.getInstrInfo();
4213 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4218bool GCNHazardRecognizer::fixDsAtomicAsyncBarrierArriveB64(
MachineInstr *
MI) {
4219 if (
MI->getOpcode() != AMDGPU::DS_ATOMIC_ASYNC_BARRIER_ARRIVE_B64)
4222 const SIInstrInfo *TII = ST.getInstrInfo();
4224 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4226 BuildMI(*
MI->getParent(), std::next(
MI->getIterator()),
MI->getDebugLoc(),
4227 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4233bool GCNHazardRecognizer::fixScratchBaseForwardingHazard(
MachineInstr *
MI) {
4239 const SIRegisterInfo *TRI = ST.getRegisterInfo();
4240 const SIInstrInfo *TII = ST.getInstrInfo();
4242 const int FlatScrBaseWaitStates = 10;
4244 bool ReadsFlatScrLo =
4246 bool ReadsFlatScrHi =
4247 MI->readsRegister(AMDGPU::SRC_FLAT_SCRATCH_BASE_HI, TRI);
4253 ReadsFlatScrLo =
true;
4256 ReadsFlatScrHi =
true;
4261 const MachineRegisterInfo &MRI = MF.getRegInfo();
4264 DenseSet<const MachineBasicBlock *> Visited;
4266 return MI.modifiesRegister(
Reg, TRI);
4271 auto IsSGPRDef = [TII, TRI, &MRI](
const MachineInstr &
MI) ->
unsigned {
4272 if (!TII->isSALU(
MI) && !TII->isVALU(
MI,
true))
4274 for (
const MachineOperand &MO :
MI.all_defs()) {
4275 if (TRI->isSGPRReg(MRI, MO.getReg()))
4281 auto IsExpiredFn = [=](
const MachineInstr &
MI,
int SgprWrites) {
4282 if (
MI.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR) {
4283 unsigned Wait =
MI.getOperand(0).getImm();
4288 return SgprWrites >= FlatScrBaseWaitStates;
4291 return ::getWaitStatesSince(
4292 IsHazardFn,
MI->getParent(), std::next(
MI->getReverseIterator()),
4293 0,
IsExpiredFn, Visited, IsSGPRDef) < FlatScrBaseWaitStates;
4297 !IsRegDefHazard(AMDGPU::SGPR102)) &&
4299 !IsRegDefHazard(AMDGPU::SGPR103)))
4303 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4314 BuildMI(*
MI->getParent(),
MI,
MI->getDebugLoc(), TII.get(AMDGPU::V_NOP_e32));
4315 BuildMI(*
MI->getParent(),
MI,
MI->getDebugLoc(), TII.get(AMDGPU::V_NOP_e32));
4320 auto IsTDM = [&](
const MachineInstr &
MI) ->
bool {
4322 MI.getOpcode() != AMDGPU::S_WAIT_TENSORCNT;
4329 if (
MI.getOpcode() != AMDGPU::S_WAIT_TENSORCNT)
4331 return MI.getOperand(0).getImm() <= 10;
4335 std::numeric_limits<int>::max())
4339 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...