blob: dd3b46f1392154cc7065fd5282064a51008bbe29 [file] [log] [blame]
Tom Stellardcb6ba622016-04-30 00:23:06 +00001//===-- 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 "SIInstrInfo.h"
17#include "llvm/CodeGen/ScheduleDAG.h"
18#include "llvm/Support/Debug.h"
19
20using namespace llvm;
21
22//===----------------------------------------------------------------------===//
23// Hazard Recoginizer Implementation
24//===----------------------------------------------------------------------===//
25
26GCNHazardRecognizer::GCNHazardRecognizer(const MachineFunction &MF) :
27 CurrCycleInstr(nullptr),
Matt Arsenault43e92fe2016-06-24 06:30:11 +000028 MF(MF),
29 ST(MF.getSubtarget<SISubtarget>()) {
Tom Stellardcb6ba622016-04-30 00:23:06 +000030 MaxLookAhead = 5;
31}
32
33void GCNHazardRecognizer::EmitInstruction(SUnit *SU) {
34 EmitInstruction(SU->getInstr());
35}
36
37void GCNHazardRecognizer::EmitInstruction(MachineInstr *MI) {
38 CurrCycleInstr = MI;
39}
40
Tom Stellard5ab61542016-10-07 23:42:48 +000041static bool isDivFMas(unsigned Opcode) {
42 return Opcode == AMDGPU::V_DIV_FMAS_F32 || Opcode == AMDGPU::V_DIV_FMAS_F64;
43}
44
Tom Stellard961811c2016-10-15 00:58:14 +000045static bool isSGetReg(unsigned Opcode) {
46 return Opcode == AMDGPU::S_GETREG_B32;
47}
48
49static bool isSSetReg(unsigned Opcode) {
50 return Opcode == AMDGPU::S_SETREG_B32 || Opcode == AMDGPU::S_SETREG_IMM32_B32;
51}
52
Tom Stellard04051b52016-10-27 23:42:29 +000053static bool isRWLane(unsigned Opcode) {
54 return Opcode == AMDGPU::V_READLANE_B32 || Opcode == AMDGPU::V_WRITELANE_B32;
55}
56
Tom Stellardaea899e2016-10-27 23:50:21 +000057static bool isRFE(unsigned Opcode) {
58 return Opcode == AMDGPU::S_RFE_B64;
59}
60
61static unsigned getHWReg(const SIInstrInfo *TII, const MachineInstr &RegInstr) {
Tom Stellard961811c2016-10-15 00:58:14 +000062
63 const MachineOperand *RegOp = TII->getNamedOperand(RegInstr,
64 AMDGPU::OpName::simm16);
65 return RegOp->getImm() & AMDGPU::Hwreg::ID_MASK_;
66}
67
Tom Stellardcb6ba622016-04-30 00:23:06 +000068ScheduleHazardRecognizer::HazardType
69GCNHazardRecognizer::getHazardType(SUnit *SU, int Stalls) {
Tom Stellardcb6ba622016-04-30 00:23:06 +000070 MachineInstr *MI = SU->getInstr();
71
Aaron Ballman5c190d02016-05-02 14:48:03 +000072 if (SIInstrInfo::isSMRD(*MI) && checkSMRDHazards(MI) > 0)
Tom Stellardcb6ba622016-04-30 00:23:06 +000073 return NoopHazard;
74
Aaron Ballman5c190d02016-05-02 14:48:03 +000075 if (SIInstrInfo::isVMEM(*MI) && checkVMEMHazards(MI) > 0)
Tom Stellardcb6ba622016-04-30 00:23:06 +000076 return NoopHazard;
77
Tom Stellardb133fbb2016-10-27 23:05:31 +000078 if (SIInstrInfo::isVALU(*MI) && checkVALUHazards(MI) > 0)
79 return NoopHazard;
80
Tom Stellarda27007e2016-05-02 16:23:09 +000081 if (SIInstrInfo::isDPP(*MI) && checkDPPHazards(MI) > 0)
82 return NoopHazard;
83
Tom Stellard5ab61542016-10-07 23:42:48 +000084 if (isDivFMas(MI->getOpcode()) && checkDivFMasHazards(MI) > 0)
85 return NoopHazard;
86
Tom Stellard04051b52016-10-27 23:42:29 +000087 if (isRWLane(MI->getOpcode()) && checkRWLaneHazards(MI) > 0)
88 return NoopHazard;
89
Tom Stellard961811c2016-10-15 00:58:14 +000090 if (isSGetReg(MI->getOpcode()) && checkGetRegHazards(MI) > 0)
91 return NoopHazard;
92
Tom Stellard30d30822016-10-27 20:39:09 +000093 if (isSSetReg(MI->getOpcode()) && checkSetRegHazards(MI) > 0)
94 return NoopHazard;
95
Tom Stellardaea899e2016-10-27 23:50:21 +000096 if (isRFE(MI->getOpcode()) && checkRFEHazards(MI) > 0)
97 return NoopHazard;
98
Tom Stellardcb6ba622016-04-30 00:23:06 +000099 return NoHazard;
100}
101
102unsigned GCNHazardRecognizer::PreEmitNoops(SUnit *SU) {
103 return PreEmitNoops(SU->getInstr());
104}
105
106unsigned GCNHazardRecognizer::PreEmitNoops(MachineInstr *MI) {
Aaron Ballman5c190d02016-05-02 14:48:03 +0000107 if (SIInstrInfo::isSMRD(*MI))
Tom Stellardcb6ba622016-04-30 00:23:06 +0000108 return std::max(0, checkSMRDHazards(MI));
109
Tom Stellardb133fbb2016-10-27 23:05:31 +0000110 if (SIInstrInfo::isVALU(*MI)) {
111 int WaitStates = std::max(0, checkVALUHazards(MI));
Tom Stellardcb6ba622016-04-30 00:23:06 +0000112
Tom Stellardb133fbb2016-10-27 23:05:31 +0000113 if (SIInstrInfo::isVMEM(*MI))
114 WaitStates = std::max(WaitStates, checkVMEMHazards(MI));
Tom Stellarda27007e2016-05-02 16:23:09 +0000115
Tom Stellardb133fbb2016-10-27 23:05:31 +0000116 if (SIInstrInfo::isDPP(*MI))
117 WaitStates = std::max(WaitStates, checkDPPHazards(MI));
118
119 if (isDivFMas(MI->getOpcode()))
120 WaitStates = std::max(WaitStates, checkDivFMasHazards(MI));
121
Tom Stellard04051b52016-10-27 23:42:29 +0000122 if (isRWLane(MI->getOpcode()))
123 WaitStates = std::max(WaitStates, checkRWLaneHazards(MI));
124
Tom Stellardb133fbb2016-10-27 23:05:31 +0000125 return WaitStates;
126 }
Tom Stellard5ab61542016-10-07 23:42:48 +0000127
Tom Stellard961811c2016-10-15 00:58:14 +0000128 if (isSGetReg(MI->getOpcode()))
129 return std::max(0, checkGetRegHazards(MI));
130
Tom Stellard30d30822016-10-27 20:39:09 +0000131 if (isSSetReg(MI->getOpcode()))
132 return std::max(0, checkSetRegHazards(MI));
133
Tom Stellardaea899e2016-10-27 23:50:21 +0000134 if (isRFE(MI->getOpcode()))
135 return std::max(0, checkRFEHazards(MI));
136
Tom Stellardcb6ba622016-04-30 00:23:06 +0000137 return 0;
138}
139
140void GCNHazardRecognizer::EmitNoop() {
141 EmittedInstrs.push_front(nullptr);
142}
143
144void GCNHazardRecognizer::AdvanceCycle() {
145
146 // When the scheduler detects a stall, it will call AdvanceCycle() without
147 // emitting any instructions.
148 if (!CurrCycleInstr)
149 return;
150
Matt Arsenault43e92fe2016-06-24 06:30:11 +0000151 const SIInstrInfo *TII = ST.getInstrInfo();
Tom Stellardcb6ba622016-04-30 00:23:06 +0000152 unsigned NumWaitStates = TII->getNumWaitStates(*CurrCycleInstr);
153
154 // Keep track of emitted instructions
155 EmittedInstrs.push_front(CurrCycleInstr);
156
157 // Add a nullptr for each additional wait state after the first. Make sure
158 // not to add more than getMaxLookAhead() items to the list, since we
159 // truncate the list to that size right after this loop.
160 for (unsigned i = 1, e = std::min(NumWaitStates, getMaxLookAhead());
161 i < e; ++i) {
162 EmittedInstrs.push_front(nullptr);
163 }
164
165 // getMaxLookahead() is the largest number of wait states we will ever need
166 // to insert, so there is no point in keeping track of more than that many
167 // wait states.
168 EmittedInstrs.resize(getMaxLookAhead());
169
170 CurrCycleInstr = nullptr;
171}
172
173void GCNHazardRecognizer::RecedeCycle() {
174 llvm_unreachable("hazard recognizer does not support bottom-up scheduling.");
175}
176
177//===----------------------------------------------------------------------===//
178// Helper Functions
179//===----------------------------------------------------------------------===//
180
Tom Stellardb133fbb2016-10-27 23:05:31 +0000181int GCNHazardRecognizer::getWaitStatesSince(
Tom Stellard961811c2016-10-15 00:58:14 +0000182 function_ref<bool(MachineInstr *)> IsHazard) {
183
184 int WaitStates = -1;
185 for (MachineInstr *MI : EmittedInstrs) {
186 ++WaitStates;
Tom Stellardb133fbb2016-10-27 23:05:31 +0000187 if (!MI || !IsHazard(MI))
Tom Stellard961811c2016-10-15 00:58:14 +0000188 continue;
189 return WaitStates;
190 }
191 return std::numeric_limits<int>::max();
192}
193
Tom Stellardb133fbb2016-10-27 23:05:31 +0000194int GCNHazardRecognizer::getWaitStatesSinceDef(
195 unsigned Reg, function_ref<bool(MachineInstr *)> IsHazardDef) {
196 const SIRegisterInfo *TRI = ST.getRegisterInfo();
197
198 auto IsHazardFn = [IsHazardDef, TRI, Reg] (MachineInstr *MI) {
199 return IsHazardDef(MI) && MI->modifiesRegister(Reg, TRI);
200 };
201
202 return getWaitStatesSince(IsHazardFn);
203}
204
205int GCNHazardRecognizer::getWaitStatesSinceSetReg(
206 function_ref<bool(MachineInstr *)> IsHazard) {
207
208 auto IsHazardFn = [IsHazard] (MachineInstr *MI) {
209 return isSSetReg(MI->getOpcode()) && IsHazard(MI);
210 };
211
212 return getWaitStatesSince(IsHazardFn);
213}
214
Tom Stellardcb6ba622016-04-30 00:23:06 +0000215//===----------------------------------------------------------------------===//
216// No-op Hazard Detection
217//===----------------------------------------------------------------------===//
218
Tom Stellard1f520e52016-05-02 17:39:06 +0000219static void addRegsToSet(iterator_range<MachineInstr::const_mop_iterator> Ops,
220 std::set<unsigned> &Set) {
221 for (const MachineOperand &Op : Ops) {
222 if (Op.isReg())
223 Set.insert(Op.getReg());
224 }
225}
226
227int GCNHazardRecognizer::checkSMEMSoftClauseHazards(MachineInstr *SMEM) {
Tom Stellard1f520e52016-05-02 17:39:06 +0000228 // SMEM soft clause are only present on VI+
Matt Arsenault43e92fe2016-06-24 06:30:11 +0000229 if (ST.getGeneration() < SISubtarget::VOLCANIC_ISLANDS)
Tom Stellard1f520e52016-05-02 17:39:06 +0000230 return 0;
231
232 // A soft-clause is any group of consecutive SMEM instructions. The
233 // instructions in this group may return out of order and/or may be
234 // replayed (i.e. the same instruction issued more than once).
235 //
236 // In order to handle these situations correctly we need to make sure
237 // that when a clause has more than one instruction, no instruction in the
238 // clause writes to a register that is read another instruction in the clause
239 // (including itself). If we encounter this situaion, we need to break the
240 // clause by inserting a non SMEM instruction.
241
Tom Stellard1f520e52016-05-02 17:39:06 +0000242 std::set<unsigned> ClauseDefs;
243 std::set<unsigned> ClauseUses;
244
245 for (MachineInstr *MI : EmittedInstrs) {
246
247 // When we hit a non-SMEM instruction then we have passed the start of the
248 // clause and we can stop.
Aaron Ballman3bd56b32016-05-03 15:17:25 +0000249 if (!MI || !SIInstrInfo::isSMRD(*MI))
Tom Stellard1f520e52016-05-02 17:39:06 +0000250 break;
251
252 addRegsToSet(MI->defs(), ClauseDefs);
253 addRegsToSet(MI->uses(), ClauseUses);
254 }
255
256 if (ClauseDefs.empty())
257 return 0;
258
259 // FIXME: When we support stores, we need to make sure not to put loads and
260 // stores in the same clause if they use the same address. For now, just
261 // start a new clause whenever we see a store.
262 if (SMEM->mayStore())
263 return 1;
264
265 addRegsToSet(SMEM->defs(), ClauseDefs);
266 addRegsToSet(SMEM->uses(), ClauseUses);
267
268 std::vector<unsigned> Result(std::max(ClauseDefs.size(), ClauseUses.size()));
269 std::vector<unsigned>::iterator End;
270
271 End = std::set_intersection(ClauseDefs.begin(), ClauseDefs.end(),
272 ClauseUses.begin(), ClauseUses.end(), Result.begin());
273
274 // If the set of defs and uses intersect then we cannot add this instruction
275 // to the clause, so we have a hazard.
276 if (End != Result.begin())
277 return 1;
278
279 return 0;
280}
281
Tom Stellardcb6ba622016-04-30 00:23:06 +0000282int GCNHazardRecognizer::checkSMRDHazards(MachineInstr *SMRD) {
Matt Arsenault43e92fe2016-06-24 06:30:11 +0000283 const SISubtarget &ST = MF.getSubtarget<SISubtarget>();
284 const SIInstrInfo *TII = ST.getInstrInfo();
Tom Stellard1f520e52016-05-02 17:39:06 +0000285 int WaitStatesNeeded = 0;
286
287 WaitStatesNeeded = checkSMEMSoftClauseHazards(SMRD);
Tom Stellardcb6ba622016-04-30 00:23:06 +0000288
289 // This SMRD hazard only affects SI.
Matt Arsenault43e92fe2016-06-24 06:30:11 +0000290 if (ST.getGeneration() != SISubtarget::SOUTHERN_ISLANDS)
Tom Stellard1f520e52016-05-02 17:39:06 +0000291 return WaitStatesNeeded;
Tom Stellardcb6ba622016-04-30 00:23:06 +0000292
293 // A read of an SGPR by SMRD instruction requires 4 wait states when the
294 // SGPR was written by a VALU instruction.
295 int SmrdSgprWaitStates = 4;
Tom Stellardcb6ba622016-04-30 00:23:06 +0000296 auto IsHazardDefFn = [TII] (MachineInstr *MI) { return TII->isVALU(*MI); };
297
298 for (const MachineOperand &Use : SMRD->uses()) {
299 if (!Use.isReg())
300 continue;
301 int WaitStatesNeededForUse =
302 SmrdSgprWaitStates - getWaitStatesSinceDef(Use.getReg(), IsHazardDefFn);
303 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
304 }
305 return WaitStatesNeeded;
306}
307
308int GCNHazardRecognizer::checkVMEMHazards(MachineInstr* VMEM) {
Matt Arsenault43e92fe2016-06-24 06:30:11 +0000309 const SIInstrInfo *TII = ST.getInstrInfo();
Tom Stellardcb6ba622016-04-30 00:23:06 +0000310
Matt Arsenault43e92fe2016-06-24 06:30:11 +0000311 if (ST.getGeneration() < SISubtarget::VOLCANIC_ISLANDS)
Tom Stellardcb6ba622016-04-30 00:23:06 +0000312 return 0;
313
314 const SIRegisterInfo &TRI = TII->getRegisterInfo();
315
316 // A read of an SGPR by a VMEM instruction requires 5 wait states when the
317 // SGPR was written by a VALU Instruction.
318 int VmemSgprWaitStates = 5;
319 int WaitStatesNeeded = 0;
320 auto IsHazardDefFn = [TII] (MachineInstr *MI) { return TII->isVALU(*MI); };
321
322 for (const MachineOperand &Use : VMEM->uses()) {
323 if (!Use.isReg() || TRI.isVGPR(MF.getRegInfo(), Use.getReg()))
324 continue;
325
326 int WaitStatesNeededForUse =
327 VmemSgprWaitStates - getWaitStatesSinceDef(Use.getReg(), IsHazardDefFn);
328 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
329 }
330 return WaitStatesNeeded;
331}
Tom Stellarda27007e2016-05-02 16:23:09 +0000332
333int GCNHazardRecognizer::checkDPPHazards(MachineInstr *DPP) {
Matt Arsenault43e92fe2016-06-24 06:30:11 +0000334 const SIRegisterInfo *TRI = ST.getRegisterInfo();
Tom Stellarda27007e2016-05-02 16:23:09 +0000335
336 // Check for DPP VGPR read after VALU VGPR write.
337 int DppVgprWaitStates = 2;
338 int WaitStatesNeeded = 0;
339
340 for (const MachineOperand &Use : DPP->uses()) {
341 if (!Use.isReg() || !TRI->isVGPR(MF.getRegInfo(), Use.getReg()))
342 continue;
343 int WaitStatesNeededForUse =
344 DppVgprWaitStates - getWaitStatesSinceDef(Use.getReg());
345 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
346 }
347
348 return WaitStatesNeeded;
349}
Tom Stellard5ab61542016-10-07 23:42:48 +0000350
351int GCNHazardRecognizer::checkDivFMasHazards(MachineInstr *DivFMas) {
352 const SIInstrInfo *TII = ST.getInstrInfo();
353
354 // v_div_fmas requires 4 wait states after a write to vcc from a VALU
355 // instruction.
356 const int DivFMasWaitStates = 4;
357 auto IsHazardDefFn = [TII] (MachineInstr *MI) { return TII->isVALU(*MI); };
358 int WaitStatesNeeded = getWaitStatesSinceDef(AMDGPU::VCC, IsHazardDefFn);
359
360 return DivFMasWaitStates - WaitStatesNeeded;
361}
Tom Stellard961811c2016-10-15 00:58:14 +0000362
363int GCNHazardRecognizer::checkGetRegHazards(MachineInstr *GetRegInstr) {
364 const SIInstrInfo *TII = ST.getInstrInfo();
365 unsigned GetRegHWReg = getHWReg(TII, *GetRegInstr);
366
367 const int GetRegWaitStates = 2;
368 auto IsHazardFn = [TII, GetRegHWReg] (MachineInstr *MI) {
369 return GetRegHWReg == getHWReg(TII, *MI);
370 };
371 int WaitStatesNeeded = getWaitStatesSinceSetReg(IsHazardFn);
372
373 return GetRegWaitStates - WaitStatesNeeded;
374}
Tom Stellard30d30822016-10-27 20:39:09 +0000375
376int GCNHazardRecognizer::checkSetRegHazards(MachineInstr *SetRegInstr) {
377 const SIInstrInfo *TII = ST.getInstrInfo();
378 unsigned HWReg = getHWReg(TII, *SetRegInstr);
379
380 const int SetRegWaitStates =
381 ST.getGeneration() <= AMDGPUSubtarget::SEA_ISLANDS ? 1 : 2;
382 auto IsHazardFn = [TII, HWReg] (MachineInstr *MI) {
383 return HWReg == getHWReg(TII, *MI);
384 };
385 int WaitStatesNeeded = getWaitStatesSinceSetReg(IsHazardFn);
386 return SetRegWaitStates - WaitStatesNeeded;
387}
Tom Stellardb133fbb2016-10-27 23:05:31 +0000388
389int GCNHazardRecognizer::createsVALUHazard(const MachineInstr &MI) {
390 if (!MI.mayStore())
391 return -1;
392
393 const SIInstrInfo *TII = ST.getInstrInfo();
394 unsigned Opcode = MI.getOpcode();
395 const MCInstrDesc &Desc = MI.getDesc();
396
397 int VDataIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::vdata);
398 int VDataRCID = -1;
399 if (VDataIdx != -1)
400 VDataRCID = Desc.OpInfo[VDataIdx].RegClass;
401
402 if (TII->isMUBUF(MI) || TII->isMTBUF(MI)) {
Jan Veselye8cc3952016-11-15 23:55:15 +0000403 // There is no hazard if the instruction does not use vector regs
404 // (like wbinvl1)
405 if (VDataIdx == -1)
406 return -1;
Tom Stellardb133fbb2016-10-27 23:05:31 +0000407 // For MUBUF/MTBUF instructions this hazard only exists if the
408 // instruction is not using a register in the soffset field.
409 const MachineOperand *SOffset =
410 TII->getNamedOperand(MI, AMDGPU::OpName::soffset);
411 // If we have no soffset operand, then assume this field has been
412 // hardcoded to zero.
413 if (AMDGPU::getRegBitWidth(VDataRCID) > 64 &&
414 (!SOffset || !SOffset->isReg()))
415 return VDataIdx;
416 }
417
418 // MIMG instructions create a hazard if they don't use a 256-bit T# and
419 // the store size is greater than 8 bytes and they have more than two bits
420 // of their dmask set.
421 // All our MIMG definitions use a 256-bit T#, so we can skip checking for them.
422 if (TII->isMIMG(MI)) {
423 int SRsrcIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::srsrc);
424 assert(SRsrcIdx != -1 &&
425 AMDGPU::getRegBitWidth(Desc.OpInfo[SRsrcIdx].RegClass) == 256);
Tom Stellard6b9c1be2016-10-27 23:28:03 +0000426 (void)SRsrcIdx;
Tom Stellardb133fbb2016-10-27 23:05:31 +0000427 }
428
429 if (TII->isFLAT(MI)) {
Matt Arsenault97279a82016-11-29 19:30:44 +0000430 int DataIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::vdata);
Tom Stellardb133fbb2016-10-27 23:05:31 +0000431 if (AMDGPU::getRegBitWidth(Desc.OpInfo[DataIdx].RegClass) > 64)
432 return DataIdx;
433 }
434
435 return -1;
436}
437
438int GCNHazardRecognizer::checkVALUHazards(MachineInstr *VALU) {
439 // This checks for the hazard where VMEM instructions that store more than
440 // 8 bytes can have there store data over written by the next instruction.
441 if (!ST.has12DWordStoreHazard())
442 return 0;
443
444 const SIRegisterInfo *TRI = ST.getRegisterInfo();
445 const MachineRegisterInfo &MRI = VALU->getParent()->getParent()->getRegInfo();
446
447 const int VALUWaitStates = 1;
448 int WaitStatesNeeded = 0;
449
450 for (const MachineOperand &Def : VALU->defs()) {
451 if (!TRI->isVGPR(MRI, Def.getReg()))
452 continue;
453 unsigned Reg = Def.getReg();
454 auto IsHazardFn = [this, Reg, TRI] (MachineInstr *MI) {
455 int DataIdx = createsVALUHazard(*MI);
456 return DataIdx >= 0 &&
457 TRI->regsOverlap(MI->getOperand(DataIdx).getReg(), Reg);
458 };
459 int WaitStatesNeededForDef =
460 VALUWaitStates - getWaitStatesSince(IsHazardFn);
461 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
462 }
463 return WaitStatesNeeded;
464}
Tom Stellard04051b52016-10-27 23:42:29 +0000465
466int GCNHazardRecognizer::checkRWLaneHazards(MachineInstr *RWLane) {
467 const SIInstrInfo *TII = ST.getInstrInfo();
468 const SIRegisterInfo *TRI = ST.getRegisterInfo();
469 const MachineRegisterInfo &MRI =
470 RWLane->getParent()->getParent()->getRegInfo();
471
472 const MachineOperand *LaneSelectOp =
473 TII->getNamedOperand(*RWLane, AMDGPU::OpName::src1);
474
475 if (!LaneSelectOp->isReg() || !TRI->isSGPRReg(MRI, LaneSelectOp->getReg()))
476 return 0;
477
478 unsigned LaneSelectReg = LaneSelectOp->getReg();
479 auto IsHazardFn = [TII] (MachineInstr *MI) {
480 return TII->isVALU(*MI);
481 };
482
483 const int RWLaneWaitStates = 4;
484 int WaitStatesSince = getWaitStatesSinceDef(LaneSelectReg, IsHazardFn);
485 return RWLaneWaitStates - WaitStatesSince;
486}
Tom Stellardaea899e2016-10-27 23:50:21 +0000487
488int GCNHazardRecognizer::checkRFEHazards(MachineInstr *RFE) {
489
490 if (ST.getGeneration() < AMDGPUSubtarget::VOLCANIC_ISLANDS)
491 return 0;
492
493 const SIInstrInfo *TII = ST.getInstrInfo();
494
495 const int RFEWaitStates = 1;
496
497 auto IsHazardFn = [TII] (MachineInstr *MI) {
498 return getHWReg(TII, *MI) == AMDGPU::Hwreg::ID_TRAPSTS;
499 };
500 int WaitStatesNeeded = getWaitStatesSinceSetReg(IsHazardFn);
501 return RFEWaitStates - WaitStatesNeeded;
502}