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 // Check if the instruction can co-execute at the current stage.
349 if (ActiveCoExecInfo.canCoExec(InstMask, Stage))
350 return 0;
351
352 // Find next allowed stage and return stall cycles.
353 auto NextStage = ActiveCoExecInfo.findNextAllowedStage(InstMask, Stage);
354 if (NextStage.has_value()) {
355 unsigned StallCycles = *NextStage - Stage;
358 dbgs() << " CoExec stall: stage=" << Stage << "("
359 << AMDGPU::getStageTypeName(ActiveCoExecInfo.getType(Stage))
360 << ") mask=" << AMDGPU::getCoExecMaskName(InstMask)
361 << " -> stall " << StallCycles << " (next allowed=" << *NextStage
362 << ")\n"
363 << " " << MI);
364 return StallCycles;
365 }
366
367 // No compatible slot in window - stall until window ends.
368 unsigned StallCycles = ActiveCoExecInfo.TotalWindow - Stage;
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 // Check if the instruction can co-execute at the current stage.
402 if (ActiveCoExecInfo.canCoExec(InstMask, LookAheadStage))
403 return CyclesUntilTRANS;
404
405 // Find next allowed stage and return stall cycles.
406 auto NextStage =
407 ActiveCoExecInfo.findNextAllowedStage(InstMask, LookAheadStage);
408 if (NextStage.has_value()) {
409 unsigned StallCycles = *NextStage - *CurrentCoExecStage;
410 return StallCycles;
411 }
412
413 // No compatible slot in window - stall until window ends.
414 unsigned StallCycles = ActiveCoExecInfo.TotalWindow - *CurrentCoExecStage;
415 return StallCycles;
416}
417
418void GCNHazardRecognizer::schedulerEmitInstruction(MachineInstr *MI) {
419 LLVM_DEBUG({
420 bool InWindow = CurrentCoExecStage.has_value();
421 bool HasActiveState =
422 InWindow || CyclesUntilTRANS > 0 || CyclesUntilVALU > 0;
423 if (HasActiveState) {
424 if (InWindow) {
425 unsigned Stage = *CurrentCoExecStage;
426 dbgs() << " Stage " << Stage << "("
427 << AMDGPU::getStageTypeName(ActiveCoExecInfo.getType(Stage))
428 << ") Emit ["
430 << "]: " << *MI;
431 } else {
432 dbgs() << " Emit ["
434 << "]: " << *MI;
435 }
436 }
437 });
439 bool HasActiveState = CurrentCoExecStage.has_value() ||
440 CyclesUntilTRANS > 0 || CyclesUntilVALU > 0;
441 if (!HasActiveState)
442 dbgs() << " Emit ["
444 << "]: " << *MI;
445 });
446 updateWMMAWindowState(*MI);
447 updateTRANSState(*MI);
448 updateMultiCycleVALUState(*MI);
449}
450
454
456 CurrCycleInstr = MI;
457 if (isSchedulerMode())
458 schedulerEmitInstruction(MI);
459}
460
461static bool isDivFMas(unsigned Opcode) {
462 return Opcode == AMDGPU::V_DIV_FMAS_F32_e64 || Opcode == AMDGPU::V_DIV_FMAS_F64_e64;
463}
464
465static bool isSGetReg(unsigned Opcode) {
466 return Opcode == AMDGPU::S_GETREG_B32 || Opcode == AMDGPU::S_GETREG_B32_const;
467}
468
469static bool isSSetReg(unsigned Opcode) {
470 switch (Opcode) {
471 case AMDGPU::S_SETREG_B32:
472 case AMDGPU::S_SETREG_B32_mode:
473 case AMDGPU::S_SETREG_IMM32_B32:
474 case AMDGPU::S_SETREG_IMM32_B32_mode:
475 return true;
476 }
477 return false;
478}
479
480static bool isRWLane(unsigned Opcode) {
481 return Opcode == AMDGPU::V_READLANE_B32 || Opcode == AMDGPU::V_WRITELANE_B32;
482}
483
484static bool isRFE(unsigned Opcode) {
485 return Opcode == AMDGPU::S_RFE_B64;
486}
487
488static bool isSMovRel(unsigned Opcode) {
489 switch (Opcode) {
490 case AMDGPU::S_MOVRELS_B32:
491 case AMDGPU::S_MOVRELS_B64:
492 case AMDGPU::S_MOVRELD_B32:
493 case AMDGPU::S_MOVRELD_B64:
494 return true;
495 default:
496 return false;
497 }
498}
499
501 const MachineInstr &MI) {
502 if (TII.isAlwaysGDS(MI.getOpcode()))
503 return true;
504
505 switch (MI.getOpcode()) {
506 case AMDGPU::S_SENDMSG:
507 case AMDGPU::S_SENDMSGHALT:
508 case AMDGPU::S_TTRACEDATA:
509 return true;
510 // These DS opcodes don't support GDS.
511 case AMDGPU::DS_NOP:
512 case AMDGPU::DS_PERMUTE_B32:
513 case AMDGPU::DS_BPERMUTE_B32:
514 return false;
515 default:
516 if (TII.isDS(MI.getOpcode())) {
517 int GDS = AMDGPU::getNamedOperandIdx(MI.getOpcode(),
518 AMDGPU::OpName::gds);
519 if (MI.getOperand(GDS).getImm())
520 return true;
521 }
522 return false;
523 }
524}
525
526static bool isPermlane(const MachineInstr &MI) {
527 unsigned Opcode = MI.getOpcode();
528 return Opcode == AMDGPU::V_PERMLANE16_B32_e64 ||
529 Opcode == AMDGPU::V_PERMLANE64_B32 ||
530 Opcode == AMDGPU::V_PERMLANEX16_B32_e64 ||
531 Opcode == AMDGPU::V_PERMLANE16_VAR_B32_e64 ||
532 Opcode == AMDGPU::V_PERMLANEX16_VAR_B32_e64 ||
533 Opcode == AMDGPU::V_PERMLANE16_SWAP_B32_e32 ||
534 Opcode == AMDGPU::V_PERMLANE16_SWAP_B32_e64 ||
535 Opcode == AMDGPU::V_PERMLANE32_SWAP_B32_e32 ||
536 Opcode == AMDGPU::V_PERMLANE32_SWAP_B32_e64 ||
537 Opcode == AMDGPU::V_PERMLANE_BCAST_B32_e64 ||
538 Opcode == AMDGPU::V_PERMLANE_UP_B32_e64 ||
539 Opcode == AMDGPU::V_PERMLANE_DOWN_B32_e64 ||
540 Opcode == AMDGPU::V_PERMLANE_XOR_B32_e64 ||
541 Opcode == AMDGPU::V_PERMLANE_IDX_GEN_B32_e64;
542}
543
544static bool isLdsDma(const MachineInstr &MI) {
545 return SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true) &&
547}
548
549static unsigned getHWReg(const SIInstrInfo *TII, const MachineInstr &RegInstr) {
550 const MachineOperand *RegOp = TII->getNamedOperand(RegInstr,
551 AMDGPU::OpName::simm16);
552 return std::get<0>(AMDGPU::Hwreg::HwregEncoding::decode(RegOp->getImm()));
553}
554
557 MachineInstr *MI = SU->getInstr();
558 // If we are not in "HazardRecognizerMode" and therefore not being run from
559 // the scheduler, track possible stalls from hazards but don't insert noops.
561
562 if (MI->isBundle())
563 return NoHazard;
564
565 // Check co-execution slot hazards and pipeline stalls in scheduler modes.
566 if (isSchedulerMode()) {
567 if (checkMultiShadowHazard(*MI) > 0)
568 return Hazard;
569 if (checkWMMACoexecSlot(*MI) > 0)
570 return Hazard;
571 if (checkTRANSHazard(*MI) > 0)
572 return Hazard;
573 if (checkMultiCycleVALUHazard(*MI) > 0)
574 return Hazard;
575 // The remaining checks are all defined by register dependences.
576 if (!hasPhysRegs())
577 return NoHazard;
578 }
579
580 if (SIInstrInfo::isSMRD(*MI) && checkSMRDHazards(MI) > 0)
581 return HazardType;
582
583 if (ST.hasNSAtoVMEMBug() && checkNSAtoVMEMHazard(MI) > 0)
584 return HazardType;
585
586 if (checkFPAtomicToDenormModeHazard(MI) > 0)
587 return HazardType;
588
589 // Hazards which cannot be mitigated with S_NOPs.
590 if (!isHazardRecognizerMode()) {
591 if (checkWMMACoexecutionHazards(MI) > 0) {
592 HasPendingWMMACoexecHazard = true;
593 return Hazard;
594 }
595 }
596
597 if (ST.hasNoDataDepHazard())
598 return NoHazard;
599
600 if (SIInstrInfo::isVMEM(*MI) && checkVMEMHazards(MI) > 0)
601 return HazardType;
602
603 if (SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true) &&
604 checkVALUHazards(MI) > 0)
605 return HazardType;
606
607 if (SIInstrInfo::isDPP(*MI) && checkDPPHazards(MI) > 0)
608 return HazardType;
609
610 if (isDivFMas(MI->getOpcode()) && checkDivFMasHazards(MI) > 0)
611 return HazardType;
612
613 if (isRWLane(MI->getOpcode()) && checkRWLaneHazards(MI) > 0)
614 return HazardType;
615
616 if ((SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true) ||
619 checkMAIVALUHazards(MI) > 0)
620 return HazardType;
621
622 if (isSGetReg(MI->getOpcode()) && checkGetRegHazards(MI) > 0)
623 return HazardType;
624
625 if (isSSetReg(MI->getOpcode()) && checkSetRegHazards(MI) > 0)
626 return HazardType;
627
628 if (isRFE(MI->getOpcode()) && checkRFEHazards(MI) > 0)
629 return HazardType;
630
631 if (((ST.hasReadM0MovRelInterpHazard() &&
632 (TII.isVINTRP(*MI) || isSMovRel(MI->getOpcode()) ||
633 MI->getOpcode() == AMDGPU::DS_WRITE_ADDTID_B32 ||
634 MI->getOpcode() == AMDGPU::DS_READ_ADDTID_B32)) ||
635 (ST.hasReadM0SendMsgHazard() && isSendMsgTraceDataOrGDS(TII, *MI)) ||
636 (ST.hasReadM0LdsDmaHazard() && isLdsDma(*MI)) ||
637 (ST.hasReadM0LdsDirectHazard() &&
638 MI->readsRegister(AMDGPU::LDS_DIRECT, /*TRI=*/nullptr))) &&
639 checkReadM0Hazards(MI) > 0)
640 return HazardType;
641
642 if (SIInstrInfo::isMAI(*MI) && checkMAIHazards(MI) > 0)
643 return HazardType;
644
646 checkMAILdStHazards(MI) > 0)
647 return HazardType;
648
649 if (MI->isInlineAsm() && checkInlineAsmHazards(MI) > 0)
650 return HazardType;
651
652 return NoHazard;
653}
654
656 unsigned Quantity) {
657 while (Quantity > 0) {
658 unsigned Arg = std::min(Quantity, 8u);
659 Quantity -= Arg;
660 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), TII.get(AMDGPU::S_NOP))
661 .addImm(Arg - 1);
662 }
663}
664
665unsigned
666GCNHazardRecognizer::getMFMAPipelineWaitStates(const MachineInstr &MI) const {
667 const MCSchedClassDesc *SC = TSchedModel.resolveSchedClass(&MI);
668 assert(TSchedModel.getWriteProcResBegin(SC) !=
669 TSchedModel.getWriteProcResEnd(SC));
670 return TSchedModel.getWriteProcResBegin(SC)->ReleaseAtCycle;
671}
672
673void GCNHazardRecognizer::processBundle() {
674 MachineBasicBlock::instr_iterator MI = std::next(CurrCycleInstr->getIterator());
675 MachineBasicBlock::instr_iterator E = CurrCycleInstr->getParent()->instr_end();
676 // Check bundled MachineInstr's for hazards.
677 for (; MI != E && MI->isInsideBundle(); ++MI) {
678 CurrCycleInstr = &*MI;
679 unsigned WaitStates = PreEmitNoopsCommon(CurrCycleInstr);
680
682 fixHazards(CurrCycleInstr);
683
684 insertNoopsInBundle(CurrCycleInstr, TII, WaitStates);
685 }
686
687 // It’s unnecessary to track more than MaxLookAhead instructions. Since we
688 // include the bundled MI directly after, only add a maximum of
689 // (MaxLookAhead - 1) noops to EmittedInstrs.
690 for (unsigned i = 0, e = std::min(WaitStates, MaxLookAhead - 1); i < e; ++i)
691 EmittedInstrs.push_front(nullptr);
692
693 EmittedInstrs.push_front(CurrCycleInstr);
694 EmittedInstrs.resize(MaxLookAhead);
695 }
696 CurrCycleInstr = nullptr;
697}
698
699void GCNHazardRecognizer::runOnInstruction(MachineInstr *MI) {
701
702 unsigned NumPreNoops = PreEmitNoops(MI);
703 EmitNoops(NumPreNoops);
704 if (MI->isInsideBundle())
705 insertNoopsInBundle(MI, TII, NumPreNoops);
706 else
707 TII.insertNoops(*MI->getParent(), MachineBasicBlock::iterator(MI),
708 NumPreNoops);
710 AdvanceCycle();
711}
712
715 CurrCycleInstr = MI;
716 unsigned W = PreEmitNoopsCommon(MI);
717 fixHazards(MI);
718 CurrCycleInstr = nullptr;
719 return std::max(W, NopPadding.getValue());
720}
721
723 unsigned W = 0;
724
725 // Check co-execution slot hazards and pipeline stalls in scheduler modes.
726 if (isSchedulerMode()) {
727 W = checkWMMACoexecSlot(*MI);
728 W = std::max(W, checkTRANSHazard(*MI));
729 W = std::max(W, checkMultiCycleVALUHazard(*MI));
730 W = std::max(W, checkMultiShadowHazard(*MI));
731 // The remaining checks are all defined by register dependences.
732 if (!hasPhysRegs())
733 return W;
734 }
735
736 return std::max(W, PreEmitNoopsCommon(MI));
737}
738
740 if (MI->isBundle())
741 return 0;
742
743 int WaitStates = 0;
744
746 return std::max(WaitStates, checkSMRDHazards(MI));
747
748 if (ST.hasNSAtoVMEMBug())
749 WaitStates = std::max(WaitStates, checkNSAtoVMEMHazard(MI));
750
751 WaitStates = std::max(WaitStates, checkFPAtomicToDenormModeHazard(MI));
752
753 if (ST.hasNoDataDepHazard())
754 return WaitStates;
755
757 WaitStates = std::max(WaitStates, checkVMEMHazards(MI));
758
759 if (SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true))
760 WaitStates = std::max(WaitStates, checkVALUHazards(MI));
761
763 WaitStates = std::max(WaitStates, checkDPPHazards(MI));
764
765 if (isDivFMas(MI->getOpcode()))
766 WaitStates = std::max(WaitStates, checkDivFMasHazards(MI));
767
768 if (isRWLane(MI->getOpcode()))
769 WaitStates = std::max(WaitStates, checkRWLaneHazards(MI));
770
771 if ((SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true) ||
774 checkMAIVALUHazards(MI) > 0)
775 WaitStates = std::max(WaitStates, checkMAIVALUHazards(MI));
776
777 if (MI->isInlineAsm())
778 return std::max(WaitStates, checkInlineAsmHazards(MI));
779
780 if (isSGetReg(MI->getOpcode()))
781 return std::max(WaitStates, checkGetRegHazards(MI));
782
783 if (isSSetReg(MI->getOpcode()))
784 return std::max(WaitStates, checkSetRegHazards(MI));
785
786 if (isRFE(MI->getOpcode()))
787 return std::max(WaitStates, checkRFEHazards(MI));
788
789 if ((ST.hasReadM0MovRelInterpHazard() &&
790 (TII.isVINTRP(*MI) || isSMovRel(MI->getOpcode()) ||
791 MI->getOpcode() == AMDGPU::DS_WRITE_ADDTID_B32 ||
792 MI->getOpcode() == AMDGPU::DS_READ_ADDTID_B32)) ||
793 (ST.hasReadM0SendMsgHazard() && isSendMsgTraceDataOrGDS(TII, *MI)) ||
794 (ST.hasReadM0LdsDmaHazard() && isLdsDma(*MI)) ||
795 (ST.hasReadM0LdsDirectHazard() &&
796 MI->readsRegister(AMDGPU::LDS_DIRECT, /*TRI=*/nullptr)))
797 return std::max(WaitStates, checkReadM0Hazards(MI));
798
800 return std::max(WaitStates, checkMAIHazards(MI));
801
803 return std::max(WaitStates, checkMAILdStHazards(MI));
804
805 if (ST.hasGFX950Insts() && isPermlane(*MI))
806 return std::max(WaitStates, checkPermlaneHazards(MI));
807
808 return WaitStates;
809}
810
812 EmittedInstrs.push_front(nullptr);
813}
814
816 if (isSchedulerMode())
817 schedulerAdvanceCycle();
818
819 // When the scheduler detects a stall, it will call AdvanceCycle() without
820 // emitting any instructions.
821 if (!CurrCycleInstr) {
822 EmittedInstrs.push_front(nullptr);
823
824 if (HasPendingWMMACoexecHazard)
825 EmittedVALUInstrs.push_front(nullptr);
826 return;
827 }
828
829 HasPendingWMMACoexecHazard = false;
830
831 if (CurrCycleInstr->isBundle()) {
832 processBundle();
833 return;
834 }
835
836 unsigned NumWaitStates = TII.getNumWaitStates(*CurrCycleInstr);
837 if (!NumWaitStates) {
838 CurrCycleInstr = nullptr;
839 return;
840 }
841
842 // Keep track of emitted instructions
843 EmittedInstrs.push_front(CurrCycleInstr);
844
845 bool IsVALUOrWMMA =
846 SIInstrInfo::isVALU(*CurrCycleInstr, /*AllowLDSDMA=*/true) ||
847 SIInstrInfo::isWMMA(*CurrCycleInstr) ||
848 SIInstrInfo::isSWMMAC(*CurrCycleInstr);
849 if (IsVALUOrWMMA) {
850 EmittedVALUInstrs.push_front(CurrCycleInstr);
851 } else {
852 // A pending WMMA co-execution hazard optimistically records stall cycles as
853 // future V_NOPs. If the scheduler instead stalls for a different
854 // (S_NOP-resolvable) hazard and schedules a non-VALU into those cycles,
855 // they will not resolve the VALU-pipe hazard, so drop them here.
856 while (!EmittedVALUInstrs.empty() && EmittedVALUInstrs.front() == nullptr)
857 EmittedVALUInstrs.pop_front();
858 }
859
860 // Add a nullptr for each additional wait state after the first. Make sure
861 // not to add more than getMaxLookAhead() items to the list, since we
862 // truncate the list to that size right after this loop.
863 for (unsigned i = 1, e = std::min(NumWaitStates, getMaxLookAhead());
864 i < e; ++i) {
865 EmittedInstrs.push_front(nullptr);
866 }
867
868 // getMaxLookahead() is the largest number of wait states we will ever need
869 // to insert, so there is no point in keeping track of more than that many
870 // wait states.
871 EmittedInstrs.resize(getMaxLookAhead());
872 if (EmittedVALUInstrs.size() > MaxVALULookAhead)
873 EmittedVALUInstrs.resize(MaxVALULookAhead);
874
875 CurrCycleInstr = nullptr;
876}
877
880 "Bottom-up scheduling shouldn't run in hazard recognizer mode");
881}
882
883//===----------------------------------------------------------------------===//
884// Helper Functions
885//===----------------------------------------------------------------------===//
886
888
889// Search for a hazard in a block and its predecessors.
890template <typename StateT>
891static bool
892hasHazard(StateT InitialState,
893 function_ref<HazardFnResult(StateT &, const MachineInstr &)> IsHazard,
894 function_ref<void(StateT &, const MachineInstr &)> UpdateState,
895 const MachineBasicBlock *InitialMBB,
897 struct StateMapKey {
899 unsigned Idx;
900 static bool isEqual(const StateMapKey &LHS, const StateMapKey &RHS) {
901 return LHS.States == RHS.States && LHS.Idx == RHS.Idx;
902 }
903 };
904 struct StateMapKeyTraits : DenseMapInfo<StateMapKey> {
905 static unsigned getHashValue(const StateMapKey &Key) {
906 return StateT::getHashValue((*Key.States)[Key.Idx]);
907 }
908 static unsigned getHashValue(const StateT &State) {
909 return StateT::getHashValue(State);
910 }
911 static bool isEqual(const StateMapKey &LHS, const StateMapKey &RHS) {
912 return StateT::isEqual((*LHS.States)[LHS.Idx], (*RHS.States)[RHS.Idx]);
913 }
914 static bool isEqual(const StateT &LHS, const StateMapKey &RHS) {
915 return StateT::isEqual(LHS, (*RHS.States)[RHS.Idx]);
916 }
917 };
918
921
923 const MachineBasicBlock *MBB = InitialMBB;
924 StateT State = InitialState;
925
927 unsigned WorkIdx = 0;
928 for (;;) {
929 bool Expired = false;
930 for (auto E = MBB->instr_rend(); I != E; ++I) {
931 // No need to look at parent BUNDLE instructions.
932 if (I->isBundle())
933 continue;
934
935 auto Result = IsHazard(State, *I);
936 if (Result == HazardFound)
937 return true;
938 if (Result == HazardExpired) {
939 Expired = true;
940 break;
941 }
942
943 if (I->isInlineAsm() || I->isMetaInstruction())
944 continue;
945
946 UpdateState(State, *I);
947 }
948
949 if (!Expired) {
950 unsigned StateIdx = States.size();
951 StateMapKey Key = {&States, StateIdx};
952 auto Insertion = StateMap.insert_as(std::pair(Key, StateIdx), State);
953 if (Insertion.second) {
954 States.emplace_back(State);
955 } else {
956 StateIdx = Insertion.first->second;
957 }
958 for (MachineBasicBlock *Pred : MBB->predecessors())
959 Worklist.insert(std::pair(Pred, StateIdx));
960 }
961
962 if (WorkIdx == Worklist.size())
963 break;
964
965 unsigned StateIdx;
966 std::tie(MBB, StateIdx) = Worklist[WorkIdx++];
967 State = States[StateIdx];
968 I = MBB->instr_rbegin();
969 }
970
971 return false;
972}
973
974// Returns a minimum wait states since \p I walking all predecessors.
975// Only scans until \p IsExpired does not return true.
976// Can only be run in a hazard recognizer mode.
977static int
979 const MachineBasicBlock *MBB,
981 int WaitStates, GCNHazardRecognizer::IsExpiredFn IsExpired,
985 for (auto E = MBB->instr_rend(); I != E; ++I) {
986 // Don't add WaitStates for parent BUNDLE instructions.
987 if (I->isBundle())
988 continue;
989
990 if (IsHazard(*I))
991 return WaitStates;
992
993 if (I->isInlineAsm())
994 continue;
995
996 WaitStates += GetNumWaitStates(*I);
997
998 if (IsExpired(*I, WaitStates))
999 return std::numeric_limits<int>::max();
1000 }
1001
1002 int MinWaitStates = std::numeric_limits<int>::max();
1003 for (MachineBasicBlock *Pred : MBB->predecessors()) {
1004 if (!Visited.insert(Pred).second)
1005 continue;
1006
1007 int W = getWaitStatesSince(IsHazard, Pred, Pred->instr_rbegin(), WaitStates,
1008 IsExpired, Visited, GetNumWaitStates);
1009
1010 MinWaitStates = std::min(MinWaitStates, W);
1011 }
1012
1013 return MinWaitStates;
1014}
1015
1016static int
1018 const MachineInstr *MI,
1023 return getWaitStatesSince(IsHazard, MI->getParent(),
1024 std::next(MI->getReverseIterator()), 0, IsExpired,
1025 Visited, GetNumWaitStates);
1026}
1027
1028int GCNHazardRecognizer::getWaitStatesSince(
1029 IsHazardFn IsHazard, int Limit, GetNumWaitStatesFn GetNumWaitStates) const {
1030 if (isHazardRecognizerMode()) {
1031 auto IsExpiredFn = [Limit](const MachineInstr &, int WaitStates) {
1032 return WaitStates >= Limit;
1033 };
1034 return ::getWaitStatesSince(IsHazard, CurrCycleInstr, IsExpiredFn,
1035 GetNumWaitStates);
1036 }
1037
1038 int WaitStates = 0;
1039 for (MachineInstr *MI : EmittedInstrs) {
1040 if (MI) {
1041 if (IsHazard(*MI))
1042 return WaitStates;
1043
1044 if (MI->isInlineAsm())
1045 continue;
1046 }
1047 WaitStates += MI ? GetNumWaitStates(*MI) : 1;
1048
1049 if (WaitStates >= Limit)
1050 break;
1051 }
1052 return std::numeric_limits<int>::max();
1053}
1054
1055int GCNHazardRecognizer::getWaitStatesSince(IsHazardFn IsHazard,
1056 int Limit) const {
1057 return getWaitStatesSince(IsHazard, Limit, SIInstrInfo::getNumWaitStates);
1058}
1059
1060int GCNHazardRecognizer::getWaitStatesSinceVALU(IsHazardFn IsHazard,
1061 int Limit) const {
1062 if (isHazardRecognizerMode()) {
1063 auto GetVALUWaitStates = [](const MachineInstr &MI) -> unsigned {
1064 return SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true) ? 1 : 0;
1065 };
1066 return getWaitStatesSince(IsHazard, Limit, GetVALUWaitStates);
1067 }
1068
1069 // EmittedVALUInstrs is capped at MaxVALULookAhead, so a Limit beyond that
1070 // window could miss a hazard. Keep the cap in sync with the wait-state
1071 // tables.
1072 assert(Limit <= (int)MaxVALULookAhead &&
1073 "Limit exceeds the EmittedVALUInstrs lookahead window");
1074 int WaitStates = 0;
1075 for (MachineInstr *MI : EmittedVALUInstrs) {
1076 if (MI) {
1077 if (IsHazard(*MI))
1078 return WaitStates;
1079 }
1080
1081 ++WaitStates;
1082
1083 if (WaitStates >= Limit)
1084 break;
1085 }
1086 return std::numeric_limits<int>::max();
1087}
1088
1089int GCNHazardRecognizer::getWaitStatesSinceDef(unsigned Reg,
1090 IsHazardFn IsHazardDef,
1091 int Limit) const {
1092 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1093
1094 auto IsHazardFn = [IsHazardDef, TRI, Reg](const MachineInstr &MI) {
1095 return IsHazardDef(MI) && MI.modifiesRegister(Reg, TRI);
1096 };
1097
1098 return getWaitStatesSince(IsHazardFn, Limit);
1099}
1100
1101int GCNHazardRecognizer::getWaitStatesSinceSetReg(IsHazardFn IsHazard,
1102 int Limit) const {
1103 auto IsHazardFn = [IsHazard](const MachineInstr &MI) {
1104 return isSSetReg(MI.getOpcode()) && IsHazard(MI);
1105 };
1106
1107 return getWaitStatesSince(IsHazardFn, Limit);
1108}
1109
1110//===----------------------------------------------------------------------===//
1111// No-op Hazard Detection
1112//===----------------------------------------------------------------------===//
1113
1114static void addRegUnits(const SIRegisterInfo &TRI, BitVector &BV,
1115 MCRegister Reg) {
1116 for (MCRegUnit Unit : TRI.regunits(Reg))
1117 BV.set(static_cast<unsigned>(Unit));
1118}
1119
1122 BitVector &DefSet, BitVector &UseSet) {
1123 for (const MachineOperand &Op : Ops) {
1124 if (Op.isReg())
1125 addRegUnits(TRI, Op.isDef() ? DefSet : UseSet, Op.getReg().asMCReg());
1126 }
1127}
1128
1129void GCNHazardRecognizer::addClauseInst(const MachineInstr &MI) const {
1130 addRegsToSet(TRI, MI.operands(), ClauseDefs, ClauseUses);
1131}
1132
1134 return !SIInstrInfo::isSMRD(*MI);
1135}
1136
1138 return !SIInstrInfo::isVMEM(*MI);
1139}
1140
1141int GCNHazardRecognizer::checkSoftClauseHazards(MachineInstr *MEM) const {
1142 // SMEM soft clause are only present on VI+, and only matter if xnack is
1143 // enabled.
1144 if (!ST.isXNACKEnabled())
1145 return 0;
1146
1147 bool IsSMRD = TII.isSMRD(*MEM);
1148
1149 resetClause();
1150
1151 // A soft-clause is any group of consecutive SMEM instructions. The
1152 // instructions in this group may return out of order and/or may be
1153 // replayed (i.e. the same instruction issued more than once).
1154 //
1155 // In order to handle these situations correctly we need to make sure that
1156 // when a clause has more than one instruction, no instruction in the clause
1157 // writes to a register that is read by another instruction in the clause
1158 // (including itself). If we encounter this situation, we need to break the
1159 // clause by inserting a non SMEM instruction.
1160
1161 for (MachineInstr *MI : EmittedInstrs) {
1162 // When we hit a non-SMEM instruction then we have passed the start of the
1163 // clause and we can stop.
1164 if (!MI)
1165 break;
1166
1168 break;
1169
1170 addClauseInst(*MI);
1171 }
1172
1173 if (ClauseDefs.none())
1174 return 0;
1175
1176 // We need to make sure not to put loads and stores in the same clause if they
1177 // use the same address. For now, just start a new clause whenever we see a
1178 // store.
1179 if (MEM->mayStore())
1180 return 1;
1181
1182 addClauseInst(*MEM);
1183
1184 // If the set of defs and uses intersect then we cannot add this instruction
1185 // to the clause, so we have a hazard.
1186 return ClauseDefs.anyCommon(ClauseUses) ? 1 : 0;
1187}
1188
1189int GCNHazardRecognizer::checkSMRDHazards(MachineInstr *SMRD) const {
1190 int WaitStatesNeeded = 0;
1191
1192 WaitStatesNeeded = checkSoftClauseHazards(SMRD);
1193
1194 // This SMRD hazard only affects SI.
1195 if (!ST.hasSMRDReadVALUDefHazard())
1196 return WaitStatesNeeded;
1197
1198 // A read of an SGPR by SMRD instruction requires 4 wait states when the
1199 // SGPR was written by a VALU instruction.
1200 int SmrdSgprWaitStates = 4;
1201 auto IsHazardDefFn = [this](const MachineInstr &MI) {
1202 return TII.isVALU(MI, /*AllowLDSDMA=*/true);
1203 };
1204 auto IsBufferHazardDefFn = [this](const MachineInstr &MI) {
1205 return TII.isSALU(MI);
1206 };
1207
1208 bool IsBufferSMRD = TII.isBufferSMRD(*SMRD);
1209
1210 for (const MachineOperand &Use : SMRD->uses()) {
1211 if (!Use.isReg())
1212 continue;
1213 int WaitStatesNeededForUse =
1214 SmrdSgprWaitStates - getWaitStatesSinceDef(Use.getReg(), IsHazardDefFn,
1215 SmrdSgprWaitStates);
1216 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1217
1218 // This fixes what appears to be undocumented hardware behavior in SI where
1219 // s_mov writing a descriptor and s_buffer_load_dword reading the descriptor
1220 // needs some number of nops in between. We don't know how many we need, but
1221 // let's use 4. This wasn't discovered before probably because the only
1222 // case when this happens is when we expand a 64-bit pointer into a full
1223 // descriptor and use s_buffer_load_dword instead of s_load_dword, which was
1224 // probably never encountered in the closed-source land.
1225 if (IsBufferSMRD) {
1226 int WaitStatesNeededForUse =
1227 SmrdSgprWaitStates - getWaitStatesSinceDef(Use.getReg(),
1228 IsBufferHazardDefFn,
1229 SmrdSgprWaitStates);
1230 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1231 }
1232 }
1233
1234 return WaitStatesNeeded;
1235}
1236
1237int GCNHazardRecognizer::checkVMEMHazards(MachineInstr *VMEM) const {
1238 if (!ST.hasVMEMReadSGPRVALUDefHazard())
1239 return 0;
1240
1241 int WaitStatesNeeded = checkSoftClauseHazards(VMEM);
1242
1243 // A read of an SGPR by a VMEM instruction requires 5 wait states when the
1244 // SGPR was written by a VALU Instruction.
1245 const int VmemSgprWaitStates = 5;
1246 auto IsHazardDefFn = [this](const MachineInstr &MI) {
1247 return TII.isVALU(MI, /*AllowLDSDMA=*/true);
1248 };
1249 for (const MachineOperand &Use : VMEM->uses()) {
1250 if (!Use.isReg() || TRI.isVectorRegister(MF.getRegInfo(), Use.getReg()))
1251 continue;
1252
1253 int WaitStatesNeededForUse =
1254 VmemSgprWaitStates - getWaitStatesSinceDef(Use.getReg(), IsHazardDefFn,
1255 VmemSgprWaitStates);
1256 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1257 }
1258 return WaitStatesNeeded;
1259}
1260
1261int GCNHazardRecognizer::checkDPPHazards(MachineInstr *DPP) const {
1262 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1263 const SIInstrInfo *TII = ST.getInstrInfo();
1264
1265 // Check for DPP VGPR read after VALU VGPR write and EXEC write.
1266 int DppVgprWaitStates = 2;
1267 int DppExecWaitStates = 5;
1268 int WaitStatesNeeded = 0;
1269 auto IsHazardDefFn = [TII](const MachineInstr &MI) {
1270 return TII->isVALU(MI, /*AllowLDSDMA=*/true);
1271 };
1272
1273 for (const MachineOperand &Use : DPP->uses()) {
1274 if (!Use.isReg() || !TRI->isVGPR(MF.getRegInfo(), Use.getReg()))
1275 continue;
1276 int WaitStatesNeededForUse =
1277 DppVgprWaitStates - getWaitStatesSinceDef(
1278 Use.getReg(),
1279 [](const MachineInstr &) { return true; },
1280 DppVgprWaitStates);
1281 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1282 }
1283
1284 WaitStatesNeeded = std::max(
1285 WaitStatesNeeded,
1286 DppExecWaitStates - getWaitStatesSinceDef(AMDGPU::EXEC, IsHazardDefFn,
1287 DppExecWaitStates));
1288
1289 return WaitStatesNeeded;
1290}
1291
1292int GCNHazardRecognizer::checkDivFMasHazards(MachineInstr *DivFMas) const {
1293 const SIInstrInfo *TII = ST.getInstrInfo();
1294
1295 // v_div_fmas requires 4 wait states after a write to vcc from a VALU
1296 // instruction.
1297 const int DivFMasWaitStates = 4;
1298 auto IsHazardDefFn = [TII](const MachineInstr &MI) {
1299 return TII->isVALU(MI, /*AllowLDSDMA=*/true);
1300 };
1301 int WaitStatesNeeded = getWaitStatesSinceDef(AMDGPU::VCC, IsHazardDefFn,
1302 DivFMasWaitStates);
1303
1304 return DivFMasWaitStates - WaitStatesNeeded;
1305}
1306
1307int GCNHazardRecognizer::checkGetRegHazards(MachineInstr *GetRegInstr) const {
1308 const SIInstrInfo *TII = ST.getInstrInfo();
1309 unsigned GetRegHWReg = getHWReg(TII, *GetRegInstr);
1310
1311 const int GetRegWaitStates = 2;
1312 auto IsHazardFn = [TII, GetRegHWReg](const MachineInstr &MI) {
1313 return GetRegHWReg == getHWReg(TII, MI);
1314 };
1315 int WaitStatesNeeded = getWaitStatesSinceSetReg(IsHazardFn, GetRegWaitStates);
1316
1317 return GetRegWaitStates - WaitStatesNeeded;
1318}
1319
1320int GCNHazardRecognizer::checkSetRegHazards(MachineInstr *SetRegInstr) const {
1321 const SIInstrInfo *TII = ST.getInstrInfo();
1322 unsigned HWReg = getHWReg(TII, *SetRegInstr);
1323
1324 const int SetRegWaitStates = ST.getSetRegWaitStates();
1325 auto IsHazardFn = [TII, HWReg](const MachineInstr &MI) {
1326 return HWReg == getHWReg(TII, MI);
1327 };
1328 int WaitStatesNeeded = getWaitStatesSinceSetReg(IsHazardFn, SetRegWaitStates);
1329 return SetRegWaitStates - WaitStatesNeeded;
1330}
1331
1332int GCNHazardRecognizer::createsVALUHazard(const MachineInstr &MI) const {
1333 if (!MI.mayStore())
1334 return -1;
1335
1336 const SIInstrInfo *TII = ST.getInstrInfo();
1337 unsigned Opcode = MI.getOpcode();
1338 const MCInstrDesc &Desc = MI.getDesc();
1339
1340 int VDataIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::vdata);
1341 int VDataRCID = -1;
1342 if (VDataIdx != -1)
1343 VDataRCID = TII->getOpRegClassID(Desc.operands()[VDataIdx]);
1344
1345 if (TII->isMUBUF(MI) || TII->isMTBUF(MI)) {
1346 // There is no hazard if the instruction does not use vector regs
1347 // (like wbinvl1)
1348 if (VDataIdx == -1)
1349 return -1;
1350 if (AMDGPU::getRegBitWidth(VDataRCID) > 64) {
1351 // When SOFFSET-dependent wide-store windows apply, the BUFFER_STORE
1352 // source-vgpr WAR hazard exists for every SOFFSET shape; the wait-state
1353 // count differs by SOFFSET and is computed in checkVALUHazardsHelper.
1354 // Otherwise the hazard only exists if soffset is not an SGPR.
1355 if (ST.hasVDecCoExecHazard())
1356 return VDataIdx;
1357 const MachineOperand *SOffset =
1358 TII->getNamedOperand(MI, AMDGPU::OpName::soffset);
1359 if (!SOffset || !SOffset->isReg())
1360 return VDataIdx;
1361 }
1362 }
1363
1364 // MIMG instructions create a hazard if they don't use a 256-bit T# and
1365 // the store size is greater than 8 bytes and they have more than two bits
1366 // of their dmask set.
1367 // All our MIMG definitions use a 256-bit T#, so we can skip checking for them.
1368 if (TII->isMIMG(MI)) {
1369 int SRsrcIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::srsrc);
1370 assert(SRsrcIdx != -1 && AMDGPU::getRegBitWidth(TII->getOpRegClassID(
1371 Desc.operands()[SRsrcIdx])) == 256);
1372 (void)SRsrcIdx;
1373 }
1374
1375 if (TII->isFLAT(MI)) {
1376 // There is no hazard if the instruction does not use vector regs
1377 if (VDataIdx == -1)
1378 return -1;
1379
1380 if (AMDGPU::getRegBitWidth(VDataRCID) > 64)
1381 return VDataIdx;
1382 }
1383
1384 return -1;
1385}
1386
1387int GCNHazardRecognizer::checkUniformWindowVALUHazardsHelper(
1388 Register Reg) const {
1389 // Wide stores need a single wait-state bubble before a VALU that overwrites
1390 // store data. createsVALUHazard already excludes MUBUF/MTBUF stores with an
1391 // SGPR SOFFSET.
1392 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1393
1394 auto IsHazard = [&](const MachineInstr &MI) {
1395 int DataIdx = createsVALUHazard(MI);
1396 return DataIdx >= 0 &&
1397 TRI->regsOverlap(MI.getOperand(DataIdx).getReg(), Reg);
1398 };
1399
1400 return std::max(0, 1 - getWaitStatesSince(IsHazard, /*Limit=*/1));
1401}
1402
1403int GCNHazardRecognizer::checkSOFFSETWindowVALUHazardsHelper(
1404 Register Reg) const {
1405 // The required wait-state window depends on the producer's SOFFSET shape:
1406 // - MUBUF/MTBUF wide store with sgpr SOFFSET: 1 wait state.
1407 // - MUBUF/MTBUF wide store with literal/absent SOFFSET, and FLAT wide
1408 // store: 2 wait states.
1409 // The 1-cycle sgpr-SOFFSET window was measured on gfx950.
1410 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1411 const SIInstrInfo *TII = ST.getInstrInfo();
1412
1413 int WaitStatesNeeded = 0;
1414
1415 // Scan each wait-state window separately and take the max padding needed.
1416 // getWaitStatesSince supplies the minimum distance to a producer over paths.
1417 for (int Window = 1; Window <= 2; ++Window) {
1418 auto IsHazard = [&](const MachineInstr &MI) {
1419 int DataIdx = createsVALUHazard(MI);
1420 if (DataIdx < 0 ||
1421 !TRI->regsOverlap(MI.getOperand(DataIdx).getReg(), Reg))
1422 return false;
1423
1424 // Window 1 matches every hazard producer. Window 2 excludes BUF stores
1425 // with an SGPR SOFFSET, which only require a single wait state.
1426 if (Window == 1 || !TII->isBUF(MI))
1427 return true;
1428
1429 const MachineOperand *SOffset =
1430 TII->getNamedOperand(MI, AMDGPU::OpName::soffset);
1431 return !SOffset || !SOffset->isReg();
1432 };
1433 WaitStatesNeeded = std::max(WaitStatesNeeded,
1434 Window - getWaitStatesSince(IsHazard, Window));
1435 }
1436
1437 return WaitStatesNeeded;
1438}
1439
1440int GCNHazardRecognizer::checkVALUHazardsHelper(
1441 const MachineOperand &Def, const MachineRegisterInfo &MRI) const {
1442 // Helper to check for the hazard where VMEM instructions that store more
1443 // than 8 bytes can have their store data overwritten by the next
1444 // instruction.
1445 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1446
1447 if (!TRI->isVectorRegister(MRI, Def.getReg()))
1448 return 0;
1449
1450 if (ST.hasVDecCoExecHazard())
1451 return checkSOFFSETWindowVALUHazardsHelper(Def.getReg());
1452
1453 return checkUniformWindowVALUHazardsHelper(Def.getReg());
1454}
1455
1456/// Dest sel forwarding issue occurs if additional logic is needed to swizzle /
1457/// pack the computed value into correct bit position of the dest register. This
1458/// occurs if we have SDWA with dst_sel != DWORD or if we have op_sel with
1459/// dst_sel that is not aligned to the register. This function analayzes the \p
1460/// MI and \returns an operand with dst forwarding issue, or nullptr if
1461/// none exists.
1462static const MachineOperand *
1464 if (!SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true))
1465 return nullptr;
1466
1467 const SIInstrInfo *TII = ST.getInstrInfo();
1468
1469 unsigned Opcode = MI.getOpcode();
1470
1471 // There are three different types of instructions
1472 // which produce forwarded dest: 1. SDWA with dst_sel != DWORD, 2. VOP3
1473 // which write hi bits (e.g. op_sel[3] == 1), and 3. FP8DstSelInst
1474 // (instructions with dest byte sel, e.g. CVT_SR_BF8_F32) and
1475 // op_sel[3:2]
1476 // != 0
1477 if (SIInstrInfo::isSDWA(MI)) {
1478 // Type 1: SDWA with dst_sel != DWORD
1479 if (auto *DstSel = TII->getNamedOperand(MI, AMDGPU::OpName::dst_sel))
1480 if (DstSel->getImm() != AMDGPU::SDWA::DWORD)
1481 return TII->getNamedOperand(MI, AMDGPU::OpName::vdst);
1482 }
1483
1484 AMDGPU::FPType IsFP4OrFP8ConvOpc = AMDGPU::getFPDstSelType(Opcode);
1485 if (AMDGPU::hasNamedOperand(Opcode, AMDGPU::OpName::op_sel)) {
1486 // Type 2: VOP3 which write the hi bits
1487 if (TII->getNamedImmOperand(MI, AMDGPU::OpName::src0_modifiers) &
1489 return TII->getNamedOperand(MI, AMDGPU::OpName::vdst);
1490
1491 // Type 3: FP8DstSelInst with op_sel[3:2] != 0)
1492 if (IsFP4OrFP8ConvOpc == AMDGPU::FPType::FP8 &&
1493 (TII->getNamedImmOperand(MI, AMDGPU::OpName::src2_modifiers) &
1495 return TII->getNamedOperand(MI, AMDGPU::OpName::vdst);
1496 }
1497
1498 // Special case: nop is required for all the opsel values for fp4 sr variant
1499 // cvt scale instructions
1500 if (IsFP4OrFP8ConvOpc == AMDGPU::FPType::FP4)
1501 return TII->getNamedOperand(MI, AMDGPU::OpName::vdst);
1502
1503 return nullptr;
1504}
1505
1506/// Checks whether the provided \p MI "consumes" the operand with a Dest sel
1507/// fowarding issue \p Dst . We may "consume" the Dst via a standard explicit
1508/// RAW, or through irregular ways (e.g implicit RAW, certain types of WAW)
1510 const MachineOperand *Dst,
1511 const SIRegisterInfo *TRI) {
1512 // We must consider implicit reads of the VALU. SDWA with dst_sel and
1513 // UNUSED_PRESERVE will implicitly read the result from forwarded dest,
1514 // and we must account for that hazard.
1515 // We also must account for WAW hazards. In particular, WAW with dest
1516 // preserve semantics (e.g. VOP3 with op_sel, VOP2 &&
1517 // !zeroesHigh16BitsOfDest) will read the forwarded dest for parity
1518 // check for ECC. Without accounting for this hazard, the ECC will be
1519 // wrong.
1520 // TODO: limit to RAW (including implicit reads) + problematic WAW (i.e.
1521 // complete zeroesHigh16BitsOfDest)
1522 for (auto &Operand : VALU->operands()) {
1523 if (Operand.isReg() && TRI->regsOverlap(Dst->getReg(), Operand.getReg())) {
1524 return true;
1525 }
1526 }
1527 return false;
1528}
1529
1530int GCNHazardRecognizer::checkVALUHazards(MachineInstr *VALU) const {
1531 int WaitStatesNeeded = 0;
1532
1533 if (ST.hasTransForwardingHazard() && !SIInstrInfo::isTRANS(*VALU)) {
1534 const int TransDefWaitstates = 1;
1535
1536 auto IsTransDefFn = [this, VALU](const MachineInstr &MI) {
1538 return false;
1539 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1540 const SIInstrInfo *TII = ST.getInstrInfo();
1541 Register Def = TII->getNamedOperand(MI, AMDGPU::OpName::vdst)->getReg();
1542
1543 for (const MachineOperand &Use : VALU->explicit_uses()) {
1544 if (Use.isReg() && TRI->regsOverlap(Def, Use.getReg()))
1545 return true;
1546 }
1547
1548 return false;
1549 };
1550
1551 int WaitStatesNeededForDef =
1552 TransDefWaitstates -
1553 getWaitStatesSince(IsTransDefFn, TransDefWaitstates);
1554 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1555 }
1556
1557 if (ST.hasDstSelForwardingHazard() || ST.hasCvtScaleForwardingHazard()) {
1558 const int Shift16DefWaitstates = 1;
1559
1560 auto IsShift16BitDefFn = [this, VALU](const MachineInstr &ProducerMI) {
1561 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1562 const MachineOperand *ForwardedDst =
1563 getDstSelForwardingOperand(ProducerMI, ST);
1564 if (ForwardedDst) {
1565 return consumesDstSelForwardingOperand(VALU, ForwardedDst, TRI);
1566 }
1567
1568 if (ProducerMI.isInlineAsm()) {
1569 // Assume inline asm has dst forwarding hazard
1570 for (auto &Def : ProducerMI.all_defs()) {
1571 if (consumesDstSelForwardingOperand(VALU, &Def, TRI))
1572 return true;
1573 }
1574 }
1575
1576 return false;
1577 };
1578
1579 int WaitStatesNeededForDef =
1580 Shift16DefWaitstates -
1581 getWaitStatesSince(IsShift16BitDefFn, Shift16DefWaitstates);
1582 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1583 }
1584
1585 if (ST.hasVDecCoExecHazard()) {
1586 const int VALUWriteSGPRVALUReadWaitstates = 2;
1587 const int VALUWriteEXECRWLane = 4;
1588 const int VALUWriteVGPRReadlaneRead = 1;
1589
1590 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1591 const MachineRegisterInfo &MRI = MF.getRegInfo();
1593 auto IsVALUDefSGPRFn = [&UseReg, TRI](const MachineInstr &MI) {
1594 if (!SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true))
1595 return false;
1596 return MI.modifiesRegister(UseReg, TRI);
1597 };
1598
1599 for (const MachineOperand &Use : VALU->explicit_uses()) {
1600 if (!Use.isReg())
1601 continue;
1602
1603 UseReg = Use.getReg();
1604 if (TRI->isSGPRReg(MRI, UseReg)) {
1605 int WaitStatesNeededForDef =
1606 VALUWriteSGPRVALUReadWaitstates -
1607 getWaitStatesSince(IsVALUDefSGPRFn,
1608 VALUWriteSGPRVALUReadWaitstates);
1609 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1610 }
1611 }
1612
1613 if (VALU->readsRegister(AMDGPU::VCC, TRI)) {
1614 UseReg = AMDGPU::VCC;
1615 int WaitStatesNeededForDef =
1616 VALUWriteSGPRVALUReadWaitstates -
1617 getWaitStatesSince(IsVALUDefSGPRFn, VALUWriteSGPRVALUReadWaitstates);
1618 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1619 }
1620
1621 switch (VALU->getOpcode()) {
1622 case AMDGPU::V_READLANE_B32:
1623 case AMDGPU::V_READFIRSTLANE_B32: {
1624 MachineOperand *Src = TII.getNamedOperand(*VALU, AMDGPU::OpName::src0);
1625 UseReg = Src->getReg();
1626 int WaitStatesNeededForDef =
1627 VALUWriteVGPRReadlaneRead -
1628 getWaitStatesSince(IsVALUDefSGPRFn, VALUWriteVGPRReadlaneRead);
1629 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1630 }
1631 [[fallthrough]];
1632 case AMDGPU::V_WRITELANE_B32: {
1633 UseReg = AMDGPU::EXEC;
1634 int WaitStatesNeededForDef =
1635 VALUWriteEXECRWLane -
1636 getWaitStatesSince(IsVALUDefSGPRFn, VALUWriteEXECRWLane);
1637 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1638 break;
1639 }
1640 default:
1641 break;
1642 }
1643 }
1644
1645 // This checks for the hazard where VMEM instructions that store more than
1646 // 8 bytes can have there store data over written by the next instruction.
1647 if (!ST.has12DWordStoreHazard())
1648 return WaitStatesNeeded;
1649
1650 const MachineRegisterInfo &MRI = MF.getRegInfo();
1651
1652 for (const MachineOperand &Def : VALU->defs()) {
1653 WaitStatesNeeded = std::max(WaitStatesNeeded, checkVALUHazardsHelper(Def, MRI));
1654 }
1655
1656 return WaitStatesNeeded;
1657}
1658
1659int GCNHazardRecognizer::checkInlineAsmHazards(MachineInstr *IA) const {
1660 // This checks for hazards associated with inline asm statements.
1661 // Since inline asms can contain just about anything, we use this
1662 // to call/leverage other check*Hazard routines. Note that
1663 // this function doesn't attempt to address all possible inline asm
1664 // hazards (good luck), but is a collection of what has been
1665 // problematic thus far.
1666
1667 // see checkVALUHazards()
1668 if (!ST.has12DWordStoreHazard() && !ST.hasDstSelForwardingHazard() &&
1669 !ST.hasCvtScaleForwardingHazard())
1670 return 0;
1671
1672 const MachineRegisterInfo &MRI = MF.getRegInfo();
1673 int WaitStatesNeeded = 0;
1674
1675 for (const MachineOperand &Op :
1677 if (Op.isReg() && Op.isDef()) {
1678 if (!TRI.isVectorRegister(MRI, Op.getReg()))
1679 continue;
1680
1681 if (ST.has12DWordStoreHazard()) {
1682 WaitStatesNeeded =
1683 std::max(WaitStatesNeeded, checkVALUHazardsHelper(Op, MRI));
1684 }
1685 }
1686 }
1687
1688 if (ST.hasDstSelForwardingHazard()) {
1689 const int Shift16DefWaitstates = 1;
1690
1691 auto IsShift16BitDefFn = [this, &IA](const MachineInstr &ProducerMI) {
1692 const MachineOperand *Dst = getDstSelForwardingOperand(ProducerMI, ST);
1693 // Assume inline asm reads the dst
1694 if (Dst)
1695 return IA->modifiesRegister(Dst->getReg(), &TRI) ||
1696 IA->readsRegister(Dst->getReg(), &TRI);
1697
1698 if (ProducerMI.isInlineAsm()) {
1699 // If MI is inline asm, assume it has dst forwarding hazard
1700 for (auto &Def : ProducerMI.all_defs()) {
1701 if (IA->modifiesRegister(Def.getReg(), &TRI) ||
1702 IA->readsRegister(Def.getReg(), &TRI)) {
1703 return true;
1704 }
1705 }
1706 }
1707
1708 return false;
1709 };
1710
1711 int WaitStatesNeededForDef =
1712 Shift16DefWaitstates -
1713 getWaitStatesSince(IsShift16BitDefFn, Shift16DefWaitstates);
1714 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1715 }
1716
1717 return WaitStatesNeeded;
1718}
1719
1720int GCNHazardRecognizer::checkRWLaneHazards(MachineInstr *RWLane) const {
1721 const SIInstrInfo *TII = ST.getInstrInfo();
1722 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1723 const MachineRegisterInfo &MRI = MF.getRegInfo();
1724
1725 const MachineOperand *LaneSelectOp =
1726 TII->getNamedOperand(*RWLane, AMDGPU::OpName::src1);
1727
1728 if (!LaneSelectOp->isReg() || !TRI->isSGPRReg(MRI, LaneSelectOp->getReg()))
1729 return 0;
1730
1731 Register LaneSelectReg = LaneSelectOp->getReg();
1732 auto IsHazardFn = [TII](const MachineInstr &MI) {
1733 return TII->isVALU(MI, /*AllowLDSDMA=*/true);
1734 };
1735
1736 const int RWLaneWaitStates = 4;
1737 int WaitStatesSince = getWaitStatesSinceDef(LaneSelectReg, IsHazardFn,
1738 RWLaneWaitStates);
1739 return RWLaneWaitStates - WaitStatesSince;
1740}
1741
1742int GCNHazardRecognizer::checkRFEHazards(MachineInstr *RFE) const {
1743 if (!ST.hasRFEHazards())
1744 return 0;
1745
1746 const SIInstrInfo *TII = ST.getInstrInfo();
1747
1748 const int RFEWaitStates = 1;
1749
1750 auto IsHazardFn = [TII](const MachineInstr &MI) {
1751 return getHWReg(TII, MI) == AMDGPU::Hwreg::ID_TRAPSTS;
1752 };
1753 int WaitStatesNeeded = getWaitStatesSinceSetReg(IsHazardFn, RFEWaitStates);
1754 return RFEWaitStates - WaitStatesNeeded;
1755}
1756
1757int GCNHazardRecognizer::checkReadM0Hazards(MachineInstr *MI) const {
1758 const SIInstrInfo *TII = ST.getInstrInfo();
1759 const int ReadM0WaitStates = 1;
1760 auto IsHazardFn = [TII](const MachineInstr &MI) { return TII->isSALU(MI); };
1761 return ReadM0WaitStates -
1762 getWaitStatesSinceDef(AMDGPU::M0, IsHazardFn, ReadM0WaitStates);
1763}
1764
1765void GCNHazardRecognizer::emitVNops(MachineBasicBlock &MBB,
1767 int WaitStatesNeeded, bool IsHoisting) {
1768 const DebugLoc &DL = IsHoisting ? DebugLoc() : InsertPt->getDebugLoc();
1769 for (int I = 0; I < WaitStatesNeeded; ++I)
1770 BuildMI(MBB, InsertPt, DL, TII.get(AMDGPU::V_NOP_e32));
1771}
1772
1773void GCNHazardRecognizer::fixHazards(MachineInstr *MI) {
1774 fixVMEMtoScalarWriteHazards(MI);
1775 fixVcmpxPermlaneHazards(MI);
1776 fixSMEMtoVectorWriteHazards(MI);
1777 fixVcmpxExecWARHazard(MI);
1778 fixLdsBranchVmemWARHazard(MI);
1779 if (ST.hasLdsDirect()) {
1780 fixLdsDirectVALUHazard(MI);
1781 fixLdsDirectVMEMHazard(MI);
1782 }
1783 fixVALUPartialForwardingHazard(MI);
1784 fixVALUTransUseHazard(MI);
1785 fixVALUTransCoexecutionHazards(MI);
1786 fixWMMAHazards(MI); // fall-through if co-execution is enabled.
1787 fixWMMACoexecutionHazards(MI);
1788 fixShift64HighRegBug(MI);
1789 fixVALUMaskWriteHazard(MI);
1790 fixRequiredExportPriority(MI);
1791 if (ST.requiresWaitIdleBeforeGetReg())
1792 fixGetRegWaitIdle(MI);
1793 if (ST.hasDsAtomicAsyncBarrierArriveB64PipeBug())
1794 fixDsAtomicAsyncBarrierArriveB64(MI);
1795 if (ST.hasScratchBaseForwardingHazard())
1796 fixScratchBaseForwardingHazard(MI);
1797 if (ST.setRegModeNeedsVNOPs())
1798 fixSetRegMode(MI);
1799 if (ST.hasNeedsTDMDrain())
1800 fixTDM(MI);
1801}
1802
1804 const MachineInstr &MI) {
1805 return (TII.isVOPC(MI) ||
1806 (MI.isCompare() && (TII.isVOP3(MI) || TII.isSDWA(MI)))) &&
1807 MI.modifiesRegister(AMDGPU::EXEC, &TRI);
1808}
1809
1810bool GCNHazardRecognizer::fixVcmpxPermlaneHazards(MachineInstr *MI) {
1811 if (!ST.hasVcmpxPermlaneHazard() || !isPermlane(*MI))
1812 return false;
1813
1814 const SIInstrInfo *TII = ST.getInstrInfo();
1815 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1816 auto IsHazardFn = [TII, TRI](const MachineInstr &MI) {
1817 return isVCmpXWritesExec(*TII, *TRI, MI);
1818 };
1819
1820 auto IsExpiredFn = [](const MachineInstr &MI, int) {
1821 unsigned Opc = MI.getOpcode();
1822 return SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true) &&
1823 Opc != AMDGPU::V_NOP_e32 && Opc != AMDGPU::V_NOP_e64 &&
1824 Opc != AMDGPU::V_NOP_sdwa;
1825 };
1826
1827 if (::getWaitStatesSince(IsHazardFn, MI, IsExpiredFn) ==
1828 std::numeric_limits<int>::max())
1829 return false;
1830
1831 // V_NOP will be discarded by SQ.
1832 // Use V_MOV_B32 v?, v?. Register must be alive so use src0 of V_PERMLANE*
1833 // which is always a VGPR and available.
1834 auto *Src0 = TII->getNamedOperand(*MI, AMDGPU::OpName::src0);
1835 Register Reg = Src0->getReg();
1836 bool IsUndef = Src0->isUndef();
1837 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
1838 TII->get(AMDGPU::V_MOV_B32_e32))
1841
1842 return true;
1843}
1844
1845bool GCNHazardRecognizer::fixVMEMtoScalarWriteHazards(MachineInstr *MI) {
1846 if (!ST.hasVMEMtoScalarWriteHazard())
1847 return false;
1848 assert(!ST.hasExtendedWaitCounts());
1849
1851 return false;
1852
1853 if (MI->getNumDefs() == 0)
1854 return false;
1855
1856 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1857
1858 auto IsHazardFn = [TRI, MI](const MachineInstr &I) {
1860 return false;
1861
1862 for (const MachineOperand &Def : MI->defs()) {
1863 const MachineOperand *Op =
1864 I.findRegisterUseOperand(Def.getReg(), TRI, false);
1865 if (!Op)
1866 continue;
1867 return true;
1868 }
1869 return false;
1870 };
1871
1872 auto IsExpiredFn = [](const MachineInstr &MI, int) {
1873 return SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true) ||
1874 (MI.getOpcode() == AMDGPU::S_WAITCNT &&
1875 !MI.getOperand(0).getImm()) ||
1876 (MI.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
1877 AMDGPU::DepCtr::decodeFieldVmVsrc(MI.getOperand(0).getImm()) == 0);
1878 };
1879
1880 if (::getWaitStatesSince(IsHazardFn, MI, IsExpiredFn) ==
1881 std::numeric_limits<int>::max())
1882 return false;
1883
1884 const SIInstrInfo *TII = ST.getInstrInfo();
1885 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
1886 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
1888 return true;
1889}
1890
1891bool GCNHazardRecognizer::fixSMEMtoVectorWriteHazards(MachineInstr *MI) {
1892 if (!ST.hasSMEMtoVectorWriteHazard())
1893 return false;
1894 assert(!ST.hasExtendedWaitCounts());
1895
1896 if (!SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true))
1897 return false;
1898
1899 AMDGPU::OpName SDSTName;
1900 switch (MI->getOpcode()) {
1901 case AMDGPU::V_READLANE_B32:
1902 case AMDGPU::V_READFIRSTLANE_B32:
1903 SDSTName = AMDGPU::OpName::vdst;
1904 break;
1905 default:
1906 SDSTName = AMDGPU::OpName::sdst;
1907 break;
1908 }
1909
1910 const SIInstrInfo *TII = ST.getInstrInfo();
1911 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1912 const AMDGPU::IsaVersion IV = AMDGPU::getIsaVersion(ST.getCPU());
1913 const MachineOperand *SDST = TII->getNamedOperand(*MI, SDSTName);
1914 if (!SDST) {
1915 for (const auto &MO : MI->implicit_operands()) {
1916 if (MO.isDef() && TRI->isSGPRClass(TRI->getPhysRegBaseClass(MO.getReg()))) {
1917 SDST = &MO;
1918 break;
1919 }
1920 }
1921 }
1922
1923 if (!SDST)
1924 return false;
1925
1926 const Register SDSTReg = SDST->getReg();
1927 auto IsHazardFn = [SDSTReg, TRI](const MachineInstr &I) {
1928 return SIInstrInfo::isSMRD(I) && I.readsRegister(SDSTReg, TRI);
1929 };
1930
1931 auto IsExpiredFn = [TII, IV](const MachineInstr &MI, int) {
1932 if (TII->isSALU(MI)) {
1933 switch (MI.getOpcode()) {
1934 case AMDGPU::S_SETVSKIP:
1935 case AMDGPU::S_VERSION:
1936 case AMDGPU::S_WAITCNT_VSCNT:
1937 case AMDGPU::S_WAITCNT_VMCNT:
1938 case AMDGPU::S_WAITCNT_EXPCNT:
1939 // These instructions cannot not mitigate the hazard.
1940 return false;
1941 case AMDGPU::S_WAITCNT_LGKMCNT:
1942 // Reducing lgkmcnt count to 0 always mitigates the hazard.
1943 return (MI.getOperand(1).getImm() == 0) &&
1944 (MI.getOperand(0).getReg() == AMDGPU::SGPR_NULL);
1945 case AMDGPU::S_WAITCNT: {
1946 const int64_t Imm = MI.getOperand(0).getImm();
1947 AMDGPU::Waitcnt Decoded = AMDGPU::decodeWaitcnt(IV, Imm);
1948 // DsCnt corresponds to LGKMCnt here.
1949 return Decoded.get(AMDGPU::DS_CNT) == 0;
1950 }
1951 default:
1952 assert((!SIInstrInfo::isWaitcnt(MI.getOpcode()) ||
1953 MI.getOpcode() == AMDGPU::S_WAIT_IDLE) &&
1954 "unexpected wait count instruction");
1955 // SOPP instructions cannot mitigate the hazard.
1956 if (TII->isSOPP(MI))
1957 return false;
1958 // At this point the SALU can be assumed to mitigate the hazard
1959 // because either:
1960 // (a) it is independent of the at risk SMEM (breaking chain),
1961 // or
1962 // (b) it is dependent on the SMEM, in which case an appropriate
1963 // s_waitcnt lgkmcnt _must_ exist between it and the at risk
1964 // SMEM instruction.
1965 return true;
1966 }
1967 }
1968 return false;
1969 };
1970
1971 if (::getWaitStatesSince(IsHazardFn, MI, IsExpiredFn) ==
1972 std::numeric_limits<int>::max())
1973 return false;
1974
1975 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
1976 TII->get(AMDGPU::S_MOV_B32), AMDGPU::SGPR_NULL)
1977 .addImm(0);
1978 return true;
1979}
1980
1981bool GCNHazardRecognizer::fixVcmpxExecWARHazard(MachineInstr *MI) {
1982 if (!ST.hasVcmpxExecWARHazard())
1983 return false;
1984 assert(!ST.hasExtendedWaitCounts());
1985
1986 if (!SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true))
1987 return false;
1988
1989 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1990 if (!MI->modifiesRegister(AMDGPU::EXEC, TRI))
1991 return false;
1992
1993 auto IsHazardFn = [TRI](const MachineInstr &I) {
1994 if (SIInstrInfo::isVALU(I, /*AllowLDSDMA=*/true))
1995 return false;
1996 return I.readsRegister(AMDGPU::EXEC, TRI);
1997 };
1998
1999 const SIInstrInfo *TII = ST.getInstrInfo();
2000 auto IsExpiredFn = [TII, TRI](const MachineInstr &MI, int) {
2001 if (SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true)) {
2002 if (TII->getNamedOperand(MI, AMDGPU::OpName::sdst))
2003 return true;
2004 for (auto MO : MI.implicit_operands())
2005 if (MO.isDef() && TRI->isSGPRClass(TRI->getPhysRegBaseClass(MO.getReg())))
2006 return true;
2007 }
2008 if (MI.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2009 AMDGPU::DepCtr::decodeFieldSaSdst(MI.getOperand(0).getImm()) == 0)
2010 return true;
2011 return false;
2012 };
2013
2014 if (::getWaitStatesSince(IsHazardFn, MI, IsExpiredFn) ==
2015 std::numeric_limits<int>::max())
2016 return false;
2017
2018 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
2019 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
2021 return true;
2022}
2023
2025 const GCNSubtarget &ST) {
2026 if (!ST.hasLdsBranchVmemWARHazard())
2027 return false;
2028
2029 // Check if the necessary condition for the hazard is met: both LDS and VMEM
2030 // instructions need to appear in the same function.
2031 bool HasLds = false;
2032 bool HasVmem = false;
2033 for (auto &MBB : MF) {
2034 for (auto &MI : MBB) {
2036 HasVmem |= SIInstrInfo::isVMEM(MI);
2037 if (HasLds && HasVmem)
2038 return true;
2039 }
2040 }
2041 return false;
2042}
2043
2045 return I.getOpcode() == AMDGPU::S_WAITCNT_VSCNT &&
2046 I.getOperand(0).getReg() == AMDGPU::SGPR_NULL &&
2047 !I.getOperand(1).getImm();
2048}
2049
2050bool GCNHazardRecognizer::fixLdsBranchVmemWARHazard(MachineInstr *MI) {
2051 if (!RunLdsBranchVmemWARHazardFixup)
2052 return false;
2053
2054 assert(ST.hasLdsBranchVmemWARHazard());
2055 assert(!ST.hasExtendedWaitCounts());
2056
2057 auto IsHazardInst = [](const MachineInstr &MI) {
2059 return 1;
2061 return 2;
2062 return 0;
2063 };
2064
2065 auto InstType = IsHazardInst(*MI);
2066 if (!InstType)
2067 return false;
2068
2069 auto IsExpiredFn = [&IsHazardInst](const MachineInstr &I, int) {
2070 return IsHazardInst(I) || isStoreCountWaitZero(I);
2071 };
2072
2073 auto IsHazardFn = [InstType, &IsHazardInst](const MachineInstr &I) {
2074 if (!I.isBranch())
2075 return false;
2076
2077 auto IsHazardFn = [InstType, IsHazardInst](const MachineInstr &I) {
2078 auto InstType2 = IsHazardInst(I);
2079 return InstType2 && InstType != InstType2;
2080 };
2081
2082 auto IsExpiredFn = [InstType, &IsHazardInst](const MachineInstr &I, int) {
2083 auto InstType2 = IsHazardInst(I);
2084 if (InstType == InstType2)
2085 return true;
2086
2087 return isStoreCountWaitZero(I);
2088 };
2089
2090 return ::getWaitStatesSince(IsHazardFn, &I, IsExpiredFn) !=
2091 std::numeric_limits<int>::max();
2092 };
2093
2094 if (::getWaitStatesSince(IsHazardFn, MI, IsExpiredFn) ==
2095 std::numeric_limits<int>::max())
2096 return false;
2097
2098 const SIInstrInfo *TII = ST.getInstrInfo();
2099 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
2100 TII->get(AMDGPU::S_WAITCNT_VSCNT))
2101 .addReg(AMDGPU::SGPR_NULL, RegState::Undef)
2102 .addImm(0);
2103
2104 return true;
2105}
2106
2107bool GCNHazardRecognizer::fixLdsDirectVALUHazard(MachineInstr *MI) {
2109 return false;
2110
2111 const int NoHazardWaitStates = 15;
2112 const MachineOperand *VDST = TII.getNamedOperand(*MI, AMDGPU::OpName::vdst);
2113 const Register VDSTReg = VDST->getReg();
2114
2115 bool VisitedTrans = false;
2116 auto IsHazardFn = [this, VDSTReg, &VisitedTrans](const MachineInstr &I) {
2117 if (!SIInstrInfo::isVALU(I, /*AllowLDSDMA=*/true))
2118 return false;
2119 VisitedTrans = VisitedTrans || SIInstrInfo::isTRANS(I);
2120 // Cover both WAR and WAW
2121 return I.readsRegister(VDSTReg, &TRI) || I.modifiesRegister(VDSTReg, &TRI);
2122 };
2123 auto IsExpiredFn = [&](const MachineInstr &I, int WaitStates) {
2124 if (WaitStates >= NoHazardWaitStates)
2125 return true;
2126 // Instructions which cause va_vdst==0 expire hazard
2129 };
2130 auto GetWaitStatesFn = [](const MachineInstr &MI) {
2131 return SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true) ? 1 : 0;
2132 };
2133
2134 DenseSet<const MachineBasicBlock *> Visited;
2135 auto Count = ::getWaitStatesSince(IsHazardFn, MI->getParent(),
2136 std::next(MI->getReverseIterator()), 0,
2137 IsExpiredFn, Visited, GetWaitStatesFn);
2138
2139 // Transcendentals can execute in parallel to other VALUs.
2140 // This makes va_vdst count unusable with a mixture of VALU and TRANS.
2141 if (VisitedTrans)
2142 Count = 0;
2143
2144 MachineOperand *WaitVdstOp =
2145 TII.getNamedOperand(*MI, AMDGPU::OpName::waitvdst);
2146 WaitVdstOp->setImm(std::min(Count, NoHazardWaitStates));
2147
2148 return true;
2149}
2150
2151bool GCNHazardRecognizer::fixLdsDirectVMEMHazard(MachineInstr *MI) {
2153 return false;
2154
2155 const MachineOperand *VDST = TII.getNamedOperand(*MI, AMDGPU::OpName::vdst);
2156 const Register VDSTReg = VDST->getReg();
2157
2158 auto IsHazardFn = [this, VDSTReg](const MachineInstr &I) {
2160 return false;
2161 return I.readsRegister(VDSTReg, &TRI) || I.modifiesRegister(VDSTReg, &TRI);
2162 };
2163 bool LdsdirCanWait = ST.hasLdsWaitVMSRC();
2164 // TODO: On GFX12 the hazard should expire on S_WAIT_LOADCNT/SAMPLECNT/BVHCNT
2165 // according to the type of VMEM instruction.
2166 auto IsExpiredFn = [this, LdsdirCanWait](const MachineInstr &I, int) {
2167 return SIInstrInfo::isVALU(I, /*AllowLDSDMA=*/true) ||
2169 (I.getOpcode() == AMDGPU::S_WAITCNT && !I.getOperand(0).getImm()) ||
2170 (I.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2171 AMDGPU::DepCtr::decodeFieldVmVsrc(I.getOperand(0).getImm()) == 0) ||
2172 (LdsdirCanWait && SIInstrInfo::isLDSDIR(I) &&
2173 !TII.getNamedOperand(I, AMDGPU::OpName::waitvsrc)->getImm());
2174 };
2175
2176 if (::getWaitStatesSince(IsHazardFn, MI, IsExpiredFn) ==
2177 std::numeric_limits<int>::max())
2178 return false;
2179
2180 if (LdsdirCanWait) {
2181 TII.getNamedOperand(*MI, AMDGPU::OpName::waitvsrc)->setImm(0);
2182 } else {
2183 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
2184 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
2186 }
2187
2188 return true;
2189}
2190
2191bool GCNHazardRecognizer::fixVALUPartialForwardingHazard(MachineInstr *MI) {
2192 if (!ST.hasVALUPartialForwardingHazard())
2193 return false;
2194 assert(!ST.hasExtendedWaitCounts());
2195
2196 if (!ST.isWave64() || !SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true))
2197 return false;
2198
2199 SmallSetVector<Register, 4> SrcVGPRs;
2200
2201 for (const MachineOperand &Use : MI->explicit_uses()) {
2202 if (Use.isReg() && TRI.isVGPR(MF.getRegInfo(), Use.getReg()))
2203 SrcVGPRs.insert(Use.getReg());
2204 }
2205
2206 // Only applies with >= 2 unique VGPR sources
2207 if (SrcVGPRs.size() <= 1)
2208 return false;
2209
2210 // Look for the following pattern:
2211 // Va <- VALU [PreExecPos]
2212 // intv1
2213 // Exec <- SALU [ExecPos]
2214 // intv2
2215 // Vb <- VALU [PostExecPos]
2216 // intv3
2217 // MI Va, Vb (WaitState = 0)
2218 //
2219 // Where:
2220 // intv1 + intv2 <= 2 VALUs
2221 // intv3 <= 4 VALUs
2222 //
2223 // If found, insert an appropriate S_WAITCNT_DEPCTR before MI.
2224
2225 const int Intv1plus2MaxVALUs = 2;
2226 const int Intv3MaxVALUs = 4;
2227 const int IntvMaxVALUs = 6;
2228 const int NoHazardVALUWaitStates = IntvMaxVALUs + 2;
2229
2230 struct StateType {
2231 SmallDenseMap<Register, int, 4> DefPos;
2232 int ExecPos = std::numeric_limits<int>::max();
2233 int VALUs = 0;
2234
2235 static unsigned getHashValue(const StateType &State) {
2236 return hash_combine(State.ExecPos, State.VALUs,
2237 hash_combine_range(State.DefPos));
2238 }
2239 static bool isEqual(const StateType &LHS, const StateType &RHS) {
2240 return LHS.DefPos == RHS.DefPos && LHS.ExecPos == RHS.ExecPos &&
2241 LHS.VALUs == RHS.VALUs;
2242 }
2243 };
2244
2245 StateType State;
2246
2247 // This overloads expiry testing with all the hazard detection
2248 auto IsHazardFn = [&, this](StateType &State, const MachineInstr &I) {
2249 // Too many VALU states have passed
2250 if (State.VALUs > NoHazardVALUWaitStates)
2251 return HazardExpired;
2252
2253 // Instructions which cause va_vdst==0 expire hazard
2256 (I.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2257 AMDGPU::DepCtr::decodeFieldVaVdst(I.getOperand(0).getImm()) == 0))
2258 return HazardExpired;
2259
2260 // Track registers writes
2261 bool Changed = false;
2262 if (SIInstrInfo::isVALU(I, /*AllowLDSDMA=*/true)) {
2263 for (Register Src : SrcVGPRs) {
2264 if (!State.DefPos.count(Src) && I.modifiesRegister(Src, &TRI)) {
2265 State.DefPos[Src] = State.VALUs;
2266 Changed = true;
2267 }
2268 }
2269 } else if (SIInstrInfo::isSALU(I)) {
2270 if (State.ExecPos == std::numeric_limits<int>::max()) {
2271 if (!State.DefPos.empty() && I.modifiesRegister(AMDGPU::EXEC, &TRI)) {
2272 State.ExecPos = State.VALUs;
2273 Changed = true;
2274 }
2275 }
2276 }
2277
2278 // Early expiration: too many VALUs in intv3
2279 if (State.VALUs > Intv3MaxVALUs && State.DefPos.empty())
2280 return HazardExpired;
2281
2282 // Only evaluate state if something changed
2283 if (!Changed)
2284 return NoHazardFound;
2285
2286 // Determine positions of VALUs pre/post exec change
2287 if (State.ExecPos == std::numeric_limits<int>::max())
2288 return NoHazardFound;
2289
2290 int PreExecPos = std::numeric_limits<int>::max();
2291 int PostExecPos = std::numeric_limits<int>::max();
2292
2293 for (auto Entry : State.DefPos) {
2294 int DefVALUs = Entry.second;
2295 if (DefVALUs != std::numeric_limits<int>::max()) {
2296 if (DefVALUs >= State.ExecPos)
2297 PreExecPos = std::min(PreExecPos, DefVALUs);
2298 else
2299 PostExecPos = std::min(PostExecPos, DefVALUs);
2300 }
2301 }
2302
2303 // Need a VALUs post exec change
2304 if (PostExecPos == std::numeric_limits<int>::max())
2305 return NoHazardFound;
2306
2307 // Too many VALUs in intv3?
2308 int Intv3VALUs = PostExecPos;
2309 if (Intv3VALUs > Intv3MaxVALUs)
2310 return HazardExpired;
2311
2312 // Too many VALUs in intv2?
2313 int Intv2VALUs = (State.ExecPos - PostExecPos) - 1;
2314 if (Intv2VALUs > Intv1plus2MaxVALUs)
2315 return HazardExpired;
2316
2317 // Need a VALUs pre exec change
2318 if (PreExecPos == std::numeric_limits<int>::max())
2319 return NoHazardFound;
2320
2321 // Too many VALUs in intv1?
2322 int Intv1VALUs = PreExecPos - State.ExecPos;
2323 if (Intv1VALUs > Intv1plus2MaxVALUs)
2324 return HazardExpired;
2325
2326 // Too many VALUs in intv1 + intv2
2327 if (Intv1VALUs + Intv2VALUs > Intv1plus2MaxVALUs)
2328 return HazardExpired;
2329
2330 return HazardFound;
2331 };
2332 auto UpdateStateFn = [](StateType &State, const MachineInstr &MI) {
2333 if (SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true))
2334 State.VALUs += 1;
2335 };
2336
2337 if (!hasHazard<StateType>(State, IsHazardFn, UpdateStateFn, MI->getParent(),
2338 std::next(MI->getReverseIterator())))
2339 return false;
2340
2341 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
2342 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
2344
2345 return true;
2346}
2347
2348bool GCNHazardRecognizer::fixVALUTransUseHazard(MachineInstr *MI) {
2349 if (!ST.hasVALUTransUseHazard())
2350 return false;
2351 assert(!ST.hasExtendedWaitCounts());
2352
2353 if (!SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true))
2354 return false;
2355
2356 SmallSet<Register, 4> SrcVGPRs;
2357
2358 for (const MachineOperand &Use : MI->explicit_uses()) {
2359 if (Use.isReg() && TRI.isVGPR(MF.getRegInfo(), Use.getReg()))
2360 SrcVGPRs.insert(Use.getReg());
2361 }
2362
2363 // Look for the following pattern:
2364 // Va <- TRANS VALU
2365 // intv
2366 // MI Va (WaitState = 0)
2367 //
2368 // Where:
2369 // intv <= 5 VALUs / 1 TRANS
2370 //
2371 // If found, insert an appropriate S_WAITCNT_DEPCTR before MI.
2372
2373 const int IntvMaxVALUs = 5;
2374 const int IntvMaxTRANS = 1;
2375
2376 struct StateType {
2377 int VALUs = 0;
2378 int TRANS = 0;
2379
2380 static unsigned getHashValue(const StateType &State) {
2381 return hash_combine(State.VALUs, State.TRANS);
2382 }
2383 static bool isEqual(const StateType &LHS, const StateType &RHS) {
2384 return LHS.VALUs == RHS.VALUs && LHS.TRANS == RHS.TRANS;
2385 }
2386 };
2387
2388 StateType State;
2389
2390 // This overloads expiry testing with all the hazard detection
2391 auto IsHazardFn = [&, this](StateType &State, const MachineInstr &I) {
2392 // Too many VALU states have passed
2393 if (State.VALUs > IntvMaxVALUs || State.TRANS > IntvMaxTRANS)
2394 return HazardExpired;
2395
2396 // Instructions which cause va_vdst==0 expire hazard
2399 (I.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2400 AMDGPU::DepCtr::decodeFieldVaVdst(I.getOperand(0).getImm()) == 0))
2401 return HazardExpired;
2402
2403 // Track registers writes
2404 if (SIInstrInfo::isTRANS(I)) {
2405 for (Register Src : SrcVGPRs) {
2406 if (I.modifiesRegister(Src, &TRI)) {
2407 return HazardFound;
2408 }
2409 }
2410 }
2411
2412 return NoHazardFound;
2413 };
2414 auto UpdateStateFn = [](StateType &State, const MachineInstr &MI) {
2415 if (SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true))
2416 State.VALUs += 1;
2418 State.TRANS += 1;
2419 };
2420
2421 if (!hasHazard<StateType>(State, IsHazardFn, UpdateStateFn, MI->getParent(),
2422 std::next(MI->getReverseIterator())))
2423 return false;
2424
2425 // Hazard is observed - insert a wait on va_dst counter to ensure hazard is
2426 // avoided.
2427 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
2428 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
2430
2431 return true;
2432}
2433
2434bool GCNHazardRecognizer::fixVALUTransCoexecutionHazards(MachineInstr *MI) {
2435 if (!ST.hasTransCoexecutionHazard() || // Coexecution disabled.
2436 !SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true) ||
2438 return false;
2439
2440 const SIInstrInfo *TII = ST.getInstrInfo();
2441 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2442
2443 auto IsTransHazardFn = [MI, TII, TRI](const MachineInstr &I) {
2444 if (!SIInstrInfo::isTRANS(I))
2445 return false;
2446
2447 // RAW: Trans(I) writes, VALU(MI) reads.
2448 Register TransDef = TII->getNamedOperand(I, AMDGPU::OpName::vdst)->getReg();
2449 for (const MachineOperand &ValuUse : MI->explicit_uses()) {
2450 if (ValuUse.isReg() && TRI->regsOverlap(TransDef, ValuUse.getReg()))
2451 return true;
2452 }
2453
2454 auto *ValuDst = TII->getNamedOperand(*MI, AMDGPU::OpName::vdst);
2455 if (!ValuDst || !ValuDst->isReg())
2456 return false;
2457
2458 // WAR: Trans(I) reads, VALU(MI) writes.
2459 Register ValuDef = ValuDst->getReg();
2460 for (const MachineOperand &TransUse : I.explicit_uses()) {
2461 if (TransUse.isReg() && TRI->regsOverlap(ValuDef, TransUse.getReg()))
2462 return true;
2463 }
2464
2465 return false;
2466 };
2467
2468 auto IsExpiredFn = [](const MachineInstr &I, int) {
2469 return SIInstrInfo::isVALU(I, /*AllowLDSDMA=*/true);
2470 };
2471
2472 const int HasVALU = std::numeric_limits<int>::max();
2473 if (::getWaitStatesSince(IsTransHazardFn, MI, IsExpiredFn) == HasVALU)
2474 return false;
2475
2476 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), TII->get(AMDGPU::V_NOP_e32));
2477 return true;
2478}
2479
2480bool GCNHazardRecognizer::fixWMMAHazards(MachineInstr *MI) {
2482 return false;
2483
2484 const SIInstrInfo *TII = ST.getInstrInfo();
2485 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2486
2487 auto IsHazardFn = [MI, TII, TRI, this](const MachineInstr &I) {
2489 return false;
2490
2491 // Src0(matrix A) or Src1(matrix B) of the current wmma instruction overlaps
2492 // with the dest(matrix D) of the previous wmma.
2493 const Register CurSrc0Reg =
2494 TII->getNamedOperand(*MI, AMDGPU::OpName::src0)->getReg();
2495 const Register CurSrc1Reg =
2496 TII->getNamedOperand(*MI, AMDGPU::OpName::src1)->getReg();
2497
2498 const Register PrevDstReg =
2499 TII->getNamedOperand(I, AMDGPU::OpName::vdst)->getReg();
2500
2501 if (TRI->regsOverlap(PrevDstReg, CurSrc0Reg) ||
2502 TRI->regsOverlap(PrevDstReg, CurSrc1Reg)) {
2503 return true;
2504 }
2505
2506 // GFX12+ allows overlap of matrix C with PrevDstReg (hardware will stall)
2507 // but Index can't overlap with PrevDstReg.
2508 if (AMDGPU::isGFX12Plus(ST)) {
2509 if (SIInstrInfo::isSWMMAC(*MI)) {
2510 const Register CurIndex =
2511 TII->getNamedOperand(*MI, AMDGPU::OpName::src2)->getReg();
2512 if (TRI->regsOverlap(PrevDstReg, CurIndex))
2513 return true;
2514 }
2515 return false;
2516 }
2517
2518 return false;
2519 };
2520
2521 auto IsExpiredFn = [](const MachineInstr &I, int) {
2522 return SIInstrInfo::isVALU(I, /*AllowLDSDMA=*/true);
2523 };
2524
2525 if (::getWaitStatesSince(IsHazardFn, MI, IsExpiredFn) ==
2526 std::numeric_limits<int>::max())
2527 return false;
2528
2529 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), TII->get(AMDGPU::V_NOP_e32));
2530
2531 return true;
2532}
2533
2535 return SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true) &&
2538}
2539
2540// Classify XDL WMMA instructions into co-execution hazard categories
2541// (Refer to SPG 4.6.12.1), mainly based on instruction latency.
2542//
2543// Category 0: WMMA with Latency 8
2544// WMMA_*F16, WMMA_*BF16
2545// WMMA_*_16X16X128_{FP8,BF8}
2546// WMMA_*F8F6F4 if SRCA & SRCB are not both F4
2547//
2548// Category 1: WMMA Latency 16
2549// WMMA_IU8
2550//
2551// Category 2: SWMMAC with Latency 8
2552// SWMMAC_*F16, SWMMAC_*BF16,
2553// SWMMAC_*FP8FP8
2554// SWMMAC_*BF8FP8
2555// SWMMAC_*FP8BF8
2556// SWMMAC_*BF8BF8
2557//
2558// Category 3: SWMMAC with Latency 16
2559// SWMMAC_IU8
2560//
2561// Category 4: 16 Pass GFX1251 WMMA with latency 16
2562// V_WMMA_*_16X16X32_{F16,BF16}
2563// V_WMMA_{F32,F16}_16X16X64_{FP8,BF8}*
2564// V_WMMA_F32_16x16x128_F8F6F4 (F4 only)
2565// V_SWMMAC_*_16X16X64_{F16,BF16}
2566// V_SWMMAC_{F32,F16}_16X16X128_{FP8,BF8}*
2567//
2568// Category 5: 32 Pass GFX1251 WMMA with latency 32
2569// V_WMMA_F32_16x16x128_F8F6F4 (not all F4)
2570// V_WMMA_{F32,F16}_16X16X128_{FP8,BF8}*
2571// V_WMMA_F32_32X16X128_F4
2572// V_WMMA_I32_16X16X64_IU8
2573// V_WMMA_I32_16X16X64_IU8
2574//
2575// Category 6: gfx1250 WMMA with Latency 4 (one co-execution slot)
2576// WMMA_*_16X16X64_{FP8,BF8}
2577// WMMA_*F8F6F4 if SRCA & SRCB are both F4
2579 const SIInstrInfo *TII,
2580 const TargetSchedModel &SchedModel,
2581 const GCNSubtarget &ST) {
2582 assert(TII->isXDLWMMA(MI) && "must be xdl wmma");
2583 bool IsSWMMAC = SIInstrInfo::isSWMMAC(MI);
2584 bool IsLowestRateWMMA = ST.hasGFX125xLowestRateWMMA();
2585 unsigned Category = 0;
2586
2587 unsigned Latency = SchedModel.computeInstrLatency(&MI);
2588 switch (Latency) {
2589 case 4:
2590 // Dense 4-cycle WMMA (gfx1250 16x16x64 FP8/BF8 and f8f6f4 with both
2591 // inputs F4). One co-execution slot; there is no 4-cycle SWMMAC.
2592 assert(!IsSWMMAC && "no 4-cycle SWMMAC expected");
2593 Category = 6;
2594 break;
2595 case 8:
2596 Category = IsSWMMAC ? 2 : 0;
2597 break;
2598 case 16:
2599 Category = IsLowestRateWMMA ? 4 : (IsSWMMAC ? 3 : 1);
2600 break;
2601 case 32:
2602 assert(IsLowestRateWMMA && "latency 32 is not expected");
2603 Category = 5;
2604 break;
2605 default:
2606 llvm_unreachable("unexpected xdl wmma latency");
2607 } // end switch.
2608
2609 return Category;
2610}
2611
2612int GCNHazardRecognizer::checkWMMACoexecutionHazards(MachineInstr *MI) const {
2613 if (!ST.hasWMMACoexecutionHazards())
2614 return 0;
2615
2616 const SIInstrInfo *TII = ST.getInstrInfo();
2617 if (!TII->isXDLWMMA(*MI) && !isCoexecutableVALUInst(*MI))
2618 return 0;
2619
2620 // WaitStates here is the number of V_NOPs or unrelated VALU instructions must
2621 // be in between the first WMMA and the second instruction to cover the hazard
2622 // (WMMAWaitStates if the second is also a WMMA, VALUWaitStates if the second
2623 // is a VALU). Refer to SPG 4.6.12.1. "Requirements for WMMA data hazards" for
2624 // numbers, which depends on the category of the first WMMA.
2625 const int WMMAWaitStates[] = {5, 9, 3, 5, 9, 17, 2};
2626 const int VALUWaitStates[] = {4, 8, 2, 4, 8, 16, 1};
2627 unsigned Category = 0;
2628
2629 auto IsWMMAHazardFn = [MI, TII, &Category, this](const MachineInstr &I) {
2630 if (!TII->isXDLWMMA(I))
2631 return false;
2632
2633 Category = getWMMAHazardInstInCategory(I, TII, TSchedModel, ST);
2634 return hasWMMAToWMMARegOverlap(I, *MI);
2635 };
2636
2637 auto IsVALUHazardFn = [MI, TII, &Category, this](const MachineInstr &I) {
2638 if (!TII->isXDLWMMA(I))
2639 return false;
2640
2641 Category = getWMMAHazardInstInCategory(I, TII, TSchedModel, ST);
2642 return hasWMMAToVALURegOverlap(I, *MI);
2643 };
2644
2645 int WaitStatesNeeded = -1;
2646 int ExistingVALUs = 0; // Existing number of VALU ops in between.
2647 bool IsLowestRateWMMA = ST.hasGFX125xLowestRateWMMA();
2648
2649 // getWaitStatesSinceVALU checks for a hazard between instruction 'I' and
2650 // 'MI':
2651 // - If a hazard exists: returns the number of VALUs in between and sets
2652 // 'Category' via IsWMMAHazardFn/IsVALUHazardFn for instruction 'I'.
2653 // - If no hazard exists: returns INT_MAX, making WaitStatesNeeded negative,
2654 // so no V_NOP insertion is needed.
2655 if (TII->isXDLWMMA(*MI)) {
2656 // Maximum of MMAWaitStates.
2657 const int WMMAWaitsLimit = IsLowestRateWMMA ? 17 : 9;
2658 ExistingVALUs = getWaitStatesSinceVALU(IsWMMAHazardFn, WMMAWaitsLimit);
2659 WaitStatesNeeded = WMMAWaitStates[Category] - ExistingVALUs;
2660 } else { // Must be a co-executable VALU.
2661 // Maximum of VALUWaitStates.
2662 const int VALUWaitsLimit = IsLowestRateWMMA ? 16 : 8;
2663 ExistingVALUs = getWaitStatesSinceVALU(IsVALUHazardFn, VALUWaitsLimit);
2664 WaitStatesNeeded = VALUWaitStates[Category] - ExistingVALUs;
2665 }
2666
2667 return WaitStatesNeeded;
2668}
2669
2670bool GCNHazardRecognizer::hasWMMAToWMMARegOverlap(
2671 const MachineInstr &WMMA, const MachineInstr &MI) const {
2672 Register D0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::vdst)->getReg();
2673 Register A1 = TII.getNamedOperand(MI, AMDGPU::OpName::src0)->getReg();
2674 Register B1 = TII.getNamedOperand(MI, AMDGPU::OpName::src1)->getReg();
2675
2676 // WMMA0 writes (D0), WMMA1 reads (A1/B1/Idx1).
2677 if (TRI.regsOverlap(D0, A1) || TRI.regsOverlap(D0, B1))
2678 return true;
2679
2681 Register Idx1 = TII.getNamedOperand(MI, AMDGPU::OpName::src2)->getReg();
2682 if (TRI.regsOverlap(D0, Idx1))
2683 return true;
2684 }
2685 return false;
2686}
2687
2688bool GCNHazardRecognizer::hasWMMAToVALURegOverlap(
2689 const MachineInstr &WMMA, const MachineInstr &MI) const {
2690 // WMMA writes, VALU reads.
2691 Register D0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::vdst)->getReg();
2692 for (const MachineOperand &ValuUse : MI.explicit_uses()) {
2693 if (ValuUse.isReg() && TRI.regsOverlap(D0, ValuUse.getReg()))
2694 return true;
2695 }
2696
2697 // WMMA reads or writes, VALU writes.
2698 Register A0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::src0)->getReg();
2699 Register B0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::src1)->getReg();
2700 SmallVector<Register, 4> WMMARegs({D0, A0, B0});
2701
2702 if (SIInstrInfo::isSWMMAC(WMMA)) {
2703 Register Idx0 = TII.getNamedOperand(WMMA, AMDGPU::OpName::src2)->getReg();
2704 WMMARegs.push_back(Idx0);
2705 }
2706
2707 for (const MachineOperand &ValuDef : MI.defs()) {
2708 Register VDstReg = ValuDef.getReg();
2709 for (Register WMMAReg : WMMARegs) {
2710 if (TRI.regsOverlap(VDstReg, WMMAReg))
2711 return true;
2712 }
2713 }
2714 return false;
2715}
2716
2717bool GCNHazardRecognizer::isCoexecutionHazardFor(const MachineInstr &I,
2718 const MachineInstr &MI) const {
2719 // I is the potential WMMA hazard source, MI is the instruction being checked
2720 // for hazard.
2721 if (!TII.isXDLWMMA(I))
2722 return false;
2723
2724 // Dispatch based on MI type
2725 if (TII.isXDLWMMA(MI))
2726 return hasWMMAToWMMARegOverlap(I, MI);
2728 return hasWMMAToVALURegOverlap(I, MI);
2729
2730 return false;
2731}
2732
2733bool GCNHazardRecognizer::hasWMMAHazardInLoop(MachineLoop *L, MachineInstr *MI,
2734 bool IncludeSubloops) {
2735 // Scan loop for any WMMA that hazards MI.
2736 // TODO: Avoid full loop scan when WMMA is beyond VALU distance.
2737 for (MachineBasicBlock *MBB : L->getBlocks()) {
2738 if (!IncludeSubloops && MLI->getLoopFor(MBB) != L)
2739 continue;
2740 for (MachineInstr &I : *MBB) {
2741 if (&I == MI)
2742 continue;
2743 if (isCoexecutionHazardFor(I, *MI))
2744 return true;
2745 }
2746 }
2747 return false;
2748}
2749
2750bool GCNHazardRecognizer::tryHoistWMMAVnopsFromLoop(MachineInstr *MI,
2751 int WaitStatesNeeded) {
2752 if (!MLI)
2753 return false;
2754
2755 MachineLoop *L = MLI->getLoopFor(MI->getParent());
2756 if (!L) {
2757 ++NumWMMAHoistingBailed;
2758 return false;
2759 }
2760
2761 // If innermost loop has WMMA hazard, we can't hoist at all
2762 if (hasWMMAHazardInLoop(L, MI)) {
2763 ++NumWMMAHoistingBailed;
2764 return false;
2765 }
2766
2767 // Find outermost loop with no internal hazard
2768 MachineLoop *TargetLoop = L;
2769 while (MachineLoop *Parent = TargetLoop->getParentLoop()) {
2770 if (hasWMMAHazardInLoop(Parent, MI, false))
2771 break; // Parent has hazard in its own blocks, stop here
2772 TargetLoop = Parent; // Safe to hoist further out
2773 }
2774
2775 // Need valid preheader to insert V_NOPs
2776 MachineBasicBlock *Preheader = TargetLoop->getLoopPreheader();
2777 if (!Preheader) {
2778 ++NumWMMAHoistingBailed;
2779 return false;
2780 }
2781
2782 LLVM_DEBUG(dbgs() << "WMMA V_NOP Hoisting: Moving " << WaitStatesNeeded
2783 << " V_NOPs from loop to " << printMBBReference(*Preheader)
2784 << "\n");
2785
2786 emitVNops(*Preheader, Preheader->getFirstTerminator(), WaitStatesNeeded,
2787 /*IsHoisting=*/true);
2788 NumWMMANopsHoisted += WaitStatesNeeded;
2789 return true;
2790}
2791
2792bool GCNHazardRecognizer::fixWMMACoexecutionHazards(MachineInstr *MI) {
2793 int WaitStatesNeeded = checkWMMACoexecutionHazards(MI);
2794 if (WaitStatesNeeded <= 0)
2795 return false;
2796
2797 if (EnableWMMAVnopHoisting && tryHoistWMMAVnopsFromLoop(MI, WaitStatesNeeded))
2798 return true;
2799
2800 emitVNops(*MI->getParent(), MI->getIterator(), WaitStatesNeeded);
2801 return true;
2802}
2803
2804bool GCNHazardRecognizer::fixShift64HighRegBug(MachineInstr *MI) {
2805 if (!ST.hasShift64HighRegBug())
2806 return false;
2807 assert(!ST.hasExtendedWaitCounts());
2808
2809 switch (MI->getOpcode()) {
2810 default:
2811 return false;
2812 case AMDGPU::V_LSHLREV_B64_e64:
2813 case AMDGPU::V_LSHRREV_B64_e64:
2814 case AMDGPU::V_ASHRREV_I64_e64:
2815 break;
2816 }
2817
2818 MachineOperand *Amt = TII.getNamedOperand(*MI, AMDGPU::OpName::src0);
2819 if (!Amt->isReg())
2820 return false;
2821
2822 Register AmtReg = Amt->getReg();
2823 const MachineRegisterInfo &MRI = MF.getRegInfo();
2824 // Check if this is a last VGPR in the allocation block.
2825 if (!TRI.isVGPR(MRI, AmtReg) || ((AmtReg - AMDGPU::VGPR0) & 7) != 7)
2826 return false;
2827
2828 if (AmtReg != AMDGPU::VGPR255 && MRI.isPhysRegUsed(AmtReg + 1))
2829 return false;
2830
2831 assert(ST.needsAlignedVGPRs());
2832 static_assert(AMDGPU::VGPR0 + 1 == AMDGPU::VGPR1);
2833
2834 const DebugLoc &DL = MI->getDebugLoc();
2835 MachineBasicBlock *MBB = MI->getParent();
2836 MachineOperand *Src1 = TII.getNamedOperand(*MI, AMDGPU::OpName::src1);
2837
2838 // In:
2839 //
2840 // Dst = shiftrev64 Amt, Src1
2841 //
2842 // if Dst!=Src1 then avoid the bug with:
2843 //
2844 // Dst.sub0 = Amt
2845 // Dst = shift64 Dst.sub0, Src1
2846
2847 Register DstReg = MI->getOperand(0).getReg();
2848 if (!Src1->isReg() || Src1->getReg() != DstReg) {
2849 Register DstLo = TRI.getSubReg(DstReg, AMDGPU::sub0);
2850 runOnInstruction(
2851 BuildMI(*MBB, MI, DL, TII.get(AMDGPU::V_MOV_B32_e32), DstLo).add(*Amt));
2852 Amt->setReg(DstLo);
2853 Amt->setIsKill(true);
2854 return true;
2855 }
2856
2857 bool Overlapped = MI->modifiesRegister(AmtReg, &TRI);
2858 Register NewReg;
2859 for (MCRegister Reg : Overlapped ? AMDGPU::VReg_64_Align2RegClass
2860 : AMDGPU::VGPR_32RegClass) {
2861 if (!MI->modifiesRegister(Reg, &TRI) && !MI->readsRegister(Reg, &TRI)) {
2862 NewReg = Reg;
2863 break;
2864 }
2865 }
2866
2867 Register NewAmt = Overlapped ? (Register)TRI.getSubReg(NewReg, AMDGPU::sub1)
2868 : NewReg;
2869 Register NewAmtLo;
2870
2871 if (Overlapped)
2872 NewAmtLo = TRI.getSubReg(NewReg, AMDGPU::sub0);
2873
2874 // Insert a full wait count because found register might be pending a wait.
2875 BuildMI(*MBB, MI, DL, TII.get(AMDGPU::S_WAITCNT))
2876 .addImm(0);
2877
2878 // Insert V_SWAP_B32 instruction(s) and run hazard recognizer on them.
2879 if (Overlapped)
2880 runOnInstruction(
2881 BuildMI(*MBB, MI, DL, TII.get(AMDGPU::V_SWAP_B32), NewAmtLo)
2882 .addDef(AmtReg - 1)
2883 .addReg(AmtReg - 1, RegState::Undef)
2884 .addReg(NewAmtLo, RegState::Undef));
2885 runOnInstruction(BuildMI(*MBB, MI, DL, TII.get(AMDGPU::V_SWAP_B32), NewAmt)
2886 .addDef(AmtReg)
2887 .addReg(AmtReg, RegState::Undef)
2888 .addReg(NewAmt, RegState::Undef));
2889
2890 // Instructions emitted after the current instruction will be processed by the
2891 // parent loop of the hazard recognizer in a natural way.
2892 BuildMI(*MBB, std::next(MI->getIterator()), DL, TII.get(AMDGPU::V_SWAP_B32),
2893 AmtReg)
2894 .addDef(NewAmt)
2895 .addReg(NewAmt)
2896 .addReg(AmtReg);
2897 if (Overlapped)
2898 BuildMI(*MBB, std::next(MI->getIterator()), DL, TII.get(AMDGPU::V_SWAP_B32),
2899 AmtReg - 1)
2900 .addDef(NewAmtLo)
2901 .addReg(NewAmtLo)
2902 .addReg(AmtReg - 1);
2903
2904 // Re-running hazard recognizer on the modified instruction is not necessary,
2905 // inserted V_SWAP_B32 has already both read and write new registers so
2906 // hazards related to these register has already been handled.
2907 Amt->setReg(NewAmt);
2908 Amt->setIsKill(false);
2909 // We do not update liveness, so verifier may see it as undef.
2910 Amt->setIsUndef();
2911 if (Overlapped) {
2912 MI->getOperand(0).setReg(NewReg);
2913 Src1->setReg(NewReg);
2914 Src1->setIsKill(false);
2915 Src1->setIsUndef();
2916 }
2917
2918 return true;
2919}
2920
2921int GCNHazardRecognizer::checkNSAtoVMEMHazard(MachineInstr *MI) const {
2922 int NSAtoVMEMWaitStates = 1;
2923
2924 if (!ST.hasNSAtoVMEMBug())
2925 return 0;
2926
2928 return 0;
2929
2930 const SIInstrInfo *TII = ST.getInstrInfo();
2931 const auto *Offset = TII->getNamedOperand(*MI, AMDGPU::OpName::offset);
2932 if (!Offset || (Offset->getImm() & 6) == 0)
2933 return 0;
2934
2935 auto IsHazardFn = [TII](const MachineInstr &I) {
2936 if (!SIInstrInfo::isMIMG(I))
2937 return false;
2938 const AMDGPU::MIMGInfo *Info = AMDGPU::getMIMGInfo(I.getOpcode());
2939 return Info->MIMGEncoding == AMDGPU::MIMGEncGfx10NSA &&
2940 TII->getInstSizeInBytes(I) >= 16;
2941 };
2942
2943 return NSAtoVMEMWaitStates - getWaitStatesSince(IsHazardFn, 1);
2944}
2945
2946int GCNHazardRecognizer::checkFPAtomicToDenormModeHazard(
2947 MachineInstr *MI) const {
2948 int FPAtomicToDenormModeWaitStates = 3;
2949
2950 if (!ST.hasFPAtomicToDenormModeHazard())
2951 return 0;
2952 assert(!ST.hasExtendedWaitCounts());
2953
2954 if (MI->getOpcode() != AMDGPU::S_DENORM_MODE)
2955 return 0;
2956
2957 auto IsHazardFn = [](const MachineInstr &I) {
2958 if (!SIInstrInfo::isVMEM(I))
2959 return false;
2960 return SIInstrInfo::isFPAtomic(I);
2961 };
2962
2963 auto IsExpiredFn = [](const MachineInstr &MI, int WaitStates) {
2964 if (WaitStates >= 3 || SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true))
2965 return true;
2966
2967 return SIInstrInfo::isWaitcnt(MI.getOpcode());
2968 };
2969
2970 return FPAtomicToDenormModeWaitStates -
2971 ::getWaitStatesSince(IsHazardFn, MI, IsExpiredFn);
2972}
2973
2974int GCNHazardRecognizer::checkMAIHazards(MachineInstr *MI) const {
2976
2977 return ST.hasGFX90AInsts() ? checkMAIHazards90A(MI) : checkMAIHazards908(MI);
2978}
2979
2980int GCNHazardRecognizer::checkMFMAPadding(MachineInstr *MI) const {
2981 // Early exit if no padding is requested.
2982 if (MFMAPaddingRatio == 0)
2983 return 0;
2984
2985 const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
2986 if (!SIInstrInfo::isMFMA(*MI) || MFI->getOccupancy() < 2)
2987 return 0;
2988
2989 int NeighborMFMALatency = 0;
2990 auto IsNeighboringMFMA = [&NeighborMFMALatency,
2991 this](const MachineInstr &MI) {
2992 if (!SIInstrInfo::isMFMA(MI))
2993 return false;
2994
2995 NeighborMFMALatency = this->getMFMAPipelineWaitStates(MI);
2996 return true;
2997 };
2998
2999 const int MaxMFMAPipelineWaitStates = 16;
3000 int WaitStatesSinceNeighborMFMA =
3001 getWaitStatesSince(IsNeighboringMFMA, MaxMFMAPipelineWaitStates);
3002
3003 int NeighborMFMAPaddingNeeded =
3004 (NeighborMFMALatency * MFMAPaddingRatio / 100) -
3005 WaitStatesSinceNeighborMFMA;
3006
3007 return std::max(0, NeighborMFMAPaddingNeeded);
3008}
3009
3010int GCNHazardRecognizer::checkMAIHazards908(MachineInstr *MI) const {
3011 int WaitStatesNeeded = 0;
3012 unsigned Opc = MI->getOpcode();
3013
3014 auto IsVALUFn = [](const MachineInstr &MI) {
3015 return SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true) || MI.isInlineAsm();
3016 };
3017
3018 if (Opc != AMDGPU::V_ACCVGPR_READ_B32_e64) { // MFMA or v_accvgpr_write
3019 const int LegacyVALUWritesVGPRWaitStates = 2;
3020 const int VALUWritesExecWaitStates = 4;
3021 const int MaxWaitStates = 4;
3022
3023 int WaitStatesNeededForUse = VALUWritesExecWaitStates -
3024 getWaitStatesSinceDef(AMDGPU::EXEC, IsVALUFn, MaxWaitStates);
3025 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3026
3027 if (WaitStatesNeeded < MaxWaitStates) {
3028 for (const MachineOperand &Use : MI->explicit_uses()) {
3029 const int MaxWaitStates = 2;
3030
3031 if (!Use.isReg() || !TRI.isVGPR(MF.getRegInfo(), Use.getReg()))
3032 continue;
3033
3034 int WaitStatesNeededForUse = LegacyVALUWritesVGPRWaitStates -
3035 getWaitStatesSinceDef(Use.getReg(), IsVALUFn, MaxWaitStates);
3036 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3037
3038 if (WaitStatesNeeded == MaxWaitStates)
3039 break;
3040 }
3041 }
3042 }
3043
3044 for (const MachineOperand &Op : MI->explicit_operands()) {
3045 if (!Op.isReg() || !TRI.isAGPR(MF.getRegInfo(), Op.getReg()))
3046 continue;
3047
3048 if (Op.isDef() && Opc != AMDGPU::V_ACCVGPR_WRITE_B32_e64)
3049 continue;
3050
3051 const int MFMAWritesAGPROverlappedSrcABWaitStates = 4;
3052 const int MFMAWritesAGPROverlappedSrcCWaitStates = 2;
3053 const int MFMA4x4WritesAGPRAccVgprReadWaitStates = 4;
3054 const int MFMA16x16WritesAGPRAccVgprReadWaitStates = 10;
3055 const int MFMA32x32WritesAGPRAccVgprReadWaitStates = 18;
3056 const int MFMA4x4WritesAGPRAccVgprWriteWaitStates = 1;
3057 const int MFMA16x16WritesAGPRAccVgprWriteWaitStates = 7;
3058 const int MFMA32x32WritesAGPRAccVgprWriteWaitStates = 15;
3059 const int MaxWaitStates = 18;
3060 Register Reg = Op.getReg();
3061 unsigned HazardDefLatency = 0;
3062
3063 auto IsOverlappedMFMAFn = [Reg, &HazardDefLatency,
3064 this](const MachineInstr &MI) {
3065 if (!SIInstrInfo::isMFMA(MI))
3066 return false;
3067 Register DstReg = MI.getOperand(0).getReg();
3068 if (DstReg == Reg)
3069 return false;
3070 HazardDefLatency =
3071 std::max(HazardDefLatency, TSchedModel.computeInstrLatency(&MI));
3072 return TRI.regsOverlap(DstReg, Reg);
3073 };
3074
3075 int WaitStatesSinceDef = getWaitStatesSinceDef(Reg, IsOverlappedMFMAFn,
3076 MaxWaitStates);
3077 int NeedWaitStates = MFMAWritesAGPROverlappedSrcABWaitStates;
3078 int SrcCIdx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src2);
3079 int OpNo = Op.getOperandNo();
3080 if (OpNo == SrcCIdx) {
3081 NeedWaitStates = MFMAWritesAGPROverlappedSrcCWaitStates;
3082 } else if (Opc == AMDGPU::V_ACCVGPR_READ_B32_e64) {
3083 switch (HazardDefLatency) {
3084 case 2: NeedWaitStates = MFMA4x4WritesAGPRAccVgprReadWaitStates;
3085 break;
3086 case 8: NeedWaitStates = MFMA16x16WritesAGPRAccVgprReadWaitStates;
3087 break;
3088 case 16: [[fallthrough]];
3089 default: NeedWaitStates = MFMA32x32WritesAGPRAccVgprReadWaitStates;
3090 break;
3091 }
3092 } else if (Opc == AMDGPU::V_ACCVGPR_WRITE_B32_e64) {
3093 switch (HazardDefLatency) {
3094 case 2: NeedWaitStates = MFMA4x4WritesAGPRAccVgprWriteWaitStates;
3095 break;
3096 case 8: NeedWaitStates = MFMA16x16WritesAGPRAccVgprWriteWaitStates;
3097 break;
3098 case 16: [[fallthrough]];
3099 default: NeedWaitStates = MFMA32x32WritesAGPRAccVgprWriteWaitStates;
3100 break;
3101 }
3102 }
3103
3104 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceDef;
3105 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3106
3107 if (WaitStatesNeeded == MaxWaitStates)
3108 return WaitStatesNeeded; // Early exit.
3109
3110 auto IsAccVgprWriteFn = [Reg, this](const MachineInstr &MI) {
3111 if (MI.getOpcode() != AMDGPU::V_ACCVGPR_WRITE_B32_e64)
3112 return false;
3113 Register DstReg = MI.getOperand(0).getReg();
3114 return TRI.regsOverlap(Reg, DstReg);
3115 };
3116
3117 const int AccVGPRWriteMFMAReadSrcCWaitStates = 1;
3118 const int AccVGPRWriteMFMAReadSrcABWaitStates = 3;
3119 const int AccVGPRWriteAccVgprReadWaitStates = 3;
3120 NeedWaitStates = AccVGPRWriteMFMAReadSrcABWaitStates;
3121 if (OpNo == SrcCIdx)
3122 NeedWaitStates = AccVGPRWriteMFMAReadSrcCWaitStates;
3123 else if (Opc == AMDGPU::V_ACCVGPR_READ_B32_e64)
3124 NeedWaitStates = AccVGPRWriteAccVgprReadWaitStates;
3125
3126 WaitStatesNeededForUse = NeedWaitStates -
3127 getWaitStatesSinceDef(Reg, IsAccVgprWriteFn, MaxWaitStates);
3128 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3129
3130 if (WaitStatesNeeded == MaxWaitStates)
3131 return WaitStatesNeeded; // Early exit.
3132 }
3133
3134 if (Opc == AMDGPU::V_ACCVGPR_WRITE_B32_e64) {
3135 const int MFMA4x4ReadSrcCAccVgprWriteWaitStates = 0;
3136 const int MFMA16x16ReadSrcCAccVgprWriteWaitStates = 5;
3137 const int MFMA32x32ReadSrcCAccVgprWriteWaitStates = 13;
3138 const int MaxWaitStates = 13;
3139 Register DstReg = MI->getOperand(0).getReg();
3140 unsigned HazardDefLatency = 0;
3141
3142 auto IsSrcCMFMAFn = [DstReg, &HazardDefLatency,
3143 this](const MachineInstr &MI) {
3144 if (!SIInstrInfo::isMFMA(MI))
3145 return false;
3146 Register Reg = TII.getNamedOperand(MI, AMDGPU::OpName::src2)->getReg();
3147 HazardDefLatency =
3148 std::max(HazardDefLatency, TSchedModel.computeInstrLatency(&MI));
3149 return TRI.regsOverlap(Reg, DstReg);
3150 };
3151
3152 int WaitStatesSince = getWaitStatesSince(IsSrcCMFMAFn, MaxWaitStates);
3153 int NeedWaitStates;
3154 switch (HazardDefLatency) {
3155 case 2: NeedWaitStates = MFMA4x4ReadSrcCAccVgprWriteWaitStates;
3156 break;
3157 case 8: NeedWaitStates = MFMA16x16ReadSrcCAccVgprWriteWaitStates;
3158 break;
3159 case 16: [[fallthrough]];
3160 default: NeedWaitStates = MFMA32x32ReadSrcCAccVgprWriteWaitStates;
3161 break;
3162 }
3163
3164 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSince;
3165 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3166 }
3167
3168 // Pad neighboring MFMA with noops for better inter-wave performance.
3169 WaitStatesNeeded = std::max(WaitStatesNeeded, checkMFMAPadding(MI));
3170
3171 return WaitStatesNeeded;
3172}
3173
3174static int
3176 bool IsGFX950) {
3177 // xdl def cycles | gfx940 | gfx950
3178 // 2 pass | 3 4
3179 // 4 pass | 5 6
3180 // 8 pass | 9 10
3181 // 16 pass | 17 18
3182 return NumPasses + 1 + IsGFX950;
3183}
3184
3185static int
3187 bool IsGFX950) {
3188 // xdl def cycles | gfx940 | gfx950
3189 // 2 pass | 3 3
3190 // 4 pass | 5 6
3191 // 8 pass | 9 10
3192 // 16 pass | 17 18
3193 return NumPasses + 1 + (NumPasses != 2 && IsGFX950);
3194}
3195
3196static int
3198 // 2 pass -> 2
3199 // 4 pass -> 4
3200 // 8 pass -> 8
3201 // 16 pass -> 16
3202 return NumPasses;
3203}
3204
3205static int
3207 // 2 pass -> 4
3208 // 4 pass -> 6
3209 // 8 pass -> 10
3210 // 16 pass -> 18
3211 return NumPasses + 2;
3212}
3213
3215 bool IsGFX950) {
3216 // xdl def cycles | gfx942 | gfx950
3217 // 2 pass | 5 5
3218 // 4 pass | 7 8
3219 // 8 pass | 11 12
3220 // 16 pass | 19 20
3221 return NumPasses + 3 + (NumPasses != 2 && IsGFX950);
3222}
3223
3224int GCNHazardRecognizer::checkMAIHazards90A(MachineInstr *MI) const {
3225 int WaitStatesNeeded = 0;
3226 unsigned Opc = MI->getOpcode();
3227
3228 auto IsLegacyVALUFn = [](const MachineInstr &MI) {
3229 return SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true) &&
3231 };
3232
3233 auto IsLegacyVALUNotDotFn = [](const MachineInstr &MI) {
3234 return SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true) &&
3236 };
3237
3238 if (!SIInstrInfo::isMFMA(*MI))
3239 return WaitStatesNeeded;
3240
3241 const int VALUWritesExecWaitStates = 4;
3242 int WaitStatesNeededForUse = VALUWritesExecWaitStates -
3243 getWaitStatesSinceDef(AMDGPU::EXEC, IsLegacyVALUFn,
3244 VALUWritesExecWaitStates);
3245 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3246
3247 int SrcCIdx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src2);
3248
3249 // Loop for both DGEMM and S/HGEMM 2nd instruction.
3250 for (const MachineOperand &Use : MI->explicit_uses()) {
3251 const int LegacyVALUNotDotWritesVGPRWaitStates = 2;
3252 const int SMFMA4x4WritesVGPROverlappedSMFMASrcCWaitStates = 2;
3253 const int SMFMA16x16WritesVGPROverlappedSMFMASrcCWaitStates = 8;
3254 const int SMFMA32x32WritesVGPROverlappedSMFMASrcCWaitStates = 16;
3255 const int SMFMA4x4WritesVGPROverlappedDMFMASrcCWaitStates = 3;
3256 const int SMFMA16x16WritesVGPROverlappedDMFMASrcCWaitStates = 9;
3257 const int SMFMA32x32WritesVGPROverlappedDMFMASrcCWaitStates = 17;
3258 const int DMFMA16x16WritesVGPROverlappedSrcCWaitStates = 9;
3259 const int GFX950_DMFMA16x16WritesVGPROverlappedSrcCWaitStates = 17;
3260 const int DMFMA4x4WritesVGPROverlappedSrcCWaitStates = 4;
3261 const int SMFMA4x4WritesVGPROverlappedSrcABWaitStates = 5;
3262 const int SMFMA16x16WritesVGPROverlappedSrcABWaitStates = 11;
3263 const int SMFMA32x32WritesVGPROverlappedSrcABWaitStates = 19;
3264 const int DMFMA4x4WritesVGPROverlappedMFMASrcABWaitStates = 6;
3265 const int DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates = 11;
3266 const int GFX950_DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates = 19;
3267 const int DMFMA4x4WritesVGPRFullSrcCWaitStates = 4;
3268 const int GFX940_SMFMA4x4WritesVGPRFullSrcCWaitStates = 2;
3269 const int MaxWaitStates = 19;
3270
3271 if (!Use.isReg())
3272 continue;
3273 Register Reg = Use.getReg();
3274 bool FullReg;
3275 const MachineInstr *MI1;
3276
3277 auto IsOverlappedMFMAFn = [Reg, &FullReg, &MI1,
3278 this](const MachineInstr &MI) {
3279 if (!SIInstrInfo::isMFMA(MI))
3280 return false;
3281 Register DstReg = MI.getOperand(0).getReg();
3282 FullReg = (DstReg == Reg);
3283 MI1 = &MI;
3284 return TRI.regsOverlap(DstReg, Reg);
3285 };
3286
3287 WaitStatesNeededForUse = LegacyVALUNotDotWritesVGPRWaitStates -
3288 getWaitStatesSinceDef(Reg, IsLegacyVALUNotDotFn, MaxWaitStates);
3289 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3290
3291 int NumWaitStates =
3292 getWaitStatesSinceDef(Reg, IsOverlappedMFMAFn, MaxWaitStates);
3293 if (NumWaitStates == std::numeric_limits<int>::max())
3294 continue;
3295
3296 int OpNo = Use.getOperandNo();
3297 unsigned Opc1 = MI1->getOpcode();
3298 int NeedWaitStates = 0;
3299 if (OpNo == SrcCIdx) {
3300 if (!SIInstrInfo::isDGEMM(Opc) &&
3301 (!ST.hasGFX940Insts() && SIInstrInfo::isDGEMM(Opc1))) {
3302 NeedWaitStates = 0;
3303 } else if (FullReg) {
3304 if ((Opc == AMDGPU::V_MFMA_F64_4X4X4F64_e64 ||
3305 Opc == AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64) &&
3306 (Opc1 == AMDGPU::V_MFMA_F64_4X4X4F64_e64 ||
3307 Opc1 == AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64))
3308 NeedWaitStates = DMFMA4x4WritesVGPRFullSrcCWaitStates;
3309 else if (ST.hasGFX940Insts() &&
3310 TSchedModel.computeInstrLatency(MI1) == 2)
3311 NeedWaitStates = GFX940_SMFMA4x4WritesVGPRFullSrcCWaitStates;
3312 } else {
3313 switch (Opc1) {
3314 case AMDGPU::V_MFMA_F64_16X16X4F64_e64:
3315 case AMDGPU::V_MFMA_F64_16X16X4F64_vgprcd_e64:
3316 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_e64:
3317 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_vgprcd_e64:
3318 if (!TII.isXDL(*MI))
3319 NeedWaitStates =
3320 ST.hasGFX950Insts()
3321 ? GFX950_DMFMA16x16WritesVGPROverlappedSrcCWaitStates
3322 : DMFMA16x16WritesVGPROverlappedSrcCWaitStates;
3323 break;
3324 case AMDGPU::V_MFMA_F64_4X4X4F64_e64:
3325 case AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64:
3326 if (!TII.isXDL(*MI))
3327 NeedWaitStates = DMFMA4x4WritesVGPROverlappedSrcCWaitStates;
3328 break;
3329 default:
3330 int NumPasses = TSchedModel.computeInstrLatency(MI1);
3331 if (ST.hasGFX940Insts()) {
3332 if (TII.isXDL(*MI) && !TII.isXDL(*MI1))
3333 break;
3334
3335 NeedWaitStates =
3336 TII.isXDL(*MI1)
3337 ? (TII.isXDL(*MI)
3339 NumPasses, ST.hasGFX950Insts())
3341 NumPasses, ST.hasGFX950Insts()))
3343 NumPasses);
3344 break;
3345 }
3346
3347 switch (NumPasses) {
3348 case 2:
3349 NeedWaitStates =
3351 ? SMFMA4x4WritesVGPROverlappedDMFMASrcCWaitStates
3352 : SMFMA4x4WritesVGPROverlappedSMFMASrcCWaitStates;
3353 break;
3354 case 8:
3355 NeedWaitStates =
3357 ? SMFMA16x16WritesVGPROverlappedDMFMASrcCWaitStates
3358 : SMFMA16x16WritesVGPROverlappedSMFMASrcCWaitStates;
3359 break;
3360 case 16:
3361 NeedWaitStates =
3363 ? SMFMA32x32WritesVGPROverlappedDMFMASrcCWaitStates
3364 : SMFMA32x32WritesVGPROverlappedSMFMASrcCWaitStates;
3365 break;
3366 default:
3367 llvm_unreachable("unexpected number of passes");
3368 }
3369 }
3370 }
3371 } else {
3372 switch (Opc1) {
3373 case AMDGPU::V_MFMA_F64_16X16X4F64_e64:
3374 case AMDGPU::V_MFMA_F64_16X16X4F64_vgprcd_e64:
3375 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_e64:
3376 case AMDGPU::V_MFMA_F64_16X16X4F64_mac_vgprcd_e64:
3377 NeedWaitStates =
3378 ST.hasGFX950Insts()
3379 ? GFX950_DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates
3380 : DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates;
3381 break;
3382 case AMDGPU::V_MFMA_F64_4X4X4F64_e64:
3383 case AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64:
3384 NeedWaitStates = DMFMA4x4WritesVGPROverlappedMFMASrcABWaitStates;
3385 break;
3386 default:
3387 int NumPasses = TSchedModel.computeInstrLatency(MI1);
3388
3389 if (ST.hasGFX940Insts()) {
3390 NeedWaitStates =
3391 TII.isXDL(*MI1)
3393 NumPasses, ST.hasGFX950Insts())
3395 NumPasses);
3396 break;
3397 }
3398
3399 switch (NumPasses) {
3400 case 2:
3401 NeedWaitStates = SMFMA4x4WritesVGPROverlappedSrcABWaitStates;
3402 break;
3403 case 4:
3404 llvm_unreachable("unexpected number of passes for mfma");
3405 case 8:
3406 NeedWaitStates = SMFMA16x16WritesVGPROverlappedSrcABWaitStates;
3407 break;
3408 case 16:
3409 default:
3410 NeedWaitStates = SMFMA32x32WritesVGPROverlappedSrcABWaitStates;
3411 }
3412 }
3413 }
3414 if (WaitStatesNeeded >= NeedWaitStates)
3415 continue;
3416
3417 WaitStatesNeededForUse = NeedWaitStates - NumWaitStates;
3418 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3419
3420 if (WaitStatesNeeded == MaxWaitStates)
3421 break;
3422 }
3423
3424 // Pad neighboring MFMA with noops for better inter-wave performance.
3425 WaitStatesNeeded = std::max(WaitStatesNeeded, checkMFMAPadding(MI));
3426
3427 return WaitStatesNeeded;
3428}
3429
3430int GCNHazardRecognizer::checkMAILdStHazards(MachineInstr *MI) const {
3431 // On gfx90a+ relevant hazards are checked in checkMAIVALUHazards()
3432 if (!ST.hasMAIInsts() || ST.hasGFX90AInsts())
3433 return 0;
3434
3435 int WaitStatesNeeded = 0;
3436
3437 auto IsAccVgprReadFn = [](const MachineInstr &MI) {
3438 return MI.getOpcode() == AMDGPU::V_ACCVGPR_READ_B32_e64;
3439 };
3440
3441 for (const MachineOperand &Op : MI->explicit_uses()) {
3442 if (!Op.isReg() || !TRI.isVGPR(MF.getRegInfo(), Op.getReg()))
3443 continue;
3444
3445 Register Reg = Op.getReg();
3446
3447 const int AccVgprReadLdStWaitStates = 2;
3448 const int VALUWriteAccVgprRdWrLdStDepVALUWaitStates = 1;
3449 const int MaxWaitStates = 2;
3450
3451 int WaitStatesNeededForUse = AccVgprReadLdStWaitStates -
3452 getWaitStatesSinceDef(Reg, IsAccVgprReadFn, MaxWaitStates);
3453 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3454
3455 if (WaitStatesNeeded == MaxWaitStates)
3456 return WaitStatesNeeded; // Early exit.
3457
3458 auto IsVALUAccVgprRdWrCheckFn = [Reg, this](const MachineInstr &MI) {
3459 if (MI.getOpcode() != AMDGPU::V_ACCVGPR_READ_B32_e64 &&
3460 MI.getOpcode() != AMDGPU::V_ACCVGPR_WRITE_B32_e64)
3461 return false;
3462 auto IsVALUFn = [](const MachineInstr &MI) {
3463 return SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true) &&
3465 };
3466 return getWaitStatesSinceDef(Reg, IsVALUFn, 2 /*MaxWaitStates*/) <
3467 std::numeric_limits<int>::max();
3468 };
3469
3470 WaitStatesNeededForUse = VALUWriteAccVgprRdWrLdStDepVALUWaitStates -
3471 getWaitStatesSince(IsVALUAccVgprRdWrCheckFn, MaxWaitStates);
3472 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3473 }
3474
3475 return WaitStatesNeeded;
3476}
3477
3478int GCNHazardRecognizer::checkPermlaneHazards(MachineInstr *MI) const {
3479 assert(!ST.hasVcmpxPermlaneHazard() &&
3480 "this is a different vcmpx+permlane hazard");
3481 const SIRegisterInfo *TRI = ST.getRegisterInfo();
3482 const SIInstrInfo *TII = ST.getInstrInfo();
3483
3484 auto IsVCmpXWritesExecFn = [TII, TRI](const MachineInstr &MI) {
3485 return isVCmpXWritesExec(*TII, *TRI, MI);
3486 };
3487
3488 auto IsVALUFn = [](const MachineInstr &MI) {
3489 return SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true);
3490 };
3491
3492 const int VCmpXWritesExecWaitStates = 4;
3493 const int VALUWritesVDstWaitStates = 2;
3494 int WaitStatesNeeded = 0;
3495
3496 for (const MachineOperand &Op : MI->explicit_uses()) {
3497 if (!Op.isReg() || !TRI->isVGPR(MF.getRegInfo(), Op.getReg()))
3498 continue;
3499 Register Reg = Op.getReg();
3500
3501 int WaitStatesSinceDef =
3502 VALUWritesVDstWaitStates -
3503 getWaitStatesSinceDef(Reg, IsVALUFn,
3504 /*MaxWaitStates=*/VALUWritesVDstWaitStates);
3505 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesSinceDef);
3506 if (WaitStatesNeeded >= VALUWritesVDstWaitStates)
3507 break;
3508 }
3509
3510 int VCmpXHazardWaits =
3511 VCmpXWritesExecWaitStates -
3512 getWaitStatesSince(IsVCmpXWritesExecFn, VCmpXWritesExecWaitStates);
3513
3514 WaitStatesNeeded = std::max(WaitStatesNeeded, VCmpXHazardWaits);
3515 return WaitStatesNeeded;
3516}
3517
3519 // 2 pass -> 4
3520 // 4 pass -> 6
3521 // 8 pass -> 10
3522 // 16 pass -> 18
3523 return NumPasses + 2;
3524}
3525
3527 bool IsGFX950) {
3528 // xdl def cycles | gfx942 | gfx950
3529 // 2 pass | 5 5
3530 // 4 pass | 7 8
3531 // 8 pass | 11 12
3532 // 16 pass | 19 20
3533 return NumPasses + 3 + (NumPasses != 2 && IsGFX950);
3534}
3535
3537 bool IsGFX950) {
3538 // xdl def cycles | gfx942 | gfx950
3539 // 2 pass | 5 5
3540 // 4 pass | 7 8
3541 // 8 pass | 11 12
3542 // 16 pass | 19 20
3543 return NumPasses + 3 + (NumPasses != 2 && IsGFX950);
3544}
3545
3547 // 2 pass -> 4
3548 // 4 pass -> 6
3549 // 8 pass -> 10
3550 // 16 pass -> 18
3551 return NumPasses + 2;
3552}
3553
3554int GCNHazardRecognizer::checkMAIVALUHazards(MachineInstr *MI) const {
3555 if (!ST.hasGFX90AInsts())
3556 return 0;
3557
3558 auto IsDGEMMFn = [](const MachineInstr &MI) -> bool {
3559 return SIInstrInfo::isDGEMM(MI.getOpcode());
3560 };
3561
3562 // This is checked in checkMAIHazards90A()
3563 if (SIInstrInfo::isMFMA(*MI))
3564 return 0;
3565
3566 const MachineRegisterInfo &MRI = MF.getRegInfo();
3567
3568 int WaitStatesNeeded = 0;
3569
3570 bool IsMem = SIInstrInfo::isVMEM(*MI) || SIInstrInfo::isDS(*MI);
3571 bool IsMemOrExport = IsMem || SIInstrInfo::isEXP(*MI);
3572 bool IsVALU = SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true);
3573
3574 const MachineInstr *MFMA = nullptr;
3575 unsigned Reg;
3576 auto IsMFMAWriteFn = [&Reg, &MFMA, this](const MachineInstr &MI) {
3577 if (!SIInstrInfo::isMFMA(MI) ||
3578 !TRI.regsOverlap(MI.getOperand(0).getReg(), Reg))
3579 return false;
3580 MFMA = &MI;
3581 return true;
3582 };
3583
3584 const MachineInstr *DOT = nullptr;
3585 auto IsDotWriteFn = [&Reg, &DOT, this](const MachineInstr &MI) {
3586 if (!SIInstrInfo::isDOT(MI) ||
3587 !TRI.regsOverlap(MI.getOperand(0).getReg(), Reg))
3588 return false;
3589 DOT = &MI;
3590 return true;
3591 };
3592
3593 bool DGEMMAfterVALUWrite = false;
3594 auto IsDGEMMHazard = [&DGEMMAfterVALUWrite, this](const MachineInstr &MI) {
3595 // Found DGEMM on reverse traversal to def.
3596 if (SIInstrInfo::isDGEMM(MI.getOpcode()))
3597 DGEMMAfterVALUWrite = true;
3598
3599 // Only hazard if register is defined by a VALU and a DGEMM is found after
3600 // after the def.
3601 if (!TII.isVALU(MI, /*AllowLDSDMA=*/true) || !DGEMMAfterVALUWrite)
3602 return false;
3603
3604 return true;
3605 };
3606
3607 int SrcCIdx = AMDGPU::getNamedOperandIdx(MI->getOpcode(),
3608 AMDGPU::OpName::src2);
3609
3610 if (IsMemOrExport || IsVALU) {
3611 const int SMFMA4x4WriteVgprVALUMemExpReadWaitStates = 5;
3612 const int SMFMA16x16WriteVgprVALUMemExpReadWaitStates = 11;
3613 const int SMFMA32x32WriteVgprVALUMemExpReadWaitStates = 19;
3614 const int DMFMA4x4WriteVgprMemExpReadWaitStates = 9;
3615 const int DMFMA16x16WriteVgprMemExpReadWaitStates = 18;
3616 const int DMFMA4x4WriteVgprVALUReadWaitStates = 6;
3617 const int DMFMA16x16WriteVgprVALUReadWaitStates = 11;
3618 const int GFX950_DMFMA16x16WriteVgprVALUReadWaitStates = 19;
3619 const int DotWriteSameDotReadSrcAB = 3;
3620 const int DotWriteDifferentVALURead = 3;
3621 const int DMFMABetweenVALUWriteVMEMRead = 2;
3622 const int MaxWaitStates = 19;
3623
3624 for (const MachineOperand &Use : MI->explicit_uses()) {
3625 if (!Use.isReg())
3626 continue;
3627 Reg = Use.getReg();
3628
3629 DOT = nullptr;
3630 int WaitStatesSinceDef = getWaitStatesSinceDef(Reg, IsDotWriteFn,
3631 MaxWaitStates);
3632 if (DOT) {
3633 int NeedWaitStates = 0;
3634 if (DOT->getOpcode() == MI->getOpcode()) {
3635 if (&Use - &MI->getOperand(0) != SrcCIdx)
3636 NeedWaitStates = DotWriteSameDotReadSrcAB;
3637 } else {
3638 NeedWaitStates = DotWriteDifferentVALURead;
3639 }
3640
3641 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceDef;
3642 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3643 }
3644
3645 // Workaround for HW data hazard bug observed only in GFX90A. When there
3646 // is a DGEMM instruction in-between a VALU and a VMEM instruction it
3647 // causes the SQ to incorrectly not insert two wait states between the two
3648 // instructions needed to avoid data hazard.
3649 if (IsMem && ST.hasGFX90AInsts() && !ST.hasGFX940Insts()) {
3650 DGEMMAfterVALUWrite = false;
3651 if (TRI.isVectorRegister(MRI, Reg)) {
3652 int WaitStatesNeededForUse =
3653 DMFMABetweenVALUWriteVMEMRead -
3654 getWaitStatesSinceDef(Reg, IsDGEMMHazard,
3655 DMFMABetweenVALUWriteVMEMRead);
3656
3657 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3658 }
3659 }
3660
3661 MFMA = nullptr;
3662 WaitStatesSinceDef =
3663 getWaitStatesSinceDef(Reg, IsMFMAWriteFn, MaxWaitStates);
3664 if (!MFMA)
3665 continue;
3666
3667 unsigned HazardDefLatency = TSchedModel.computeInstrLatency(MFMA);
3668 int NumPasses = HazardDefLatency;
3669 int NeedWaitStates = MaxWaitStates;
3670
3671 if (SIInstrInfo::isDGEMM(MFMA->getOpcode())) {
3672 switch (HazardDefLatency) {
3673 case 4:
3674 NeedWaitStates = IsMemOrExport ? DMFMA4x4WriteVgprMemExpReadWaitStates
3675 : DMFMA4x4WriteVgprVALUReadWaitStates;
3676 break;
3677 case 8:
3678 case 16:
3679 NeedWaitStates =
3680 IsMemOrExport
3681 ? DMFMA16x16WriteVgprMemExpReadWaitStates
3682 : (ST.hasGFX950Insts()
3683 ? GFX950_DMFMA16x16WriteVgprVALUReadWaitStates
3684 : DMFMA16x16WriteVgprVALUReadWaitStates);
3685 break;
3686 default:
3687 llvm_unreachable("unexpected dgemm");
3688 }
3689 } else if (ST.hasGFX940Insts()) {
3690 NeedWaitStates =
3691 TII.isXDL(*MFMA)
3693 NumPasses, ST.hasGFX950Insts())
3695 NumPasses);
3696 } else {
3697 switch (HazardDefLatency) {
3698 case 2:
3699 NeedWaitStates = SMFMA4x4WriteVgprVALUMemExpReadWaitStates;
3700 break;
3701 case 8:
3702 NeedWaitStates = SMFMA16x16WriteVgprVALUMemExpReadWaitStates;
3703 break;
3704 case 16:
3705 NeedWaitStates = SMFMA32x32WriteVgprVALUMemExpReadWaitStates;
3706 break;
3707 default:
3708 llvm_unreachable("unexpected number of passes for mfma");
3709 }
3710 }
3711
3712 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceDef;
3713 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3714
3715 if (WaitStatesNeeded == MaxWaitStates)
3716 break;
3717 }
3718 }
3719
3720 unsigned Opc = MI->getOpcode();
3721 const int DMFMAToFMA64WaitStates = 2;
3722 if ((Opc == AMDGPU::V_FMA_F64_e64 ||
3723 Opc == AMDGPU::V_FMAC_F64_e32 || Opc == AMDGPU::V_FMAC_F64_e64 ||
3724 Opc == AMDGPU::V_FMAC_F64_dpp) &&
3725 WaitStatesNeeded < DMFMAToFMA64WaitStates) {
3726 int WaitStatesNeededForUse = DMFMAToFMA64WaitStates -
3727 getWaitStatesSince(IsDGEMMFn, DMFMAToFMA64WaitStates);
3728 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3729 }
3730
3731 if (!IsVALU && !IsMemOrExport)
3732 return WaitStatesNeeded;
3733
3734 for (const MachineOperand &Def : MI->defs()) {
3735 const int SMFMA4x4WriteVgprVALUWawWaitStates = 5;
3736 const int SMFMA16x16WriteVgprVALUWawWaitStates = 11;
3737 const int SMFMA32x32WriteVgprVALUWawWaitStates = 19;
3738 const int SMFMA4x4ReadVgprVALUWarWaitStates = 1;
3739 const int GFX940_XDL4PassReadVgprVALUWarWaitStates = 3;
3740 const int SMFMA16x16ReadVgprVALUWarWaitStates = 7;
3741 const int SMFMA32x32ReadVgprVALUWarWaitStates = 15;
3742 const int DMFMA4x4WriteVgprVALUWriteWaitStates = 6;
3743 const int DMFMA16x16WriteVgprVALUWriteWaitStates = 11;
3744 const int DotWriteDifferentVALUWrite = 3;
3745 const int MaxWaitStates = 19;
3746 const int MaxWarWaitStates = 15;
3747
3748 Reg = Def.getReg();
3749
3750 DOT = nullptr;
3751 int WaitStatesSinceDef = getWaitStatesSinceDef(Reg, IsDotWriteFn,
3752 MaxWaitStates);
3753 if (DOT && DOT->getOpcode() != MI->getOpcode())
3754 WaitStatesNeeded = std::max(WaitStatesNeeded, DotWriteDifferentVALUWrite -
3755 WaitStatesSinceDef);
3756
3757 MFMA = nullptr;
3758 WaitStatesSinceDef =
3759 getWaitStatesSinceDef(Reg, IsMFMAWriteFn, MaxWaitStates);
3760 if (MFMA) {
3761 int NeedWaitStates = MaxWaitStates;
3762 int NumPasses = TSchedModel.computeInstrLatency(MFMA);
3763
3764 if (SIInstrInfo::isDGEMM(MFMA->getOpcode())) {
3765 switch (NumPasses) {
3766 case 4:
3767 NeedWaitStates = DMFMA4x4WriteVgprVALUWriteWaitStates;
3768 break;
3769 case 8:
3770 case 16:
3771 NeedWaitStates = DMFMA16x16WriteVgprVALUWriteWaitStates;
3772 break;
3773 default:
3774 llvm_unreachable("unexpected number of cycles for dgemm");
3775 }
3776 } else if (ST.hasGFX940Insts()) {
3777 NeedWaitStates =
3778 TII.isXDL(*MFMA)
3780 NumPasses, ST.hasGFX950Insts())
3782 } else {
3783 switch (NumPasses) {
3784 case 2:
3785 NeedWaitStates = SMFMA4x4WriteVgprVALUWawWaitStates;
3786 break;
3787 case 8:
3788 NeedWaitStates = SMFMA16x16WriteVgprVALUWawWaitStates;
3789 break;
3790 case 16:
3791 NeedWaitStates = SMFMA32x32WriteVgprVALUWawWaitStates;
3792 break;
3793 default:
3794 llvm_unreachable("Unexpected number of passes for mfma");
3795 }
3796 }
3797
3798 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceDef;
3799 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3800
3801 if (WaitStatesNeeded == MaxWaitStates)
3802 break;
3803 }
3804
3805 auto IsSMFMAReadAsCFn = [&Reg, &MFMA, this](const MachineInstr &MI) {
3806 if (!SIInstrInfo::isMFMA(MI) || SIInstrInfo::isDGEMM(MI.getOpcode()) ||
3807 !MI.readsRegister(Reg, &TRI))
3808 return false;
3809
3810 if (ST.hasGFX940Insts() && !TII.isXDL(MI))
3811 return false;
3812
3813 const MachineOperand *SrcC =
3814 TII.getNamedOperand(MI, AMDGPU::OpName::src2);
3815 assert(SrcC);
3816 if (!SrcC->isReg() || !TRI.regsOverlap(SrcC->getReg(), Reg))
3817 return false;
3818
3819 MFMA = &MI;
3820 return true;
3821 };
3822
3823 MFMA = nullptr;
3824 int WaitStatesSinceUse = getWaitStatesSince(IsSMFMAReadAsCFn,
3825 MaxWarWaitStates);
3826 if (!MFMA)
3827 continue;
3828
3829 unsigned HazardDefLatency = TSchedModel.computeInstrLatency(MFMA);
3830 int NeedWaitStates = MaxWaitStates;
3831 switch (HazardDefLatency) {
3832 case 2: NeedWaitStates = SMFMA4x4ReadVgprVALUWarWaitStates;
3833 break;
3834 case 4: assert(ST.hasGFX940Insts());
3835 NeedWaitStates = GFX940_XDL4PassReadVgprVALUWarWaitStates;
3836 break;
3837 case 8: NeedWaitStates = SMFMA16x16ReadVgprVALUWarWaitStates;
3838 break;
3839 case 16: [[fallthrough]];
3840 default: NeedWaitStates = SMFMA32x32ReadVgprVALUWarWaitStates;
3841 break;
3842 }
3843
3844 int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceUse;
3845 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
3846 }
3847
3848 return WaitStatesNeeded;
3849}
3850
3852 if (!SU->isInstr())
3853 return false;
3854
3855 const MachineInstr *MAI = nullptr;
3856
3857 auto IsMFMAFn = [&MAI](const MachineInstr &MI) {
3858 MAI = nullptr;
3860 MAI = &MI;
3861 return MAI != nullptr;
3862 };
3863
3864 MachineInstr *MI = SU->getInstr();
3865 if (IsMFMAFn(*MI)) {
3866 int W = getWaitStatesSince(IsMFMAFn, 16);
3867 if (MAI)
3868 return W < (int)TSchedModel.computeInstrLatency(MAI);
3869 }
3870
3871 return false;
3872}
3873
3874// Adjust global offsets for instructions bundled with S_GETPC_B64 after
3875// insertion of a new instruction.
3876static void updateGetPCBundle(MachineInstr *NewMI) {
3877 if (!NewMI->isBundled())
3878 return;
3879
3880 // Find start of bundle.
3881 auto I = NewMI->getIterator();
3882 while (I->isBundledWithPred())
3883 I--;
3884 if (I->isBundle())
3885 I++;
3886
3887 // Bail if this is not an S_GETPC bundle.
3888 if (I->getOpcode() != AMDGPU::S_GETPC_B64)
3889 return;
3890
3891 // Update offsets of any references in the bundle.
3892 const unsigned NewBytes = 4;
3893 assert(NewMI->getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
3894 "Unexpected instruction insertion in bundle");
3895 auto NextMI = std::next(NewMI->getIterator());
3896 auto End = NewMI->getParent()->end();
3897 while (NextMI != End && NextMI->isBundledWithPred()) {
3898 for (auto &Operand : NextMI->operands()) {
3899 if (Operand.isGlobal())
3900 Operand.setOffset(Operand.getOffset() + NewBytes);
3901 }
3902 NextMI++;
3903 }
3904}
3905
3906bool GCNHazardRecognizer::fixVALUMaskWriteHazard(MachineInstr *MI) {
3907 if (!ST.hasVALUMaskWriteHazard())
3908 return false;
3909 assert(!ST.hasExtendedWaitCounts());
3910
3911 if (!ST.isWave64())
3912 return false;
3913
3914 const bool IsSALU = SIInstrInfo::isSALU(*MI);
3915 const bool IsVALU = SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true);
3916 if (!IsSALU && !IsVALU)
3917 return false;
3918
3919 // The hazard sequence is three instructions:
3920 // 1. VALU reads SGPR as mask
3921 // 2. VALU/SALU writes SGPR
3922 // 3. VALU/SALU reads SGPR
3923 // The hazard can expire if the distance between 2 and 3 is sufficient,
3924 // or (2) is VALU and (3) is SALU.
3925 // In practice this happens <10% of the time, hence always assume the hazard
3926 // exists if (1) and (2) are present to avoid searching all SGPR reads.
3927
3928 const SIRegisterInfo *TRI = ST.getRegisterInfo();
3929 const MachineRegisterInfo &MRI = MF.getRegInfo();
3930
3931 auto IgnoreableSGPR = [](const Register Reg) {
3932 switch (Reg) {
3933 case AMDGPU::EXEC:
3934 case AMDGPU::EXEC_LO:
3935 case AMDGPU::EXEC_HI:
3936 case AMDGPU::M0:
3937 case AMDGPU::SGPR_NULL:
3938 case AMDGPU::SGPR_NULL64:
3939 case AMDGPU::SCC:
3940 return true;
3941 default:
3942 return false;
3943 }
3944 };
3945 auto IsVCC = [](const Register Reg) {
3946 return Reg == AMDGPU::VCC || Reg == AMDGPU::VCC_LO || Reg == AMDGPU::VCC_HI;
3947 };
3948
3949 struct StateType {
3950 SmallSet<Register, 2> HazardSGPRs;
3951
3952 static unsigned getHashValue(const StateType &State) {
3953 return hash_combine_range(State.HazardSGPRs);
3954 }
3955 static bool isEqual(const StateType &LHS, const StateType &RHS) {
3956 return LHS.HazardSGPRs == RHS.HazardSGPRs;
3957 }
3958 };
3959
3960 SmallVector<const MachineInstr *> WaitInstrs;
3961 StateType InitialState;
3962
3963 // Look for SGPR write.
3964 MachineOperand *HazardDef = nullptr;
3965 for (MachineOperand &Op : MI->all_defs()) {
3966 Register Reg = Op.getReg();
3967 if (IgnoreableSGPR(Reg))
3968 continue;
3969 if (!IsVCC(Reg)) {
3970 if (Op.isImplicit())
3971 continue;
3972 if (!TRI->isSGPRReg(MRI, Reg))
3973 continue;
3974 }
3975
3976 HazardDef = &Op;
3977 break;
3978 }
3979
3980 if (!HazardDef)
3981 return false;
3982
3983 // Setup to track writes to individual SGPRs
3984 const Register HazardReg = HazardDef->getReg();
3985 if (AMDGPU::SReg_32RegClass.contains(HazardReg)) {
3986 InitialState.HazardSGPRs.insert(HazardReg);
3987 } else {
3988 assert(AMDGPU::SReg_64RegClass.contains(HazardReg));
3989 InitialState.HazardSGPRs.insert(TRI->getSubReg(HazardReg, AMDGPU::sub0));
3990 InitialState.HazardSGPRs.insert(TRI->getSubReg(HazardReg, AMDGPU::sub1));
3991 }
3992
3993 auto IsHazardFn = [&](StateType &State, const MachineInstr &I) {
3994 if (State.HazardSGPRs.empty())
3995 return HazardExpired;
3996
3997 switch (I.getOpcode()) {
3998 case AMDGPU::V_ADDC_U32_e32:
3999 case AMDGPU::V_ADDC_U32_dpp:
4000 case AMDGPU::V_CNDMASK_B16_t16_e32:
4001 case AMDGPU::V_CNDMASK_B16_fake16_e32:
4002 case AMDGPU::V_CNDMASK_B16_t16_dpp:
4003 case AMDGPU::V_CNDMASK_B16_fake16_dpp:
4004 case AMDGPU::V_CNDMASK_B32_e32:
4005 case AMDGPU::V_CNDMASK_B32_dpp:
4006 case AMDGPU::V_DIV_FMAS_F32_e64:
4007 case AMDGPU::V_DIV_FMAS_F64_e64:
4008 case AMDGPU::V_SUBB_U32_e32:
4009 case AMDGPU::V_SUBB_U32_dpp:
4010 case AMDGPU::V_SUBBREV_U32_e32:
4011 case AMDGPU::V_SUBBREV_U32_dpp: {
4012 // These implicitly read VCC as mask source.
4013 return IsVCC(HazardReg) ? HazardFound : NoHazardFound;
4014 }
4015 case AMDGPU::V_ADDC_U32_e64:
4016 case AMDGPU::V_ADDC_U32_e64_dpp:
4017 case AMDGPU::V_CNDMASK_B16_t16_e64:
4018 case AMDGPU::V_CNDMASK_B16_fake16_e64:
4019 case AMDGPU::V_CNDMASK_B16_t16_e64_dpp:
4020 case AMDGPU::V_CNDMASK_B16_fake16_e64_dpp:
4021 case AMDGPU::V_CNDMASK_B32_e64:
4022 case AMDGPU::V_CNDMASK_B32_e64_dpp:
4023 case AMDGPU::V_SUBB_U32_e64:
4024 case AMDGPU::V_SUBB_U32_e64_dpp:
4025 case AMDGPU::V_SUBBREV_U32_e64:
4026 case AMDGPU::V_SUBBREV_U32_e64_dpp: {
4027 // Only check mask register overlaps.
4028 const MachineOperand *SSRCOp = TII.getNamedOperand(I, AMDGPU::OpName::src2);
4029 assert(SSRCOp);
4030 bool Result = TRI->regsOverlap(SSRCOp->getReg(), HazardReg);
4031 return Result ? HazardFound : NoHazardFound;
4032 }
4033 default:
4034 return NoHazardFound;
4035 }
4036 };
4037
4038 auto UpdateStateFn = [&](StateType &State, const MachineInstr &I) {
4039 // Update tracking of SGPR writes.
4040 for (auto &Op : I.all_defs()) {
4041 Register Reg = Op.getReg();
4042 if (IgnoreableSGPR(Reg))
4043 continue;
4044 if (!IsVCC(Reg)) {
4045 if (Op.isImplicit())
4046 continue;
4047 if (!TRI->isSGPRReg(MRI, Reg))
4048 continue;
4049 }
4050
4051 // Stop tracking any SGPRs with writes on the basis that they will
4052 // already have an appropriate wait inserted afterwards.
4054 for (Register SGPR : State.HazardSGPRs) {
4055 if (Reg == SGPR || TRI->regsOverlap(Reg, SGPR))
4056 Found.push_back(SGPR);
4057 }
4058 for (Register SGPR : Found)
4059 State.HazardSGPRs.erase(SGPR);
4060 }
4061 };
4062
4063 // Check for hazard
4064 if (!hasHazard<StateType>(InitialState, IsHazardFn, UpdateStateFn,
4065 MI->getParent(),
4066 std::next(MI->getReverseIterator())))
4067 return false;
4068
4069 // Compute counter mask
4070 unsigned DepCtr =
4071 IsVALU ? (IsVCC(HazardReg) ? AMDGPU::DepCtr::encodeFieldVaVcc(0, ST)
4072 : AMDGPU::DepCtr::encodeFieldVaSdst(0, ST))
4073 : AMDGPU::DepCtr::encodeFieldSaSdst(0, ST);
4074
4075 // Add s_waitcnt_depctr after SGPR write.
4076 auto NextMI = std::next(MI->getIterator());
4077 auto NewMI = BuildMI(*MI->getParent(), NextMI, MI->getDebugLoc(),
4078 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
4079 .addImm(DepCtr);
4080
4081 // SALU write may be s_getpc in a bundle.
4082 updateGetPCBundle(NewMI);
4083
4084 return true;
4085}
4086
4087static bool ensureEntrySetPrio(MachineFunction *MF, int Priority,
4088 const SIInstrInfo &TII) {
4089 MachineBasicBlock &EntryMBB = MF->front();
4090 if (EntryMBB.begin() != EntryMBB.end()) {
4091 auto &EntryMI = *EntryMBB.begin();
4092 if (EntryMI.getOpcode() == AMDGPU::S_SETPRIO &&
4093 EntryMI.getOperand(0).getImm() >= Priority)
4094 return false;
4095 }
4096
4097 BuildMI(EntryMBB, EntryMBB.begin(), DebugLoc(), TII.get(AMDGPU::S_SETPRIO))
4098 .addImm(Priority);
4099 return true;
4100}
4101
4102bool GCNHazardRecognizer::fixRequiredExportPriority(MachineInstr *MI) {
4103 if (!ST.hasRequiredExportPriority())
4104 return false;
4105
4106 // Assume the following shader types will never have exports,
4107 // and avoid adding or adjusting S_SETPRIO.
4108 MachineBasicBlock *MBB = MI->getParent();
4109 MachineFunction *MF = MBB->getParent();
4110 auto CC = MF->getFunction().getCallingConv();
4111 switch (CC) {
4116 return false;
4117 default:
4118 break;
4119 }
4120
4121 const int MaxPriority = 3;
4122 const int NormalPriority = 2;
4123 const int PostExportPriority = 0;
4124
4125 auto It = MI->getIterator();
4126 switch (MI->getOpcode()) {
4127 case AMDGPU::S_ENDPGM:
4128 case AMDGPU::S_ENDPGM_SAVED:
4129 case AMDGPU::S_ENDPGM_ORDERED_PS_DONE:
4130 case AMDGPU::SI_RETURN_TO_EPILOG:
4131 // Ensure shader with calls raises priority at entry.
4132 // This ensures correct priority if exports exist in callee.
4133 if (MF->getFrameInfo().hasCalls())
4134 return ensureEntrySetPrio(MF, NormalPriority, TII);
4135 return false;
4136 case AMDGPU::S_SETPRIO: {
4137 // Raise minimum priority unless in workaround.
4138 auto &PrioOp = MI->getOperand(0);
4139 int Prio = PrioOp.getImm();
4140 bool InWA = (Prio == PostExportPriority) &&
4141 (It != MBB->begin() && TII.isEXP(*std::prev(It)));
4142 if (InWA || Prio >= NormalPriority)
4143 return false;
4144 PrioOp.setImm(std::min(Prio + NormalPriority, MaxPriority));
4145 return true;
4146 }
4147 default:
4148 if (!TII.isEXP(*MI))
4149 return false;
4150 break;
4151 }
4152
4153 // Check entry priority at each export (as there will only be a few).
4154 // Note: amdgpu_gfx can only be a callee, so defer to caller setprio.
4155 bool Changed = false;
4157 Changed = ensureEntrySetPrio(MF, NormalPriority, TII);
4158
4159 auto NextMI = std::next(It);
4160 bool EndOfShader = false;
4161 if (NextMI != MBB->end()) {
4162 // Only need WA at end of sequence of exports.
4163 if (TII.isEXP(*NextMI))
4164 return Changed;
4165 // Assume appropriate S_SETPRIO after export means WA already applied.
4166 if (NextMI->getOpcode() == AMDGPU::S_SETPRIO &&
4167 NextMI->getOperand(0).getImm() == PostExportPriority)
4168 return Changed;
4169 EndOfShader = NextMI->getOpcode() == AMDGPU::S_ENDPGM;
4170 }
4171
4172 const DebugLoc &DL = MI->getDebugLoc();
4173
4174 // Lower priority.
4175 BuildMI(*MBB, NextMI, DL, TII.get(AMDGPU::S_SETPRIO))
4176 .addImm(PostExportPriority);
4177
4178 if (!EndOfShader) {
4179 // Wait for exports to complete.
4180 BuildMI(*MBB, NextMI, DL, TII.get(AMDGPU::S_WAITCNT_EXPCNT))
4181 .addReg(AMDGPU::SGPR_NULL)
4182 .addImm(0);
4183 }
4184
4185 BuildMI(*MBB, NextMI, DL, TII.get(AMDGPU::S_NOP)).addImm(0);
4186 BuildMI(*MBB, NextMI, DL, TII.get(AMDGPU::S_NOP)).addImm(0);
4187
4188 if (!EndOfShader) {
4189 // Return to normal (higher) priority.
4190 BuildMI(*MBB, NextMI, DL, TII.get(AMDGPU::S_SETPRIO))
4191 .addImm(NormalPriority);
4192 }
4193
4194 return true;
4195}
4196
4197bool GCNHazardRecognizer::fixGetRegWaitIdle(MachineInstr *MI) {
4198 if (!isSGetReg(MI->getOpcode()))
4199 return false;
4200
4201 const SIInstrInfo *TII = ST.getInstrInfo();
4202 switch (getHWReg(TII, *MI)) {
4203 default:
4204 return false;
4209 break;
4210 }
4211
4212 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
4213 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4214 .addImm(0);
4215 return true;
4216}
4217
4218bool GCNHazardRecognizer::fixDsAtomicAsyncBarrierArriveB64(MachineInstr *MI) {
4219 if (MI->getOpcode() != AMDGPU::DS_ATOMIC_ASYNC_BARRIER_ARRIVE_B64)
4220 return false;
4221
4222 const SIInstrInfo *TII = ST.getInstrInfo();
4223 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
4224 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4226 BuildMI(*MI->getParent(), std::next(MI->getIterator()), MI->getDebugLoc(),
4227 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4229
4230 return true;
4231}
4232
4233bool GCNHazardRecognizer::fixScratchBaseForwardingHazard(MachineInstr *MI) {
4234 // No reason to check this in pre-RA scheduling, SGPRs have to be allocated
4235 // for hazard to trigger.
4237 return false;
4238
4239 const SIRegisterInfo *TRI = ST.getRegisterInfo();
4240 const SIInstrInfo *TII = ST.getInstrInfo();
4241 // Hazard expires after 10 SGPR writes by SALU or 8 SGPR writes by VALU.
4242 const int FlatScrBaseWaitStates = 10;
4243
4244 bool ReadsFlatScrLo =
4245 MI->readsRegister(AMDGPU::SRC_FLAT_SCRATCH_BASE_LO, TRI);
4246 bool ReadsFlatScrHi =
4247 MI->readsRegister(AMDGPU::SRC_FLAT_SCRATCH_BASE_HI, TRI);
4248 if (isSGetReg(MI->getOpcode())) {
4249 switch (getHWReg(TII, *MI)) {
4250 default:
4251 break;
4253 ReadsFlatScrLo = true;
4254 break;
4256 ReadsFlatScrHi = true;
4257 break;
4258 }
4259 }
4260
4261 const MachineRegisterInfo &MRI = MF.getRegInfo();
4262
4263 auto IsRegDefHazard = [&](Register Reg) -> bool {
4264 DenseSet<const MachineBasicBlock *> Visited;
4265 auto IsHazardFn = [TRI, Reg](const MachineInstr &MI) {
4266 return MI.modifiesRegister(Reg, TRI);
4267 };
4268
4269 // This literally abuses the idea of waitstates. Instead of waitstates it
4270 // returns 1 for SGPR written and 0 otherwise.
4271 auto IsSGPRDef = [TII, TRI, &MRI](const MachineInstr &MI) -> unsigned {
4272 if (!TII->isSALU(MI) && !TII->isVALU(MI, /*AllowLDSDMA=*/true))
4273 return 0;
4274 for (const MachineOperand &MO : MI.all_defs()) {
4275 if (TRI->isSGPRReg(MRI, MO.getReg()))
4276 return 1;
4277 }
4278 return 0;
4279 };
4280
4281 auto IsExpiredFn = [=](const MachineInstr &MI, int SgprWrites) {
4282 if (MI.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR) {
4283 unsigned Wait = MI.getOperand(0).getImm();
4286 return true;
4287 }
4288 return SgprWrites >= FlatScrBaseWaitStates;
4289 };
4290
4291 return ::getWaitStatesSince(
4292 IsHazardFn, MI->getParent(), std::next(MI->getReverseIterator()),
4293 0, IsExpiredFn, Visited, IsSGPRDef) < FlatScrBaseWaitStates;
4294 };
4295
4296 if ((!ReadsFlatScrLo || MRI.isConstantPhysReg(AMDGPU::SGPR102) ||
4297 !IsRegDefHazard(AMDGPU::SGPR102)) &&
4298 (!ReadsFlatScrHi || MRI.isConstantPhysReg(AMDGPU::SGPR103) ||
4299 !IsRegDefHazard(AMDGPU::SGPR103)))
4300 return false;
4301
4302 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
4303 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
4306 return true;
4307}
4308
4309bool GCNHazardRecognizer::fixSetRegMode(MachineInstr *MI) {
4310 if (!isSSetReg(MI->getOpcode()) ||
4311 MI->getOperand(1).getImm() != AMDGPU::Hwreg::ID_MODE)
4312 return false;
4313
4314 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), TII.get(AMDGPU::V_NOP_e32));
4315 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), TII.get(AMDGPU::V_NOP_e32));
4316 return true;
4317}
4318
4319bool GCNHazardRecognizer::fixTDM(MachineInstr *MI) {
4320 auto IsTDM = [&](const MachineInstr &MI) -> bool {
4322 MI.getOpcode() != AMDGPU::S_WAIT_TENSORCNT;
4323 };
4324
4325 if (!IsTDM(*MI))
4326 return false;
4327
4328 auto IsExpiredFn = [](const MachineInstr &MI, int) {
4329 if (MI.getOpcode() != AMDGPU::S_WAIT_TENSORCNT)
4330 return false;
4331 return MI.getOperand(0).getImm() <= 10;
4332 };
4333
4334 if (::getWaitStatesSince(IsTDM, MI, IsExpiredFn) ==
4335 std::numeric_limits<int>::max())
4336 return false;
4337
4338 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
4339 TII.get(AMDGPU::S_WAIT_TENSORCNT))
4340 .addImm(10);
4341 return true;
4342}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
unsigned Imm
AMDGPU Rewrite AGPR Copy MFMA
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< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static cl::opt< unsigned, false, MFMAPaddingRatioParser > MFMAPaddingRatio("amdgpu-mfma-padding-ratio", cl::init(0), cl::Hidden, cl::desc("Fill a percentage of the latency between " "neighboring MFMA with s_nops."))
static bool shouldRunLdsBranchVmemWARHazardFixup(const MachineFunction &MF, const GCNSubtarget &ST)
static cl::opt< bool > EnableWMMAVnopHoisting("amdgpu-wmma-vnop-hoisting", cl::init(true), cl::Hidden, cl::desc("Hoist WMMA hazard V_NOPs from loops to preheaders"))
static bool consumesDstSelForwardingOperand(const MachineInstr *VALU, const MachineOperand *Dst, const SIRegisterInfo *TRI)
Checks whether the provided MI "consumes" the operand with a Dest sel fowarding issue Dst .
static bool isSGetReg(unsigned Opcode)
static bool breaksSMEMSoftClause(MachineInstr *MI)
static bool isLdsDma(const MachineInstr &MI)
static int GFX940_XDL_N_PassWritesVGPROverlappedSrcABWaitStates(int NumPasses, bool IsGFX950)
static unsigned getWMMAHazardInstInCategory(const MachineInstr &MI, const SIInstrInfo *TII, const TargetSchedModel &SchedModel, const GCNSubtarget &ST)
static bool isRFE(unsigned Opcode)
static bool isRWLane(unsigned Opcode)
static bool isSMovRel(unsigned Opcode)
#define DEBUG_TYPE_VERBOSE
static const MachineOperand * getDstSelForwardingOperand(const MachineInstr &MI, const GCNSubtarget &ST)
Dest sel forwarding issue occurs if additional logic is needed to swizzle / pack the computed value i...
static int GFX940_XDL_N_PassWritesVGPROverlappedSGEMMDGEMMSrcCWaitStates(int NumPasses, bool IsGFX950)
static void updateGetPCBundle(MachineInstr *NewMI)
static int GFX940_XDL_N_PassWriteVgprVALUMemExpReadWaitStates(int NumPasses, bool IsGFX950)
static bool isStoreCountWaitZero(const MachineInstr &I)
static bool breaksVMEMSoftClause(MachineInstr *MI)
static bool isVCmpXWritesExec(const SIInstrInfo &TII, const SIRegisterInfo &TRI, const MachineInstr &MI)
static bool isSSetReg(unsigned Opcode)
static void addRegUnits(const SIRegisterInfo &TRI, BitVector &BV, MCRegister Reg)
static unsigned getHWReg(const SIInstrInfo *TII, const MachineInstr &RegInstr)
static bool isDivFMas(unsigned Opcode)
static bool hasHazard(StateT InitialState, function_ref< HazardFnResult(StateT &, const MachineInstr &)> IsHazard, function_ref< void(StateT &, const MachineInstr &)> UpdateState, const MachineBasicBlock *InitialMBB, MachineBasicBlock::const_reverse_instr_iterator InitialI)
static int getWaitStatesSince(GCNHazardRecognizer::IsHazardFn IsHazard, const MachineBasicBlock *MBB, MachineBasicBlock::const_reverse_instr_iterator I, int WaitStates, GCNHazardRecognizer::IsExpiredFn IsExpired, DenseSet< const MachineBasicBlock * > &Visited, GCNHazardRecognizer::GetNumWaitStatesFn GetNumWaitStates=SIInstrInfo::getNumWaitStates)
static int GFX940_SMFMA_N_PassWritesVGPROverlappedSrcABWaitStates(int NumPasses)
static int GFX940_XDL_N_PassWriteVgprVALUWawWaitStates(int NumPasses, bool IsGFX950)
static int GFX940_SMFMA_N_PassWriteVgprVALUMemExpReadWaitStates(int NumPasses)
static int GFX940_SMFMA_N_PassWritesVGPROverlappedSMFMASrcCWaitStates(int NumPasses)
static bool isCoexecutableVALUInst(const MachineInstr &MI)
static bool ensureEntrySetPrio(MachineFunction *MF, int Priority, const SIInstrInfo &TII)
static void addRegsToSet(const SIRegisterInfo &TRI, iterator_range< MachineInstr::const_mop_iterator > Ops, BitVector &DefSet, BitVector &UseSet)
static void insertNoopsInBundle(MachineInstr *MI, const SIInstrInfo &TII, unsigned Quantity)
static bool isSendMsgTraceDataOrGDS(const SIInstrInfo &TII, const MachineInstr &MI)
static cl::opt< unsigned > NopPadding("amdgpu-snop-padding", cl::init(0), cl::Hidden, cl::desc("Insert a s_nop x before every instruction"))
static bool isPermlane(const MachineInstr &MI)
static int GFX940_SMFMA_N_PassWriteVgprVALUWawWaitStates(int NumPasses)
static int GFX940_XDL_N_PassWritesVGPROverlappedXDLOrSMFMASrcCWaitStates(int NumPasses, bool IsGFX950)
AMD GCN specific subclass of TargetSubtarget.
static Register UseReg(const MachineOperand &MO)
const HexagonInstrInfo * TII
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
Register Reg
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
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:317
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.
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 isVALU(const MachineInstr &MI, bool AllowLDSDMA)
static bool isTRANS(const MachineInstr &MI)
static bool isMUBUF(const MachineInstr &MI)
static bool isWaitcnt(unsigned Opcode)
static bool isDPP(const MachineInstr &MI)
static bool isMFMA(const MachineInstr &MI)
static bool isMAI(const MCInstrDesc &Desc)
static bool isFPAtomic(const MachineInstr &MI)
static bool isMIMG(const MachineInstr &MI)
static unsigned getNumWaitStates(const MachineInstr &MI)
Return the number of wait states that result from executing this instruction.
static bool isWMMA(const MachineInstr &MI)
static bool isFLAT(const MachineInstr &MI)
static bool isLDSDMA(const MachineInstr &MI)
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.
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(uint64_t Opcode, OpName NamedIdx)
InstructionFlavor classifyFlavor(const MachineInstr &MI, const SIInstrInfo &SII)
Classify MI into the execution flavor that drives both the scheduler's slot preferences and the hazar...
constexpr CoExecMaskT getCoExecMask(InstructionFlavor F)
Map a flavor to the co-execution class it occupies in a window slot.
bool isGFX1250(const MCSubtargetInfo &STI)
@ 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 MCSchedule.h:35
initializer< Ty > init(const Ty &Val)
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:315
@ Offset
Definition DWP.cpp:577
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
@ Kill
The last use of a register.
@ Undef
Value of the register doesn't matter.
@ Define
Register definition.
@ Wait
Definition Threading.h:60
constexpr RegState getDeadRegState(bool B)
Op::Description Desc
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
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
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:305
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:285
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...