blob: 725727979e9ec31643d1b91be05fa0baed55bda6 [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),
28 MF(MF) {
29 MaxLookAhead = 5;
30}
31
32void GCNHazardRecognizer::EmitInstruction(SUnit *SU) {
33 EmitInstruction(SU->getInstr());
34}
35
36void GCNHazardRecognizer::EmitInstruction(MachineInstr *MI) {
37 CurrCycleInstr = MI;
38}
39
40ScheduleHazardRecognizer::HazardType
41GCNHazardRecognizer::getHazardType(SUnit *SU, int Stalls) {
Tom Stellardcb6ba622016-04-30 00:23:06 +000042 MachineInstr *MI = SU->getInstr();
43
Aaron Ballman5c190d02016-05-02 14:48:03 +000044 if (SIInstrInfo::isSMRD(*MI) && checkSMRDHazards(MI) > 0)
Tom Stellardcb6ba622016-04-30 00:23:06 +000045 return NoopHazard;
46
Aaron Ballman5c190d02016-05-02 14:48:03 +000047 if (SIInstrInfo::isVMEM(*MI) && checkVMEMHazards(MI) > 0)
Tom Stellardcb6ba622016-04-30 00:23:06 +000048 return NoopHazard;
49
50 return NoHazard;
51}
52
53unsigned GCNHazardRecognizer::PreEmitNoops(SUnit *SU) {
54 return PreEmitNoops(SU->getInstr());
55}
56
57unsigned GCNHazardRecognizer::PreEmitNoops(MachineInstr *MI) {
Aaron Ballman5c190d02016-05-02 14:48:03 +000058 if (SIInstrInfo::isSMRD(*MI))
Tom Stellardcb6ba622016-04-30 00:23:06 +000059 return std::max(0, checkSMRDHazards(MI));
60
Aaron Ballman5c190d02016-05-02 14:48:03 +000061 if (SIInstrInfo::isVMEM(*MI))
Tom Stellardcb6ba622016-04-30 00:23:06 +000062 return std::max(0, checkVMEMHazards(MI));
63
64 return 0;
65}
66
67void GCNHazardRecognizer::EmitNoop() {
68 EmittedInstrs.push_front(nullptr);
69}
70
71void GCNHazardRecognizer::AdvanceCycle() {
72
73 // When the scheduler detects a stall, it will call AdvanceCycle() without
74 // emitting any instructions.
75 if (!CurrCycleInstr)
76 return;
77
78 const SIInstrInfo *TII =
79 static_cast<const SIInstrInfo*>(MF.getSubtarget().getInstrInfo());
80 unsigned NumWaitStates = TII->getNumWaitStates(*CurrCycleInstr);
81
82 // Keep track of emitted instructions
83 EmittedInstrs.push_front(CurrCycleInstr);
84
85 // Add a nullptr for each additional wait state after the first. Make sure
86 // not to add more than getMaxLookAhead() items to the list, since we
87 // truncate the list to that size right after this loop.
88 for (unsigned i = 1, e = std::min(NumWaitStates, getMaxLookAhead());
89 i < e; ++i) {
90 EmittedInstrs.push_front(nullptr);
91 }
92
93 // getMaxLookahead() is the largest number of wait states we will ever need
94 // to insert, so there is no point in keeping track of more than that many
95 // wait states.
96 EmittedInstrs.resize(getMaxLookAhead());
97
98 CurrCycleInstr = nullptr;
99}
100
101void GCNHazardRecognizer::RecedeCycle() {
102 llvm_unreachable("hazard recognizer does not support bottom-up scheduling.");
103}
104
105//===----------------------------------------------------------------------===//
106// Helper Functions
107//===----------------------------------------------------------------------===//
108
109int GCNHazardRecognizer::getWaitStatesSinceDef(unsigned Reg,
110 std::function<bool(MachineInstr*)> IsHazardDef ) {
111 const TargetRegisterInfo *TRI =
112 MF.getSubtarget<AMDGPUSubtarget>().getRegisterInfo();
113
114 int WaitStates = -1;
115 for (MachineInstr *MI : EmittedInstrs) {
116 ++WaitStates;
117 if (!MI || !IsHazardDef(MI))
118 continue;
119 if (MI->modifiesRegister(Reg, TRI))
120 return WaitStates;
121 }
122 return std::numeric_limits<int>::max();
123}
124
125//===----------------------------------------------------------------------===//
126// No-op Hazard Detection
127//===----------------------------------------------------------------------===//
128
129int GCNHazardRecognizer::checkSMRDHazards(MachineInstr *SMRD) {
130 const AMDGPUSubtarget &ST = MF.getSubtarget<AMDGPUSubtarget>();
131 const SIInstrInfo *TII = static_cast<const SIInstrInfo*>(ST.getInstrInfo());
132
133 // This SMRD hazard only affects SI.
134 if (ST.getGeneration() != AMDGPUSubtarget::SOUTHERN_ISLANDS)
135 return 0;
136
137 // A read of an SGPR by SMRD instruction requires 4 wait states when the
138 // SGPR was written by a VALU instruction.
139 int SmrdSgprWaitStates = 4;
140 int WaitStatesNeeded = 0;
141 auto IsHazardDefFn = [TII] (MachineInstr *MI) { return TII->isVALU(*MI); };
142
143 for (const MachineOperand &Use : SMRD->uses()) {
144 if (!Use.isReg())
145 continue;
146 int WaitStatesNeededForUse =
147 SmrdSgprWaitStates - getWaitStatesSinceDef(Use.getReg(), IsHazardDefFn);
148 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
149 }
150 return WaitStatesNeeded;
151}
152
153int GCNHazardRecognizer::checkVMEMHazards(MachineInstr* VMEM) {
154 const AMDGPUSubtarget &ST = MF.getSubtarget<AMDGPUSubtarget>();
155 const SIInstrInfo *TII = static_cast<const SIInstrInfo*>(ST.getInstrInfo());
156
157 if (ST.getGeneration() < AMDGPUSubtarget::VOLCANIC_ISLANDS)
158 return 0;
159
160 const SIRegisterInfo &TRI = TII->getRegisterInfo();
161
162 // A read of an SGPR by a VMEM instruction requires 5 wait states when the
163 // SGPR was written by a VALU Instruction.
164 int VmemSgprWaitStates = 5;
165 int WaitStatesNeeded = 0;
166 auto IsHazardDefFn = [TII] (MachineInstr *MI) { return TII->isVALU(*MI); };
167
168 for (const MachineOperand &Use : VMEM->uses()) {
169 if (!Use.isReg() || TRI.isVGPR(MF.getRegInfo(), Use.getReg()))
170 continue;
171
172 int WaitStatesNeededForUse =
173 VmemSgprWaitStates - getWaitStatesSinceDef(Use.getReg(), IsHazardDefFn);
174 WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse);
175 }
176 return WaitStatesNeeded;
177}