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