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 return ST.hasWMMACoexecutionHazards() && ST.hasTransCoexecutionHazard() &&
223void GCNHazardRecognizer::updateWMMAWindowState(
const MachineInstr &
MI) {
224 if (!hasCoExecWindowModel())
234 if (CurrentCoExecStage.has_value()) {
235 unsigned Stage = *CurrentCoExecStage;
237 CoExecWindowLog[Stage] = ActiveCoExecInfo.Pattern[Stage];
238 dbgs() <<
" CoExec window interrupted at stage " << Stage <<
":\n";
245 CurrentCoExecStage = 0;
246 CoExecWindowLog.fill(
'.');
248 LLVM_DEBUG(
dbgs() <<
" WMMA window started: " << ActiveCoExecInfo.Pattern
249 <<
" (window=" << ActiveCoExecInfo.TotalWindow <<
")\n"
253void GCNHazardRecognizer::updateTRANSState(
const MachineInstr &
MI) {
254 if (!hasCoExecWindowModel())
268 CyclesUntilTRANS = 2;
272void GCNHazardRecognizer::updateMultiCycleVALUState(
const MachineInstr &
MI) {
273 if (!hasCoExecWindowModel())
284 unsigned RepeatRate = TII.getRepeatRate(
MI);
285 if (RepeatRate > 1) {
289 CyclesUntilVALU = RepeatRate;
291 <<
", CyclesUntilVALU=" << CyclesUntilVALU <<
"\n");
301unsigned GCNHazardRecognizer::checkTRANSHazard(
const MachineInstr &
MI)
const {
302 if (!CyclesUntilTRANS)
307 return CyclesUntilTRANS;
311 TII.getRepeatRate(
MI) > 1)
312 return CyclesUntilTRANS;
318GCNHazardRecognizer::checkMultiCycleVALUHazard(
const MachineInstr &
MI)
const {
319 if (!CyclesUntilVALU)
330 return CyclesUntilVALU;
334GCNHazardRecognizer::checkWMMACoexecSlot(
const MachineInstr &
MI)
const {
336 if (!CurrentCoExecStage.has_value())
339 unsigned Stage = *CurrentCoExecStage;
342 if (ActiveCoExecInfo.canCoExec(InstMask, Stage))
346 auto NextStage = ActiveCoExecInfo.findNextAllowedStage(InstMask, Stage);
347 if (NextStage.has_value()) {
348 unsigned StallCycles = *NextStage - Stage;
351 dbgs() <<
" CoExec stall: stage=" << Stage <<
"("
354 <<
" -> stall " << StallCycles <<
" (next allowed=" << *NextStage
361 unsigned StallCycles = ActiveCoExecInfo.TotalWindow - Stage;
364 dbgs() <<
" CoExec stall: stage=" << Stage <<
"("
367 << StallCycles <<
" (window ends)\n"
373GCNHazardRecognizer::checkMultiShadowHazard(
const MachineInstr &
MI)
const {
375 if (!hasCoExecWindowModel())
379 if (!CurrentCoExecStage.has_value())
382 if (!CyclesUntilTRANS)
392 unsigned LookAheadStage = *CurrentCoExecStage + CyclesUntilTRANS;
395 if (ActiveCoExecInfo.canCoExec(InstMask, LookAheadStage))
396 return CyclesUntilTRANS;
400 ActiveCoExecInfo.findNextAllowedStage(InstMask, LookAheadStage);
401 if (NextStage.has_value()) {
402 unsigned StallCycles = *NextStage - *CurrentCoExecStage;
407 unsigned StallCycles = ActiveCoExecInfo.TotalWindow - *CurrentCoExecStage;
411void GCNHazardRecognizer::schedulerEmitInstruction(
MachineInstr *
MI) {
413 bool InWindow = CurrentCoExecStage.has_value();
414 bool HasActiveState =
415 InWindow || CyclesUntilTRANS > 0 || CyclesUntilVALU > 0;
416 if (HasActiveState) {
418 unsigned Stage = *CurrentCoExecStage;
419 dbgs() <<
" Stage " << Stage <<
"("
432 bool HasActiveState = CurrentCoExecStage.has_value() ||
433 CyclesUntilTRANS > 0 || CyclesUntilVALU > 0;
439 updateWMMAWindowState(*
MI);
440 updateTRANSState(*
MI);
441 updateMultiCycleVALUState(*
MI);
451 schedulerEmitInstruction(
MI);
455 return Opcode == AMDGPU::V_DIV_FMAS_F32_e64 || Opcode == AMDGPU::V_DIV_FMAS_F64_e64;
459 return Opcode == AMDGPU::S_GETREG_B32 || Opcode == AMDGPU::S_GETREG_B32_const;
464 case AMDGPU::S_SETREG_B32:
465 case AMDGPU::S_SETREG_B32_mode:
466 case AMDGPU::S_SETREG_IMM32_B32:
467 case AMDGPU::S_SETREG_IMM32_B32_mode:
474 return Opcode == AMDGPU::V_READLANE_B32 || Opcode == AMDGPU::V_WRITELANE_B32;
478 return Opcode == AMDGPU::S_RFE_B64;
483 case AMDGPU::S_MOVRELS_B32:
484 case AMDGPU::S_MOVRELS_B64:
485 case AMDGPU::S_MOVRELD_B32:
486 case AMDGPU::S_MOVRELD_B64:
495 if (
TII.isAlwaysGDS(
MI.getOpcode()))
498 switch (
MI.getOpcode()) {
499 case AMDGPU::S_SENDMSG:
500 case AMDGPU::S_SENDMSGHALT:
501 case AMDGPU::S_TTRACEDATA:
505 case AMDGPU::DS_PERMUTE_B32:
506 case AMDGPU::DS_BPERMUTE_B32:
509 if (
TII.isDS(
MI.getOpcode())) {
510 int GDS = AMDGPU::getNamedOperandIdx(
MI.getOpcode(),
511 AMDGPU::OpName::gds);
512 if (
MI.getOperand(GDS).getImm())
520 unsigned Opcode =
MI.getOpcode();
521 return Opcode == AMDGPU::V_PERMLANE16_B32_e64 ||
522 Opcode == AMDGPU::V_PERMLANE64_B32 ||
523 Opcode == AMDGPU::V_PERMLANEX16_B32_e64 ||
524 Opcode == AMDGPU::V_PERMLANE16_VAR_B32_e64 ||
525 Opcode == AMDGPU::V_PERMLANEX16_VAR_B32_e64 ||
526 Opcode == AMDGPU::V_PERMLANE16_SWAP_B32_e32 ||
527 Opcode == AMDGPU::V_PERMLANE16_SWAP_B32_e64 ||
528 Opcode == AMDGPU::V_PERMLANE32_SWAP_B32_e32 ||
529 Opcode == AMDGPU::V_PERMLANE32_SWAP_B32_e64 ||
530 Opcode == AMDGPU::V_PERMLANE_BCAST_B32_e64 ||
531 Opcode == AMDGPU::V_PERMLANE_UP_B32_e64 ||
532 Opcode == AMDGPU::V_PERMLANE_DOWN_B32_e64 ||
533 Opcode == AMDGPU::V_PERMLANE_XOR_B32_e64 ||
534 Opcode == AMDGPU::V_PERMLANE_IDX_GEN_B32_e64;
544 AMDGPU::OpName::simm16);
560 if (checkMultiShadowHazard(*
MI) > 0)
562 if (checkWMMACoexecSlot(*
MI) > 0)
564 if (checkTRANSHazard(*
MI) > 0)
566 if (checkMultiCycleVALUHazard(*
MI) > 0)
576 if (ST.hasNSAtoVMEMBug() && checkNSAtoVMEMHazard(
MI) > 0)
579 if (checkFPAtomicToDenormModeHazard(
MI) > 0)
584 if (checkWMMACoexecutionHazards(
MI) > 0) {
585 HasPendingWMMACoexecHazard =
true;
590 if (ST.hasNoDataDepHazard())
597 checkVALUHazards(
MI) > 0)
603 if (
isDivFMas(
MI->getOpcode()) && checkDivFMasHazards(
MI) > 0)
606 if (
isRWLane(
MI->getOpcode()) && checkRWLaneHazards(
MI) > 0)
612 checkMAIVALUHazards(
MI) > 0)
615 if (
isSGetReg(
MI->getOpcode()) && checkGetRegHazards(
MI) > 0)
618 if (
isSSetReg(
MI->getOpcode()) && checkSetRegHazards(
MI) > 0)
621 if (
isRFE(
MI->getOpcode()) && checkRFEHazards(
MI) > 0)
624 if (((ST.hasReadM0MovRelInterpHazard() &&
626 MI->getOpcode() == AMDGPU::DS_WRITE_ADDTID_B32 ||
627 MI->getOpcode() == AMDGPU::DS_READ_ADDTID_B32)) ||
629 (ST.hasReadM0LdsDmaHazard() &&
isLdsDma(*
MI)) ||
630 (ST.hasReadM0LdsDirectHazard() &&
631 MI->readsRegister(AMDGPU::LDS_DIRECT,
nullptr))) &&
632 checkReadM0Hazards(
MI) > 0)
639 checkMAILdStHazards(
MI) > 0)
642 if (
MI->isInlineAsm() && checkInlineAsmHazards(
MI) > 0)
650 while (Quantity > 0) {
651 unsigned Arg = std::min(Quantity, 8u);
659GCNHazardRecognizer::getMFMAPipelineWaitStates(
const MachineInstr &
MI)
const {
660 const MCSchedClassDesc *SC = TSchedModel.resolveSchedClass(&
MI);
661 assert(TSchedModel.getWriteProcResBegin(SC) !=
662 TSchedModel.getWriteProcResEnd(SC));
663 return TSchedModel.getWriteProcResBegin(SC)->ReleaseAtCycle;
666void GCNHazardRecognizer::processBundle() {
670 for (;
MI !=
E &&
MI->isInsideBundle(); ++
MI) {
671 CurrCycleInstr = &*
MI;
675 fixHazards(CurrCycleInstr);
683 for (
unsigned i = 0, e = std::min(WaitStates,
MaxLookAhead - 1); i <
e; ++i)
684 EmittedInstrs.push_front(
nullptr);
686 EmittedInstrs.push_front(CurrCycleInstr);
689 CurrCycleInstr =
nullptr;
697 if (
MI->isInsideBundle())
711 CurrCycleInstr =
nullptr;
720 W = checkWMMACoexecSlot(*
MI);
721 W = std::max(W, checkTRANSHazard(*
MI));
722 W = std::max(W, checkMultiCycleVALUHazard(*
MI));
723 W = std::max(W, checkMultiShadowHazard(*
MI));
739 return std::max(WaitStates, checkSMRDHazards(
MI));
741 if (ST.hasNSAtoVMEMBug())
742 WaitStates = std::max(WaitStates, checkNSAtoVMEMHazard(
MI));
744 WaitStates = std::max(WaitStates, checkFPAtomicToDenormModeHazard(
MI));
746 if (ST.hasNoDataDepHazard())
750 WaitStates = std::max(WaitStates, checkVMEMHazards(
MI));
753 WaitStates = std::max(WaitStates, checkVALUHazards(
MI));
756 WaitStates = std::max(WaitStates, checkDPPHazards(
MI));
759 WaitStates = std::max(WaitStates, checkDivFMasHazards(
MI));
762 WaitStates = std::max(WaitStates, checkRWLaneHazards(
MI));
767 checkMAIVALUHazards(
MI) > 0)
768 WaitStates = std::max(WaitStates, checkMAIVALUHazards(
MI));
770 if (
MI->isInlineAsm())
771 return std::max(WaitStates, checkInlineAsmHazards(
MI));
774 return std::max(WaitStates, checkGetRegHazards(
MI));
777 return std::max(WaitStates, checkSetRegHazards(
MI));
780 return std::max(WaitStates, checkRFEHazards(
MI));
782 if ((ST.hasReadM0MovRelInterpHazard() &&
784 MI->getOpcode() == AMDGPU::DS_WRITE_ADDTID_B32 ||
785 MI->getOpcode() == AMDGPU::DS_READ_ADDTID_B32)) ||
787 (ST.hasReadM0LdsDmaHazard() &&
isLdsDma(*
MI)) ||
788 (ST.hasReadM0LdsDirectHazard() &&
789 MI->readsRegister(AMDGPU::LDS_DIRECT,
nullptr)))
790 return std::max(WaitStates, checkReadM0Hazards(
MI));
793 return std::max(WaitStates, checkMAIHazards(
MI));
796 return std::max(WaitStates, checkMAILdStHazards(
MI));
799 return std::max(WaitStates, checkPermlaneHazards(
MI));
805 EmittedInstrs.push_front(
nullptr);
810 schedulerAdvanceCycle();
814 if (!CurrCycleInstr) {
815 EmittedInstrs.push_front(
nullptr);
817 if (HasPendingWMMACoexecHazard)
818 EmittedVALUInstrs.push_front(
nullptr);
822 HasPendingWMMACoexecHazard =
false;
824 if (CurrCycleInstr->isBundle()) {
829 unsigned NumWaitStates = TII.getNumWaitStates(*CurrCycleInstr);
830 if (!NumWaitStates) {
831 CurrCycleInstr =
nullptr;
836 EmittedInstrs.push_front(CurrCycleInstr);
843 EmittedVALUInstrs.push_front(CurrCycleInstr);
849 while (!EmittedVALUInstrs.empty() && EmittedVALUInstrs.front() ==
nullptr)
850 EmittedVALUInstrs.pop_front();
858 EmittedInstrs.push_front(
nullptr);
865 if (EmittedVALUInstrs.size() > MaxVALULookAhead)
866 EmittedVALUInstrs.resize(MaxVALULookAhead);
868 CurrCycleInstr =
nullptr;
873 "Bottom-up scheduling shouldn't run in hazard recognizer mode");
883template <
typename StateT>
893 static bool isEqual(
const StateMapKey &
LHS,
const StateMapKey &
RHS) {
898 static unsigned getHashValue(
const StateMapKey &
Key) {
899 return StateT::getHashValue((*
Key.States)[
Key.Idx]);
901 static unsigned getHashValue(
const StateT &State) {
902 return StateT::getHashValue(State);
904 static bool isEqual(
const StateMapKey &
LHS,
const StateMapKey &
RHS) {
905 return StateT::isEqual((*
LHS.States)[
LHS.Idx], (*
RHS.States)[
RHS.Idx]);
907 static bool isEqual(
const StateT &
LHS,
const StateMapKey &
RHS) {
908 return StateT::isEqual(
LHS, (*
RHS.States)[
RHS.Idx]);
917 StateT State = InitialState;
920 unsigned WorkIdx = 0;
922 bool Expired =
false;
923 for (
auto E =
MBB->instr_rend();
I !=
E; ++
I) {
928 auto Result = IsHazard(State, *
I);
936 if (
I->isInlineAsm() ||
I->isMetaInstruction())
939 UpdateState(State, *
I);
943 unsigned StateIdx = States.
size();
944 StateMapKey
Key = {&States, StateIdx};
945 auto Insertion = StateMap.
insert_as(std::pair(
Key, StateIdx), State);
946 if (Insertion.second) {
949 StateIdx = Insertion.first->second;
952 Worklist.
insert(std::pair(Pred, StateIdx));
955 if (WorkIdx == Worklist.
size())
959 std::tie(
MBB, StateIdx) = Worklist[WorkIdx++];
960 State = States[StateIdx];
961 I =
MBB->instr_rbegin();
978 for (
auto E =
MBB->instr_rend();
I !=
E; ++
I) {
986 if (
I->isInlineAsm())
989 WaitStates += GetNumWaitStates(*
I);
991 if (IsExpired(*
I, WaitStates))
992 return std::numeric_limits<int>::max();
995 int MinWaitStates = std::numeric_limits<int>::max();
997 if (!Visited.
insert(Pred).second)
1001 IsExpired, Visited, GetNumWaitStates);
1003 MinWaitStates = std::min(MinWaitStates, W);
1006 return MinWaitStates;
1017 std::next(
MI->getReverseIterator()), 0, IsExpired,
1018 Visited, GetNumWaitStates);
1021int GCNHazardRecognizer::getWaitStatesSince(
1022 IsHazardFn IsHazard,
int Limit, GetNumWaitStatesFn GetNumWaitStates)
const {
1024 auto IsExpiredFn = [Limit](
const MachineInstr &,
int WaitStates) {
1025 return WaitStates >= Limit;
1027 return ::getWaitStatesSince(IsHazard, CurrCycleInstr,
IsExpiredFn,
1032 for (MachineInstr *
MI : EmittedInstrs) {
1037 if (
MI->isInlineAsm())
1040 WaitStates +=
MI ? GetNumWaitStates(*
MI) : 1;
1042 if (WaitStates >= Limit)
1045 return std::numeric_limits<int>::max();
1048int GCNHazardRecognizer::getWaitStatesSince(IsHazardFn IsHazard,
1053int GCNHazardRecognizer::getWaitStatesSinceVALU(IsHazardFn IsHazard,
1056 auto GetVALUWaitStates = [](
const MachineInstr &
MI) ->
unsigned {
1059 return getWaitStatesSince(IsHazard, Limit, GetVALUWaitStates);
1065 assert(Limit <= (
int)MaxVALULookAhead &&
1066 "Limit exceeds the EmittedVALUInstrs lookahead window");
1068 for (MachineInstr *
MI : EmittedVALUInstrs) {
1076 if (WaitStates >= Limit)
1079 return std::numeric_limits<int>::max();
1082int GCNHazardRecognizer::getWaitStatesSinceDef(
unsigned Reg,
1083 IsHazardFn IsHazardDef,
1085 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1088 return IsHazardDef(
MI) &&
MI.modifiesRegister(
Reg, TRI);
1091 return getWaitStatesSince(
IsHazardFn, Limit);
1094int GCNHazardRecognizer::getWaitStatesSinceSetReg(IsHazardFn IsHazard,
1100 return getWaitStatesSince(
IsHazardFn, Limit);
1109 for (MCRegUnit Unit :
TRI.regunits(
Reg))
1110 BV.
set(
static_cast<unsigned>(Unit));
1122void GCNHazardRecognizer::addClauseInst(
const MachineInstr &
MI)
const {
1134int GCNHazardRecognizer::checkSoftClauseHazards(
MachineInstr *MEM)
const {
1137 if (!ST.isXNACKEnabled())
1140 bool IsSMRD = TII.isSMRD(*MEM);
1154 for (MachineInstr *
MI : EmittedInstrs) {
1166 if (ClauseDefs.none())
1172 if (
MEM->mayStore())
1175 addClauseInst(*MEM);
1179 return ClauseDefs.anyCommon(ClauseUses) ? 1 : 0;
1182int GCNHazardRecognizer::checkSMRDHazards(
MachineInstr *SMRD)
const {
1183 int WaitStatesNeeded = 0;
1185 WaitStatesNeeded = checkSoftClauseHazards(SMRD);
1188 if (!ST.hasSMRDReadVALUDefHazard())
1189 return WaitStatesNeeded;
1193 int SmrdSgprWaitStates = 4;
1194 auto IsHazardDefFn = [
this](
const MachineInstr &
MI) {
1195 return TII.isVALU(
MI,
true);
1197 auto IsBufferHazardDefFn = [
this](
const MachineInstr &
MI) {
1198 return TII.isSALU(
MI);
1201 bool IsBufferSMRD = TII.isBufferSMRD(*SMRD);
1203 for (
const MachineOperand &Use :
SMRD->uses()) {
1206 int WaitStatesNeededForUse =
1207 SmrdSgprWaitStates - getWaitStatesSinceDef(
Use.getReg(), IsHazardDefFn,
1208 SmrdSgprWaitStates);
1209 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1219 int WaitStatesNeededForUse =
1220 SmrdSgprWaitStates - getWaitStatesSinceDef(
Use.getReg(),
1221 IsBufferHazardDefFn,
1222 SmrdSgprWaitStates);
1223 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1227 return WaitStatesNeeded;
1230int GCNHazardRecognizer::checkVMEMHazards(
MachineInstr *VMEM)
const {
1231 if (!ST.hasVMEMReadSGPRVALUDefHazard())
1234 int WaitStatesNeeded = checkSoftClauseHazards(VMEM);
1238 const int VmemSgprWaitStates = 5;
1239 auto IsHazardDefFn = [
this](
const MachineInstr &
MI) {
1240 return TII.isVALU(
MI,
true);
1242 for (
const MachineOperand &Use :
VMEM->uses()) {
1243 if (!
Use.isReg() || TRI.isVectorRegister(MF.getRegInfo(),
Use.getReg()))
1246 int WaitStatesNeededForUse =
1247 VmemSgprWaitStates - getWaitStatesSinceDef(
Use.getReg(), IsHazardDefFn,
1248 VmemSgprWaitStates);
1249 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1251 return WaitStatesNeeded;
1255 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1256 const SIInstrInfo *TII = ST.getInstrInfo();
1259 int DppVgprWaitStates = 2;
1260 int DppExecWaitStates = 5;
1261 int WaitStatesNeeded = 0;
1262 auto IsHazardDefFn = [TII](
const MachineInstr &
MI) {
1263 return TII->isVALU(
MI,
true);
1266 for (
const MachineOperand &Use :
DPP->uses()) {
1267 if (!
Use.isReg() || !TRI->isVGPR(MF.getRegInfo(),
Use.getReg()))
1269 int WaitStatesNeededForUse =
1270 DppVgprWaitStates - getWaitStatesSinceDef(
1272 [](
const MachineInstr &) { return true; },
1274 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1277 WaitStatesNeeded = std::max(
1279 DppExecWaitStates - getWaitStatesSinceDef(AMDGPU::EXEC, IsHazardDefFn,
1280 DppExecWaitStates));
1282 return WaitStatesNeeded;
1285int GCNHazardRecognizer::checkDivFMasHazards(
MachineInstr *DivFMas)
const {
1286 const SIInstrInfo *TII = ST.getInstrInfo();
1290 const int DivFMasWaitStates = 4;
1291 auto IsHazardDefFn = [TII](
const MachineInstr &
MI) {
1292 return TII->isVALU(
MI,
true);
1294 int WaitStatesNeeded = getWaitStatesSinceDef(AMDGPU::VCC, IsHazardDefFn,
1297 return DivFMasWaitStates - WaitStatesNeeded;
1300int GCNHazardRecognizer::checkGetRegHazards(
MachineInstr *GetRegInstr)
const {
1301 const SIInstrInfo *TII = ST.getInstrInfo();
1302 unsigned GetRegHWReg =
getHWReg(TII, *GetRegInstr);
1304 const int GetRegWaitStates = 2;
1305 auto IsHazardFn = [TII, GetRegHWReg](
const MachineInstr &
MI) {
1308 int WaitStatesNeeded = getWaitStatesSinceSetReg(
IsHazardFn, GetRegWaitStates);
1310 return GetRegWaitStates - WaitStatesNeeded;
1313int GCNHazardRecognizer::checkSetRegHazards(
MachineInstr *SetRegInstr)
const {
1314 const SIInstrInfo *TII = ST.getInstrInfo();
1315 unsigned HWReg =
getHWReg(TII, *SetRegInstr);
1317 const int SetRegWaitStates = ST.getSetRegWaitStates();
1318 auto IsHazardFn = [TII, HWReg](
const MachineInstr &
MI) {
1321 int WaitStatesNeeded = getWaitStatesSinceSetReg(
IsHazardFn, SetRegWaitStates);
1322 return SetRegWaitStates - WaitStatesNeeded;
1325int GCNHazardRecognizer::createsVALUHazard(
const MachineInstr &
MI)
const {
1329 const SIInstrInfo *TII = ST.getInstrInfo();
1330 unsigned Opcode =
MI.getOpcode();
1331 const MCInstrDesc &
Desc =
MI.getDesc();
1333 int VDataIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::vdata);
1336 VDataRCID = TII->getOpRegClassID(
Desc.operands()[VDataIdx]);
1338 if (TII->isMUBUF(
MI) || TII->isMTBUF(
MI)) {
1348 if (ST.hasVDecCoExecHazard())
1350 const MachineOperand *SOffset =
1351 TII->getNamedOperand(
MI, AMDGPU::OpName::soffset);
1352 if (!SOffset || !SOffset->
isReg())
1361 if (TII->isMIMG(
MI)) {
1362 int SRsrcIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::srsrc);
1364 Desc.operands()[SRsrcIdx])) == 256);
1368 if (TII->isFLAT(
MI)) {
1380int GCNHazardRecognizer::checkUniformWindowVALUHazardsHelper(
1385 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1387 auto IsHazard = [&](
const MachineInstr &
MI) {
1388 int DataIdx = createsVALUHazard(
MI);
1389 return DataIdx >= 0 &&
1390 TRI->regsOverlap(
MI.getOperand(DataIdx).getReg(),
Reg);
1393 return std::max(0, 1 - getWaitStatesSince(IsHazard, 1));
1396int GCNHazardRecognizer::checkSOFFSETWindowVALUHazardsHelper(
1403 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1404 const SIInstrInfo *TII = ST.getInstrInfo();
1406 int WaitStatesNeeded = 0;
1410 for (
int Window = 1; Window <= 2; ++Window) {
1411 auto IsHazard = [&](
const MachineInstr &
MI) {
1412 int DataIdx = createsVALUHazard(
MI);
1414 !TRI->regsOverlap(
MI.getOperand(DataIdx).getReg(),
Reg))
1419 if (Window == 1 || !TII->isBUF(
MI))
1422 const MachineOperand *SOffset =
1423 TII->getNamedOperand(
MI, AMDGPU::OpName::soffset);
1424 return !SOffset || !SOffset->
isReg();
1426 WaitStatesNeeded = std::max(WaitStatesNeeded,
1427 Window - getWaitStatesSince(IsHazard, Window));
1430 return WaitStatesNeeded;
1433int GCNHazardRecognizer::checkVALUHazardsHelper(
1438 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1440 if (!TRI->isVectorRegister(MRI,
Def.getReg()))
1443 if (ST.hasVDecCoExecHazard())
1444 return checkSOFFSETWindowVALUHazardsHelper(
Def.getReg());
1446 return checkUniformWindowVALUHazardsHelper(
Def.getReg());
1462 unsigned Opcode =
MI.getOpcode();
1472 if (
auto *DstSel =
TII->getNamedOperand(
MI, AMDGPU::OpName::dst_sel))
1474 return TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
1480 if (
TII->getNamedImmOperand(
MI, AMDGPU::OpName::src0_modifiers) &
1482 return TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
1486 (
TII->getNamedImmOperand(
MI, AMDGPU::OpName::src2_modifiers) &
1488 return TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
1494 return TII->getNamedOperand(
MI, AMDGPU::OpName::vdst);
1515 for (
auto &Operand : VALU->operands()) {
1516 if (Operand.isReg() &&
TRI->regsOverlap(Dst->getReg(), Operand.getReg())) {
1523int GCNHazardRecognizer::checkVALUHazards(
MachineInstr *VALU)
const {
1524 int WaitStatesNeeded = 0;
1527 const int TransDefWaitstates = 1;
1529 auto IsTransDefFn = [
this,
VALU](
const MachineInstr &
MI) {
1532 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1533 const SIInstrInfo *TII = ST.getInstrInfo();
1534 Register Def = TII->getNamedOperand(
MI, AMDGPU::OpName::vdst)->getReg();
1536 for (
const MachineOperand &Use :
VALU->explicit_uses()) {
1537 if (
Use.isReg() && TRI->regsOverlap(Def,
Use.getReg()))
1544 int WaitStatesNeededForDef =
1545 TransDefWaitstates -
1546 getWaitStatesSince(IsTransDefFn, TransDefWaitstates);
1547 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1550 if (ST.hasDstSelForwardingHazard() || ST.hasCvtScaleForwardingHazard()) {
1551 const int Shift16DefWaitstates = 1;
1553 auto IsShift16BitDefFn = [
this,
VALU](
const MachineInstr &ProducerMI) {
1554 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1555 const MachineOperand *ForwardedDst =
1561 if (ProducerMI.isInlineAsm()) {
1563 for (
auto &Def : ProducerMI.all_defs()) {
1572 int WaitStatesNeededForDef =
1573 Shift16DefWaitstates -
1574 getWaitStatesSince(IsShift16BitDefFn, Shift16DefWaitstates);
1575 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1578 if (ST.hasVDecCoExecHazard()) {
1579 const int VALUWriteSGPRVALUReadWaitstates = 2;
1580 const int VALUWriteEXECRWLane = 4;
1581 const int VALUWriteVGPRReadlaneRead = 1;
1583 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1584 const MachineRegisterInfo &MRI = MF.getRegInfo();
1586 auto IsVALUDefSGPRFn = [&
UseReg, TRI](
const MachineInstr &
MI) {
1589 return MI.modifiesRegister(
UseReg, TRI);
1592 for (
const MachineOperand &Use :
VALU->explicit_uses()) {
1597 if (TRI->isSGPRReg(MRI,
UseReg)) {
1598 int WaitStatesNeededForDef =
1599 VALUWriteSGPRVALUReadWaitstates -
1600 getWaitStatesSince(IsVALUDefSGPRFn,
1601 VALUWriteSGPRVALUReadWaitstates);
1602 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1606 if (
VALU->readsRegister(AMDGPU::VCC, TRI)) {
1608 int WaitStatesNeededForDef =
1609 VALUWriteSGPRVALUReadWaitstates -
1610 getWaitStatesSince(IsVALUDefSGPRFn, VALUWriteSGPRVALUReadWaitstates);
1611 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1614 switch (
VALU->getOpcode()) {
1615 case AMDGPU::V_READLANE_B32:
1616 case AMDGPU::V_READFIRSTLANE_B32: {
1617 MachineOperand *Src = TII.getNamedOperand(*VALU, AMDGPU::OpName::src0);
1619 int WaitStatesNeededForDef =
1620 VALUWriteVGPRReadlaneRead -
1621 getWaitStatesSince(IsVALUDefSGPRFn, VALUWriteVGPRReadlaneRead);
1622 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1625 case AMDGPU::V_WRITELANE_B32: {
1627 int WaitStatesNeededForDef =
1628 VALUWriteEXECRWLane -
1629 getWaitStatesSince(IsVALUDefSGPRFn, VALUWriteEXECRWLane);
1630 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1640 if (!ST.has12DWordStoreHazard())
1641 return WaitStatesNeeded;
1643 const MachineRegisterInfo &MRI = MF.getRegInfo();
1645 for (
const MachineOperand &Def :
VALU->defs()) {
1646 WaitStatesNeeded = std::max(WaitStatesNeeded, checkVALUHazardsHelper(Def, MRI));
1649 return WaitStatesNeeded;
1652int GCNHazardRecognizer::checkInlineAsmHazards(
MachineInstr *IA)
const {
1661 if (!ST.has12DWordStoreHazard() && !ST.hasDstSelForwardingHazard() &&
1662 !ST.hasCvtScaleForwardingHazard())
1665 const MachineRegisterInfo &MRI = MF.getRegInfo();
1666 int WaitStatesNeeded = 0;
1668 for (
const MachineOperand &
Op :
1670 if (
Op.isReg() &&
Op.isDef()) {
1671 if (!TRI.isVectorRegister(MRI,
Op.getReg()))
1674 if (ST.has12DWordStoreHazard()) {
1676 std::max(WaitStatesNeeded, checkVALUHazardsHelper(
Op, MRI));
1681 if (ST.hasDstSelForwardingHazard()) {
1682 const int Shift16DefWaitstates = 1;
1684 auto IsShift16BitDefFn = [
this, &
IA](
const MachineInstr &ProducerMI) {
1688 return IA->modifiesRegister(Dst->getReg(), &TRI) ||
1689 IA->readsRegister(Dst->getReg(), &TRI);
1691 if (ProducerMI.isInlineAsm()) {
1693 for (
auto &Def : ProducerMI.all_defs()) {
1694 if (
IA->modifiesRegister(
Def.getReg(), &TRI) ||
1695 IA->readsRegister(
Def.getReg(), &TRI)) {
1704 int WaitStatesNeededForDef =
1705 Shift16DefWaitstates -
1706 getWaitStatesSince(IsShift16BitDefFn, Shift16DefWaitstates);
1707 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1710 return WaitStatesNeeded;
1713int GCNHazardRecognizer::checkRWLaneHazards(
MachineInstr *RWLane)
const {
1714 const SIInstrInfo *TII = ST.getInstrInfo();
1715 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1716 const MachineRegisterInfo &MRI = MF.getRegInfo();
1718 const MachineOperand *LaneSelectOp =
1719 TII->getNamedOperand(*RWLane, AMDGPU::OpName::src1);
1721 if (!LaneSelectOp->
isReg() || !TRI->isSGPRReg(MRI, LaneSelectOp->
getReg()))
1726 return TII->isVALU(
MI,
true);
1729 const int RWLaneWaitStates = 4;
1730 int WaitStatesSince = getWaitStatesSinceDef(LaneSelectReg,
IsHazardFn,
1732 return RWLaneWaitStates - WaitStatesSince;
1735int GCNHazardRecognizer::checkRFEHazards(
MachineInstr *RFE)
const {
1736 if (!ST.hasRFEHazards())
1739 const SIInstrInfo *TII = ST.getInstrInfo();
1741 const int RFEWaitStates = 1;
1746 int WaitStatesNeeded = getWaitStatesSinceSetReg(
IsHazardFn, RFEWaitStates);
1747 return RFEWaitStates - WaitStatesNeeded;
1750int GCNHazardRecognizer::checkReadM0Hazards(
MachineInstr *
MI)
const {
1751 const SIInstrInfo *TII = ST.getInstrInfo();
1752 const int ReadM0WaitStates = 1;
1753 auto IsHazardFn = [TII](
const MachineInstr &
MI) {
return TII->isSALU(
MI); };
1754 return ReadM0WaitStates -
1755 getWaitStatesSinceDef(AMDGPU::M0,
IsHazardFn, ReadM0WaitStates);
1760 int WaitStatesNeeded,
bool IsHoisting) {
1762 for (
int I = 0;
I < WaitStatesNeeded; ++
I)
1763 BuildMI(
MBB, InsertPt,
DL, TII.get(AMDGPU::V_NOP_e32));
1767 fixVMEMtoScalarWriteHazards(
MI);
1768 fixVcmpxPermlaneHazards(
MI);
1769 fixSMEMtoVectorWriteHazards(
MI);
1770 fixVcmpxExecWARHazard(
MI);
1771 fixLdsBranchVmemWARHazard(
MI);
1772 if (ST.hasLdsDirect()) {
1773 fixLdsDirectVALUHazard(
MI);
1774 fixLdsDirectVMEMHazard(
MI);
1776 fixVALUPartialForwardingHazard(
MI);
1777 fixVALUTransUseHazard(
MI);
1778 fixVALUTransCoexecutionHazards(
MI);
1780 fixWMMACoexecutionHazards(
MI);
1781 fixShift64HighRegBug(
MI);
1782 fixVALUMaskWriteHazard(
MI);
1783 fixRequiredExportPriority(
MI);
1784 if (ST.requiresWaitIdleBeforeGetReg())
1785 fixGetRegWaitIdle(
MI);
1786 if (ST.hasDsAtomicAsyncBarrierArriveB64PipeBug())
1787 fixDsAtomicAsyncBarrierArriveB64(
MI);
1788 if (ST.hasScratchBaseForwardingHazard())
1789 fixScratchBaseForwardingHazard(
MI);
1790 if (ST.setRegModeNeedsVNOPs())
1792 if (ST.hasNeedsTDMDrain())
1798 return (
TII.isVOPC(
MI) ||
1799 (
MI.isCompare() && (
TII.isVOP3(
MI) ||
TII.isSDWA(
MI)))) &&
1800 MI.modifiesRegister(AMDGPU::EXEC, &
TRI);
1803bool GCNHazardRecognizer::fixVcmpxPermlaneHazards(
MachineInstr *
MI) {
1807 const SIInstrInfo *TII = ST.getInstrInfo();
1808 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1814 unsigned Opc =
MI.getOpcode();
1816 Opc != AMDGPU::V_NOP_e32 &&
Opc != AMDGPU::V_NOP_e64 &&
1817 Opc != AMDGPU::V_NOP_sdwa;
1821 std::numeric_limits<int>::max())
1827 auto *Src0 = TII->getNamedOperand(*
MI, AMDGPU::OpName::src0);
1829 bool IsUndef = Src0->isUndef();
1831 TII->get(AMDGPU::V_MOV_B32_e32))
1838bool GCNHazardRecognizer::fixVMEMtoScalarWriteHazards(
MachineInstr *
MI) {
1839 if (!ST.hasVMEMtoScalarWriteHazard())
1841 assert(!ST.hasExtendedWaitCounts());
1846 if (
MI->getNumDefs() == 0)
1849 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1855 for (
const MachineOperand &Def :
MI->defs()) {
1856 const MachineOperand *
Op =
1857 I.findRegisterUseOperand(
Def.getReg(), TRI,
false);
1867 (
MI.getOpcode() == AMDGPU::S_WAITCNT &&
1868 !
MI.getOperand(0).getImm()) ||
1869 (
MI.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
1874 std::numeric_limits<int>::max())
1877 const SIInstrInfo *TII = ST.getInstrInfo();
1879 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
1884bool GCNHazardRecognizer::fixSMEMtoVectorWriteHazards(
MachineInstr *
MI) {
1885 if (!ST.hasSMEMtoVectorWriteHazard())
1887 assert(!ST.hasExtendedWaitCounts());
1892 AMDGPU::OpName SDSTName;
1893 switch (
MI->getOpcode()) {
1894 case AMDGPU::V_READLANE_B32:
1895 case AMDGPU::V_READFIRSTLANE_B32:
1896 SDSTName = AMDGPU::OpName::vdst;
1899 SDSTName = AMDGPU::OpName::sdst;
1903 const SIInstrInfo *TII = ST.getInstrInfo();
1904 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1906 const MachineOperand *SDST = TII->getNamedOperand(*
MI, SDSTName);
1908 for (
const auto &MO :
MI->implicit_operands()) {
1909 if (MO.isDef() && TRI->isSGPRClass(TRI->getPhysRegBaseClass(MO.getReg()))) {
1920 auto IsHazardFn = [SDSTReg, TRI](
const MachineInstr &
I) {
1925 if (TII->isSALU(
MI)) {
1926 switch (
MI.getOpcode()) {
1927 case AMDGPU::S_SETVSKIP:
1928 case AMDGPU::S_VERSION:
1929 case AMDGPU::S_WAITCNT_VSCNT:
1930 case AMDGPU::S_WAITCNT_VMCNT:
1931 case AMDGPU::S_WAITCNT_EXPCNT:
1934 case AMDGPU::S_WAITCNT_LGKMCNT:
1936 return (
MI.getOperand(1).getImm() == 0) &&
1937 (
MI.getOperand(0).
getReg() == AMDGPU::SGPR_NULL);
1938 case AMDGPU::S_WAITCNT: {
1939 const int64_t
Imm =
MI.getOperand(0).getImm();
1946 MI.getOpcode() == AMDGPU::S_WAIT_IDLE) &&
1947 "unexpected wait count instruction");
1949 if (TII->isSOPP(
MI))
1965 std::numeric_limits<int>::max())
1969 TII->get(AMDGPU::S_MOV_B32), AMDGPU::SGPR_NULL)
1974bool GCNHazardRecognizer::fixVcmpxExecWARHazard(
MachineInstr *
MI) {
1975 if (!ST.hasVcmpxExecWARHazard())
1977 assert(!ST.hasExtendedWaitCounts());
1982 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1983 if (!
MI->modifiesRegister(AMDGPU::EXEC, TRI))
1989 return I.readsRegister(AMDGPU::EXEC, TRI);
1992 const SIInstrInfo *TII = ST.getInstrInfo();
1993 auto IsExpiredFn = [TII, TRI](
const MachineInstr &
MI, int) {
1995 if (TII->getNamedOperand(
MI, AMDGPU::OpName::sdst))
1997 for (
auto MO :
MI.implicit_operands())
1998 if (MO.isDef() && TRI->isSGPRClass(TRI->getPhysRegBaseClass(MO.getReg())))
2001 if (
MI.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2008 std::numeric_limits<int>::max())
2012 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
2019 if (!ST.hasLdsBranchVmemWARHazard())
2024 bool HasLds =
false;
2025 bool HasVmem =
false;
2026 for (
auto &
MBB : MF) {
2027 for (
auto &
MI :
MBB) {
2030 if (HasLds && HasVmem)
2038 return I.getOpcode() == AMDGPU::S_WAITCNT_VSCNT &&
2039 I.getOperand(0).getReg() == AMDGPU::SGPR_NULL &&
2040 !
I.getOperand(1).getImm();
2043bool GCNHazardRecognizer::fixLdsBranchVmemWARHazard(
MachineInstr *
MI) {
2044 if (!RunLdsBranchVmemWARHazardFixup)
2047 assert(ST.hasLdsBranchVmemWARHazard());
2048 assert(!ST.hasExtendedWaitCounts());
2050 auto IsHazardInst = [](
const MachineInstr &
MI) {
2058 auto InstType = IsHazardInst(*
MI);
2062 auto IsExpiredFn = [&IsHazardInst](
const MachineInstr &
I, int) {
2066 auto IsHazardFn = [InstType, &IsHazardInst](
const MachineInstr &
I) {
2070 auto IsHazardFn = [InstType, IsHazardInst](
const MachineInstr &
I) {
2071 auto InstType2 = IsHazardInst(
I);
2072 return InstType2 && InstType != InstType2;
2075 auto IsExpiredFn = [InstType, &IsHazardInst](
const MachineInstr &
I, int) {
2076 auto InstType2 = IsHazardInst(
I);
2077 if (InstType == InstType2)
2084 std::numeric_limits<int>::max();
2088 std::numeric_limits<int>::max())
2091 const SIInstrInfo *TII = ST.getInstrInfo();
2093 TII->get(AMDGPU::S_WAITCNT_VSCNT))
2100bool GCNHazardRecognizer::fixLdsDirectVALUHazard(
MachineInstr *
MI) {
2104 const int NoHazardWaitStates = 15;
2105 const MachineOperand *VDST = TII.getNamedOperand(*
MI, AMDGPU::OpName::vdst);
2108 bool VisitedTrans =
false;
2109 auto IsHazardFn = [
this, VDSTReg, &VisitedTrans](
const MachineInstr &
I) {
2114 return I.readsRegister(VDSTReg, &TRI) ||
I.modifiesRegister(VDSTReg, &TRI);
2116 auto IsExpiredFn = [&](
const MachineInstr &
I,
int WaitStates) {
2117 if (WaitStates >= NoHazardWaitStates)
2123 auto GetWaitStatesFn = [](
const MachineInstr &
MI) {
2127 DenseSet<const MachineBasicBlock *> Visited;
2129 std::next(
MI->getReverseIterator()), 0,
2137 MachineOperand *WaitVdstOp =
2138 TII.getNamedOperand(*
MI, AMDGPU::OpName::waitvdst);
2139 WaitVdstOp->
setImm(std::min(
Count, NoHazardWaitStates));
2144bool GCNHazardRecognizer::fixLdsDirectVMEMHazard(
MachineInstr *
MI) {
2148 const MachineOperand *VDST = TII.getNamedOperand(*
MI, AMDGPU::OpName::vdst);
2151 auto IsHazardFn = [
this, VDSTReg](
const MachineInstr &
I) {
2154 return I.readsRegister(VDSTReg, &TRI) ||
I.modifiesRegister(VDSTReg, &TRI);
2156 bool LdsdirCanWait = ST.hasLdsWaitVMSRC();
2159 auto IsExpiredFn = [
this, LdsdirCanWait](
const MachineInstr &
I, int) {
2162 (
I.getOpcode() == AMDGPU::S_WAITCNT && !
I.getOperand(0).getImm()) ||
2163 (
I.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2166 !TII.getNamedOperand(
I, AMDGPU::OpName::waitvsrc)->getImm());
2170 std::numeric_limits<int>::max())
2173 if (LdsdirCanWait) {
2174 TII.getNamedOperand(*
MI, AMDGPU::OpName::waitvsrc)->setImm(0);
2177 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
2184bool GCNHazardRecognizer::fixVALUPartialForwardingHazard(
MachineInstr *
MI) {
2185 if (!ST.hasVALUPartialForwardingHazard())
2187 assert(!ST.hasExtendedWaitCounts());
2192 SmallSetVector<Register, 4> SrcVGPRs;
2194 for (
const MachineOperand &Use :
MI->explicit_uses()) {
2195 if (
Use.isReg() && TRI.isVGPR(MF.getRegInfo(),
Use.getReg()))
2200 if (SrcVGPRs.
size() <= 1)
2218 const int Intv1plus2MaxVALUs = 2;
2219 const int Intv3MaxVALUs = 4;
2220 const int IntvMaxVALUs = 6;
2221 const int NoHazardVALUWaitStates = IntvMaxVALUs + 2;
2224 SmallDenseMap<Register, int, 4> DefPos;
2225 int ExecPos = std::numeric_limits<int>::max();
2228 static unsigned getHashValue(
const StateType &State) {
2232 static bool isEqual(
const StateType &
LHS,
const StateType &
RHS) {
2233 return LHS.DefPos ==
RHS.DefPos &&
LHS.ExecPos ==
RHS.ExecPos &&
2241 auto IsHazardFn = [&,
this](StateType &State,
const MachineInstr &
I) {
2243 if (State.VALUs > NoHazardVALUWaitStates)
2249 (
I.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2257 if (!State.DefPos.count(Src) &&
I.modifiesRegister(Src, &TRI)) {
2258 State.DefPos[Src] = State.VALUs;
2263 if (State.ExecPos == std::numeric_limits<int>::max()) {
2264 if (!State.DefPos.empty() &&
I.modifiesRegister(AMDGPU::EXEC, &TRI)) {
2265 State.ExecPos = State.VALUs;
2272 if (State.VALUs > Intv3MaxVALUs && State.DefPos.empty())
2280 if (State.ExecPos == std::numeric_limits<int>::max())
2283 int PreExecPos = std::numeric_limits<int>::max();
2284 int PostExecPos = std::numeric_limits<int>::max();
2286 for (
auto Entry : State.DefPos) {
2287 int DefVALUs =
Entry.second;
2288 if (DefVALUs != std::numeric_limits<int>::max()) {
2289 if (DefVALUs >= State.ExecPos)
2290 PreExecPos = std::min(PreExecPos, DefVALUs);
2292 PostExecPos = std::min(PostExecPos, DefVALUs);
2297 if (PostExecPos == std::numeric_limits<int>::max())
2301 int Intv3VALUs = PostExecPos;
2302 if (Intv3VALUs > Intv3MaxVALUs)
2306 int Intv2VALUs = (State.ExecPos - PostExecPos) - 1;
2307 if (Intv2VALUs > Intv1plus2MaxVALUs)
2311 if (PreExecPos == std::numeric_limits<int>::max())
2315 int Intv1VALUs = PreExecPos - State.ExecPos;
2316 if (Intv1VALUs > Intv1plus2MaxVALUs)
2320 if (Intv1VALUs + Intv2VALUs > Intv1plus2MaxVALUs)
2325 auto UpdateStateFn = [](StateType &State,
const MachineInstr &
MI) {
2331 std::next(
MI->getReverseIterator())))
2335 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
2341bool GCNHazardRecognizer::fixVALUTransUseHazard(
MachineInstr *
MI) {
2342 if (!ST.hasVALUTransUseHazard())
2344 assert(!ST.hasExtendedWaitCounts());
2349 SmallSet<Register, 4> SrcVGPRs;
2351 for (
const MachineOperand &Use :
MI->explicit_uses()) {
2352 if (
Use.isReg() && TRI.isVGPR(MF.getRegInfo(),
Use.getReg()))
2366 const int IntvMaxVALUs = 5;
2367 const int IntvMaxTRANS = 1;
2373 static unsigned getHashValue(
const StateType &State) {
2376 static bool isEqual(
const StateType &
LHS,
const StateType &
RHS) {
2377 return LHS.VALUs ==
RHS.VALUs &&
LHS.TRANS ==
RHS.TRANS;
2384 auto IsHazardFn = [&,
this](StateType &State,
const MachineInstr &
I) {
2386 if (State.VALUs > IntvMaxVALUs || State.TRANS > IntvMaxTRANS)
2392 (
I.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2399 if (
I.modifiesRegister(Src, &TRI)) {
2407 auto UpdateStateFn = [](StateType &State,
const MachineInstr &
MI) {
2415 std::next(
MI->getReverseIterator())))
2421 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
2427bool GCNHazardRecognizer::fixVALUTransCoexecutionHazards(
MachineInstr *
MI) {
2428 if (!ST.hasTransCoexecutionHazard() ||
2433 const SIInstrInfo *TII = ST.getInstrInfo();
2434 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2436 auto IsTransHazardFn = [
MI, TII, TRI](
const MachineInstr &
I) {
2441 Register TransDef = TII->getNamedOperand(
I, AMDGPU::OpName::vdst)->getReg();
2442 for (
const MachineOperand &ValuUse :
MI->explicit_uses()) {
2443 if (ValuUse.isReg() && TRI->regsOverlap(TransDef, ValuUse.getReg()))
2447 auto *ValuDst = TII->getNamedOperand(*
MI, AMDGPU::OpName::vdst);
2448 if (!ValuDst || !ValuDst->isReg())
2452 Register ValuDef = ValuDst->getReg();
2453 for (
const MachineOperand &TransUse :
I.explicit_uses()) {
2454 if (TransUse.isReg() && TRI->regsOverlap(ValuDef, TransUse.getReg()))
2465 const int HasVALU = std::numeric_limits<int>::max();
2466 if (::getWaitStatesSince(IsTransHazardFn,
MI,
IsExpiredFn) == HasVALU)
2469 BuildMI(*
MI->getParent(),
MI,
MI->getDebugLoc(), TII->get(AMDGPU::V_NOP_e32));
2477 const SIInstrInfo *TII = ST.getInstrInfo();
2478 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2480 auto IsHazardFn = [
MI, TII, TRI,
this](
const MachineInstr &
I) {
2487 TII->getNamedOperand(*
MI, AMDGPU::OpName::src0)->getReg();
2489 TII->getNamedOperand(*
MI, AMDGPU::OpName::src1)->getReg();
2492 TII->getNamedOperand(
I, AMDGPU::OpName::vdst)->getReg();
2494 if (TRI->regsOverlap(PrevDstReg, CurSrc0Reg) ||
2495 TRI->regsOverlap(PrevDstReg, CurSrc1Reg)) {
2504 TII->getNamedOperand(*
MI, AMDGPU::OpName::src2)->getReg();
2505 if (TRI->regsOverlap(PrevDstReg, CurIndex))
2519 std::numeric_limits<int>::max())
2522 BuildMI(*
MI->getParent(),
MI,
MI->getDebugLoc(), TII->get(AMDGPU::V_NOP_e32));
2577 bool IsLowestRateWMMA = ST.hasGFX125xLowestRateWMMA();
2578 unsigned Category = 0;
2580 unsigned Latency = SchedModel.computeInstrLatency(&
MI);
2585 assert(!IsSWMMAC &&
"no 4-cycle SWMMAC expected");
2589 Category = IsSWMMAC ? 2 : 0;
2592 Category = IsLowestRateWMMA ? 4 : (IsSWMMAC ? 3 : 1);
2595 assert(IsLowestRateWMMA &&
"latency 32 is not expected");
2605int GCNHazardRecognizer::checkWMMACoexecutionHazards(
MachineInstr *
MI)
const {
2606 if (!ST.hasWMMACoexecutionHazards())
2609 const SIInstrInfo *TII = ST.getInstrInfo();
2618 const int WMMAWaitStates[] = {5, 9, 3, 5, 9, 17, 2};
2619 const int VALUWaitStates[] = {4, 8, 2, 4, 8, 16, 1};
2620 unsigned Category = 0;
2622 auto IsWMMAHazardFn = [
MI, TII, &Category,
this](
const MachineInstr &
I) {
2623 if (!TII->isXDLWMMA(
I))
2627 return hasWMMAToWMMARegOverlap(
I, *
MI);
2630 auto IsVALUHazardFn = [
MI, TII, &Category,
this](
const MachineInstr &
I) {
2631 if (!TII->isXDLWMMA(
I))
2635 return hasWMMAToVALURegOverlap(
I, *
MI);
2638 int WaitStatesNeeded = -1;
2639 int ExistingVALUs = 0;
2640 bool IsLowestRateWMMA = ST.hasGFX125xLowestRateWMMA();
2648 if (TII->isXDLWMMA(*
MI)) {
2650 const int WMMAWaitsLimit = IsLowestRateWMMA ? 17 : 9;
2651 ExistingVALUs = getWaitStatesSinceVALU(IsWMMAHazardFn, WMMAWaitsLimit);
2652 WaitStatesNeeded = WMMAWaitStates[Category] - ExistingVALUs;
2655 const int VALUWaitsLimit = IsLowestRateWMMA ? 16 : 8;
2656 ExistingVALUs = getWaitStatesSinceVALU(IsVALUHazardFn, VALUWaitsLimit);
2657 WaitStatesNeeded = VALUWaitStates[Category] - ExistingVALUs;
2660 return WaitStatesNeeded;
2663bool GCNHazardRecognizer::hasWMMAToWMMARegOverlap(
2665 Register D0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::vdst)->getReg();
2666 Register A1 = TII.getNamedOperand(
MI, AMDGPU::OpName::src0)->getReg();
2667 Register B1 = TII.getNamedOperand(
MI, AMDGPU::OpName::src1)->getReg();
2670 if (TRI.regsOverlap(D0, A1) || TRI.regsOverlap(D0, B1))
2674 Register Idx1 = TII.getNamedOperand(
MI, AMDGPU::OpName::src2)->getReg();
2675 if (TRI.regsOverlap(D0, Idx1))
2681bool GCNHazardRecognizer::hasWMMAToVALURegOverlap(
2684 Register D0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::vdst)->getReg();
2685 for (
const MachineOperand &ValuUse :
MI.explicit_uses()) {
2686 if (ValuUse.isReg() && TRI.regsOverlap(D0, ValuUse.getReg()))
2691 Register A0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::src0)->getReg();
2692 Register B0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::src1)->getReg();
2696 Register Idx0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::src2)->getReg();
2697 WMMARegs.push_back(Idx0);
2700 for (
const MachineOperand &ValuDef :
MI.defs()) {
2701 Register VDstReg = ValuDef.getReg();
2702 for (
Register WMMAReg : WMMARegs) {
2703 if (TRI.regsOverlap(VDstReg, WMMAReg))
2710bool GCNHazardRecognizer::isCoexecutionHazardFor(
const MachineInstr &
I,
2714 if (!TII.isXDLWMMA(
I))
2718 if (TII.isXDLWMMA(
MI))
2719 return hasWMMAToWMMARegOverlap(
I,
MI);
2721 return hasWMMAToVALURegOverlap(
I,
MI);
2727 bool IncludeSubloops) {
2730 for (MachineBasicBlock *
MBB :
L->getBlocks()) {
2731 if (!IncludeSubloops && MLI->getLoopFor(
MBB) != L)
2733 for (MachineInstr &
I : *
MBB) {
2736 if (isCoexecutionHazardFor(
I, *
MI))
2743bool GCNHazardRecognizer::tryHoistWMMAVnopsFromLoop(
MachineInstr *
MI,
2744 int WaitStatesNeeded) {
2748 MachineLoop *
L = MLI->getLoopFor(
MI->getParent());
2750 ++NumWMMAHoistingBailed;
2755 if (hasWMMAHazardInLoop(L,
MI)) {
2756 ++NumWMMAHoistingBailed;
2761 MachineLoop *TargetLoop =
L;
2763 if (hasWMMAHazardInLoop(Parent,
MI,
false))
2765 TargetLoop = Parent;
2771 ++NumWMMAHoistingBailed;
2775 LLVM_DEBUG(
dbgs() <<
"WMMA V_NOP Hoisting: Moving " << WaitStatesNeeded
2781 NumWMMANopsHoisted += WaitStatesNeeded;
2785bool GCNHazardRecognizer::fixWMMACoexecutionHazards(
MachineInstr *
MI) {
2786 int WaitStatesNeeded = checkWMMACoexecutionHazards(
MI);
2787 if (WaitStatesNeeded <= 0)
2793 emitVNops(*
MI->getParent(),
MI->getIterator(), WaitStatesNeeded);
2797bool GCNHazardRecognizer::fixShift64HighRegBug(
MachineInstr *
MI) {
2798 if (!ST.hasShift64HighRegBug())
2800 assert(!ST.hasExtendedWaitCounts());
2802 switch (
MI->getOpcode()) {
2805 case AMDGPU::V_LSHLREV_B64_e64:
2806 case AMDGPU::V_LSHRREV_B64_e64:
2807 case AMDGPU::V_ASHRREV_I64_e64:
2811 MachineOperand *Amt = TII.getNamedOperand(*
MI, AMDGPU::OpName::src0);
2816 const MachineRegisterInfo &MRI = MF.getRegInfo();
2818 if (!TRI.isVGPR(MRI, AmtReg) || ((AmtReg - AMDGPU::VGPR0) & 7) != 7)
2821 if (AmtReg != AMDGPU::VGPR255 && MRI.
isPhysRegUsed(AmtReg + 1))
2824 assert(ST.needsAlignedVGPRs());
2825 static_assert(AMDGPU::VGPR0 + 1 == AMDGPU::VGPR1);
2828 MachineBasicBlock *
MBB =
MI->getParent();
2829 MachineOperand *Src1 = TII.getNamedOperand(*
MI, AMDGPU::OpName::src1);
2840 Register DstReg =
MI->getOperand(0).getReg();
2842 Register DstLo = TRI.getSubReg(DstReg, AMDGPU::sub0);
2850 bool Overlapped =
MI->modifiesRegister(AmtReg, &TRI);
2852 for (MCRegister
Reg : Overlapped ? AMDGPU::VReg_64_Align2RegClass
2853 : AMDGPU::VGPR_32RegClass) {
2854 if (!
MI->modifiesRegister(
Reg, &TRI) && !
MI->readsRegister(
Reg, &TRI)) {
2860 Register NewAmt = Overlapped ? (
Register)TRI.getSubReg(NewReg, AMDGPU::sub1)
2865 NewAmtLo = TRI.getSubReg(NewReg, AMDGPU::sub0);
2878 runOnInstruction(
BuildMI(*
MBB,
MI,
DL, TII.get(AMDGPU::V_SWAP_B32), NewAmt)
2885 BuildMI(*
MBB, std::next(
MI->getIterator()),
DL, TII.get(AMDGPU::V_SWAP_B32),
2891 BuildMI(*
MBB, std::next(
MI->getIterator()),
DL, TII.get(AMDGPU::V_SWAP_B32),
2905 MI->getOperand(0).setReg(NewReg);
2914int GCNHazardRecognizer::checkNSAtoVMEMHazard(
MachineInstr *
MI)
const {
2915 int NSAtoVMEMWaitStates = 1;
2917 if (!ST.hasNSAtoVMEMBug())
2923 const SIInstrInfo *TII = ST.getInstrInfo();
2924 const auto *
Offset = TII->getNamedOperand(*
MI, AMDGPU::OpName::offset);
2932 return Info->MIMGEncoding == AMDGPU::MIMGEncGfx10NSA &&
2933 TII->getInstSizeInBytes(
I) >= 16;
2936 return NSAtoVMEMWaitStates - getWaitStatesSince(
IsHazardFn, 1);
2939int GCNHazardRecognizer::checkFPAtomicToDenormModeHazard(
2941 int FPAtomicToDenormModeWaitStates = 3;
2943 if (!ST.hasFPAtomicToDenormModeHazard())
2945 assert(!ST.hasExtendedWaitCounts());
2947 if (
MI->getOpcode() != AMDGPU::S_DENORM_MODE)
2956 auto IsExpiredFn = [](
const MachineInstr &
MI,
int WaitStates) {
2963 return FPAtomicToDenormModeWaitStates -
2967int GCNHazardRecognizer::checkMAIHazards(
MachineInstr *
MI)
const {
2970 return ST.hasGFX90AInsts() ? checkMAIHazards90A(
MI) : checkMAIHazards908(
MI);
2973int GCNHazardRecognizer::checkMFMAPadding(
MachineInstr *
MI)
const {
2978 const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
2982 int NeighborMFMALatency = 0;
2983 auto IsNeighboringMFMA = [&NeighborMFMALatency,
2984 this](
const MachineInstr &
MI) {
2988 NeighborMFMALatency = this->getMFMAPipelineWaitStates(
MI);
2992 const int MaxMFMAPipelineWaitStates = 16;
2993 int WaitStatesSinceNeighborMFMA =
2994 getWaitStatesSince(IsNeighboringMFMA, MaxMFMAPipelineWaitStates);
2996 int NeighborMFMAPaddingNeeded =
2998 WaitStatesSinceNeighborMFMA;
3000 return std::max(0, NeighborMFMAPaddingNeeded);
3003int GCNHazardRecognizer::checkMAIHazards908(
MachineInstr *
MI)
const {
3004 int WaitStatesNeeded = 0;
3005 unsigned Opc =
MI->getOpcode();
3007 auto IsVALUFn = [](
const MachineInstr &
MI) {
3011 if (
Opc != AMDGPU::V_ACCVGPR_READ_B32_e64) {
3012 const int LegacyVALUWritesVGPRWaitStates = 2;
3013 const int VALUWritesExecWaitStates = 4;
3014 const int MaxWaitStates = 4;
3016 int WaitStatesNeededForUse = VALUWritesExecWaitStates -
3017 getWaitStatesSinceDef(AMDGPU::EXEC, IsVALUFn, MaxWaitStates);
3018 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3020 if (WaitStatesNeeded < MaxWaitStates) {
3021 for (
const MachineOperand &Use :
MI->explicit_uses()) {
3022 const int MaxWaitStates = 2;
3024 if (!
Use.isReg() || !TRI.isVGPR(MF.getRegInfo(),
Use.getReg()))
3027 int WaitStatesNeededForUse = LegacyVALUWritesVGPRWaitStates -
3028 getWaitStatesSinceDef(
Use.getReg(), IsVALUFn, MaxWaitStates);
3029 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3031 if (WaitStatesNeeded == MaxWaitStates)
3037 for (
const MachineOperand &
Op :
MI->explicit_operands()) {
3038 if (!
Op.isReg() || !TRI.isAGPR(MF.getRegInfo(),
Op.getReg()))
3041 if (
Op.isDef() &&
Opc != AMDGPU::V_ACCVGPR_WRITE_B32_e64)
3044 const int MFMAWritesAGPROverlappedSrcABWaitStates = 4;
3045 const int MFMAWritesAGPROverlappedSrcCWaitStates = 2;
3046 const int MFMA4x4WritesAGPRAccVgprReadWaitStates = 4;
3047 const int MFMA16x16WritesAGPRAccVgprReadWaitStates = 10;
3048 const int MFMA32x32WritesAGPRAccVgprReadWaitStates = 18;
3049 const int MFMA4x4WritesAGPRAccVgprWriteWaitStates = 1;
3050 const int MFMA16x16WritesAGPRAccVgprWriteWaitStates = 7;
3051 const int MFMA32x32WritesAGPRAccVgprWriteWaitStates = 15;
3052 const int MaxWaitStates = 18;
3054 unsigned HazardDefLatency = 0;
3056 auto IsOverlappedMFMAFn = [
Reg, &HazardDefLatency,
3057 this](
const MachineInstr &
MI) {
3064 std::max(HazardDefLatency, TSchedModel.computeInstrLatency(&
MI));
3065 return TRI.regsOverlap(DstReg,
Reg);
3068 int WaitStatesSinceDef = getWaitStatesSinceDef(
Reg, IsOverlappedMFMAFn,
3070 int NeedWaitStates = MFMAWritesAGPROverlappedSrcABWaitStates;
3071 int SrcCIdx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src2);
3072 int OpNo =
Op.getOperandNo();
3073 if (OpNo == SrcCIdx) {
3074 NeedWaitStates = MFMAWritesAGPROverlappedSrcCWaitStates;
3075 }
else if (
Opc == AMDGPU::V_ACCVGPR_READ_B32_e64) {
3076 switch (HazardDefLatency) {
3077 case 2: NeedWaitStates = MFMA4x4WritesAGPRAccVgprReadWaitStates;
3079 case 8: NeedWaitStates = MFMA16x16WritesAGPRAccVgprReadWaitStates;
3081 case 16: [[fallthrough]];
3082 default: NeedWaitStates = MFMA32x32WritesAGPRAccVgprReadWaitStates;
3085 }
else if (
Opc == AMDGPU::V_ACCVGPR_WRITE_B32_e64) {
3086 switch (HazardDefLatency) {
3087 case 2: NeedWaitStates = MFMA4x4WritesAGPRAccVgprWriteWaitStates;
3089 case 8: NeedWaitStates = MFMA16x16WritesAGPRAccVgprWriteWaitStates;
3091 case 16: [[fallthrough]];
3092 default: NeedWaitStates = MFMA32x32WritesAGPRAccVgprWriteWaitStates;
3097 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceDef;
3098 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3100 if (WaitStatesNeeded == MaxWaitStates)
3101 return WaitStatesNeeded;
3103 auto IsAccVgprWriteFn = [
Reg,
this](
const MachineInstr &
MI) {
3104 if (
MI.getOpcode() != AMDGPU::V_ACCVGPR_WRITE_B32_e64)
3107 return TRI.regsOverlap(
Reg, DstReg);
3110 const int AccVGPRWriteMFMAReadSrcCWaitStates = 1;
3111 const int AccVGPRWriteMFMAReadSrcABWaitStates = 3;
3112 const int AccVGPRWriteAccVgprReadWaitStates = 3;
3113 NeedWaitStates = AccVGPRWriteMFMAReadSrcABWaitStates;
3114 if (OpNo == SrcCIdx)
3115 NeedWaitStates = AccVGPRWriteMFMAReadSrcCWaitStates;
3116 else if (
Opc == AMDGPU::V_ACCVGPR_READ_B32_e64)
3117 NeedWaitStates = AccVGPRWriteAccVgprReadWaitStates;
3119 WaitStatesNeededForUse = NeedWaitStates -
3120 getWaitStatesSinceDef(
Reg, IsAccVgprWriteFn, MaxWaitStates);
3121 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3123 if (WaitStatesNeeded == MaxWaitStates)
3124 return WaitStatesNeeded;
3127 if (
Opc == AMDGPU::V_ACCVGPR_WRITE_B32_e64) {
3128 const int MFMA4x4ReadSrcCAccVgprWriteWaitStates = 0;
3129 const int MFMA16x16ReadSrcCAccVgprWriteWaitStates = 5;
3130 const int MFMA32x32ReadSrcCAccVgprWriteWaitStates = 13;
3131 const int MaxWaitStates = 13;
3132 Register DstReg =
MI->getOperand(0).getReg();
3133 unsigned HazardDefLatency = 0;
3135 auto IsSrcCMFMAFn = [DstReg, &HazardDefLatency,
3136 this](
const MachineInstr &
MI) {
3139 Register Reg = TII.getNamedOperand(
MI, AMDGPU::OpName::src2)->getReg();
3141 std::max(HazardDefLatency, TSchedModel.computeInstrLatency(&
MI));
3142 return TRI.regsOverlap(
Reg, DstReg);
3145 int WaitStatesSince = getWaitStatesSince(IsSrcCMFMAFn, MaxWaitStates);
3147 switch (HazardDefLatency) {
3148 case 2: NeedWaitStates = MFMA4x4ReadSrcCAccVgprWriteWaitStates;
3150 case 8: NeedWaitStates = MFMA16x16ReadSrcCAccVgprWriteWaitStates;
3152 case 16: [[fallthrough]];
3153 default: NeedWaitStates = MFMA32x32ReadSrcCAccVgprWriteWaitStates;
3157 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSince;
3158 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3162 WaitStatesNeeded = std::max(WaitStatesNeeded, checkMFMAPadding(
MI));
3164 return WaitStatesNeeded;
3175 return NumPasses + 1 + IsGFX950;
3186 return NumPasses + 1 + (NumPasses != 2 && IsGFX950);
3204 return NumPasses + 2;
3214 return NumPasses + 3 + (NumPasses != 2 && IsGFX950);
3217int GCNHazardRecognizer::checkMAIHazards90A(
MachineInstr *
MI)
const {
3218 int WaitStatesNeeded = 0;
3219 unsigned Opc =
MI->getOpcode();
3221 auto IsLegacyVALUFn = [](
const MachineInstr &
MI) {
3226 auto IsLegacyVALUNotDotFn = [](
const MachineInstr &
MI) {
3232 return WaitStatesNeeded;
3234 const int VALUWritesExecWaitStates = 4;
3235 int WaitStatesNeededForUse = VALUWritesExecWaitStates -
3236 getWaitStatesSinceDef(AMDGPU::EXEC, IsLegacyVALUFn,
3237 VALUWritesExecWaitStates);
3238 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3240 int SrcCIdx = AMDGPU::getNamedOperandIdx(
Opc, AMDGPU::OpName::src2);
3243 for (
const MachineOperand &Use :
MI->explicit_uses()) {
3244 const int LegacyVALUNotDotWritesVGPRWaitStates = 2;
3245 const int SMFMA4x4WritesVGPROverlappedSMFMASrcCWaitStates = 2;
3246 const int SMFMA16x16WritesVGPROverlappedSMFMASrcCWaitStates = 8;
3247 const int SMFMA32x32WritesVGPROverlappedSMFMASrcCWaitStates = 16;
3248 const int SMFMA4x4WritesVGPROverlappedDMFMASrcCWaitStates = 3;
3249 const int SMFMA16x16WritesVGPROverlappedDMFMASrcCWaitStates = 9;
3250 const int SMFMA32x32WritesVGPROverlappedDMFMASrcCWaitStates = 17;
3251 const int DMFMA16x16WritesVGPROverlappedSrcCWaitStates = 9;
3252 const int GFX950_DMFMA16x16WritesVGPROverlappedSrcCWaitStates = 17;
3253 const int DMFMA4x4WritesVGPROverlappedSrcCWaitStates = 4;
3254 const int SMFMA4x4WritesVGPROverlappedSrcABWaitStates = 5;
3255 const int SMFMA16x16WritesVGPROverlappedSrcABWaitStates = 11;
3256 const int SMFMA32x32WritesVGPROverlappedSrcABWaitStates = 19;
3257 const int DMFMA4x4WritesVGPROverlappedMFMASrcABWaitStates = 6;
3258 const int DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates = 11;
3259 const int GFX950_DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates = 19;
3260 const int DMFMA4x4WritesVGPRFullSrcCWaitStates = 4;
3261 const int GFX940_SMFMA4x4WritesVGPRFullSrcCWaitStates = 2;
3262 const int MaxWaitStates = 19;
3268 const MachineInstr *MI1;
3270 auto IsOverlappedMFMAFn = [
Reg, &FullReg, &MI1,
3271 this](
const MachineInstr &
MI) {
3275 FullReg = (DstReg ==
Reg);
3277 return TRI.regsOverlap(DstReg,
Reg);
3280 WaitStatesNeededForUse = LegacyVALUNotDotWritesVGPRWaitStates -
3281 getWaitStatesSinceDef(
Reg, IsLegacyVALUNotDotFn, MaxWaitStates);
3282 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3285 getWaitStatesSinceDef(
Reg, IsOverlappedMFMAFn, MaxWaitStates);
3286 if (NumWaitStates == std::numeric_limits<int>::max())
3289 int OpNo =
Use.getOperandNo();
3291 int NeedWaitStates = 0;
3292 if (OpNo == SrcCIdx) {
3296 }
else if (FullReg) {
3297 if ((
Opc == AMDGPU::V_MFMA_F64_4X4X4F64_e64 ||
3298 Opc == AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64) &&
3299 (Opc1 == AMDGPU::V_MFMA_F64_4X4X4F64_e64 ||
3300 Opc1 == AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64))
3301 NeedWaitStates = DMFMA4x4WritesVGPRFullSrcCWaitStates;
3302 else if (ST.hasGFX940Insts() &&
3303 TSchedModel.computeInstrLatency(MI1) == 2)
3304 NeedWaitStates = GFX940_SMFMA4x4WritesVGPRFullSrcCWaitStates;
3307 case AMDGPU::V_MFMA_F64_16X16X4F64_e64:
3308 case AMDGPU::V_MFMA_F64_16X16X4F64_vgprcd_e64:
3309 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_e64:
3310 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_vgprcd_e64:
3311 if (!TII.isXDL(*
MI))
3314 ? GFX950_DMFMA16x16WritesVGPROverlappedSrcCWaitStates
3315 : DMFMA16x16WritesVGPROverlappedSrcCWaitStates;
3317 case AMDGPU::V_MFMA_F64_4X4X4F64_e64:
3318 case AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64:
3319 if (!TII.isXDL(*
MI))
3320 NeedWaitStates = DMFMA4x4WritesVGPROverlappedSrcCWaitStates;
3323 int NumPasses = TSchedModel.computeInstrLatency(MI1);
3324 if (ST.hasGFX940Insts()) {
3325 if (TII.isXDL(*
MI) && !TII.isXDL(*MI1))
3332 NumPasses, ST.hasGFX950Insts())
3334 NumPasses, ST.hasGFX950Insts()))
3340 switch (NumPasses) {
3344 ? SMFMA4x4WritesVGPROverlappedDMFMASrcCWaitStates
3345 : SMFMA4x4WritesVGPROverlappedSMFMASrcCWaitStates;
3350 ? SMFMA16x16WritesVGPROverlappedDMFMASrcCWaitStates
3351 : SMFMA16x16WritesVGPROverlappedSMFMASrcCWaitStates;
3356 ? SMFMA32x32WritesVGPROverlappedDMFMASrcCWaitStates
3357 : SMFMA32x32WritesVGPROverlappedSMFMASrcCWaitStates;
3366 case AMDGPU::V_MFMA_F64_16X16X4F64_e64:
3367 case AMDGPU::V_MFMA_F64_16X16X4F64_vgprcd_e64:
3368 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_e64:
3369 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_vgprcd_e64:
3372 ? GFX950_DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates
3373 : DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates;
3375 case AMDGPU::V_MFMA_F64_4X4X4F64_e64:
3376 case AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64:
3377 NeedWaitStates = DMFMA4x4WritesVGPROverlappedMFMASrcABWaitStates;
3380 int NumPasses = TSchedModel.computeInstrLatency(MI1);
3382 if (ST.hasGFX940Insts()) {
3386 NumPasses, ST.hasGFX950Insts())
3392 switch (NumPasses) {
3394 NeedWaitStates = SMFMA4x4WritesVGPROverlappedSrcABWaitStates;
3399 NeedWaitStates = SMFMA16x16WritesVGPROverlappedSrcABWaitStates;
3403 NeedWaitStates = SMFMA32x32WritesVGPROverlappedSrcABWaitStates;
3407 if (WaitStatesNeeded >= NeedWaitStates)
3410 WaitStatesNeededForUse = NeedWaitStates - NumWaitStates;
3411 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3413 if (WaitStatesNeeded == MaxWaitStates)
3418 WaitStatesNeeded = std::max(WaitStatesNeeded, checkMFMAPadding(
MI));
3420 return WaitStatesNeeded;
3423int GCNHazardRecognizer::checkMAILdStHazards(
MachineInstr *
MI)
const {
3425 if (!ST.hasMAIInsts() || ST.hasGFX90AInsts())
3428 int WaitStatesNeeded = 0;
3430 auto IsAccVgprReadFn = [](
const MachineInstr &
MI) {
3431 return MI.getOpcode() == AMDGPU::V_ACCVGPR_READ_B32_e64;
3434 for (
const MachineOperand &
Op :
MI->explicit_uses()) {
3435 if (!
Op.isReg() || !TRI.isVGPR(MF.getRegInfo(),
Op.getReg()))
3440 const int AccVgprReadLdStWaitStates = 2;
3441 const int VALUWriteAccVgprRdWrLdStDepVALUWaitStates = 1;
3442 const int MaxWaitStates = 2;
3444 int WaitStatesNeededForUse = AccVgprReadLdStWaitStates -
3445 getWaitStatesSinceDef(
Reg, IsAccVgprReadFn, MaxWaitStates);
3446 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3448 if (WaitStatesNeeded == MaxWaitStates)
3449 return WaitStatesNeeded;
3451 auto IsVALUAccVgprRdWrCheckFn = [
Reg,
this](
const MachineInstr &
MI) {
3452 if (
MI.getOpcode() != AMDGPU::V_ACCVGPR_READ_B32_e64 &&
3453 MI.getOpcode() != AMDGPU::V_ACCVGPR_WRITE_B32_e64)
3455 auto IsVALUFn = [](
const MachineInstr &
MI) {
3459 return getWaitStatesSinceDef(
Reg, IsVALUFn, 2 ) <
3460 std::numeric_limits<int>::max();
3463 WaitStatesNeededForUse = VALUWriteAccVgprRdWrLdStDepVALUWaitStates -
3464 getWaitStatesSince(IsVALUAccVgprRdWrCheckFn, MaxWaitStates);
3465 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3468 return WaitStatesNeeded;
3471int GCNHazardRecognizer::checkPermlaneHazards(
MachineInstr *
MI)
const {
3472 assert(!ST.hasVcmpxPermlaneHazard() &&
3473 "this is a different vcmpx+permlane hazard");
3474 const SIRegisterInfo *TRI = ST.getRegisterInfo();
3475 const SIInstrInfo *TII = ST.getInstrInfo();
3477 auto IsVCmpXWritesExecFn = [TII, TRI](
const MachineInstr &
MI) {
3481 auto IsVALUFn = [](
const MachineInstr &
MI) {
3485 const int VCmpXWritesExecWaitStates = 4;
3486 const int VALUWritesVDstWaitStates = 2;
3487 int WaitStatesNeeded = 0;
3489 for (
const MachineOperand &
Op :
MI->explicit_uses()) {
3490 if (!
Op.isReg() || !TRI->isVGPR(MF.getRegInfo(),
Op.getReg()))
3494 int WaitStatesSinceDef =
3495 VALUWritesVDstWaitStates -
3496 getWaitStatesSinceDef(
Reg, IsVALUFn,
3497 VALUWritesVDstWaitStates);
3498 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesSinceDef);
3499 if (WaitStatesNeeded >= VALUWritesVDstWaitStates)
3503 int VCmpXHazardWaits =
3504 VCmpXWritesExecWaitStates -
3505 getWaitStatesSince(IsVCmpXWritesExecFn, VCmpXWritesExecWaitStates);
3507 WaitStatesNeeded = std::max(WaitStatesNeeded, VCmpXHazardWaits);
3508 return WaitStatesNeeded;
3516 return NumPasses + 2;
3526 return NumPasses + 3 + (NumPasses != 2 && IsGFX950);
3536 return NumPasses + 3 + (NumPasses != 2 && IsGFX950);
3544 return NumPasses + 2;
3547int GCNHazardRecognizer::checkMAIVALUHazards(
MachineInstr *
MI)
const {
3548 if (!ST.hasGFX90AInsts())
3551 auto IsDGEMMFn = [](
const MachineInstr &
MI) ->
bool {
3559 const MachineRegisterInfo &MRI = MF.getRegInfo();
3561 int WaitStatesNeeded = 0;
3567 const MachineInstr *
MFMA =
nullptr;
3569 auto IsMFMAWriteFn = [&
Reg, &
MFMA,
this](
const MachineInstr &
MI) {
3571 !TRI.regsOverlap(
MI.getOperand(0).getReg(),
Reg))
3577 const MachineInstr *
DOT =
nullptr;
3578 auto IsDotWriteFn = [&
Reg, &
DOT,
this](
const MachineInstr &
MI) {
3580 !TRI.regsOverlap(
MI.getOperand(0).getReg(),
Reg))
3586 bool DGEMMAfterVALUWrite =
false;
3587 auto IsDGEMMHazard = [&DGEMMAfterVALUWrite,
this](
const MachineInstr &
MI) {
3590 DGEMMAfterVALUWrite =
true;
3594 if (!TII.isVALU(
MI,
true) || !DGEMMAfterVALUWrite)
3600 int SrcCIdx = AMDGPU::getNamedOperandIdx(
MI->getOpcode(),
3601 AMDGPU::OpName::src2);
3603 if (IsMemOrExport || IsVALU) {
3604 const int SMFMA4x4WriteVgprVALUMemExpReadWaitStates = 5;
3605 const int SMFMA16x16WriteVgprVALUMemExpReadWaitStates = 11;
3606 const int SMFMA32x32WriteVgprVALUMemExpReadWaitStates = 19;
3607 const int DMFMA4x4WriteVgprMemExpReadWaitStates = 9;
3608 const int DMFMA16x16WriteVgprMemExpReadWaitStates = 18;
3609 const int DMFMA4x4WriteVgprVALUReadWaitStates = 6;
3610 const int DMFMA16x16WriteVgprVALUReadWaitStates = 11;
3611 const int GFX950_DMFMA16x16WriteVgprVALUReadWaitStates = 19;
3612 const int DotWriteSameDotReadSrcAB = 3;
3613 const int DotWriteDifferentVALURead = 3;
3614 const int DMFMABetweenVALUWriteVMEMRead = 2;
3615 const int MaxWaitStates = 19;
3617 for (
const MachineOperand &Use :
MI->explicit_uses()) {
3623 int WaitStatesSinceDef = getWaitStatesSinceDef(
Reg, IsDotWriteFn,
3626 int NeedWaitStates = 0;
3627 if (
DOT->getOpcode() ==
MI->getOpcode()) {
3628 if (&Use - &
MI->getOperand(0) != SrcCIdx)
3629 NeedWaitStates = DotWriteSameDotReadSrcAB;
3631 NeedWaitStates = DotWriteDifferentVALURead;
3634 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceDef;
3635 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3642 if (IsMem && ST.hasGFX90AInsts() && !ST.hasGFX940Insts()) {
3643 DGEMMAfterVALUWrite =
false;
3644 if (TRI.isVectorRegister(MRI,
Reg)) {
3645 int WaitStatesNeededForUse =
3646 DMFMABetweenVALUWriteVMEMRead -
3647 getWaitStatesSinceDef(
Reg, IsDGEMMHazard,
3648 DMFMABetweenVALUWriteVMEMRead);
3650 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3655 WaitStatesSinceDef =
3656 getWaitStatesSinceDef(
Reg, IsMFMAWriteFn, MaxWaitStates);
3660 unsigned HazardDefLatency = TSchedModel.computeInstrLatency(
MFMA);
3661 int NumPasses = HazardDefLatency;
3662 int NeedWaitStates = MaxWaitStates;
3665 switch (HazardDefLatency) {
3667 NeedWaitStates = IsMemOrExport ? DMFMA4x4WriteVgprMemExpReadWaitStates
3668 : DMFMA4x4WriteVgprVALUReadWaitStates;
3674 ? DMFMA16x16WriteVgprMemExpReadWaitStates
3675 : (ST.hasGFX950Insts()
3676 ? GFX950_DMFMA16x16WriteVgprVALUReadWaitStates
3677 : DMFMA16x16WriteVgprVALUReadWaitStates);
3682 }
else if (ST.hasGFX940Insts()) {
3686 NumPasses, ST.hasGFX950Insts())
3690 switch (HazardDefLatency) {
3692 NeedWaitStates = SMFMA4x4WriteVgprVALUMemExpReadWaitStates;
3695 NeedWaitStates = SMFMA16x16WriteVgprVALUMemExpReadWaitStates;
3698 NeedWaitStates = SMFMA32x32WriteVgprVALUMemExpReadWaitStates;
3705 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceDef;
3706 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3708 if (WaitStatesNeeded == MaxWaitStates)
3713 unsigned Opc =
MI->getOpcode();
3714 const int DMFMAToFMA64WaitStates = 2;
3715 if ((
Opc == AMDGPU::V_FMA_F64_e64 ||
3716 Opc == AMDGPU::V_FMAC_F64_e32 ||
Opc == AMDGPU::V_FMAC_F64_e64 ||
3717 Opc == AMDGPU::V_FMAC_F64_dpp) &&
3718 WaitStatesNeeded < DMFMAToFMA64WaitStates) {
3719 int WaitStatesNeededForUse = DMFMAToFMA64WaitStates -
3720 getWaitStatesSince(IsDGEMMFn, DMFMAToFMA64WaitStates);
3721 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3724 if (!IsVALU && !IsMemOrExport)
3725 return WaitStatesNeeded;
3727 for (
const MachineOperand &Def :
MI->defs()) {
3728 const int SMFMA4x4WriteVgprVALUWawWaitStates = 5;
3729 const int SMFMA16x16WriteVgprVALUWawWaitStates = 11;
3730 const int SMFMA32x32WriteVgprVALUWawWaitStates = 19;
3731 const int SMFMA4x4ReadVgprVALUWarWaitStates = 1;
3732 const int GFX940_XDL4PassReadVgprVALUWarWaitStates = 3;
3733 const int SMFMA16x16ReadVgprVALUWarWaitStates = 7;
3734 const int SMFMA32x32ReadVgprVALUWarWaitStates = 15;
3735 const int DMFMA4x4WriteVgprVALUWriteWaitStates = 6;
3736 const int DMFMA16x16WriteVgprVALUWriteWaitStates = 11;
3737 const int DotWriteDifferentVALUWrite = 3;
3738 const int MaxWaitStates = 19;
3739 const int MaxWarWaitStates = 15;
3744 int WaitStatesSinceDef = getWaitStatesSinceDef(
Reg, IsDotWriteFn,
3746 if (DOT &&
DOT->getOpcode() !=
MI->getOpcode())
3747 WaitStatesNeeded = std::max(WaitStatesNeeded, DotWriteDifferentVALUWrite -
3748 WaitStatesSinceDef);
3751 WaitStatesSinceDef =
3752 getWaitStatesSinceDef(
Reg, IsMFMAWriteFn, MaxWaitStates);
3754 int NeedWaitStates = MaxWaitStates;
3755 int NumPasses = TSchedModel.computeInstrLatency(
MFMA);
3758 switch (NumPasses) {
3760 NeedWaitStates = DMFMA4x4WriteVgprVALUWriteWaitStates;
3764 NeedWaitStates = DMFMA16x16WriteVgprVALUWriteWaitStates;
3769 }
else if (ST.hasGFX940Insts()) {
3773 NumPasses, ST.hasGFX950Insts())
3776 switch (NumPasses) {
3778 NeedWaitStates = SMFMA4x4WriteVgprVALUWawWaitStates;
3781 NeedWaitStates = SMFMA16x16WriteVgprVALUWawWaitStates;
3784 NeedWaitStates = SMFMA32x32WriteVgprVALUWawWaitStates;
3791 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceDef;
3792 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3794 if (WaitStatesNeeded == MaxWaitStates)
3798 auto IsSMFMAReadAsCFn = [&
Reg, &
MFMA,
this](
const MachineInstr &
MI) {
3800 !
MI.readsRegister(
Reg, &TRI))
3803 if (ST.hasGFX940Insts() && !TII.isXDL(
MI))
3806 const MachineOperand *SrcC =
3807 TII.getNamedOperand(
MI, AMDGPU::OpName::src2);
3817 int WaitStatesSinceUse = getWaitStatesSince(IsSMFMAReadAsCFn,
3822 unsigned HazardDefLatency = TSchedModel.computeInstrLatency(
MFMA);
3823 int NeedWaitStates = MaxWaitStates;
3824 switch (HazardDefLatency) {
3825 case 2: NeedWaitStates = SMFMA4x4ReadVgprVALUWarWaitStates;
3827 case 4:
assert(ST.hasGFX940Insts());
3828 NeedWaitStates = GFX940_XDL4PassReadVgprVALUWarWaitStates;
3830 case 8: NeedWaitStates = SMFMA16x16ReadVgprVALUWarWaitStates;
3832 case 16: [[fallthrough]];
3833 default: NeedWaitStates = SMFMA32x32ReadVgprVALUWarWaitStates;
3837 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceUse;
3838 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3841 return WaitStatesNeeded;
3854 return MAI !=
nullptr;
3858 if (IsMFMAFn(*
MI)) {
3859 int W = getWaitStatesSince(IsMFMAFn, 16);
3861 return W < (int)TSchedModel.computeInstrLatency(MAI);
3875 while (
I->isBundledWithPred())
3881 if (
I->getOpcode() != AMDGPU::S_GETPC_B64)
3885 const unsigned NewBytes = 4;
3887 "Unexpected instruction insertion in bundle");
3890 while (NextMI != End && NextMI->isBundledWithPred()) {
3891 for (
auto &Operand : NextMI->operands()) {
3892 if (Operand.isGlobal())
3893 Operand.setOffset(Operand.getOffset() + NewBytes);
3899bool GCNHazardRecognizer::fixVALUMaskWriteHazard(
MachineInstr *
MI) {
3900 if (!ST.hasVALUMaskWriteHazard())
3902 assert(!ST.hasExtendedWaitCounts());
3909 if (!IsSALU && !IsVALU)
3921 const SIRegisterInfo *TRI = ST.getRegisterInfo();
3922 const MachineRegisterInfo &MRI = MF.getRegInfo();
3927 case AMDGPU::EXEC_LO:
3928 case AMDGPU::EXEC_HI:
3930 case AMDGPU::SGPR_NULL:
3931 case AMDGPU::SGPR_NULL64:
3939 return Reg == AMDGPU::VCC ||
Reg == AMDGPU::VCC_LO ||
Reg == AMDGPU::VCC_HI;
3943 SmallSet<Register, 2> HazardSGPRs;
3945 static unsigned getHashValue(
const StateType &State) {
3948 static bool isEqual(
const StateType &
LHS,
const StateType &
RHS) {
3949 return LHS.HazardSGPRs ==
RHS.HazardSGPRs;
3953 SmallVector<const MachineInstr *> WaitInstrs;
3954 StateType InitialState;
3957 MachineOperand *HazardDef =
nullptr;
3958 for (MachineOperand &
Op :
MI->all_defs()) {
3960 if (IgnoreableSGPR(
Reg))
3963 if (
Op.isImplicit())
3965 if (!TRI->isSGPRReg(MRI,
Reg))
3978 if (AMDGPU::SReg_32RegClass.
contains(HazardReg)) {
3979 InitialState.HazardSGPRs.insert(HazardReg);
3982 InitialState.HazardSGPRs.insert(TRI->getSubReg(HazardReg, AMDGPU::sub0));
3983 InitialState.HazardSGPRs.insert(TRI->getSubReg(HazardReg, AMDGPU::sub1));
3986 auto IsHazardFn = [&](StateType &State,
const MachineInstr &
I) {
3987 if (State.HazardSGPRs.empty())
3990 switch (
I.getOpcode()) {
3991 case AMDGPU::V_ADDC_U32_e32:
3992 case AMDGPU::V_ADDC_U32_dpp:
3993 case AMDGPU::V_CNDMASK_B16_t16_e32:
3994 case AMDGPU::V_CNDMASK_B16_fake16_e32:
3995 case AMDGPU::V_CNDMASK_B16_t16_dpp:
3996 case AMDGPU::V_CNDMASK_B16_fake16_dpp:
3997 case AMDGPU::V_CNDMASK_B32_e32:
3998 case AMDGPU::V_CNDMASK_B32_dpp:
3999 case AMDGPU::V_DIV_FMAS_F32_e64:
4000 case AMDGPU::V_DIV_FMAS_F64_e64:
4001 case AMDGPU::V_SUBB_U32_e32:
4002 case AMDGPU::V_SUBB_U32_dpp:
4003 case AMDGPU::V_SUBBREV_U32_e32:
4004 case AMDGPU::V_SUBBREV_U32_dpp: {
4008 case AMDGPU::V_ADDC_U32_e64:
4009 case AMDGPU::V_ADDC_U32_e64_dpp:
4010 case AMDGPU::V_CNDMASK_B16_t16_e64:
4011 case AMDGPU::V_CNDMASK_B16_fake16_e64:
4012 case AMDGPU::V_CNDMASK_B16_t16_e64_dpp:
4013 case AMDGPU::V_CNDMASK_B16_fake16_e64_dpp:
4014 case AMDGPU::V_CNDMASK_B32_e64:
4015 case AMDGPU::V_CNDMASK_B32_e64_dpp:
4016 case AMDGPU::V_SUBB_U32_e64:
4017 case AMDGPU::V_SUBB_U32_e64_dpp:
4018 case AMDGPU::V_SUBBREV_U32_e64:
4019 case AMDGPU::V_SUBBREV_U32_e64_dpp: {
4021 const MachineOperand *SSRCOp = TII.getNamedOperand(
I, AMDGPU::OpName::src2);
4023 bool Result = TRI->regsOverlap(SSRCOp->
getReg(), HazardReg);
4031 auto UpdateStateFn = [&](StateType &State,
const MachineInstr &
I) {
4033 for (
auto &
Op :
I.all_defs()) {
4035 if (IgnoreableSGPR(
Reg))
4038 if (
Op.isImplicit())
4040 if (!TRI->isSGPRReg(MRI,
Reg))
4047 for (
Register SGPR : State.HazardSGPRs) {
4048 if (
Reg == SGPR || TRI->regsOverlap(
Reg, SGPR))
4052 State.HazardSGPRs.erase(SGPR);
4059 std::next(
MI->getReverseIterator())))
4069 auto NextMI = std::next(
MI->getIterator());
4070 auto NewMI =
BuildMI(*
MI->getParent(), NextMI,
MI->getDebugLoc(),
4071 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
4083 if (EntryMBB.
begin() != EntryMBB.
end()) {
4084 auto &EntryMI = *EntryMBB.
begin();
4085 if (EntryMI.getOpcode() == AMDGPU::S_SETPRIO &&
4086 EntryMI.getOperand(0).getImm() >= Priority)
4095bool GCNHazardRecognizer::fixRequiredExportPriority(
MachineInstr *
MI) {
4096 if (!ST.hasRequiredExportPriority())
4101 MachineBasicBlock *
MBB =
MI->getParent();
4114 const int MaxPriority = 3;
4115 const int NormalPriority = 2;
4116 const int PostExportPriority = 0;
4118 auto It =
MI->getIterator();
4119 switch (
MI->getOpcode()) {
4120 case AMDGPU::S_ENDPGM:
4121 case AMDGPU::S_ENDPGM_SAVED:
4122 case AMDGPU::S_ENDPGM_ORDERED_PS_DONE:
4123 case AMDGPU::SI_RETURN_TO_EPILOG:
4126 if (MF->getFrameInfo().hasCalls())
4129 case AMDGPU::S_SETPRIO: {
4131 auto &PrioOp =
MI->getOperand(0);
4132 int Prio = PrioOp.getImm();
4133 bool InWA = (Prio == PostExportPriority) &&
4134 (It !=
MBB->
begin() && TII.isEXP(*std::prev(It)));
4135 if (InWA || Prio >= NormalPriority)
4137 PrioOp.setImm(std::min(Prio + NormalPriority, MaxPriority));
4141 if (!TII.isEXP(*
MI))
4152 auto NextMI = std::next(It);
4153 bool EndOfShader =
false;
4154 if (NextMI !=
MBB->
end()) {
4156 if (TII.isEXP(*NextMI))
4159 if (NextMI->getOpcode() == AMDGPU::S_SETPRIO &&
4160 NextMI->getOperand(0).getImm() == PostExportPriority)
4162 EndOfShader = NextMI->getOpcode() == AMDGPU::S_ENDPGM;
4169 .
addImm(PostExportPriority);
4173 BuildMI(*
MBB, NextMI,
DL, TII.get(AMDGPU::S_WAITCNT_EXPCNT))
4174 .
addReg(AMDGPU::SGPR_NULL)
4194 const SIInstrInfo *TII = ST.getInstrInfo();
4206 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4211bool GCNHazardRecognizer::fixDsAtomicAsyncBarrierArriveB64(
MachineInstr *
MI) {
4212 if (
MI->getOpcode() != AMDGPU::DS_ATOMIC_ASYNC_BARRIER_ARRIVE_B64)
4215 const SIInstrInfo *TII = ST.getInstrInfo();
4217 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4219 BuildMI(*
MI->getParent(), std::next(
MI->getIterator()),
MI->getDebugLoc(),
4220 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4226bool GCNHazardRecognizer::fixScratchBaseForwardingHazard(
MachineInstr *
MI) {
4232 const SIRegisterInfo *TRI = ST.getRegisterInfo();
4233 const SIInstrInfo *TII = ST.getInstrInfo();
4235 const int FlatScrBaseWaitStates = 10;
4237 bool ReadsFlatScrLo =
4238 MI->readsRegister(AMDGPU::SRC_FLAT_SCRATCH_BASE_LO, TRI);
4239 bool ReadsFlatScrHi =
4240 MI->readsRegister(AMDGPU::SRC_FLAT_SCRATCH_BASE_HI, TRI);
4246 ReadsFlatScrLo =
true;
4249 ReadsFlatScrHi =
true;
4254 const MachineRegisterInfo &MRI = MF.getRegInfo();
4257 DenseSet<const MachineBasicBlock *> Visited;
4259 return MI.modifiesRegister(
Reg, TRI);
4264 auto IsSGPRDef = [TII, TRI, &MRI](
const MachineInstr &
MI) ->
unsigned {
4265 if (!TII->isSALU(
MI) && !TII->isVALU(
MI,
true))
4267 for (
const MachineOperand &MO :
MI.all_defs()) {
4268 if (TRI->isSGPRReg(MRI, MO.getReg()))
4274 auto IsExpiredFn = [=](
const MachineInstr &
MI,
int SgprWrites) {
4275 if (
MI.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR) {
4276 unsigned Wait =
MI.getOperand(0).getImm();
4281 return SgprWrites >= FlatScrBaseWaitStates;
4284 return ::getWaitStatesSince(
4285 IsHazardFn,
MI->getParent(), std::next(
MI->getReverseIterator()),
4286 0,
IsExpiredFn, Visited, IsSGPRDef) < FlatScrBaseWaitStates;
4290 !IsRegDefHazard(AMDGPU::SGPR102)) &&
4292 !IsRegDefHazard(AMDGPU::SGPR103)))
4296 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4307 BuildMI(*
MI->getParent(),
MI,
MI->getDebugLoc(), TII.get(AMDGPU::V_NOP_e32));
4308 BuildMI(*
MI->getParent(),
MI,
MI->getDebugLoc(), TII.get(AMDGPU::V_NOP_e32));
4313 auto IsTDM = [&](
const MachineInstr &
MI) ->
bool {
4315 MI.getOpcode() != AMDGPU::S_WAIT_TENSORCNT;
4322 if (
MI.getOpcode() != AMDGPU::S_WAIT_TENSORCNT)
4324 return MI.getOperand(0).getImm() <= 10;
4328 std::numeric_limits<int>::max())
4332 TII.get(AMDGPU::S_WAIT_TENSORCNT))
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
Provides AMDGPU specific target descriptions.
AMDGPU Rewrite AGPR Copy MFMA
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 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 isFLAT(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)
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...