1 //=====-- AMDGPUSubtarget.h - Define Subtarget for AMDGPU ------*- C++ -*-====//
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 AMDGPU specific subclass of TargetSubtarget.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef LLVM_LIB_TARGET_AMDGPU_AMDGPUSUBTARGET_H
16 #define LLVM_LIB_TARGET_AMDGPU_AMDGPUSUBTARGET_H
17 
18 #include "AMDGPU.h"
19 #include "R600InstrInfo.h"
20 #include "R600ISelLowering.h"
21 #include "R600FrameLowering.h"
22 #include "SIInstrInfo.h"
23 #include "SIISelLowering.h"
24 #include "SIFrameLowering.h"
25 #include "Utils/AMDGPUBaseInfo.h"
26 #include "llvm/CodeGen/GlobalISel/GISelAccessor.h"
27 #include "llvm/CodeGen/SelectionDAGTargetInfo.h"
28 #include "llvm/Target/TargetSubtargetInfo.h"
29 
30 #define GET_SUBTARGETINFO_HEADER
31 #include "AMDGPUGenSubtargetInfo.inc"
32 
33 namespace llvm {
34 
35 class SIMachineFunctionInfo;
36 class StringRef;
37 
38 class AMDGPUSubtarget : public AMDGPUGenSubtargetInfo {
39 public:
40   enum Generation {
41     R600 = 0,
42     R700,
43     EVERGREEN,
44     NORTHERN_ISLANDS,
45     SOUTHERN_ISLANDS,
46     SEA_ISLANDS,
47     VOLCANIC_ISLANDS,
48   };
49 
50   enum {
51     ISAVersion0_0_0,
52     ISAVersion7_0_0,
53     ISAVersion7_0_1,
54     ISAVersion8_0_0,
55     ISAVersion8_0_1,
56     ISAVersion8_0_2,
57     ISAVersion8_0_3
58   };
59 
60 protected:
61   // Basic subtarget description.
62   Triple TargetTriple;
63   Generation Gen;
64   unsigned IsaVersion;
65   unsigned WavefrontSize;
66   int LocalMemorySize;
67   int LDSBankCount;
68   unsigned MaxPrivateElementSize;
69 
70   // Possibly statically set by tablegen, but may want to be overridden.
71   bool FastFMAF32;
72   bool HalfRate64Ops;
73 
74   // Dynamially set bits that enable features.
75   bool FP32Denormals;
76   bool FP64Denormals;
77   bool FPExceptions;
78   bool FlatForGlobal;
79   bool UnalignedBufferAccess;
80   bool EnableXNACK;
81   bool DebuggerInsertNops;
82   bool DebuggerReserveRegs;
83   bool DebuggerEmitPrologue;
84 
85   // Used as options.
86   bool EnableVGPRSpilling;
87   bool EnablePromoteAlloca;
88   bool EnableLoadStoreOpt;
89   bool EnableUnsafeDSOffsetFolding;
90   bool EnableSIScheduler;
91   bool DumpCode;
92 
93   // Subtarget statically properties set by tablegen
94   bool FP64;
95   bool IsGCN;
96   bool GCN1Encoding;
97   bool GCN3Encoding;
98   bool CIInsts;
99   bool SGPRInitBug;
100   bool HasSMemRealTime;
101   bool Has16BitInsts;
102   bool HasMovrel;
103   bool HasVGPRIndexMode;
104   bool FlatAddressSpace;
105   bool R600ALUInst;
106   bool CaymanISA;
107   bool CFALUBug;
108   bool HasVertexCache;
109   short TexVTXClauseSize;
110 
111   // Dummy feature to use for assembler in tablegen.
112   bool FeatureDisable;
113 
114   InstrItineraryData InstrItins;
115   SelectionDAGTargetInfo TSInfo;
116 
117 public:
118   AMDGPUSubtarget(const Triple &TT, StringRef GPU, StringRef FS,
119                   const TargetMachine &TM);
120   virtual ~AMDGPUSubtarget();
121   AMDGPUSubtarget &initializeSubtargetDependencies(const Triple &TT,
122                                                    StringRef GPU, StringRef FS);
123 
124   const AMDGPUInstrInfo *getInstrInfo() const override = 0;
125   const AMDGPUFrameLowering *getFrameLowering() const override = 0;
126   const AMDGPUTargetLowering *getTargetLowering() const override = 0;
127   const AMDGPURegisterInfo *getRegisterInfo() const override = 0;
128 
129   const InstrItineraryData *getInstrItineraryData() const override {
130     return &InstrItins;
131   }
132 
133   // Nothing implemented, just prevent crashes on use.
134   const SelectionDAGTargetInfo *getSelectionDAGInfo() const override {
135     return &TSInfo;
136   }
137 
138   void ParseSubtargetFeatures(StringRef CPU, StringRef FS);
139 
140   bool isAmdHsaOS() const {
141     return TargetTriple.getOS() == Triple::AMDHSA;
142   }
143 
144   bool isMesa3DOS() const {
145     return TargetTriple.getOS() == Triple::Mesa3D;
146   }
147 
148   bool isOpenCLEnv() const {
149     return TargetTriple.getEnvironment() == Triple::OpenCL;
150   }
151 
152   Generation getGeneration() const {
153     return Gen;
154   }
155 
156   unsigned getWavefrontSize() const {
157     return WavefrontSize;
158   }
159 
160   int getLocalMemorySize() const {
161     return LocalMemorySize;
162   }
163 
164   int getLDSBankCount() const {
165     return LDSBankCount;
166   }
167 
168   unsigned getMaxPrivateElementSize() const {
169     return MaxPrivateElementSize;
170   }
171 
172   bool hasHWFP64() const {
173     return FP64;
174   }
175 
176   bool hasFastFMAF32() const {
177     return FastFMAF32;
178   }
179 
180   bool hasHalfRate64Ops() const {
181     return HalfRate64Ops;
182   }
183 
184   bool hasAddr64() const {
185     return (getGeneration() < VOLCANIC_ISLANDS);
186   }
187 
188   bool hasBFE() const {
189     return (getGeneration() >= EVERGREEN);
190   }
191 
192   bool hasBFI() const {
193     return (getGeneration() >= EVERGREEN);
194   }
195 
196   bool hasBFM() const {
197     return hasBFE();
198   }
199 
200   bool hasBCNT(unsigned Size) const {
201     if (Size == 32)
202       return (getGeneration() >= EVERGREEN);
203 
204     if (Size == 64)
205       return (getGeneration() >= SOUTHERN_ISLANDS);
206 
207     return false;
208   }
209 
210   bool hasMulU24() const {
211     return (getGeneration() >= EVERGREEN);
212   }
213 
214   bool hasMulI24() const {
215     return (getGeneration() >= SOUTHERN_ISLANDS ||
216             hasCaymanISA());
217   }
218 
219   bool hasFFBL() const {
220     return (getGeneration() >= EVERGREEN);
221   }
222 
223   bool hasFFBH() const {
224     return (getGeneration() >= EVERGREEN);
225   }
226 
227   bool hasCARRY() const {
228     return (getGeneration() >= EVERGREEN);
229   }
230 
231   bool hasBORROW() const {
232     return (getGeneration() >= EVERGREEN);
233   }
234 
235   bool hasCaymanISA() const {
236     return CaymanISA;
237   }
238 
239   bool isPromoteAllocaEnabled() const {
240     return EnablePromoteAlloca;
241   }
242 
243   bool unsafeDSOffsetFoldingEnabled() const {
244     return EnableUnsafeDSOffsetFolding;
245   }
246 
247   bool dumpCode() const {
248     return DumpCode;
249   }
250 
251   /// Return the amount of LDS that can be used that will not restrict the
252   /// occupancy lower than WaveCount.
253   unsigned getMaxLocalMemSizeWithWaveCount(unsigned WaveCount) const;
254 
255   /// Inverse of getMaxLocalMemWithWaveCount. Return the maximum wavecount if
256   /// the given LDS memory size is the only constraint.
257   unsigned getOccupancyWithLocalMemSize(uint32_t Bytes) const;
258 
259 
260   bool hasFP32Denormals() const {
261     return FP32Denormals;
262   }
263 
264   bool hasFP64Denormals() const {
265     return FP64Denormals;
266   }
267 
268   bool hasFPExceptions() const {
269     return FPExceptions;
270   }
271 
272   bool useFlatForGlobal() const {
273     return FlatForGlobal;
274   }
275 
276   bool hasUnalignedBufferAccess() const {
277     return UnalignedBufferAccess;
278   }
279 
280   bool isXNACKEnabled() const {
281     return EnableXNACK;
282   }
283 
284   bool isAmdCodeObjectV2() const {
285     return isAmdHsaOS() || isMesa3DOS();
286   }
287 
288   /// \brief Returns the offset in bytes from the start of the input buffer
289   ///        of the first explicit kernel argument.
290   unsigned getExplicitKernelArgOffset() const {
291     return isAmdCodeObjectV2() ? 0 : 36;
292   }
293 
294   unsigned getAlignmentForImplicitArgPtr() const {
295     return isAmdHsaOS() ? 8 : 4;
296   }
297 
298   unsigned getImplicitArgNumBytes() const {
299     if (isMesa3DOS())
300       return 16;
301     if (isAmdHsaOS() && isOpenCLEnv())
302       return 32;
303     return 0;
304   }
305 
306   unsigned getStackAlignment() const {
307     // Scratch is allocated in 256 dword per wave blocks.
308     return 4 * 256 / getWavefrontSize();
309   }
310 
311   bool enableMachineScheduler() const override {
312     return true;
313   }
314 
315   bool enableSubRegLiveness() const override {
316     return true;
317   }
318 
319   /// \returns Number of execution units per compute unit supported by the
320   /// subtarget.
321   unsigned getEUsPerCU() const {
322     return 4;
323   }
324 
325   /// \returns Maximum number of work groups per compute unit supported by the
326   /// subtarget and limited by given flat work group size.
327   unsigned getMaxWorkGroupsPerCU(unsigned FlatWorkGroupSize) const {
328     if (getGeneration() < AMDGPUSubtarget::SOUTHERN_ISLANDS)
329       return 8;
330     return getWavesPerWorkGroup(FlatWorkGroupSize) == 1 ? 40 : 16;
331   }
332 
333   /// \returns Maximum number of waves per compute unit supported by the
334   /// subtarget without any kind of limitation.
335   unsigned getMaxWavesPerCU() const {
336     return getMaxWavesPerEU() * getEUsPerCU();
337   }
338 
339   /// \returns Maximum number of waves per compute unit supported by the
340   /// subtarget and limited by given flat work group size.
341   unsigned getMaxWavesPerCU(unsigned FlatWorkGroupSize) const {
342     return getWavesPerWorkGroup(FlatWorkGroupSize);
343   }
344 
345   /// \returns Minimum number of waves per execution unit supported by the
346   /// subtarget.
347   unsigned getMinWavesPerEU() const {
348     return 1;
349   }
350 
351   /// \returns Maximum number of waves per execution unit supported by the
352   /// subtarget without any kind of limitation.
353   unsigned getMaxWavesPerEU() const {
354     if (getGeneration() < AMDGPUSubtarget::SOUTHERN_ISLANDS)
355       return 8;
356     // FIXME: Need to take scratch memory into account.
357     return 10;
358   }
359 
360   /// \returns Maximum number of waves per execution unit supported by the
361   /// subtarget and limited by given flat work group size.
362   unsigned getMaxWavesPerEU(unsigned FlatWorkGroupSize) const {
363     return alignTo(getMaxWavesPerCU(FlatWorkGroupSize), getEUsPerCU()) /
364       getEUsPerCU();
365   }
366 
367   /// \returns Minimum flat work group size supported by the subtarget.
368   unsigned getMinFlatWorkGroupSize() const {
369     return 1;
370   }
371 
372   /// \returns Maximum flat work group size supported by the subtarget.
373   unsigned getMaxFlatWorkGroupSize() const {
374     return 2048;
375   }
376 
377   /// \returns Number of waves per work group given the flat work group size.
378   unsigned getWavesPerWorkGroup(unsigned FlatWorkGroupSize) const {
379     return alignTo(FlatWorkGroupSize, getWavefrontSize()) / getWavefrontSize();
380   }
381 
382   /// \returns Subtarget's default pair of minimum/maximum flat work group sizes
383   /// for function \p F, or minimum/maximum flat work group sizes explicitly
384   /// requested using "amdgpu-flat-work-group-size" attribute attached to
385   /// function \p F.
386   ///
387   /// \returns Subtarget's default values if explicitly requested values cannot
388   /// be converted to integer, or violate subtarget's specifications.
389   std::pair<unsigned, unsigned> getFlatWorkGroupSizes(const Function &F) const;
390 
391   /// \returns Subtarget's default pair of minimum/maximum number of waves per
392   /// execution unit for function \p F, or minimum/maximum number of waves per
393   /// execution unit explicitly requested using "amdgpu-waves-per-eu" attribute
394   /// attached to function \p F.
395   ///
396   /// \returns Subtarget's default values if explicitly requested values cannot
397   /// be converted to integer, violate subtarget's specifications, or are not
398   /// compatible with minimum/maximum number of waves limited by flat work group
399   /// size, register usage, and/or lds usage.
400   std::pair<unsigned, unsigned> getWavesPerEU(const Function &F) const;
401 };
402 
403 class R600Subtarget final : public AMDGPUSubtarget {
404 private:
405   R600InstrInfo InstrInfo;
406   R600FrameLowering FrameLowering;
407   R600TargetLowering TLInfo;
408 
409 public:
410   R600Subtarget(const Triple &TT, StringRef CPU, StringRef FS,
411                 const TargetMachine &TM);
412 
413   const R600InstrInfo *getInstrInfo() const override {
414     return &InstrInfo;
415   }
416 
417   const R600FrameLowering *getFrameLowering() const override {
418     return &FrameLowering;
419   }
420 
421   const R600TargetLowering *getTargetLowering() const override {
422     return &TLInfo;
423   }
424 
425   const R600RegisterInfo *getRegisterInfo() const override {
426     return &InstrInfo.getRegisterInfo();
427   }
428 
429   bool hasCFAluBug() const {
430     return CFALUBug;
431   }
432 
433   bool hasVertexCache() const {
434     return HasVertexCache;
435   }
436 
437   short getTexVTXClauseSize() const {
438     return TexVTXClauseSize;
439   }
440 };
441 
442 class SISubtarget final : public AMDGPUSubtarget {
443 public:
444   enum {
445     // The closed Vulkan driver sets 96, which limits the wave count to 8 but
446     // doesn't spill SGPRs as much as when 80 is set.
447     FIXED_SGPR_COUNT_FOR_INIT_BUG = 96
448   };
449 
450 private:
451   SIInstrInfo InstrInfo;
452   SIFrameLowering FrameLowering;
453   SITargetLowering TLInfo;
454   std::unique_ptr<GISelAccessor> GISel;
455 
456 public:
457   SISubtarget(const Triple &TT, StringRef CPU, StringRef FS,
458               const TargetMachine &TM);
459 
460   const SIInstrInfo *getInstrInfo() const override {
461     return &InstrInfo;
462   }
463 
464   const SIFrameLowering *getFrameLowering() const override {
465     return &FrameLowering;
466   }
467 
468   const SITargetLowering *getTargetLowering() const override {
469     return &TLInfo;
470   }
471 
472   const CallLowering *getCallLowering() const override {
473     assert(GISel && "Access to GlobalISel APIs not set");
474     return GISel->getCallLowering();
475   }
476 
477   const SIRegisterInfo *getRegisterInfo() const override {
478     return &InstrInfo.getRegisterInfo();
479   }
480 
481   void setGISelAccessor(GISelAccessor &GISel) {
482     this->GISel.reset(&GISel);
483   }
484 
485   void overrideSchedPolicy(MachineSchedPolicy &Policy,
486                            unsigned NumRegionInstrs) const override;
487 
488   bool isVGPRSpillingEnabled(const Function& F) const;
489 
490   unsigned getMaxNumUserSGPRs() const {
491     return 16;
492   }
493 
494   bool hasFlatAddressSpace() const {
495     return FlatAddressSpace;
496   }
497 
498   bool hasSMemRealTime() const {
499     return HasSMemRealTime;
500   }
501 
502   bool has16BitInsts() const {
503     return Has16BitInsts;
504   }
505 
506   bool hasMovrel() const {
507     return HasMovrel;
508   }
509 
510   bool hasVGPRIndexMode() const {
511     return HasVGPRIndexMode;
512   }
513 
514   bool hasScalarCompareEq64() const {
515     return getGeneration() >= VOLCANIC_ISLANDS;
516   }
517 
518   bool enableSIScheduler() const {
519     return EnableSIScheduler;
520   }
521 
522   bool debuggerSupported() const {
523     return debuggerInsertNops() && debuggerReserveRegs() &&
524       debuggerEmitPrologue();
525   }
526 
527   bool debuggerInsertNops() const {
528     return DebuggerInsertNops;
529   }
530 
531   bool debuggerReserveRegs() const {
532     return DebuggerReserveRegs;
533   }
534 
535   bool debuggerEmitPrologue() const {
536     return DebuggerEmitPrologue;
537   }
538 
539   bool loadStoreOptEnabled() const {
540     return EnableLoadStoreOpt;
541   }
542 
543   bool hasSGPRInitBug() const {
544     return SGPRInitBug;
545   }
546 
547   unsigned getKernArgSegmentSize(unsigned ExplictArgBytes) const;
548 
549   /// Return the maximum number of waves per SIMD for kernels using \p SGPRs SGPRs
550   unsigned getOccupancyWithNumSGPRs(unsigned SGPRs) const;
551 
552   /// Return the maximum number of waves per SIMD for kernels using \p VGPRs VGPRs
553   unsigned getOccupancyWithNumVGPRs(unsigned VGPRs) const;
554 
555   /// \returns True if waitcnt instruction is needed before barrier instruction,
556   /// false otherwise.
557   bool needWaitcntBeforeBarrier() const {
558     return true;
559   }
560 };
561 
562 } // End namespace llvm
563 
564 #endif
565