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) {
546}
547
548static unsigned getHWReg(const SIInstrInfo *TII, const MachineInstr &RegInstr) {
549 const MachineOperand *RegOp = TII->getNamedOperand(RegInstr,
550 AMDGPU::OpName::simm16);
551 return std::get<0>(AMDGPU::Hwreg::HwregEncoding::decode(RegOp->getImm()));
552}
553
556 MachineInstr *MI = SU->getInstr();
557 // If we are not in "HazardRecognizerMode" and therefore not being run from
558 // the scheduler, track possible stalls from hazards but don't insert noops.
560
561 if (MI->isBundle())
562 return NoHazard;
563
564 // Check co-execution slot hazards and pipeline stalls in scheduler modes.
565 if (isSchedulerMode()) {
566 if (checkMultiShadowHazard(*MI) > 0)
567 return Hazard;
568 if (checkWMMACoexecSlot(*MI) > 0)
569 return Hazard;
570 if (checkTRANSHazard(*MI) > 0)
571 return Hazard;
572 if (checkMultiCycleVALUHazard(*MI) > 0)
573 return Hazard;
574 // The remaining checks are all defined by register dependences.
575 if (!hasPhysRegs())
576 return NoHazard;
577 }
578
579 if (SIInstrInfo::isSMRD(*MI) && checkSMRDHazards(MI) > 0)
580 return HazardType;
581
582 if (ST.hasNSAtoVMEMBug() && checkNSAtoVMEMHazard(MI) > 0)
583 return HazardType;
584
585 if (checkFPAtomicToDenormModeHazard(MI) > 0)
586 return HazardType;
587
588 // Hazards which cannot be mitigated with S_NOPs.
589 if (!isHazardRecognizerMode()) {
590 if (checkWMMACoexecutionHazards(MI) > 0) {
591 HasPendingWMMACoexecHazard = true;
592 return Hazard;
593 }
594 }
595
596 if (ST.hasNoDataDepHazard())
597 return NoHazard;
598
599 if (SIInstrInfo::isVMEM(*MI) && checkVMEMHazards(MI) > 0)
600 return HazardType;
601
602 if (SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true) &&
603 checkVALUHazards(MI) > 0)
604 return HazardType;
605
606 if (SIInstrInfo::isDPP(*MI) && checkDPPHazards(MI) > 0)
607 return HazardType;
608
609 if (isDivFMas(MI->getOpcode()) && checkDivFMasHazards(MI) > 0)
610 return HazardType;
611
612 if (isRWLane(MI->getOpcode()) && checkRWLaneHazards(MI) > 0)
613 return HazardType;
614
615 if ((SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true) ||
618 checkMAIVALUHazards(MI) > 0)
619 return HazardType;
620
621 if (isSGetReg(MI->getOpcode()) && checkGetRegHazards(MI) > 0)
622 return HazardType;
623
624 if (isSSetReg(MI->getOpcode()) && checkSetRegHazards(MI) > 0)
625 return HazardType;
626
627 if (isRFE(MI->getOpcode()) && checkRFEHazards(MI) > 0)
628 return HazardType;
629
630 if (((ST.hasReadM0MovRelInterpHazard() &&
631 (TII.isVINTRP(*MI) || isSMovRel(MI->getOpcode()) ||
632 MI->getOpcode() == AMDGPU::DS_WRITE_ADDTID_B32 ||
633 MI->getOpcode() == AMDGPU::DS_READ_ADDTID_B32)) ||
634 (ST.hasReadM0SendMsgHazard() && isSendMsgTraceDataOrGDS(TII, *MI)) ||
635 (ST.hasReadM0LdsDmaHazard() && isLdsDma(*MI)) ||
636 (ST.hasReadM0LdsDirectHazard() &&
637 MI->readsRegister(AMDGPU::LDS_DIRECT, /*TRI=*/nullptr))) &&
638 checkReadM0Hazards(MI) > 0)
639 return HazardType;
640
641 if (SIInstrInfo::isMAI(*MI) && checkMAIHazards(MI) > 0)
642 return HazardType;
643
645 checkMAILdStHazards(MI) > 0)
646 return HazardType;
647
648 if (MI->isInlineAsm() && checkInlineAsmHazards(MI) > 0)
649 return HazardType;
650
651 return NoHazard;
652}
653
655 unsigned Quantity) {
656 while (Quantity > 0) {
657 unsigned Arg = std::min(Quantity, 8u);
658 Quantity -= Arg;
659 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), TII.get(AMDGPU::S_NOP))
660 .addImm(Arg - 1);
661 }
662}
663
664unsigned
665GCNHazardRecognizer::getMFMAPipelineWaitStates(const MachineInstr &MI) const {
666 const MCSchedClassDesc *SC = TSchedModel.resolveSchedClass(&MI);
667 assert(TSchedModel.getWriteProcResBegin(SC) !=
668 TSchedModel.getWriteProcResEnd(SC));
669 return TSchedModel.getWriteProcResBegin(SC)->ReleaseAtCycle;
670}
671
672void GCNHazardRecognizer::processBundle() {
673 MachineBasicBlock::instr_iterator MI = std::next(CurrCycleInstr->getIterator());
674 MachineBasicBlock::instr_iterator E = CurrCycleInstr->getParent()->instr_end();
675 // Check bundled MachineInstr's for hazards.
676 for (; MI != E && MI->isInsideBundle(); ++MI) {
677 CurrCycleInstr = &*MI;
678 unsigned WaitStates = PreEmitNoopsCommon(CurrCycleInstr);
679
681 fixHazards(CurrCycleInstr);
682
683 insertNoopsInBundle(CurrCycleInstr, TII, WaitStates);
684 }
685
686 // It’s unnecessary to track more than MaxLookAhead instructions. Since we
687 // include the bundled MI directly after, only add a maximum of
688 // (MaxLookAhead - 1) noops to EmittedInstrs.
689 for (unsigned i = 0, e = std::min(WaitStates, MaxLookAhead - 1); i < e; ++i)
690 EmittedInstrs.push_front(nullptr);
691
692 EmittedInstrs.push_front(CurrCycleInstr);
693 EmittedInstrs.resize(MaxLookAhead);
694 }
695 CurrCycleInstr = nullptr;
696}
697
698void GCNHazardRecognizer::runOnInstruction(MachineInstr *MI) {
700
701 unsigned NumPreNoops = PreEmitNoops(MI);
702 EmitNoops(NumPreNoops);
703 if (MI->isInsideBundle())
704 insertNoopsInBundle(MI, TII, NumPreNoops);
705 else
706 TII.insertNoops(*MI->getParent(), MachineBasicBlock::iterator(MI),
707 NumPreNoops);
709 AdvanceCycle();
710}
711
714 CurrCycleInstr = MI;
715 unsigned W = PreEmitNoopsCommon(MI);
716 fixHazards(MI);
717 CurrCycleInstr = nullptr;
718 return std::max(W, NopPadding.getValue());
719}
720
722 unsigned W = 0;
723
724 // Check co-execution slot hazards and pipeline stalls in scheduler modes.
725 if (isSchedulerMode()) {
726 W = checkWMMACoexecSlot(*MI);
727 W = std::max(W, checkTRANSHazard(*MI));
728 W = std::max(W, checkMultiCycleVALUHazard(*MI));
729 W = std::max(W, checkMultiShadowHazard(*MI));
730 // The remaining checks are all defined by register dependences.
731 if (!hasPhysRegs())
732 return W;
733 }
734
735 return std::max(W, PreEmitNoopsCommon(MI));
736}
737
739 if (MI->isBundle())
740 return 0;
741
742 int WaitStates = 0;
743
745 return std::max(WaitStates, checkSMRDHazards(MI));
746
747 if (ST.hasNSAtoVMEMBug())
748 WaitStates = std::max(WaitStates, checkNSAtoVMEMHazard(MI));
749
750 WaitStates = std::max(WaitStates, checkFPAtomicToDenormModeHazard(MI));
751
752 if (ST.hasNoDataDepHazard())
753 return WaitStates;
754
756 WaitStates = std::max(WaitStates, checkVMEMHazards(MI));
757
758 if (SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true))
759 WaitStates = std::max(WaitStates, checkVALUHazards(MI));
760
762 WaitStates = std::max(WaitStates, checkDPPHazards(MI));
763
764 if (isDivFMas(MI->getOpcode()))
765 WaitStates = std::max(WaitStates, checkDivFMasHazards(MI));
766
767 if (isRWLane(MI->getOpcode()))
768 WaitStates = std::max(WaitStates, checkRWLaneHazards(MI));
769
770 if ((SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true) ||
773 checkMAIVALUHazards(MI) > 0)
774 WaitStates = std::max(WaitStates, checkMAIVALUHazards(MI));
775
776 if (MI->isInlineAsm())
777 return std::max(WaitStates, checkInlineAsmHazards(MI));
778
779 if (isSGetReg(MI->getOpcode()))
780 return std::max(WaitStates, checkGetRegHazards(MI));
781
782 if (isSSetReg(MI->getOpcode()))
783 return std::max(WaitStates, checkSetRegHazards(MI));
784
785 if (isRFE(MI->getOpcode()))
786 return std::max(WaitStates, checkRFEHazards(MI));
787
788 if ((ST.hasReadM0MovRelInterpHazard() &&
789 (TII.isVINTRP(*MI) || isSMovRel(MI->getOpcode()) ||
790 MI->getOpcode() == AMDGPU::DS_WRITE_ADDTID_B32 ||
791 MI->getOpcode() == AMDGPU::DS_READ_ADDTID_B32)) ||
792 (ST.hasReadM0SendMsgHazard() && isSendMsgTraceDataOrGDS(TII, *MI)) ||
793 (ST.hasReadM0LdsDmaHazard() && isLdsDma(*MI)) ||
794 (ST.hasReadM0LdsDirectHazard() &&
795 MI->readsRegister(AMDGPU::LDS_DIRECT, /*TRI=*/nullptr)))
796 return std::max(WaitStates, checkReadM0Hazards(MI));
797
799 return std::max(WaitStates, checkMAIHazards(MI));
800
802 return std::max(WaitStates, checkMAILdStHazards(MI));
803
804 if (ST.hasGFX950Insts() && isPermlane(*MI))
805 return std::max(WaitStates, checkPermlaneHazards(MI));
806
807 return WaitStates;
808}
809
811 EmittedInstrs.push_front(nullptr);
812}
813
815 if (isSchedulerMode())
816 schedulerAdvanceCycle();
817
818 // When the scheduler detects a stall, it will call AdvanceCycle() without
819 // emitting any instructions.
820 if (!CurrCycleInstr) {
821 EmittedInstrs.push_front(nullptr);
822
823 if (HasPendingWMMACoexecHazard)
824 EmittedVALUInstrs.push_front(nullptr);
825 return;
826 }
827
828 HasPendingWMMACoexecHazard = false;
829
830 if (CurrCycleInstr->isBundle()) {
831 processBundle();
832 return;
833 }
834
835 unsigned NumWaitStates = TII.getNumWaitStates(*CurrCycleInstr);
836 if (!NumWaitStates) {
837 CurrCycleInstr = nullptr;
838 return;
839 }
840
841 // Keep track of emitted instructions
842 EmittedInstrs.push_front(CurrCycleInstr);
843
844 bool IsVALUOrWMMA =
845 SIInstrInfo::isVALU(*CurrCycleInstr, /*AllowLDSDMA=*/true) ||
846 SIInstrInfo::isWMMA(*CurrCycleInstr) ||
847 SIInstrInfo::isSWMMAC(*CurrCycleInstr);
848 if (IsVALUOrWMMA) {
849 EmittedVALUInstrs.push_front(CurrCycleInstr);
850 } else {
851 // A pending WMMA co-execution hazard optimistically records stall cycles as
852 // future V_NOPs. If the scheduler instead stalls for a different
853 // (S_NOP-resolvable) hazard and schedules a non-VALU into those cycles,
854 // they will not resolve the VALU-pipe hazard, so drop them here.
855 while (!EmittedVALUInstrs.empty() && EmittedVALUInstrs.front() == nullptr)
856 EmittedVALUInstrs.pop_front();
857 }
858
859 // Add a nullptr for each additional wait state after the first. Make sure
860 // not to add more than getMaxLookAhead() items to the list, since we
861 // truncate the list to that size right after this loop.
862 for (unsigned i = 1, e = std::min(NumWaitStates, getMaxLookAhead());
863 i < e; ++i) {
864 EmittedInstrs.push_front(nullptr);
865 }
866
867 // getMaxLookahead() is the largest number of wait states we will ever need
868 // to insert, so there is no point in keeping track of more than that many
869 // wait states.
870 EmittedInstrs.resize(getMaxLookAhead());
871 if (EmittedVALUInstrs.size() > MaxVALULookAhead)
872 EmittedVALUInstrs.resize(MaxVALULookAhead);
873
874 CurrCycleInstr = nullptr;
875}
876
879 "Bottom-up scheduling shouldn't run in hazard recognizer mode");
880}
881
882//===----------------------------------------------------------------------===//
883// Helper Functions
884//===----------------------------------------------------------------------===//
885
887
888// Search for a hazard in a block and its predecessors.
889template <typename StateT>
890static bool
891hasHazard(StateT InitialState,
892 function_ref<HazardFnResult(StateT &, const MachineInstr &)> IsHazard,
893 function_ref<void(StateT &, const MachineInstr &)> UpdateState,
894 const MachineBasicBlock *InitialMBB,
896 struct StateMapKey {
898 unsigned Idx;
899 static bool isEqual(const StateMapKey &LHS, const StateMapKey &RHS) {
900 return LHS.States == RHS.States && LHS.Idx == RHS.Idx;
901 }
902 };
903 struct StateMapKeyTraits : DenseMapInfo<StateMapKey> {
904 static unsigned getHashValue(const StateMapKey &Key) {
905 return StateT::getHashValue((*Key.States)[Key.Idx]);
906 }
907 static unsigned getHashValue(const StateT &State) {
908 return StateT::getHashValue(State);
909 }
910 static bool isEqual(const StateMapKey &LHS, const StateMapKey &RHS) {
911 return StateT::isEqual((*LHS.States)[LHS.Idx], (*RHS.States)[RHS.Idx]);
912 }
913 static bool isEqual(const StateT &LHS, const StateMapKey &RHS) {
914 return StateT::isEqual(LHS, (*RHS.States)[RHS.Idx]);
915 }
916 };
917
920
922 const MachineBasicBlock *MBB = InitialMBB;
923 StateT State = InitialState;
924
926 unsigned WorkIdx = 0;
927 for (;;) {
928 bool Expired = false;
929 for (auto E = MBB->instr_rend(); I != E; ++I) {
930 // No need to look at parent BUNDLE instructions.
931 if (I->isBundle())
932 continue;
933
934 auto Result = IsHazard(State, *I);
935 if (Result == HazardFound)
936 return true;
937 if (Result == HazardExpired) {
938 Expired = true;
939 break;
940 }
941
942 if (I->isInlineAsm() || I->isMetaInstruction())
943 continue;
944
945 UpdateState(State, *I);
946 }
947
948 if (!Expired) {
949 unsigned StateIdx = States.size();
950 StateMapKey Key = {&States, StateIdx};
951 auto Insertion = StateMap.insert_as(std::pair(Key, StateIdx), State);
952 if (Insertion.second) {
953 States.emplace_back(State);
954 } else {
955 StateIdx = Insertion.first->second;
956 }
957 for (MachineBasicBlock *Pred : MBB->predecessors())
958 Worklist.insert(std::pair(Pred, StateIdx));
959 }
960
961 if (WorkIdx == Worklist.size())
962 break;
963
964 unsigned StateIdx;
965 std::tie(MBB, StateIdx) = Worklist[WorkIdx++];
966 State = States[StateIdx];
967 I = MBB->instr_rbegin();
968 }
969
970 return false;
971}
972
973// Returns a minimum wait states since \p I walking all predecessors.
974// Only scans until \p IsExpired does not return true.
975// Can only be run in a hazard recognizer mode.
976static int
978 const MachineBasicBlock *MBB,
980 int WaitStates, GCNHazardRecognizer::IsExpiredFn IsExpired,
984 for (auto E = MBB->instr_rend(); I != E; ++I) {
985 // Don't add WaitStates for parent BUNDLE instructions.
986 if (I->isBundle())
987 continue;
988
989 if (IsHazard(*I))
990 return WaitStates;
991
992 if (I->isInlineAsm())
993 continue;
994
995 WaitStates += GetNumWaitStates(*I);
996
997 if (IsExpired(*I, WaitStates))
998 return std::numeric_limits<int>::max();
999 }
1000
1001 int MinWaitStates = std::numeric_limits<int>::max();
1002 for (MachineBasicBlock *Pred : MBB->predecessors()) {
1003 if (!Visited.insert(Pred).second)
1004 continue;
1005
1006 int W = getWaitStatesSince(IsHazard, Pred, Pred->instr_rbegin(), WaitStates,
1007 IsExpired, Visited, GetNumWaitStates);
1008
1009 MinWaitStates = std::min(MinWaitStates, W);
1010 }
1011
1012 return MinWaitStates;
1013}
1014
1015static int
1017 const MachineInstr *MI,
1022 return getWaitStatesSince(IsHazard, MI->getParent(),
1023 std::next(MI->getReverseIterator()), 0, IsExpired,
1024 Visited, GetNumWaitStates);
1025}
1026
1027int GCNHazardRecognizer::getWaitStatesSince(
1028 IsHazardFn IsHazard, int Limit, GetNumWaitStatesFn GetNumWaitStates) const {
1029 if (isHazardRecognizerMode()) {
1030 auto IsExpiredFn = [Limit](const MachineInstr &, int WaitStates) {
1031 return WaitStates >= Limit;
1032 };
1033 return ::getWaitStatesSince(IsHazard, CurrCycleInstr, IsExpiredFn,
1034 GetNumWaitStates);
1035 }
1036
1037 int WaitStates = 0;
1038 for (MachineInstr *MI : EmittedInstrs) {
1039 if (MI) {
1040 if (IsHazard(*MI))
1041 return WaitStates;
1042
1043 if (MI->isInlineAsm())
1044 continue;
1045 }
1046 WaitStates += MI ? GetNumWaitStates(*MI) : 1;
1047
1048 if (WaitStates >= Limit)
1049 break;
1050 }
1051 return std::numeric_limits<int>::max();
1052}
1053
1054int GCNHazardRecognizer::getWaitStatesSince(IsHazardFn IsHazard,
1055 int Limit) const {
1056 return getWaitStatesSince(IsHazard, Limit, SIInstrInfo::getNumWaitStates);
1057}
1058
1059int GCNHazardRecognizer::getWaitStatesSinceVALU(IsHazardFn IsHazard,
1060 int Limit) const {
1061 if (isHazardRecognizerMode()) {
1062 auto GetVALUWaitStates = [](const MachineInstr &MI) -> unsigned {
1063 return SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true) ? 1 : 0;
1064 };
1065 return getWaitStatesSince(IsHazard, Limit, GetVALUWaitStates);
1066 }
1067
1068 // EmittedVALUInstrs is capped at MaxVALULookAhead, so a Limit beyond that
1069 // window could miss a hazard. Keep the cap in sync with the wait-state
1070 // tables.
1071 assert(Limit <= (int)MaxVALULookAhead &&
1072 "Limit exceeds the EmittedVALUInstrs lookahead window");
1073 int WaitStates = 0;
1074 for (MachineInstr *MI : EmittedVALUInstrs) {
1075 if (MI) {
1076 if (IsHazard(*MI))
1077 return WaitStates;
1078 }
1079
1080 ++WaitStates;
1081
1082 if (WaitStates >= Limit)
1083 break;
1084 }
1085 return std::numeric_limits<int>::max();
1086}
1087
1088int GCNHazardRecognizer::getWaitStatesSinceDef(unsigned Reg,
1089 IsHazardFn IsHazardDef,
1090 int Limit) const {
1091 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1092
1093 auto IsHazardFn = [IsHazardDef, TRI, Reg](const MachineInstr &MI) {
1094 return IsHazardDef(MI) && MI.modifiesRegister(Reg, TRI);
1095 };
1096
1097 return getWaitStatesSince(IsHazardFn, Limit);
1098}
1099
1100int GCNHazardRecognizer::getWaitStatesSinceSetReg(IsHazardFn IsHazard,
1101 int Limit) const {
1102 auto IsHazardFn = [IsHazard](const MachineInstr &MI) {
1103 return isSSetReg(MI.getOpcode()) && IsHazard(MI);
1104 };
1105
1106 return getWaitStatesSince(IsHazardFn, Limit);
1107}
1108
1109//===----------------------------------------------------------------------===//
1110// No-op Hazard Detection
1111//===----------------------------------------------------------------------===//
1112
1113static void addRegUnits(const SIRegisterInfo &TRI, BitVector &BV,
1114 MCRegister Reg) {
1115 for (MCRegUnit Unit : TRI.regunits(Reg))
1116 BV.set(static_cast<unsigned>(Unit));
1117}
1118
1121 BitVector &DefSet, BitVector &UseSet) {
1122 for (const MachineOperand &Op : Ops) {
1123 if (Op.isReg())
1124 addRegUnits(TRI, Op.isDef() ? DefSet : UseSet, Op.getReg().asMCReg());
1125 }
1126}
1127
1128void GCNHazardRecognizer::addClauseInst(const MachineInstr &MI) const {
1129 addRegsToSet(TRI, MI.operands(), ClauseDefs, ClauseUses);
1130}
1131
1133 return !SIInstrInfo::isSMRD(*MI);
1134}
1135
1137 return !SIInstrInfo::isVMEM(*MI);
1138}
1139
1140int GCNHazardRecognizer::checkSoftClauseHazards(MachineInstr *MEM) const {
1141 // SMEM soft clause are only present on VI+, and only matter if xnack is
1142 // enabled.
1143 if (!ST.isXNACKEnabled())
1144 return 0;
1145
1146 bool IsSMRD = TII.isSMRD(*MEM);
1147
1148 resetClause();
1149
1150 // A soft-clause is any group of consecutive SMEM instructions. The
1151 // instructions in this group may return out of order and/or may be
1152 // replayed (i.e. the same instruction issued more than once).
1153 //
1154 // In order to handle these situations correctly we need to make sure that
1155 // when a clause has more than one instruction, no instruction in the clause
1156 // writes to a register that is read by another instruction in the clause
1157 // (including itself). If we encounter this situation, we need to break the
1158 // clause by inserting a non SMEM instruction.
1159
1160 for (MachineInstr *MI : EmittedInstrs) {
1161 // When we hit a non-SMEM instruction then we have passed the start of the
1162 // clause and we can stop.
1163 if (!MI)
1164 break;
1165
1167 break;
1168
1169 addClauseInst(*MI);
1170 }
1171
1172 if (ClauseDefs.none())
1173 return 0;
1174
1175 // We need to make sure not to put loads and stores in the same clause if they
1176 // use the same address. For now, just start a new clause whenever we see a
1177 // store.
1178 if (MEM->mayStore())
1179 return 1;
1180
1181 addClauseInst(*MEM);
1182
1183 // If the set of defs and uses intersect then we cannot add this instruction
1184 // to the clause, so we have a hazard.
1185 return ClauseDefs.anyCommon(ClauseUses) ? 1 : 0;
1186}
1187
1188int GCNHazardRecognizer::checkSMRDHazards(MachineInstr *SMRD) const {
1189 int WaitStatesNeeded = 0;
1190
1191 WaitStatesNeeded = checkSoftClauseHazards(SMRD);
1192
1193 // This SMRD hazard only affects SI.
1194 if (!ST.hasSMRDReadVALUDefHazard())
1195 return WaitStatesNeeded;
1196
1197 // A read of an SGPR by SMRD instruction requires 4 wait states when the
1198 // SGPR was written by a VALU instruction.
1199 int SmrdSgprWaitStates = 4;
1200 auto IsHazardDefFn = [this](const MachineInstr &MI) {
1201 return TII.isVALU(MI, /*AllowLDSDMA=*/true);
1202 };
1203 auto IsBufferHazardDefFn = [this](const MachineInstr &MI) {
1204 return TII.isSALU(MI);
1205 };
1206
1207 bool IsBufferSMRD = TII.isBufferSMRD(*SMRD);
1208
1209 for (const MachineOperand &Use : SMRD->uses()) {
1210 if (!Use.isReg())
1211 continue;
1212 int WaitStatesNeededForUse =
1213 SmrdSgprWaitStates - getWaitStatesSinceDef(Use.getReg(), IsHazardDefFn,
1214 SmrdSgprWaitStates);
1215 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1216
1217 // This fixes what appears to be undocumented hardware behavior in SI where
1218 // s_mov writing a descriptor and s_buffer_load_dword reading the descriptor
1219 // needs some number of nops in between. We don't know how many we need, but
1220 // let's use 4. This wasn't discovered before probably because the only
1221 // case when this happens is when we expand a 64-bit pointer into a full
1222 // descriptor and use s_buffer_load_dword instead of s_load_dword, which was
1223 // probably never encountered in the closed-source land.
1224 if (IsBufferSMRD) {
1225 int WaitStatesNeededForUse =
1226 SmrdSgprWaitStates - getWaitStatesSinceDef(Use.getReg(),
1227 IsBufferHazardDefFn,
1228 SmrdSgprWaitStates);
1229 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1230 }
1231 }
1232
1233 return WaitStatesNeeded;
1234}
1235
1236int GCNHazardRecognizer::checkVMEMHazards(MachineInstr *VMEM) const {
1237 if (!ST.hasVMEMReadSGPRVALUDefHazard())
1238 return 0;
1239
1240 int WaitStatesNeeded = checkSoftClauseHazards(VMEM);
1241
1242 // A read of an SGPR by a VMEM instruction requires 5 wait states when the
1243 // SGPR was written by a VALU Instruction.
1244 const int VmemSgprWaitStates = 5;
1245 auto IsHazardDefFn = [this](const MachineInstr &MI) {
1246 return TII.isVALU(MI, /*AllowLDSDMA=*/true);
1247 };
1248 for (const MachineOperand &Use : VMEM->uses()) {
1249 if (!Use.isReg() || TRI.isVectorRegister(MF.getRegInfo(), Use.getReg()))
1250 continue;
1251
1252 int WaitStatesNeededForUse =
1253 VmemSgprWaitStates - getWaitStatesSinceDef(Use.getReg(), IsHazardDefFn,
1254 VmemSgprWaitStates);
1255 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1256 }
1257 return WaitStatesNeeded;
1258}
1259
1260int GCNHazardRecognizer::checkDPPHazards(MachineInstr *DPP) const {
1261 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1262 const SIInstrInfo *TII = ST.getInstrInfo();
1263
1264 // Check for DPP VGPR read after VALU VGPR write and EXEC write.
1265 int DppVgprWaitStates = 2;
1266 int DppExecWaitStates = 5;
1267 int WaitStatesNeeded = 0;
1268 auto IsHazardDefFn = [TII](const MachineInstr &MI) {
1269 return TII->isVALU(MI, /*AllowLDSDMA=*/true);
1270 };
1271
1272 for (const MachineOperand &Use : DPP->uses()) {
1273 if (!Use.isReg() || !TRI->isVGPR(MF.getRegInfo(), Use.getReg()))
1274 continue;
1275 int WaitStatesNeededForUse =
1276 DppVgprWaitStates - getWaitStatesSinceDef(
1277 Use.getReg(),
1278 [](const MachineInstr &) { return true; },
1279 DppVgprWaitStates);
1280 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
1281 }
1282
1283 WaitStatesNeeded = std::max(
1284 WaitStatesNeeded,
1285 DppExecWaitStates - getWaitStatesSinceDef(AMDGPU::EXEC, IsHazardDefFn,
1286 DppExecWaitStates));
1287
1288 return WaitStatesNeeded;
1289}
1290
1291int GCNHazardRecognizer::checkDivFMasHazards(MachineInstr *DivFMas) const {
1292 const SIInstrInfo *TII = ST.getInstrInfo();
1293
1294 // v_div_fmas requires 4 wait states after a write to vcc from a VALU
1295 // instruction.
1296 const int DivFMasWaitStates = 4;
1297 auto IsHazardDefFn = [TII](const MachineInstr &MI) {
1298 return TII->isVALU(MI, /*AllowLDSDMA=*/true);
1299 };
1300 int WaitStatesNeeded = getWaitStatesSinceDef(AMDGPU::VCC, IsHazardDefFn,
1301 DivFMasWaitStates);
1302
1303 return DivFMasWaitStates - WaitStatesNeeded;
1304}
1305
1306int GCNHazardRecognizer::checkGetRegHazards(MachineInstr *GetRegInstr) const {
1307 const SIInstrInfo *TII = ST.getInstrInfo();
1308 unsigned GetRegHWReg = getHWReg(TII, *GetRegInstr);
1309
1310 const int GetRegWaitStates = 2;
1311 auto IsHazardFn = [TII, GetRegHWReg](const MachineInstr &MI) {
1312 return GetRegHWReg == getHWReg(TII, MI);
1313 };
1314 int WaitStatesNeeded = getWaitStatesSinceSetReg(IsHazardFn, GetRegWaitStates);
1315
1316 return GetRegWaitStates - WaitStatesNeeded;
1317}
1318
1319int GCNHazardRecognizer::checkSetRegHazards(MachineInstr *SetRegInstr) const {
1320 const SIInstrInfo *TII = ST.getInstrInfo();
1321 unsigned HWReg = getHWReg(TII, *SetRegInstr);
1322
1323 const int SetRegWaitStates = ST.getSetRegWaitStates();
1324 auto IsHazardFn = [TII, HWReg](const MachineInstr &MI) {
1325 return HWReg == getHWReg(TII, MI);
1326 };
1327 int WaitStatesNeeded = getWaitStatesSinceSetReg(IsHazardFn, SetRegWaitStates);
1328 return SetRegWaitStates - WaitStatesNeeded;
1329}
1330
1331int GCNHazardRecognizer::createsVALUHazard(const MachineInstr &MI) const {
1332 if (!MI.mayStore())
1333 return -1;
1334
1335 const SIInstrInfo *TII = ST.getInstrInfo();
1336 unsigned Opcode = MI.getOpcode();
1337 const MCInstrDesc &Desc = MI.getDesc();
1338
1339 int VDataIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::vdata);
1340 int VDataRCID = -1;
1341 if (VDataIdx != -1)
1342 VDataRCID = TII->getOpRegClassID(Desc.operands()[VDataIdx]);
1343
1344 if (TII->isMUBUF(MI) || TII->isMTBUF(MI)) {
1345 // There is no hazard if the instruction does not use vector regs
1346 // (like wbinvl1)
1347 if (VDataIdx == -1)
1348 return -1;
1349 if (AMDGPU::getRegBitWidth(VDataRCID) > 64) {
1350 // When SOFFSET-dependent wide-store windows apply, the BUFFER_STORE
1351 // source-vgpr WAR hazard exists for every SOFFSET shape; the wait-state
1352 // count differs by SOFFSET and is computed in checkVALUHazardsHelper.
1353 // Otherwise the hazard only exists if soffset is not an SGPR.
1354 if (ST.hasVDecCoExecHazard())
1355 return VDataIdx;
1356 const MachineOperand *SOffset =
1357 TII->getNamedOperand(MI, AMDGPU::OpName::soffset);
1358 if (!SOffset || !SOffset->isReg())
1359 return VDataIdx;
1360 }
1361 }
1362
1363 // MIMG instructions create a hazard if they don't use a 256-bit T# and
1364 // the store size is greater than 8 bytes and they have more than two bits
1365 // of their dmask set.
1366 // All our MIMG definitions use a 256-bit T#, so we can skip checking for them.
1367 if (TII->isMIMG(MI)) {
1368 int SRsrcIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::srsrc);
1369 assert(SRsrcIdx != -1 && AMDGPU::getRegBitWidth(TII->getOpRegClassID(
1370 Desc.operands()[SRsrcIdx])) == 256);
1371 (void)SRsrcIdx;
1372 }
1373
1374 if (TII->isFLAT(MI)) {
1375 // There is no hazard if the instruction does not use vector regs
1376 if (VDataIdx == -1)
1377 return -1;
1378
1379 if (AMDGPU::getRegBitWidth(VDataRCID) > 64)
1380 return VDataIdx;
1381 }
1382
1383 return -1;
1384}
1385
1386int GCNHazardRecognizer::checkUniformWindowVALUHazardsHelper(
1387 Register Reg) const {
1388 // Wide stores need a single wait-state bubble before a VALU that overwrites
1389 // store data. createsVALUHazard already excludes MUBUF/MTBUF stores with an
1390 // SGPR SOFFSET.
1391 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1392
1393 auto IsHazard = [&](const MachineInstr &MI) {
1394 int DataIdx = createsVALUHazard(MI);
1395 return DataIdx >= 0 &&
1396 TRI->regsOverlap(MI.getOperand(DataIdx).getReg(), Reg);
1397 };
1398
1399 return std::max(0, 1 - getWaitStatesSince(IsHazard, /*Limit=*/1));
1400}
1401
1402int GCNHazardRecognizer::checkSOFFSETWindowVALUHazardsHelper(
1403 Register Reg) const {
1404 // The required wait-state window depends on the producer's SOFFSET shape:
1405 // - MUBUF/MTBUF wide store with sgpr SOFFSET: 1 wait state.
1406 // - MUBUF/MTBUF wide store with literal/absent SOFFSET, and FLAT wide
1407 // store: 2 wait states.
1408 // The 1-cycle sgpr-SOFFSET window was measured on gfx950.
1409 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1410 const SIInstrInfo *TII = ST.getInstrInfo();
1411
1412 int WaitStatesNeeded = 0;
1413
1414 // Scan each wait-state window separately and take the max padding needed.
1415 // getWaitStatesSince supplies the minimum distance to a producer over paths.
1416 for (int Window = 1; Window <= 2; ++Window) {
1417 auto IsHazard = [&](const MachineInstr &MI) {
1418 int DataIdx = createsVALUHazard(MI);
1419 if (DataIdx < 0 ||
1420 !TRI->regsOverlap(MI.getOperand(DataIdx).getReg(), Reg))
1421 return false;
1422
1423 // Window 1 matches every hazard producer. Window 2 excludes BUF stores
1424 // with an SGPR SOFFSET, which only require a single wait state.
1425 if (Window == 1 || !TII->isBUF(MI))
1426 return true;
1427
1428 const MachineOperand *SOffset =
1429 TII->getNamedOperand(MI, AMDGPU::OpName::soffset);
1430 return !SOffset || !SOffset->isReg();
1431 };
1432 WaitStatesNeeded = std::max(WaitStatesNeeded,
1433 Window - getWaitStatesSince(IsHazard, Window));
1434 }
1435
1436 return WaitStatesNeeded;
1437}
1438
1439int GCNHazardRecognizer::checkVALUHazardsHelper(
1440 const MachineOperand &Def, const MachineRegisterInfo &MRI) const {
1441 // Helper to check for the hazard where VMEM instructions that store more
1442 // than 8 bytes can have their store data overwritten by the next
1443 // instruction.
1444 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1445
1446 if (!TRI->isVectorRegister(MRI, Def.getReg()))
1447 return 0;
1448
1449 if (ST.hasVDecCoExecHazard())
1450 return checkSOFFSETWindowVALUHazardsHelper(Def.getReg());
1451
1452 return checkUniformWindowVALUHazardsHelper(Def.getReg());
1453}
1454
1455/// Dest sel forwarding issue occurs if additional logic is needed to swizzle /
1456/// pack the computed value into correct bit position of the dest register. This
1457/// occurs if we have SDWA with dst_sel != DWORD or if we have op_sel with
1458/// dst_sel that is not aligned to the register. This function analayzes the \p
1459/// MI and \returns an operand with dst forwarding issue, or nullptr if
1460/// none exists.
1461static const MachineOperand *
1463 if (!SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/false))
1464 return nullptr;
1465
1466 const SIInstrInfo *TII = ST.getInstrInfo();
1467
1468 unsigned Opcode = MI.getOpcode();
1469
1470 // There are three different types of instructions
1471 // which produce forwarded dest: 1. SDWA with dst_sel != DWORD, 2. VOP3
1472 // which write hi bits (e.g. op_sel[3] == 1), and 3. FP8DstSelInst
1473 // (instructions with dest byte sel, e.g. CVT_SR_BF8_F32) and
1474 // op_sel[3:2]
1475 // != 0
1476 if (SIInstrInfo::isSDWA(MI)) {
1477 // Type 1: SDWA with dst_sel != DWORD
1478 if (auto *DstSel = TII->getNamedOperand(MI, AMDGPU::OpName::dst_sel))
1479 if (DstSel->getImm() != AMDGPU::SDWA::DWORD)
1480 return TII->getNamedOperand(MI, AMDGPU::OpName::vdst);
1481 }
1482
1483 AMDGPU::FPType IsFP4OrFP8ConvOpc = AMDGPU::getFPDstSelType(Opcode);
1484 if (AMDGPU::hasNamedOperand(Opcode, AMDGPU::OpName::op_sel)) {
1485 // Type 2: VOP3 which write the hi bits
1486 if (TII->getNamedImmOperand(MI, AMDGPU::OpName::src0_modifiers) &
1488 return TII->getNamedOperand(MI, AMDGPU::OpName::vdst);
1489
1490 // Type 3: FP8DstSelInst with op_sel[3:2] != 0)
1491 if (IsFP4OrFP8ConvOpc == AMDGPU::FPType::FP8 &&
1492 (TII->getNamedImmOperand(MI, AMDGPU::OpName::src2_modifiers) &
1494 return TII->getNamedOperand(MI, AMDGPU::OpName::vdst);
1495 }
1496
1497 // Special case: nop is required for all the opsel values for fp4 sr variant
1498 // cvt scale instructions
1499 if (IsFP4OrFP8ConvOpc == AMDGPU::FPType::FP4)
1500 return TII->getNamedOperand(MI, AMDGPU::OpName::vdst);
1501
1502 return nullptr;
1503}
1504
1505/// Checks whether the provided \p MI "consumes" the operand with a Dest sel
1506/// fowarding issue \p Dst . We may "consume" the Dst via a standard explicit
1507/// RAW, or through irregular ways (e.g implicit RAW, certain types of WAW)
1509 const MachineOperand *Dst,
1510 const SIRegisterInfo *TRI) {
1511 // We must consider implicit reads of the VALU. SDWA with dst_sel and
1512 // UNUSED_PRESERVE will implicitly read the result from forwarded dest,
1513 // and we must account for that hazard.
1514 // We also must account for WAW hazards. In particular, WAW with dest
1515 // preserve semantics (e.g. VOP3 with op_sel, VOP2 &&
1516 // !zeroesHigh16BitsOfDest) will read the forwarded dest for parity
1517 // check for ECC. Without accounting for this hazard, the ECC will be
1518 // wrong.
1519 // TODO: limit to RAW (including implicit reads) + problematic WAW (i.e.
1520 // complete zeroesHigh16BitsOfDest)
1521 for (auto &Operand : VALU->operands()) {
1522 if (Operand.isReg() && TRI->regsOverlap(Dst->getReg(), Operand.getReg())) {
1523 return true;
1524 }
1525 }
1526 return false;
1527}
1528
1529int GCNHazardRecognizer::checkVALUHazards(MachineInstr *VALU) const {
1530 int WaitStatesNeeded = 0;
1531
1532 if (ST.hasTransForwardingHazard() && !SIInstrInfo::isTRANS(*VALU)) {
1533 const int TransDefWaitstates = 1;
1534
1535 auto IsTransDefFn = [this, VALU](const MachineInstr &MI) {
1537 return false;
1538 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1539 const SIInstrInfo *TII = ST.getInstrInfo();
1540 Register Def = TII->getNamedOperand(MI, AMDGPU::OpName::vdst)->getReg();
1541
1542 for (const MachineOperand &Use : VALU->explicit_uses()) {
1543 if (Use.isReg() && TRI->regsOverlap(Def, Use.getReg()))
1544 return true;
1545 }
1546
1547 return false;
1548 };
1549
1550 int WaitStatesNeededForDef =
1551 TransDefWaitstates -
1552 getWaitStatesSince(IsTransDefFn, TransDefWaitstates);
1553 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1554 }
1555
1556 if (ST.hasDstSelForwardingHazard() || ST.hasCvtScaleForwardingHazard()) {
1557 const int Shift16DefWaitstates = 1;
1558
1559 auto IsShift16BitDefFn = [this, VALU](const MachineInstr &ProducerMI) {
1560 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1561 const MachineOperand *ForwardedDst =
1562 getDstSelForwardingOperand(ProducerMI, ST);
1563 if (ForwardedDst) {
1564 return consumesDstSelForwardingOperand(VALU, ForwardedDst, TRI);
1565 }
1566
1567 if (ProducerMI.isInlineAsm()) {
1568 // Assume inline asm has dst forwarding hazard
1569 for (auto &Def : ProducerMI.all_defs()) {
1570 if (consumesDstSelForwardingOperand(VALU, &Def, TRI))
1571 return true;
1572 }
1573 }
1574
1575 return false;
1576 };
1577
1578 int WaitStatesNeededForDef =
1579 Shift16DefWaitstates -
1580 getWaitStatesSince(IsShift16BitDefFn, Shift16DefWaitstates);
1581 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1582 }
1583
1584 if (ST.hasVDecCoExecHazard()) {
1585 const int VALUWriteSGPRVALUReadWaitstates = 2;
1586 const int VALUWriteEXECRWLane = 4;
1587 const int VALUWriteVGPRReadlaneRead = 1;
1588
1589 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1590 const MachineRegisterInfo &MRI = MF.getRegInfo();
1592 auto IsVALUDefSGPRFn = [&UseReg, TRI](const MachineInstr &MI) {
1593 if (!SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true))
1594 return false;
1595 return MI.modifiesRegister(UseReg, TRI);
1596 };
1597
1598 for (const MachineOperand &Use : VALU->explicit_uses()) {
1599 if (!Use.isReg())
1600 continue;
1601
1602 UseReg = Use.getReg();
1603 if (TRI->isSGPRReg(MRI, UseReg)) {
1604 int WaitStatesNeededForDef =
1605 VALUWriteSGPRVALUReadWaitstates -
1606 getWaitStatesSince(IsVALUDefSGPRFn,
1607 VALUWriteSGPRVALUReadWaitstates);
1608 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1609 }
1610 }
1611
1612 if (VALU->readsRegister(AMDGPU::VCC, TRI)) {
1613 UseReg = AMDGPU::VCC;
1614 int WaitStatesNeededForDef =
1615 VALUWriteSGPRVALUReadWaitstates -
1616 getWaitStatesSince(IsVALUDefSGPRFn, VALUWriteSGPRVALUReadWaitstates);
1617 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1618 }
1619
1620 switch (VALU->getOpcode()) {
1621 case AMDGPU::V_READLANE_B32:
1622 case AMDGPU::V_READFIRSTLANE_B32: {
1623 MachineOperand *Src = TII.getNamedOperand(*VALU, AMDGPU::OpName::src0);
1624 UseReg = Src->getReg();
1625 int WaitStatesNeededForDef =
1626 VALUWriteVGPRReadlaneRead -
1627 getWaitStatesSince(IsVALUDefSGPRFn, VALUWriteVGPRReadlaneRead);
1628 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1629 }
1630 [[fallthrough]];
1631 case AMDGPU::V_WRITELANE_B32: {
1632 UseReg = AMDGPU::EXEC;
1633 int WaitStatesNeededForDef =
1634 VALUWriteEXECRWLane -
1635 getWaitStatesSince(IsVALUDefSGPRFn, VALUWriteEXECRWLane);
1636 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1637 break;
1638 }
1639 default:
1640 break;
1641 }
1642 }
1643
1644 // This checks for the hazard where VMEM instructions that store more than
1645 // 8 bytes can have there store data over written by the next instruction.
1646 if (!ST.has12DWordStoreHazard())
1647 return WaitStatesNeeded;
1648
1649 const MachineRegisterInfo &MRI = MF.getRegInfo();
1650
1651 for (const MachineOperand &Def : VALU->defs()) {
1652 WaitStatesNeeded = std::max(WaitStatesNeeded, checkVALUHazardsHelper(Def, MRI));
1653 }
1654
1655 return WaitStatesNeeded;
1656}
1657
1658int GCNHazardRecognizer::checkInlineAsmHazards(MachineInstr *IA) const {
1659 // This checks for hazards associated with inline asm statements.
1660 // Since inline asms can contain just about anything, we use this
1661 // to call/leverage other check*Hazard routines. Note that
1662 // this function doesn't attempt to address all possible inline asm
1663 // hazards (good luck), but is a collection of what has been
1664 // problematic thus far.
1665
1666 // see checkVALUHazards()
1667 if (!ST.has12DWordStoreHazard() && !ST.hasDstSelForwardingHazard() &&
1668 !ST.hasCvtScaleForwardingHazard())
1669 return 0;
1670
1671 const MachineRegisterInfo &MRI = MF.getRegInfo();
1672 int WaitStatesNeeded = 0;
1673
1674 for (const MachineOperand &Op :
1676 if (Op.isReg() && Op.isDef()) {
1677 if (!TRI.isVectorRegister(MRI, Op.getReg()))
1678 continue;
1679
1680 if (ST.has12DWordStoreHazard()) {
1681 WaitStatesNeeded =
1682 std::max(WaitStatesNeeded, checkVALUHazardsHelper(Op, MRI));
1683 }
1684 }
1685 }
1686
1687 if (ST.hasDstSelForwardingHazard()) {
1688 const int Shift16DefWaitstates = 1;
1689
1690 auto IsShift16BitDefFn = [this, &IA](const MachineInstr &ProducerMI) {
1691 const MachineOperand *Dst = getDstSelForwardingOperand(ProducerMI, ST);
1692 // Assume inline asm reads the dst
1693 if (Dst)
1694 return IA->modifiesRegister(Dst->getReg(), &TRI) ||
1695 IA->readsRegister(Dst->getReg(), &TRI);
1696
1697 if (ProducerMI.isInlineAsm()) {
1698 // If MI is inline asm, assume it has dst forwarding hazard
1699 for (auto &Def : ProducerMI.all_defs()) {
1700 if (IA->modifiesRegister(Def.getReg(), &TRI) ||
1701 IA->readsRegister(Def.getReg(), &TRI)) {
1702 return true;
1703 }
1704 }
1705 }
1706
1707 return false;
1708 };
1709
1710 int WaitStatesNeededForDef =
1711 Shift16DefWaitstates -
1712 getWaitStatesSince(IsShift16BitDefFn, Shift16DefWaitstates);
1713 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
1714 }
1715
1716 return WaitStatesNeeded;
1717}
1718
1719int GCNHazardRecognizer::checkRWLaneHazards(MachineInstr *RWLane) const {
1720 const SIInstrInfo *TII = ST.getInstrInfo();
1721 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1722 const MachineRegisterInfo &MRI = MF.getRegInfo();
1723
1724 const MachineOperand *LaneSelectOp =
1725 TII->getNamedOperand(*RWLane, AMDGPU::OpName::src1);
1726
1727 if (!LaneSelectOp->isReg() || !TRI->isSGPRReg(MRI, LaneSelectOp->getReg()))
1728 return 0;
1729
1730 Register LaneSelectReg = LaneSelectOp->getReg();
1731 auto IsHazardFn = [TII](const MachineInstr &MI) {
1732 return TII->isVALU(MI, /*AllowLDSDMA=*/true);
1733 };
1734
1735 const int RWLaneWaitStates = 4;
1736 int WaitStatesSince = getWaitStatesSinceDef(LaneSelectReg, IsHazardFn,
1737 RWLaneWaitStates);
1738 return RWLaneWaitStates - WaitStatesSince;
1739}
1740
1741int GCNHazardRecognizer::checkRFEHazards(MachineInstr *RFE) const {
1742 if (!ST.hasRFEHazards())
1743 return 0;
1744
1745 const SIInstrInfo *TII = ST.getInstrInfo();
1746
1747 const int RFEWaitStates = 1;
1748
1749 auto IsHazardFn = [TII](const MachineInstr &MI) {
1750 return getHWReg(TII, MI) == AMDGPU::Hwreg::ID_TRAPSTS;
1751 };
1752 int WaitStatesNeeded = getWaitStatesSinceSetReg(IsHazardFn, RFEWaitStates);
1753 return RFEWaitStates - WaitStatesNeeded;
1754}
1755
1756int GCNHazardRecognizer::checkReadM0Hazards(MachineInstr *MI) const {
1757 const SIInstrInfo *TII = ST.getInstrInfo();
1758 const int ReadM0WaitStates = 1;
1759 auto IsHazardFn = [TII](const MachineInstr &MI) { return TII->isSALU(MI); };
1760 return ReadM0WaitStates -
1761 getWaitStatesSinceDef(AMDGPU::M0, IsHazardFn, ReadM0WaitStates);
1762}
1763
1764void GCNHazardRecognizer::emitVNops(MachineBasicBlock &MBB,
1766 int WaitStatesNeeded, bool IsHoisting) {
1767 const DebugLoc &DL = IsHoisting ? DebugLoc() : InsertPt->getDebugLoc();
1768 for (int I = 0; I < WaitStatesNeeded; ++I)
1769 BuildMI(MBB, InsertPt, DL, TII.get(AMDGPU::V_NOP_e32));
1770}
1771
1772void GCNHazardRecognizer::fixHazards(MachineInstr *MI) {
1773 fixVMEMtoScalarWriteHazards(MI);
1774 fixVcmpxPermlaneHazards(MI);
1775 fixSMEMtoVectorWriteHazards(MI);
1776 fixVcmpxExecWARHazard(MI);
1777 fixLdsBranchVmemWARHazard(MI);
1778 if (ST.hasLdsDirect()) {
1779 fixLdsDirectVALUHazard(MI);
1780 fixLdsDirectVMEMHazard(MI);
1781 }
1782 fixVALUPartialForwardingHazard(MI);
1783 fixVALUTransUseHazard(MI);
1784 fixVALUTransCoexecutionHazards(MI);
1785 fixWMMAHazards(MI); // fall-through if co-execution is enabled.
1786 fixWMMACoexecutionHazards(MI);
1787 fixShift64HighRegBug(MI);
1788 fixVALUMaskWriteHazard(MI);
1789 fixRequiredExportPriority(MI);
1790 if (ST.requiresWaitIdleBeforeGetReg())
1791 fixGetRegWaitIdle(MI);
1792 if (ST.hasDsAtomicAsyncBarrierArriveB64PipeBug())
1793 fixDsAtomicAsyncBarrierArriveB64(MI);
1794 if (ST.hasScratchBaseForwardingHazard())
1795 fixScratchBaseForwardingHazard(MI);
1796 if (ST.setRegModeNeedsVNOPs())
1797 fixSetRegMode(MI);
1798 if (ST.hasNeedsTDMDrain())
1799 fixTDM(MI);
1800}
1801
1803 const MachineInstr &MI) {
1804 return (TII.isVOPC(MI) ||
1805 (MI.isCompare() && (TII.isVOP3(MI) || TII.isSDWA(MI)))) &&
1806 MI.modifiesRegister(AMDGPU::EXEC, &TRI);
1807}
1808
1809bool GCNHazardRecognizer::fixVcmpxPermlaneHazards(MachineInstr *MI) {
1810 if (!ST.hasVcmpxPermlaneHazard() || !isPermlane(*MI))
1811 return false;
1812
1813 const SIInstrInfo *TII = ST.getInstrInfo();
1814 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1815 auto IsHazardFn = [TII, TRI](const MachineInstr &MI) {
1816 return isVCmpXWritesExec(*TII, *TRI, MI);
1817 };
1818
1819 auto IsExpiredFn = [](const MachineInstr &MI, int) {
1820 unsigned Opc = MI.getOpcode();
1821 return SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true) &&
1822 Opc != AMDGPU::V_NOP_e32 && Opc != AMDGPU::V_NOP_e64 &&
1823 Opc != AMDGPU::V_NOP_sdwa;
1824 };
1825
1826 if (::getWaitStatesSince(IsHazardFn, MI, IsExpiredFn) ==
1827 std::numeric_limits<int>::max())
1828 return false;
1829
1830 // V_NOP will be discarded by SQ.
1831 // Use V_MOV_B32 v?, v?. Register must be alive so use src0 of V_PERMLANE*
1832 // which is always a VGPR and available.
1833 auto *Src0 = TII->getNamedOperand(*MI, AMDGPU::OpName::src0);
1834 Register Reg = Src0->getReg();
1835 bool IsUndef = Src0->isUndef();
1836 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
1837 TII->get(AMDGPU::V_MOV_B32_e32))
1840
1841 return true;
1842}
1843
1844bool GCNHazardRecognizer::fixVMEMtoScalarWriteHazards(MachineInstr *MI) {
1845 if (!ST.hasVMEMtoScalarWriteHazard())
1846 return false;
1847 assert(!ST.hasExtendedWaitCounts());
1848
1850 return false;
1851
1852 if (MI->getNumDefs() == 0)
1853 return false;
1854
1855 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1856
1857 auto IsHazardFn = [TRI, MI](const MachineInstr &I) {
1859 return false;
1860
1861 for (const MachineOperand &Def : MI->defs()) {
1862 const MachineOperand *Op =
1863 I.findRegisterUseOperand(Def.getReg(), TRI, false);
1864 if (!Op)
1865 continue;
1866 return true;
1867 }
1868 return false;
1869 };
1870
1871 auto IsExpiredFn = [](const MachineInstr &MI, int) {
1872 return SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true) ||
1873 (MI.getOpcode() == AMDGPU::S_WAITCNT &&
1874 !MI.getOperand(0).getImm()) ||
1875 (MI.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
1876 AMDGPU::DepCtr::decodeFieldVmVsrc(MI.getOperand(0).getImm()) == 0);
1877 };
1878
1879 if (::getWaitStatesSince(IsHazardFn, MI, IsExpiredFn) ==
1880 std::numeric_limits<int>::max())
1881 return false;
1882
1883 const SIInstrInfo *TII = ST.getInstrInfo();
1884 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
1885 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
1887 return true;
1888}
1889
1890bool GCNHazardRecognizer::fixSMEMtoVectorWriteHazards(MachineInstr *MI) {
1891 if (!ST.hasSMEMtoVectorWriteHazard())
1892 return false;
1893 assert(!ST.hasExtendedWaitCounts());
1894
1895 if (!SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true))
1896 return false;
1897
1898 AMDGPU::OpName SDSTName;
1899 switch (MI->getOpcode()) {
1900 case AMDGPU::V_READLANE_B32:
1901 case AMDGPU::V_READFIRSTLANE_B32:
1902 SDSTName = AMDGPU::OpName::vdst;
1903 break;
1904 default:
1905 SDSTName = AMDGPU::OpName::sdst;
1906 break;
1907 }
1908
1909 const SIInstrInfo *TII = ST.getInstrInfo();
1910 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1911 const AMDGPU::IsaVersion IV = AMDGPU::getIsaVersion(ST.getCPU());
1912 const MachineOperand *SDST = TII->getNamedOperand(*MI, SDSTName);
1913 if (!SDST) {
1914 for (const auto &MO : MI->implicit_operands()) {
1915 if (MO.isDef() && TRI->isSGPRClass(TRI->getPhysRegBaseClass(MO.getReg()))) {
1916 SDST = &MO;
1917 break;
1918 }
1919 }
1920 }
1921
1922 if (!SDST)
1923 return false;
1924
1925 const Register SDSTReg = SDST->getReg();
1926 auto IsHazardFn = [SDSTReg, TRI](const MachineInstr &I) {
1927 return SIInstrInfo::isSMRD(I) && I.readsRegister(SDSTReg, TRI);
1928 };
1929
1930 auto IsExpiredFn = [TII, IV](const MachineInstr &MI, int) {
1931 if (TII->isSALU(MI)) {
1932 switch (MI.getOpcode()) {
1933 case AMDGPU::S_SETVSKIP:
1934 case AMDGPU::S_VERSION:
1935 case AMDGPU::S_WAITCNT_VSCNT:
1936 case AMDGPU::S_WAITCNT_VMCNT:
1937 case AMDGPU::S_WAITCNT_EXPCNT:
1938 // These instructions cannot not mitigate the hazard.
1939 return false;
1940 case AMDGPU::S_WAITCNT_LGKMCNT:
1941 // Reducing lgkmcnt count to 0 always mitigates the hazard.
1942 return (MI.getOperand(1).getImm() == 0) &&
1943 (MI.getOperand(0).getReg() == AMDGPU::SGPR_NULL);
1944 case AMDGPU::S_WAITCNT: {
1945 const int64_t Imm = MI.getOperand(0).getImm();
1946 AMDGPU::Waitcnt Decoded = AMDGPU::decodeWaitcnt(IV, Imm);
1947 // DsCnt corresponds to LGKMCnt here.
1948 return Decoded.get(AMDGPU::DS_CNT) == 0;
1949 }
1950 default:
1951 assert((!SIInstrInfo::isWaitcnt(MI.getOpcode()) ||
1952 MI.getOpcode() == AMDGPU::S_WAIT_IDLE) &&
1953 "unexpected wait count instruction");
1954 // SOPP instructions cannot mitigate the hazard.
1955 if (TII->isSOPP(MI))
1956 return false;
1957 // At this point the SALU can be assumed to mitigate the hazard
1958 // because either:
1959 // (a) it is independent of the at risk SMEM (breaking chain),
1960 // or
1961 // (b) it is dependent on the SMEM, in which case an appropriate
1962 // s_waitcnt lgkmcnt _must_ exist between it and the at risk
1963 // SMEM instruction.
1964 return true;
1965 }
1966 }
1967 return false;
1968 };
1969
1970 if (::getWaitStatesSince(IsHazardFn, MI, IsExpiredFn) ==
1971 std::numeric_limits<int>::max())
1972 return false;
1973
1974 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
1975 TII->get(AMDGPU::S_MOV_B32), AMDGPU::SGPR_NULL)
1976 .addImm(0);
1977 return true;
1978}
1979
1980bool GCNHazardRecognizer::fixVcmpxExecWARHazard(MachineInstr *MI) {
1981 if (!ST.hasVcmpxExecWARHazard())
1982 return false;
1983 assert(!ST.hasExtendedWaitCounts());
1984
1985 if (!SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true))
1986 return false;
1987
1988 const SIRegisterInfo *TRI = ST.getRegisterInfo();
1989 if (!MI->modifiesRegister(AMDGPU::EXEC, TRI))
1990 return false;
1991
1992 auto IsHazardFn = [TRI](const MachineInstr &I) {
1993 if (SIInstrInfo::isVALU(I, /*AllowLDSDMA=*/true))
1994 return false;
1995 return I.readsRegister(AMDGPU::EXEC, TRI);
1996 };
1997
1998 const SIInstrInfo *TII = ST.getInstrInfo();
1999 auto IsExpiredFn = [TII, TRI](const MachineInstr &MI, int) {
2000 if (SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true)) {
2001 if (TII->getNamedOperand(MI, AMDGPU::OpName::sdst))
2002 return true;
2003 for (auto MO : MI.implicit_operands())
2004 if (MO.isDef() && TRI->isSGPRClass(TRI->getPhysRegBaseClass(MO.getReg())))
2005 return true;
2006 }
2007 if (MI.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2008 AMDGPU::DepCtr::decodeFieldSaSdst(MI.getOperand(0).getImm()) == 0)
2009 return true;
2010 return false;
2011 };
2012
2013 if (::getWaitStatesSince(IsHazardFn, MI, IsExpiredFn) ==
2014 std::numeric_limits<int>::max())
2015 return false;
2016
2017 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
2018 TII->get(AMDGPU::S_WAITCNT_DEPCTR))
2020 return true;
2021}
2022
2024 const GCNSubtarget &ST) {
2025 if (!ST.hasLdsBranchVmemWARHazard())
2026 return false;
2027
2028 // Check if the necessary condition for the hazard is met: both LDS and VMEM
2029 // instructions need to appear in the same function.
2030 bool HasLds = false;
2031 bool HasVmem = false;
2032 for (auto &MBB : MF) {
2033 for (auto &MI : MBB) {
2035 HasVmem |= SIInstrInfo::isVMEM(MI);
2036 if (HasLds && HasVmem)
2037 return true;
2038 }
2039 }
2040 return false;
2041}
2042
2044 return I.getOpcode() == AMDGPU::S_WAITCNT_VSCNT &&
2045 I.getOperand(0).getReg() == AMDGPU::SGPR_NULL &&
2046 !I.getOperand(1).getImm();
2047}
2048
2049bool GCNHazardRecognizer::fixLdsBranchVmemWARHazard(MachineInstr *MI) {
2050 if (!RunLdsBranchVmemWARHazardFixup)
2051 return false;
2052
2053 assert(ST.hasLdsBranchVmemWARHazard());
2054 assert(!ST.hasExtendedWaitCounts());
2055
2056 auto IsHazardInst = [](const MachineInstr &MI) {
2058 return 1;
2060 return 2;
2061 return 0;
2062 };
2063
2064 auto InstType = IsHazardInst(*MI);
2065 if (!InstType)
2066 return false;
2067
2068 auto IsExpiredFn = [&IsHazardInst](const MachineInstr &I, int) {
2069 return IsHazardInst(I) || isStoreCountWaitZero(I);
2070 };
2071
2072 auto IsHazardFn = [InstType, &IsHazardInst](const MachineInstr &I) {
2073 if (!I.isBranch())
2074 return false;
2075
2076 auto IsHazardFn = [InstType, IsHazardInst](const MachineInstr &I) {
2077 auto InstType2 = IsHazardInst(I);
2078 return InstType2 && InstType != InstType2;
2079 };
2080
2081 auto IsExpiredFn = [InstType, &IsHazardInst](const MachineInstr &I, int) {
2082 auto InstType2 = IsHazardInst(I);
2083 if (InstType == InstType2)
2084 return true;
2085
2086 return isStoreCountWaitZero(I);
2087 };
2088
2089 return ::getWaitStatesSince(IsHazardFn, &I, IsExpiredFn) !=
2090 std::numeric_limits<int>::max();
2091 };
2092
2093 if (::getWaitStatesSince(IsHazardFn, MI, IsExpiredFn) ==
2094 std::numeric_limits<int>::max())
2095 return false;
2096
2097 const SIInstrInfo *TII = ST.getInstrInfo();
2098 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
2099 TII->get(AMDGPU::S_WAITCNT_VSCNT))
2100 .addReg(AMDGPU::SGPR_NULL, RegState::Undef)
2101 .addImm(0);
2102
2103 return true;
2104}
2105
2106bool GCNHazardRecognizer::fixLdsDirectVALUHazard(MachineInstr *MI) {
2108 return false;
2109
2110 const int NoHazardWaitStates = 15;
2111 const MachineOperand *VDST = TII.getNamedOperand(*MI, AMDGPU::OpName::vdst);
2112 const Register VDSTReg = VDST->getReg();
2113
2114 bool VisitedTrans = false;
2115 auto IsHazardFn = [this, VDSTReg, &VisitedTrans](const MachineInstr &I) {
2116 if (!SIInstrInfo::isVALU(I, /*AllowLDSDMA=*/true))
2117 return false;
2118 VisitedTrans = VisitedTrans || SIInstrInfo::isTRANS(I);
2119 // Cover both WAR and WAW
2120 return I.readsRegister(VDSTReg, &TRI) || I.modifiesRegister(VDSTReg, &TRI);
2121 };
2122 auto IsExpiredFn = [&](const MachineInstr &I, int WaitStates) {
2123 if (WaitStates >= NoHazardWaitStates)
2124 return true;
2125 // Instructions which cause va_vdst==0 expire hazard
2128 };
2129 auto GetWaitStatesFn = [](const MachineInstr &MI) {
2130 return SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true) ? 1 : 0;
2131 };
2132
2133 DenseSet<const MachineBasicBlock *> Visited;
2134 auto Count = ::getWaitStatesSince(IsHazardFn, MI->getParent(),
2135 std::next(MI->getReverseIterator()), 0,
2136 IsExpiredFn, Visited, GetWaitStatesFn);
2137
2138 // Transcendentals can execute in parallel to other VALUs.
2139 // This makes va_vdst count unusable with a mixture of VALU and TRANS.
2140 if (VisitedTrans)
2141 Count = 0;
2142
2143 MachineOperand *WaitVdstOp =
2144 TII.getNamedOperand(*MI, AMDGPU::OpName::waitvdst);
2145 WaitVdstOp->setImm(std::min(Count, NoHazardWaitStates));
2146
2147 return true;
2148}
2149
2150bool GCNHazardRecognizer::fixLdsDirectVMEMHazard(MachineInstr *MI) {
2152 return false;
2153
2154 const MachineOperand *VDST = TII.getNamedOperand(*MI, AMDGPU::OpName::vdst);
2155 const Register VDSTReg = VDST->getReg();
2156
2157 auto IsHazardFn = [this, VDSTReg](const MachineInstr &I) {
2159 return false;
2160 return I.readsRegister(VDSTReg, &TRI) || I.modifiesRegister(VDSTReg, &TRI);
2161 };
2162 bool LdsdirCanWait = ST.hasLdsWaitVMSRC();
2163 // TODO: On GFX12 the hazard should expire on S_WAIT_LOADCNT/SAMPLECNT/BVHCNT
2164 // according to the type of VMEM instruction.
2165 auto IsExpiredFn = [this, LdsdirCanWait](const MachineInstr &I, int) {
2166 return SIInstrInfo::isVALU(I, /*AllowLDSDMA=*/true) ||
2168 (I.getOpcode() == AMDGPU::S_WAITCNT && !I.getOperand(0).getImm()) ||
2169 (I.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2170 AMDGPU::DepCtr::decodeFieldVmVsrc(I.getOperand(0).getImm()) == 0) ||
2171 (LdsdirCanWait && SIInstrInfo::isLDSDIR(I) &&
2172 !TII.getNamedOperand(I, AMDGPU::OpName::waitvsrc)->getImm());
2173 };
2174
2175 if (::getWaitStatesSince(IsHazardFn, MI, IsExpiredFn) ==
2176 std::numeric_limits<int>::max())
2177 return false;
2178
2179 if (LdsdirCanWait) {
2180 TII.getNamedOperand(*MI, AMDGPU::OpName::waitvsrc)->setImm(0);
2181 } else {
2182 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
2183 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
2185 }
2186
2187 return true;
2188}
2189
2190bool GCNHazardRecognizer::fixVALUPartialForwardingHazard(MachineInstr *MI) {
2191 if (!ST.hasVALUPartialForwardingHazard())
2192 return false;
2193 assert(!ST.hasExtendedWaitCounts());
2194
2195 if (!ST.isWave64() || !SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true))
2196 return false;
2197
2198 SmallSetVector<Register, 4> SrcVGPRs;
2199
2200 for (const MachineOperand &Use : MI->explicit_uses()) {
2201 if (Use.isReg() && TRI.isVGPR(MF.getRegInfo(), Use.getReg()))
2202 SrcVGPRs.insert(Use.getReg());
2203 }
2204
2205 // Only applies with >= 2 unique VGPR sources
2206 if (SrcVGPRs.size() <= 1)
2207 return false;
2208
2209 // Look for the following pattern:
2210 // Va <- VALU [PreExecPos]
2211 // intv1
2212 // Exec <- SALU [ExecPos]
2213 // intv2
2214 // Vb <- VALU [PostExecPos]
2215 // intv3
2216 // MI Va, Vb (WaitState = 0)
2217 //
2218 // Where:
2219 // intv1 + intv2 <= 2 VALUs
2220 // intv3 <= 4 VALUs
2221 //
2222 // If found, insert an appropriate S_WAITCNT_DEPCTR before MI.
2223
2224 const int Intv1plus2MaxVALUs = 2;
2225 const int Intv3MaxVALUs = 4;
2226 const int IntvMaxVALUs = 6;
2227 const int NoHazardVALUWaitStates = IntvMaxVALUs + 2;
2228
2229 struct StateType {
2230 SmallDenseMap<Register, int, 4> DefPos;
2231 int ExecPos = std::numeric_limits<int>::max();
2232 int VALUs = 0;
2233
2234 static unsigned getHashValue(const StateType &State) {
2235 hash_code H = hash_combine(State.ExecPos, State.VALUs);
2236 for (const auto &[Reg, Pos] : State.DefPos)
2237 H = hash_combine(H, Reg, Pos);
2238 return H;
2239 }
2240 static bool isEqual(const StateType &LHS, const StateType &RHS) {
2241 return LHS.DefPos == RHS.DefPos && LHS.ExecPos == RHS.ExecPos &&
2242 LHS.VALUs == RHS.VALUs;
2243 }
2244 };
2245
2246 StateType State;
2247
2248 // This overloads expiry testing with all the hazard detection
2249 auto IsHazardFn = [&, this](StateType &State, const MachineInstr &I) {
2250 // Too many VALU states have passed
2251 if (State.VALUs > NoHazardVALUWaitStates)
2252 return HazardExpired;
2253
2254 // Instructions which cause va_vdst==0 expire hazard
2257 (I.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2258 AMDGPU::DepCtr::decodeFieldVaVdst(I.getOperand(0).getImm()) == 0))
2259 return HazardExpired;
2260
2261 // Track registers writes
2262 bool Changed = false;
2263 if (SIInstrInfo::isVALU(I, /*AllowLDSDMA=*/true)) {
2264 for (Register Src : SrcVGPRs) {
2265 if (!State.DefPos.count(Src) && I.modifiesRegister(Src, &TRI)) {
2266 State.DefPos[Src] = State.VALUs;
2267 Changed = true;
2268 }
2269 }
2270 } else if (SIInstrInfo::isSALU(I)) {
2271 if (State.ExecPos == std::numeric_limits<int>::max()) {
2272 if (!State.DefPos.empty() && I.modifiesRegister(AMDGPU::EXEC, &TRI)) {
2273 State.ExecPos = State.VALUs;
2274 Changed = true;
2275 }
2276 }
2277 }
2278
2279 // Early expiration: too many VALUs in intv3
2280 if (State.VALUs > Intv3MaxVALUs && State.DefPos.empty())
2281 return HazardExpired;
2282
2283 // Only evaluate state if something changed
2284 if (!Changed)
2285 return NoHazardFound;
2286
2287 // Determine positions of VALUs pre/post exec change
2288 if (State.ExecPos == std::numeric_limits<int>::max())
2289 return NoHazardFound;
2290
2291 int PreExecPos = std::numeric_limits<int>::max();
2292 int PostExecPos = std::numeric_limits<int>::max();
2293
2294 for (auto Entry : State.DefPos) {
2295 int DefVALUs = Entry.second;
2296 if (DefVALUs != std::numeric_limits<int>::max()) {
2297 if (DefVALUs >= State.ExecPos)
2298 PreExecPos = std::min(PreExecPos, DefVALUs);
2299 else
2300 PostExecPos = std::min(PostExecPos, DefVALUs);
2301 }
2302 }
2303
2304 // Need a VALUs post exec change
2305 if (PostExecPos == std::numeric_limits<int>::max())
2306 return NoHazardFound;
2307
2308 // Too many VALUs in intv3?
2309 int Intv3VALUs = PostExecPos;
2310 if (Intv3VALUs > Intv3MaxVALUs)
2311 return HazardExpired;
2312
2313 // Too many VALUs in intv2?
2314 int Intv2VALUs = (State.ExecPos - PostExecPos) - 1;
2315 if (Intv2VALUs > Intv1plus2MaxVALUs)
2316 return HazardExpired;
2317
2318 // Need a VALUs pre exec change
2319 if (PreExecPos == std::numeric_limits<int>::max())
2320 return NoHazardFound;
2321
2322 // Too many VALUs in intv1?
2323 int Intv1VALUs = PreExecPos - State.ExecPos;
2324 if (Intv1VALUs > Intv1plus2MaxVALUs)
2325 return HazardExpired;
2326
2327 // Too many VALUs in intv1 + intv2
2328 if (Intv1VALUs + Intv2VALUs > Intv1plus2MaxVALUs)
2329 return HazardExpired;
2330
2331 return HazardFound;
2332 };
2333 auto UpdateStateFn = [](StateType &State, const MachineInstr &MI) {
2334 if (SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true))
2335 State.VALUs += 1;
2336 };
2337
2338 if (!hasHazard<StateType>(State, IsHazardFn, UpdateStateFn, MI->getParent(),
2339 std::next(MI->getReverseIterator())))
2340 return false;
2341
2342 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
2343 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
2345
2346 return true;
2347}
2348
2349bool GCNHazardRecognizer::fixVALUTransUseHazard(MachineInstr *MI) {
2350 if (!ST.hasVALUTransUseHazard())
2351 return false;
2352 assert(!ST.hasExtendedWaitCounts());
2353
2354 if (!SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true))
2355 return false;
2356
2357 SmallSet<Register, 4> SrcVGPRs;
2358
2359 for (const MachineOperand &Use : MI->explicit_uses()) {
2360 if (Use.isReg() && TRI.isVGPR(MF.getRegInfo(), Use.getReg()))
2361 SrcVGPRs.insert(Use.getReg());
2362 }
2363
2364 // Look for the following pattern:
2365 // Va <- TRANS VALU
2366 // intv
2367 // MI Va (WaitState = 0)
2368 //
2369 // Where:
2370 // intv <= 5 VALUs / 1 TRANS
2371 //
2372 // If found, insert an appropriate S_WAITCNT_DEPCTR before MI.
2373
2374 const int IntvMaxVALUs = 5;
2375 const int IntvMaxTRANS = 1;
2376
2377 struct StateType {
2378 int VALUs = 0;
2379 int TRANS = 0;
2380
2381 static unsigned getHashValue(const StateType &State) {
2382 return hash_combine(State.VALUs, State.TRANS);
2383 }
2384 static bool isEqual(const StateType &LHS, const StateType &RHS) {
2385 return LHS.VALUs == RHS.VALUs && LHS.TRANS == RHS.TRANS;
2386 }
2387 };
2388
2389 StateType State;
2390
2391 // This overloads expiry testing with all the hazard detection
2392 auto IsHazardFn = [&, this](StateType &State, const MachineInstr &I) {
2393 // Too many VALU states have passed
2394 if (State.VALUs > IntvMaxVALUs || State.TRANS > IntvMaxTRANS)
2395 return HazardExpired;
2396
2397 // Instructions which cause va_vdst==0 expire hazard
2400 (I.getOpcode() == AMDGPU::S_WAITCNT_DEPCTR &&
2401 AMDGPU::DepCtr::decodeFieldVaVdst(I.getOperand(0).getImm()) == 0))
2402 return HazardExpired;
2403
2404 // Track registers writes
2405 if (SIInstrInfo::isTRANS(I)) {
2406 for (Register Src : SrcVGPRs) {
2407 if (I.modifiesRegister(Src, &TRI)) {
2408 return HazardFound;
2409 }
2410 }
2411 }
2412
2413 return NoHazardFound;
2414 };
2415 auto UpdateStateFn = [](StateType &State, const MachineInstr &MI) {
2416 if (SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/true))
2417 State.VALUs += 1;
2419 State.TRANS += 1;
2420 };
2421
2422 if (!hasHazard<StateType>(State, IsHazardFn, UpdateStateFn, MI->getParent(),
2423 std::next(MI->getReverseIterator())))
2424 return false;
2425
2426 // Hazard is observed - insert a wait on va_dst counter to ensure hazard is
2427 // avoided.
2428 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
2429 TII.get(AMDGPU::S_WAITCNT_DEPCTR))
2431
2432 return true;
2433}
2434
2435bool GCNHazardRecognizer::fixVALUTransCoexecutionHazards(MachineInstr *MI) {
2436 if (!ST.hasTransCoexecutionHazard() || // Coexecution disabled.
2437 !SIInstrInfo::isVALU(*MI, /*AllowLDSDMA=*/true) ||
2439 return false;
2440
2441 const SIInstrInfo *TII = ST.getInstrInfo();
2442 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2443
2444 auto IsTransHazardFn = [MI, TII, TRI](const MachineInstr &I) {
2445 if (!SIInstrInfo::isTRANS(I))
2446 return false;
2447
2448 // RAW: Trans(I) writes, VALU(MI) reads.
2449 Register TransDef = TII->getNamedOperand(I, AMDGPU::OpName::vdst)->getReg();
2450 for (const MachineOperand &ValuUse : MI->explicit_uses()) {
2451 if (ValuUse.isReg() && TRI->regsOverlap(TransDef, ValuUse.getReg()))
2452 return true;
2453 }
2454
2455 auto *ValuDst = TII->getNamedOperand(*MI, AMDGPU::OpName::vdst);
2456 if (!ValuDst || !ValuDst->isReg())
2457 return false;
2458
2459 // WAR: Trans(I) reads, VALU(MI) writes.
2460 Register ValuDef = ValuDst->getReg();
2461 for (const MachineOperand &TransUse : I.explicit_uses()) {
2462 if (TransUse.isReg() && TRI->regsOverlap(ValuDef, TransUse.getReg()))
2463 return true;
2464 }
2465
2466 return false;
2467 };
2468
2469 auto IsExpiredFn = [](const MachineInstr &I, int) {
2470 return SIInstrInfo::isVALU(I, /*AllowLDSDMA=*/true);
2471 };
2472
2473 const int HasVALU = std::numeric_limits<int>::max();
2474 if (::getWaitStatesSince(IsTransHazardFn, MI, IsExpiredFn) == HasVALU)
2475 return false;
2476
2477 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), TII->get(AMDGPU::V_NOP_e32));
2478 return true;
2479}
2480
2481bool GCNHazardRecognizer::fixWMMAHazards(MachineInstr *MI) {
2483 return false;
2484
2485 const SIInstrInfo *TII = ST.getInstrInfo();
2486 const SIRegisterInfo *TRI = ST.getRegisterInfo();
2487
2488 auto IsHazardFn = [MI, TII, TRI, this](const MachineInstr &I) {
2490 return false;
2491
2492 // Src0(matrix A) or Src1(matrix B) of the current wmma instruction overlaps
2493 // with the dest(matrix D) of the previous wmma.
2494 const Register CurSrc0Reg =
2495 TII->getNamedOperand(*MI, AMDGPU::OpName::src0)->getReg();
2496 const Register CurSrc1Reg =
2497 TII->getNamedOperand(*MI, AMDGPU::OpName::src1)->getReg();
2498
2499 const Register PrevDstReg =
2500 TII->getNamedOperand(I, AMDGPU::OpName::vdst)->getReg();
2501
2502 if (TRI->regsOverlap(PrevDstReg, CurSrc0Reg) ||
2503 TRI->regsOverlap(PrevDstReg, CurSrc1Reg)) {
2504 return true;
2505 }
2506
2507 // GFX12+ allows overlap of matrix C with PrevDstReg (hardware will stall)
2508 // but Index can't overlap with PrevDstReg.
2509 if (AMDGPU::isGFX12Plus(ST)) {
2510 if (SIInstrInfo::isSWMMAC(*MI)) {
2511 const Register CurIndex =
2512 TII->getNamedOperand(*MI, AMDGPU::OpName::src2)->getReg();
2513 if (TRI->regsOverlap(PrevDstReg, CurIndex))
2514 return true;
2515 }
2516 return false;
2517 }
2518
2519 return false;
2520 };
2521
2522 auto IsExpiredFn = [](const MachineInstr &I, int) {
2523 return SIInstrInfo::isVALU(I, /*AllowLDSDMA=*/true);
2524 };
2525
2526 if (::getWaitStatesSince(IsHazardFn, MI, IsExpiredFn) ==
2527 std::numeric_limits<int>::max())
2528 return false;
2529
2530 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), TII->get(AMDGPU::V_NOP_e32));
2531
2532 return true;
2533}
2534
2536 return SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/false) &&
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
#define H(x, y, z)
Definition MD5.cpp:56
Register Reg
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
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:359
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 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:307
LLVM_ABI Printable printMBBReference(const MachineBasicBlock &MBB)
Prints a machine basic block reference.
hash_code hash_combine_range(InputIteratorT first, InputIteratorT last)
Compute a hash_code for a sequence of values.
Definition Hashing.h:287
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...