1 //===-- AMDGPUSubtarget.cpp - AMDGPU Subtarget Information ----------------===//
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 /// \file
11 /// \brief Implements the AMDGPU specific subclass of TargetSubtarget.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "AMDGPUSubtarget.h"
16 #include "R600ISelLowering.h"
17 #include "R600InstrInfo.h"
18 #include "SIFrameLowering.h"
19 #include "SIISelLowering.h"
20 #include "SIInstrInfo.h"
21 #include "SIMachineFunctionInfo.h"
22 #include "llvm/ADT/SmallString.h"
23 #include "llvm/CodeGen/MachineScheduler.h"
24 
25 using namespace llvm;
26 
27 #define DEBUG_TYPE "amdgpu-subtarget"
28 
29 #define GET_SUBTARGETINFO_ENUM
30 #define GET_SUBTARGETINFO_TARGET_DESC
31 #define GET_SUBTARGETINFO_CTOR
32 #include "AMDGPUGenSubtargetInfo.inc"
33 
34 AMDGPUSubtarget::~AMDGPUSubtarget() {}
35 
36 AMDGPUSubtarget &
37 AMDGPUSubtarget::initializeSubtargetDependencies(const Triple &TT,
38                                                  StringRef GPU, StringRef FS) {
39   // Determine default and user-specified characteristics
40   // On SI+, we want FP64 denormals to be on by default. FP32 denormals can be
41   // enabled, but some instructions do not respect them and they run at the
42   // double precision rate, so don't enable by default.
43   //
44   // We want to be able to turn these off, but making this a subtarget feature
45   // for SI has the unhelpful behavior that it unsets everything else if you
46   // disable it.
47 
48   SmallString<256> FullFS("+promote-alloca,+fp64-denormals,+load-store-opt,");
49   if (isAmdHsaOS()) // Turn on FlatForGlobal for HSA.
50     FullFS += "+flat-for-global,+unaligned-buffer-access,";
51   FullFS += FS;
52 
53   ParseSubtargetFeatures(GPU, FullFS);
54 
55   // FIXME: I don't think think Evergreen has any useful support for
56   // denormals, but should be checked. Should we issue a warning somewhere
57   // if someone tries to enable these?
58   if (getGeneration() <= AMDGPUSubtarget::NORTHERN_ISLANDS) {
59     FP32Denormals = false;
60     FP64Denormals = false;
61   }
62 
63   // Set defaults if needed.
64   if (MaxPrivateElementSize == 0)
65     MaxPrivateElementSize = 4;
66 
67   return *this;
68 }
69 
70 AMDGPUSubtarget::AMDGPUSubtarget(const Triple &TT, StringRef GPU, StringRef FS,
71                                  const TargetMachine &TM)
72   : AMDGPUGenSubtargetInfo(TT, GPU, FS),
73     TargetTriple(TT),
74     Gen(TT.getArch() == Triple::amdgcn ? SOUTHERN_ISLANDS : R600),
75     IsaVersion(ISAVersion0_0_0),
76     WavefrontSize(64),
77     LocalMemorySize(0),
78     LDSBankCount(0),
79     MaxPrivateElementSize(0),
80 
81     FastFMAF32(false),
82     HalfRate64Ops(false),
83 
84     FP32Denormals(false),
85     FP64Denormals(false),
86     FPExceptions(false),
87     FlatForGlobal(false),
88     UnalignedScratchAccess(false),
89     UnalignedBufferAccess(false),
90 
91     EnableXNACK(false),
92     DebuggerInsertNops(false),
93     DebuggerReserveRegs(false),
94     DebuggerEmitPrologue(false),
95 
96     EnableVGPRSpilling(false),
97     EnablePromoteAlloca(false),
98     EnableLoadStoreOpt(false),
99     EnableUnsafeDSOffsetFolding(false),
100     EnableSIScheduler(false),
101     DumpCode(false),
102 
103     FP64(false),
104     IsGCN(false),
105     GCN1Encoding(false),
106     GCN3Encoding(false),
107     CIInsts(false),
108     SGPRInitBug(false),
109     HasSMemRealTime(false),
110     Has16BitInsts(false),
111     HasMovrel(false),
112     HasVGPRIndexMode(false),
113     HasScalarStores(false),
114     HasInv2PiInlineImm(false),
115     FlatAddressSpace(false),
116 
117     R600ALUInst(false),
118     CaymanISA(false),
119     CFALUBug(false),
120     HasVertexCache(false),
121     TexVTXClauseSize(0),
122 
123     FeatureDisable(false),
124     InstrItins(getInstrItineraryForCPU(GPU)),
125     TSInfo() {
126   initializeSubtargetDependencies(TT, GPU, FS);
127 }
128 
129 // FIXME: These limits are for SI. Did they change with the larger maximum LDS
130 // size?
131 unsigned AMDGPUSubtarget::getMaxLocalMemSizeWithWaveCount(unsigned NWaves) const {
132   switch (NWaves) {
133   case 10:
134     return 1638;
135   case 9:
136     return 1820;
137   case 8:
138     return 2048;
139   case 7:
140     return 2340;
141   case 6:
142     return 2730;
143   case 5:
144     return 3276;
145   case 4:
146     return 4096;
147   case 3:
148     return 5461;
149   case 2:
150     return 8192;
151   default:
152     return getLocalMemorySize();
153   }
154 }
155 
156 unsigned AMDGPUSubtarget::getOccupancyWithLocalMemSize(uint32_t Bytes) const {
157   if (Bytes <= 1638)
158     return 10;
159 
160   if (Bytes <= 1820)
161     return 9;
162 
163   if (Bytes <= 2048)
164     return 8;
165 
166   if (Bytes <= 2340)
167     return 7;
168 
169   if (Bytes <= 2730)
170     return 6;
171 
172   if (Bytes <= 3276)
173     return 5;
174 
175   if (Bytes <= 4096)
176     return 4;
177 
178   if (Bytes <= 5461)
179     return 3;
180 
181   if (Bytes <= 8192)
182     return 2;
183 
184   return 1;
185 }
186 
187 std::pair<unsigned, unsigned> AMDGPUSubtarget::getFlatWorkGroupSizes(
188   const Function &F) const {
189 
190   // Default minimum/maximum flat work group sizes.
191   std::pair<unsigned, unsigned> Default =
192     AMDGPU::isCompute(F.getCallingConv()) ?
193       std::pair<unsigned, unsigned>(getWavefrontSize() * 2,
194                                     getWavefrontSize() * 4) :
195       std::pair<unsigned, unsigned>(1, getWavefrontSize());
196 
197   // TODO: Do not process "amdgpu-max-work-group-size" attribute once mesa
198   // starts using "amdgpu-flat-work-group-size" attribute.
199   Default.second = AMDGPU::getIntegerAttribute(
200     F, "amdgpu-max-work-group-size", Default.second);
201   Default.first = std::min(Default.first, Default.second);
202 
203   // Requested minimum/maximum flat work group sizes.
204   std::pair<unsigned, unsigned> Requested = AMDGPU::getIntegerPairAttribute(
205     F, "amdgpu-flat-work-group-size", Default);
206 
207   // Make sure requested minimum is less than requested maximum.
208   if (Requested.first > Requested.second)
209     return Default;
210 
211   // Make sure requested values do not violate subtarget's specifications.
212   if (Requested.first < getMinFlatWorkGroupSize())
213     return Default;
214   if (Requested.second > getMaxFlatWorkGroupSize())
215     return Default;
216 
217   return Requested;
218 }
219 
220 std::pair<unsigned, unsigned> AMDGPUSubtarget::getWavesPerEU(
221   const Function &F) const {
222 
223   // Default minimum/maximum number of waves per execution unit.
224   std::pair<unsigned, unsigned> Default(1, 0);
225 
226   // Default/requested minimum/maximum flat work group sizes.
227   std::pair<unsigned, unsigned> FlatWorkGroupSizes = getFlatWorkGroupSizes(F);
228 
229   // If minimum/maximum flat work group sizes were explicitly requested using
230   // "amdgpu-flat-work-group-size" attribute, then set default minimum/maximum
231   // number of waves per execution unit to values implied by requested
232   // minimum/maximum flat work group sizes.
233   unsigned MinImpliedByFlatWorkGroupSize =
234     getMaxWavesPerEU(FlatWorkGroupSizes.second);
235   bool RequestedFlatWorkGroupSize = false;
236 
237   // TODO: Do not process "amdgpu-max-work-group-size" attribute once mesa
238   // starts using "amdgpu-flat-work-group-size" attribute.
239   if (F.hasFnAttribute("amdgpu-max-work-group-size") ||
240       F.hasFnAttribute("amdgpu-flat-work-group-size")) {
241     Default.first = MinImpliedByFlatWorkGroupSize;
242     RequestedFlatWorkGroupSize = true;
243   }
244 
245   // Requested minimum/maximum number of waves per execution unit.
246   std::pair<unsigned, unsigned> Requested = AMDGPU::getIntegerPairAttribute(
247     F, "amdgpu-waves-per-eu", Default, true);
248 
249   // Make sure requested minimum is less than requested maximum.
250   if (Requested.second && Requested.first > Requested.second)
251     return Default;
252 
253   // Make sure requested values do not violate subtarget's specifications.
254   if (Requested.first < getMinWavesPerEU() ||
255       Requested.first > getMaxWavesPerEU())
256     return Default;
257   if (Requested.second > getMaxWavesPerEU())
258     return Default;
259 
260   // Make sure requested values are compatible with values implied by requested
261   // minimum/maximum flat work group sizes.
262   if (RequestedFlatWorkGroupSize &&
263       Requested.first > MinImpliedByFlatWorkGroupSize)
264     return Default;
265 
266   return Requested;
267 }
268 
269 R600Subtarget::R600Subtarget(const Triple &TT, StringRef GPU, StringRef FS,
270                              const TargetMachine &TM) :
271   AMDGPUSubtarget(TT, GPU, FS, TM),
272   InstrInfo(*this),
273   FrameLowering(TargetFrameLowering::StackGrowsUp, getStackAlignment(), 0),
274   TLInfo(TM, *this) {}
275 
276 SISubtarget::SISubtarget(const Triple &TT, StringRef GPU, StringRef FS,
277                          const TargetMachine &TM) :
278   AMDGPUSubtarget(TT, GPU, FS, TM),
279   InstrInfo(*this),
280   FrameLowering(TargetFrameLowering::StackGrowsUp, getStackAlignment(), 0),
281   TLInfo(TM, *this),
282   GISel() {}
283 
284 void SISubtarget::overrideSchedPolicy(MachineSchedPolicy &Policy,
285                                       unsigned NumRegionInstrs) const {
286   // Track register pressure so the scheduler can try to decrease
287   // pressure once register usage is above the threshold defined by
288   // SIRegisterInfo::getRegPressureSetLimit()
289   Policy.ShouldTrackPressure = true;
290 
291   // Enabling both top down and bottom up scheduling seems to give us less
292   // register spills than just using one of these approaches on its own.
293   Policy.OnlyTopDown = false;
294   Policy.OnlyBottomUp = false;
295 
296   // Enabling ShouldTrackLaneMasks crashes the SI Machine Scheduler.
297   if (!enableSIScheduler())
298     Policy.ShouldTrackLaneMasks = true;
299 }
300 
301 bool SISubtarget::isVGPRSpillingEnabled(const Function& F) const {
302   return EnableVGPRSpilling || !AMDGPU::isShader(F.getCallingConv());
303 }
304 
305 unsigned SISubtarget::getKernArgSegmentSize(unsigned ExplicitArgBytes) const {
306   unsigned ImplicitBytes = getImplicitArgNumBytes();
307   if (ImplicitBytes == 0)
308     return ExplicitArgBytes;
309 
310   unsigned Alignment = getAlignmentForImplicitArgPtr();
311   return alignTo(ExplicitArgBytes, Alignment) + ImplicitBytes;
312 }
313 
314 unsigned SISubtarget::getOccupancyWithNumSGPRs(unsigned SGPRs) const {
315   if (getGeneration() >= SISubtarget::VOLCANIC_ISLANDS) {
316     if (SGPRs <= 80)
317       return 10;
318     if (SGPRs <= 88)
319       return 9;
320     if (SGPRs <= 100)
321       return 8;
322     return 7;
323   }
324   if (SGPRs <= 48)
325     return 10;
326   if (SGPRs <= 56)
327     return 9;
328   if (SGPRs <= 64)
329     return 8;
330   if (SGPRs <= 72)
331     return 7;
332   if (SGPRs <= 80)
333     return 6;
334   return 5;
335 }
336 
337 unsigned SISubtarget::getOccupancyWithNumVGPRs(unsigned VGPRs) const {
338   if (VGPRs <= 24)
339     return 10;
340   if (VGPRs <= 28)
341     return 9;
342   if (VGPRs <= 32)
343     return 8;
344   if (VGPRs <= 36)
345     return 7;
346   if (VGPRs <= 40)
347     return 6;
348   if (VGPRs <= 48)
349     return 5;
350   if (VGPRs <= 64)
351     return 4;
352   if (VGPRs <= 84)
353     return 3;
354   if (VGPRs <= 128)
355     return 2;
356   return 1;
357 }
358 
359 unsigned SISubtarget::getMaxNumSGPRs() const {
360   if (hasSGPRInitBug())
361     return SISubtarget::FIXED_SGPR_COUNT_FOR_INIT_BUG;
362 
363   if (getGeneration() >= VOLCANIC_ISLANDS)
364     return 102;
365 
366   return 104;
367 }
368