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 size_t 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 size_t 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 size_t 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 &&
2059 static_cast<unsigned>(MI.getOperand(0).getImm())) == 0);
2060 };
2061
2062 if (::getWaitStatesSince(IsHazardFn, MI, IsExpiredFn) ==
2063 std::numeric_limits<int>::max())
2064 return false;
2065
2066 const SIInstrInfo *TII = ST.getInstrInfo();
2067 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
2068 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
2070 return true;
2071}
2072
2073bool GCNHazardRecognizer::fixSMEMtoVectorWriteHazards(MachineInstr *MI) {
2074 if (!ST.hasSMEMtoVectorWriteHazard())
2075 return false;
2076 assert(!ST.hasExtendedWaitCounts());
2077
2078 if (!SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true))
2079 return false;
2080
2081 AMDGPU::OpName SDSTName;
2082 switch (MI->getOpcode()) {
2083 case AMDGPU::V_READLANE_B32:
2084 case AMDGPU::V_READFIRSTLANE_B32:
2085 SDSTName = AMDGPU::OpName::vdst;
2086 break;
2087 default:
2088 SDSTName = AMDGPU::OpName::sdst;
2089 break;
2090 }
2091
2092 const SIInstrInfo *TII = ST.getInstrInfo();
2093 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2094 const AMDGPU::IsaVersion IV = AMDGPU::getIsaVersion(ST.getCPU());
2095 const MachineOperand *SDST = TII->getNamedOperand(*MI, SDSTName);
2096 if (!SDST) {
2097 for (const auto &MO : MI->implicit_operands()) {
2098 if (MO.isDef() && TRI->isSGPRClass(TRI->getPhysRegBaseClass(MO.getReg()))) {
2099 SDST = &MO;
2100 break;
2101 }
2102 }
2103 }
2104
2105 if (!SDST)
2106 return false;
2107
2108 const Register SDSTReg = SDST->getReg();
2109 auto IsHazardFn = [SDSTReg, TRI](const MachineInstr &I) {
2110 return SIInstrInfo::isSMRD(I) && I.readsRegister(SDSTReg, TRI);
2111 };
2112
2113 auto IsExpiredFn = [TII, IV](const MachineInstr &MI, int) {
2114 if (TII->isSALU(MI)) {
2115 switch (MI.getOpcode()) {
2116 case AMDGPU::S_SETVSKIP:
2117 case AMDGPU::S_VERSION:
2118 case AMDGPU::S_WAITCNT_VSCNT:
2119 case AMDGPU::S_WAITCNT_VMCNT:
2120 case AMDGPU::S_WAITCNT_EXPCNT:
2121 // These instructions cannot not mitigate the hazard.
2122 return false;
2123 case AMDGPU::S_WAITCNT_LGKMCNT:
2124 // Reducing lgkmcnt count to 0 always mitigates the hazard.
2125 return (MI.getOperand(1).getImm() == 0) &&
2126 (MI.getOperand(0).getReg() == AMDGPU::SGPR_NULL);
2127 case AMDGPU::S_WAITCNT: {
2128 const int64_t Imm = MI.getOperand(0).getImm();
2129 AMDGPU::Waitcnt Decoded =
2130 AMDGPU::decodeWaitcnt(IV, static_cast<unsigned>(Imm));
2131 // DsCnt corresponds to LGKMCnt here.
2132 return Decoded.get(AMDGPU::DS_CNT) == 0;
2133 }
2134 default:
2135 assert((!SIInstrInfo::isWaitcnt(MI.getOpcode()) ||
2136 MI.getOpcode() == AMDGPU::S_WAIT_IDLE) &&
2137 "unexpected wait count instruction");
2138 // SOPP instructions cannot mitigate the hazard.
2139 if (TII->isSOPP(MI))
2140 return false;
2141 // At this point the SALU can be assumed to mitigate the hazard
2142 // because either:
2143 // (a) it is independent of the at risk SMEM (breaking chain),
2144 // or
2145 // (b) it is dependent on the SMEM, in which case an appropriate
2146 // s_waitcnt lgkmcnt _must_ exist between it and the at risk
2147 // SMEM instruction.
2148 return true;
2149 }
2150 }
2151 return false;
2152 };
2153
2154 if (::getWaitStatesSince(IsHazardFn, MI, IsExpiredFn) ==
2155 std::numeric_limits<int>::max())
2156 return false;
2157
2158 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
2159 TII->get(AMDGPU::S_MOV_B32), AMDGPU::SGPR_NULL)
2160 .addImm(0);
2161 return true;
2162}
2163
2164bool GCNHazardRecognizer::fixVcmpxExecWARHazard(MachineInstr *MI) {
2165 if (!ST.hasVcmpxExecWARHazard())
2166 return false;
2167 assert(!ST.hasExtendedWaitCounts());
2168
2169 if (!SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true))
2170 return false;
2171
2172 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2173 if (!MI->modifiesRegister(AMDGPU::EXEC, TRI))
2174 return false;
2175
2176 auto IsHazardFn = [TRI](const MachineInstr &I) {
2177 if (SIInstrInfo::isVALU(I, /*AllowLDSDMA=*/true))
2178 return false;
2179 return I.readsRegister(AMDGPU::EXEC, TRI);
2180 };
2181
2182 const SIInstrInfo *TII = ST.getInstrInfo();
2183 auto IsExpiredFn = [TII, TRI](const MachineInstr &MI, int) {
2184 if (SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true)) {
2185 if (TII->getNamedOperand(MI, AMDGPU::OpName::sdst))
2186 return true;
2187 for (auto MO : MI.implicit_operands())
2188 if (MO.isDef() && TRI->isSGPRClass(TRI->getPhysRegBaseClass(MO.getReg())))
2189 return true;
2190 }
2191 if (MI.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2193 static_cast<unsigned>(MI.getOperand(0).getImm())) == 0)
2194 return true;
2195 return false;
2196 };
2197
2198 if (::getWaitStatesSince(IsHazardFn, MI, IsExpiredFn) ==
2199 std::numeric_limits<int>::max())
2200 return false;
2201
2202 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
2203 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
2205 return true;
2206}
2207
2209 const GCNSubtarget &ST) {
2210 if (!ST.hasLdsBranchVmemWARHazard())
2211 return false;
2212
2213 // Check if the necessary condition for the hazard is met: both LDS and VMEM
2214 // instructions need to appear in the same function.
2215 bool HasLds = false;
2216 bool HasVmem = false;
2217 for (auto &MBB : MF) {
2218 for (auto &MI : MBB) {
2220 HasVmem |= SIInstrInfo::isVMEM(MI);
2221 if (HasLds && HasVmem)
2222 return true;
2223 }
2224 }
2225 return false;
2226}
2227
2229 return I.getOpcode() == AMDGPU::S_WAITCNT_VSCNT &&
2230 I.getOperand(0).getReg() == AMDGPU::SGPR_NULL &&
2231 !I.getOperand(1).getImm();
2232}
2233
2234bool GCNHazardRecognizer::fixLdsBranchVmemWARHazard(MachineInstr *MI) {
2235 if (!RunLdsBranchVmemWARHazardFixup)
2236 return false;
2237
2238 assert(ST.hasLdsBranchVmemWARHazard());
2239 assert(!ST.hasExtendedWaitCounts());
2240
2241 auto IsHazardInst = [](const MachineInstr &MI) {
2243 return 1;
2245 return 2;
2246 return 0;
2247 };
2248
2249 auto InstType = IsHazardInst(*MI);
2250 if (!InstType)
2251 return false;
2252
2253 auto IsExpiredFn = [&IsHazardInst](const MachineInstr &I, int) {
2254 return IsHazardInst(I) || isStoreCountWaitZero(I);
2255 };
2256
2257 auto IsHazardFn = [InstType, &IsHazardInst](const MachineInstr &I) {
2258 if (!I.isBranch())
2259 return false;
2260
2261 auto IsHazardFn = [InstType, IsHazardInst](const MachineInstr &I) {
2262 auto InstType2 = IsHazardInst(I);
2263 return InstType2 && InstType != InstType2;
2264 };
2265
2266 auto IsExpiredFn = [InstType, &IsHazardInst](const MachineInstr &I, int) {
2267 auto InstType2 = IsHazardInst(I);
2268 if (InstType == InstType2)
2269 return true;
2270
2271 return isStoreCountWaitZero(I);
2272 };
2273
2274 return ::getWaitStatesSince(IsHazardFn, &I, IsExpiredFn) !=
2275 std::numeric_limits<int>::max();
2276 };
2277
2278 if (::getWaitStatesSince(IsHazardFn, MI, IsExpiredFn) ==
2279 std::numeric_limits<int>::max())
2280 return false;
2281
2282 const SIInstrInfo *TII = ST.getInstrInfo();
2283 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
2284 TII->get(AMDGPU::S_WAITCNT_VSCNT))
2285 .addReg(AMDGPU::SGPR_NULL, RegState::Undef)
2286 .addImm(0);
2287
2288 return true;
2289}
2290
2291bool GCNHazardRecognizer::fixLdsDirectVALUHazard(MachineInstr *MI) {
2293 return false;
2294
2295 const int NoHazardWaitStates = 15;
2296 const MachineOperand *VDST = TII.getNamedOperand(*MI, AMDGPU::OpName::vdst);
2297 const Register VDSTReg = VDST->getReg();
2298
2299 bool VisitedTrans = false;
2300 auto IsHazardFn = [this, VDSTReg, &VisitedTrans](const MachineInstr &I) {
2301 if (!SIInstrInfo::isVALU(I, /*AllowLDSDMA=*/true))
2302 return false;
2303 VisitedTrans = VisitedTrans || SIInstrInfo::isTRANS(I);
2304 // Cover both WAR and WAW
2305 return I.readsRegister(VDSTReg, &TRI) || I.modifiesRegister(VDSTReg, &TRI);
2306 };
2307 auto IsExpiredFn = [&](const MachineInstr &I, int WaitStates) {
2308 if (WaitStates >= NoHazardWaitStates)
2309 return true;
2310 // Instructions which cause va_vdst==0 expire hazard
2313 };
2314 auto GetWaitStatesFn = [](const MachineInstr &MI) {
2315 return SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true) ? 1 : 0;
2316 };
2317
2318 DenseSet<const MachineBasicBlock *> Visited;
2319 auto Count = ::getWaitStatesSince(IsHazardFn, MI->getParent(),
2320 std::next(MI->getReverseIterator()), 0,
2321 IsExpiredFn, Visited, GetWaitStatesFn);
2322
2323 // Transcendentals can execute in parallel to other VALUs.
2324 // This makes va_vdst count unusable with a mixture of VALU and TRANS.
2325 if (VisitedTrans)
2326 Count = 0;
2327
2328 MachineOperand *WaitVdstOp =
2329 TII.getNamedOperand(*MI, AMDGPU::OpName::waitvdst);
2330 WaitVdstOp->setImm(std::min(Count, NoHazardWaitStates));
2331
2332 return true;
2333}
2334
2335bool GCNHazardRecognizer::fixLdsDirectVMEMHazard(MachineInstr *MI) {
2337 return false;
2338
2339 const MachineOperand *VDST = TII.getNamedOperand(*MI, AMDGPU::OpName::vdst);
2340 const Register VDSTReg = VDST->getReg();
2341
2342 auto IsHazardFn = [this, VDSTReg](const MachineInstr &I) {
2344 return false;
2345 return I.readsRegister(VDSTReg, &TRI) || I.modifiesRegister(VDSTReg, &TRI);
2346 };
2347 bool LdsdirCanWait = ST.hasLdsWaitVMSRC();
2348 // TODO: On GFX12 the hazard should expire on S_WAIT_LOADCNT/SAMPLECNT/BVHCNT
2349 // according to the type of VMEM instruction.
2350 auto IsExpiredFn = [this, LdsdirCanWait](const MachineInstr &I, int) {
2351 return SIInstrInfo::isVALU(I, /*AllowLDSDMA=*/true) ||
2353 (I.getOpcode() == AMDGPU::S_WAITCNT && !I.getOperand(0).getImm()) ||
2354 (I.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2356 static_cast<unsigned>(I.getOperand(0).getImm())) == 0) ||
2357 (LdsdirCanWait && SIInstrInfo::isLDSDIR(I) &&
2358 !TII.getNamedOperand(I, AMDGPU::OpName::waitvsrc)->getImm());
2359 };
2360
2361 if (::getWaitStatesSince(IsHazardFn, MI, IsExpiredFn) ==
2362 std::numeric_limits<int>::max())
2363 return false;
2364
2365 if (LdsdirCanWait) {
2366 TII.getNamedOperand(*MI, AMDGPU::OpName::waitvsrc)->setImm(0);
2367 } else {
2368 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
2369 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
2371 }
2372
2373 return true;
2374}
2375
2376bool GCNHazardRecognizer::fixVALUPartialForwardingHazard(MachineInstr *MI) {
2377 if (!ST.hasVALUPartialForwardingHazard())
2378 return false;
2379 assert(!ST.hasExtendedWaitCounts());
2380
2381 if (!ST.isWave64() || !SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true))
2382 return false;
2383
2384 SmallSetVector<Register, 4> SrcVGPRs;
2385
2386 for (const MachineOperand &Use : MI->explicit_uses()) {
2387 if (Use.isReg() && TRI.isVGPR(MF.getRegInfo(), Use.getReg()))
2388 SrcVGPRs.insert(Use.getReg());
2389 }
2390
2391 // Only applies with >= 2 unique VGPR sources
2392 if (SrcVGPRs.size() <= 1)
2393 return false;
2394
2395 // Look for the following pattern:
2396 // Va <- VALU [PreExecPos]
2397 // intv1
2398 // Exec <- SALU [ExecPos]
2399 // intv2
2400 // Vb <- VALU [PostExecPos]
2401 // intv3
2402 // MI Va, Vb (WaitState = 0)
2403 //
2404 // Where:
2405 // intv1 + intv2 <= 2 VALUs
2406 // intv3 <= 4 VALUs
2407 //
2408 // If found, insert an appropriate S_WAITCNT_DEPCTR before MI.
2409
2410 const int Intv1plus2MaxVALUs = 2;
2411 const int Intv3MaxVALUs = 4;
2412 const int IntvMaxVALUs = 6;
2413 const int NoHazardVALUWaitStates = IntvMaxVALUs + 2;
2414
2415 struct StateType {
2416 SmallDenseMap<Register, int, 4> DefPos;
2417 int ExecPos = std::numeric_limits<int>::max();
2418 int VALUs = 0;
2419
2420 static unsigned getHashValue(const StateType &State) {
2421 hash_code H = hash_combine(State.ExecPos, State.VALUs);
2422 for (const auto &[Reg, Pos] : State.DefPos)
2423 H = hash_combine(H, Reg, Pos);
2424 return static_cast<unsigned>(H);
2425 }
2426 static bool isEqual(const StateType &LHS, const StateType &RHS) {
2427 return LHS.DefPos == RHS.DefPos && LHS.ExecPos == RHS.ExecPos &&
2428 LHS.VALUs == RHS.VALUs;
2429 }
2430 };
2431
2432 StateType State;
2433
2434 // This overloads expiry testing with all the hazard detection
2435 auto IsHazardFn = [&, this](StateType &State, const MachineInstr &I) {
2436 // Too many VALU states have passed
2437 if (State.VALUs > NoHazardVALUWaitStates)
2438 return HazardExpired;
2439
2440 // Instructions which cause va_vdst==0 expire hazard
2443 (I.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2445 static_cast<unsigned>(I.getOperand(0).getImm())) == 0))
2446 return HazardExpired;
2447
2448 // Track registers writes
2449 bool Changed = false;
2450 if (SIInstrInfo::isVALU(I, /*AllowLDSDMA=*/true)) {
2451 for (Register Src : SrcVGPRs) {
2452 if (!State.DefPos.count(Src) && I.modifiesRegister(Src, &TRI)) {
2453 State.DefPos[Src] = State.VALUs;
2454 Changed = true;
2455 }
2456 }
2457 } else if (SIInstrInfo::isSALU(I)) {
2458 if (State.ExecPos == std::numeric_limits<int>::max()) {
2459 if (!State.DefPos.empty() && I.modifiesRegister(AMDGPU::EXEC, &TRI)) {
2460 State.ExecPos = State.VALUs;
2461 Changed = true;
2462 }
2463 }
2464 }
2465
2466 // Early expiration: too many VALUs in intv3
2467 if (State.VALUs > Intv3MaxVALUs && State.DefPos.empty())
2468 return HazardExpired;
2469
2470 // Only evaluate state if something changed
2471 if (!Changed)
2472 return NoHazardFound;
2473
2474 // Determine positions of VALUs pre/post exec change
2475 if (State.ExecPos == std::numeric_limits<int>::max())
2476 return NoHazardFound;
2477
2478 int PreExecPos = std::numeric_limits<int>::max();
2479 int PostExecPos = std::numeric_limits<int>::max();
2480
2481 for (auto Entry : State.DefPos) {
2482 int DefVALUs = Entry.second;
2483 if (DefVALUs != std::numeric_limits<int>::max()) {
2484 if (DefVALUs >= State.ExecPos)
2485 PreExecPos = std::min(PreExecPos, DefVALUs);
2486 else
2487 PostExecPos = std::min(PostExecPos, DefVALUs);
2488 }
2489 }
2490
2491 // Need a VALUs post exec change
2492 if (PostExecPos == std::numeric_limits<int>::max())
2493 return NoHazardFound;
2494
2495 // Too many VALUs in intv3?
2496 int Intv3VALUs = PostExecPos;
2497 if (Intv3VALUs > Intv3MaxVALUs)
2498 return HazardExpired;
2499
2500 // Too many VALUs in intv2?
2501 int Intv2VALUs = (State.ExecPos - PostExecPos) - 1;
2502 if (Intv2VALUs > Intv1plus2MaxVALUs)
2503 return HazardExpired;
2504
2505 // Need a VALUs pre exec change
2506 if (PreExecPos == std::numeric_limits<int>::max())
2507 return NoHazardFound;
2508
2509 // Too many VALUs in intv1?
2510 int Intv1VALUs = PreExecPos - State.ExecPos;
2511 if (Intv1VALUs > Intv1plus2MaxVALUs)
2512 return HazardExpired;
2513
2514 // Too many VALUs in intv1 + intv2
2515 if (Intv1VALUs + Intv2VALUs > Intv1plus2MaxVALUs)
2516 return HazardExpired;
2517
2518 return HazardFound;
2519 };
2520 auto UpdateStateFn = [](StateType &State, const MachineInstr &MI) {
2521 if (SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true))
2522 State.VALUs += 1;
2523 };
2524
2525 if (!hasHazard<StateType>(State, IsHazardFn, UpdateStateFn, MI->getParent(),
2526 std::next(MI->getReverseIterator())))
2527 return false;
2528
2529 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
2530 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
2532
2533 return true;
2534}
2535
2536bool GCNHazardRecognizer::fixVALUTransUseHazard(MachineInstr *MI) {
2537 if (!ST.hasVALUTransUseHazard())
2538 return false;
2539 assert(!ST.hasExtendedWaitCounts());
2540
2541 if (!SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true))
2542 return false;
2543
2544 SmallSet<Register, 4> SrcVGPRs;
2545
2546 for (const MachineOperand &Use : MI->explicit_uses()) {
2547 if (Use.isReg() && TRI.isVGPR(MF.getRegInfo(), Use.getReg()))
2548 SrcVGPRs.insert(Use.getReg());
2549 }
2550
2551 // Look for the following pattern:
2552 // Va <- TRANS VALU
2553 // intv
2554 // MI Va (WaitState = 0)
2555 //
2556 // Where:
2557 // intv <= 5 VALUs / 1 TRANS
2558 //
2559 // If found, insert an appropriate S_WAITCNT_DEPCTR before MI.
2560
2561 const int IntvMaxVALUs = 5;
2562 const int IntvMaxTRANS = 1;
2563
2564 struct StateType {
2565 int VALUs = 0;
2566 int TRANS = 0;
2567
2568 static unsigned getHashValue(const StateType &State) {
2569 return static_cast<unsigned>(hash_combine(State.VALUs, State.TRANS));
2570 }
2571 static bool isEqual(const StateType &LHS, const StateType &RHS) {
2572 return LHS.VALUs == RHS.VALUs && LHS.TRANS == RHS.TRANS;
2573 }
2574 };
2575
2576 StateType State;
2577
2578 // This overloads expiry testing with all the hazard detection
2579 auto IsHazardFn = [&, this](StateType &State, const MachineInstr &I) {
2580 // Too many VALU states have passed
2581 if (State.VALUs > IntvMaxVALUs || State.TRANS > IntvMaxTRANS)
2582 return HazardExpired;
2583
2584 // Instructions which cause va_vdst==0 expire hazard
2587 (I.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2589 static_cast<unsigned>(I.getOperand(0).getImm())) == 0))
2590 return HazardExpired;
2591
2592 // Track registers writes
2593 if (SIInstrInfo::isTRANS(I)) {
2594 for (Register Src : SrcVGPRs) {
2595 if (I.modifiesRegister(Src, &TRI)) {
2596 return HazardFound;
2597 }
2598 }
2599 }
2600
2601 return NoHazardFound;
2602 };
2603 auto UpdateStateFn = [](StateType &State, const MachineInstr &MI) {
2604 if (SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true))
2605 State.VALUs += 1;
2607 State.TRANS += 1;
2608 };
2609
2610 if (!hasHazard<StateType>(State, IsHazardFn, UpdateStateFn, MI->getParent(),
2611 std::next(MI->getReverseIterator())))
2612 return false;
2613
2614 // Hazard is observed - insert a wait on va_dst counter to ensure hazard is
2615 // avoided.
2616 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
2617 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
2619
2620 return true;
2621}
2622
2623bool GCNHazardRecognizer::fixVALUTransCoexecutionHazards(MachineInstr *MI) {
2624 if (!ST.hasTransCoexecutionHazard() || // Coexecution disabled.
2625 !SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true) ||
2627 return false;
2628
2629 const SIInstrInfo *TII = ST.getInstrInfo();
2630 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2631
2632 auto IsTransHazardFn = [MI, TII, TRI](const MachineInstr &I) {
2633 if (!SIInstrInfo::isTRANS(I))
2634 return false;
2635
2636 // RAW: Trans(I) writes, VALU(MI) reads.
2637 Register TransDef = TII->getNamedOperand(I, AMDGPU::OpName::vdst)->getReg();
2638 for (const MachineOperand &ValuUse : MI->explicit_uses()) {
2639 if (ValuUse.isReg() && TRI->regsOverlap(TransDef, ValuUse.getReg()))
2640 return true;
2641 }
2642
2643 // WAR: Trans(I) reads, VALU(MI) writes. Use modifiesRegister for
2644 // multi-dest VALUs.
2645 for (const MachineOperand &TransUse : I.explicit_uses()) {
2646 if (TransUse.isReg() && MI->modifiesRegister(TransUse.getReg(), TRI))
2647 return true;
2648 }
2649
2650 return false;
2651 };
2652
2653 auto IsExpiredFn = [](const MachineInstr &I, int) {
2654 return SIInstrInfo::isVALU(I, /*AllowLDSDMA=*/true);
2655 };
2656
2657 const int HasVALU = std::numeric_limits<int>::max();
2658 if (::getWaitStatesSince(IsTransHazardFn, MI, IsExpiredFn) == HasVALU)
2659 return false;
2660
2661 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), TII->get(AMDGPU::V_NOP_e32));
2662 return true;
2663}
2664
2665bool GCNHazardRecognizer::fixWMMAHazards(MachineInstr *MI) {
2667 return false;
2668
2669 const SIInstrInfo *TII = ST.getInstrInfo();
2670 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2671
2672 auto IsHazardFn = [MI, TII, TRI, this](const MachineInstr &I) {
2674 return false;
2675
2676 // Src0(matrix A) or Src1(matrix B) of the current wmma instruction overlaps
2677 // with the dest(matrix D) of the previous wmma.
2678 const Register CurSrc0Reg =
2679 TII->getNamedOperand(*MI, AMDGPU::OpName::src0)->getReg();
2680 const Register CurSrc1Reg =
2681 TII->getNamedOperand(*MI, AMDGPU::OpName::src1)->getReg();
2682
2683 const Register PrevDstReg =
2684 TII->getNamedOperand(I, AMDGPU::OpName::vdst)->getReg();
2685
2686 if (TRI->regsOverlap(PrevDstReg, CurSrc0Reg) ||
2687 TRI->regsOverlap(PrevDstReg, CurSrc1Reg)) {
2688 return true;
2689 }
2690
2691 // GFX12+ allows overlap of matrix C with PrevDstReg (hardware will stall)
2692 // but Index can't overlap with PrevDstReg.
2693 if (AMDGPU::isGFX12Plus(ST)) {
2694 if (SIInstrInfo::isSWMMAC(*MI)) {
2695 const Register CurIndex =
2696 TII->getNamedOperand(*MI, AMDGPU::OpName::src2)->getReg();
2697 if (TRI->regsOverlap(PrevDstReg, CurIndex))
2698 return true;
2699 }
2700 return false;
2701 }
2702
2703 return false;
2704 };
2705
2706 auto IsExpiredFn = [](const MachineInstr &I, int) {
2707 return SIInstrInfo::isVALU(I, /*AllowLDSDMA=*/true);
2708 };
2709
2710 if (::getWaitStatesSince(IsHazardFn, MI, IsExpiredFn) ==
2711 std::numeric_limits<int>::max())
2712 return false;
2713
2714 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), TII->get(AMDGPU::V_NOP_e32));
2715
2716 return true;
2717}
2718
2720 return SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/false) &&
2722}
2723
2724// Classify XDL WMMA instructions into co-execution hazard categories
2725// (Refer to SPG 4.6.12.1), mainly based on instruction latency.
2726//
2727// Category 0: WMMA with Latency 8
2728// WMMA_*F16, WMMA_*BF16
2729// WMMA_*_16X16X128_{FP8,BF8}
2730// WMMA_*F8F6F4 if SRCA & SRCB are not both F4
2731//
2732// Category 1: WMMA Latency 16
2733// WMMA_IU8
2734//
2735// Category 2: SWMMAC with Latency 8
2736// SWMMAC_*F16, SWMMAC_*BF16,
2737// SWMMAC_*FP8FP8
2738// SWMMAC_*BF8FP8
2739// SWMMAC_*FP8BF8
2740// SWMMAC_*BF8BF8
2741//
2742// Category 3: SWMMAC with Latency 16
2743// SWMMAC_IU8
2744//
2745// Category 4: 16 Pass GFX1251 WMMA with latency 16
2746// V_WMMA_*_16X16X32_{F16,BF16}
2747// V_WMMA_{F32,F16}_16X16X64_{FP8,BF8}*
2748// V_WMMA_F32_16x16x128_F8F6F4 (F4 only)
2749// V_SWMMAC_*_16X16X64_{F16,BF16}
2750// V_SWMMAC_{F32,F16}_16X16X128_{FP8,BF8}*
2751//
2752// Category 5: 32 Pass GFX1251 WMMA with latency 32
2753// V_WMMA_F32_16x16x128_F8F6F4 (not all F4)
2754// V_WMMA_{F32,F16}_16X16X128_{FP8,BF8}*
2755// V_WMMA_F32_32X16X128_F4
2756// V_WMMA_I32_16X16X64_IU8
2757// V_WMMA_I32_16X16X64_IU8
2758//
2759// Category 6: gfx1250 WMMA with Latency 4 (one co-execution slot)
2760// WMMA_*_16X16X64_{FP8,BF8}
2761// WMMA_*F8F6F4 if SRCA & SRCB are both F4
2763 const SIInstrInfo *TII,
2764 const TargetSchedModel &SchedModel,
2765 const GCNSubtarget &ST) {
2766 assert(TII->isXDLWMMA(MI) && "must be xdl wmma");
2767 bool IsSWMMAC = SIInstrInfo::isSWMMAC(MI);
2768 bool IsLowestRateWMMA = ST.hasGFX125xLowestRateWMMA();
2769 unsigned Category = 0;
2770
2771 unsigned Latency = SchedModel.computeInstrLatency(&MI);
2772 switch (Latency) {
2773 case 4:
2774 // Dense 4-cycle WMMA (gfx1250 16x16x64 FP8/BF8 and f8f6f4 with both
2775 // inputs F4). One co-execution slot; there is no 4-cycle SWMMAC.
2776 assert(!IsSWMMAC && "no 4-cycle SWMMAC expected");
2777 Category = 6;
2778 break;
2779 case 8:
2780 Category = IsSWMMAC ? 2 : 0;
2781 break;
2782 case 16:
2783 Category = IsLowestRateWMMA ? 4 : (IsSWMMAC ? 3 : 1);
2784 break;
2785 case 32:
2786 assert(IsLowestRateWMMA && "latency 32 is not expected");
2787 Category = 5;
2788 break;
2789 default:
2790 llvm_unreachable("unexpected xdl wmma latency");
2791 } // end switch.
2792
2793 return Category;
2794}
2795
2796int GCNHazardRecognizer::checkWMMACoexecutionHazards(MachineInstr *MI) const {
2797 if (!ST.hasWMMACoexecutionHazards())
2798 return 0;
2799
2800 const SIInstrInfo *TII = ST.getInstrInfo();
2801 if (!TII->isXDLWMMA(*MI) && !isCoexecutableVALUInst(*MI))
2802 return 0;
2803
2804 // WaitStates here is the number of V_NOPs or unrelated VALU instructions must
2805 // be in between the first WMMA and the second instruction to cover the hazard
2806 // (WMMAWaitStates if the second is also a WMMA, VALUWaitStates if the second
2807 // is a VALU). Refer to SPG 4.6.12.1. "Requirements for WMMA data hazards" for
2808 // numbers, which depends on the category of the first WMMA.
2809 const int WMMAWaitStates[] = {5, 9, 3, 5, 9, 17, 2};
2810 const int VALUWaitStates[] = {4, 8, 2, 4, 8, 16, 1};
2811 const bool IsWMMA = TII->isXDLWMMA(*MI);
2812 const bool IsLowestRateWMMA = ST.hasGFX125xLowestRateWMMA();
2813 ArrayRef<int> RequiredWaitStates =
2814 IsWMMA ? ArrayRef<int>(WMMAWaitStates) : ArrayRef<int>(VALUWaitStates);
2815 const int MaxWaitStates =
2816 IsWMMA ? (IsLowestRateWMMA ? 17 : 9) : (IsLowestRateWMMA ? 16 : 8);
2817
2818 auto WindowFor = [=](const MachineInstr &I) -> std::optional<int> {
2819 if (!TII->isXDLWMMA(I))
2820 return std::nullopt;
2821 if (IsWMMA ? !hasWMMAToWMMARegOverlap(I, *MI)
2822 : !hasWMMAToVALURegOverlap(I, *MI))
2823 return std::nullopt;
2824 return RequiredWaitStates[getWMMAHazardInstInCategory(I, TII, TSchedModel,
2825 ST)];
2826 };
2827
2828 return getMaxVALUWindowDeficit(MaxWaitStates, WindowFor);
2829}
2830
2831bool GCNHazardRecognizer::hasWMMAToWMMARegOverlap(
2832 const MachineInstr &WMMA, const MachineInstr &MI) const {
2833 Register D0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::vdst)->getReg();
2834 Register A1 = TII.getNamedOperand(MI, AMDGPU::OpName::src0)->getReg();
2835 Register B1 = TII.getNamedOperand(MI, AMDGPU::OpName::src1)->getReg();
2836
2837 // WMMA0 writes (D0), WMMA1 reads (A1/B1/Idx1).
2838 if (TRI.regsOverlap(D0, A1) || TRI.regsOverlap(D0, B1))
2839 return true;
2840
2842 Register Idx1 = TII.getNamedOperand(MI, AMDGPU::OpName::src2)->getReg();
2843 if (TRI.regsOverlap(D0, Idx1))
2844 return true;
2845 }
2846 return false;
2847}
2848
2849bool GCNHazardRecognizer::hasWMMAToVALURegOverlap(
2850 const MachineInstr &WMMA, const MachineInstr &MI) const {
2851 // WMMA writes, VALU reads.
2852 Register D0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::vdst)->getReg();
2853 for (const MachineOperand &ValuUse : MI.explicit_uses()) {
2854 if (ValuUse.isReg() && TRI.regsOverlap(D0, ValuUse.getReg()))
2855 return true;
2856 }
2857
2858 // WMMA reads or writes, VALU writes.
2859 Register A0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::src0)->getReg();
2860 Register B0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::src1)->getReg();
2861 SmallVector<Register, 4> WMMARegs({D0, A0, B0});
2862
2863 const MachineOperand *Src2 = TII.getNamedOperand(WMMA, AMDGPU::OpName::src2);
2864 if (Src2->isReg())
2865 WMMARegs.push_back(Src2->getReg());
2866
2867 for (const MachineOperand &ValuDef : MI.defs()) {
2868 Register VDstReg = ValuDef.getReg();
2869 for (Register WMMAReg : WMMARegs) {
2870 if (TRI.regsOverlap(VDstReg, WMMAReg))
2871 return true;
2872 }
2873 }
2874 return false;
2875}
2876
2877bool GCNHazardRecognizer::isCoexecutionHazardFor(const MachineInstr &I,
2878 const MachineInstr &MI) const {
2879 // I is the potential WMMA hazard source, MI is the instruction being checked
2880 // for hazard.
2881 if (!TII.isXDLWMMA(I))
2882 return false;
2883
2884 // Dispatch based on MI type
2885 if (TII.isXDLWMMA(MI))
2886 return hasWMMAToWMMARegOverlap(I, MI);
2888 return hasWMMAToVALURegOverlap(I, MI);
2889
2890 return false;
2891}
2892
2893bool GCNHazardRecognizer::hasWMMAHazardInLoop(MachineLoop *L, MachineInstr *MI,
2894 bool IncludeSubloops) {
2895 // Scan loop for any WMMA that hazards MI.
2896 // TODO: Avoid full loop scan when WMMA is beyond VALU distance.
2897 for (MachineBasicBlock *MBB : L->getBlocks()) {
2898 if (!IncludeSubloops && MLI->getLoopFor(MBB) != L)
2899 continue;
2900 for (MachineInstr &I : *MBB) {
2901 if (&I == MI)
2902 continue;
2903 if (isCoexecutionHazardFor(I, *MI))
2904 return true;
2905 }
2906 }
2907 return false;
2908}
2909
2910bool GCNHazardRecognizer::tryHoistWMMAVnopsFromLoop(MachineInstr *MI,
2911 int WaitStatesNeeded) {
2912 if (!MLI)
2913 return false;
2914
2915 MachineLoop *L = MLI->getLoopFor(MI->getParent());
2916 if (!L) {
2917 ++NumWMMAHoistingBailed;
2918 return false;
2919 }
2920
2921 // If innermost loop has WMMA hazard, we can't hoist at all
2922 if (hasWMMAHazardInLoop(L, MI)) {
2923 ++NumWMMAHoistingBailed;
2924 return false;
2925 }
2926
2927 // Find outermost loop with no internal hazard
2928 MachineLoop *TargetLoop = L;
2929 while (MachineLoop *Parent = TargetLoop->getParentLoop()) {
2930 if (hasWMMAHazardInLoop(Parent, MI, false))
2931 break; // Parent has hazard in its own blocks, stop here
2932 TargetLoop = Parent; // Safe to hoist further out
2933 }
2934
2935 // Need valid preheader to insert V_NOPs
2936 MachineBasicBlock *Preheader = TargetLoop->getLoopPreheader();
2937 if (!Preheader) {
2938 ++NumWMMAHoistingBailed;
2939 return false;
2940 }
2941
2942 LLVM_DEBUG(dbgs() << "WMMA V_NOP Hoisting: Moving " << WaitStatesNeeded
2943 << " V_NOPs from loop to " << printMBBReference(*Preheader)
2944 << "\n");
2945
2946 emitVNops(*Preheader, Preheader->getFirstTerminator(), WaitStatesNeeded,
2947 /*IsHoisting=*/true);
2948 NumWMMANopsHoisted += WaitStatesNeeded;
2949 return true;
2950}
2951
2952bool GCNHazardRecognizer::fixWMMACoexecutionHazards(MachineInstr *MI) {
2953 int WaitStatesNeeded = checkWMMACoexecutionHazards(MI);
2954 if (WaitStatesNeeded <= 0)
2955 return false;
2956
2957 if (EnableWMMAVnopHoisting && tryHoistWMMAVnopsFromLoop(MI, WaitStatesNeeded))
2958 return true;
2959
2960 emitVNops(*MI->getParent(), MI->getIterator(), WaitStatesNeeded);
2961 return true;
2962}
2963
2964bool GCNHazardRecognizer::fixShift64HighRegBug(MachineInstr *MI) {
2965 if (!ST.hasShift64HighRegBug())
2966 return false;
2967 assert(!ST.hasExtendedWaitCounts());
2968
2969 switch (MI->getOpcode()) {
2970 default:
2971 return false;
2972 case AMDGPU::V_LSHLREV_B64_e64:
2973 case AMDGPU::V_LSHRREV_B64_e64:
2974 case AMDGPU::V_ASHRREV_I64_e64:
2975 break;
2976 }
2977
2978 MachineOperand *Amt = TII.getNamedOperand(*MI, AMDGPU::OpName::src0);
2979 if (!Amt->isReg())
2980 return false;
2981
2982 Register AmtReg = Amt->getReg();
2983 const MachineRegisterInfo &MRI = MF.getRegInfo();
2984 // Check if this is a last VGPR in the allocation block.
2985 if (!TRI.isVGPR(MRI, AmtReg) || ((AmtReg - AMDGPU::VGPR0) & 7) != 7)
2986 return false;
2987
2988 if (AmtReg != AMDGPU::VGPR255 && MRI.isPhysRegUsed(AmtReg + 1))
2989 return false;
2990
2991 assert(ST.needsAlignedVGPRs());
2992 static_assert(AMDGPU::VGPR0 + 1 == AMDGPU::VGPR1);
2993
2994 const DebugLoc &DL = MI->getDebugLoc();
2995 MachineBasicBlock *MBB = MI->getParent();
2996 MachineOperand *Src1 = TII.getNamedOperand(*MI, AMDGPU::OpName::src1);
2997
2998 // In:
2999 //
3000 // Dst = shiftrev64 Amt, Src1
3001 //
3002 // if Dst!=Src1 then avoid the bug with:
3003 //
3004 // Dst.sub0 = Amt
3005 // Dst = shift64 Dst.sub0, Src1
3006
3007 Register DstReg = MI->getOperand(0).getReg();
3008 if (!Src1->isReg() || Src1->getReg() != DstReg) {
3009 Register DstLo = TRI.getSubReg(DstReg, AMDGPU::sub0);
3010 runOnInstruction(
3011 BuildMI(*MBB, MI, DL, TII.get(AMDGPU::V_MOV_B32_e32), DstLo).add(*Amt));
3012 Amt->setReg(DstLo);
3013 Amt->setIsKill(true);
3014 return true;
3015 }
3016
3017 bool Overlapped = MI->modifiesRegister(AmtReg, &TRI);
3018 Register NewReg;
3019 for (MCRegister Reg : Overlapped ? AMDGPU::VReg_64_Align2RegClass
3020 : AMDGPU::VGPR_32RegClass) {
3021 if (!MI->modifiesRegister(Reg, &TRI) && !MI->readsRegister(Reg, &TRI)) {
3022 NewReg = Reg;
3023 break;
3024 }
3025 }
3026
3027 Register NewAmt = Overlapped ? (Register)TRI.getSubReg(NewReg, AMDGPU::sub1)
3028 : NewReg;
3029 Register NewAmtLo;
3030
3031 if (Overlapped)
3032 NewAmtLo = TRI.getSubReg(NewReg, AMDGPU::sub0);
3033
3034 // Insert a full wait count because found register might be pending a wait.
3035 BuildMI(*MBB, MI, DL, TII.get(AMDGPU::S_WAITCNT))
3036 .addImm(0);
3037
3038 // Insert V_SWAP_B32 instruction(s) and run hazard recognizer on them.
3039 if (Overlapped)
3040 runOnInstruction(
3041 BuildMI(*MBB, MI, DL, TII.get(AMDGPU::V_SWAP_B32), NewAmtLo)
3042 .addDef(AmtReg - 1)
3043 .addReg(AmtReg - 1, RegState::Undef)
3044 .addReg(NewAmtLo, RegState::Undef));
3045 runOnInstruction(BuildMI(*MBB, MI, DL, TII.get(AMDGPU::V_SWAP_B32), NewAmt)
3046 .addDef(AmtReg)
3047 .addReg(AmtReg, RegState::Undef)
3048 .addReg(NewAmt, RegState::Undef));
3049
3050 // Instructions emitted after the current instruction will be processed by the
3051 // parent loop of the hazard recognizer in a natural way.
3052 BuildMI(*MBB, std::next(MI->getIterator()), DL, TII.get(AMDGPU::V_SWAP_B32),
3053 AmtReg)
3054 .addDef(NewAmt)
3055 .addReg(NewAmt)
3056 .addReg(AmtReg);
3057 if (Overlapped)
3058 BuildMI(*MBB, std::next(MI->getIterator()), DL, TII.get(AMDGPU::V_SWAP_B32),
3059 AmtReg - 1)
3060 .addDef(NewAmtLo)
3061 .addReg(NewAmtLo)
3062 .addReg(AmtReg - 1);
3063
3064 // Re-running hazard recognizer on the modified instruction is not necessary,
3065 // inserted V_SWAP_B32 has already both read and write new registers so
3066 // hazards related to these register has already been handled.
3067 Amt->setReg(NewAmt);
3068 Amt->setIsKill(false);
3069 // We do not update liveness, so verifier may see it as undef.
3070 Amt->setIsUndef();
3071 if (Overlapped) {
3072 MI->getOperand(0).setReg(NewReg);
3073 Src1->setReg(NewReg);
3074 Src1->setIsKill(false);
3075 Src1->setIsUndef();
3076 }
3077
3078 return true;
3079}
3080
3081// Handle GFX950 v_pk_{add,mul,fma}_f32 invalid op_sels
3082// 1. Fix: opsel[1:0]==2’b10 : Packed ADD_F32/MUL_F32
3083// 2. Fail: opsel[2:1]==2'b01/2'b10/2'b11 : Packed FMA_F32
3084bool GCNHazardRecognizer::fixPkF32InvalidOpSel(MachineInstr *MI) {
3085 if (!ST.hasPkF32InvalidOpSel())
3086 return false;
3087
3088 switch (MI->getOpcode()) {
3089 default:
3090 return false;
3091 case AMDGPU::V_PK_ADD_F32:
3092 case AMDGPU::V_PK_MUL_F32:
3093 case AMDGPU::V_PK_FMA_F32:
3094 break;
3095 }
3096
3097 const MachineOperand *Src0Mods =
3098 TII.getNamedOperand(*MI, AMDGPU::OpName::src0_modifiers);
3099 const MachineOperand *Src1Mods =
3100 TII.getNamedOperand(*MI, AMDGPU::OpName::src1_modifiers);
3101 if (!Src0Mods || !Src1Mods)
3102 return false;
3103
3104 if (MI->getOpcode() != AMDGPU::V_PK_FMA_F32) {
3105 if (!(Src0Mods->getImm() & SISrcMods::OP_SEL_0) &&
3106 (Src1Mods->getImm() & SISrcMods::OP_SEL_0)) {
3107 if (!TII.commuteInstruction(*MI)) {
3109 "cannot swap the GFX950 v_pk_add/mul_f32 src0 and src1: " +
3110 Twine(TII.getName(MI->getOpcode())));
3111 }
3112 return true;
3113 }
3114 return false;
3115 }
3116
3117 // Safety net: v_pk_fma_f32 invalid opsels are expected to already
3118 // be prevented earlier, so just fail loudly if it is ever seen here
3119 // instead of silently miscompiling, as a safeguard against future changes.
3120 if (!TII.isLegalPkFMAF32OpSel(*MI)) {
3121 reportFatalInternalError("GFX950 v_pk_fma_f32 has an invalid op_sel that "
3122 "should have been legalized earlier in the "
3123 "pipeline");
3124 }
3125
3126 return false;
3127}
3128
3129int GCNHazardRecognizer::checkNSAtoVMEMHazard(MachineInstr *MI) const {
3130 int NSAtoVMEMWaitStates = 1;
3131
3132 if (!ST.hasNSAtoVMEMBug())
3133 return 0;
3134
3136 return 0;
3137
3138 const SIInstrInfo *TII = ST.getInstrInfo();
3139 const auto *Offset = TII->getNamedOperand(*MI, AMDGPU::OpName::offset);
3140 if (!Offset || (Offset->getImm() & 6) == 0)
3141 return 0;
3142
3143 auto IsHazardFn = [TII](const MachineInstr &I) {
3144 if (!SIInstrInfo::isMIMG(I))
3145 return false;
3146 const AMDGPU::MIMGInfo *Info = AMDGPU::getMIMGInfo(I.getOpcode());
3147 return Info->MIMGEncoding == AMDGPU::MIMGEncGfx10NSA &&
3148 TII->getInstSizeInBytes(I) >= 16;
3149 };
3150
3151 return NSAtoVMEMWaitStates - getWaitStatesSince(IsHazardFn, 1);
3152}
3153
3154int GCNHazardRecognizer::checkFPAtomicToDenormModeHazard(
3155 MachineInstr *MI) const {
3156 int FPAtomicToDenormModeWaitStates = 3;
3157
3158 if (!ST.hasFPAtomicToDenormModeHazard())
3159 return 0;
3160 assert(!ST.hasExtendedWaitCounts());
3161
3162 if (MI->getOpcode() != AMDGPU::S_DENORM_MODE)
3163 return 0;
3164
3165 auto IsHazardFn = [](const MachineInstr &I) {
3166 if (!SIInstrInfo::isVMEM(I))
3167 return false;
3168 return SIInstrInfo::isFPAtomic(I);
3169 };
3170
3171 auto IsExpiredFn = [](const MachineInstr &MI, int WaitStates) {
3172 if (WaitStates >= 3 || SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true))
3173 return true;
3174
3175 return SIInstrInfo::isWaitcnt(MI.getOpcode());
3176 };
3177
3178 return FPAtomicToDenormModeWaitStates -
3179 ::getWaitStatesSince(IsHazardFn, MI, IsExpiredFn);
3180}
3181
3182int GCNHazardRecognizer::checkMAIHazards(MachineInstr *MI) const {
3184
3185 return ST.hasGFX90AInsts() ? checkMAIHazards90A(MI) : checkMAIHazards908(MI);
3186}
3187
3188int GCNHazardRecognizer::checkMFMAPadding(MachineInstr *MI) const {
3189 // Early exit if no padding is requested.
3190 if (MFMAPaddingRatio == 0)
3191 return 0;
3192
3193 const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
3194 if (!SIInstrInfo::isMFMA(*MI) || MFI->getOccupancy() < 2)
3195 return 0;
3196
3197 int NeighborMFMALatency = 0;
3198 auto IsNeighboringMFMA = [&NeighborMFMALatency,
3199 this](const MachineInstr &MI) {
3200 if (!SIInstrInfo::isMFMA(MI))
3201 return false;
3202
3203 NeighborMFMALatency = this->getMFMAPipelineWaitStates(MI);
3204 return true;
3205 };
3206
3207 const int MaxMFMAPipelineWaitStates = 16;
3208 int WaitStatesSinceNeighborMFMA =
3209 getWaitStatesSince(IsNeighboringMFMA, MaxMFMAPipelineWaitStates);
3210
3211 int NeighborMFMAPaddingNeeded =
3212 (NeighborMFMALatency * MFMAPaddingRatio / 100) -
3213 WaitStatesSinceNeighborMFMA;
3214
3215 return std::max(0, NeighborMFMAPaddingNeeded);
3216}
3217
3218int GCNHazardRecognizer::checkMAIHazards908(MachineInstr *MI) const {
3219 int WaitStatesNeeded = 0;
3220 unsigned Opc = MI->getOpcode();
3221
3222 auto IsVALUFn = [](const MachineInstr &MI) {
3223 return SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true) || MI.isInlineAsm();
3224 };
3225
3226 if (Opc != AMDGPU::V_ACCVGPR_READ_B32_e64) { // MFMA or v_accvgpr_write
3227 const int LegacyVALUWritesVGPRWaitStates = 2;
3228 const int VALUWritesExecWaitStates = 4;
3229 const int MaxWaitStates = 4;
3230
3231 int WaitStatesNeededForUse = VALUWritesExecWaitStates -
3232 getWaitStatesSinceDef(AMDGPU::EXEC, IsVALUFn, MaxWaitStates);
3233 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3234
3235 if (WaitStatesNeeded < MaxWaitStates) {
3236 for (const MachineOperand &Use : MI->explicit_uses()) {
3237 const int MaxWaitStates = 2;
3238
3239 if (!Use.isReg() || !TRI.isVGPR(MF.getRegInfo(), Use.getReg()))
3240 continue;
3241
3242 int WaitStatesNeededForUse = LegacyVALUWritesVGPRWaitStates -
3243 getWaitStatesSinceDef(Use.getReg(), IsVALUFn, MaxWaitStates);
3244 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3245
3246 if (WaitStatesNeeded == MaxWaitStates)
3247 break;
3248 }
3249 }
3250 }
3251
3252 for (const MachineOperand &Op : MI->explicit_operands()) {
3253 if (!Op.isReg() || !TRI.isAGPR(MF.getRegInfo(), Op.getReg()))
3254 continue;
3255
3256 if (Op.isDef() && Opc != AMDGPU::V_ACCVGPR_WRITE_B32_e64)
3257 continue;
3258
3259 const int MFMAWritesAGPROverlappedSrcABWaitStates = 4;
3260 const int MFMAWritesAGPROverlappedSrcCWaitStates = 2;
3261 const int MFMA4x4WritesAGPRAccVgprReadWaitStates = 4;
3262 const int MFMA16x16WritesAGPRAccVgprReadWaitStates = 10;
3263 const int MFMA32x32WritesAGPRAccVgprReadWaitStates = 18;
3264 const int MFMA4x4WritesAGPRAccVgprWriteWaitStates = 1;
3265 const int MFMA16x16WritesAGPRAccVgprWriteWaitStates = 7;
3266 const int MFMA32x32WritesAGPRAccVgprWriteWaitStates = 15;
3267 const int MaxWaitStates = 18;
3268 Register Reg = Op.getReg();
3269 unsigned HazardDefLatency = 0;
3270
3271 auto IsOverlappedMFMAFn = [Reg, &HazardDefLatency,
3272 this](const MachineInstr &MI) {
3273 if (!SIInstrInfo::isMFMA(MI))
3274 return false;
3275 Register DstReg = MI.getOperand(0).getReg();
3276 if (DstReg == Reg)
3277 return false;
3278 HazardDefLatency =
3279 std::max(HazardDefLatency, TSchedModel.computeInstrLatency(&MI));
3280 return TRI.regsOverlap(DstReg, Reg);
3281 };
3282
3283 int WaitStatesSinceDef = getWaitStatesSinceDef(Reg, IsOverlappedMFMAFn,
3284 MaxWaitStates);
3285 int NeedWaitStates = MFMAWritesAGPROverlappedSrcABWaitStates;
3286 int SrcCIdx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src2);
3287 int OpNo = Op.getOperandNo();
3288 if (OpNo == SrcCIdx) {
3289 NeedWaitStates = MFMAWritesAGPROverlappedSrcCWaitStates;
3290 } else if (Opc == AMDGPU::V_ACCVGPR_READ_B32_e64) {
3291 switch (HazardDefLatency) {
3292 case 2: NeedWaitStates = MFMA4x4WritesAGPRAccVgprReadWaitStates;
3293 break;
3294 case 8: NeedWaitStates = MFMA16x16WritesAGPRAccVgprReadWaitStates;
3295 break;
3296 case 16: [[fallthrough]];
3297 default: NeedWaitStates = MFMA32x32WritesAGPRAccVgprReadWaitStates;
3298 break;
3299 }
3300 } else if (Opc == AMDGPU::V_ACCVGPR_WRITE_B32_e64) {
3301 switch (HazardDefLatency) {
3302 case 2: NeedWaitStates = MFMA4x4WritesAGPRAccVgprWriteWaitStates;
3303 break;
3304 case 8: NeedWaitStates = MFMA16x16WritesAGPRAccVgprWriteWaitStates;
3305 break;
3306 case 16: [[fallthrough]];
3307 default: NeedWaitStates = MFMA32x32WritesAGPRAccVgprWriteWaitStates;
3308 break;
3309 }
3310 }
3311
3312 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceDef;
3313 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3314
3315 if (WaitStatesNeeded == MaxWaitStates)
3316 return WaitStatesNeeded; // Early exit.
3317
3318 auto IsAccVgprWriteFn = [Reg, this](const MachineInstr &MI) {
3319 if (MI.getOpcode() != AMDGPU::V_ACCVGPR_WRITE_B32_e64)
3320 return false;
3321 Register DstReg = MI.getOperand(0).getReg();
3322 return TRI.regsOverlap(Reg, DstReg);
3323 };
3324
3325 const int AccVGPRWriteMFMAReadSrcCWaitStates = 1;
3326 const int AccVGPRWriteMFMAReadSrcABWaitStates = 3;
3327 const int AccVGPRWriteAccVgprReadWaitStates = 3;
3328 NeedWaitStates = AccVGPRWriteMFMAReadSrcABWaitStates;
3329 if (OpNo == SrcCIdx)
3330 NeedWaitStates = AccVGPRWriteMFMAReadSrcCWaitStates;
3331 else if (Opc == AMDGPU::V_ACCVGPR_READ_B32_e64)
3332 NeedWaitStates = AccVGPRWriteAccVgprReadWaitStates;
3333
3334 WaitStatesNeededForUse = NeedWaitStates -
3335 getWaitStatesSinceDef(Reg, IsAccVgprWriteFn, MaxWaitStates);
3336 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3337
3338 if (WaitStatesNeeded == MaxWaitStates)
3339 return WaitStatesNeeded; // Early exit.
3340 }
3341
3342 if (Opc == AMDGPU::V_ACCVGPR_WRITE_B32_e64) {
3343 const int MFMA4x4ReadSrcCAccVgprWriteWaitStates = 0;
3344 const int MFMA16x16ReadSrcCAccVgprWriteWaitStates = 5;
3345 const int MFMA32x32ReadSrcCAccVgprWriteWaitStates = 13;
3346 const int MaxWaitStates = 13;
3347 Register DstReg = MI->getOperand(0).getReg();
3348 unsigned HazardDefLatency = 0;
3349
3350 auto IsSrcCMFMAFn = [DstReg, &HazardDefLatency,
3351 this](const MachineInstr &MI) {
3352 if (!SIInstrInfo::isMFMA(MI))
3353 return false;
3354 Register Reg = TII.getNamedOperand(MI, AMDGPU::OpName::src2)->getReg();
3355 HazardDefLatency =
3356 std::max(HazardDefLatency, TSchedModel.computeInstrLatency(&MI));
3357 return TRI.regsOverlap(Reg, DstReg);
3358 };
3359
3360 int WaitStatesSince = getWaitStatesSince(IsSrcCMFMAFn, MaxWaitStates);
3361 int NeedWaitStates;
3362 switch (HazardDefLatency) {
3363 case 2: NeedWaitStates = MFMA4x4ReadSrcCAccVgprWriteWaitStates;
3364 break;
3365 case 8: NeedWaitStates = MFMA16x16ReadSrcCAccVgprWriteWaitStates;
3366 break;
3367 case 16: [[fallthrough]];
3368 default: NeedWaitStates = MFMA32x32ReadSrcCAccVgprWriteWaitStates;
3369 break;
3370 }
3371
3372 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSince;
3373 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3374 }
3375
3376 // Pad neighboring MFMA with noops for better inter-wave performance.
3377 WaitStatesNeeded = std::max(WaitStatesNeeded, checkMFMAPadding(MI));
3378
3379 return WaitStatesNeeded;
3380}
3381
3382/// One MFMA can be written with up to four opcodes that differ only in how vdst
3383/// and src2 are encoded: both are either AGPRs or VGPRs, and the mac form ties
3384/// vdst to src2 instead of taking them as separate operands. \returns the AGPR,
3385/// non-mac opcode, so that every form of the same MFMA maps to one value.
3386static unsigned getMFMANonMacAGPRFormOp(unsigned Opc) {
3387 if (int NonMacOp = AMDGPU::getMFMAEarlyClobberOp(Opc); NonMacOp != -1)
3388 Opc = NonMacOp;
3389 if (int AGPROp = AMDGPU::getAGPRFormOp(Opc); AGPROp != -1)
3390 Opc = AGPROp;
3391 return Opc;
3392}
3393
3394/// \returns true if \p Opc0 and \p Opc1 are the same MFMA, ignoring the mac
3395/// form and whether vdst/src2 are AGPRs or VGPRs.
3396static bool isSameMFMA(unsigned Opc0, unsigned Opc1) {
3398}
3399
3400static int
3402 bool IsGFX950) {
3403 // xdl def cycles | gfx940 | gfx950
3404 // 2 pass | 3 4
3405 // 4 pass | 5 6
3406 // 8 pass | 9 10
3407 // 16 pass | 17 18
3408 return NumPasses + 1 + IsGFX950;
3409}
3410
3411static int
3413 bool IsGFX950) {
3414 // xdl def cycles | gfx940 | gfx950
3415 // 2 pass | 3 3
3416 // 4 pass | 5 6
3417 // 8 pass | 9 10
3418 // 16 pass | 17 18
3419 return NumPasses + 1 + (NumPasses != 2 && IsGFX950);
3420}
3421
3422static int
3424 // 2 pass -> 2
3425 // 4 pass -> 4
3426 // 8 pass -> 8
3427 // 16 pass -> 16
3428 return NumPasses;
3429}
3430
3431static int
3433 // 2 pass -> 4
3434 // 4 pass -> 6
3435 // 8 pass -> 10
3436 // 16 pass -> 18
3437 return NumPasses + 2;
3438}
3439
3441 bool IsGFX950) {
3442 // xdl def cycles | gfx942 | gfx950
3443 // 2 pass | 5 5
3444 // 4 pass | 7 8
3445 // 8 pass | 11 12
3446 // 16 pass | 19 20
3447 return NumPasses + 3 + (NumPasses != 2 && IsGFX950);
3448}
3449
3450int GCNHazardRecognizer::getMFMAOverlappedSrcCWaitStates(
3451 const MachineInstr *Reader, const MachineInstr *Writer) const {
3452 constexpr int SMFMA4x4WritesVGPROverlappedSMFMASrcCWaitStates = 2;
3453 constexpr int SMFMA16x16WritesVGPROverlappedSMFMASrcCWaitStates = 8;
3454 constexpr int SMFMA32x32WritesVGPROverlappedSMFMASrcCWaitStates = 16;
3455 constexpr int SMFMA4x4WritesVGPROverlappedDMFMASrcCWaitStates = 3;
3456 constexpr int SMFMA16x16WritesVGPROverlappedDMFMASrcCWaitStates = 9;
3457 constexpr int SMFMA32x32WritesVGPROverlappedDMFMASrcCWaitStates = 17;
3458 constexpr int DMFMA16x16WritesVGPROverlappedSrcCWaitStates = 9;
3459 constexpr int GFX950_DMFMA16x16WritesVGPROverlappedSrcCWaitStates = 17;
3460 constexpr int DMFMA4x4WritesVGPROverlappedSrcCWaitStates = 4;
3461
3462 // An XDL read of a non-XDL result needs no wait states. DGEMM is never XDL,
3463 // so this also covers the f64 writers handled below.
3464 if (TII.isXDL(*Reader) && !TII.isXDL(*Writer))
3465 return 0;
3466
3467 switch (Writer->getOpcode()) {
3468 case AMDGPU::V_MFMA_F64_16X16X4F64_e64:
3469 case AMDGPU::V_MFMA_F64_16X16X4F64_vgprcd_e64:
3470 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_e64:
3471 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_vgprcd_e64:
3472 return ST.hasGFX950Insts()
3473 ? GFX950_DMFMA16x16WritesVGPROverlappedSrcCWaitStates
3474 : DMFMA16x16WritesVGPROverlappedSrcCWaitStates;
3475 case AMDGPU::V_MFMA_F64_4X4X4F64_e64:
3476 case AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64:
3477 return DMFMA4x4WritesVGPROverlappedSrcCWaitStates;
3478 default:
3479 break;
3480 }
3481
3482 int NumPasses = TSchedModel.computeInstrLatency(Writer);
3483 if (ST.hasGFX940Insts()) {
3484 if (!TII.isXDL(*Writer))
3486 NumPasses);
3487 return TII.isXDL(*Reader)
3489 NumPasses, ST.hasGFX950Insts())
3491 NumPasses, ST.hasGFX950Insts());
3492 }
3493
3494 bool IsDGEMM = SIInstrInfo::isDGEMM(Reader->getOpcode());
3495 switch (NumPasses) {
3496 case 2:
3497 return IsDGEMM ? SMFMA4x4WritesVGPROverlappedDMFMASrcCWaitStates
3498 : SMFMA4x4WritesVGPROverlappedSMFMASrcCWaitStates;
3499 case 8:
3500 return IsDGEMM ? SMFMA16x16WritesVGPROverlappedDMFMASrcCWaitStates
3501 : SMFMA16x16WritesVGPROverlappedSMFMASrcCWaitStates;
3502 case 16:
3503 return IsDGEMM ? SMFMA32x32WritesVGPROverlappedDMFMASrcCWaitStates
3504 : SMFMA32x32WritesVGPROverlappedSMFMASrcCWaitStates;
3505 default:
3506 llvm_unreachable("unexpected number of passes");
3507 }
3508}
3509
3510int GCNHazardRecognizer::getMFMAReadWaitStates(const MachineInstr &Consumer,
3511 const MachineInstr &Producer,
3512 Register Reg,
3513 bool IsSrcC) const {
3514 unsigned Opc = Consumer.getOpcode();
3515 const int SMFMA4x4WritesVGPROverlappedSrcABWaitStates = 5;
3516 const int SMFMA16x16WritesVGPROverlappedSrcABWaitStates = 11;
3517 const int SMFMA32x32WritesVGPROverlappedSrcABWaitStates = 19;
3518 const int DMFMA4x4WritesVGPROverlappedMFMASrcABWaitStates = 6;
3519 const int DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates = 11;
3520 const int GFX950_DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates = 19;
3521 const int DMFMA4x4WritesVGPRFullSrcCWaitStates = 4;
3522 const int GFX940_SMFMA4x4WritesVGPRFullSrcCWaitStates = 2;
3523
3524 bool FullReg = Producer.getOperand(0).getReg() == Reg;
3525 unsigned Opc1 = Producer.getOpcode();
3526 int NeedWaitStates = 0;
3527 if (IsSrcC) {
3528 if (!SIInstrInfo::isDGEMM(Opc) &&
3529 (!ST.hasGFX940Insts() && SIInstrInfo::isDGEMM(Opc1))) {
3530 NeedWaitStates = 0;
3531 } else if (FullReg) {
3532 if ((Opc == AMDGPU::V_MFMA_F64_4X4X4F64_e64 ||
3533 Opc == AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64) &&
3534 (Opc1 == AMDGPU::V_MFMA_F64_4X4X4F64_e64 ||
3535 Opc1 == AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64))
3536 NeedWaitStates = DMFMA4x4WritesVGPRFullSrcCWaitStates;
3537 else if (ST.hasGFX940Insts() &&
3538 TSchedModel.computeInstrLatency(&Producer) == 2)
3539 NeedWaitStates = GFX940_SMFMA4x4WritesVGPRFullSrcCWaitStates;
3540
3541 // The accumulator forwarding path that allows zero wait states is only
3542 // available while the chain stays on a single MFMA. Two different MFMAs
3543 // sharing an accumulator need the wait states of a partial overlap.
3544 if (ST.hasGFX940Insts() && !isSameMFMA(Opc, Opc1)) {
3545 NeedWaitStates =
3546 std::max(NeedWaitStates,
3547 getMFMAOverlappedSrcCWaitStates(&Consumer, &Producer));
3548 }
3549 } else {
3550 NeedWaitStates = getMFMAOverlappedSrcCWaitStates(&Consumer, &Producer);
3551 }
3552 } else {
3553 switch (Opc1) {
3554 case AMDGPU::V_MFMA_F64_16X16X4F64_e64:
3555 case AMDGPU::V_MFMA_F64_16X16X4F64_vgprcd_e64:
3556 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_e64:
3557 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_vgprcd_e64:
3558 NeedWaitStates =
3559 ST.hasGFX950Insts()
3560 ? GFX950_DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates
3561 : DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates;
3562 break;
3563 case AMDGPU::V_MFMA_F64_4X4X4F64_e64:
3564 case AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64:
3565 NeedWaitStates = DMFMA4x4WritesVGPROverlappedMFMASrcABWaitStates;
3566 break;
3567 default:
3568 int NumPasses = TSchedModel.computeInstrLatency(&Producer);
3569
3570 if (ST.hasGFX940Insts()) {
3571 NeedWaitStates =
3572 TII.isXDL(Producer)
3574 NumPasses, ST.hasGFX950Insts())
3576 NumPasses);
3577 break;
3578 }
3579
3580 switch (NumPasses) {
3581 case 2:
3582 NeedWaitStates = SMFMA4x4WritesVGPROverlappedSrcABWaitStates;
3583 break;
3584 case 4:
3585 llvm_unreachable("unexpected number of passes for mfma");
3586 case 8:
3587 NeedWaitStates = SMFMA16x16WritesVGPROverlappedSrcABWaitStates;
3588 break;
3589 case 16:
3590 default:
3591 NeedWaitStates = SMFMA32x32WritesVGPROverlappedSrcABWaitStates;
3592 }
3593 }
3594 }
3595 return NeedWaitStates;
3596}
3597
3598int GCNHazardRecognizer::checkMAIHazards90A(MachineInstr *MI) const {
3599 int WaitStatesNeeded = 0;
3600 unsigned Opc = MI->getOpcode();
3601
3602 auto IsLegacyVALUFn = [](const MachineInstr &MI) {
3603 return SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true) &&
3605 };
3606
3607 auto IsLegacyVALUNotDotFn = [](const MachineInstr &MI) {
3608 return SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true) &&
3610 };
3611
3612 if (!SIInstrInfo::isMFMA(*MI))
3613 return WaitStatesNeeded;
3614
3615 const int VALUWritesExecWaitStates = 4;
3616 int WaitStatesNeededForUse = VALUWritesExecWaitStates -
3617 getWaitStatesSinceDef(AMDGPU::EXEC, IsLegacyVALUFn,
3618 VALUWritesExecWaitStates);
3619 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3620
3621 int SrcCIdx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src2);
3622
3623 // Loop for both DGEMM and S/HGEMM 2nd instruction.
3624 for (const MachineOperand &Use : MI->explicit_uses()) {
3625 const int LegacyVALUNotDotWritesVGPRWaitStates = 2;
3626 const int MaxWaitStates =
3628 16, ST.hasGFX950Insts());
3629
3630 if (!Use.isReg())
3631 continue;
3632 Register Reg = Use.getReg();
3633
3634 WaitStatesNeededForUse = LegacyVALUNotDotWritesVGPRWaitStates -
3635 getWaitStatesSinceDef(Reg, IsLegacyVALUNotDotFn, MaxWaitStates);
3636 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3637
3638 int OpNo = Use.getOperandNo();
3639 WaitStatesNeeded = std::max(
3640 WaitStatesNeeded,
3641 getMaxWindowDeficit(
3642 MaxWaitStates, [&](const MachineInstr &P) -> std::optional<int> {
3643 if (!SIInstrInfo::isMFMA(P) ||
3644 !TRI.regsOverlap(P.getOperand(0).getReg(), Reg))
3645 return std::nullopt;
3646 return getMFMAReadWaitStates(*MI, P, Reg, OpNo == SrcCIdx);
3647 }));
3648
3649 if (WaitStatesNeeded == MaxWaitStates)
3650 break;
3651 }
3652
3653 // Pad neighboring MFMA with noops for better inter-wave performance.
3654 WaitStatesNeeded = std::max(WaitStatesNeeded, checkMFMAPadding(MI));
3655
3656 return WaitStatesNeeded;
3657}
3658
3659int GCNHazardRecognizer::checkMAILdStHazards(MachineInstr *MI) const {
3660 // On gfx90a+ relevant hazards are checked in checkMAIVALUHazards()
3661 if (!ST.hasMAIInsts() || ST.hasGFX90AInsts())
3662 return 0;
3663
3664 int WaitStatesNeeded = 0;
3665
3666 auto IsAccVgprReadFn = [](const MachineInstr &MI) {
3667 return MI.getOpcode() == AMDGPU::V_ACCVGPR_READ_B32_e64;
3668 };
3669
3670 for (const MachineOperand &Op : MI->explicit_uses()) {
3671 if (!Op.isReg() || !TRI.isVGPR(MF.getRegInfo(), Op.getReg()))
3672 continue;
3673
3674 Register Reg = Op.getReg();
3675
3676 const int AccVgprReadLdStWaitStates = 2;
3677 const int VALUWriteAccVgprRdWrLdStDepVALUWaitStates = 1;
3678 const int MaxWaitStates = 2;
3679
3680 int WaitStatesNeededForUse = AccVgprReadLdStWaitStates -
3681 getWaitStatesSinceDef(Reg, IsAccVgprReadFn, MaxWaitStates);
3682 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3683
3684 if (WaitStatesNeeded == MaxWaitStates)
3685 return WaitStatesNeeded; // Early exit.
3686
3687 auto IsVALUAccVgprRdWrCheckFn = [Reg, this](const MachineInstr &MI) {
3688 if (MI.getOpcode() != AMDGPU::V_ACCVGPR_READ_B32_e64 &&
3689 MI.getOpcode() != AMDGPU::V_ACCVGPR_WRITE_B32_e64)
3690 return false;
3691 auto IsVALUFn = [](const MachineInstr &MI) {
3692 return SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true) &&
3694 };
3695 return getWaitStatesSinceDef(Reg, IsVALUFn, 2 /*MaxWaitStates*/) <
3696 std::numeric_limits<int>::max();
3697 };
3698
3699 WaitStatesNeededForUse = VALUWriteAccVgprRdWrLdStDepVALUWaitStates -
3700 getWaitStatesSince(IsVALUAccVgprRdWrCheckFn, MaxWaitStates);
3701 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3702 }
3703
3704 return WaitStatesNeeded;
3705}
3706
3707int GCNHazardRecognizer::checkPermlaneHazards(MachineInstr *MI) const {
3708 assert(!ST.hasVcmpxPermlaneHazard() &&
3709 "this is a different vcmpx+permlane hazard");
3710 const SIRegisterInfo *TRI = ST.getRegisterInfo();
3711 const SIInstrInfo *TII = ST.getInstrInfo();
3712
3713 auto IsVCmpXWritesExecFn = [TII, TRI](const MachineInstr &MI) {
3714 return isVCmpXWritesExec(*TII, *TRI, MI);
3715 };
3716
3717 auto IsVALUFn = [](const MachineInstr &MI) {
3718 return SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true);
3719 };
3720
3721 const int VCmpXWritesExecWaitStates = 4;
3722 const int VALUWritesVDstWaitStates = 2;
3723 int WaitStatesNeeded = 0;
3724
3725 for (const MachineOperand &Op : MI->explicit_uses()) {
3726 if (!Op.isReg() || !TRI->isVGPR(MF.getRegInfo(), Op.getReg()))
3727 continue;
3728 Register Reg = Op.getReg();
3729
3730 int WaitStatesSinceDef =
3731 VALUWritesVDstWaitStates -
3732 getWaitStatesSinceDef(Reg, IsVALUFn,
3733 /*MaxWaitStates=*/VALUWritesVDstWaitStates);
3734 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesSinceDef);
3735 if (WaitStatesNeeded >= VALUWritesVDstWaitStates)
3736 break;
3737 }
3738
3739 int VCmpXHazardWaits =
3740 VCmpXWritesExecWaitStates -
3741 getWaitStatesSince(IsVCmpXWritesExecFn, VCmpXWritesExecWaitStates);
3742
3743 WaitStatesNeeded = std::max(WaitStatesNeeded, VCmpXHazardWaits);
3744 return WaitStatesNeeded;
3745}
3746
3748 // 2 pass -> 4
3749 // 4 pass -> 6
3750 // 8 pass -> 10
3751 // 16 pass -> 18
3752 return NumPasses + 2;
3753}
3754
3756 bool IsGFX950) {
3757 // xdl def cycles | gfx942 | gfx950
3758 // 2 pass | 5 5
3759 // 4 pass | 7 8
3760 // 8 pass | 11 12
3761 // 16 pass | 19 20
3762 return NumPasses + 3 + (NumPasses != 2 && IsGFX950);
3763}
3764
3766 bool IsGFX950) {
3767 // xdl def cycles | gfx942 | gfx950
3768 // 2 pass | 5 5
3769 // 4 pass | 7 8
3770 // 8 pass | 11 12
3771 // 16 pass | 19 20
3772 return NumPasses + 3 + (NumPasses != 2 && IsGFX950);
3773}
3774
3776 // 2 pass -> 4
3777 // 4 pass -> 6
3778 // 8 pass -> 10
3779 // 16 pass -> 18
3780 return NumPasses + 2;
3781}
3782
3783int GCNHazardRecognizer::checkMAIVALUHazards(MachineInstr *MI) const {
3784 if (!ST.hasGFX90AInsts())
3785 return 0;
3786
3787 auto IsDGEMMFn = [](const MachineInstr &MI) -> bool {
3788 return SIInstrInfo::isDGEMM(MI.getOpcode());
3789 };
3790
3791 // This is checked in checkMAIHazards90A()
3792 if (SIInstrInfo::isMFMA(*MI))
3793 return 0;
3794
3795 const MachineRegisterInfo &MRI = MF.getRegInfo();
3796
3797 int WaitStatesNeeded = 0;
3798
3799 bool IsMem = SIInstrInfo::isVMEM(*MI) || SIInstrInfo::isDS(*MI);
3800 bool IsMemOrExport = IsMem || SIInstrInfo::isEXP(*MI);
3801 bool IsVALU = SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true);
3802
3803 unsigned Reg;
3804 auto IsMFMAWriteFn = [&Reg, this](const MachineInstr &MI) {
3805 if (!SIInstrInfo::isMFMA(MI) ||
3806 !TRI.regsOverlap(MI.getOperand(0).getReg(), Reg))
3807 return false;
3808 return true;
3809 };
3810
3811 const MachineInstr *DOT = nullptr;
3812 auto IsDotWriteFn = [&Reg, &DOT, this](const MachineInstr &MI) {
3813 if (!SIInstrInfo::isDOT(MI) ||
3814 !TRI.regsOverlap(MI.getOperand(0).getReg(), Reg))
3815 return false;
3816 DOT = &MI;
3817 return true;
3818 };
3819
3820 bool DGEMMAfterVALUWrite = false;
3821 auto IsDGEMMHazard = [&DGEMMAfterVALUWrite, this](const MachineInstr &MI) {
3822 // Found DGEMM on reverse traversal to def.
3823 if (SIInstrInfo::isDGEMM(MI.getOpcode()))
3824 DGEMMAfterVALUWrite = true;
3825
3826 // Only hazard if register is defined by a VALU and a DGEMM is found after
3827 // after the def.
3828 if (!TII.isVALU(MI, /*AllowLDSDMA=*/true) || !DGEMMAfterVALUWrite)
3829 return false;
3830
3831 return true;
3832 };
3833
3834 int SrcCIdx = AMDGPU::getNamedOperandIdx(MI->getOpcode(),
3835 AMDGPU::OpName::src2);
3836
3837 if (IsMemOrExport || IsVALU) {
3838 const int SMFMA4x4WriteVgprVALUMemExpReadWaitStates = 5;
3839 const int SMFMA16x16WriteVgprVALUMemExpReadWaitStates = 11;
3840 const int SMFMA32x32WriteVgprVALUMemExpReadWaitStates = 19;
3841 const int DMFMA4x4WriteVgprMemExpReadWaitStates = 9;
3842 const int DMFMA16x16WriteVgprMemExpReadWaitStates = 18;
3843 const int DMFMA4x4WriteVgprVALUReadWaitStates = 6;
3844 const int DMFMA16x16WriteVgprVALUReadWaitStates = 11;
3845 const int GFX950_DMFMA16x16WriteVgprVALUReadWaitStates = 19;
3846 const int DotWriteSameDotReadSrcAB = 3;
3847 const int DotWriteDifferentVALURead = 3;
3848 const int DMFMABetweenVALUWriteVMEMRead = 2;
3849 const int MaxWaitStates =
3851 ST.hasGFX950Insts());
3852
3853 for (const MachineOperand &Use : MI->explicit_uses()) {
3854 if (!Use.isReg())
3855 continue;
3856 Reg = Use.getReg();
3857
3858 DOT = nullptr;
3859 int WaitStatesSinceDef = getWaitStatesSinceDef(Reg, IsDotWriteFn,
3860 MaxWaitStates);
3861 if (DOT) {
3862 int NeedWaitStates = 0;
3863 if (DOT->getOpcode() == MI->getOpcode()) {
3864 if (&Use - &MI->getOperand(0) != SrcCIdx)
3865 NeedWaitStates = DotWriteSameDotReadSrcAB;
3866 } else {
3867 NeedWaitStates = DotWriteDifferentVALURead;
3868 }
3869
3870 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceDef;
3871 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3872 }
3873
3874 // Workaround for HW data hazard bug observed only in GFX90A. When there
3875 // is a DGEMM instruction in-between a VALU and a VMEM instruction it
3876 // causes the SQ to incorrectly not insert two wait states between the two
3877 // instructions needed to avoid data hazard.
3878 if (IsMem && ST.hasGFX90AInsts() && !ST.hasGFX940Insts()) {
3879 DGEMMAfterVALUWrite = false;
3880 if (TRI.isVectorRegister(MRI, Reg)) {
3881 int WaitStatesNeededForUse =
3882 DMFMABetweenVALUWriteVMEMRead -
3883 getWaitStatesSinceDef(Reg, IsDGEMMHazard,
3884 DMFMABetweenVALUWriteVMEMRead);
3885
3886 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3887 }
3888 }
3889
3890 auto MFMAWindow = [&](const MachineInstr &Producer) {
3891 int NumPasses = TSchedModel.computeInstrLatency(&Producer);
3892 int NeedWaitStates = MaxWaitStates;
3893
3894 if (SIInstrInfo::isDGEMM(Producer.getOpcode())) {
3895 switch (NumPasses) {
3896 case 4:
3897 NeedWaitStates = IsMemOrExport
3898 ? DMFMA4x4WriteVgprMemExpReadWaitStates
3899 : DMFMA4x4WriteVgprVALUReadWaitStates;
3900 break;
3901 case 8:
3902 case 16:
3903 NeedWaitStates =
3904 IsMemOrExport
3905 ? DMFMA16x16WriteVgprMemExpReadWaitStates
3906 : (ST.hasGFX950Insts()
3907 ? GFX950_DMFMA16x16WriteVgprVALUReadWaitStates
3908 : DMFMA16x16WriteVgprVALUReadWaitStates);
3909 break;
3910 default:
3911 llvm_unreachable("unexpected dgemm");
3912 }
3913 } else if (ST.hasGFX940Insts()) {
3914 NeedWaitStates =
3915 TII.isXDL(Producer)
3917 NumPasses, ST.hasGFX950Insts())
3919 NumPasses);
3920 } else {
3921 switch (NumPasses) {
3922 case 2:
3923 NeedWaitStates = SMFMA4x4WriteVgprVALUMemExpReadWaitStates;
3924 break;
3925 case 8:
3926 NeedWaitStates = SMFMA16x16WriteVgprVALUMemExpReadWaitStates;
3927 break;
3928 case 16:
3929 NeedWaitStates = SMFMA32x32WriteVgprVALUMemExpReadWaitStates;
3930 break;
3931 default:
3932 llvm_unreachable("unexpected number of passes for mfma");
3933 }
3934 }
3935
3936 assert(NeedWaitStates <= MaxWaitStates &&
3937 "hazard requirement exceeds the scan window");
3938 return NeedWaitStates;
3939 };
3940
3941 WaitStatesNeeded = std::max(
3942 WaitStatesNeeded,
3943 getMaxWindowDeficit(MaxWaitStates,
3944 [&](const MachineInstr &P) -> std::optional<int> {
3945 if (!IsMFMAWriteFn(P))
3946 return std::nullopt;
3947 return MFMAWindow(P);
3948 }));
3949
3950 if (WaitStatesNeeded >= MaxWaitStates)
3951 break;
3952 }
3953 }
3954
3955 unsigned Opc = MI->getOpcode();
3956 const int DMFMAToFMA64WaitStates = 2;
3957 if ((Opc == AMDGPU::V_FMA_F64_e64 ||
3958 Opc == AMDGPU::V_FMAC_F64_e32 || Opc == AMDGPU::V_FMAC_F64_e64 ||
3959 Opc == AMDGPU::V_FMAC_F64_dpp) &&
3960 WaitStatesNeeded < DMFMAToFMA64WaitStates) {
3961 int WaitStatesNeededForUse = DMFMAToFMA64WaitStates -
3962 getWaitStatesSince(IsDGEMMFn, DMFMAToFMA64WaitStates);
3963 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3964 }
3965
3966 if (!IsVALU && !IsMemOrExport)
3967 return WaitStatesNeeded;
3968
3969 for (const MachineOperand &Def : MI->defs()) {
3970 const int SMFMA4x4WriteVgprVALUWawWaitStates = 5;
3971 const int SMFMA16x16WriteVgprVALUWawWaitStates = 11;
3972 const int SMFMA32x32WriteVgprVALUWawWaitStates = 19;
3973 const int SMFMA4x4ReadVgprVALUWarWaitStates = 1;
3974 const int GFX940_XDL4PassReadVgprVALUWarWaitStates = 3;
3975 const int SMFMA16x16ReadVgprVALUWarWaitStates = 7;
3976 const int SMFMA32x32ReadVgprVALUWarWaitStates = 15;
3977 const int DMFMA4x4WriteVgprVALUWriteWaitStates = 6;
3978 const int DMFMA16x16WriteVgprVALUWriteWaitStates = 11;
3979 const int DotWriteDifferentVALUWrite = 3;
3980 const int MaxWaitStates =
3981 GFX940_XDL_N_PassWriteVgprVALUWawWaitStates(16, ST.hasGFX950Insts());
3982 const int MaxWarWaitStates = 15;
3983
3984 Reg = Def.getReg();
3985
3986 DOT = nullptr;
3987 int WaitStatesSinceDef = getWaitStatesSinceDef(Reg, IsDotWriteFn,
3988 MaxWaitStates);
3989 if (DOT && DOT->getOpcode() != MI->getOpcode())
3990 WaitStatesNeeded = std::max(WaitStatesNeeded, DotWriteDifferentVALUWrite -
3991 WaitStatesSinceDef);
3992
3993 auto MFMAWawWindow = [&](const MachineInstr &Producer) {
3994 int NeedWaitStates = MaxWaitStates;
3995 int NumPasses = TSchedModel.computeInstrLatency(&Producer);
3996
3997 if (SIInstrInfo::isDGEMM(Producer.getOpcode())) {
3998 switch (NumPasses) {
3999 case 4:
4000 NeedWaitStates = DMFMA4x4WriteVgprVALUWriteWaitStates;
4001 break;
4002 case 8:
4003 case 16:
4004 NeedWaitStates = DMFMA16x16WriteVgprVALUWriteWaitStates;
4005 break;
4006 default:
4007 llvm_unreachable("unexpected number of cycles for dgemm");
4008 }
4009 } else if (ST.hasGFX940Insts()) {
4010 NeedWaitStates =
4011 TII.isXDL(Producer)
4013 NumPasses, ST.hasGFX950Insts())
4015 } else {
4016 switch (NumPasses) {
4017 case 2:
4018 NeedWaitStates = SMFMA4x4WriteVgprVALUWawWaitStates;
4019 break;
4020 case 8:
4021 NeedWaitStates = SMFMA16x16WriteVgprVALUWawWaitStates;
4022 break;
4023 case 16:
4024 NeedWaitStates = SMFMA32x32WriteVgprVALUWawWaitStates;
4025 break;
4026 default:
4027 llvm_unreachable("Unexpected number of passes for mfma");
4028 }
4029 }
4030
4031 assert(NeedWaitStates <= MaxWaitStates &&
4032 "hazard requirement exceeds the scan window");
4033 return NeedWaitStates;
4034 };
4035
4036 WaitStatesNeeded = std::max(
4037 WaitStatesNeeded,
4038 getMaxWindowDeficit(MaxWaitStates,
4039 [&](const MachineInstr &P) -> std::optional<int> {
4040 if (!IsMFMAWriteFn(P))
4041 return std::nullopt;
4042 return MFMAWawWindow(P);
4043 }));
4044
4045 if (WaitStatesNeeded >= MaxWaitStates)
4046 break;
4047
4048 // Wait states this write needs after an MFMA that read Reg as srcC.
4049 auto SMFMAReadAsCWindow =
4050 [&](const MachineInstr &Reader) -> std::optional<int> {
4051 if (!SIInstrInfo::isMFMA(Reader) ||
4052 SIInstrInfo::isDGEMM(Reader.getOpcode()) ||
4053 !Reader.readsRegister(Reg, &TRI))
4054 return std::nullopt;
4055
4056 if (ST.hasGFX940Insts() && !TII.isXDL(Reader))
4057 return std::nullopt;
4058
4059 const MachineOperand *SrcC =
4060 TII.getNamedOperand(Reader, AMDGPU::OpName::src2);
4061 assert(SrcC && "an MFMA must have a src2 operand");
4062 if (!SrcC->isReg() || !TRI.regsOverlap(SrcC->getReg(), Reg))
4063 return std::nullopt;
4064
4065 switch (TSchedModel.computeInstrLatency(&Reader)) {
4066 case 2:
4067 return SMFMA4x4ReadVgprVALUWarWaitStates;
4068 case 4:
4069 assert(ST.hasGFX940Insts() && "4-pass XDL is gfx940 or later");
4070 return GFX940_XDL4PassReadVgprVALUWarWaitStates;
4071 case 8:
4072 return SMFMA16x16ReadVgprVALUWarWaitStates;
4073 case 16:
4074 [[fallthrough]];
4075 default:
4076 return SMFMA32x32ReadVgprVALUWarWaitStates;
4077 }
4078 };
4079
4080 WaitStatesNeeded =
4081 std::max(WaitStatesNeeded,
4082 getMaxWindowDeficit(MaxWarWaitStates, SMFMAReadAsCWindow));
4083 }
4084
4085 return WaitStatesNeeded;
4086}
4087
4089 if (!SU->isInstr())
4090 return false;
4091
4092 const MachineInstr *MAI = nullptr;
4093
4094 auto IsMFMAFn = [&MAI](const MachineInstr &MI) {
4095 MAI = nullptr;
4097 MAI = &MI;
4098 return MAI != nullptr;
4099 };
4100
4101 MachineInstr *MI = SU->getInstr();
4102 if (IsMFMAFn(*MI)) {
4103 int W = getWaitStatesSince(IsMFMAFn, 16);
4104 if (MAI)
4105 return W < (int)TSchedModel.computeInstrLatency(MAI);
4106 }
4107
4108 return false;
4109}
4110
4111// Adjust global offsets for instructions bundled with S_GETPC_B64 after
4112// insertion of a new instruction.
4113static void updateGetPCBundle(MachineInstr *NewMI) {
4114 if (!NewMI->isBundled())
4115 return;
4116
4117 // Find start of bundle.
4118 auto I = NewMI->getIterator();
4119 while (I->isBundledWithPred())
4120 I--;
4121 if (I->isBundle())
4122 I++;
4123
4124 // Bail if this is not an S_GETPC bundle.
4125 if (I->getOpcode() != AMDGPU::S_GETPC_B64)
4126 return;
4127
4128 // Update offsets of any references in the bundle.
4129 const unsigned NewBytes = 4;
4130 assert(NewMI->getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
4131 "Unexpected instruction insertion in bundle");
4132 auto NextMI = std::next(NewMI->getIterator());
4133 auto End = NewMI->getParent()->end();
4134 while (NextMI != End && NextMI->isBundledWithPred()) {
4135 for (auto &Operand : NextMI->operands()) {
4136 if (Operand.isGlobal())
4137 Operand.setOffset(Operand.getOffset() + NewBytes);
4138 }
4139 NextMI++;
4140 }
4141}
4142
4143bool GCNHazardRecognizer::fixVALUMaskWriteHazard(MachineInstr *MI) {
4144 if (!ST.hasVALUMaskWriteHazard())
4145 return false;
4146 assert(!ST.hasExtendedWaitCounts());
4147
4148 if (!ST.isWave64())
4149 return false;
4150
4151 const bool IsSALU = SIInstrInfo::isSALU(*MI);
4152 const bool IsVALU = SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true);
4153 if (!IsSALU && !IsVALU)
4154 return false;
4155
4156 // The hazard sequence is three instructions:
4157 // 1. VALU reads SGPR as mask
4158 // 2. VALU/SALU writes SGPR
4159 // 3. VALU/SALU reads SGPR
4160 // The hazard can expire if the distance between 2 and 3 is sufficient,
4161 // or (2) is VALU and (3) is SALU.
4162 // In practice this happens <10% of the time, hence always assume the hazard
4163 // exists if (1) and (2) are present to avoid searching all SGPR reads.
4164
4165 const SIRegisterInfo *TRI = ST.getRegisterInfo();
4166 const MachineRegisterInfo &MRI = MF.getRegInfo();
4167
4168 auto IgnoreableSGPR = [](const Register Reg) {
4169 switch (Reg) {
4170 case AMDGPU::EXEC:
4171 case AMDGPU::EXEC_LO:
4172 case AMDGPU::EXEC_HI:
4173 case AMDGPU::M0:
4174 case AMDGPU::SGPR_NULL:
4175 case AMDGPU::SGPR_NULL64:
4176 case AMDGPU::SCC:
4177 return true;
4178 default:
4179 return false;
4180 }
4181 };
4182 auto IsVCC = [](const Register Reg) {
4183 return Reg == AMDGPU::VCC || Reg == AMDGPU::VCC_LO || Reg == AMDGPU::VCC_HI;
4184 };
4185
4186 struct StateType {
4187 SmallSet<Register, 2> HazardSGPRs;
4188
4189 static unsigned getHashValue(const StateType &State) {
4190 return static_cast<unsigned>(hash_combine_range(State.HazardSGPRs));
4191 }
4192 static bool isEqual(const StateType &LHS, const StateType &RHS) {
4193 return LHS.HazardSGPRs == RHS.HazardSGPRs;
4194 }
4195 };
4196
4197 SmallVector<const MachineInstr *> WaitInstrs;
4198 StateType InitialState;
4199
4200 // Look for SGPR write.
4201 MachineOperand *HazardDef = nullptr;
4202 for (MachineOperand &Op : MI->all_defs()) {
4203 Register Reg = Op.getReg();
4204 if (IgnoreableSGPR(Reg))
4205 continue;
4206 if (!IsVCC(Reg)) {
4207 if (Op.isImplicit())
4208 continue;
4209 if (!TRI->isSGPRReg(MRI, Reg))
4210 continue;
4211 }
4212
4213 HazardDef = &Op;
4214 break;
4215 }
4216
4217 if (!HazardDef)
4218 return false;
4219
4220 // Setup to track writes to individual SGPRs
4221 const Register HazardReg = HazardDef->getReg();
4222 if (AMDGPU::SReg_32RegClass.contains(HazardReg)) {
4223 InitialState.HazardSGPRs.insert(HazardReg);
4224 } else {
4225 assert(AMDGPU::SReg_64RegClass.contains(HazardReg));
4226 InitialState.HazardSGPRs.insert(TRI->getSubReg(HazardReg, AMDGPU::sub0));
4227 InitialState.HazardSGPRs.insert(TRI->getSubReg(HazardReg, AMDGPU::sub1));
4228 }
4229
4230 auto IsHazardFn = [&](StateType &State, const MachineInstr &I) {
4231 if (State.HazardSGPRs.empty())
4232 return HazardExpired;
4233
4234 switch (I.getOpcode()) {
4235 case AMDGPU::V_ADDC_U32_e32:
4236 case AMDGPU::V_ADDC_U32_dpp:
4237 case AMDGPU::V_CNDMASK_B16_t16_e32:
4238 case AMDGPU::V_CNDMASK_B16_fake16_e32:
4239 case AMDGPU::V_CNDMASK_B16_t16_dpp:
4240 case AMDGPU::V_CNDMASK_B16_fake16_dpp:
4241 case AMDGPU::V_CNDMASK_B32_e32:
4242 case AMDGPU::V_CNDMASK_B32_dpp:
4243 case AMDGPU::V_DIV_FMAS_F32_e64:
4244 case AMDGPU::V_DIV_FMAS_F64_e64:
4245 case AMDGPU::V_SUBB_U32_e32:
4246 case AMDGPU::V_SUBB_U32_dpp:
4247 case AMDGPU::V_SUBBREV_U32_e32:
4248 case AMDGPU::V_SUBBREV_U32_dpp: {
4249 // These implicitly read VCC as mask source.
4250 return IsVCC(HazardReg) ? HazardFound : NoHazardFound;
4251 }
4252 case AMDGPU::V_ADDC_U32_e64:
4253 case AMDGPU::V_ADDC_U32_e64_dpp:
4254 case AMDGPU::V_CNDMASK_B16_t16_e64:
4255 case AMDGPU::V_CNDMASK_B16_fake16_e64:
4256 case AMDGPU::V_CNDMASK_B16_t16_e64_dpp:
4257 case AMDGPU::V_CNDMASK_B16_fake16_e64_dpp:
4258 case AMDGPU::V_CNDMASK_B32_e64:
4259 case AMDGPU::V_CNDMASK_B32_e64_dpp:
4260 case AMDGPU::V_SUBB_U32_e64:
4261 case AMDGPU::V_SUBB_U32_e64_dpp:
4262 case AMDGPU::V_SUBBREV_U32_e64:
4263 case AMDGPU::V_SUBBREV_U32_e64_dpp: {
4264 // Only check mask register overlaps.
4265 const MachineOperand *SSRCOp = TII.getNamedOperand(I, AMDGPU::OpName::src2);
4266 assert(SSRCOp);
4267 bool Result = TRI->regsOverlap(SSRCOp->getReg(), HazardReg);
4268 return Result ? HazardFound : NoHazardFound;
4269 }
4270 default:
4271 return NoHazardFound;
4272 }
4273 };
4274
4275 auto UpdateStateFn = [&](StateType &State, const MachineInstr &I) {
4276 // Update tracking of SGPR writes.
4277 for (auto &Op : I.all_defs()) {
4278 Register Reg = Op.getReg();
4279 if (IgnoreableSGPR(Reg))
4280 continue;
4281 if (!IsVCC(Reg)) {
4282 if (Op.isImplicit())
4283 continue;
4284 if (!TRI->isSGPRReg(MRI, Reg))
4285 continue;
4286 }
4287
4288 // Stop tracking any SGPRs with writes on the basis that they will
4289 // already have an appropriate wait inserted afterwards.
4291 for (Register SGPR : State.HazardSGPRs) {
4292 if (Reg == SGPR || TRI->regsOverlap(Reg, SGPR))
4293 Found.push_back(SGPR);
4294 }
4295 for (Register SGPR : Found)
4296 State.HazardSGPRs.erase(SGPR);
4297 }
4298 };
4299
4300 // Check for hazard
4301 if (!hasHazard<StateType>(InitialState, IsHazardFn, UpdateStateFn,
4302 MI->getParent(),
4303 std::next(MI->getReverseIterator())))
4304 return false;
4305
4306 // Compute counter mask
4307 unsigned DepCtr =
4308 IsVALU ? (IsVCC(HazardReg) ? AMDGPU::DepCtr::encodeFieldVaVcc(0, ST)
4309 : AMDGPU::DepCtr::encodeFieldVaSdst(0, ST))
4310 : AMDGPU::DepCtr::encodeFieldSaSdst(0, ST);
4311
4312 // Add s_waitcnt_depctr after SGPR write.
4313 auto NextMI = std::next(MI->getIterator());
4314 auto NewMI = BuildMI(*MI->getParent(), NextMI, MI->getDebugLoc(),
4315 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
4316 .addImm(DepCtr);
4317
4318 // SALU write may be s_getpc in a bundle.
4319 updateGetPCBundle(NewMI);
4320
4321 return true;
4322}
4323
4324static bool ensureEntrySetPrio(MachineFunction *MF, int Priority,
4325 const SIInstrInfo &TII) {
4326 MachineBasicBlock &EntryMBB = MF->front();
4327 if (EntryMBB.begin() != EntryMBB.end()) {
4328 auto &EntryMI = *EntryMBB.begin();
4329 if (EntryMI.getOpcode() == AMDGPU::S_SETPRIO &&
4330 EntryMI.getOperand(0).getImm() >= Priority)
4331 return false;
4332 }
4333
4334 BuildMI(EntryMBB, EntryMBB.begin(), DebugLoc(), TII.get(AMDGPU::S_SETPRIO))
4335 .addImm(Priority);
4336 return true;
4337}
4338
4339bool GCNHazardRecognizer::fixRequiredExportPriority(MachineInstr *MI) {
4340 if (!ST.hasRequiredExportPriority())
4341 return false;
4342
4343 // Assume the following shader types will never have exports,
4344 // and avoid adding or adjusting S_SETPRIO.
4345 MachineBasicBlock *MBB = MI->getParent();
4346 MachineFunction *MF = MBB->getParent();
4347 auto CC = MF->getFunction().getCallingConv();
4348 switch (CC) {
4353 return false;
4354 default:
4355 break;
4356 }
4357
4358 const int MaxPriority = 3;
4359 const int NormalPriority = 2;
4360 const int PostExportPriority = 0;
4361
4362 auto It = MI->getIterator();
4363 switch (MI->getOpcode()) {
4364 case AMDGPU::S_ENDPGM:
4365 case AMDGPU::S_ENDPGM_SAVED:
4366 case AMDGPU::S_ENDPGM_ORDERED_PS_DONE:
4367 case AMDGPU::SI_RETURN_TO_EPILOG:
4368 // Ensure shader with calls raises priority at entry.
4369 // This ensures correct priority if exports exist in callee.
4370 if (MF->getFrameInfo().hasCalls())
4371 return ensureEntrySetPrio(MF, NormalPriority, TII);
4372 return false;
4373 case AMDGPU::S_SETPRIO: {
4374 // Raise minimum priority unless in workaround.
4375 auto &PrioOp = MI->getOperand(0);
4376 int Prio = static_cast<int>(PrioOp.getImm());
4377 bool InWA = (Prio == PostExportPriority) &&
4378 (It != MBB->begin() && TII.isEXP(*std::prev(It)));
4379 if (InWA || Prio >= NormalPriority)
4380 return false;
4381 PrioOp.setImm(std::min(Prio + NormalPriority, MaxPriority));
4382 return true;
4383 }
4384 default:
4385 if (!TII.isEXP(*MI))
4386 return false;
4387 break;
4388 }
4389
4390 // Check entry priority at each export (as there will only be a few).
4391 // Note: amdgpu_gfx can only be a callee, so defer to caller setprio.
4392 bool Changed = false;
4394 Changed = ensureEntrySetPrio(MF, NormalPriority, TII);
4395
4396 auto NextMI = std::next(It);
4397 bool EndOfShader = false;
4398 if (NextMI != MBB->end()) {
4399 // Only need WA at end of sequence of exports.
4400 if (TII.isEXP(*NextMI))
4401 return Changed;
4402 // Assume appropriate S_SETPRIO after export means WA already applied.
4403 if (NextMI->getOpcode() == AMDGPU::S_SETPRIO &&
4404 NextMI->getOperand(0).getImm() == PostExportPriority)
4405 return Changed;
4406 EndOfShader = NextMI->getOpcode() == AMDGPU::S_ENDPGM;
4407 }
4408
4409 const DebugLoc &DL = MI->getDebugLoc();
4410
4411 // Lower priority.
4412 BuildMI(*MBB, NextMI, DL, TII.get(AMDGPU::S_SETPRIO))
4413 .addImm(PostExportPriority);
4414
4415 if (!EndOfShader) {
4416 // Wait for exports to complete.
4417 BuildMI(*MBB, NextMI, DL, TII.get(AMDGPU::S_WAITCNT_EXPCNT))
4418 .addReg(AMDGPU::SGPR_NULL)
4419 .addImm(0);
4420 }
4421
4422 BuildMI(*MBB, NextMI, DL, TII.get(AMDGPU::S_NOP)).addImm(0);
4423 BuildMI(*MBB, NextMI, DL, TII.get(AMDGPU::S_NOP)).addImm(0);
4424
4425 if (!EndOfShader) {
4426 // Return to normal (higher) priority.
4427 BuildMI(*MBB, NextMI, DL, TII.get(AMDGPU::S_SETPRIO))
4428 .addImm(NormalPriority);
4429 }
4430
4431 return true;
4432}
4433
4434// Advance past meta instructions (debug values, labels, CFI, KILL, etc.) to the
4435// next instruction that actually issues. Unlike skipDebugInstructionsForward /
4436// next_nodbg, this skips the full isMetaInstruction() set.
4440 while (I != End && I->isMetaInstruction())
4441 ++I;
4442 return I;
4443}
4444
4445bool GCNHazardRecognizer::fixVPermPk16Hazard(MachineInstr *MI) {
4446 // Requirement #1 of 2:
4447 // The cross-wave entry-block mitigation is delegated to the mandatory
4448 // unclaused-VMEM entry prologue (GLOBAL_PREFETCH_B8 + V_NOP).
4449 assert(ST.hasRequiresInitialUnclausedVmem() &&
4450 "V_PERM_PK16-hazard subtarget must provide the unclaused-VMEM entry "
4451 "prologue to satisfy the cross-wave entry mitigation");
4452
4453 if (!SIInstrInfo::isVPermPk16(MI->getOpcode()))
4454 return false;
4455
4456 MachineBasicBlock *MBB = MI->getParent();
4457
4458 // Requirement #2 of 2:
4459 // V_PERM_PK16 must be immediately followed by a safe instruction.
4461 skipMetaInstructionsForward(std::next(MI->getIterator()), MBB->end());
4462 if (NextI != MBB->end() && TII.isVPermPk16SafeInstr(*NextI))
4463 return false;
4464
4465 // EXEC is guaranteed non-zero here: V_PERM_PK16 reports unwanted effects
4466 // when EXEC is empty, so s_cbranch_execz over this region is retained.
4467 // A plain V_NOP is therefore a real VALU nop and clears the hazard.
4468 BuildMI(*MBB, NextI, MI->getDebugLoc(), TII.get(AMDGPU::V_NOP_e32));
4469 return true;
4470}
4471
4472bool GCNHazardRecognizer::fixGetRegWaitIdle(MachineInstr *MI) {
4473 if (!isSGetReg(MI->getOpcode()))
4474 return false;
4475
4476 const SIInstrInfo *TII = ST.getInstrInfo();
4477 switch (getHWReg(TII, *MI)) {
4478 default:
4479 return false;
4484 break;
4485 }
4486
4487 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
4488 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4489 .addImm(0);
4490 return true;
4491}
4492
4493bool GCNHazardRecognizer::fixDsAtomicAsyncBarrierArriveB64(MachineInstr *MI) {
4494 if (MI->getOpcode() != AMDGPU::DS_ATOMIC_ASYNC_BARRIER_ARRIVE_B64)
4495 return false;
4496
4497 const SIInstrInfo *TII = ST.getInstrInfo();
4498 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
4499 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4501 BuildMI(*MI->getParent(), std::next(MI->getIterator()), MI->getDebugLoc(),
4502 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4504
4505 return true;
4506}
4507
4508bool GCNHazardRecognizer::fixScratchBaseForwardingHazard(MachineInstr *MI) {
4509 // No reason to check this in pre-RA scheduling, SGPRs have to be allocated
4510 // for hazard to trigger.
4512 return false;
4513
4514 const SIRegisterInfo *TRI = ST.getRegisterInfo();
4515 const SIInstrInfo *TII = ST.getInstrInfo();
4516 // Hazard expires after 10 SGPR writes by SALU or 8 SGPR writes by VALU.
4517 const int FlatScrBaseWaitStates = 10;
4518
4519 bool ReadsFlatScrLo =
4520 MI->readsRegister(AMDGPU::SRC_FLAT_SCRATCH_BASE_LO, TRI);
4521 bool ReadsFlatScrHi =
4522 MI->readsRegister(AMDGPU::SRC_FLAT_SCRATCH_BASE_HI, TRI);
4523 if (isSGetReg(MI->getOpcode())) {
4524 switch (getHWReg(TII, *MI)) {
4525 default:
4526 break;
4528 ReadsFlatScrLo = true;
4529 break;
4531 ReadsFlatScrHi = true;
4532 break;
4533 }
4534 }
4535
4536 const MachineRegisterInfo &MRI = MF.getRegInfo();
4537
4538 auto IsRegDefHazard = [&](Register Reg) -> bool {
4539 DenseSet<const MachineBasicBlock *> Visited;
4540 auto IsHazardFn = [TRI, Reg](const MachineInstr &MI) {
4541 return MI.modifiesRegister(Reg, TRI);
4542 };
4543
4544 // This literally abuses the idea of waitstates. Instead of waitstates it
4545 // returns 1 for SGPR written and 0 otherwise.
4546 auto IsSGPRDef = [TII, TRI, &MRI](const MachineInstr &MI) -> unsigned {
4547 if (!TII->isSALU(MI) && !TII->isVALU(MI, /*AllowLDSDMA=*/true))
4548 return 0;
4549 for (const MachineOperand &MO : MI.all_defs()) {
4550 if (TRI->isSGPRReg(MRI, MO.getReg()))
4551 return 1;
4552 }
4553 return 0;
4554 };
4555
4556 auto IsExpiredFn = [=](const MachineInstr &MI, int SgprWrites) {
4557 if (MI.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR) {
4558 unsigned Wait = static_cast<unsigned>(MI.getOperand(0).getImm());
4561 return true;
4562 }
4563 return SgprWrites >= FlatScrBaseWaitStates;
4564 };
4565
4566 return ::getWaitStatesSince(
4567 IsHazardFn, MI->getParent(), std::next(MI->getReverseIterator()),
4568 0, IsExpiredFn, Visited, IsSGPRDef) < FlatScrBaseWaitStates;
4569 };
4570
4571 if ((!ReadsFlatScrLo || MRI.isConstantPhysReg(AMDGPU::SGPR102) ||
4572 !IsRegDefHazard(AMDGPU::SGPR102)) &&
4573 (!ReadsFlatScrHi || MRI.isConstantPhysReg(AMDGPU::SGPR103) ||
4574 !IsRegDefHazard(AMDGPU::SGPR103)))
4575 return false;
4576
4577 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
4578 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4581 return true;
4582}
4583
4584bool GCNHazardRecognizer::fixSetRegMode(MachineInstr *MI) {
4585 if (!isSSetReg(MI->getOpcode()) ||
4586 MI->getOperand(1).getImm() != AMDGPU::Hwreg::ID_MODE)
4587 return false;
4588
4589 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), TII.get(AMDGPU::V_NOP_e32));
4590 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), TII.get(AMDGPU::V_NOP_e32));
4591 return true;
4592}
4593
4594bool GCNHazardRecognizer::fixTDM(MachineInstr *MI) {
4595 auto IsTDM = [&](const MachineInstr &MI) -> bool {
4597 MI.getOpcode() != AMDGPU::S_WAIT_TENSORCNT;
4598 };
4599
4600 if (!IsTDM(*MI))
4601 return false;
4602
4603 auto IsExpiredFn = [](const MachineInstr &MI, int) {
4604 if (MI.getOpcode() != AMDGPU::S_WAIT_TENSORCNT)
4605 return false;
4606 return MI.getOperand(0).getImm() <= 10;
4607 };
4608
4609 if (::getWaitStatesSince(IsTDM, MI, IsExpiredFn) ==
4610 std::numeric_limits<int>::max())
4611 return false;
4612
4613 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
4614 TII.get(AMDGPU::S_WAIT_TENSORCNT))
4615 .addImm(10);
4616 return true;
4617}
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 CodeGenData.h:33
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
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
Definition InstrProf.h:145
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Next
Definition InstrProf.h:147
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
Definition Hashing.h:307
@ End
Run the machine verifier once, at the end of the pipeline.
Definition CodeGen.h: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...