LLVM 24.0.0git
GCNHazardRecognizer.cpp
Go to the documentation of this file.
1//===-- GCNHazardRecognizers.cpp - GCN Hazard Recognizer Impls ------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements hazard recognizers for scheduling on GCN processors.
10//
11//===----------------------------------------------------------------------===//
12
13#include "GCNHazardRecognizer.h"
14#include "AMDGPUTargetMachine.h"
15#include "AMDGPUWaitcntUtils.h"
16#include "GCNSubtarget.h"
18#include "llvm/ADT/Statistic.h"
23#include "llvm/Support/Debug.h"
25
26using namespace llvm;
27
28#define DEBUG_TYPE "gcn-hazard-recognizer"
29// Opt-in debug type for the per-candidate co-execution slot traces, which are
30// far too noisy for the normal debug output. Pass both types to get everything.
31#define DEBUG_TYPE_VERBOSE "gcn-hazard-recognizer-verbose"
32
33STATISTIC(NumWMMANopsHoisted,
34 "Number of WMMA hazard V_NOPs hoisted from loops");
35STATISTIC(NumWMMAHoistingBailed,
36 "Number of WMMA hazards where V_NOP hoisting was not possible");
37
38namespace {
39
40struct MFMAPaddingRatioParser : public cl::parser<unsigned> {
41 MFMAPaddingRatioParser(cl::Option &O) : cl::parser<unsigned>(O) {}
42
43 bool parse(cl::Option &O, StringRef ArgName, StringRef Arg, unsigned &Value) {
44 if (Arg.getAsInteger(0, Value))
45 return O.error("'" + Arg + "' value invalid for uint argument!");
46
47 if (Value > 100)
48 return O.error("'" + Arg + "' value must be in the range [0, 100]!");
49
50 return false;
51 }
52};
53
54} // end anonymous namespace
55
57 MFMAPaddingRatio("amdgpu-mfma-padding-ratio", cl::init(0), cl::Hidden,
58 cl::desc("Fill a percentage of the latency between "
59 "neighboring MFMA with s_nops."));
60
61//===----------------------------------------------------------------------===//
62// Hazard Recognizer Implementation
63//===----------------------------------------------------------------------===//
64
66 const GCNSubtarget &ST);
67
70 MachineLoopInfo *MLI)
71 : Mode(Mode), CurrCycleInstr(nullptr), MF(MF),
72 ST(MF.getSubtarget<GCNSubtarget>()), TII(*ST.getInstrInfo()),
73 TRI(TII.getRegisterInfo()), TSchedModel(TII.getSchedModel()), MLI(MLI),
74 ClauseUses(TRI.getNumRegUnits()), ClauseDefs(TRI.getNumRegUnits()) {
75 MaxLookAhead = MF.getRegInfo().isPhysRegUsed(AMDGPU::AGPR0) ? 19 : 5;
76 RunLdsBranchVmemWARHazardFixup = shouldRunLdsBranchVmemWARHazardFixup(MF, ST);
78 if (isPreRA())
79 dbgs() << " PreRA hazard recognizer: " << MF.getName() << "\n";
80 });
81}
82
86
88 // Dump any active co-execution window that did not complete naturally
89 // (e.g. region ended before the window expired).
91 if (CurrentCoExecStage.has_value()) {
92 unsigned Stage = *CurrentCoExecStage;
93 if (Stage < AMDGPU::MaxCoExecStages)
94 CoExecWindowLog[Stage] = ActiveCoExecInfo.Pattern[Stage];
95 dbgs() << " CoExec window ended at stage " << Stage << ":\n";
96 dumpCoExecWindow();
97 }
98 });
99}
100
102 EmittedInstrs.clear();
103 EmittedVALUInstrs.clear();
104 HasPendingWMMACoexecHazard = false;
105 if (isSchedulerMode())
106 schedulerReset();
107}
108
109void GCNHazardRecognizer::schedulerReset() {
110 LLVM_DEBUG({
111 if (CurrentCoExecStage.has_value() || CyclesUntilTRANS > 0 ||
112 CyclesUntilVALU > 0)
113 dbgs() << " Scheduler Reset: clearing co-exec window, TRANS="
114 << CyclesUntilTRANS << ", VALU=" << CyclesUntilVALU << "\n";
115 });
116 CurrentCoExecStage = std::nullopt;
117 CoExecWindowStartCycle = 0;
118 CyclesUntilTRANS = 0;
119 CyclesUntilVALU = 0;
120 ActiveCoExecInfo = AMDGPU::CoExecInfo();
121 CoExecWindowLog.fill('.');
122}
123
124void GCNHazardRecognizer::dumpCoExecWindow() const {
125 unsigned W = ActiveCoExecInfo.TotalWindow;
126 if (W == 0)
127 return;
128
129 // Print the stage numbers row.
130 dbgs() << " Stages: ";
131 for (unsigned I = 0; I < W; ++I)
132 dbgs() << I % 10 << ' ';
133 dbgs() << '\n';
134
135 // Print the pattern row.
136 dbgs() << " Slots: ";
137 for (unsigned I = 0; I < W; ++I)
138 dbgs() << ActiveCoExecInfo.Pattern[I] << ' ';
139 dbgs() << '\n';
140
141 // Print the scheduled row.
142 dbgs() << " Scheduled: ";
143 for (unsigned I = 0; I < W; ++I)
144 dbgs() << CoExecWindowLog[I] << ' ';
145 dbgs() << '\n';
146}
147
148void GCNHazardRecognizer::schedulerAdvanceCycle() {
149 // Record what happened at the current stage of the co-exec window.
150 if (CurrentCoExecStage.has_value()) {
151 unsigned Stage = *CurrentCoExecStage;
152 if (Stage < AMDGPU::MaxCoExecStages) {
153 if (CurrCycleInstr)
154 CoExecWindowLog[Stage] = ActiveCoExecInfo.Pattern[Stage];
155 else
156 CoExecWindowLog[Stage] = '-';
157 }
158 }
159
160 LLVM_DEBUG({
161 bool HasState = CurrentCoExecStage.has_value() || CyclesUntilTRANS > 0 ||
162 CyclesUntilVALU > 0;
163 if (HasState) {
164 dbgs() << " Scheduler AdvanceCycle:";
165 if (CurrentCoExecStage.has_value()) {
166 unsigned Stage = *CurrentCoExecStage;
167 unsigned Next = Stage + 1;
168 if (Next >= ActiveCoExecInfo.TotalWindow)
169 dbgs() << " stage " << Stage << "->expired";
170 else
171 dbgs() << " stage " << Stage << "->" << Next;
172 }
173 if (CyclesUntilTRANS > 0)
174 dbgs() << " TRANS=" << CyclesUntilTRANS << "->"
175 << (CyclesUntilTRANS - 1);
176 if (CyclesUntilVALU > 0)
177 dbgs() << " VALU=" << CyclesUntilVALU << "->" << (CyclesUntilVALU - 1);
178 dbgs() << "\n";
179 }
180 });
181
182 // Decrement hazard counters.
183 if (CyclesUntilTRANS > 0)
184 --CyclesUntilTRANS;
185 if (CyclesUntilVALU > 0)
186 --CyclesUntilVALU;
187
188 // Advance WMMA co-execution window.
189 if (CurrentCoExecStage.has_value()) {
190 unsigned Stage = *CurrentCoExecStage + 1;
191 if (Stage >= ActiveCoExecInfo.TotalWindow) {
192 // Window expired.
193 LLVM_DEBUG({
194 dbgs() << " CoExec window complete:\n";
195 dumpCoExecWindow();
196 });
197 CurrentCoExecStage = std::nullopt;
198 } else {
199 CurrentCoExecStage = Stage;
200 }
201 }
202}
203
204bool GCNHazardRecognizer::hasCoExecWindowModel() const {
205 // The co-execution slot patterns returned by getCoExecInfo() are derived from
206 // gfx1250 timings, so the window model is restricted to gfx1250 for now.
207 // gfx1251 and gfx12.5-generic report the same co-execution hazard features
208 // but have different WMMA latencies, so they need their own slot patterns
209 // before they can be modeled here.
210 if (ST.hasWMMACoexecutionHazards() && ST.hasTransCoexecutionHazard() &&
212 return true;
213
214 if (ST.hasGFX950Insts() &&
215 AMDGPU::getSchedStrategy(ST.getCLOpts(), MF.getFunction()) == "coexec")
216 return true;
217
218 return false;
219}
220
221void GCNHazardRecognizer::updateWMMAWindowState(const MachineInstr &MI) {
222 if (!hasCoExecWindowModel())
223 return;
224
227 return;
228
229 // If a previous window was still active, dump it before starting a new one.
230 // Record the current stage (filled by this new WMMA) before dumping.
231 LLVM_DEBUG({
232 if (CurrentCoExecStage.has_value()) {
233 unsigned Stage = *CurrentCoExecStage;
234 if (Stage < AMDGPU::MaxCoExecStages)
235 CoExecWindowLog[Stage] = ActiveCoExecInfo.Pattern[Stage];
236 dbgs() << " CoExec window interrupted at stage " << Stage << ":\n";
237 dumpCoExecWindow();
238 }
239 });
240
241 // Start a new co-execution window.
242 ActiveCoExecInfo = AMDGPU::getCoExecInfo(MI, TII);
243 CurrentCoExecStage = 0;
244 CoExecWindowLog.fill('.');
245
246 LLVM_DEBUG(dbgs() << " WMMA window started: " << ActiveCoExecInfo.Pattern
247 << " (window=" << ActiveCoExecInfo.TotalWindow << ")\n"
248 << " " << MI);
249}
250
251void GCNHazardRecognizer::updateTRANSState(const MachineInstr &MI) {
252 if (!hasCoExecWindowModel())
253 return;
255 return;
256
257 // Back-to-back TRANS instructions have a 1-cycle hazard.
258 // This is checked via checkTRANSHazard() and does not create a co-exec
259 // window. The TRANS shadow slot allows anything except TRANS and
260 // multi-cycle VALU.
261 // Set to 2: bumpCycle advances to the next pick's cycle (decrementing
262 // by 1 via AdvanceCycle) before the next instruction's hazard check, so
263 // the counter is observed at 1 there. That 1-cycle stall lets the
264 // strategy pick a non-TRANS, non-multi-cycle-VALU candidate to fill the
265 // shadow slot.
266 CyclesUntilTRANS = 2;
267 LLVM_DEBUG(dbgs() << " TRANS hazard set: CyclesUntilTRANS=2\n");
268}
269
270void GCNHazardRecognizer::updateMultiCycleVALUState(const MachineInstr &MI) {
271 if (!hasCoExecWindowModel())
272 return;
273 // Multi-cycle VALU (CVT, etc.) blocks subsequent VALU for repeat rate cycles.
274 if (!SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true))
275 return;
276
277 // Skip WMMA, MFMA, and TRANS - they have their own tracking.
280 return;
281
282 unsigned RepeatRate = TII.getRepeatRate(MI);
283 if (RepeatRate > 1) {
284 // bumpCycle's AdvanceCycle decrements once before the next pick's
285 // hazard check (same convention as CyclesUntilTRANS), so to expose
286 // RepeatRate-1 cycles of shadow we must seed with RepeatRate.
287 CyclesUntilVALU = RepeatRate;
288 LLVM_DEBUG(dbgs() << " Multi-cycle VALU: repeat=" << RepeatRate
289 << ", CyclesUntilVALU=" << CyclesUntilVALU << "\n");
290 }
291}
292
298
299unsigned GCNHazardRecognizer::checkTRANSHazard(const MachineInstr &MI) const {
300 if (!CyclesUntilTRANS)
301 return 0;
302
303 // Only TRANS and multi-cycle VALU are blocked by the TRANS shadow.
305 return CyclesUntilTRANS;
306
307 if (SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true) &&
309 TII.getRepeatRate(MI) > 1)
310 return CyclesUntilTRANS;
311
312 return 0;
313}
314
315unsigned
316GCNHazardRecognizer::checkMultiCycleVALUHazard(const MachineInstr &MI) const {
317 if (!CyclesUntilVALU)
318 return 0;
319
320 // Multi-cycle VALU blocks anything on the VALU pipe - VALU, WMMA, SWMMAC,
321 // and TRANS - for RepeatRate-1 cycles. Only off-pipe instructions (MEM,
322 // SALU, control) can fill the shadow.
323 if (!SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true) &&
326 return 0;
327
328 return CyclesUntilVALU;
329}
330
331unsigned
332GCNHazardRecognizer::checkWMMACoexecSlot(const MachineInstr &MI) const {
333 // No hazard if not in a WMMA window.
334 if (!CurrentCoExecStage.has_value())
335 return 0;
336
337 unsigned Stage = *CurrentCoExecStage;
339 unsigned StallCycles = ActiveCoExecInfo.getStallCycles(InstMask, Stage);
340
341 // No stall required if the instruction can co-execute at the current stage.
342 if (StallCycles == 0)
343 return 0;
344
345 // Stall for the required number of cycles until the next allowed stage.
346 unsigned NextStage = Stage + StallCycles;
347 if (NextStage < ActiveCoExecInfo.TotalWindow) {
350 dbgs() << " CoExec stall: stage=" << Stage << "("
351 << AMDGPU::getStageTypeName(ActiveCoExecInfo.getType(Stage))
352 << ") mask=" << AMDGPU::getCoExecMaskName(InstMask)
353 << " -> stall " << StallCycles << " (next allowed=" << NextStage
354 << ")\n"
355 << " " << MI);
356 return StallCycles;
357 }
358
359 // No compatible slot in window - stall until window ends.
362 dbgs() << " CoExec stall: stage=" << Stage << "("
363 << AMDGPU::getStageTypeName(ActiveCoExecInfo.getType(Stage))
364 << ") mask=" << AMDGPU::getCoExecMaskName(InstMask) << " -> stall "
365 << StallCycles << " (window ends)\n"
366 << " " << MI);
367 return StallCycles;
368}
369
370unsigned
371GCNHazardRecognizer::checkMultiShadowHazard(const MachineInstr &MI) const {
372 // This models a VALU caught in both a WMMA and a TRANS shadow.
373 if (!hasCoExecWindowModel())
374 return 0;
375
376 // No hazard if not in a WMMA window.
377 if (!CurrentCoExecStage.has_value())
378 return 0;
379
380 if (!CyclesUntilTRANS)
381 return 0;
382
383 if (!SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true) ||
385 return 0;
386
387 // We have a VALU instruction that is under both a TRANS and WMMA shadow.
388 // We need to wait for at least one to clear.
389
390 unsigned LookAheadStage = *CurrentCoExecStage + CyclesUntilTRANS;
392 return CyclesUntilTRANS +
393 ActiveCoExecInfo.getStallCycles(InstMask, LookAheadStage);
394}
395
396void GCNHazardRecognizer::schedulerEmitInstruction(MachineInstr *MI) {
397 LLVM_DEBUG({
398 bool InWindow = CurrentCoExecStage.has_value();
399 bool HasActiveState =
400 InWindow || CyclesUntilTRANS > 0 || CyclesUntilVALU > 0;
401 if (HasActiveState) {
402 if (InWindow) {
403 unsigned Stage = *CurrentCoExecStage;
404 dbgs() << " Stage " << Stage << "("
405 << AMDGPU::getStageTypeName(ActiveCoExecInfo.getType(Stage))
406 << ") Emit ["
408 << "]: " << *MI;
409 } else {
410 dbgs() << " Emit ["
412 << "]: " << *MI;
413 }
414 }
415 });
417 bool HasActiveState = CurrentCoExecStage.has_value() ||
418 CyclesUntilTRANS > 0 || CyclesUntilVALU > 0;
419 if (!HasActiveState)
420 dbgs() << " Emit ["
422 << "]: " << *MI;
423 });
424 updateWMMAWindowState(*MI);
425 updateTRANSState(*MI);
426 updateMultiCycleVALUState(*MI);
427}
428
432
434 CurrCycleInstr = MI;
435 if (isSchedulerMode())
436 schedulerEmitInstruction(MI);
437}
438
439static bool isDivFMas(unsigned Opcode) {
440 return Opcode == AMDGPU::V_DIV_FMAS_F32_e64 || Opcode == AMDGPU::V_DIV_FMAS_F64_e64;
441}
442
443static bool isSGetReg(unsigned Opcode) {
444 return Opcode == AMDGPU::S_GETREG_B32 || Opcode == AMDGPU::S_GETREG_B32_const;
445}
446
447static bool isSSetReg(unsigned Opcode) {
448 switch (Opcode) {
449 case AMDGPU::S_SETREG_B32:
450 case AMDGPU::S_SETREG_B32_mode:
451 case AMDGPU::S_SETREG_IMM32_B32:
452 case AMDGPU::S_SETREG_IMM32_B32_mode:
453 return true;
454 }
455 return false;
456}
457
458static bool isRWLane(unsigned Opcode) {
459 return Opcode == AMDGPU::V_READLANE_B32 || Opcode == AMDGPU::V_WRITELANE_B32;
460}
461
462static bool isRFE(unsigned Opcode) {
463 return Opcode == AMDGPU::S_RFE_B64;
464}
465
466static bool isSMovRel(unsigned Opcode) {
467 switch (Opcode) {
468 case AMDGPU::S_MOVRELS_B32:
469 case AMDGPU::S_MOVRELS_B64:
470 case AMDGPU::S_MOVRELD_B32:
471 case AMDGPU::S_MOVRELD_B64:
472 return true;
473 default:
474 return false;
475 }
476}
477
479 const MachineInstr &MI) {
480 if (TII.isAlwaysGDS(MI.getOpcode()))
481 return true;
482
483 switch (MI.getOpcode()) {
484 case AMDGPU::S_SENDMSG:
485 case AMDGPU::S_SENDMSGHALT:
486 case AMDGPU::S_TTRACEDATA:
487 return true;
488 // These DS opcodes don't support GDS.
489 case AMDGPU::DS_NOP:
490 case AMDGPU::DS_PERMUTE_B32:
491 case AMDGPU::DS_BPERMUTE_B32:
492 return false;
493 default:
494 if (TII.isDS(MI.getOpcode())) {
495 int GDS = AMDGPU::getNamedOperandIdx(MI.getOpcode(),
496 AMDGPU::OpName::gds);
497 if (MI.getOperand(GDS).getImm())
498 return true;
499 }
500 return false;
501 }
502}
503
504static bool isPermlane(const MachineInstr &MI) {
505 unsigned Opcode = MI.getOpcode();
506 return Opcode == AMDGPU::V_PERMLANE16_B32_e64 ||
507 Opcode == AMDGPU::V_PERMLANE64_B32 ||
508 Opcode == AMDGPU::V_PERMLANEX16_B32_e64 ||
509 Opcode == AMDGPU::V_PERMLANE16_VAR_B32_e64 ||
510 Opcode == AMDGPU::V_PERMLANEX16_VAR_B32_e64 ||
511 Opcode == AMDGPU::V_PERMLANE16_SWAP_B32_e32 ||
512 Opcode == AMDGPU::V_PERMLANE16_SWAP_B32_e64 ||
513 Opcode == AMDGPU::V_PERMLANE32_SWAP_B32_e32 ||
514 Opcode == AMDGPU::V_PERMLANE32_SWAP_B32_e64 ||
515 Opcode == AMDGPU::V_PERMLANE_BCAST_B32_e64 ||
516 Opcode == AMDGPU::V_PERMLANE_UP_B32_e64 ||
517 Opcode == AMDGPU::V_PERMLANE_DOWN_B32_e64 ||
518 Opcode == AMDGPU::V_PERMLANE_XOR_B32_e64 ||
519 Opcode == AMDGPU::V_PERMLANE_IDX_GEN_B32_e64;
520}
521
522static bool isLdsDma(const MachineInstr &MI) {
524}
525
526static unsigned getHWReg(const SIInstrInfo *TII, const MachineInstr &RegInstr) {
527 const MachineOperand *RegOp = TII->getNamedOperand(RegInstr,
528 AMDGPU::OpName::simm16);
529 return std::get<0>(AMDGPU::Hwreg::HwregEncoding::decode(RegOp->getImm()));
530}
531
534 MachineInstr *MI = SU->getInstr();
535 // If we are not in "HazardRecognizerMode" and therefore not being run from
536 // the scheduler, track possible stalls from hazards but don't insert noops.
538
539 if (MI->isBundle())
540 return NoHazard;
541
542 // Check co-execution slot hazards and pipeline stalls in scheduler modes.
543 if (isSchedulerMode()) {
544 if (checkMultiShadowHazard(*MI) > 0)
545 return Hazard;
546 if (checkWMMACoexecSlot(*MI) > 0)
547 return Hazard;
548 if (checkTRANSHazard(*MI) > 0)
549 return Hazard;
550 if (checkMultiCycleVALUHazard(*MI) > 0)
551 return Hazard;
552 // The remaining checks are all defined by register dependences.
553 if (!hasPhysRegs())
554 return NoHazard;
555 }
556
557 if (SIInstrInfo::isSMRD(*MI) && checkSMRDHazards(MI) > 0)
558 return HazardType;
559
560 if (ST.hasNSAtoVMEMBug() && checkNSAtoVMEMHazard(MI) > 0)
561 return HazardType;
562
563 if (checkFPAtomicToDenormModeHazard(MI) > 0)
564 return HazardType;
565
566 // Hazards which cannot be mitigated with S_NOPs.
567 if (!isHazardRecognizerMode()) {
568 if (checkWMMACoexecutionHazards(MI) > 0) {
569 HasPendingWMMACoexecHazard = true;
570 return Hazard;
571 }
572 }
573
574 if (ST.hasNoDataDepHazard())
575 return NoHazard;
576
577 if (SIInstrInfo::isVMEM(*MI) && checkVMEMHazards(MI) > 0)
578 return HazardType;
579
580 if (SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true) &&
581 checkVALUHazards(MI) > 0)
582 return HazardType;
583
584 if (SIInstrInfo::isDPP(*MI) && checkDPPHazards(MI) > 0)
585 return HazardType;
586
587 if (isDivFMas(MI->getOpcode()) && checkDivFMasHazards(MI) > 0)
588 return HazardType;
589
590 if (isRWLane(MI->getOpcode()) && checkRWLaneHazards(MI) > 0)
591 return HazardType;
592
593 if ((SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true) ||
596 checkMAIVALUHazards(MI) > 0)
597 return HazardType;
598
599 if (isSGetReg(MI->getOpcode()) && checkGetRegHazards(MI) > 0)
600 return HazardType;
601
602 if (isSSetReg(MI->getOpcode()) && checkSetRegHazards(MI) > 0)
603 return HazardType;
604
605 if (isRFE(MI->getOpcode()) && checkRFEHazards(MI) > 0)
606 return HazardType;
607
608 if (((ST.hasReadM0MovRelInterpHazard() &&
609 (TII.isVINTRP(*MI) || isSMovRel(MI->getOpcode()) ||
610 MI->getOpcode() == AMDGPU::DS_WRITE_ADDTID_B32 ||
611 MI->getOpcode() == AMDGPU::DS_READ_ADDTID_B32)) ||
612 (ST.hasReadM0SendMsgHazard() && isSendMsgTraceDataOrGDS(TII, *MI)) ||
613 (ST.hasReadM0LdsDmaHazard() && isLdsDma(*MI)) ||
614 (ST.hasReadM0LdsDirectHazard() &&
615 MI->readsRegister(AMDGPU::LDS_DIRECT, /*TRI=*/nullptr))) &&
616 checkReadM0Hazards(MI) > 0)
617 return HazardType;
618
619 if (SIInstrInfo::isMAI(*MI) && checkMAIHazards(MI) > 0)
620 return HazardType;
621
623 checkMAILdStHazards(MI) > 0)
624 return HazardType;
625
626 if (ST.hasPermlaneForwardingHazard() && isPermlane(*MI) &&
627 checkPermlaneHazards(MI) > 0)
628 return HazardType;
629
630 if (MI->isInlineAsm() && checkInlineAsmHazards(MI) > 0)
631 return HazardType;
632
633 return NoHazard;
634}
635
637 unsigned Quantity) {
638 while (Quantity > 0) {
639 unsigned Arg = std::min(Quantity, 8u);
640 Quantity -= Arg;
641 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), TII.get(AMDGPU::S_NOP))
642 .addImm(Arg - 1);
643 }
644}
645
646unsigned
647GCNHazardRecognizer::getMFMAPipelineWaitStates(const MachineInstr &MI) const {
648 const MCSchedClassDesc *SC = TSchedModel.resolveSchedClass(&MI);
649 assert(TSchedModel.getWriteProcResBegin(SC) !=
650 TSchedModel.getWriteProcResEnd(SC));
651 return TSchedModel.getWriteProcResBegin(SC)->ReleaseAtCycle;
652}
653
654void GCNHazardRecognizer::processBundle() {
655 MachineBasicBlock::instr_iterator MI = std::next(CurrCycleInstr->getIterator());
656 MachineBasicBlock::instr_iterator E = CurrCycleInstr->getParent()->instr_end();
657 // Check bundled MachineInstr's for hazards.
658 for (; MI != E && MI->isInsideBundle(); ++MI) {
659 CurrCycleInstr = &*MI;
660 unsigned WaitStates = PreEmitNoopsCommon(CurrCycleInstr);
661
663 fixHazards(CurrCycleInstr);
664
665 insertNoopsInBundle(CurrCycleInstr, TII, WaitStates);
666 }
667
668 // It’s unnecessary to track more than MaxLookAhead instructions. Since we
669 // include the bundled MI directly after, only add a maximum of
670 // (MaxLookAhead - 1) noops to EmittedInstrs.
671 for (unsigned i = 0, e = std::min(WaitStates, MaxLookAhead - 1); i < e; ++i)
672 EmittedInstrs.push_front(nullptr);
673
674 EmittedInstrs.push_front(CurrCycleInstr);
675 EmittedInstrs.resize(MaxLookAhead);
676 }
677 CurrCycleInstr = nullptr;
678}
679
680void GCNHazardRecognizer::runOnInstruction(MachineInstr *MI) {
682
683 unsigned NumPreNoops = PreEmitNoops(MI);
684 EmitNoops(NumPreNoops);
685 if (MI->isInsideBundle())
686 insertNoopsInBundle(MI, TII, NumPreNoops);
687 else
688 TII.insertNoops(*MI->getParent(), MachineBasicBlock::iterator(MI),
689 NumPreNoops);
691 AdvanceCycle();
692}
693
696 CurrCycleInstr = MI;
697 unsigned W = PreEmitNoopsCommon(MI);
698 fixHazards(MI);
699 CurrCycleInstr = nullptr;
700 return std::max(W, ST.getCLOpts().snop_padding);
701}
702
704 unsigned W = 0;
705
706 // Check co-execution slot hazards and pipeline stalls in scheduler modes.
707 if (isSchedulerMode()) {
708 W = checkWMMACoexecSlot(*MI);
709 W = std::max(W, checkTRANSHazard(*MI));
710 W = std::max(W, checkMultiCycleVALUHazard(*MI));
711 W = std::max(W, checkMultiShadowHazard(*MI));
712 // The remaining checks are all defined by register dependences.
713 if (!hasPhysRegs())
714 return W;
715 }
716
717 return std::max(W, PreEmitNoopsCommon(MI));
718}
719
721 if (MI->isBundle())
722 return 0;
723
724 int WaitStates = 0;
725
727 return std::max(WaitStates, checkSMRDHazards(MI));
728
729 if (ST.hasNSAtoVMEMBug())
730 WaitStates = std::max(WaitStates, checkNSAtoVMEMHazard(MI));
731
732 WaitStates = std::max(WaitStates, checkFPAtomicToDenormModeHazard(MI));
733
734 if (ST.hasNoDataDepHazard())
735 return WaitStates;
736
738 WaitStates = std::max(WaitStates, checkVMEMHazards(MI));
739
740 if (SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true))
741 WaitStates = std::max(WaitStates, checkVALUHazards(MI));
742
744 WaitStates = std::max(WaitStates, checkDPPHazards(MI));
745
746 if (isDivFMas(MI->getOpcode()))
747 WaitStates = std::max(WaitStates, checkDivFMasHazards(MI));
748
749 if (isRWLane(MI->getOpcode()))
750 WaitStates = std::max(WaitStates, checkRWLaneHazards(MI));
751
752 if (SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true) ||
755 WaitStates = std::max(WaitStates, checkMAIVALUHazards(MI));
756
757 if (MI->isInlineAsm())
758 return std::max(WaitStates, checkInlineAsmHazards(MI));
759
760 if (isSGetReg(MI->getOpcode()))
761 return std::max(WaitStates, checkGetRegHazards(MI));
762
763 if (isSSetReg(MI->getOpcode()))
764 return std::max(WaitStates, checkSetRegHazards(MI));
765
766 if (isRFE(MI->getOpcode()))
767 return std::max(WaitStates, checkRFEHazards(MI));
768
769 if ((ST.hasReadM0MovRelInterpHazard() &&
770 (TII.isVINTRP(*MI) || isSMovRel(MI->getOpcode()) ||
771 MI->getOpcode() == AMDGPU::DS_WRITE_ADDTID_B32 ||
772 MI->getOpcode() == AMDGPU::DS_READ_ADDTID_B32)) ||
773 (ST.hasReadM0SendMsgHazard() && isSendMsgTraceDataOrGDS(TII, *MI)) ||
774 (ST.hasReadM0LdsDmaHazard() && isLdsDma(*MI)) ||
775 (ST.hasReadM0LdsDirectHazard() &&
776 MI->readsRegister(AMDGPU::LDS_DIRECT, /*TRI=*/nullptr)))
777 return std::max(WaitStates, checkReadM0Hazards(MI));
778
780 return std::max(WaitStates, checkMAIHazards(MI));
781
783 return std::max(WaitStates, checkMAILdStHazards(MI));
784
785 if (ST.hasPermlaneForwardingHazard() && isPermlane(*MI))
786 return std::max(WaitStates, checkPermlaneHazards(MI));
787
788 return WaitStates;
789}
790
792 EmittedInstrs.push_front(nullptr);
793}
794
796 if (isSchedulerMode())
797 schedulerAdvanceCycle();
798
799 // When the scheduler detects a stall, it will call AdvanceCycle() without
800 // emitting any instructions.
801 if (!CurrCycleInstr) {
802 EmittedInstrs.push_front(nullptr);
803
804 if (HasPendingWMMACoexecHazard)
805 EmittedVALUInstrs.push_front(nullptr);
806 return;
807 }
808
809 HasPendingWMMACoexecHazard = false;
810
811 if (CurrCycleInstr->isBundle()) {
812 processBundle();
813 return;
814 }
815
816 unsigned NumWaitStates = TII.getNumWaitStates(*CurrCycleInstr);
817 if (!NumWaitStates) {
818 CurrCycleInstr = nullptr;
819 return;
820 }
821
822 // Keep track of emitted instructions
823 EmittedInstrs.push_front(CurrCycleInstr);
824
825 bool IsVALUOrWMMA =
826 SIInstrInfo::isVALU(*CurrCycleInstr, /*AllowLDSDMA=*/true) ||
827 SIInstrInfo::isWMMA(*CurrCycleInstr) ||
828 SIInstrInfo::isSWMMAC(*CurrCycleInstr);
829 if (IsVALUOrWMMA) {
830 EmittedVALUInstrs.push_front(CurrCycleInstr);
831 } else {
832 // A pending WMMA co-execution hazard optimistically records stall cycles as
833 // future V_NOPs. If the scheduler instead stalls for a different
834 // (S_NOP-resolvable) hazard and schedules a non-VALU into those cycles,
835 // they will not resolve the VALU-pipe hazard, so drop them here.
836 while (!EmittedVALUInstrs.empty() && EmittedVALUInstrs.front() == nullptr)
837 EmittedVALUInstrs.pop_front();
838 }
839
840 // Add a nullptr for each additional wait state after the first. Make sure
841 // not to add more than getMaxLookAhead() items to the list, since we
842 // truncate the list to that size right after this loop.
843 for (unsigned i = 1, e = std::min(NumWaitStates, getMaxLookAhead());
844 i < e; ++i) {
845 EmittedInstrs.push_front(nullptr);
846 }
847
848 // getMaxLookahead() is the largest number of wait states we will ever need
849 // to insert, so there is no point in keeping track of more than that many
850 // wait states.
851 EmittedInstrs.resize(getMaxLookAhead());
852 if (EmittedVALUInstrs.size() > MaxVALULookAhead)
853 EmittedVALUInstrs.resize(MaxVALULookAhead);
854
855 CurrCycleInstr = nullptr;
856}
857
860 "Bottom-up scheduling shouldn't run in hazard recognizer mode");
861}
862
863//===----------------------------------------------------------------------===//
864// Helper Functions
865//===----------------------------------------------------------------------===//
866
868
869// Search for a hazard in a block and its predecessors.
870template <typename StateT>
871static bool
872hasHazard(StateT InitialState,
873 function_ref<HazardFnResult(StateT &, const MachineInstr &)> IsHazard,
874 function_ref<void(StateT &, const MachineInstr &)> UpdateState,
875 const MachineBasicBlock *InitialMBB,
877 struct StateMapKey {
879 size_t Idx;
880 static bool isEqual(const StateMapKey &LHS, const StateMapKey &RHS) {
881 return LHS.States == RHS.States && LHS.Idx == RHS.Idx;
882 }
883 };
884 struct StateMapKeyTraits : DenseMapInfo<StateMapKey> {
885 static unsigned getHashValue(const StateMapKey &Key) {
886 return StateT::getHashValue((*Key.States)[Key.Idx]);
887 }
888 static unsigned getHashValue(const StateT &State) {
889 return StateT::getHashValue(State);
890 }
891 static bool isEqual(const StateMapKey &LHS, const StateMapKey &RHS) {
892 return StateT::isEqual((*LHS.States)[LHS.Idx], (*RHS.States)[RHS.Idx]);
893 }
894 static bool isEqual(const StateT &LHS, const StateMapKey &RHS) {
895 return StateT::isEqual(LHS, (*RHS.States)[RHS.Idx]);
896 }
897 };
898
901
903 const MachineBasicBlock *MBB = InitialMBB;
904 StateT State = InitialState;
905
907 unsigned WorkIdx = 0;
908 for (;;) {
909 bool Expired = false;
910 for (auto E = MBB->instr_rend(); I != E; ++I) {
911 // No need to look at parent BUNDLE instructions.
912 if (I->isBundle())
913 continue;
914
915 auto Result = IsHazard(State, *I);
916 if (Result == HazardFound)
917 return true;
918 if (Result == HazardExpired) {
919 Expired = true;
920 break;
921 }
922
923 if (I->isInlineAsm() || I->isMetaInstruction())
924 continue;
925
926 UpdateState(State, *I);
927 }
928
929 if (!Expired) {
930 size_t StateIdx = States.size();
931 StateMapKey Key = {&States, StateIdx};
932 auto Insertion = StateMap.insert_as(std::pair(Key, StateIdx), State);
933 if (Insertion.second) {
934 States.emplace_back(State);
935 } else {
936 StateIdx = Insertion.first->second;
937 }
938 for (MachineBasicBlock *Pred : MBB->predecessors())
939 Worklist.insert(std::pair(Pred, StateIdx));
940 }
941
942 if (WorkIdx == Worklist.size())
943 break;
944
945 size_t StateIdx;
946 std::tie(MBB, StateIdx) = Worklist[WorkIdx++];
947 State = States[StateIdx];
948 I = MBB->instr_rbegin();
949 }
950
951 return false;
952}
953
954// Number of trailing terminators of \p Pred not executed on the edge to \p MBB:
955// control leaves at the first terminator branching to \p MBB, so the ones after
956// it are dead on that edge. A fallthrough executes them all.
958 const MachineBasicBlock *MBB) {
959 const SIInstrInfo &TII =
960 *Pred.getParent()->getSubtarget<GCNSubtarget>().getInstrInfo();
961 unsigned Unexecuted = 0, Passed = 0;
962 for (auto I = Pred.instr_rbegin(), E = Pred.instr_rend();
963 I != E && I->isTerminator(); ++I, ++Passed) {
964 // Only an explicit MBB destination identifies this edge; the last match is
965 // the earliest such branch in program order.
966 if (I->isBranch() && I->getNumOperands() > 0 && I->getOperand(0).isMBB() &&
967 TII.getBranchDestBlock(*I) == MBB)
968 Unexecuted = Passed;
969 }
970 return Unexecuted;
971}
972
973// Wait states \p MI adds to a distance. Inline asm may be empty, so it adds
974// none, which is the worst case.
975static unsigned
978 return MI.isInlineAsm() ? 0 : GetNumWaitStates(MI);
979}
980
981namespace {
982
983// Answers GCNHazardRecognizer::getMax*WindowDeficit, which documents the
984// result, by walking the CFG backwards from the instruction being checked,
985// counting distances with GetNumWaitStates. That needs the instruction in its
986// final place, so hazard recognizer mode only. Each object answers one query.
987class WindowDeficitSearch {
988public:
989 WindowDeficitSearch(
990 function_ref<std::optional<int>(const MachineInstr &)> WindowFor,
991 int MaxWindow,
994 : WindowFor(WindowFor), GetNumWaitStates(GetNumWaitStates),
995 MaxWindow(MaxWindow) {}
996
997 int run(const MachineInstr &MI);
998
999private:
1000 // A block to scan upwards from Start, which is Distance away from the
1001 // instruction being checked. In a predecessor, Start is the last instruction
1002 // above the terminators, and Distance includes the ones the edge executes.
1003 struct Arrival {
1004 const MachineBasicBlock *MBB;
1006 int Distance;
1007 };
1008
1009 void arrive(const MachineBasicBlock *MBB,
1011 int Distance);
1012 void scan(Arrival A);
1013
1014 const function_ref<std::optional<int>(const MachineInstr &)> WindowFor;
1015 const GCNHazardRecognizer::GetNumWaitStatesFn GetNumWaitStates;
1016 const int MaxWindow;
1017 int Deficit = 0;
1018 // Pending[D] holds the arrivals at distance D, and Best the smallest distance
1019 // each block has been queued at. Buckets are emptied in increasing distance,
1020 // so the first arrival scanned at a block is the shortest way into it, and
1021 // any later one is stale.
1023 DenseMap<const MachineBasicBlock *, int> Best;
1024};
1025
1026} // end anonymous namespace
1027
1028void WindowDeficitSearch::arrive(
1029 const MachineBasicBlock *MBB,
1031 // No window exceeds MaxWindow, so nothing this far back can beat the deficit
1032 // already found.
1033 if (MaxWindow - Distance <= Deficit)
1034 return;
1035
1036 if (Pending.empty())
1037 Pending.resize(MaxWindow);
1038
1039 auto [It, Inserted] = Best.try_emplace(MBB, Distance);
1040 if (!Inserted) {
1041 if (It->second <= Distance)
1042 return;
1043 It->second = Distance;
1044 }
1045
1046 assert(Distance < MaxWindow && "arrival outside the window");
1047 Pending[Distance].push_back({MBB, Start, Distance});
1048}
1049
1050// \p A is a copy because arrive() may append to the bucket it came from, which
1051// can move that bucket's elements.
1052void WindowDeficitSearch::scan(Arrival A) {
1053 // A shorter way into this block has been queued since.
1054 if (Best.lookup(A.MBB) < A.Distance)
1055 return;
1056
1057 int Distance = A.Distance;
1058 for (auto I = A.Start, E = A.MBB->instr_rend(); I != E; ++I) {
1059 if (I->isBundle())
1060 continue;
1061
1062 if (std::optional<int> Window = WindowFor(*I)) {
1063 assert(*Window >= 0 && *Window <= MaxWindow && "window out of bounds");
1064 Deficit = std::max(Deficit, *Window - Distance);
1065 }
1066
1067 Distance += getCountedWaitStates(*I, GetNumWaitStates);
1068
1069 if (Distance >= MaxWindow)
1070 return;
1071 }
1072
1073 for (const MachineBasicBlock *Pred : A.MBB->predecessors()) {
1074 auto Start = Pred->instr_rbegin(), End = Pred->instr_rend();
1075 for (unsigned N = countUnexecutedTerminators(*Pred, A.MBB); N; --N)
1076 ++Start;
1077
1078 int Executed = 0;
1079 for (; Start != End && Start->isTerminator(); ++Start) {
1080 assert(!WindowFor(*Start) && "terminators must not ask for a window");
1081 Executed += getCountedWaitStates(*Start, GetNumWaitStates);
1082 }
1083
1084 arrive(Pred, Start, Distance + Executed);
1085 }
1086}
1087
1088int WindowDeficitSearch::run(const MachineInstr &MI) {
1089 // Only the part above MI is scanned here, so the block stays out of Best: a
1090 // backedge into it must still scan it from its end.
1091 scan({MI.getParent(), std::next(MI.getReverseIterator()), 0});
1092
1093 // Distances never shrink along a path, so a scan only queues arrivals at the
1094 // distance being swept or further, and one pass over the buckets is enough.
1095 // The inner loop re-reads the size because an edge that adds nothing appends
1096 // to the bucket in hand; Best keeps a cycle that adds nothing from looping.
1097 for (int Distance = 0; Distance < static_cast<int>(Pending.size());
1098 ++Distance)
1099 for (unsigned I = 0; I != Pending[Distance].size(); ++I)
1100 scan(Pending[Distance][I]);
1101
1102 return Deficit;
1103}
1104
1105// Returns a minimum wait states since \p I walking all predecessors.
1106// Only scans until \p IsExpired does not return true.
1107// Can only be run in a hazard recognizer mode.
1108static int
1110 const MachineBasicBlock *MBB,
1112 int WaitStates, GCNHazardRecognizer::IsExpiredFn IsExpired,
1116 for (auto E = MBB->instr_rend(); I != E; ++I) {
1117 // Don't add WaitStates for parent BUNDLE instructions.
1118 if (I->isBundle())
1119 continue;
1120
1121 if (I->isMetaInstruction())
1122 continue;
1123
1124 if (IsHazard(*I))
1125 return WaitStates;
1126
1127 if (I->isInlineAsm())
1128 continue;
1129
1130 WaitStates += GetNumWaitStates(*I);
1131
1132 if (IsExpired(*I, WaitStates))
1133 return std::numeric_limits<int>::max();
1134 }
1135
1136 int MinWaitStates = std::numeric_limits<int>::max();
1137 for (MachineBasicBlock *Pred : MBB->predecessors()) {
1138 if (!Visited.insert(Pred).second)
1139 continue;
1140
1141 int W = getWaitStatesSince(IsHazard, Pred, Pred->instr_rbegin(), WaitStates,
1142 IsExpired, Visited, GetNumWaitStates);
1143
1144 MinWaitStates = std::min(MinWaitStates, W);
1145 }
1146
1147 return MinWaitStates;
1148}
1149
1150static int
1152 const MachineInstr *MI,
1157 return getWaitStatesSince(IsHazard, MI->getParent(),
1158 std::next(MI->getReverseIterator()), 0, IsExpired,
1159 Visited, GetNumWaitStates);
1160}
1161
1162int GCNHazardRecognizer::getMaxWindowDeficit(int MaxWindow,
1163 WindowForFn WindowFor) const {
1165 return WindowDeficitSearch(WindowFor, MaxWindow).run(*CurrCycleInstr);
1166
1167 // EmittedInstrs is capped and can be shorter than the widest window, which
1168 // costs scheduling quality only: the standalone pass still pads.
1169 int Deficit = 0, Distance = 0;
1170 for (MachineInstr *MI : EmittedInstrs) {
1171 if (MI) {
1172 if (std::optional<int> Window = WindowFor(*MI)) {
1173 assert(*Window >= 0 && *Window <= MaxWindow && "window out of bounds");
1174 Deficit = std::max(Deficit, *Window - Distance);
1175 }
1176 }
1177
1178 Distance +=
1180
1181 if (Distance >= MaxWindow)
1182 break;
1183 }
1184 return Deficit;
1185}
1186
1187int GCNHazardRecognizer::getWaitStatesSince(
1188 IsHazardFn IsHazard, int Limit, GetNumWaitStatesFn GetNumWaitStates) const {
1189 if (isHazardRecognizerMode()) {
1190 auto IsExpiredFn = [Limit](const MachineInstr &, int WaitStates) {
1191 return WaitStates >= Limit;
1192 };
1193 return ::getWaitStatesSince(IsHazard, CurrCycleInstr, IsExpiredFn,
1194 GetNumWaitStates);
1195 }
1196
1197 int WaitStates = 0;
1198 for (MachineInstr *MI : EmittedInstrs) {
1199 if (MI) {
1200 if (IsHazard(*MI))
1201 return WaitStates;
1202
1203 if (MI->isInlineAsm())
1204 continue;
1205 }
1206 WaitStates += MI ? GetNumWaitStates(*MI) : 1;
1207
1208 if (WaitStates >= Limit)
1209 break;
1210 }
1211 return std::numeric_limits<int>::max();
1212}
1213
1214int GCNHazardRecognizer::getWaitStatesSince(IsHazardFn IsHazard,
1215 int Limit) const {
1216 return getWaitStatesSince(IsHazard, Limit, SIInstrInfo::getNumWaitStates);
1217}
1218
1219int GCNHazardRecognizer::getMaxVALUWindowDeficit(int MaxWindow,
1220 WindowForFn WindowFor) const {
1221 if (isHazardRecognizerMode()) {
1222 auto GetVALUWaitStates = [](const MachineInstr &MI) -> unsigned {
1223 return SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true) ? 1 : 0;
1224 };
1225 return WindowDeficitSearch(WindowFor, MaxWindow, GetVALUWaitStates)
1226 .run(*CurrCycleInstr);
1227 }
1228
1229 // EmittedVALUInstrs is capped at MaxVALULookAhead, so a MaxWindow beyond that
1230 // window could miss a hazard. Keep the cap in sync with the wait-state
1231 // tables.
1232 assert(MaxWindow <= static_cast<int>(MaxVALULookAhead) &&
1233 "MaxWindow exceeds the EmittedVALUInstrs lookahead window");
1234 int WaitStates = 0;
1235 for (MachineInstr *MI : EmittedVALUInstrs) {
1236 if (MI) {
1237 if (std::optional<int> Window = WindowFor(*MI)) {
1238 assert(*Window >= 0 && *Window <= MaxWindow && "window out of bounds");
1239 return *Window - WaitStates;
1240 }
1241 }
1242
1243 ++WaitStates;
1244
1245 if (WaitStates >= MaxWindow)
1246 break;
1247 }
1248 return 0;
1249}
1250
1251int GCNHazardRecognizer::getWaitStatesSinceDef(unsigned Reg,
1252 IsHazardFn IsHazardDef,
1253 int Limit) const {
1254 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1255
1256 auto IsHazardFn = [IsHazardDef, TRI, Reg](const MachineInstr &MI) {
1257 return IsHazardDef(MI) && MI.modifiesRegister(Reg, TRI);
1258 };
1259
1260 return getWaitStatesSince(IsHazardFn, Limit);
1261}
1262
1263int GCNHazardRecognizer::getWaitStatesSinceSetReg(IsHazardFn IsHazard,
1264 int Limit) const {
1265 auto IsHazardFn = [IsHazard](const MachineInstr &MI) {
1266 return isSSetReg(MI.getOpcode()) && IsHazard(MI);
1267 };
1268
1269 return getWaitStatesSince(IsHazardFn, Limit);
1270}
1271
1272//===----------------------------------------------------------------------===//
1273// No-op Hazard Detection
1274//===----------------------------------------------------------------------===//
1275
1276static void addRegUnits(const SIRegisterInfo &TRI, BitVector &BV,
1277 MCRegister Reg) {
1278 for (MCRegUnit Unit : TRI.regunits(Reg))
1279 BV.set(static_cast<unsigned>(Unit));
1280}
1281
1284 BitVector &DefSet, BitVector &UseSet) {
1285 for (const MachineOperand &Op : Ops) {
1286 if (Op.isReg())
1287 addRegUnits(TRI, Op.isDef() ? DefSet : UseSet, Op.getReg().asMCReg());
1288 }
1289}
1290
1291void GCNHazardRecognizer::addClauseInst(const MachineInstr &MI) const {
1292 addRegsToSet(TRI, MI.operands(), ClauseDefs, ClauseUses);
1293}
1294
1296 return !SIInstrInfo::isSMRD(*MI);
1297}
1298
1300 return !SIInstrInfo::isVMEM(*MI);
1301}
1302
1303int GCNHazardRecognizer::checkSoftClauseHazards(MachineInstr *MEM) const {
1304 // SMEM soft clause are only present on VI+, and only matter if xnack is
1305 // enabled.
1306 if (!ST.isXNACKEnabled())
1307 return 0;
1308
1309 bool IsSMRD = TII.isSMRD(*MEM);
1310
1311 resetClause();
1312
1313 // A soft-clause is any group of consecutive SMEM instructions. The
1314 // instructions in this group may return out of order and/or may be
1315 // replayed (i.e. the same instruction issued more than once).
1316 //
1317 // In order to handle these situations correctly we need to make sure that
1318 // when a clause has more than one instruction, no instruction in the clause
1319 // writes to a register that is read by another instruction in the clause
1320 // (including itself). If we encounter this situation, we need to break the
1321 // clause by inserting a non SMEM instruction.
1322
1323 for (MachineInstr *MI : EmittedInstrs) {
1324 // When we hit a non-SMEM instruction then we have passed the start of the
1325 // clause and we can stop.
1326 if (!MI)
1327 break;
1328
1330 break;
1331
1332 addClauseInst(*MI);
1333 }
1334
1335 if (ClauseDefs.none())
1336 return 0;
1337
1338 // We need to make sure not to put loads and stores in the same clause if they
1339 // use the same address. For now, just start a new clause whenever we see a
1340 // store.
1341 if (MEM->mayStore())
1342 return 1;
1343
1344 addClauseInst(*MEM);
1345
1346 // If the set of defs and uses intersect then we cannot add this instruction
1347 // to the clause, so we have a hazard.
1348 return ClauseDefs.anyCommon(ClauseUses) ? 1 : 0;
1349}
1350
1351int GCNHazardRecognizer::checkSMRDHazards(MachineInstr *SMRD) const {
1352 int WaitStatesNeeded = 0;
1353
1354 WaitStatesNeeded = checkSoftClauseHazards(SMRD);
1355
1356 // This SMRD hazard only affects SI.
1357 if (!ST.hasSMRDReadVALUDefHazard())
1358 return WaitStatesNeeded;
1359
1360 // A read of an SGPR by SMRD instruction requires 4 wait states when the
1361 // SGPR was written by a VALU instruction.
1362 int SmrdSgprWaitStates = 4;
1363 auto IsHazardDefFn = [this](const MachineInstr &MI) {
1364 return TII.isVALU(MI, /*AllowLDSDMA=*/true);
1365 };
1366 auto IsBufferHazardDefFn = [this](const MachineInstr &MI) {
1367 return TII.isSALU(MI);
1368 };
1369
1370 bool IsBufferSMRD = TII.isBufferSMRD(*SMRD);
1371
1372 for (const MachineOperand &Use : SMRD->uses()) {
1373 if (!Use.isReg())
1374 continue;
1375 int WaitStatesNeededForUse =
1376 SmrdSgprWaitStates - getWaitStatesSinceDef(Use.getReg(), IsHazardDefFn,
1377 SmrdSgprWaitStates);
1378 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1379
1380 // This fixes what appears to be undocumented hardware behavior in SI where
1381 // s_mov writing a descriptor and s_buffer_load_dword reading the descriptor
1382 // needs some number of nops in between. We don't know how many we need, but
1383 // let's use 4. This wasn't discovered before probably because the only
1384 // case when this happens is when we expand a 64-bit pointer into a full
1385 // descriptor and use s_buffer_load_dword instead of s_load_dword, which was
1386 // probably never encountered in the closed-source land.
1387 if (IsBufferSMRD) {
1388 int WaitStatesNeededForUse =
1389 SmrdSgprWaitStates - getWaitStatesSinceDef(Use.getReg(),
1390 IsBufferHazardDefFn,
1391 SmrdSgprWaitStates);
1392 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1393 }
1394 }
1395
1396 return WaitStatesNeeded;
1397}
1398
1399int GCNHazardRecognizer::checkVMEMHazards(MachineInstr *VMEM) const {
1400 if (!ST.hasVMEMReadSGPRVALUDefHazard())
1401 return 0;
1402
1403 int WaitStatesNeeded = checkSoftClauseHazards(VMEM);
1404
1405 // A read of an SGPR by a VMEM instruction requires 5 wait states when the
1406 // SGPR was written by a VALU Instruction.
1407 const int VmemSgprWaitStates = 5;
1408 auto IsHazardDefFn = [this](const MachineInstr &MI) {
1409 return TII.isVALU(MI, /*AllowLDSDMA=*/true);
1410 };
1411 for (const MachineOperand &Use : VMEM->uses()) {
1412 if (!Use.isReg() || TRI.isVectorRegister(MF.getRegInfo(), Use.getReg()))
1413 continue;
1414
1415 int WaitStatesNeededForUse =
1416 VmemSgprWaitStates - getWaitStatesSinceDef(Use.getReg(), IsHazardDefFn,
1417 VmemSgprWaitStates);
1418 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1419 }
1420 return WaitStatesNeeded;
1421}
1422
1423int GCNHazardRecognizer::checkDPPHazards(MachineInstr *DPP) const {
1424 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1425 const SIInstrInfo *TII = ST.getInstrInfo();
1426
1427 // Check for DPP VGPR read after VALU VGPR write and EXEC write.
1428 int DppVgprWaitStates = 2;
1429 int DppExecWaitStates = 5;
1430 int WaitStatesNeeded = 0;
1431 auto IsHazardDefFn = [TII](const MachineInstr &MI) {
1432 return TII->isVALU(MI, /*AllowLDSDMA=*/true);
1433 };
1434
1435 for (const MachineOperand &Use : DPP->uses()) {
1436 if (!Use.isReg() || !TRI->isVGPR(MF.getRegInfo(), Use.getReg()))
1437 continue;
1438 int WaitStatesNeededForUse =
1439 DppVgprWaitStates - getWaitStatesSinceDef(
1440 Use.getReg(),
1441 [](const MachineInstr &) { return true; },
1442 DppVgprWaitStates);
1443 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1444 }
1445
1446 WaitStatesNeeded = std::max(
1447 WaitStatesNeeded,
1448 DppExecWaitStates - getWaitStatesSinceDef(AMDGPU::EXEC, IsHazardDefFn,
1449 DppExecWaitStates));
1450
1451 return WaitStatesNeeded;
1452}
1453
1454int GCNHazardRecognizer::checkDivFMasHazards(MachineInstr *DivFMas) const {
1455 const SIInstrInfo *TII = ST.getInstrInfo();
1456
1457 // v_div_fmas requires 4 wait states after a write to vcc from a VALU
1458 // instruction.
1459 const int DivFMasWaitStates = 4;
1460 auto IsHazardDefFn = [TII](const MachineInstr &MI) {
1461 return TII->isVALU(MI, /*AllowLDSDMA=*/true);
1462 };
1463 int WaitStatesNeeded = getWaitStatesSinceDef(AMDGPU::VCC, IsHazardDefFn,
1464 DivFMasWaitStates);
1465
1466 return DivFMasWaitStates - WaitStatesNeeded;
1467}
1468
1469int GCNHazardRecognizer::checkGetRegHazards(MachineInstr *GetRegInstr) const {
1470 const SIInstrInfo *TII = ST.getInstrInfo();
1471 unsigned GetRegHWReg = getHWReg(TII, *GetRegInstr);
1472
1473 const int GetRegWaitStates = 2;
1474 auto IsHazardFn = [TII, GetRegHWReg](const MachineInstr &MI) {
1475 return GetRegHWReg == getHWReg(TII, MI);
1476 };
1477 int WaitStatesNeeded = getWaitStatesSinceSetReg(IsHazardFn, GetRegWaitStates);
1478
1479 return GetRegWaitStates - WaitStatesNeeded;
1480}
1481
1482int GCNHazardRecognizer::checkSetRegHazards(MachineInstr *SetRegInstr) const {
1483 const SIInstrInfo *TII = ST.getInstrInfo();
1484 unsigned HWReg = getHWReg(TII, *SetRegInstr);
1485
1486 const int SetRegWaitStates = ST.getSetRegWaitStates();
1487 auto IsHazardFn = [TII, HWReg](const MachineInstr &MI) {
1488 return HWReg == getHWReg(TII, MI);
1489 };
1490 int WaitStatesNeeded = getWaitStatesSinceSetReg(IsHazardFn, SetRegWaitStates);
1491 return SetRegWaitStates - WaitStatesNeeded;
1492}
1493
1494int GCNHazardRecognizer::createsVALUHazard(const MachineInstr &MI) const {
1495 if (!MI.mayStore())
1496 return -1;
1497
1498 const SIInstrInfo *TII = ST.getInstrInfo();
1499 unsigned Opcode = MI.getOpcode();
1500 const MCInstrDesc &Desc = MI.getDesc();
1501
1502 int VDataIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::vdata);
1503 int VDataRCID = -1;
1504 if (VDataIdx != -1)
1505 VDataRCID = TII->getOpRegClassID(Desc.operands()[VDataIdx]);
1506
1507 if (TII->isMUBUF(MI) || TII->isMTBUF(MI)) {
1508 // There is no hazard if the instruction does not use vector regs
1509 // (like wbinvl1)
1510 if (VDataIdx == -1)
1511 return -1;
1512 if (AMDGPU::getRegBitWidth(VDataRCID) > 64) {
1513 // When SOFFSET-dependent wide-store windows apply, the BUFFER_STORE
1514 // source-vgpr WAR hazard exists for every SOFFSET shape; the wait-state
1515 // count differs by SOFFSET and is computed in checkVALUHazardsHelper.
1516 // Otherwise the hazard only exists if soffset is not an SGPR.
1517 if (ST.hasVDecCoExecHazard())
1518 return VDataIdx;
1519 const MachineOperand *SOffset =
1520 TII->getNamedOperand(MI, AMDGPU::OpName::soffset);
1521 if (!SOffset || !SOffset->isReg())
1522 return VDataIdx;
1523 }
1524 }
1525
1526 // MIMG instructions create a hazard if they don't use a 256-bit T# and
1527 // the store size is greater than 8 bytes and they have more than two bits
1528 // of their dmask set.
1529 // All our MIMG definitions use a 256-bit T#, so we can skip checking for them.
1530 if (TII->isMIMG(MI)) {
1531 int SRsrcIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::srsrc);
1532 assert(SRsrcIdx != -1 && AMDGPU::getRegBitWidth(TII->getOpRegClassID(
1533 Desc.operands()[SRsrcIdx])) == 256);
1534 (void)SRsrcIdx;
1535 }
1536
1537 if (TII->isFLAT(MI)) {
1538 // There is no hazard if the instruction does not use vector regs
1539 if (VDataIdx == -1)
1540 return -1;
1541
1542 if (AMDGPU::getRegBitWidth(VDataRCID) > 64)
1543 return VDataIdx;
1544 }
1545
1546 return -1;
1547}
1548
1549int GCNHazardRecognizer::checkUniformWindowVALUHazardsHelper(
1550 Register Reg) const {
1551 // Wide stores need a single wait-state bubble before a VALU that overwrites
1552 // store data. createsVALUHazard already excludes MUBUF/MTBUF stores with an
1553 // SGPR SOFFSET.
1554 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1555
1556 auto IsHazard = [&](const MachineInstr &MI) {
1557 int DataIdx = createsVALUHazard(MI);
1558 return DataIdx >= 0 &&
1559 TRI->regsOverlap(MI.getOperand(DataIdx).getReg(), Reg);
1560 };
1561
1562 return std::max(0, 1 - getWaitStatesSince(IsHazard, /*Limit=*/1));
1563}
1564
1565int GCNHazardRecognizer::checkSOFFSETWindowVALUHazardsHelper(
1566 Register Reg) const {
1567 // The required wait-state window depends on the producer's SOFFSET shape:
1568 // - MUBUF/MTBUF wide store with sgpr SOFFSET: 1 wait state.
1569 // - MUBUF/MTBUF wide store with literal/absent SOFFSET, and FLAT wide
1570 // store: 2 wait states.
1571 // The 1-cycle sgpr-SOFFSET window was measured on gfx950.
1572 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1573 const SIInstrInfo *TII = ST.getInstrInfo();
1574
1575 int WaitStatesNeeded = 0;
1576
1577 // Scan each wait-state window separately and take the max padding needed.
1578 // getWaitStatesSince supplies the minimum distance to a producer over paths.
1579 for (int Window = 1; Window <= 2; ++Window) {
1580 auto IsHazard = [&](const MachineInstr &MI) {
1581 int DataIdx = createsVALUHazard(MI);
1582 if (DataIdx < 0 ||
1583 !TRI->regsOverlap(MI.getOperand(DataIdx).getReg(), Reg))
1584 return false;
1585
1586 // Window 1 matches every hazard producer. Window 2 excludes BUF stores
1587 // with an SGPR SOFFSET, which only require a single wait state.
1588 if (Window == 1 || !TII->isBUF(MI))
1589 return true;
1590
1591 const MachineOperand *SOffset =
1592 TII->getNamedOperand(MI, AMDGPU::OpName::soffset);
1593 return !SOffset || !SOffset->isReg();
1594 };
1595 WaitStatesNeeded = std::max(WaitStatesNeeded,
1596 Window - getWaitStatesSince(IsHazard, Window));
1597 }
1598
1599 return WaitStatesNeeded;
1600}
1601
1602int GCNHazardRecognizer::checkVALUHazardsHelper(
1603 const MachineOperand &Def, const MachineRegisterInfo &MRI) const {
1604 // Helper to check for the hazard where VMEM instructions that store more
1605 // than 8 bytes can have their store data overwritten by the next
1606 // instruction.
1607 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1608
1609 if (!TRI->isVectorRegister(MRI, Def.getReg()))
1610 return 0;
1611
1612 if (ST.hasVDecCoExecHazard())
1613 return checkSOFFSETWindowVALUHazardsHelper(Def.getReg());
1614
1615 return checkUniformWindowVALUHazardsHelper(Def.getReg());
1616}
1617
1618/// Dest sel forwarding issue occurs if additional logic is needed to swizzle /
1619/// pack the computed value into correct bit position of the dest register. This
1620/// occurs if we have SDWA with dst_sel != DWORD or if we have op_sel with
1621/// dst_sel that is not aligned to the register. This function analayzes the \p
1622/// MI and \returns an operand with dst forwarding issue, or nullptr if
1623/// none exists.
1624static const MachineOperand *
1626 if (!SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/false))
1627 return nullptr;
1628
1629 const SIInstrInfo *TII = ST.getInstrInfo();
1630
1631 unsigned Opcode = MI.getOpcode();
1632
1633 // There are three different types of instructions
1634 // which produce forwarded dest: 1. SDWA with dst_sel != DWORD, 2. VOP3
1635 // which write hi bits (e.g. op_sel[3] == 1), and 3. FP8DstSelInst
1636 // (instructions with dest byte sel, e.g. CVT_SR_BF8_F32) and
1637 // op_sel[3:2]
1638 // != 0
1639 if (SIInstrInfo::isSDWA(MI)) {
1640 // Type 1: SDWA with dst_sel != DWORD
1641 if (auto *DstSel = TII->getNamedOperand(MI, AMDGPU::OpName::dst_sel))
1642 if (DstSel->getImm() != AMDGPU::SDWA::DWORD)
1643 return TII->getNamedOperand(MI, AMDGPU::OpName::vdst);
1644 }
1645
1646 AMDGPU::FPType IsFP4OrFP8ConvOpc = AMDGPU::getFPDstSelType(Opcode);
1647 if (AMDGPU::hasNamedOperand(Opcode, AMDGPU::OpName::op_sel)) {
1648 // Type 2: VOP3 which write the hi bits. DST_OP_SEL is a destination
1649 // selector in the VOP3 layout; VOP3P uses this bit for source op_sel_hi.
1651 (TII->getNamedImmOperand(MI, AMDGPU::OpName::src0_modifiers) &
1653 return TII->getNamedOperand(MI, AMDGPU::OpName::vdst);
1654
1655 // Type 2b: VOP3P mix instructions with a tied destination (MIXLO/MIXHI)
1656 // write only one half of vdst and preserve the other half, so treat them
1657 // like a VOP3 destination op_sel write regardless of their source
1658 // op_sel_hi bits.
1659 if (SIInstrInfo::isVOP3P(MI) &&
1660 AMDGPU::hasNamedOperand(Opcode, AMDGPU::OpName::vdst_in))
1661 return TII->getNamedOperand(MI, AMDGPU::OpName::vdst);
1662
1663 // Type 3: FP8DstSelInst with op_sel[3:2] != 0)
1664 if (IsFP4OrFP8ConvOpc == AMDGPU::FPType::FP8 &&
1665 (TII->getNamedImmOperand(MI, AMDGPU::OpName::src2_modifiers) &
1667 return TII->getNamedOperand(MI, AMDGPU::OpName::vdst);
1668 }
1669
1670 // Special case: nop is required for all the opsel values for fp4 sr variant
1671 // cvt scale instructions
1672 if (IsFP4OrFP8ConvOpc == AMDGPU::FPType::FP4)
1673 return TII->getNamedOperand(MI, AMDGPU::OpName::vdst);
1674
1675 return nullptr;
1676}
1677
1678/// Checks whether the provided \p MI "consumes" the operand with a Dest sel
1679/// fowarding issue \p Dst . We may "consume" the Dst via a standard explicit
1680/// RAW, or through irregular ways (e.g implicit RAW, certain types of WAW)
1682 const MachineOperand *Dst,
1683 const SIRegisterInfo *TRI) {
1684 // We must consider implicit reads of the VALU. SDWA with dst_sel and
1685 // UNUSED_PRESERVE will implicitly read the result from forwarded dest,
1686 // and we must account for that hazard.
1687 // We also must account for WAW hazards. In particular, WAW with dest
1688 // preserve semantics (e.g. VOP3 with op_sel, VOP2 &&
1689 // !zeroesHigh16BitsOfDest) will read the forwarded dest for parity
1690 // check for ECC. Without accounting for this hazard, the ECC will be
1691 // wrong.
1692 // TODO: limit to RAW (including implicit reads) + problematic WAW (i.e.
1693 // complete zeroesHigh16BitsOfDest)
1694 for (auto &Operand : VALU->operands()) {
1695 if (Operand.isReg() && TRI->regsOverlap(Dst->getReg(), Operand.getReg())) {
1696 return true;
1697 }
1698 }
1699 return false;
1700}
1701
1702int GCNHazardRecognizer::checkVALUHazards(MachineInstr *VALU) const {
1703 int WaitStatesNeeded = 0;
1704
1705 if (ST.hasTransForwardingHazard() && !SIInstrInfo::isTRANS(*VALU)) {
1706 const int TransDefWaitstates = 1;
1707
1708 auto IsTransDefFn = [this, VALU](const MachineInstr &MI) {
1710 return false;
1711 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1712 const SIInstrInfo *TII = ST.getInstrInfo();
1713 Register Def = TII->getNamedOperand(MI, AMDGPU::OpName::vdst)->getReg();
1714
1715 for (const MachineOperand &Use : VALU->explicit_uses()) {
1716 if (Use.isReg() && TRI->regsOverlap(Def, Use.getReg()))
1717 return true;
1718 }
1719
1720 return false;
1721 };
1722
1723 int WaitStatesNeededForDef =
1724 TransDefWaitstates -
1725 getWaitStatesSince(IsTransDefFn, TransDefWaitstates);
1726 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1727 }
1728
1729 if (ST.hasDstSelForwardingHazard() || ST.hasCvtScaleForwardingHazard()) {
1730 const int Shift16DefWaitstates = 1;
1731
1732 auto IsShift16BitDefFn = [this, VALU](const MachineInstr &ProducerMI) {
1733 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1734 const MachineOperand *ForwardedDst =
1735 getDstSelForwardingOperand(ProducerMI, ST);
1736 if (ForwardedDst) {
1737 return consumesDstSelForwardingOperand(VALU, ForwardedDst, TRI);
1738 }
1739
1740 if (ProducerMI.isInlineAsm()) {
1741 // Assume inline asm has dst forwarding hazard
1742 for (auto &Def : ProducerMI.all_defs()) {
1743 if (consumesDstSelForwardingOperand(VALU, &Def, TRI))
1744 return true;
1745 }
1746 }
1747
1748 return false;
1749 };
1750
1751 int WaitStatesNeededForDef =
1752 Shift16DefWaitstates -
1753 getWaitStatesSince(IsShift16BitDefFn, Shift16DefWaitstates);
1754 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1755 }
1756
1757 if (ST.hasVDecCoExecHazard()) {
1758 const int VALUWriteSGPRVALUReadWaitstates = 2;
1759 const int VALUWriteEXECRWLane = 4;
1760 const int VALUWriteVGPRReadlaneRead = 1;
1761
1762 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1763 const MachineRegisterInfo &MRI = MF.getRegInfo();
1765 auto IsVALUDefSGPRFn = [&UseReg, TRI](const MachineInstr &MI) {
1766 if (!SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true))
1767 return false;
1768 return MI.modifiesRegister(UseReg, TRI);
1769 };
1770
1771 for (const MachineOperand &Use : VALU->explicit_uses()) {
1772 if (!Use.isReg())
1773 continue;
1774
1775 UseReg = Use.getReg();
1776 if (TRI->isSGPRReg(MRI, UseReg)) {
1777 int WaitStatesNeededForDef =
1778 VALUWriteSGPRVALUReadWaitstates -
1779 getWaitStatesSince(IsVALUDefSGPRFn,
1780 VALUWriteSGPRVALUReadWaitstates);
1781 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1782 }
1783 }
1784
1785 if (VALU->readsRegister(AMDGPU::VCC, TRI)) {
1786 UseReg = AMDGPU::VCC;
1787 int WaitStatesNeededForDef =
1788 VALUWriteSGPRVALUReadWaitstates -
1789 getWaitStatesSince(IsVALUDefSGPRFn, VALUWriteSGPRVALUReadWaitstates);
1790 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1791 }
1792
1793 switch (VALU->getOpcode()) {
1794 case AMDGPU::V_READLANE_B32:
1795 case AMDGPU::V_READFIRSTLANE_B32: {
1796 MachineOperand *Src = TII.getNamedOperand(*VALU, AMDGPU::OpName::src0);
1797 UseReg = Src->getReg();
1798 int WaitStatesNeededForDef =
1799 VALUWriteVGPRReadlaneRead -
1800 getWaitStatesSince(IsVALUDefSGPRFn, VALUWriteVGPRReadlaneRead);
1801 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1802 }
1803 [[fallthrough]];
1804 case AMDGPU::V_WRITELANE_B32: {
1805 UseReg = AMDGPU::EXEC;
1806 int WaitStatesNeededForDef =
1807 VALUWriteEXECRWLane -
1808 getWaitStatesSince(IsVALUDefSGPRFn, VALUWriteEXECRWLane);
1809 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1810 break;
1811 }
1812 default:
1813 break;
1814 }
1815 }
1816
1817 // This checks for the hazard where VMEM instructions that store more than
1818 // 8 bytes can have there store data over written by the next instruction.
1819 if (!ST.has12DWordStoreHazard())
1820 return WaitStatesNeeded;
1821
1822 const MachineRegisterInfo &MRI = MF.getRegInfo();
1823
1824 for (const MachineOperand &Def : VALU->defs()) {
1825 WaitStatesNeeded = std::max(WaitStatesNeeded, checkVALUHazardsHelper(Def, MRI));
1826 }
1827
1828 return WaitStatesNeeded;
1829}
1830
1831int GCNHazardRecognizer::checkInlineAsmHazards(MachineInstr *IA) const {
1832 // This checks for hazards associated with inline asm statements.
1833 // Since inline asms can contain just about anything, we use this
1834 // to call/leverage other check*Hazard routines. Note that
1835 // this function doesn't attempt to address all possible inline asm
1836 // hazards (good luck), but is a collection of what has been
1837 // problematic thus far.
1838
1839 // see checkVALUHazards()
1840 if (!ST.has12DWordStoreHazard() && !ST.hasDstSelForwardingHazard() &&
1841 !ST.hasCvtScaleForwardingHazard())
1842 return 0;
1843
1844 const MachineRegisterInfo &MRI = MF.getRegInfo();
1845 int WaitStatesNeeded = 0;
1846
1847 for (const MachineOperand &Op :
1849 if (Op.isReg() && Op.isDef()) {
1850 if (!TRI.isVectorRegister(MRI, Op.getReg()))
1851 continue;
1852
1853 if (ST.has12DWordStoreHazard()) {
1854 WaitStatesNeeded =
1855 std::max(WaitStatesNeeded, checkVALUHazardsHelper(Op, MRI));
1856 }
1857 }
1858 }
1859
1860 if (ST.hasDstSelForwardingHazard()) {
1861 const int Shift16DefWaitstates = 1;
1862
1863 auto IsShift16BitDefFn = [this, &IA](const MachineInstr &ProducerMI) {
1864 const MachineOperand *Dst = getDstSelForwardingOperand(ProducerMI, ST);
1865 // Assume inline asm reads the dst
1866 if (Dst)
1867 return IA->modifiesRegister(Dst->getReg(), &TRI) ||
1868 IA->readsRegister(Dst->getReg(), &TRI);
1869
1870 if (ProducerMI.isInlineAsm()) {
1871 // If MI is inline asm, assume it has dst forwarding hazard
1872 for (auto &Def : ProducerMI.all_defs()) {
1873 if (IA->modifiesRegister(Def.getReg(), &TRI) ||
1874 IA->readsRegister(Def.getReg(), &TRI)) {
1875 return true;
1876 }
1877 }
1878 }
1879
1880 return false;
1881 };
1882
1883 int WaitStatesNeededForDef =
1884 Shift16DefWaitstates -
1885 getWaitStatesSince(IsShift16BitDefFn, Shift16DefWaitstates);
1886 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1887 }
1888
1889 return WaitStatesNeeded;
1890}
1891
1892int GCNHazardRecognizer::checkRWLaneHazards(MachineInstr *RWLane) const {
1893 const SIInstrInfo *TII = ST.getInstrInfo();
1894 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1895 const MachineRegisterInfo &MRI = MF.getRegInfo();
1896
1897 const MachineOperand *LaneSelectOp =
1898 TII->getNamedOperand(*RWLane, AMDGPU::OpName::src1);
1899
1900 if (!LaneSelectOp->isReg() || !TRI->isSGPRReg(MRI, LaneSelectOp->getReg()))
1901 return 0;
1902
1903 Register LaneSelectReg = LaneSelectOp->getReg();
1904 auto IsHazardFn = [TII](const MachineInstr &MI) {
1905 return TII->isVALU(MI, /*AllowLDSDMA=*/true);
1906 };
1907
1908 const int RWLaneWaitStates = 4;
1909 int WaitStatesSince = getWaitStatesSinceDef(LaneSelectReg, IsHazardFn,
1910 RWLaneWaitStates);
1911 return RWLaneWaitStates - WaitStatesSince;
1912}
1913
1914int GCNHazardRecognizer::checkRFEHazards(MachineInstr *RFE) const {
1915 if (!ST.hasRFEHazards())
1916 return 0;
1917
1918 const SIInstrInfo *TII = ST.getInstrInfo();
1919
1920 const int RFEWaitStates = 1;
1921
1922 auto IsHazardFn = [TII](const MachineInstr &MI) {
1923 return getHWReg(TII, MI) == AMDGPU::Hwreg::ID_TRAPSTS;
1924 };
1925 int WaitStatesNeeded = getWaitStatesSinceSetReg(IsHazardFn, RFEWaitStates);
1926 return RFEWaitStates - WaitStatesNeeded;
1927}
1928
1929int GCNHazardRecognizer::checkReadM0Hazards(MachineInstr *MI) const {
1930 const SIInstrInfo *TII = ST.getInstrInfo();
1931 const int ReadM0WaitStates = 1;
1932 auto IsHazardFn = [TII](const MachineInstr &MI) { return TII->isSALU(MI); };
1933 return ReadM0WaitStates -
1934 getWaitStatesSinceDef(AMDGPU::M0, IsHazardFn, ReadM0WaitStates);
1935}
1936
1937void GCNHazardRecognizer::emitVNops(MachineBasicBlock &MBB,
1939 int WaitStatesNeeded, bool IsHoisting) {
1940 const DebugLoc &DL = IsHoisting ? DebugLoc() : InsertPt->getDebugLoc();
1941 for (int I = 0; I < WaitStatesNeeded; ++I)
1942 BuildMI(MBB, InsertPt, DL, TII.get(AMDGPU::V_NOP_e32));
1943}
1944
1945void GCNHazardRecognizer::fixHazards(MachineInstr *MI) {
1946 fixVMEMtoScalarWriteHazards(MI);
1947 fixVcmpxPermlaneHazards(MI);
1948 fixSMEMtoVectorWriteHazards(MI);
1949 fixVcmpxExecWARHazard(MI);
1950 fixLdsBranchVmemWARHazard(MI);
1951 if (ST.hasLdsDirect()) {
1952 fixLdsDirectVALUHazard(MI);
1953 fixLdsDirectVMEMHazard(MI);
1954 }
1955 fixVALUPartialForwardingHazard(MI);
1956 fixVALUTransUseHazard(MI);
1957 fixVALUTransCoexecutionHazards(MI);
1958 fixWMMAHazards(MI); // fall-through if co-execution is enabled.
1959 fixWMMACoexecutionHazards(MI);
1960 fixShift64HighRegBug(MI);
1961 fixVALUMaskWriteHazard(MI);
1962 fixRequiredExportPriority(MI);
1963 if (ST.hasVPermPk16Hazard())
1964 fixVPermPk16Hazard(MI);
1965 if (ST.requiresWaitIdleBeforeGetReg())
1966 fixGetRegWaitIdle(MI);
1967 if (ST.hasDsAtomicAsyncBarrierArriveB64PipeBug())
1968 fixDsAtomicAsyncBarrierArriveB64(MI);
1969 if (ST.hasScratchBaseForwardingHazard())
1970 fixScratchBaseForwardingHazard(MI);
1971 if (ST.setRegModeNeedsVNOPs())
1972 fixSetRegMode(MI);
1973 if (ST.hasNeedsTDMDrain())
1974 fixTDM(MI);
1975}
1976
1978 const MachineInstr &MI) {
1979 return (TII.isVOPC(MI) ||
1980 (MI.isCompare() && (TII.isVOP3(MI) || TII.isSDWA(MI)))) &&
1981 MI.modifiesRegister(AMDGPU::EXEC, &TRI);
1982}
1983
1984bool GCNHazardRecognizer::fixVcmpxPermlaneHazards(MachineInstr *MI) {
1985 if (!ST.hasVcmpxPermlaneHazard() || !isPermlane(*MI))
1986 return false;
1987
1988 const SIInstrInfo *TII = ST.getInstrInfo();
1989 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1990 auto IsHazardFn = [TII, TRI](const MachineInstr &MI) {
1991 return isVCmpXWritesExec(*TII, *TRI, MI);
1992 };
1993
1994 auto IsExpiredFn = [](const MachineInstr &MI, int) {
1995 unsigned Opc = MI.getOpcode();
1996 return SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true) &&
1997 Opc != AMDGPU::V_NOP_e32 && Opc != AMDGPU::V_NOP_e64 &&
1998 Opc != AMDGPU::V_NOP_sdwa;
1999 };
2000
2001 if (::getWaitStatesSince(IsHazardFn, MI, IsExpiredFn) ==
2002 std::numeric_limits<int>::max())
2003 return false;
2004
2005 // V_NOP will be discarded by SQ.
2006 // Use V_MOV_B32 v?, v?. Register must be alive so use src0 of V_PERMLANE*
2007 // which is always a VGPR and available.
2008 auto *Src0 = TII->getNamedOperand(*MI, AMDGPU::OpName::src0);
2009 Register Reg = Src0->getReg();
2010 bool IsUndef = Src0->isUndef();
2011 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
2012 TII->get(AMDGPU::V_MOV_B32_e32))
2015
2016 return true;
2017}
2018
2019bool GCNHazardRecognizer::fixVMEMtoScalarWriteHazards(MachineInstr *MI) {
2020 if (!ST.hasVMEMtoScalarWriteHazard())
2021 return false;
2022 assert(!ST.hasExtendedWaitCounts());
2023
2025 return false;
2026
2027 if (MI->getNumDefs() == 0)
2028 return false;
2029
2030 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2031
2032 auto IsHazardFn = [TRI, MI](const MachineInstr &I) {
2034 return false;
2035
2036 for (const MachineOperand &Def : MI->defs()) {
2037 const MachineOperand *Op =
2038 I.findRegisterUseOperand(Def.getReg(), TRI, false);
2039 if (!Op)
2040 continue;
2041 return true;
2042 }
2043 return false;
2044 };
2045
2046 auto IsExpiredFn = [](const MachineInstr &MI, int) {
2047 return SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true) ||
2048 (MI.getOpcode() == AMDGPU::S_WAITCNT &&
2049 !MI.getOperand(0).getImm()) ||
2050 (MI.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2052 static_cast<unsigned>(MI.getOperand(0).getImm())) == 0);
2053 };
2054
2055 if (::getWaitStatesSince(IsHazardFn, MI, IsExpiredFn) ==
2056 std::numeric_limits<int>::max())
2057 return false;
2058
2059 const SIInstrInfo *TII = ST.getInstrInfo();
2060 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
2061 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
2063 return true;
2064}
2065
2066bool GCNHazardRecognizer::fixSMEMtoVectorWriteHazards(MachineInstr *MI) {
2067 if (!ST.hasSMEMtoVectorWriteHazard())
2068 return false;
2069 assert(!ST.hasExtendedWaitCounts());
2070
2071 if (!SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true))
2072 return false;
2073
2074 AMDGPU::OpName SDSTName;
2075 switch (MI->getOpcode()) {
2076 case AMDGPU::V_READLANE_B32:
2077 case AMDGPU::V_READFIRSTLANE_B32:
2078 SDSTName = AMDGPU::OpName::vdst;
2079 break;
2080 default:
2081 SDSTName = AMDGPU::OpName::sdst;
2082 break;
2083 }
2084
2085 const SIInstrInfo *TII = ST.getInstrInfo();
2086 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2087 const AMDGPU::IsaVersion IV = AMDGPU::getIsaVersion(ST.getCPU());
2088 const MachineOperand *SDST = TII->getNamedOperand(*MI, SDSTName);
2089 if (!SDST) {
2090 for (const auto &MO : MI->implicit_operands()) {
2091 if (MO.isDef() && TRI->isSGPRClass(TRI->getPhysRegBaseClass(MO.getReg()))) {
2092 SDST = &MO;
2093 break;
2094 }
2095 }
2096 }
2097
2098 if (!SDST)
2099 return false;
2100
2101 const Register SDSTReg = SDST->getReg();
2102 auto IsHazardFn = [SDSTReg, TRI](const MachineInstr &I) {
2103 return SIInstrInfo::isSMRD(I) && I.readsRegister(SDSTReg, TRI);
2104 };
2105
2106 auto IsExpiredFn = [TII, IV](const MachineInstr &MI, int) {
2107 if (TII->isSALU(MI)) {
2108 switch (MI.getOpcode()) {
2109 case AMDGPU::S_SETVSKIP:
2110 case AMDGPU::S_VERSION:
2111 case AMDGPU::S_WAITCNT_VSCNT:
2112 case AMDGPU::S_WAITCNT_VMCNT:
2113 case AMDGPU::S_WAITCNT_EXPCNT:
2114 // These instructions cannot not mitigate the hazard.
2115 return false;
2116 case AMDGPU::S_WAITCNT_LGKMCNT:
2117 // Reducing lgkmcnt count to 0 always mitigates the hazard.
2118 return (MI.getOperand(1).getImm() == 0) &&
2119 (MI.getOperand(0).getReg() == AMDGPU::SGPR_NULL);
2120 case AMDGPU::S_WAITCNT: {
2121 const int64_t Imm = MI.getOperand(0).getImm();
2122 AMDGPU::Waitcnt Decoded =
2123 AMDGPU::decodeWaitcnt(IV, static_cast<unsigned>(Imm));
2124 // DsCnt corresponds to LGKMCnt here.
2125 return Decoded.get(AMDGPU::DS_CNT) == 0;
2126 }
2127 default:
2128 assert((!SIInstrInfo::isWaitcnt(MI.getOpcode()) ||
2129 MI.getOpcode() == AMDGPU::S_WAIT_IDLE) &&
2130 "unexpected wait count instruction");
2131 // SOPP instructions cannot mitigate the hazard.
2132 if (TII->isSOPP(MI))
2133 return false;
2134 // At this point the SALU can be assumed to mitigate the hazard
2135 // because either:
2136 // (a) it is independent of the at risk SMEM (breaking chain),
2137 // or
2138 // (b) it is dependent on the SMEM, in which case an appropriate
2139 // s_waitcnt lgkmcnt _must_ exist between it and the at risk
2140 // SMEM instruction.
2141 return true;
2142 }
2143 }
2144 return false;
2145 };
2146
2147 if (::getWaitStatesSince(IsHazardFn, MI, IsExpiredFn) ==
2148 std::numeric_limits<int>::max())
2149 return false;
2150
2151 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
2152 TII->get(AMDGPU::S_MOV_B32), AMDGPU::SGPR_NULL)
2153 .addImm(0);
2154 return true;
2155}
2156
2157bool GCNHazardRecognizer::fixVcmpxExecWARHazard(MachineInstr *MI) {
2158 if (!ST.hasVcmpxExecWARHazard())
2159 return false;
2160 assert(!ST.hasExtendedWaitCounts());
2161
2162 if (!SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true))
2163 return false;
2164
2165 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2166 if (!MI->modifiesRegister(AMDGPU::EXEC, TRI))
2167 return false;
2168
2169 auto IsHazardFn = [TRI](const MachineInstr &I) {
2170 if (SIInstrInfo::isVALU(I, /*AllowLDSDMA=*/true))
2171 return false;
2172 return I.readsRegister(AMDGPU::EXEC, TRI);
2173 };
2174
2175 const SIInstrInfo *TII = ST.getInstrInfo();
2176 auto IsExpiredFn = [TII, TRI](const MachineInstr &MI, int) {
2177 if (SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true)) {
2178 if (TII->getNamedOperand(MI, AMDGPU::OpName::sdst))
2179 return true;
2180 for (auto MO : MI.implicit_operands())
2181 if (MO.isDef() && TRI->isSGPRClass(TRI->getPhysRegBaseClass(MO.getReg())))
2182 return true;
2183 }
2184 if (MI.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2186 static_cast<unsigned>(MI.getOperand(0).getImm())) == 0)
2187 return true;
2188 return false;
2189 };
2190
2191 if (::getWaitStatesSince(IsHazardFn, MI, IsExpiredFn) ==
2192 std::numeric_limits<int>::max())
2193 return false;
2194
2195 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
2196 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
2198 return true;
2199}
2200
2202 const GCNSubtarget &ST) {
2203 if (!ST.hasLdsBranchVmemWARHazard())
2204 return false;
2205
2206 // Check if the necessary condition for the hazard is met: both LDS and VMEM
2207 // instructions need to appear in the same function.
2208 bool HasLds = false;
2209 bool HasVmem = false;
2210 for (auto &MBB : MF) {
2211 for (auto &MI : MBB) {
2213 HasVmem |= SIInstrInfo::isVMEM(MI);
2214 if (HasLds && HasVmem)
2215 return true;
2216 }
2217 }
2218 return false;
2219}
2220
2222 return I.getOpcode() == AMDGPU::S_WAITCNT_VSCNT &&
2223 I.getOperand(0).getReg() == AMDGPU::SGPR_NULL &&
2224 !I.getOperand(1).getImm();
2225}
2226
2227bool GCNHazardRecognizer::fixLdsBranchVmemWARHazard(MachineInstr *MI) {
2228 if (!RunLdsBranchVmemWARHazardFixup)
2229 return false;
2230
2231 assert(ST.hasLdsBranchVmemWARHazard());
2232 assert(!ST.hasExtendedWaitCounts());
2233
2234 auto IsHazardInst = [](const MachineInstr &MI) {
2236 return 1;
2238 return 2;
2239 return 0;
2240 };
2241
2242 auto InstType = IsHazardInst(*MI);
2243 if (!InstType)
2244 return false;
2245
2246 auto IsExpiredFn = [&IsHazardInst](const MachineInstr &I, int) {
2247 return IsHazardInst(I) || isStoreCountWaitZero(I);
2248 };
2249
2250 auto IsHazardFn = [InstType, &IsHazardInst](const MachineInstr &I) {
2251 if (!I.isBranch())
2252 return false;
2253
2254 auto IsHazardFn = [InstType, IsHazardInst](const MachineInstr &I) {
2255 auto InstType2 = IsHazardInst(I);
2256 return InstType2 && InstType != InstType2;
2257 };
2258
2259 auto IsExpiredFn = [InstType, &IsHazardInst](const MachineInstr &I, int) {
2260 auto InstType2 = IsHazardInst(I);
2261 if (InstType == InstType2)
2262 return true;
2263
2264 return isStoreCountWaitZero(I);
2265 };
2266
2267 return ::getWaitStatesSince(IsHazardFn, &I, IsExpiredFn) !=
2268 std::numeric_limits<int>::max();
2269 };
2270
2271 if (::getWaitStatesSince(IsHazardFn, MI, IsExpiredFn) ==
2272 std::numeric_limits<int>::max())
2273 return false;
2274
2275 const SIInstrInfo *TII = ST.getInstrInfo();
2276 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
2277 TII->get(AMDGPU::S_WAITCNT_VSCNT))
2278 .addReg(AMDGPU::SGPR_NULL, RegState::Undef)
2279 .addImm(0);
2280
2281 return true;
2282}
2283
2284bool GCNHazardRecognizer::fixLdsDirectVALUHazard(MachineInstr *MI) {
2286 return false;
2287
2288 const int NoHazardWaitStates = 15;
2289 const MachineOperand *VDST = TII.getNamedOperand(*MI, AMDGPU::OpName::vdst);
2290 const Register VDSTReg = VDST->getReg();
2291
2292 bool VisitedTrans = false;
2293 auto IsHazardFn = [this, VDSTReg, &VisitedTrans](const MachineInstr &I) {
2294 if (!SIInstrInfo::isVALU(I, /*AllowLDSDMA=*/true))
2295 return false;
2296 VisitedTrans = VisitedTrans || SIInstrInfo::isTRANS(I);
2297 // Cover both WAR and WAW
2298 return I.readsRegister(VDSTReg, &TRI) || I.modifiesRegister(VDSTReg, &TRI);
2299 };
2300 auto IsExpiredFn = [&](const MachineInstr &I, int WaitStates) {
2301 if (WaitStates >= NoHazardWaitStates)
2302 return true;
2303 // Instructions which cause va_vdst==0 expire hazard
2306 };
2307 auto GetWaitStatesFn = [](const MachineInstr &MI) {
2308 return SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true) ? 1 : 0;
2309 };
2310
2311 DenseSet<const MachineBasicBlock *> Visited;
2312 auto Count = ::getWaitStatesSince(IsHazardFn, MI->getParent(),
2313 std::next(MI->getReverseIterator()), 0,
2314 IsExpiredFn, Visited, GetWaitStatesFn);
2315
2316 // Transcendentals can execute in parallel to other VALUs.
2317 // This makes va_vdst count unusable with a mixture of VALU and TRANS.
2318 if (VisitedTrans)
2319 Count = 0;
2320
2321 MachineOperand *WaitVdstOp =
2322 TII.getNamedOperand(*MI, AMDGPU::OpName::waitvdst);
2323 WaitVdstOp->setImm(std::min(Count, NoHazardWaitStates));
2324
2325 return true;
2326}
2327
2328bool GCNHazardRecognizer::fixLdsDirectVMEMHazard(MachineInstr *MI) {
2330 return false;
2331
2332 const MachineOperand *VDST = TII.getNamedOperand(*MI, AMDGPU::OpName::vdst);
2333 const Register VDSTReg = VDST->getReg();
2334
2335 auto IsHazardFn = [this, VDSTReg](const MachineInstr &I) {
2337 return false;
2338 return I.readsRegister(VDSTReg, &TRI) || I.modifiesRegister(VDSTReg, &TRI);
2339 };
2340 bool LdsdirCanWait = ST.hasLdsWaitVMSRC();
2341 // TODO: On GFX12 the hazard should expire on S_WAIT_LOADCNT/SAMPLECNT/BVHCNT
2342 // according to the type of VMEM instruction.
2343 auto IsExpiredFn = [this, LdsdirCanWait](const MachineInstr &I, int) {
2344 return SIInstrInfo::isVALU(I, /*AllowLDSDMA=*/true) ||
2346 (I.getOpcode() == AMDGPU::S_WAITCNT && !I.getOperand(0).getImm()) ||
2347 (I.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2349 static_cast<unsigned>(I.getOperand(0).getImm())) == 0) ||
2350 (LdsdirCanWait && SIInstrInfo::isLDSDIR(I) &&
2351 !TII.getNamedOperand(I, AMDGPU::OpName::waitvsrc)->getImm());
2352 };
2353
2354 if (::getWaitStatesSince(IsHazardFn, MI, IsExpiredFn) ==
2355 std::numeric_limits<int>::max())
2356 return false;
2357
2358 if (LdsdirCanWait) {
2359 TII.getNamedOperand(*MI, AMDGPU::OpName::waitvsrc)->setImm(0);
2360 } else {
2361 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
2362 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
2364 }
2365
2366 return true;
2367}
2368
2369bool GCNHazardRecognizer::fixVALUPartialForwardingHazard(MachineInstr *MI) {
2370 if (!ST.hasVALUPartialForwardingHazard())
2371 return false;
2372 assert(!ST.hasExtendedWaitCounts());
2373
2374 if (!ST.isWave64() || !SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true))
2375 return false;
2376
2377 SmallSetVector<Register, 4> SrcVGPRs;
2378
2379 for (const MachineOperand &Use : MI->explicit_uses()) {
2380 if (Use.isReg() && TRI.isVGPR(MF.getRegInfo(), Use.getReg()))
2381 SrcVGPRs.insert(Use.getReg());
2382 }
2383
2384 // Only applies with >= 2 unique VGPR sources
2385 if (SrcVGPRs.size() <= 1)
2386 return false;
2387
2388 // Look for the following pattern:
2389 // Va <- VALU [PreExecPos]
2390 // intv1
2391 // Exec <- SALU [ExecPos]
2392 // intv2
2393 // Vb <- VALU [PostExecPos]
2394 // intv3
2395 // MI Va, Vb (WaitState = 0)
2396 //
2397 // Where:
2398 // intv1 + intv2 <= 2 VALUs
2399 // intv3 <= 4 VALUs
2400 //
2401 // If found, insert an appropriate S_WAITCNT_DEPCTR before MI.
2402
2403 const int Intv1plus2MaxVALUs = 2;
2404 const int Intv3MaxVALUs = 4;
2405 const int IntvMaxVALUs = 6;
2406 const int NoHazardVALUWaitStates = IntvMaxVALUs + 2;
2407
2408 struct StateType {
2409 SmallDenseMap<Register, int, 4> DefPos;
2410 int ExecPos = std::numeric_limits<int>::max();
2411 int VALUs = 0;
2412
2413 static unsigned getHashValue(const StateType &State) {
2414 hash_code H = hash_combine(State.ExecPos, State.VALUs);
2415 for (const auto &[Reg, Pos] : State.DefPos)
2416 H = hash_combine(H, Reg, Pos);
2417 return static_cast<unsigned>(H);
2418 }
2419 static bool isEqual(const StateType &LHS, const StateType &RHS) {
2420 return LHS.DefPos == RHS.DefPos && LHS.ExecPos == RHS.ExecPos &&
2421 LHS.VALUs == RHS.VALUs;
2422 }
2423 };
2424
2425 StateType State;
2426
2427 // This overloads expiry testing with all the hazard detection
2428 auto IsHazardFn = [&, this](StateType &State, const MachineInstr &I) {
2429 // Too many VALU states have passed
2430 if (State.VALUs > NoHazardVALUWaitStates)
2431 return HazardExpired;
2432
2433 // Instructions which cause va_vdst==0 expire hazard
2436 (I.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2438 static_cast<unsigned>(I.getOperand(0).getImm())) == 0))
2439 return HazardExpired;
2440
2441 // Track registers writes
2442 bool Changed = false;
2443 if (SIInstrInfo::isVALU(I, /*AllowLDSDMA=*/true)) {
2444 for (Register Src : SrcVGPRs) {
2445 if (!State.DefPos.count(Src) && I.modifiesRegister(Src, &TRI)) {
2446 State.DefPos[Src] = State.VALUs;
2447 Changed = true;
2448 }
2449 }
2450 } else if (SIInstrInfo::isSALU(I)) {
2451 if (State.ExecPos == std::numeric_limits<int>::max()) {
2452 if (!State.DefPos.empty() && I.modifiesRegister(AMDGPU::EXEC, &TRI)) {
2453 State.ExecPos = State.VALUs;
2454 Changed = true;
2455 }
2456 }
2457 }
2458
2459 // Early expiration: too many VALUs in intv3
2460 if (State.VALUs > Intv3MaxVALUs && State.DefPos.empty())
2461 return HazardExpired;
2462
2463 // Only evaluate state if something changed
2464 if (!Changed)
2465 return NoHazardFound;
2466
2467 // Determine positions of VALUs pre/post exec change
2468 if (State.ExecPos == std::numeric_limits<int>::max())
2469 return NoHazardFound;
2470
2471 int PreExecPos = std::numeric_limits<int>::max();
2472 int PostExecPos = std::numeric_limits<int>::max();
2473
2474 for (auto Entry : State.DefPos) {
2475 int DefVALUs = Entry.second;
2476 if (DefVALUs != std::numeric_limits<int>::max()) {
2477 if (DefVALUs >= State.ExecPos)
2478 PreExecPos = std::min(PreExecPos, DefVALUs);
2479 else
2480 PostExecPos = std::min(PostExecPos, DefVALUs);
2481 }
2482 }
2483
2484 // Need a VALUs post exec change
2485 if (PostExecPos == std::numeric_limits<int>::max())
2486 return NoHazardFound;
2487
2488 // Too many VALUs in intv3?
2489 int Intv3VALUs = PostExecPos;
2490 if (Intv3VALUs > Intv3MaxVALUs)
2491 return HazardExpired;
2492
2493 // Too many VALUs in intv2?
2494 int Intv2VALUs = (State.ExecPos - PostExecPos) - 1;
2495 if (Intv2VALUs > Intv1plus2MaxVALUs)
2496 return HazardExpired;
2497
2498 // Need a VALUs pre exec change
2499 if (PreExecPos == std::numeric_limits<int>::max())
2500 return NoHazardFound;
2501
2502 // Too many VALUs in intv1?
2503 int Intv1VALUs = PreExecPos - State.ExecPos;
2504 if (Intv1VALUs > Intv1plus2MaxVALUs)
2505 return HazardExpired;
2506
2507 // Too many VALUs in intv1 + intv2
2508 if (Intv1VALUs + Intv2VALUs > Intv1plus2MaxVALUs)
2509 return HazardExpired;
2510
2511 return HazardFound;
2512 };
2513 auto UpdateStateFn = [](StateType &State, const MachineInstr &MI) {
2514 if (SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true))
2515 State.VALUs += 1;
2516 };
2517
2518 if (!hasHazard<StateType>(State, IsHazardFn, UpdateStateFn, MI->getParent(),
2519 std::next(MI->getReverseIterator())))
2520 return false;
2521
2522 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
2523 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
2525
2526 return true;
2527}
2528
2529bool GCNHazardRecognizer::fixVALUTransUseHazard(MachineInstr *MI) {
2530 if (!ST.hasVALUTransUseHazard())
2531 return false;
2532 assert(!ST.hasExtendedWaitCounts());
2533
2534 if (!SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true))
2535 return false;
2536
2537 SmallSet<Register, 4> SrcVGPRs;
2538
2539 for (const MachineOperand &Use : MI->explicit_uses()) {
2540 if (Use.isReg() && TRI.isVGPR(MF.getRegInfo(), Use.getReg()))
2541 SrcVGPRs.insert(Use.getReg());
2542 }
2543
2544 // Look for the following pattern:
2545 // Va <- TRANS VALU
2546 // intv
2547 // MI Va (WaitState = 0)
2548 //
2549 // Where:
2550 // intv <= 5 VALUs / 1 TRANS
2551 //
2552 // If found, insert an appropriate S_WAITCNT_DEPCTR before MI.
2553
2554 const int IntvMaxVALUs = 5;
2555 const int IntvMaxTRANS = 1;
2556
2557 struct StateType {
2558 int VALUs = 0;
2559 int TRANS = 0;
2560
2561 static unsigned getHashValue(const StateType &State) {
2562 return static_cast<unsigned>(hash_combine(State.VALUs, State.TRANS));
2563 }
2564 static bool isEqual(const StateType &LHS, const StateType &RHS) {
2565 return LHS.VALUs == RHS.VALUs && LHS.TRANS == RHS.TRANS;
2566 }
2567 };
2568
2569 StateType State;
2570
2571 // This overloads expiry testing with all the hazard detection
2572 auto IsHazardFn = [&, this](StateType &State, const MachineInstr &I) {
2573 // Too many VALU states have passed
2574 if (State.VALUs > IntvMaxVALUs || State.TRANS > IntvMaxTRANS)
2575 return HazardExpired;
2576
2577 // Instructions which cause va_vdst==0 expire hazard
2580 (I.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2582 static_cast<unsigned>(I.getOperand(0).getImm())) == 0))
2583 return HazardExpired;
2584
2585 // Track registers writes
2586 if (SIInstrInfo::isTRANS(I)) {
2587 for (Register Src : SrcVGPRs) {
2588 if (I.modifiesRegister(Src, &TRI)) {
2589 return HazardFound;
2590 }
2591 }
2592 }
2593
2594 return NoHazardFound;
2595 };
2596 auto UpdateStateFn = [](StateType &State, const MachineInstr &MI) {
2597 if (SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true))
2598 State.VALUs += 1;
2600 State.TRANS += 1;
2601 };
2602
2603 if (!hasHazard<StateType>(State, IsHazardFn, UpdateStateFn, MI->getParent(),
2604 std::next(MI->getReverseIterator())))
2605 return false;
2606
2607 // Hazard is observed - insert a wait on va_dst counter to ensure hazard is
2608 // avoided.
2609 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
2610 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
2612
2613 return true;
2614}
2615
2616bool GCNHazardRecognizer::fixVALUTransCoexecutionHazards(MachineInstr *MI) {
2617 if (!ST.hasTransCoexecutionHazard() || // Coexecution disabled.
2618 !SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true) ||
2620 return false;
2621
2622 const SIInstrInfo *TII = ST.getInstrInfo();
2623 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2624
2625 auto IsTransHazardFn = [MI, TII, TRI](const MachineInstr &I) {
2626 if (!SIInstrInfo::isTRANS(I))
2627 return false;
2628
2629 // RAW: Trans(I) writes, VALU(MI) reads.
2630 Register TransDef = TII->getNamedOperand(I, AMDGPU::OpName::vdst)->getReg();
2631 for (const MachineOperand &ValuUse : MI->explicit_uses()) {
2632 if (ValuUse.isReg() && TRI->regsOverlap(TransDef, ValuUse.getReg()))
2633 return true;
2634 }
2635
2636 // WAR: Trans(I) reads, VALU(MI) writes. Use modifiesRegister for
2637 // multi-dest VALUs.
2638 for (const MachineOperand &TransUse : I.explicit_uses()) {
2639 if (TransUse.isReg() && MI->modifiesRegister(TransUse.getReg(), TRI))
2640 return true;
2641 }
2642
2643 return false;
2644 };
2645
2646 auto IsExpiredFn = [](const MachineInstr &I, int) {
2647 return SIInstrInfo::isVALU(I, /*AllowLDSDMA=*/true);
2648 };
2649
2650 const int HasVALU = std::numeric_limits<int>::max();
2651 if (::getWaitStatesSince(IsTransHazardFn, MI, IsExpiredFn) == HasVALU)
2652 return false;
2653
2654 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), TII->get(AMDGPU::V_NOP_e32));
2655 return true;
2656}
2657
2658bool GCNHazardRecognizer::fixWMMAHazards(MachineInstr *MI) {
2660 return false;
2661
2662 const SIInstrInfo *TII = ST.getInstrInfo();
2663 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2664
2665 auto IsHazardFn = [MI, TII, TRI, this](const MachineInstr &I) {
2667 return false;
2668
2669 // Src0(matrix A) or Src1(matrix B) of the current wmma instruction overlaps
2670 // with the dest(matrix D) of the previous wmma.
2671 const Register CurSrc0Reg =
2672 TII->getNamedOperand(*MI, AMDGPU::OpName::src0)->getReg();
2673 const Register CurSrc1Reg =
2674 TII->getNamedOperand(*MI, AMDGPU::OpName::src1)->getReg();
2675
2676 const Register PrevDstReg =
2677 TII->getNamedOperand(I, AMDGPU::OpName::vdst)->getReg();
2678
2679 if (TRI->regsOverlap(PrevDstReg, CurSrc0Reg) ||
2680 TRI->regsOverlap(PrevDstReg, CurSrc1Reg)) {
2681 return true;
2682 }
2683
2684 // GFX12+ allows overlap of matrix C with PrevDstReg (hardware will stall)
2685 // but Index can't overlap with PrevDstReg.
2686 if (AMDGPU::isGFX12Plus(ST)) {
2687 if (SIInstrInfo::isSWMMAC(*MI)) {
2688 const Register CurIndex =
2689 TII->getNamedOperand(*MI, AMDGPU::OpName::src2)->getReg();
2690 if (TRI->regsOverlap(PrevDstReg, CurIndex))
2691 return true;
2692 }
2693 return false;
2694 }
2695
2696 return false;
2697 };
2698
2699 auto IsExpiredFn = [](const MachineInstr &I, int) {
2700 return SIInstrInfo::isVALU(I, /*AllowLDSDMA=*/true);
2701 };
2702
2703 if (::getWaitStatesSince(IsHazardFn, MI, IsExpiredFn) ==
2704 std::numeric_limits<int>::max())
2705 return false;
2706
2707 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), TII->get(AMDGPU::V_NOP_e32));
2708
2709 return true;
2710}
2711
2713 return SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/false) &&
2715}
2716
2717// Classify XDL WMMA instructions into co-execution hazard categories
2718// (Refer to SPG 4.6.12.1), mainly based on instruction latency.
2719//
2720// Category 0: WMMA with Latency 8
2721// WMMA_*F16, WMMA_*BF16
2722// WMMA_*_16X16X128_{FP8,BF8}
2723// WMMA_*F8F6F4 if SRCA & SRCB are not both F4
2724//
2725// Category 1: WMMA Latency 16
2726// WMMA_IU8
2727//
2728// Category 2: SWMMAC with Latency 8
2729// SWMMAC_*F16, SWMMAC_*BF16,
2730// SWMMAC_*FP8FP8
2731// SWMMAC_*BF8FP8
2732// SWMMAC_*FP8BF8
2733// SWMMAC_*BF8BF8
2734//
2735// Category 3: SWMMAC with Latency 16
2736// SWMMAC_IU8
2737//
2738// Category 4: 16 Pass GFX1251 WMMA with latency 16
2739// V_WMMA_*_16X16X32_{F16,BF16}
2740// V_WMMA_{F32,F16}_16X16X64_{FP8,BF8}*
2741// V_WMMA_F32_16x16x128_F8F6F4 (F4 only)
2742// V_SWMMAC_*_16X16X64_{F16,BF16}
2743// V_SWMMAC_{F32,F16}_16X16X128_{FP8,BF8}*
2744//
2745// Category 5: 32 Pass GFX1251 WMMA with latency 32
2746// V_WMMA_F32_16x16x128_F8F6F4 (not all F4)
2747// V_WMMA_{F32,F16}_16X16X128_{FP8,BF8}*
2748// V_WMMA_F32_32X16X128_F4
2749// V_WMMA_I32_16X16X64_IU8
2750// V_WMMA_I32_16X16X64_IU8
2751//
2752// Category 6: gfx1250 WMMA with Latency 4 (one co-execution slot)
2753// WMMA_*_16X16X64_{FP8,BF8}
2754// WMMA_*F8F6F4 if SRCA & SRCB are both F4
2756 const SIInstrInfo *TII,
2757 const TargetSchedModel &SchedModel,
2758 const GCNSubtarget &ST) {
2759 assert(TII->isXDLWMMA(MI) && "must be xdl wmma");
2760 bool IsSWMMAC = SIInstrInfo::isSWMMAC(MI);
2761 bool IsLowestRateWMMA = ST.hasGFX125xLowestRateWMMA();
2762 unsigned Category = 0;
2763
2764 unsigned Latency = SchedModel.computeInstrLatency(&MI);
2765 switch (Latency) {
2766 case 4:
2767 // Dense 4-cycle WMMA (gfx1250 16x16x64 FP8/BF8 and f8f6f4 with both
2768 // inputs F4). One co-execution slot; there is no 4-cycle SWMMAC.
2769 assert(!IsSWMMAC && "no 4-cycle SWMMAC expected");
2770 Category = 6;
2771 break;
2772 case 8:
2773 Category = IsSWMMAC ? 2 : 0;
2774 break;
2775 case 16:
2776 Category = IsLowestRateWMMA ? 4 : (IsSWMMAC ? 3 : 1);
2777 break;
2778 case 32:
2779 assert(IsLowestRateWMMA && "latency 32 is not expected");
2780 Category = 5;
2781 break;
2782 default:
2783 llvm_unreachable("unexpected xdl wmma latency");
2784 } // end switch.
2785
2786 return Category;
2787}
2788
2789int GCNHazardRecognizer::checkWMMACoexecutionHazards(MachineInstr *MI) const {
2790 if (!ST.hasWMMACoexecutionHazards())
2791 return 0;
2792
2793 const SIInstrInfo *TII = ST.getInstrInfo();
2794 if (!TII->isXDLWMMA(*MI) && !isCoexecutableVALUInst(*MI))
2795 return 0;
2796
2797 // WaitStates here is the number of V_NOPs or unrelated VALU instructions must
2798 // be in between the first WMMA and the second instruction to cover the hazard
2799 // (WMMAWaitStates if the second is also a WMMA, VALUWaitStates if the second
2800 // is a VALU). Refer to SPG 4.6.12.1. "Requirements for WMMA data hazards" for
2801 // numbers, which depends on the category of the first WMMA.
2802 const int WMMAWaitStates[] = {5, 9, 3, 5, 9, 17, 2};
2803 const int VALUWaitStates[] = {4, 8, 2, 4, 8, 16, 1};
2804 const bool IsWMMA = TII->isXDLWMMA(*MI);
2805 const bool IsLowestRateWMMA = ST.hasGFX125xLowestRateWMMA();
2806 ArrayRef<int> RequiredWaitStates =
2807 IsWMMA ? ArrayRef<int>(WMMAWaitStates) : ArrayRef<int>(VALUWaitStates);
2808 const int MaxWaitStates =
2809 IsWMMA ? (IsLowestRateWMMA ? 17 : 9) : (IsLowestRateWMMA ? 16 : 8);
2810
2811 auto WindowFor = [=](const MachineInstr &I) -> std::optional<int> {
2812 if (!TII->isXDLWMMA(I))
2813 return std::nullopt;
2814 if (IsWMMA ? !hasWMMAToWMMARegOverlap(I, *MI)
2815 : !hasWMMAToVALURegOverlap(I, *MI))
2816 return std::nullopt;
2817 return RequiredWaitStates[getWMMAHazardInstInCategory(I, TII, TSchedModel,
2818 ST)];
2819 };
2820
2821 return getMaxVALUWindowDeficit(MaxWaitStates, WindowFor);
2822}
2823
2824bool GCNHazardRecognizer::hasWMMAToWMMARegOverlap(
2825 const MachineInstr &WMMA, const MachineInstr &MI) const {
2826 Register D0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::vdst)->getReg();
2827 Register A1 = TII.getNamedOperand(MI, AMDGPU::OpName::src0)->getReg();
2828 Register B1 = TII.getNamedOperand(MI, AMDGPU::OpName::src1)->getReg();
2829
2830 // WMMA0 writes (D0), WMMA1 reads (A1/B1/Idx1).
2831 if (TRI.regsOverlap(D0, A1) || TRI.regsOverlap(D0, B1))
2832 return true;
2833
2835 Register Idx1 = TII.getNamedOperand(MI, AMDGPU::OpName::src2)->getReg();
2836 if (TRI.regsOverlap(D0, Idx1))
2837 return true;
2838 }
2839 return false;
2840}
2841
2842bool GCNHazardRecognizer::hasWMMAToVALURegOverlap(
2843 const MachineInstr &WMMA, const MachineInstr &MI) const {
2844 // WMMA writes, VALU reads.
2845 Register D0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::vdst)->getReg();
2846 for (const MachineOperand &ValuUse : MI.explicit_uses()) {
2847 if (ValuUse.isReg() && TRI.regsOverlap(D0, ValuUse.getReg()))
2848 return true;
2849 }
2850
2851 // WMMA reads or writes, VALU writes.
2852 Register A0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::src0)->getReg();
2853 Register B0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::src1)->getReg();
2854 SmallVector<Register, 4> WMMARegs({D0, A0, B0});
2855
2856 const MachineOperand *Src2 = TII.getNamedOperand(WMMA, AMDGPU::OpName::src2);
2857 if (Src2->isReg())
2858 WMMARegs.push_back(Src2->getReg());
2859
2860 for (const MachineOperand &ValuDef : MI.defs()) {
2861 Register VDstReg = ValuDef.getReg();
2862 for (Register WMMAReg : WMMARegs) {
2863 if (TRI.regsOverlap(VDstReg, WMMAReg))
2864 return true;
2865 }
2866 }
2867 return false;
2868}
2869
2870bool GCNHazardRecognizer::isCoexecutionHazardFor(const MachineInstr &I,
2871 const MachineInstr &MI) const {
2872 // I is the potential WMMA hazard source, MI is the instruction being checked
2873 // for hazard.
2874 if (!TII.isXDLWMMA(I))
2875 return false;
2876
2877 // Dispatch based on MI type
2878 if (TII.isXDLWMMA(MI))
2879 return hasWMMAToWMMARegOverlap(I, MI);
2881 return hasWMMAToVALURegOverlap(I, MI);
2882
2883 return false;
2884}
2885
2886bool GCNHazardRecognizer::hasWMMAHazardInLoop(MachineLoop *L, MachineInstr *MI,
2887 bool IncludeSubloops) {
2888 // Scan loop for any WMMA that hazards MI.
2889 // TODO: Avoid full loop scan when WMMA is beyond VALU distance.
2890 for (MachineBasicBlock *MBB : L->getBlocks()) {
2891 if (!IncludeSubloops && MLI->getLoopFor(MBB) != L)
2892 continue;
2893 for (MachineInstr &I : *MBB) {
2894 if (&I == MI)
2895 continue;
2896 if (isCoexecutionHazardFor(I, *MI))
2897 return true;
2898 }
2899 }
2900 return false;
2901}
2902
2903bool GCNHazardRecognizer::tryHoistWMMAVnopsFromLoop(MachineInstr *MI,
2904 int WaitStatesNeeded) {
2905 if (!MLI)
2906 return false;
2907
2908 MachineLoop *L = MLI->getLoopFor(MI->getParent());
2909 if (!L) {
2910 ++NumWMMAHoistingBailed;
2911 return false;
2912 }
2913
2914 // If innermost loop has WMMA hazard, we can't hoist at all
2915 if (hasWMMAHazardInLoop(L, MI)) {
2916 ++NumWMMAHoistingBailed;
2917 return false;
2918 }
2919
2920 // Find outermost loop with no internal hazard
2921 MachineLoop *TargetLoop = L;
2922 while (MachineLoop *Parent = TargetLoop->getParentLoop()) {
2923 if (hasWMMAHazardInLoop(Parent, MI, false))
2924 break; // Parent has hazard in its own blocks, stop here
2925 TargetLoop = Parent; // Safe to hoist further out
2926 }
2927
2928 // Need valid preheader to insert V_NOPs
2929 MachineBasicBlock *Preheader = TargetLoop->getLoopPreheader();
2930 if (!Preheader) {
2931 ++NumWMMAHoistingBailed;
2932 return false;
2933 }
2934
2935 LLVM_DEBUG(dbgs() << "WMMA V_NOP Hoisting: Moving " << WaitStatesNeeded
2936 << " V_NOPs from loop to " << printMBBReference(*Preheader)
2937 << "\n");
2938
2939 emitVNops(*Preheader, Preheader->getFirstTerminator(), WaitStatesNeeded,
2940 /*IsHoisting=*/true);
2941 NumWMMANopsHoisted += WaitStatesNeeded;
2942 return true;
2943}
2944
2945bool GCNHazardRecognizer::fixWMMACoexecutionHazards(MachineInstr *MI) {
2946 int WaitStatesNeeded = checkWMMACoexecutionHazards(MI);
2947 if (WaitStatesNeeded <= 0)
2948 return false;
2949
2950 if (ST.getCLOpts().wmma_vnop_hoisting &&
2951 tryHoistWMMAVnopsFromLoop(MI, WaitStatesNeeded))
2952 return true;
2953
2954 emitVNops(*MI->getParent(), MI->getIterator(), WaitStatesNeeded);
2955 return true;
2956}
2957
2958bool GCNHazardRecognizer::fixShift64HighRegBug(MachineInstr *MI) {
2959 if (!ST.hasShift64HighRegBug())
2960 return false;
2961 assert(!ST.hasExtendedWaitCounts());
2962
2963 switch (MI->getOpcode()) {
2964 default:
2965 return false;
2966 case AMDGPU::V_LSHLREV_B64_e64:
2967 case AMDGPU::V_LSHRREV_B64_e64:
2968 case AMDGPU::V_ASHRREV_I64_e64:
2969 break;
2970 }
2971
2972 MachineOperand *Amt = TII.getNamedOperand(*MI, AMDGPU::OpName::src0);
2973 if (!Amt->isReg())
2974 return false;
2975
2976 Register AmtReg = Amt->getReg();
2977 const MachineRegisterInfo &MRI = MF.getRegInfo();
2978 // Check if this is a last VGPR in the allocation block.
2979 if (!TRI.isVGPR(MRI, AmtReg) || ((AmtReg - AMDGPU::VGPR0) & 7) != 7)
2980 return false;
2981
2982 if (AmtReg != AMDGPU::VGPR255 && MRI.isPhysRegUsed(AmtReg + 1))
2983 return false;
2984
2985 assert(ST.needsAlignedVGPRs());
2986 static_assert(AMDGPU::VGPR0 + 1 == AMDGPU::VGPR1);
2987
2988 const DebugLoc &DL = MI->getDebugLoc();
2989 MachineBasicBlock *MBB = MI->getParent();
2990 MachineOperand *Src1 = TII.getNamedOperand(*MI, AMDGPU::OpName::src1);
2991
2992 // In:
2993 //
2994 // Dst = shiftrev64 Amt, Src1
2995 //
2996 // if Dst!=Src1 then avoid the bug with:
2997 //
2998 // Dst.sub0 = Amt
2999 // Dst = shift64 Dst.sub0, Src1
3000
3001 Register DstReg = MI->getOperand(0).getReg();
3002 if (!Src1->isReg() || Src1->getReg() != DstReg) {
3003 Register DstLo = TRI.getSubReg(DstReg, AMDGPU::sub0);
3004 runOnInstruction(
3005 BuildMI(*MBB, MI, DL, TII.get(AMDGPU::V_MOV_B32_e32), DstLo).add(*Amt));
3006 Amt->setReg(DstLo);
3007 Amt->setIsKill(true);
3008 return true;
3009 }
3010
3011 bool Overlapped = MI->modifiesRegister(AmtReg, &TRI);
3012 Register NewReg;
3013 for (MCRegister Reg : Overlapped ? AMDGPU::VReg_64_Align2RegClass
3014 : AMDGPU::VGPR_32RegClass) {
3015 if (!MI->modifiesRegister(Reg, &TRI) && !MI->readsRegister(Reg, &TRI)) {
3016 NewReg = Reg;
3017 break;
3018 }
3019 }
3020
3021 Register NewAmt = Overlapped ? (Register)TRI.getSubReg(NewReg, AMDGPU::sub1)
3022 : NewReg;
3023 Register NewAmtLo;
3024
3025 if (Overlapped)
3026 NewAmtLo = TRI.getSubReg(NewReg, AMDGPU::sub0);
3027
3028 // Insert a full wait count because found register might be pending a wait.
3029 BuildMI(*MBB, MI, DL, TII.get(AMDGPU::S_WAITCNT))
3030 .addImm(0);
3031
3032 // Insert V_SWAP_B32 instruction(s) and run hazard recognizer on them.
3033 if (Overlapped)
3034 runOnInstruction(
3035 BuildMI(*MBB, MI, DL, TII.get(AMDGPU::V_SWAP_B32), NewAmtLo)
3036 .addDef(AmtReg - 1)
3037 .addReg(AmtReg - 1, RegState::Undef)
3038 .addReg(NewAmtLo, RegState::Undef));
3039 runOnInstruction(BuildMI(*MBB, MI, DL, TII.get(AMDGPU::V_SWAP_B32), NewAmt)
3040 .addDef(AmtReg)
3041 .addReg(AmtReg, RegState::Undef)
3042 .addReg(NewAmt, RegState::Undef));
3043
3044 // Instructions emitted after the current instruction will be processed by the
3045 // parent loop of the hazard recognizer in a natural way.
3046 BuildMI(*MBB, std::next(MI->getIterator()), DL, TII.get(AMDGPU::V_SWAP_B32),
3047 AmtReg)
3048 .addDef(NewAmt)
3049 .addReg(NewAmt)
3050 .addReg(AmtReg);
3051 if (Overlapped)
3052 BuildMI(*MBB, std::next(MI->getIterator()), DL, TII.get(AMDGPU::V_SWAP_B32),
3053 AmtReg - 1)
3054 .addDef(NewAmtLo)
3055 .addReg(NewAmtLo)
3056 .addReg(AmtReg - 1);
3057
3058 // Re-running hazard recognizer on the modified instruction is not necessary,
3059 // inserted V_SWAP_B32 has already both read and write new registers so
3060 // hazards related to these register has already been handled.
3061 Amt->setReg(NewAmt);
3062 Amt->setIsKill(false);
3063 // We do not update liveness, so verifier may see it as undef.
3064 Amt->setIsUndef();
3065 if (Overlapped) {
3066 MI->getOperand(0).setReg(NewReg);
3067 Src1->setReg(NewReg);
3068 Src1->setIsKill(false);
3069 Src1->setIsUndef();
3070 }
3071
3072 return true;
3073}
3074
3075int GCNHazardRecognizer::checkNSAtoVMEMHazard(MachineInstr *MI) const {
3076 int NSAtoVMEMWaitStates = 1;
3077
3078 if (!ST.hasNSAtoVMEMBug())
3079 return 0;
3080
3082 return 0;
3083
3084 const SIInstrInfo *TII = ST.getInstrInfo();
3085 const auto *Offset = TII->getNamedOperand(*MI, AMDGPU::OpName::offset);
3086 if (!Offset || (Offset->getImm() & 6) == 0)
3087 return 0;
3088
3089 auto IsHazardFn = [TII](const MachineInstr &I) {
3090 if (!SIInstrInfo::isMIMG(I))
3091 return false;
3092 const AMDGPU::MIMGInfo *Info = AMDGPU::getMIMGInfo(I.getOpcode());
3093 return Info->MIMGEncoding == AMDGPU::MIMGEncGfx10NSA &&
3094 TII->getInstSizeInBytes(I) >= 16;
3095 };
3096
3097 return NSAtoVMEMWaitStates - getWaitStatesSince(IsHazardFn, 1);
3098}
3099
3100int GCNHazardRecognizer::checkFPAtomicToDenormModeHazard(
3101 MachineInstr *MI) const {
3102 int FPAtomicToDenormModeWaitStates = 3;
3103
3104 if (!ST.hasFPAtomicToDenormModeHazard())
3105 return 0;
3106 assert(!ST.hasExtendedWaitCounts());
3107
3108 if (MI->getOpcode() != AMDGPU::S_DENORM_MODE)
3109 return 0;
3110
3111 auto IsHazardFn = [](const MachineInstr &I) {
3112 if (!SIInstrInfo::isVMEM(I))
3113 return false;
3114 return SIInstrInfo::isFPAtomic(I);
3115 };
3116
3117 auto IsExpiredFn = [](const MachineInstr &MI, int WaitStates) {
3118 if (WaitStates >= 3 || SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true))
3119 return true;
3120
3121 return SIInstrInfo::isWaitcnt(MI.getOpcode());
3122 };
3123
3124 return FPAtomicToDenormModeWaitStates -
3125 ::getWaitStatesSince(IsHazardFn, MI, IsExpiredFn);
3126}
3127
3128int GCNHazardRecognizer::checkMAIHazards(MachineInstr *MI) const {
3130
3131 return ST.hasGFX90AInsts() ? checkMAIHazards90A(MI) : checkMAIHazards908(MI);
3132}
3133
3134int GCNHazardRecognizer::checkMFMAPadding(MachineInstr *MI) const {
3135 // Early exit if no padding is requested.
3136 if (MFMAPaddingRatio == 0)
3137 return 0;
3138
3139 const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
3140 if (!SIInstrInfo::isMFMA(*MI) || MFI->getOccupancy() < 2)
3141 return 0;
3142
3143 int NeighborMFMALatency = 0;
3144 auto IsNeighboringMFMA = [&NeighborMFMALatency,
3145 this](const MachineInstr &MI) {
3146 if (!SIInstrInfo::isMFMA(MI))
3147 return false;
3148
3149 NeighborMFMALatency = this->getMFMAPipelineWaitStates(MI);
3150 return true;
3151 };
3152
3153 const int MaxMFMAPipelineWaitStates = 16;
3154 int WaitStatesSinceNeighborMFMA =
3155 getWaitStatesSince(IsNeighboringMFMA, MaxMFMAPipelineWaitStates);
3156
3157 int NeighborMFMAPaddingNeeded =
3158 (NeighborMFMALatency * MFMAPaddingRatio / 100) -
3159 WaitStatesSinceNeighborMFMA;
3160
3161 return std::max(0, NeighborMFMAPaddingNeeded);
3162}
3163
3164int GCNHazardRecognizer::checkMAIHazards908(MachineInstr *MI) const {
3165 int WaitStatesNeeded = 0;
3166 unsigned Opc = MI->getOpcode();
3167
3168 auto IsVALUFn = [](const MachineInstr &MI) {
3169 return SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true) || MI.isInlineAsm();
3170 };
3171
3172 if (Opc != AMDGPU::V_ACCVGPR_READ_B32_e64) { // MFMA or v_accvgpr_write
3173 const int LegacyVALUWritesVGPRWaitStates = 2;
3174 const int VALUWritesExecWaitStates = 4;
3175 const int MaxWaitStates = 4;
3176
3177 int WaitStatesNeededForUse = VALUWritesExecWaitStates -
3178 getWaitStatesSinceDef(AMDGPU::EXEC, IsVALUFn, MaxWaitStates);
3179 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3180
3181 if (WaitStatesNeeded < MaxWaitStates) {
3182 for (const MachineOperand &Use : MI->explicit_uses()) {
3183 const int MaxWaitStates = 2;
3184
3185 if (!Use.isReg() || !TRI.isVGPR(MF.getRegInfo(), Use.getReg()))
3186 continue;
3187
3188 int WaitStatesNeededForUse = LegacyVALUWritesVGPRWaitStates -
3189 getWaitStatesSinceDef(Use.getReg(), IsVALUFn, MaxWaitStates);
3190 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3191
3192 if (WaitStatesNeeded == MaxWaitStates)
3193 break;
3194 }
3195 }
3196 }
3197
3198 for (const MachineOperand &Op : MI->explicit_operands()) {
3199 if (!Op.isReg() || !TRI.isAGPR(MF.getRegInfo(), Op.getReg()))
3200 continue;
3201
3202 if (Op.isDef() && Opc != AMDGPU::V_ACCVGPR_WRITE_B32_e64)
3203 continue;
3204
3205 const int MFMAWritesAGPROverlappedSrcABWaitStates = 4;
3206 const int MFMAWritesAGPROverlappedSrcCWaitStates = 2;
3207 const int MFMA4x4WritesAGPRAccVgprReadWaitStates = 4;
3208 const int MFMA16x16WritesAGPRAccVgprReadWaitStates = 10;
3209 const int MFMA32x32WritesAGPRAccVgprReadWaitStates = 18;
3210 const int MFMA4x4WritesAGPRAccVgprWriteWaitStates = 1;
3211 const int MFMA16x16WritesAGPRAccVgprWriteWaitStates = 7;
3212 const int MFMA32x32WritesAGPRAccVgprWriteWaitStates = 15;
3213 const int MaxWaitStates = 18;
3214 Register Reg = Op.getReg();
3215 unsigned HazardDefLatency = 0;
3216
3217 auto IsOverlappedMFMAFn = [Reg, &HazardDefLatency,
3218 this](const MachineInstr &MI) {
3219 if (!SIInstrInfo::isMFMA(MI))
3220 return false;
3221 Register DstReg = MI.getOperand(0).getReg();
3222 if (DstReg == Reg)
3223 return false;
3224 HazardDefLatency =
3225 std::max(HazardDefLatency, TSchedModel.computeInstrLatency(&MI));
3226 return TRI.regsOverlap(DstReg, Reg);
3227 };
3228
3229 int WaitStatesSinceDef = getWaitStatesSinceDef(Reg, IsOverlappedMFMAFn,
3230 MaxWaitStates);
3231 int NeedWaitStates = MFMAWritesAGPROverlappedSrcABWaitStates;
3232 int SrcCIdx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src2);
3233 int OpNo = Op.getOperandNo();
3234 if (OpNo == SrcCIdx) {
3235 NeedWaitStates = MFMAWritesAGPROverlappedSrcCWaitStates;
3236 } else if (Opc == AMDGPU::V_ACCVGPR_READ_B32_e64) {
3237 switch (HazardDefLatency) {
3238 case 2: NeedWaitStates = MFMA4x4WritesAGPRAccVgprReadWaitStates;
3239 break;
3240 case 8: NeedWaitStates = MFMA16x16WritesAGPRAccVgprReadWaitStates;
3241 break;
3242 case 16: [[fallthrough]];
3243 default: NeedWaitStates = MFMA32x32WritesAGPRAccVgprReadWaitStates;
3244 break;
3245 }
3246 } else if (Opc == AMDGPU::V_ACCVGPR_WRITE_B32_e64) {
3247 switch (HazardDefLatency) {
3248 case 2: NeedWaitStates = MFMA4x4WritesAGPRAccVgprWriteWaitStates;
3249 break;
3250 case 8: NeedWaitStates = MFMA16x16WritesAGPRAccVgprWriteWaitStates;
3251 break;
3252 case 16: [[fallthrough]];
3253 default: NeedWaitStates = MFMA32x32WritesAGPRAccVgprWriteWaitStates;
3254 break;
3255 }
3256 }
3257
3258 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceDef;
3259 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3260
3261 if (WaitStatesNeeded == MaxWaitStates)
3262 return WaitStatesNeeded; // Early exit.
3263
3264 auto IsAccVgprWriteFn = [Reg, this](const MachineInstr &MI) {
3265 if (MI.getOpcode() != AMDGPU::V_ACCVGPR_WRITE_B32_e64)
3266 return false;
3267 Register DstReg = MI.getOperand(0).getReg();
3268 return TRI.regsOverlap(Reg, DstReg);
3269 };
3270
3271 const int AccVGPRWriteMFMAReadSrcCWaitStates = 1;
3272 const int AccVGPRWriteMFMAReadSrcABWaitStates = 3;
3273 const int AccVGPRWriteAccVgprReadWaitStates = 3;
3274 NeedWaitStates = AccVGPRWriteMFMAReadSrcABWaitStates;
3275 if (OpNo == SrcCIdx)
3276 NeedWaitStates = AccVGPRWriteMFMAReadSrcCWaitStates;
3277 else if (Opc == AMDGPU::V_ACCVGPR_READ_B32_e64)
3278 NeedWaitStates = AccVGPRWriteAccVgprReadWaitStates;
3279
3280 WaitStatesNeededForUse = NeedWaitStates -
3281 getWaitStatesSinceDef(Reg, IsAccVgprWriteFn, MaxWaitStates);
3282 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3283
3284 if (WaitStatesNeeded == MaxWaitStates)
3285 return WaitStatesNeeded; // Early exit.
3286 }
3287
3288 if (Opc == AMDGPU::V_ACCVGPR_WRITE_B32_e64) {
3289 const int MFMA4x4ReadSrcCAccVgprWriteWaitStates = 0;
3290 const int MFMA16x16ReadSrcCAccVgprWriteWaitStates = 5;
3291 const int MFMA32x32ReadSrcCAccVgprWriteWaitStates = 13;
3292 const int MaxWaitStates = 13;
3293 Register DstReg = MI->getOperand(0).getReg();
3294 unsigned HazardDefLatency = 0;
3295
3296 auto IsSrcCMFMAFn = [DstReg, &HazardDefLatency,
3297 this](const MachineInstr &MI) {
3298 if (!SIInstrInfo::isMFMA(MI))
3299 return false;
3300 Register Reg = TII.getNamedOperand(MI, AMDGPU::OpName::src2)->getReg();
3301 HazardDefLatency =
3302 std::max(HazardDefLatency, TSchedModel.computeInstrLatency(&MI));
3303 return TRI.regsOverlap(Reg, DstReg);
3304 };
3305
3306 int WaitStatesSince = getWaitStatesSince(IsSrcCMFMAFn, MaxWaitStates);
3307 int NeedWaitStates;
3308 switch (HazardDefLatency) {
3309 case 2: NeedWaitStates = MFMA4x4ReadSrcCAccVgprWriteWaitStates;
3310 break;
3311 case 8: NeedWaitStates = MFMA16x16ReadSrcCAccVgprWriteWaitStates;
3312 break;
3313 case 16: [[fallthrough]];
3314 default: NeedWaitStates = MFMA32x32ReadSrcCAccVgprWriteWaitStates;
3315 break;
3316 }
3317
3318 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSince;
3319 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3320 }
3321
3322 // Pad neighboring MFMA with noops for better inter-wave performance.
3323 WaitStatesNeeded = std::max(WaitStatesNeeded, checkMFMAPadding(MI));
3324
3325 return WaitStatesNeeded;
3326}
3327
3328/// One MFMA can be written with up to four opcodes that differ only in how vdst
3329/// and src2 are encoded: both are either AGPRs or VGPRs, and the mac form ties
3330/// vdst to src2 instead of taking them as separate operands. \returns the AGPR,
3331/// non-mac opcode, so that every form of the same MFMA maps to one value.
3332static unsigned getMFMANonMacAGPRFormOp(unsigned Opc) {
3333 if (int NonMacOp = AMDGPU::getMFMAEarlyClobberOp(Opc); NonMacOp != -1)
3334 Opc = NonMacOp;
3335 if (int AGPROp = AMDGPU::getAGPRFormOp(Opc); AGPROp != -1)
3336 Opc = AGPROp;
3337 return Opc;
3338}
3339
3340/// \returns true if \p Opc0 and \p Opc1 are the same MFMA, ignoring the mac
3341/// form and whether vdst/src2 are AGPRs or VGPRs.
3342static bool isSameMFMA(unsigned Opc0, unsigned Opc1) {
3344}
3345
3346static int
3348 bool IsGFX950) {
3349 // xdl def cycles | gfx940 | gfx950
3350 // 2 pass | 3 4
3351 // 4 pass | 5 6
3352 // 8 pass | 9 10
3353 // 16 pass | 17 18
3354 return NumPasses + 1 + IsGFX950;
3355}
3356
3357static int
3359 bool IsGFX950) {
3360 // xdl def cycles | gfx940 | gfx950
3361 // 2 pass | 3 3
3362 // 4 pass | 5 6
3363 // 8 pass | 9 10
3364 // 16 pass | 17 18
3365 return NumPasses + 1 + (NumPasses != 2 && IsGFX950);
3366}
3367
3368static int
3370 // 2 pass -> 2
3371 // 4 pass -> 4
3372 // 8 pass -> 8
3373 // 16 pass -> 16
3374 return NumPasses;
3375}
3376
3377static int
3379 // 2 pass -> 4
3380 // 4 pass -> 6
3381 // 8 pass -> 10
3382 // 16 pass -> 18
3383 return NumPasses + 2;
3384}
3385
3387 bool IsGFX950) {
3388 // xdl def cycles | gfx942 | gfx950
3389 // 2 pass | 5 5
3390 // 4 pass | 7 8
3391 // 8 pass | 11 12
3392 // 16 pass | 19 20
3393 return NumPasses + 3 + (NumPasses != 2 && IsGFX950);
3394}
3395
3396int GCNHazardRecognizer::getMFMAOverlappedSrcCWaitStates(
3397 const MachineInstr *Reader, const MachineInstr *Writer) const {
3398 constexpr int SMFMA4x4WritesVGPROverlappedSMFMASrcCWaitStates = 2;
3399 constexpr int SMFMA16x16WritesVGPROverlappedSMFMASrcCWaitStates = 8;
3400 constexpr int SMFMA32x32WritesVGPROverlappedSMFMASrcCWaitStates = 16;
3401 constexpr int SMFMA4x4WritesVGPROverlappedDMFMASrcCWaitStates = 3;
3402 constexpr int SMFMA16x16WritesVGPROverlappedDMFMASrcCWaitStates = 9;
3403 constexpr int SMFMA32x32WritesVGPROverlappedDMFMASrcCWaitStates = 17;
3404 constexpr int DMFMA16x16WritesVGPROverlappedSrcCWaitStates = 9;
3405 constexpr int GFX950_DMFMA16x16WritesVGPROverlappedSrcCWaitStates = 17;
3406 constexpr int DMFMA4x4WritesVGPROverlappedSrcCWaitStates = 4;
3407
3408 // An XDL read of a non-XDL result needs no wait states. DGEMM is never XDL,
3409 // so this also covers the f64 writers handled below.
3410 if (TII.isXDL(*Reader) && !TII.isXDL(*Writer))
3411 return 0;
3412
3413 switch (Writer->getOpcode()) {
3414 case AMDGPU::V_MFMA_F64_16X16X4F64_e64:
3415 case AMDGPU::V_MFMA_F64_16X16X4F64_vgprcd_e64:
3416 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_e64:
3417 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_vgprcd_e64:
3418 return ST.hasGFX950Insts()
3419 ? GFX950_DMFMA16x16WritesVGPROverlappedSrcCWaitStates
3420 : DMFMA16x16WritesVGPROverlappedSrcCWaitStates;
3421 case AMDGPU::V_MFMA_F64_4X4X4F64_e64:
3422 case AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64:
3423 return DMFMA4x4WritesVGPROverlappedSrcCWaitStates;
3424 default:
3425 break;
3426 }
3427
3428 int NumPasses = TSchedModel.computeInstrLatency(Writer);
3429 if (ST.hasGFX940Insts()) {
3430 if (!TII.isXDL(*Writer))
3432 NumPasses);
3433 return TII.isXDL(*Reader)
3435 NumPasses, ST.hasGFX950Insts())
3437 NumPasses, ST.hasGFX950Insts());
3438 }
3439
3440 bool IsDGEMM = SIInstrInfo::isDGEMM(Reader->getOpcode());
3441 switch (NumPasses) {
3442 case 2:
3443 return IsDGEMM ? SMFMA4x4WritesVGPROverlappedDMFMASrcCWaitStates
3444 : SMFMA4x4WritesVGPROverlappedSMFMASrcCWaitStates;
3445 case 8:
3446 return IsDGEMM ? SMFMA16x16WritesVGPROverlappedDMFMASrcCWaitStates
3447 : SMFMA16x16WritesVGPROverlappedSMFMASrcCWaitStates;
3448 case 16:
3449 return IsDGEMM ? SMFMA32x32WritesVGPROverlappedDMFMASrcCWaitStates
3450 : SMFMA32x32WritesVGPROverlappedSMFMASrcCWaitStates;
3451 default:
3452 llvm_unreachable("unexpected number of passes");
3453 }
3454}
3455
3456int GCNHazardRecognizer::getMFMAReadWaitStates(const MachineInstr &Consumer,
3457 const MachineInstr &Producer,
3458 Register Reg,
3459 bool IsSrcC) const {
3460 unsigned Opc = Consumer.getOpcode();
3461 const int SMFMA4x4WritesVGPROverlappedSrcABWaitStates = 5;
3462 const int SMFMA16x16WritesVGPROverlappedSrcABWaitStates = 11;
3463 const int SMFMA32x32WritesVGPROverlappedSrcABWaitStates = 19;
3464 const int DMFMA4x4WritesVGPROverlappedMFMASrcABWaitStates = 6;
3465 const int DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates = 11;
3466 const int GFX950_DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates = 19;
3467 const int DMFMA4x4WritesVGPRFullSrcCWaitStates = 4;
3468 const int GFX940_SMFMA4x4WritesVGPRFullSrcCWaitStates = 2;
3469
3470 bool FullReg = Producer.getOperand(0).getReg() == Reg;
3471 unsigned Opc1 = Producer.getOpcode();
3472 int NeedWaitStates = 0;
3473 if (IsSrcC) {
3474 if (!SIInstrInfo::isDGEMM(Opc) &&
3475 (!ST.hasGFX940Insts() && SIInstrInfo::isDGEMM(Opc1))) {
3476 NeedWaitStates = 0;
3477 } else if (FullReg) {
3478 if ((Opc == AMDGPU::V_MFMA_F64_4X4X4F64_e64 ||
3479 Opc == AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64) &&
3480 (Opc1 == AMDGPU::V_MFMA_F64_4X4X4F64_e64 ||
3481 Opc1 == AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64))
3482 NeedWaitStates = DMFMA4x4WritesVGPRFullSrcCWaitStates;
3483 else if (ST.hasGFX940Insts() &&
3484 TSchedModel.computeInstrLatency(&Producer) == 2)
3485 NeedWaitStates = GFX940_SMFMA4x4WritesVGPRFullSrcCWaitStates;
3486
3487 // The accumulator forwarding path that allows zero wait states is only
3488 // available while the chain stays on a single MFMA. Two different MFMAs
3489 // sharing an accumulator need the wait states of a partial overlap.
3490 if (ST.hasGFX940Insts() && !isSameMFMA(Opc, Opc1)) {
3491 NeedWaitStates =
3492 std::max(NeedWaitStates,
3493 getMFMAOverlappedSrcCWaitStates(&Consumer, &Producer));
3494 }
3495 } else {
3496 NeedWaitStates = getMFMAOverlappedSrcCWaitStates(&Consumer, &Producer);
3497 }
3498 } else {
3499 switch (Opc1) {
3500 case AMDGPU::V_MFMA_F64_16X16X4F64_e64:
3501 case AMDGPU::V_MFMA_F64_16X16X4F64_vgprcd_e64:
3502 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_e64:
3503 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_vgprcd_e64:
3504 NeedWaitStates =
3505 ST.hasGFX950Insts()
3506 ? GFX950_DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates
3507 : DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates;
3508 break;
3509 case AMDGPU::V_MFMA_F64_4X4X4F64_e64:
3510 case AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64:
3511 NeedWaitStates = DMFMA4x4WritesVGPROverlappedMFMASrcABWaitStates;
3512 break;
3513 default:
3514 int NumPasses = TSchedModel.computeInstrLatency(&Producer);
3515
3516 if (ST.hasGFX940Insts()) {
3517 NeedWaitStates =
3518 TII.isXDL(Producer)
3520 NumPasses, ST.hasGFX950Insts())
3522 NumPasses);
3523 break;
3524 }
3525
3526 switch (NumPasses) {
3527 case 2:
3528 NeedWaitStates = SMFMA4x4WritesVGPROverlappedSrcABWaitStates;
3529 break;
3530 case 4:
3531 llvm_unreachable("unexpected number of passes for mfma");
3532 case 8:
3533 NeedWaitStates = SMFMA16x16WritesVGPROverlappedSrcABWaitStates;
3534 break;
3535 case 16:
3536 default:
3537 NeedWaitStates = SMFMA32x32WritesVGPROverlappedSrcABWaitStates;
3538 }
3539 }
3540 }
3541 return NeedWaitStates;
3542}
3543
3544int GCNHazardRecognizer::checkMAIHazards90A(MachineInstr *MI) const {
3545 int WaitStatesNeeded = 0;
3546 unsigned Opc = MI->getOpcode();
3547
3548 auto IsLegacyVALUFn = [](const MachineInstr &MI) {
3549 return SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true) &&
3551 };
3552
3553 auto IsLegacyVALUNotDotFn = [](const MachineInstr &MI) {
3554 return SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true) &&
3556 };
3557
3558 if (!SIInstrInfo::isMFMA(*MI))
3559 return WaitStatesNeeded;
3560
3561 const int VALUWritesExecWaitStates = 4;
3562 int WaitStatesNeededForUse = VALUWritesExecWaitStates -
3563 getWaitStatesSinceDef(AMDGPU::EXEC, IsLegacyVALUFn,
3564 VALUWritesExecWaitStates);
3565 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3566
3567 int SrcCIdx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src2);
3568
3569 // Loop for both DGEMM and S/HGEMM 2nd instruction.
3570 for (const MachineOperand &Use : MI->explicit_uses()) {
3571 const int LegacyVALUNotDotWritesVGPRWaitStates = 2;
3572 const int MaxWaitStates =
3574 16, ST.hasGFX950Insts());
3575
3576 if (!Use.isReg())
3577 continue;
3578 Register Reg = Use.getReg();
3579
3580 WaitStatesNeededForUse = LegacyVALUNotDotWritesVGPRWaitStates -
3581 getWaitStatesSinceDef(Reg, IsLegacyVALUNotDotFn, MaxWaitStates);
3582 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3583
3584 int OpNo = Use.getOperandNo();
3585 WaitStatesNeeded = std::max(
3586 WaitStatesNeeded,
3587 getMaxWindowDeficit(
3588 MaxWaitStates, [&](const MachineInstr &P) -> std::optional<int> {
3589 if (!SIInstrInfo::isMFMA(P) ||
3590 !TRI.regsOverlap(P.getOperand(0).getReg(), Reg))
3591 return std::nullopt;
3592 return getMFMAReadWaitStates(*MI, P, Reg, OpNo == SrcCIdx);
3593 }));
3594
3595 if (WaitStatesNeeded == MaxWaitStates)
3596 break;
3597 }
3598
3599 // Pad neighboring MFMA with noops for better inter-wave performance.
3600 WaitStatesNeeded = std::max(WaitStatesNeeded, checkMFMAPadding(MI));
3601
3602 return WaitStatesNeeded;
3603}
3604
3605int GCNHazardRecognizer::checkMAILdStHazards(MachineInstr *MI) const {
3606 // On gfx90a+ relevant hazards are checked in checkMAIVALUHazards()
3607 if (!ST.hasMAIInsts() || ST.hasGFX90AInsts())
3608 return 0;
3609
3610 int WaitStatesNeeded = 0;
3611
3612 auto IsAccVgprReadFn = [](const MachineInstr &MI) {
3613 return MI.getOpcode() == AMDGPU::V_ACCVGPR_READ_B32_e64;
3614 };
3615
3616 for (const MachineOperand &Op : MI->explicit_uses()) {
3617 if (!Op.isReg() || !TRI.isVGPR(MF.getRegInfo(), Op.getReg()))
3618 continue;
3619
3620 Register Reg = Op.getReg();
3621
3622 const int AccVgprReadLdStWaitStates = 2;
3623 const int VALUWriteAccVgprRdWrLdStDepVALUWaitStates = 1;
3624 const int MaxWaitStates = 2;
3625
3626 int WaitStatesNeededForUse = AccVgprReadLdStWaitStates -
3627 getWaitStatesSinceDef(Reg, IsAccVgprReadFn, MaxWaitStates);
3628 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3629
3630 if (WaitStatesNeeded == MaxWaitStates)
3631 return WaitStatesNeeded; // Early exit.
3632
3633 auto IsVALUAccVgprRdWrCheckFn = [Reg, this](const MachineInstr &MI) {
3634 if (MI.getOpcode() != AMDGPU::V_ACCVGPR_READ_B32_e64 &&
3635 MI.getOpcode() != AMDGPU::V_ACCVGPR_WRITE_B32_e64)
3636 return false;
3637 auto IsVALUFn = [](const MachineInstr &MI) {
3638 return SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true) &&
3640 };
3641 return getWaitStatesSinceDef(Reg, IsVALUFn, 2 /*MaxWaitStates*/) <
3642 std::numeric_limits<int>::max();
3643 };
3644
3645 WaitStatesNeededForUse = VALUWriteAccVgprRdWrLdStDepVALUWaitStates -
3646 getWaitStatesSince(IsVALUAccVgprRdWrCheckFn, MaxWaitStates);
3647 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3648 }
3649
3650 return WaitStatesNeeded;
3651}
3652
3653int GCNHazardRecognizer::checkPermlaneHazards(MachineInstr *MI) const {
3654 assert(!ST.hasVcmpxPermlaneHazard() &&
3655 "this is a different vcmpx+permlane hazard");
3656 const SIRegisterInfo *TRI = ST.getRegisterInfo();
3657 const SIInstrInfo *TII = ST.getInstrInfo();
3658
3659 auto IsVCmpXWritesExecFn = [TII, TRI](const MachineInstr &MI) {
3660 return isVCmpXWritesExec(*TII, *TRI, MI);
3661 };
3662
3663 auto IsVALUFn = [](const MachineInstr &MI) {
3664 return SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true);
3665 };
3666
3667 const int VCmpXWritesExecWaitStates = 4;
3668 const int VALUWritesVDstWaitStates = 2;
3669 int WaitStatesNeeded = 0;
3670
3671 for (const MachineOperand &Op : MI->explicit_uses()) {
3672 if (!Op.isReg() || !TRI->isVGPR(MF.getRegInfo(), Op.getReg()))
3673 continue;
3674 Register Reg = Op.getReg();
3675
3676 int WaitStatesSinceDef =
3677 VALUWritesVDstWaitStates -
3678 getWaitStatesSinceDef(Reg, IsVALUFn,
3679 /*MaxWaitStates=*/VALUWritesVDstWaitStates);
3680 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesSinceDef);
3681 if (WaitStatesNeeded >= VALUWritesVDstWaitStates)
3682 break;
3683 }
3684
3685 int VCmpXHazardWaits =
3686 VCmpXWritesExecWaitStates -
3687 getWaitStatesSince(IsVCmpXWritesExecFn, VCmpXWritesExecWaitStates);
3688
3689 WaitStatesNeeded = std::max(WaitStatesNeeded, VCmpXHazardWaits);
3690 return WaitStatesNeeded;
3691}
3692
3694 // 2 pass -> 4
3695 // 4 pass -> 6
3696 // 8 pass -> 10
3697 // 16 pass -> 18
3698 return NumPasses + 2;
3699}
3700
3702 bool IsGFX950) {
3703 // xdl def cycles | gfx942 | gfx950
3704 // 2 pass | 5 5
3705 // 4 pass | 7 8
3706 // 8 pass | 11 12
3707 // 16 pass | 19 20
3708 return NumPasses + 3 + (NumPasses != 2 && IsGFX950);
3709}
3710
3712 bool IsGFX950) {
3713 // xdl def cycles | gfx942 | gfx950
3714 // 2 pass | 5 5
3715 // 4 pass | 7 8
3716 // 8 pass | 11 12
3717 // 16 pass | 19 20
3718 return NumPasses + 3 + (NumPasses != 2 && IsGFX950);
3719}
3720
3722 // 2 pass -> 4
3723 // 4 pass -> 6
3724 // 8 pass -> 10
3725 // 16 pass -> 18
3726 return NumPasses + 2;
3727}
3728
3729int GCNHazardRecognizer::checkMAIVALUHazards(MachineInstr *MI) const {
3730 if (!ST.hasGFX90AInsts())
3731 return 0;
3732
3733 auto IsDGEMMFn = [](const MachineInstr &MI) -> bool {
3734 return SIInstrInfo::isDGEMM(MI.getOpcode());
3735 };
3736
3737 // This is checked in checkMAIHazards90A()
3738 if (SIInstrInfo::isMFMA(*MI))
3739 return 0;
3740
3741 const MachineRegisterInfo &MRI = MF.getRegInfo();
3742
3743 int WaitStatesNeeded = 0;
3744
3745 bool IsMem = SIInstrInfo::isVMEM(*MI) || SIInstrInfo::isDS(*MI);
3746 bool IsMemOrExport = IsMem || SIInstrInfo::isEXP(*MI);
3747 bool IsVALU = SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true);
3748
3749 unsigned Reg;
3750 auto IsMFMAWriteFn = [&Reg, this](const MachineInstr &MI) {
3751 if (!SIInstrInfo::isMFMA(MI) ||
3752 !TRI.regsOverlap(MI.getOperand(0).getReg(), Reg))
3753 return false;
3754 return true;
3755 };
3756
3757 const MachineInstr *DOT = nullptr;
3758 auto IsDotWriteFn = [&Reg, &DOT, this](const MachineInstr &MI) {
3759 if (!SIInstrInfo::isDOT(MI) ||
3760 !TRI.regsOverlap(MI.getOperand(0).getReg(), Reg))
3761 return false;
3762 DOT = &MI;
3763 return true;
3764 };
3765
3766 bool DGEMMAfterVALUWrite = false;
3767 auto IsDGEMMHazard = [&DGEMMAfterVALUWrite, this](const MachineInstr &MI) {
3768 // Found DGEMM on reverse traversal to def.
3769 if (SIInstrInfo::isDGEMM(MI.getOpcode()))
3770 DGEMMAfterVALUWrite = true;
3771
3772 // Only hazard if register is defined by a VALU and a DGEMM is found after
3773 // after the def.
3774 if (!TII.isVALU(MI, /*AllowLDSDMA=*/true) || !DGEMMAfterVALUWrite)
3775 return false;
3776
3777 return true;
3778 };
3779
3780 int SrcCIdx = AMDGPU::getNamedOperandIdx(MI->getOpcode(),
3781 AMDGPU::OpName::src2);
3782
3783 if (IsMemOrExport || IsVALU) {
3784 const int SMFMA4x4WriteVgprVALUMemExpReadWaitStates = 5;
3785 const int SMFMA16x16WriteVgprVALUMemExpReadWaitStates = 11;
3786 const int SMFMA32x32WriteVgprVALUMemExpReadWaitStates = 19;
3787 const int DMFMA4x4WriteVgprMemExpReadWaitStates = 9;
3788 const int DMFMA16x16WriteVgprMemExpReadWaitStates = 18;
3789 const int DMFMA4x4WriteVgprVALUReadWaitStates = 6;
3790 const int DMFMA16x16WriteVgprVALUReadWaitStates = 11;
3791 const int GFX950_DMFMA16x16WriteVgprVALUReadWaitStates = 19;
3792 const int DotWriteSameDotReadSrcAB = 3;
3793 const int DotWriteDifferentVALURead = 3;
3794 const int DMFMABetweenVALUWriteVMEMRead = 2;
3795 const int MaxWaitStates =
3797 ST.hasGFX950Insts());
3798
3799 for (const MachineOperand &Use : MI->explicit_uses()) {
3800 if (!Use.isReg())
3801 continue;
3802 Reg = Use.getReg();
3803
3804 DOT = nullptr;
3805 int WaitStatesSinceDef = getWaitStatesSinceDef(Reg, IsDotWriteFn,
3806 MaxWaitStates);
3807 if (DOT) {
3808 int NeedWaitStates = 0;
3809 if (DOT->getOpcode() == MI->getOpcode()) {
3810 if (&Use - &MI->getOperand(0) != SrcCIdx)
3811 NeedWaitStates = DotWriteSameDotReadSrcAB;
3812 } else {
3813 NeedWaitStates = DotWriteDifferentVALURead;
3814 }
3815
3816 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceDef;
3817 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3818 }
3819
3820 // Workaround for HW data hazard bug observed only in GFX90A. When there
3821 // is a DGEMM instruction in-between a VALU and a VMEM instruction it
3822 // causes the SQ to incorrectly not insert two wait states between the two
3823 // instructions needed to avoid data hazard.
3824 if (IsMem && ST.hasGFX90AInsts() && !ST.hasGFX940Insts()) {
3825 DGEMMAfterVALUWrite = false;
3826 if (TRI.isVectorRegister(MRI, Reg)) {
3827 int WaitStatesNeededForUse =
3828 DMFMABetweenVALUWriteVMEMRead -
3829 getWaitStatesSinceDef(Reg, IsDGEMMHazard,
3830 DMFMABetweenVALUWriteVMEMRead);
3831
3832 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3833 }
3834 }
3835
3836 auto MFMAWindow = [&](const MachineInstr &Producer) {
3837 int NumPasses = TSchedModel.computeInstrLatency(&Producer);
3838 int NeedWaitStates = MaxWaitStates;
3839
3840 if (SIInstrInfo::isDGEMM(Producer.getOpcode())) {
3841 switch (NumPasses) {
3842 case 4:
3843 NeedWaitStates = IsMemOrExport
3844 ? DMFMA4x4WriteVgprMemExpReadWaitStates
3845 : DMFMA4x4WriteVgprVALUReadWaitStates;
3846 break;
3847 case 8:
3848 case 16:
3849 NeedWaitStates =
3850 IsMemOrExport
3851 ? DMFMA16x16WriteVgprMemExpReadWaitStates
3852 : (ST.hasGFX950Insts()
3853 ? GFX950_DMFMA16x16WriteVgprVALUReadWaitStates
3854 : DMFMA16x16WriteVgprVALUReadWaitStates);
3855 break;
3856 default:
3857 llvm_unreachable("unexpected dgemm");
3858 }
3859 } else if (ST.hasGFX940Insts()) {
3860 NeedWaitStates =
3861 TII.isXDL(Producer)
3863 NumPasses, ST.hasGFX950Insts())
3865 NumPasses);
3866 } else {
3867 switch (NumPasses) {
3868 case 2:
3869 NeedWaitStates = SMFMA4x4WriteVgprVALUMemExpReadWaitStates;
3870 break;
3871 case 8:
3872 NeedWaitStates = SMFMA16x16WriteVgprVALUMemExpReadWaitStates;
3873 break;
3874 case 16:
3875 NeedWaitStates = SMFMA32x32WriteVgprVALUMemExpReadWaitStates;
3876 break;
3877 default:
3878 llvm_unreachable("unexpected number of passes for mfma");
3879 }
3880 }
3881
3882 assert(NeedWaitStates <= MaxWaitStates &&
3883 "hazard requirement exceeds the scan window");
3884 return NeedWaitStates;
3885 };
3886
3887 WaitStatesNeeded = std::max(
3888 WaitStatesNeeded,
3889 getMaxWindowDeficit(MaxWaitStates,
3890 [&](const MachineInstr &P) -> std::optional<int> {
3891 if (!IsMFMAWriteFn(P))
3892 return std::nullopt;
3893 return MFMAWindow(P);
3894 }));
3895
3896 if (WaitStatesNeeded >= MaxWaitStates)
3897 break;
3898 }
3899 }
3900
3901 unsigned Opc = MI->getOpcode();
3902 const int DMFMAToFMA64WaitStates = 2;
3903 if ((Opc == AMDGPU::V_FMA_F64_e64 ||
3904 Opc == AMDGPU::V_FMAC_F64_e32 || Opc == AMDGPU::V_FMAC_F64_e64 ||
3905 Opc == AMDGPU::V_FMAC_F64_dpp) &&
3906 WaitStatesNeeded < DMFMAToFMA64WaitStates) {
3907 int WaitStatesNeededForUse = DMFMAToFMA64WaitStates -
3908 getWaitStatesSince(IsDGEMMFn, DMFMAToFMA64WaitStates);
3909 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3910 }
3911
3912 if (!IsVALU && !IsMemOrExport)
3913 return WaitStatesNeeded;
3914
3915 for (const MachineOperand &Def : MI->defs()) {
3916 const int SMFMA4x4WriteVgprVALUWawWaitStates = 5;
3917 const int SMFMA16x16WriteVgprVALUWawWaitStates = 11;
3918 const int SMFMA32x32WriteVgprVALUWawWaitStates = 19;
3919 const int SMFMA4x4ReadVgprVALUWarWaitStates = 1;
3920 const int GFX940_XDL4PassReadVgprVALUWarWaitStates = 3;
3921 const int SMFMA16x16ReadVgprVALUWarWaitStates = 7;
3922 const int SMFMA32x32ReadVgprVALUWarWaitStates = 15;
3923 const int DMFMA4x4WriteVgprVALUWriteWaitStates = 6;
3924 const int DMFMA16x16WriteVgprVALUWriteWaitStates = 11;
3925 const int DotWriteDifferentVALUWrite = 3;
3926 const int MaxWaitStates =
3927 GFX940_XDL_N_PassWriteVgprVALUWawWaitStates(16, ST.hasGFX950Insts());
3928 const int MaxWarWaitStates = 15;
3929
3930 Reg = Def.getReg();
3931
3932 DOT = nullptr;
3933 int WaitStatesSinceDef = getWaitStatesSinceDef(Reg, IsDotWriteFn,
3934 MaxWaitStates);
3935 if (DOT && DOT->getOpcode() != MI->getOpcode())
3936 WaitStatesNeeded = std::max(WaitStatesNeeded, DotWriteDifferentVALUWrite -
3937 WaitStatesSinceDef);
3938
3939 auto MFMAWawWindow = [&](const MachineInstr &Producer) {
3940 int NeedWaitStates = MaxWaitStates;
3941 int NumPasses = TSchedModel.computeInstrLatency(&Producer);
3942
3943 if (SIInstrInfo::isDGEMM(Producer.getOpcode())) {
3944 switch (NumPasses) {
3945 case 4:
3946 NeedWaitStates = DMFMA4x4WriteVgprVALUWriteWaitStates;
3947 break;
3948 case 8:
3949 case 16:
3950 NeedWaitStates = DMFMA16x16WriteVgprVALUWriteWaitStates;
3951 break;
3952 default:
3953 llvm_unreachable("unexpected number of cycles for dgemm");
3954 }
3955 } else if (ST.hasGFX940Insts()) {
3956 NeedWaitStates =
3957 TII.isXDL(Producer)
3959 NumPasses, ST.hasGFX950Insts())
3961 } else {
3962 switch (NumPasses) {
3963 case 2:
3964 NeedWaitStates = SMFMA4x4WriteVgprVALUWawWaitStates;
3965 break;
3966 case 8:
3967 NeedWaitStates = SMFMA16x16WriteVgprVALUWawWaitStates;
3968 break;
3969 case 16:
3970 NeedWaitStates = SMFMA32x32WriteVgprVALUWawWaitStates;
3971 break;
3972 default:
3973 llvm_unreachable("Unexpected number of passes for mfma");
3974 }
3975 }
3976
3977 assert(NeedWaitStates <= MaxWaitStates &&
3978 "hazard requirement exceeds the scan window");
3979 return NeedWaitStates;
3980 };
3981
3982 WaitStatesNeeded = std::max(
3983 WaitStatesNeeded,
3984 getMaxWindowDeficit(MaxWaitStates,
3985 [&](const MachineInstr &P) -> std::optional<int> {
3986 if (!IsMFMAWriteFn(P))
3987 return std::nullopt;
3988 return MFMAWawWindow(P);
3989 }));
3990
3991 if (WaitStatesNeeded >= MaxWaitStates)
3992 break;
3993
3994 // Wait states this write needs after an MFMA that read Reg as srcC.
3995 auto SMFMAReadAsCWindow =
3996 [&](const MachineInstr &Reader) -> std::optional<int> {
3997 if (!SIInstrInfo::isMFMA(Reader) ||
3998 SIInstrInfo::isDGEMM(Reader.getOpcode()) ||
3999 !Reader.readsRegister(Reg, &TRI))
4000 return std::nullopt;
4001
4002 if (ST.hasGFX940Insts() && !TII.isXDL(Reader))
4003 return std::nullopt;
4004
4005 const MachineOperand *SrcC =
4006 TII.getNamedOperand(Reader, AMDGPU::OpName::src2);
4007 assert(SrcC && "an MFMA must have a src2 operand");
4008 if (!SrcC->isReg() || !TRI.regsOverlap(SrcC->getReg(), Reg))
4009 return std::nullopt;
4010
4011 switch (TSchedModel.computeInstrLatency(&Reader)) {
4012 case 2:
4013 return SMFMA4x4ReadVgprVALUWarWaitStates;
4014 case 4:
4015 assert(ST.hasGFX940Insts() && "4-pass XDL is gfx940 or later");
4016 return GFX940_XDL4PassReadVgprVALUWarWaitStates;
4017 case 8:
4018 return SMFMA16x16ReadVgprVALUWarWaitStates;
4019 case 16:
4020 [[fallthrough]];
4021 default:
4022 return SMFMA32x32ReadVgprVALUWarWaitStates;
4023 }
4024 };
4025
4026 WaitStatesNeeded =
4027 std::max(WaitStatesNeeded,
4028 getMaxWindowDeficit(MaxWarWaitStates, SMFMAReadAsCWindow));
4029 }
4030
4031 return WaitStatesNeeded;
4032}
4033
4035 if (!SU->isInstr())
4036 return false;
4037
4038 const MachineInstr *MAI = nullptr;
4039
4040 auto IsMFMAFn = [&MAI](const MachineInstr &MI) {
4041 MAI = nullptr;
4043 MAI = &MI;
4044 return MAI != nullptr;
4045 };
4046
4047 MachineInstr *MI = SU->getInstr();
4048 if (IsMFMAFn(*MI)) {
4049 int W = getWaitStatesSince(IsMFMAFn, 16);
4050 if (MAI)
4051 return W < (int)TSchedModel.computeInstrLatency(MAI);
4052 }
4053
4054 return false;
4055}
4056
4057// Adjust global offsets for instructions bundled with S_GETPC_B64 after
4058// insertion of a new instruction.
4059static void updateGetPCBundle(MachineInstr *NewMI) {
4060 if (!NewMI->isBundled())
4061 return;
4062
4063 // Find start of bundle.
4064 auto I = NewMI->getIterator();
4065 while (I->isBundledWithPred())
4066 I--;
4067 if (I->isBundle())
4068 I++;
4069
4070 // Bail if this is not an S_GETPC bundle.
4071 if (I->getOpcode() != AMDGPU::S_GETPC_B64)
4072 return;
4073
4074 // Update offsets of any references in the bundle.
4075 const unsigned NewBytes = 4;
4076 assert(NewMI->getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
4077 "Unexpected instruction insertion in bundle");
4078 auto NextMI = std::next(NewMI->getIterator());
4079 auto End = NewMI->getParent()->end();
4080 while (NextMI != End && NextMI->isBundledWithPred()) {
4081 for (auto &Operand : NextMI->operands()) {
4082 if (Operand.isGlobal())
4083 Operand.setOffset(Operand.getOffset() + NewBytes);
4084 }
4085 NextMI++;
4086 }
4087}
4088
4089bool GCNHazardRecognizer::fixVALUMaskWriteHazard(MachineInstr *MI) {
4090 if (!ST.hasVALUMaskWriteHazard())
4091 return false;
4092 assert(!ST.hasExtendedWaitCounts());
4093
4094 if (!ST.isWave64())
4095 return false;
4096
4097 const bool IsSALU = SIInstrInfo::isSALU(*MI);
4098 const bool IsVALU = SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true);
4099 if (!IsSALU && !IsVALU)
4100 return false;
4101
4102 // The hazard sequence is three instructions:
4103 // 1. VALU reads SGPR as mask
4104 // 2. VALU/SALU writes SGPR
4105 // 3. VALU/SALU reads SGPR
4106 // The hazard can expire if the distance between 2 and 3 is sufficient,
4107 // or (2) is VALU and (3) is SALU.
4108 // In practice this happens <10% of the time, hence always assume the hazard
4109 // exists if (1) and (2) are present to avoid searching all SGPR reads.
4110
4111 const SIRegisterInfo *TRI = ST.getRegisterInfo();
4112 const MachineRegisterInfo &MRI = MF.getRegInfo();
4113
4114 auto IgnoreableSGPR = [](const Register Reg) {
4115 switch (Reg) {
4116 case AMDGPU::EXEC:
4117 case AMDGPU::EXEC_LO:
4118 case AMDGPU::EXEC_HI:
4119 case AMDGPU::M0:
4120 case AMDGPU::SGPR_NULL:
4121 case AMDGPU::SGPR_NULL64:
4122 case AMDGPU::SCC:
4123 return true;
4124 default:
4125 return false;
4126 }
4127 };
4128 auto IsVCC = [](const Register Reg) {
4129 return Reg == AMDGPU::VCC || Reg == AMDGPU::VCC_LO || Reg == AMDGPU::VCC_HI;
4130 };
4131
4132 struct StateType {
4133 SmallSet<Register, 2> HazardSGPRs;
4134
4135 static unsigned getHashValue(const StateType &State) {
4136 return static_cast<unsigned>(hash_combine_range(State.HazardSGPRs));
4137 }
4138 static bool isEqual(const StateType &LHS, const StateType &RHS) {
4139 return LHS.HazardSGPRs == RHS.HazardSGPRs;
4140 }
4141 };
4142
4143 StateType InitialState;
4144
4145 // Look for SGPR write.
4146 MachineOperand *HazardDef = nullptr;
4147 for (MachineOperand &Op : MI->all_defs()) {
4148 Register Reg = Op.getReg();
4149 if (IgnoreableSGPR(Reg))
4150 continue;
4151 if (!IsVCC(Reg)) {
4152 if (Op.isImplicit())
4153 continue;
4154 if (!TRI->isSGPRReg(MRI, Reg))
4155 continue;
4156 }
4157
4158 HazardDef = &Op;
4159 break;
4160 }
4161
4162 if (!HazardDef)
4163 return false;
4164
4165 // Setup to track writes to individual SGPRs
4166 const Register HazardReg = HazardDef->getReg();
4167 if (AMDGPU::SReg_32RegClass.contains(HazardReg)) {
4168 InitialState.HazardSGPRs.insert(HazardReg);
4169 } else {
4170 assert(AMDGPU::SReg_64RegClass.contains(HazardReg));
4171 InitialState.HazardSGPRs.insert(TRI->getSubReg(HazardReg, AMDGPU::sub0));
4172 InitialState.HazardSGPRs.insert(TRI->getSubReg(HazardReg, AMDGPU::sub1));
4173 }
4174
4175 auto IsHazardFn = [&](StateType &State, const MachineInstr &I) {
4176 if (State.HazardSGPRs.empty())
4177 return HazardExpired;
4178
4179 switch (I.getOpcode()) {
4180 case AMDGPU::V_ADDC_U32_e32:
4181 case AMDGPU::V_ADDC_U32_dpp:
4182 case AMDGPU::V_CNDMASK_B16_t16_e32:
4183 case AMDGPU::V_CNDMASK_B16_fake16_e32:
4184 case AMDGPU::V_CNDMASK_B16_t16_dpp:
4185 case AMDGPU::V_CNDMASK_B16_fake16_dpp:
4186 case AMDGPU::V_CNDMASK_B32_e32:
4187 case AMDGPU::V_CNDMASK_B32_dpp:
4188 case AMDGPU::V_DIV_FMAS_F32_e64:
4189 case AMDGPU::V_DIV_FMAS_F64_e64:
4190 case AMDGPU::V_SUBB_U32_e32:
4191 case AMDGPU::V_SUBB_U32_dpp:
4192 case AMDGPU::V_SUBBREV_U32_e32:
4193 case AMDGPU::V_SUBBREV_U32_dpp: {
4194 // These implicitly read VCC as mask source.
4195 return IsVCC(HazardReg) ? HazardFound : NoHazardFound;
4196 }
4197 case AMDGPU::V_ADDC_U32_e64:
4198 case AMDGPU::V_ADDC_U32_e64_dpp:
4199 case AMDGPU::V_CNDMASK_B16_t16_e64:
4200 case AMDGPU::V_CNDMASK_B16_fake16_e64:
4201 case AMDGPU::V_CNDMASK_B16_t16_e64_dpp:
4202 case AMDGPU::V_CNDMASK_B16_fake16_e64_dpp:
4203 case AMDGPU::V_CNDMASK_B32_e64:
4204 case AMDGPU::V_CNDMASK_B32_e64_dpp:
4205 case AMDGPU::V_SUBB_U32_e64:
4206 case AMDGPU::V_SUBB_U32_e64_dpp:
4207 case AMDGPU::V_SUBBREV_U32_e64:
4208 case AMDGPU::V_SUBBREV_U32_e64_dpp: {
4209 // Only check mask register overlaps.
4210 const MachineOperand *SSRCOp = TII.getNamedOperand(I, AMDGPU::OpName::src2);
4211 assert(SSRCOp);
4212 bool Result = TRI->regsOverlap(SSRCOp->getReg(), HazardReg);
4213 return Result ? HazardFound : NoHazardFound;
4214 }
4215 default:
4216 return NoHazardFound;
4217 }
4218 };
4219
4220 auto UpdateStateFn = [&](StateType &State, const MachineInstr &I) {
4221 // Update tracking of SGPR writes.
4222 for (auto &Op : I.all_defs()) {
4223 Register Reg = Op.getReg();
4224 if (IgnoreableSGPR(Reg))
4225 continue;
4226 if (!IsVCC(Reg)) {
4227 if (Op.isImplicit())
4228 continue;
4229 if (!TRI->isSGPRReg(MRI, Reg))
4230 continue;
4231 }
4232
4233 // Stop tracking any SGPRs with writes on the basis that they will
4234 // already have an appropriate wait inserted afterwards.
4236 for (Register SGPR : State.HazardSGPRs) {
4237 if (Reg == SGPR || TRI->regsOverlap(Reg, SGPR))
4238 Found.push_back(SGPR);
4239 }
4240 for (Register SGPR : Found)
4241 State.HazardSGPRs.erase(SGPR);
4242 }
4243 };
4244
4245 // Check for hazard
4246 if (!hasHazard<StateType>(InitialState, IsHazardFn, UpdateStateFn,
4247 MI->getParent(),
4248 std::next(MI->getReverseIterator())))
4249 return false;
4250
4251 // Compute counter mask
4252 unsigned DepCtr =
4253 IsVALU ? (IsVCC(HazardReg) ? AMDGPU::DepCtr::encodeFieldVaVcc(0, ST)
4254 : AMDGPU::DepCtr::encodeFieldVaSdst(0, ST))
4255 : AMDGPU::DepCtr::encodeFieldSaSdst(0, ST);
4256
4257 // Add s_waitcnt_depctr after SGPR write.
4258 auto NextMI = std::next(MI->getIterator());
4259 auto NewMI = BuildMI(*MI->getParent(), NextMI, MI->getDebugLoc(),
4260 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
4261 .addImm(DepCtr);
4262
4263 // SALU write may be s_getpc in a bundle.
4264 updateGetPCBundle(NewMI);
4265
4266 return true;
4267}
4268
4269static bool ensureEntrySetPrio(MachineFunction *MF, int Priority,
4270 const SIInstrInfo &TII) {
4271 MachineBasicBlock &EntryMBB = MF->front();
4272 if (EntryMBB.begin() != EntryMBB.end()) {
4273 auto &EntryMI = *EntryMBB.begin();
4274 if (EntryMI.getOpcode() == AMDGPU::S_SETPRIO &&
4275 EntryMI.getOperand(0).getImm() >= Priority)
4276 return false;
4277 }
4278
4279 BuildMI(EntryMBB, EntryMBB.begin(), DebugLoc(), TII.get(AMDGPU::S_SETPRIO))
4280 .addImm(Priority);
4281 return true;
4282}
4283
4284bool GCNHazardRecognizer::fixRequiredExportPriority(MachineInstr *MI) {
4285 if (!ST.hasRequiredExportPriority())
4286 return false;
4287
4288 // Assume the following shader types will never have exports,
4289 // and avoid adding or adjusting S_SETPRIO.
4290 MachineBasicBlock *MBB = MI->getParent();
4291 MachineFunction *MF = MBB->getParent();
4292 auto CC = MF->getFunction().getCallingConv();
4293 switch (CC) {
4298 return false;
4299 default:
4300 break;
4301 }
4302
4303 const int MaxPriority = 3;
4304 const int NormalPriority = 2;
4305 const int PostExportPriority = 0;
4306
4307 auto It = MI->getIterator();
4308 switch (MI->getOpcode()) {
4309 case AMDGPU::S_ENDPGM:
4310 case AMDGPU::S_ENDPGM_SAVED:
4311 case AMDGPU::S_ENDPGM_ORDERED_PS_DONE:
4312 case AMDGPU::SI_RETURN_TO_EPILOG:
4313 // Ensure shader with calls raises priority at entry.
4314 // This ensures correct priority if exports exist in callee.
4315 if (MF->getFrameInfo().hasCalls())
4316 return ensureEntrySetPrio(MF, NormalPriority, TII);
4317 return false;
4318 case AMDGPU::S_SETPRIO: {
4319 // Raise minimum priority unless in workaround.
4320 auto &PrioOp = MI->getOperand(0);
4321 int Prio = static_cast<int>(PrioOp.getImm());
4322 bool InWA = (Prio == PostExportPriority) &&
4323 (It != MBB->begin() && TII.isEXP(*std::prev(It)));
4324 if (InWA || Prio >= NormalPriority)
4325 return false;
4326 PrioOp.setImm(std::min(Prio + NormalPriority, MaxPriority));
4327 return true;
4328 }
4329 default:
4330 if (!TII.isEXP(*MI))
4331 return false;
4332 break;
4333 }
4334
4335 // Check entry priority at each export (as there will only be a few).
4336 // Note: amdgpu_gfx can only be a callee, so defer to caller setprio.
4337 bool Changed = false;
4339 Changed = ensureEntrySetPrio(MF, NormalPriority, TII);
4340
4341 auto NextMI = std::next(It);
4342 bool EndOfShader = false;
4343 if (NextMI != MBB->end()) {
4344 // Only need WA at end of sequence of exports.
4345 if (TII.isEXP(*NextMI))
4346 return Changed;
4347 // Assume appropriate S_SETPRIO after export means WA already applied.
4348 if (NextMI->getOpcode() == AMDGPU::S_SETPRIO &&
4349 NextMI->getOperand(0).getImm() == PostExportPriority)
4350 return Changed;
4351 EndOfShader = NextMI->getOpcode() == AMDGPU::S_ENDPGM;
4352 }
4353
4354 const DebugLoc &DL = MI->getDebugLoc();
4355
4356 // Lower priority.
4357 BuildMI(*MBB, NextMI, DL, TII.get(AMDGPU::S_SETPRIO))
4358 .addImm(PostExportPriority);
4359
4360 if (!EndOfShader) {
4361 // Wait for exports to complete.
4362 BuildMI(*MBB, NextMI, DL, TII.get(AMDGPU::S_WAITCNT_EXPCNT))
4363 .addReg(AMDGPU::SGPR_NULL)
4364 .addImm(0);
4365 }
4366
4367 BuildMI(*MBB, NextMI, DL, TII.get(AMDGPU::S_NOP)).addImm(0);
4368 BuildMI(*MBB, NextMI, DL, TII.get(AMDGPU::S_NOP)).addImm(0);
4369
4370 if (!EndOfShader) {
4371 // Return to normal (higher) priority.
4372 BuildMI(*MBB, NextMI, DL, TII.get(AMDGPU::S_SETPRIO))
4373 .addImm(NormalPriority);
4374 }
4375
4376 return true;
4377}
4378
4379// Advance past meta instructions (debug values, labels, CFI, KILL, etc.) to the
4380// next instruction that actually issues. Unlike skipDebugInstructionsForward /
4381// next_nodbg, this skips the full isMetaInstruction() set.
4385 while (I != End && I->isMetaInstruction())
4386 ++I;
4387 return I;
4388}
4389
4390bool GCNHazardRecognizer::fixVPermPk16Hazard(MachineInstr *MI) {
4391 // Requirement #1 of 2:
4392 // The cross-wave entry-block mitigation is delegated to the mandatory
4393 // unclaused-VMEM entry prologue (GLOBAL_PREFETCH_B8 + V_NOP).
4394 assert(ST.hasRequiresInitialUnclausedVmem() &&
4395 "V_PERM_PK16-hazard subtarget must provide the unclaused-VMEM entry "
4396 "prologue to satisfy the cross-wave entry mitigation");
4397
4398 if (!SIInstrInfo::isVPermPk16(MI->getOpcode()))
4399 return false;
4400
4401 MachineBasicBlock *MBB = MI->getParent();
4402
4403 // Requirement #2 of 2:
4404 // V_PERM_PK16 must be immediately followed by a safe instruction.
4406 skipMetaInstructionsForward(std::next(MI->getIterator()), MBB->end());
4407 if (NextI != MBB->end() && TII.isVPermPk16SafeInstr(*NextI))
4408 return false;
4409
4410 // EXEC is guaranteed non-zero here: V_PERM_PK16 reports unwanted effects
4411 // when EXEC is empty, so s_cbranch_execz over this region is retained.
4412 // A plain V_NOP is therefore a real VALU nop and clears the hazard.
4413 BuildMI(*MBB, NextI, MI->getDebugLoc(), TII.get(AMDGPU::V_NOP_e32));
4414 return true;
4415}
4416
4417bool GCNHazardRecognizer::fixGetRegWaitIdle(MachineInstr *MI) {
4418 if (!isSGetReg(MI->getOpcode()))
4419 return false;
4420
4421 const SIInstrInfo *TII = ST.getInstrInfo();
4422 switch (getHWReg(TII, *MI)) {
4423 default:
4424 return false;
4429 break;
4430 }
4431
4432 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
4433 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4434 .addImm(0);
4435 return true;
4436}
4437
4438bool GCNHazardRecognizer::fixDsAtomicAsyncBarrierArriveB64(MachineInstr *MI) {
4439 if (MI->getOpcode() != AMDGPU::DS_ATOMIC_ASYNC_BARRIER_ARRIVE_B64)
4440 return false;
4441
4442 const SIInstrInfo *TII = ST.getInstrInfo();
4443 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
4444 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4446 BuildMI(*MI->getParent(), std::next(MI->getIterator()), MI->getDebugLoc(),
4447 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4449
4450 return true;
4451}
4452
4453bool GCNHazardRecognizer::fixScratchBaseForwardingHazard(MachineInstr *MI) {
4454 // No reason to check this in pre-RA scheduling, SGPRs have to be allocated
4455 // for hazard to trigger.
4457 return false;
4458
4459 const SIRegisterInfo *TRI = ST.getRegisterInfo();
4460 const SIInstrInfo *TII = ST.getInstrInfo();
4461 // Hazard expires after 10 SGPR writes by SALU or 8 SGPR writes by VALU.
4462 const int FlatScrBaseWaitStates = 10;
4463
4464 bool ReadsFlatScrLo =
4465 MI->readsRegister(AMDGPU::SRC_FLAT_SCRATCH_BASE_LO, TRI);
4466 bool ReadsFlatScrHi =
4467 MI->readsRegister(AMDGPU::SRC_FLAT_SCRATCH_BASE_HI, TRI);
4468 if (isSGetReg(MI->getOpcode())) {
4469 switch (getHWReg(TII, *MI)) {
4470 default:
4471 break;
4473 ReadsFlatScrLo = true;
4474 break;
4476 ReadsFlatScrHi = true;
4477 break;
4478 }
4479 }
4480
4481 const MachineRegisterInfo &MRI = MF.getRegInfo();
4482
4483 auto IsRegDefHazard = [&](Register Reg) -> bool {
4484 DenseSet<const MachineBasicBlock *> Visited;
4485 auto IsHazardFn = [TRI, Reg](const MachineInstr &MI) {
4486 return MI.modifiesRegister(Reg, TRI);
4487 };
4488
4489 // This literally abuses the idea of waitstates. Instead of waitstates it
4490 // returns 1 for SGPR written and 0 otherwise.
4491 auto IsSGPRDef = [TII, TRI, &MRI](const MachineInstr &MI) -> unsigned {
4492 if (!TII->isSALU(MI) && !TII->isVALU(MI, /*AllowLDSDMA=*/true))
4493 return 0;
4494 for (const MachineOperand &MO : MI.all_defs()) {
4495 if (TRI->isSGPRReg(MRI, MO.getReg()))
4496 return 1;
4497 }
4498 return 0;
4499 };
4500
4501 auto IsExpiredFn = [=](const MachineInstr &MI, int SgprWrites) {
4502 if (MI.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR) {
4503 unsigned Wait = static_cast<unsigned>(MI.getOperand(0).getImm());
4506 return true;
4507 }
4508 return SgprWrites >= FlatScrBaseWaitStates;
4509 };
4510
4511 return ::getWaitStatesSince(
4512 IsHazardFn, MI->getParent(), std::next(MI->getReverseIterator()),
4513 0, IsExpiredFn, Visited, IsSGPRDef) < FlatScrBaseWaitStates;
4514 };
4515
4516 if ((!ReadsFlatScrLo || MRI.isConstantPhysReg(AMDGPU::SGPR102) ||
4517 !IsRegDefHazard(AMDGPU::SGPR102)) &&
4518 (!ReadsFlatScrHi || MRI.isConstantPhysReg(AMDGPU::SGPR103) ||
4519 !IsRegDefHazard(AMDGPU::SGPR103)))
4520 return false;
4521
4522 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
4523 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4526 return true;
4527}
4528
4529bool GCNHazardRecognizer::fixSetRegMode(MachineInstr *MI) {
4530 if (!isSSetReg(MI->getOpcode()) ||
4531 MI->getOperand(1).getImm() != AMDGPU::Hwreg::ID_MODE)
4532 return false;
4533
4534 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), TII.get(AMDGPU::V_NOP_e32));
4535 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), TII.get(AMDGPU::V_NOP_e32));
4536 return true;
4537}
4538
4539bool GCNHazardRecognizer::fixTDM(MachineInstr *MI) {
4540 auto IsTDM = [&](const MachineInstr &MI) -> bool {
4542 MI.getOpcode() != AMDGPU::S_WAIT_TENSORCNT;
4543 };
4544
4545 if (!IsTDM(*MI))
4546 return false;
4547
4548 auto IsExpiredFn = [](const MachineInstr &MI, int) {
4549 if (MI.getOpcode() != AMDGPU::S_WAIT_TENSORCNT)
4550 return false;
4551 return MI.getOperand(0).getImm() <= 10;
4552 };
4553
4554 if (::getWaitStatesSince(IsTDM, MI, IsExpiredFn) ==
4555 std::numeric_limits<int>::max())
4556 return false;
4557
4558 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
4559 TII.get(AMDGPU::S_WAIT_TENSORCNT))
4560 .addImm(10);
4561 return true;
4562}
SDValue Pred
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
uint64_t Imm
The AMDGPU TargetMachine interface definition for hw codegen targets.
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static bool isEqual(const Function &Caller, const Function &Callee)
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static cl::opt< unsigned, false, MFMAPaddingRatioParser > MFMAPaddingRatio("amdgpu-mfma-padding-ratio", cl::init(0), cl::Hidden, cl::desc("Fill a percentage of the latency between " "neighboring MFMA with s_nops."))
static bool shouldRunLdsBranchVmemWARHazardFixup(const MachineFunction &MF, const GCNSubtarget &ST)
static bool consumesDstSelForwardingOperand(const MachineInstr *VALU, const MachineOperand *Dst, const SIRegisterInfo *TRI)
Checks whether the provided MI "consumes" the operand with a Dest sel fowarding issue Dst .
static bool isSGetReg(unsigned Opcode)
static bool breaksSMEMSoftClause(MachineInstr *MI)
static bool isLdsDma(const MachineInstr &MI)
static int GFX940_XDL_N_PassWritesVGPROverlappedSrcABWaitStates(int NumPasses, bool IsGFX950)
static unsigned getWMMAHazardInstInCategory(const MachineInstr &MI, const SIInstrInfo *TII, const TargetSchedModel &SchedModel, const GCNSubtarget &ST)
static bool isRFE(unsigned Opcode)
static bool isRWLane(unsigned Opcode)
static bool isSMovRel(unsigned Opcode)
static unsigned getMFMANonMacAGPRFormOp(unsigned Opc)
One MFMA can be written with up to four opcodes that differ only in how vdst and src2 are encoded: bo...
#define DEBUG_TYPE_VERBOSE
static const MachineOperand * getDstSelForwardingOperand(const MachineInstr &MI, const GCNSubtarget &ST)
Dest sel forwarding issue occurs if additional logic is needed to swizzle / pack the computed value i...
static int GFX940_XDL_N_PassWritesVGPROverlappedSGEMMDGEMMSrcCWaitStates(int NumPasses, bool IsGFX950)
static void updateGetPCBundle(MachineInstr *NewMI)
static int GFX940_XDL_N_PassWriteVgprVALUMemExpReadWaitStates(int NumPasses, bool IsGFX950)
static bool isStoreCountWaitZero(const MachineInstr &I)
static bool breaksVMEMSoftClause(MachineInstr *MI)
static bool isVCmpXWritesExec(const SIInstrInfo &TII, const SIRegisterInfo &TRI, const MachineInstr &MI)
static bool isSSetReg(unsigned Opcode)
static void addRegUnits(const SIRegisterInfo &TRI, BitVector &BV, MCRegister Reg)
static unsigned getHWReg(const SIInstrInfo *TII, const MachineInstr &RegInstr)
static bool isSameMFMA(unsigned Opc0, unsigned Opc1)
static bool isDivFMas(unsigned Opcode)
static unsigned getCountedWaitStates(const MachineInstr &MI, GCNHazardRecognizer::GetNumWaitStatesFn GetNumWaitStates)
static bool hasHazard(StateT InitialState, function_ref< HazardFnResult(StateT &, const MachineInstr &)> IsHazard, function_ref< void(StateT &, const MachineInstr &)> UpdateState, const MachineBasicBlock *InitialMBB, MachineBasicBlock::const_reverse_instr_iterator InitialI)
static int getWaitStatesSince(GCNHazardRecognizer::IsHazardFn IsHazard, const MachineBasicBlock *MBB, MachineBasicBlock::const_reverse_instr_iterator I, int WaitStates, GCNHazardRecognizer::IsExpiredFn IsExpired, DenseSet< const MachineBasicBlock * > &Visited, GCNHazardRecognizer::GetNumWaitStatesFn GetNumWaitStates=SIInstrInfo::getNumWaitStates)
static int GFX940_SMFMA_N_PassWritesVGPROverlappedSrcABWaitStates(int NumPasses)
static int GFX940_XDL_N_PassWriteVgprVALUWawWaitStates(int NumPasses, bool IsGFX950)
static int GFX940_SMFMA_N_PassWriteVgprVALUMemExpReadWaitStates(int NumPasses)
static MachineBasicBlock::iterator skipMetaInstructionsForward(MachineBasicBlock::iterator I, MachineBasicBlock::iterator End)
static int GFX940_SMFMA_N_PassWritesVGPROverlappedSMFMASrcCWaitStates(int NumPasses)
static bool isCoexecutableVALUInst(const MachineInstr &MI)
static bool ensureEntrySetPrio(MachineFunction *MF, int Priority, const SIInstrInfo &TII)
static void addRegsToSet(const SIRegisterInfo &TRI, iterator_range< MachineInstr::const_mop_iterator > Ops, BitVector &DefSet, BitVector &UseSet)
static void insertNoopsInBundle(MachineInstr *MI, const SIInstrInfo &TII, unsigned Quantity)
static bool isSendMsgTraceDataOrGDS(const SIInstrInfo &TII, const MachineInstr &MI)
static unsigned countUnexecutedTerminators(const MachineBasicBlock &Pred, const MachineBasicBlock *MBB)
static 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
IRTranslator LLVM IR MI
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
static llvm::Error parse(GsymDataExtractor &Data, uint64_t BaseAddr, LineEntryCallback const &Callback)
Definition LineTable.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
#define H(x, y, z)
Definition MD5.cpp:56
Register Reg
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
#define P(N)
RISCVCC::CondCode CC
MachineRegisterInfo & MRI
Func MI getDebugLoc()))
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
Definition Value.cpp:479
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition Statistic.h:171
#define LLVM_DEBUG(...)
Definition Debug.h:119
#define DEBUG_WITH_TYPE(TYPE,...)
DEBUG_WITH_TYPE macro - This macro should be used by passes to emit debug information.
Definition Debug.h:72
Value * RHS
Value * LHS
static const uint32_t IV[8]
Definition blake3_impl.h:83
unsigned get(InstCounterType T) const
BitVector & set()
Set all bits in the bitvector.
Definition BitVector.h:367
A debug info location.
Definition DebugLoc.h:126
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,...
Definition DenseMap.h:874
Implements a dense probed hash-table based set.
Definition DenseSet.h:283
CallingConv::ID getCallingConv() const
getCallingConv()/setCallingConv(CC) - These method get and set the calling convention of this functio...
Definition Function.h:273
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.
Definition MCRegister.h:41
Instructions::const_reverse_iterator const_reverse_instr_iterator
LLVM_ABI iterator getFirstTerminator()
Returns an iterator to the first terminator instruction of this basic block.
Instructions::iterator instr_iterator
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineInstrBundleIterator< MachineInstr > iterator
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineBasicBlock & front() const
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & addDef(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register definition operand.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
bool readsRegister(Register Reg, const TargetRegisterInfo *TRI) const
Return true if the MachineInstr reads the specified register.
bool isBundled() const
Return true if this instruction part of a bundle.
MachineOperand class - Representation of each machine instruction operand.
void setImm(int64_t immVal)
int64_t getImm() const
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.
Definition Register.h:20
static bool isDS(const MachineInstr &MI)
static bool isVMEM(const MachineInstr &MI)
static bool isSMRD(const MachineInstr &MI)
static bool isMTBUF(const MachineInstr &MI)
static bool isDGEMM(unsigned Opcode)
static bool isEXP(const MachineInstr &MI)
static bool isSALU(const MachineInstr &MI)
static bool isSDWA(const MachineInstr &MI)
static bool isDOT(const MachineInstr &MI)
static bool usesTENSOR_CNT(const MachineInstr &MI)
static bool isSWMMAC(const MachineInstr &MI)
static bool isLDSDIR(const MachineInstr &MI)
static bool isVPermPk16(unsigned Opcode)
static bool isVALU(const MachineInstr &MI, bool AllowLDSDMA)
static bool isTRANS(const MachineInstr &MI)
static bool isMUBUF(const MachineInstr &MI)
static bool isWaitcnt(unsigned Opcode)
static bool isVOP3(const MCInstrDesc &Desc)
static bool isDPP(const MachineInstr &MI)
static bool isMFMA(const MachineInstr &MI)
static bool isMAI(const MCInstrDesc &Desc)
static bool isFPAtomic(const MachineInstr &MI)
static bool isMIMG(const MachineInstr &MI)
static unsigned getNumWaitStates(const MachineInstr &MI)
Return the number of wait states that result from executing this instruction.
static bool isVOP3P(const MachineInstr &MI)
static bool isWMMA(const MachineInstr &MI)
static bool isLDSDMA(const MachineInstr &MI)
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 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.
Definition SetVector.h:103
bool insert(const value_type &X)
Insert a new element into the SetVector.
Definition SetVector.h:157
A SetVector that performs no allocations if smaller than a certain size.
Definition SetVector.h:346
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
Definition SmallSet.h:184
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.
Definition StringRef.h:490
Provide an instruction scheduling machine model to CodeGen passes.
std::pair< iterator, bool > insert(const ValueT &V)
Definition DenseSet.h:210
An efficient, type-erasing, non-owning reference to a callable.
self_iterator getIterator()
Definition ilist_node.h:123
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)
StringRef getSchedStrategy(const AMDGPUOptions &CLOpts, const Function &F)
const char * getStageTypeName(CoExecStageType T)
LLVM_ABI IsaVersion getIsaVersion(StringRef GPU)
unsigned getRegBitWidth(unsigned RCID)
Get the size in bits of a register from the register class RC.
LLVM_READONLY int32_t getMFMAEarlyClobberOp(uint32_t Opcode)
CoExecMask CoExecMaskT
Waitcnt decodeWaitcnt(const IsaVersion &Version, unsigned Encoded)
CoExecInfo getCoExecInfo(const MachineInstr &MI, const SIInstrInfo &TII)
Get co-execution info for a WMMA instruction, selecting the per-cycle slot pattern from the opcode (a...
LLVM_READONLY bool hasNamedOperand(uint32_t Opcode, OpName NamedIdx)
LLVM_READONLY int32_t getAGPRFormOp(uint32_t Opcode)
InstructionFlavor classifyFlavor(const MachineInstr &MI, const SIInstrInfo &SII)
Classify MI into the execution flavor that drives both the scheduler's slot preferences and the hazar...
CoExecMaskT getCoExecMask(InstructionFlavor F)
Map a flavor to the co-execution class it occupies in a window slot.
bool isGFX1250(const MCSubtargetInfo &STI)
@ Entry
Definition COFF.h:862
@ AMDGPU_CS
Used for Mesa/AMDPAL compute shaders.
@ AMDGPU_KERNEL
Used for AMDGPU code object kernels.
@ AMDGPU_Gfx
Used for AMD graphics targets.
@ AMDGPU_CS_ChainPreserve
Used on AMDGPUs to give the middle-end more control over argument placement.
@ AMDGPU_CS_Chain
Used on AMDGPUs to give the middle-end more control over argument placement.
This namespace contains all of the command line option processing machinery.
initializer< Ty > init(const Ty &Val)
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
constexpr double e
NodeAddr< DefNode * > Def
Definition RDFGraph.h:384
NodeAddr< UseNode * > Use
Definition RDFGraph.h:385
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.
Definition STLExtras.h:316
@ Offset
Definition DWP.cpp:577
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.
@ Wait
Definition Threading.h:60
constexpr RegState getDeadRegState(bool B)
Op::Description Desc
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
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
Definition InstrProf.h:145
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Next
Definition InstrProf.h:147
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
Definition Hashing.h:307
@ End
Run the machine verifier once, at the end of the pipeline.
Definition CodeGen.h:320
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.
Definition Hashing.h:287
#define N
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...