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