1 //===-- GCNHazardRecognizers.cpp - GCN Hazard Recognizer Impls ------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file implements hazard recognizers for scheduling on GCN processors. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "GCNHazardRecognizer.h" 15 #include "AMDGPUSubtarget.h" 16 #include "SIDefines.h" 17 #include "SIInstrInfo.h" 18 #include "SIRegisterInfo.h" 19 #include "Utils/AMDGPUBaseInfo.h" 20 #include "llvm/ADT/iterator_range.h" 21 #include "llvm/CodeGen/MachineFunction.h" 22 #include "llvm/CodeGen/MachineInstr.h" 23 #include "llvm/CodeGen/MachineOperand.h" 24 #include "llvm/CodeGen/ScheduleDAG.h" 25 #include "llvm/MC/MCInstrDesc.h" 26 #include "llvm/Support/ErrorHandling.h" 27 #include <algorithm> 28 #include <cassert> 29 #include <limits> 30 #include <set> 31 #include <vector> 32 33 using namespace llvm; 34 35 //===----------------------------------------------------------------------===// 36 // Hazard Recoginizer Implementation 37 //===----------------------------------------------------------------------===// 38 39 GCNHazardRecognizer::GCNHazardRecognizer(const MachineFunction &MF) : 40 CurrCycleInstr(nullptr), 41 MF(MF), 42 ST(MF.getSubtarget<SISubtarget>()), 43 TII(*ST.getInstrInfo()), 44 TRI(TII.getRegisterInfo()), 45 ClauseUses(TRI.getNumRegUnits()), 46 ClauseDefs(TRI.getNumRegUnits()) { 47 MaxLookAhead = 5; 48 } 49 50 void GCNHazardRecognizer::EmitInstruction(SUnit *SU) { 51 EmitInstruction(SU->getInstr()); 52 } 53 54 void GCNHazardRecognizer::EmitInstruction(MachineInstr *MI) { 55 CurrCycleInstr = MI; 56 } 57 58 static bool isDivFMas(unsigned Opcode) { 59 return Opcode == AMDGPU::V_DIV_FMAS_F32 || Opcode == AMDGPU::V_DIV_FMAS_F64; 60 } 61 62 static bool isSGetReg(unsigned Opcode) { 63 return Opcode == AMDGPU::S_GETREG_B32; 64 } 65 66 static bool isSSetReg(unsigned Opcode) { 67 return Opcode == AMDGPU::S_SETREG_B32 || Opcode == AMDGPU::S_SETREG_IMM32_B32; 68 } 69 70 static bool isRWLane(unsigned Opcode) { 71 return Opcode == AMDGPU::V_READLANE_B32 || Opcode == AMDGPU::V_WRITELANE_B32; 72 } 73 74 static bool isRFE(unsigned Opcode) { 75 return Opcode == AMDGPU::S_RFE_B64; 76 } 77 78 static bool isSMovRel(unsigned Opcode) { 79 switch (Opcode) { 80 case AMDGPU::S_MOVRELS_B32: 81 case AMDGPU::S_MOVRELS_B64: 82 case AMDGPU::S_MOVRELD_B32: 83 case AMDGPU::S_MOVRELD_B64: 84 return true; 85 default: 86 return false; 87 } 88 } 89 90 static bool isSendMsgTraceDataOrGDS(const MachineInstr &MI) { 91 switch (MI.getOpcode()) { 92 case AMDGPU::S_SENDMSG: 93 case AMDGPU::S_SENDMSGHALT: 94 case AMDGPU::S_TTRACEDATA: 95 return true; 96 default: 97 // TODO: GDS 98 return false; 99 } 100 } 101 102 static unsigned getHWReg(const SIInstrInfo *TII, const MachineInstr &RegInstr) { 103 const MachineOperand *RegOp = TII->getNamedOperand(RegInstr, 104 AMDGPU::OpName::simm16); 105 return RegOp->getImm() & AMDGPU::Hwreg::ID_MASK_; 106 } 107 108 ScheduleHazardRecognizer::HazardType 109 GCNHazardRecognizer::getHazardType(SUnit *SU, int Stalls) { 110 MachineInstr *MI = SU->getInstr(); 111 112 if (SIInstrInfo::isSMRD(*MI) && checkSMRDHazards(MI) > 0) 113 return NoopHazard; 114 115 // FIXME: Should flat be considered vmem? 116 if ((SIInstrInfo::isVMEM(*MI) || 117 SIInstrInfo::isFLAT(*MI)) 118 && checkVMEMHazards(MI) > 0) 119 return NoopHazard; 120 121 if (SIInstrInfo::isVALU(*MI) && checkVALUHazards(MI) > 0) 122 return NoopHazard; 123 124 if (SIInstrInfo::isDPP(*MI) && checkDPPHazards(MI) > 0) 125 return NoopHazard; 126 127 if (isDivFMas(MI->getOpcode()) && checkDivFMasHazards(MI) > 0) 128 return NoopHazard; 129 130 if (isRWLane(MI->getOpcode()) && checkRWLaneHazards(MI) > 0) 131 return NoopHazard; 132 133 if (isSGetReg(MI->getOpcode()) && checkGetRegHazards(MI) > 0) 134 return NoopHazard; 135 136 if (isSSetReg(MI->getOpcode()) && checkSetRegHazards(MI) > 0) 137 return NoopHazard; 138 139 if (isRFE(MI->getOpcode()) && checkRFEHazards(MI) > 0) 140 return NoopHazard; 141 142 if (ST.hasReadM0MovRelInterpHazard() && 143 (TII.isVINTRP(*MI) || isSMovRel(MI->getOpcode())) && 144 checkReadM0Hazards(MI) > 0) 145 return NoopHazard; 146 147 if (ST.hasReadM0SendMsgHazard() && isSendMsgTraceDataOrGDS(*MI) && 148 checkReadM0Hazards(MI) > 0) 149 return NoopHazard; 150 151 if (checkAnyInstHazards(MI) > 0) 152 return NoopHazard; 153 154 return NoHazard; 155 } 156 157 unsigned GCNHazardRecognizer::PreEmitNoops(SUnit *SU) { 158 return PreEmitNoops(SU->getInstr()); 159 } 160 161 unsigned GCNHazardRecognizer::PreEmitNoops(MachineInstr *MI) { 162 int WaitStates = std::max(0, checkAnyInstHazards(MI)); 163 164 if (SIInstrInfo::isSMRD(*MI)) 165 return std::max(WaitStates, checkSMRDHazards(MI)); 166 167 if (SIInstrInfo::isVALU(*MI)) 168 WaitStates = std::max(WaitStates, checkVALUHazards(MI)); 169 170 if (SIInstrInfo::isVMEM(*MI) || SIInstrInfo::isFLAT(*MI)) 171 WaitStates = std::max(WaitStates, checkVMEMHazards(MI)); 172 173 if (SIInstrInfo::isDPP(*MI)) 174 WaitStates = std::max(WaitStates, checkDPPHazards(MI)); 175 176 if (isDivFMas(MI->getOpcode())) 177 WaitStates = std::max(WaitStates, checkDivFMasHazards(MI)); 178 179 if (isRWLane(MI->getOpcode())) 180 WaitStates = std::max(WaitStates, checkRWLaneHazards(MI)); 181 182 if (isSGetReg(MI->getOpcode())) 183 return std::max(WaitStates, checkGetRegHazards(MI)); 184 185 if (isSSetReg(MI->getOpcode())) 186 return std::max(WaitStates, checkSetRegHazards(MI)); 187 188 if (isRFE(MI->getOpcode())) 189 return std::max(WaitStates, checkRFEHazards(MI)); 190 191 if (ST.hasReadM0MovRelInterpHazard() && (TII.isVINTRP(*MI) || 192 isSMovRel(MI->getOpcode()))) 193 return std::max(WaitStates, checkReadM0Hazards(MI)); 194 195 if (ST.hasReadM0SendMsgHazard() && isSendMsgTraceDataOrGDS(*MI)) 196 return std::max(WaitStates, checkReadM0Hazards(MI)); 197 198 return WaitStates; 199 } 200 201 void GCNHazardRecognizer::EmitNoop() { 202 EmittedInstrs.push_front(nullptr); 203 } 204 205 void GCNHazardRecognizer::AdvanceCycle() { 206 // When the scheduler detects a stall, it will call AdvanceCycle() without 207 // emitting any instructions. 208 if (!CurrCycleInstr) 209 return; 210 211 unsigned NumWaitStates = TII.getNumWaitStates(*CurrCycleInstr); 212 213 // Keep track of emitted instructions 214 EmittedInstrs.push_front(CurrCycleInstr); 215 216 // Add a nullptr for each additional wait state after the first. Make sure 217 // not to add more than getMaxLookAhead() items to the list, since we 218 // truncate the list to that size right after this loop. 219 for (unsigned i = 1, e = std::min(NumWaitStates, getMaxLookAhead()); 220 i < e; ++i) { 221 EmittedInstrs.push_front(nullptr); 222 } 223 224 // getMaxLookahead() is the largest number of wait states we will ever need 225 // to insert, so there is no point in keeping track of more than that many 226 // wait states. 227 EmittedInstrs.resize(getMaxLookAhead()); 228 229 CurrCycleInstr = nullptr; 230 } 231 232 void GCNHazardRecognizer::RecedeCycle() { 233 llvm_unreachable("hazard recognizer does not support bottom-up scheduling."); 234 } 235 236 //===----------------------------------------------------------------------===// 237 // Helper Functions 238 //===----------------------------------------------------------------------===// 239 240 int GCNHazardRecognizer::getWaitStatesSince( 241 function_ref<bool(MachineInstr *)> IsHazard) { 242 int WaitStates = 0; 243 for (MachineInstr *MI : EmittedInstrs) { 244 if (MI) { 245 if (IsHazard(MI)) 246 return WaitStates; 247 248 unsigned Opcode = MI->getOpcode(); 249 if (Opcode == AMDGPU::DBG_VALUE || Opcode == AMDGPU::IMPLICIT_DEF || 250 Opcode == AMDGPU::INLINEASM) 251 continue; 252 } 253 ++WaitStates; 254 } 255 return std::numeric_limits<int>::max(); 256 } 257 258 int GCNHazardRecognizer::getWaitStatesSinceDef( 259 unsigned Reg, function_ref<bool(MachineInstr *)> IsHazardDef) { 260 const SIRegisterInfo *TRI = ST.getRegisterInfo(); 261 262 auto IsHazardFn = [IsHazardDef, TRI, Reg] (MachineInstr *MI) { 263 return IsHazardDef(MI) && MI->modifiesRegister(Reg, TRI); 264 }; 265 266 return getWaitStatesSince(IsHazardFn); 267 } 268 269 int GCNHazardRecognizer::getWaitStatesSinceSetReg( 270 function_ref<bool(MachineInstr *)> IsHazard) { 271 auto IsHazardFn = [IsHazard] (MachineInstr *MI) { 272 return isSSetReg(MI->getOpcode()) && IsHazard(MI); 273 }; 274 275 return getWaitStatesSince(IsHazardFn); 276 } 277 278 //===----------------------------------------------------------------------===// 279 // No-op Hazard Detection 280 //===----------------------------------------------------------------------===// 281 282 static void addRegUnits(const SIRegisterInfo &TRI, 283 BitVector &BV, unsigned Reg) { 284 for (MCRegUnitIterator RUI(Reg, &TRI); RUI.isValid(); ++RUI) 285 BV.set(*RUI); 286 } 287 288 static void addRegsToSet(const SIRegisterInfo &TRI, 289 iterator_range<MachineInstr::const_mop_iterator> Ops, 290 BitVector &Set) { 291 for (const MachineOperand &Op : Ops) { 292 if (Op.isReg()) 293 addRegUnits(TRI, Set, Op.getReg()); 294 } 295 } 296 297 void GCNHazardRecognizer::addClauseInst(const MachineInstr &MI) { 298 // XXX: Do we need to worry about implicit operands 299 addRegsToSet(TRI, MI.defs(), ClauseDefs); 300 addRegsToSet(TRI, MI.uses(), ClauseUses); 301 } 302 303 int GCNHazardRecognizer::checkSoftClauseHazards(MachineInstr *MEM) { 304 // SMEM soft clause are only present on VI+, and only matter if xnack is 305 // enabled. 306 if (!ST.isXNACKEnabled()) 307 return 0; 308 309 bool IsSMRD = TII.isSMRD(*MEM); 310 311 resetClause(); 312 313 // A soft-clause is any group of consecutive SMEM instructions. The 314 // instructions in this group may return out of order and/or may be 315 // replayed (i.e. the same instruction issued more than once). 316 // 317 // In order to handle these situations correctly we need to make sure 318 // that when a clause has more than one instruction, no instruction in the 319 // clause writes to a register that is read another instruction in the clause 320 // (including itself). If we encounter this situaion, we need to break the 321 // clause by inserting a non SMEM instruction. 322 323 for (MachineInstr *MI : EmittedInstrs) { 324 // When we hit a non-SMEM instruction then we have passed the start of the 325 // clause and we can stop. 326 if (!MI) 327 break; 328 329 if (IsSMRD != SIInstrInfo::isSMRD(*MI)) 330 break; 331 332 addClauseInst(*MI); 333 } 334 335 if (ClauseDefs.none()) 336 return 0; 337 338 // We need to make sure not to put loads and stores in the same clause if they 339 // use the same address. For now, just start a new clause whenever we see a 340 // store. 341 if (MEM->mayStore()) 342 return 1; 343 344 addClauseInst(*MEM); 345 346 // If the set of defs and uses intersect then we cannot add this instruction 347 // to the clause, so we have a hazard. 348 return ClauseDefs.anyCommon(ClauseUses) ? 1 : 0; 349 } 350 351 int GCNHazardRecognizer::checkSMRDHazards(MachineInstr *SMRD) { 352 const SISubtarget &ST = MF.getSubtarget<SISubtarget>(); 353 int WaitStatesNeeded = 0; 354 355 WaitStatesNeeded = checkSoftClauseHazards(SMRD); 356 357 // This SMRD hazard only affects SI. 358 if (ST.getGeneration() != SISubtarget::SOUTHERN_ISLANDS) 359 return WaitStatesNeeded; 360 361 // A read of an SGPR by SMRD instruction requires 4 wait states when the 362 // SGPR was written by a VALU instruction. 363 int SmrdSgprWaitStates = 4; 364 auto IsHazardDefFn = [this] (MachineInstr *MI) { return TII.isVALU(*MI); }; 365 auto IsBufferHazardDefFn = [this] (MachineInstr *MI) { return TII.isSALU(*MI); }; 366 367 bool IsBufferSMRD = TII.isBufferSMRD(*SMRD); 368 369 for (const MachineOperand &Use : SMRD->uses()) { 370 if (!Use.isReg()) 371 continue; 372 int WaitStatesNeededForUse = 373 SmrdSgprWaitStates - getWaitStatesSinceDef(Use.getReg(), IsHazardDefFn); 374 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse); 375 376 // This fixes what appears to be undocumented hardware behavior in SI where 377 // s_mov writing a descriptor and s_buffer_load_dword reading the descriptor 378 // needs some number of nops in between. We don't know how many we need, but 379 // let's use 4. This wasn't discovered before probably because the only 380 // case when this happens is when we expand a 64-bit pointer into a full 381 // descriptor and use s_buffer_load_dword instead of s_load_dword, which was 382 // probably never encountered in the closed-source land. 383 if (IsBufferSMRD) { 384 int WaitStatesNeededForUse = 385 SmrdSgprWaitStates - getWaitStatesSinceDef(Use.getReg(), 386 IsBufferHazardDefFn); 387 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse); 388 } 389 } 390 391 return WaitStatesNeeded; 392 } 393 394 int GCNHazardRecognizer::checkVMEMHazards(MachineInstr* VMEM) { 395 if (ST.getGeneration() < SISubtarget::VOLCANIC_ISLANDS) 396 return 0; 397 398 int WaitStatesNeeded = checkSoftClauseHazards(VMEM); 399 400 // A read of an SGPR by a VMEM instruction requires 5 wait states when the 401 // SGPR was written by a VALU Instruction. 402 const int VmemSgprWaitStates = 5; 403 auto IsHazardDefFn = [this] (MachineInstr *MI) { return TII.isVALU(*MI); }; 404 405 for (const MachineOperand &Use : VMEM->uses()) { 406 if (!Use.isReg() || TRI.isVGPR(MF.getRegInfo(), Use.getReg())) 407 continue; 408 409 int WaitStatesNeededForUse = 410 VmemSgprWaitStates - getWaitStatesSinceDef(Use.getReg(), IsHazardDefFn); 411 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse); 412 } 413 return WaitStatesNeeded; 414 } 415 416 int GCNHazardRecognizer::checkDPPHazards(MachineInstr *DPP) { 417 const SIRegisterInfo *TRI = ST.getRegisterInfo(); 418 const SIInstrInfo *TII = ST.getInstrInfo(); 419 420 // Check for DPP VGPR read after VALU VGPR write and EXEC write. 421 int DppVgprWaitStates = 2; 422 int DppExecWaitStates = 5; 423 int WaitStatesNeeded = 0; 424 auto IsHazardDefFn = [TII] (MachineInstr *MI) { return TII->isVALU(*MI); }; 425 426 for (const MachineOperand &Use : DPP->uses()) { 427 if (!Use.isReg() || !TRI->isVGPR(MF.getRegInfo(), Use.getReg())) 428 continue; 429 int WaitStatesNeededForUse = 430 DppVgprWaitStates - getWaitStatesSinceDef(Use.getReg()); 431 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse); 432 } 433 434 WaitStatesNeeded = std::max( 435 WaitStatesNeeded, 436 DppExecWaitStates - getWaitStatesSinceDef(AMDGPU::EXEC, IsHazardDefFn)); 437 438 return WaitStatesNeeded; 439 } 440 441 int GCNHazardRecognizer::checkDivFMasHazards(MachineInstr *DivFMas) { 442 const SIInstrInfo *TII = ST.getInstrInfo(); 443 444 // v_div_fmas requires 4 wait states after a write to vcc from a VALU 445 // instruction. 446 const int DivFMasWaitStates = 4; 447 auto IsHazardDefFn = [TII] (MachineInstr *MI) { return TII->isVALU(*MI); }; 448 int WaitStatesNeeded = getWaitStatesSinceDef(AMDGPU::VCC, IsHazardDefFn); 449 450 return DivFMasWaitStates - WaitStatesNeeded; 451 } 452 453 int GCNHazardRecognizer::checkGetRegHazards(MachineInstr *GetRegInstr) { 454 const SIInstrInfo *TII = ST.getInstrInfo(); 455 unsigned GetRegHWReg = getHWReg(TII, *GetRegInstr); 456 457 const int GetRegWaitStates = 2; 458 auto IsHazardFn = [TII, GetRegHWReg] (MachineInstr *MI) { 459 return GetRegHWReg == getHWReg(TII, *MI); 460 }; 461 int WaitStatesNeeded = getWaitStatesSinceSetReg(IsHazardFn); 462 463 return GetRegWaitStates - WaitStatesNeeded; 464 } 465 466 int GCNHazardRecognizer::checkSetRegHazards(MachineInstr *SetRegInstr) { 467 const SIInstrInfo *TII = ST.getInstrInfo(); 468 unsigned HWReg = getHWReg(TII, *SetRegInstr); 469 470 const int SetRegWaitStates = 471 ST.getGeneration() <= AMDGPUSubtarget::SEA_ISLANDS ? 1 : 2; 472 auto IsHazardFn = [TII, HWReg] (MachineInstr *MI) { 473 return HWReg == getHWReg(TII, *MI); 474 }; 475 int WaitStatesNeeded = getWaitStatesSinceSetReg(IsHazardFn); 476 return SetRegWaitStates - WaitStatesNeeded; 477 } 478 479 int GCNHazardRecognizer::createsVALUHazard(const MachineInstr &MI) { 480 if (!MI.mayStore()) 481 return -1; 482 483 const SIInstrInfo *TII = ST.getInstrInfo(); 484 unsigned Opcode = MI.getOpcode(); 485 const MCInstrDesc &Desc = MI.getDesc(); 486 487 int VDataIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::vdata); 488 int VDataRCID = -1; 489 if (VDataIdx != -1) 490 VDataRCID = Desc.OpInfo[VDataIdx].RegClass; 491 492 if (TII->isMUBUF(MI) || TII->isMTBUF(MI)) { 493 // There is no hazard if the instruction does not use vector regs 494 // (like wbinvl1) 495 if (VDataIdx == -1) 496 return -1; 497 // For MUBUF/MTBUF instructions this hazard only exists if the 498 // instruction is not using a register in the soffset field. 499 const MachineOperand *SOffset = 500 TII->getNamedOperand(MI, AMDGPU::OpName::soffset); 501 // If we have no soffset operand, then assume this field has been 502 // hardcoded to zero. 503 if (AMDGPU::getRegBitWidth(VDataRCID) > 64 && 504 (!SOffset || !SOffset->isReg())) 505 return VDataIdx; 506 } 507 508 // MIMG instructions create a hazard if they don't use a 256-bit T# and 509 // the store size is greater than 8 bytes and they have more than two bits 510 // of their dmask set. 511 // All our MIMG definitions use a 256-bit T#, so we can skip checking for them. 512 if (TII->isMIMG(MI)) { 513 int SRsrcIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::srsrc); 514 assert(SRsrcIdx != -1 && 515 AMDGPU::getRegBitWidth(Desc.OpInfo[SRsrcIdx].RegClass) == 256); 516 (void)SRsrcIdx; 517 } 518 519 if (TII->isFLAT(MI)) { 520 int DataIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::vdata); 521 if (AMDGPU::getRegBitWidth(Desc.OpInfo[DataIdx].RegClass) > 64) 522 return DataIdx; 523 } 524 525 return -1; 526 } 527 528 int GCNHazardRecognizer::checkVALUHazards(MachineInstr *VALU) { 529 // This checks for the hazard where VMEM instructions that store more than 530 // 8 bytes can have there store data over written by the next instruction. 531 if (!ST.has12DWordStoreHazard()) 532 return 0; 533 534 const SIRegisterInfo *TRI = ST.getRegisterInfo(); 535 const MachineRegisterInfo &MRI = VALU->getParent()->getParent()->getRegInfo(); 536 537 const int VALUWaitStates = 1; 538 int WaitStatesNeeded = 0; 539 540 for (const MachineOperand &Def : VALU->defs()) { 541 if (!TRI->isVGPR(MRI, Def.getReg())) 542 continue; 543 unsigned Reg = Def.getReg(); 544 auto IsHazardFn = [this, Reg, TRI] (MachineInstr *MI) { 545 int DataIdx = createsVALUHazard(*MI); 546 return DataIdx >= 0 && 547 TRI->regsOverlap(MI->getOperand(DataIdx).getReg(), Reg); 548 }; 549 int WaitStatesNeededForDef = 550 VALUWaitStates - getWaitStatesSince(IsHazardFn); 551 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef); 552 } 553 return WaitStatesNeeded; 554 } 555 556 int GCNHazardRecognizer::checkRWLaneHazards(MachineInstr *RWLane) { 557 const SIInstrInfo *TII = ST.getInstrInfo(); 558 const SIRegisterInfo *TRI = ST.getRegisterInfo(); 559 const MachineRegisterInfo &MRI = 560 RWLane->getParent()->getParent()->getRegInfo(); 561 562 const MachineOperand *LaneSelectOp = 563 TII->getNamedOperand(*RWLane, AMDGPU::OpName::src1); 564 565 if (!LaneSelectOp->isReg() || !TRI->isSGPRReg(MRI, LaneSelectOp->getReg())) 566 return 0; 567 568 unsigned LaneSelectReg = LaneSelectOp->getReg(); 569 auto IsHazardFn = [TII] (MachineInstr *MI) { 570 return TII->isVALU(*MI); 571 }; 572 573 const int RWLaneWaitStates = 4; 574 int WaitStatesSince = getWaitStatesSinceDef(LaneSelectReg, IsHazardFn); 575 return RWLaneWaitStates - WaitStatesSince; 576 } 577 578 int GCNHazardRecognizer::checkRFEHazards(MachineInstr *RFE) { 579 if (ST.getGeneration() < AMDGPUSubtarget::VOLCANIC_ISLANDS) 580 return 0; 581 582 const SIInstrInfo *TII = ST.getInstrInfo(); 583 584 const int RFEWaitStates = 1; 585 586 auto IsHazardFn = [TII] (MachineInstr *MI) { 587 return getHWReg(TII, *MI) == AMDGPU::Hwreg::ID_TRAPSTS; 588 }; 589 int WaitStatesNeeded = getWaitStatesSinceSetReg(IsHazardFn); 590 return RFEWaitStates - WaitStatesNeeded; 591 } 592 593 int GCNHazardRecognizer::checkAnyInstHazards(MachineInstr *MI) { 594 if (MI->isDebugValue()) 595 return 0; 596 597 const SIRegisterInfo *TRI = ST.getRegisterInfo(); 598 if (!ST.hasSMovFedHazard()) 599 return 0; 600 601 // Check for any instruction reading an SGPR after a write from 602 // s_mov_fed_b32. 603 int MovFedWaitStates = 1; 604 int WaitStatesNeeded = 0; 605 606 for (const MachineOperand &Use : MI->uses()) { 607 if (!Use.isReg() || TRI->isVGPR(MF.getRegInfo(), Use.getReg())) 608 continue; 609 auto IsHazardFn = [] (MachineInstr *MI) { 610 return MI->getOpcode() == AMDGPU::S_MOV_FED_B32; 611 }; 612 int WaitStatesNeededForUse = 613 MovFedWaitStates - getWaitStatesSinceDef(Use.getReg(), IsHazardFn); 614 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse); 615 } 616 617 return WaitStatesNeeded; 618 } 619 620 int GCNHazardRecognizer::checkReadM0Hazards(MachineInstr *MI) { 621 const SIInstrInfo *TII = ST.getInstrInfo(); 622 const int SMovRelWaitStates = 1; 623 auto IsHazardFn = [TII] (MachineInstr *MI) { 624 return TII->isSALU(*MI); 625 }; 626 return SMovRelWaitStates - getWaitStatesSinceDef(AMDGPU::M0, IsHazardFn); 627 } 628