1 //===--- AMDGPU.h - Declare AMDGPU target feature support -------*- 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 // This file declares AMDGPU TargetInfo objects.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_CLANG_LIB_BASIC_TARGETS_AMDGPU_H
15 #define LLVM_CLANG_LIB_BASIC_TARGETS_AMDGPU_H
16 
17 #include "clang/AST/Type.h"
18 #include "clang/Basic/TargetInfo.h"
19 #include "clang/Basic/TargetOptions.h"
20 #include "llvm/ADT/StringSet.h"
21 #include "llvm/ADT/Triple.h"
22 #include "llvm/Support/Compiler.h"
23 
24 namespace clang {
25 namespace targets {
26 
27 class LLVM_LIBRARY_VISIBILITY AMDGPUTargetInfo final : public TargetInfo {
28 
29   static const Builtin::Info BuiltinInfo[];
30   static const char *const GCCRegNames[];
31 
32   struct LLVM_LIBRARY_VISIBILITY AddrSpace {
33     unsigned Generic, Global, Local, Constant, Private;
34     AddrSpace(bool IsGenericZero_ = false) {
35       if (IsGenericZero_) {
36         Generic = 0;
37         Global = 1;
38         Local = 3;
39         Constant = 2;
40         Private = 5;
41       } else {
42         Generic = 4;
43         Global = 1;
44         Local = 3;
45         Constant = 2;
46         Private = 0;
47       }
48     }
49   };
50 
51   /// \brief The GPU profiles supported by the AMDGPU target.
52   enum GPUKind {
53     GK_NONE,
54     GK_R600,
55     GK_R600_DOUBLE_OPS,
56     GK_R700,
57     GK_R700_DOUBLE_OPS,
58     GK_EVERGREEN,
59     GK_EVERGREEN_DOUBLE_OPS,
60     GK_NORTHERN_ISLANDS,
61     GK_CAYMAN,
62     GK_GFX6,
63     GK_GFX7,
64     GK_GFX8,
65     GK_GFX9
66   } GPU;
67 
68   bool hasFP64 : 1;
69   bool hasFMAF : 1;
70   bool hasLDEXPF : 1;
71   const AddrSpace AS;
72 
73   static bool hasFullSpeedFMAF32(StringRef GPUName) {
74     return parseAMDGCNName(GPUName) >= GK_GFX9;
75   }
76 
77   static bool isAMDGCN(const llvm::Triple &TT) {
78     return TT.getArch() == llvm::Triple::amdgcn;
79   }
80 
81   static bool isGenericZero(const llvm::Triple &TT) {
82     return TT.getEnvironmentName() == "amdgiz" ||
83            TT.getEnvironmentName() == "amdgizcl";
84   }
85 
86 public:
87   AMDGPUTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts);
88 
89   void setAddressSpaceMap(bool DefaultIsPrivate);
90 
91   void adjust(LangOptions &Opts) override;
92 
93   uint64_t getPointerWidthV(unsigned AddrSpace) const override {
94     if (GPU <= GK_CAYMAN)
95       return 32;
96 
97     if (AddrSpace == AS.Private || AddrSpace == AS.Local) {
98       return 32;
99     }
100     return 64;
101   }
102 
103   uint64_t getPointerAlignV(unsigned AddrSpace) const override {
104     return getPointerWidthV(AddrSpace);
105   }
106 
107   uint64_t getMaxPointerWidth() const override {
108     return getTriple().getArch() == llvm::Triple::amdgcn ? 64 : 32;
109   }
110 
111   const char *getClobbers() const override { return ""; }
112 
113   ArrayRef<const char *> getGCCRegNames() const override;
114 
115   ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
116     return None;
117   }
118 
119   /// Accepted register names: (n, m is unsigned integer, n < m)
120   /// v
121   /// s
122   /// {vn}, {v[n]}
123   /// {sn}, {s[n]}
124   /// {S} , where S is a special register name
125   ////{v[n:m]}
126   /// {s[n:m]}
127   bool validateAsmConstraint(const char *&Name,
128                              TargetInfo::ConstraintInfo &Info) const override {
129     static const ::llvm::StringSet<> SpecialRegs({
130         "exec", "vcc", "flat_scratch", "m0", "scc", "tba", "tma",
131         "flat_scratch_lo", "flat_scratch_hi", "vcc_lo", "vcc_hi", "exec_lo",
132         "exec_hi", "tma_lo", "tma_hi", "tba_lo", "tba_hi",
133     });
134 
135     StringRef S(Name);
136     bool HasLeftParen = false;
137     if (S.front() == '{') {
138       HasLeftParen = true;
139       S = S.drop_front();
140     }
141     if (S.empty())
142       return false;
143     if (S.front() != 'v' && S.front() != 's') {
144       if (!HasLeftParen)
145         return false;
146       auto E = S.find('}');
147       if (!SpecialRegs.count(S.substr(0, E)))
148         return false;
149       S = S.drop_front(E + 1);
150       if (!S.empty())
151         return false;
152       // Found {S} where S is a special register.
153       Info.setAllowsRegister();
154       Name = S.data() - 1;
155       return true;
156     }
157     S = S.drop_front();
158     if (!HasLeftParen) {
159       if (!S.empty())
160         return false;
161       // Found s or v.
162       Info.setAllowsRegister();
163       Name = S.data() - 1;
164       return true;
165     }
166     bool HasLeftBracket = false;
167     if (!S.empty() && S.front() == '[') {
168       HasLeftBracket = true;
169       S = S.drop_front();
170     }
171     unsigned long long N;
172     if (S.empty() || consumeUnsignedInteger(S, 10, N))
173       return false;
174     if (!S.empty() && S.front() == ':') {
175       if (!HasLeftBracket)
176         return false;
177       S = S.drop_front();
178       unsigned long long M;
179       if (consumeUnsignedInteger(S, 10, M) || N >= M)
180         return false;
181     }
182     if (HasLeftBracket) {
183       if (S.empty() || S.front() != ']')
184         return false;
185       S = S.drop_front();
186     }
187     if (S.empty() || S.front() != '}')
188       return false;
189     S = S.drop_front();
190     if (!S.empty())
191       return false;
192     // Found {vn}, {sn}, {v[n]}, {s[n]}, {v[n:m]}, or {s[n:m]}.
193     Info.setAllowsRegister();
194     Name = S.data() - 1;
195     return true;
196   }
197 
198   bool
199   initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
200                  StringRef CPU,
201                  const std::vector<std::string> &FeatureVec) const override;
202 
203   void adjustTargetOptions(const CodeGenOptions &CGOpts,
204                            TargetOptions &TargetOpts) const override;
205 
206   ArrayRef<Builtin::Info> getTargetBuiltins() const override;
207 
208   void getTargetDefines(const LangOptions &Opts,
209                         MacroBuilder &Builder) const override;
210 
211   BuiltinVaListKind getBuiltinVaListKind() const override {
212     return TargetInfo::CharPtrBuiltinVaList;
213   }
214 
215   static GPUKind parseR600Name(StringRef Name);
216 
217   static GPUKind parseAMDGCNName(StringRef Name);
218 
219   bool isValidCPUName(StringRef Name) const override {
220     if (getTriple().getArch() == llvm::Triple::amdgcn)
221       return GK_NONE != parseAMDGCNName(Name);
222     else
223       return GK_NONE != parseR600Name(Name);
224   }
225 
226   bool setCPU(const std::string &Name) override {
227     if (getTriple().getArch() == llvm::Triple::amdgcn)
228       GPU = parseAMDGCNName(Name);
229     else
230       GPU = parseR600Name(Name);
231 
232     return GPU != GK_NONE;
233   }
234 
235   void setSupportedOpenCLOpts() override {
236     auto &Opts = getSupportedOpenCLOpts();
237     Opts.support("cl_clang_storage_class_specifiers");
238     Opts.support("cl_khr_icd");
239 
240     if (hasFP64)
241       Opts.support("cl_khr_fp64");
242     if (GPU >= GK_EVERGREEN) {
243       Opts.support("cl_khr_byte_addressable_store");
244       Opts.support("cl_khr_global_int32_base_atomics");
245       Opts.support("cl_khr_global_int32_extended_atomics");
246       Opts.support("cl_khr_local_int32_base_atomics");
247       Opts.support("cl_khr_local_int32_extended_atomics");
248     }
249     if (GPU >= GK_GFX6) {
250       Opts.support("cl_khr_fp16");
251       Opts.support("cl_khr_int64_base_atomics");
252       Opts.support("cl_khr_int64_extended_atomics");
253       Opts.support("cl_khr_mipmap_image");
254       Opts.support("cl_khr_subgroups");
255       Opts.support("cl_khr_3d_image_writes");
256       Opts.support("cl_amd_media_ops");
257       Opts.support("cl_amd_media_ops2");
258     }
259   }
260 
261   LangAS getOpenCLTypeAddrSpace(const Type *T) const override {
262     auto BT = dyn_cast<BuiltinType>(T);
263 
264     if (!BT)
265       return TargetInfo::getOpenCLTypeAddrSpace(T);
266 
267     switch (BT->getKind()) {
268 #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix)                   \
269   case BuiltinType::Id:                                                        \
270     return LangAS::opencl_constant;
271 #include "clang/Basic/OpenCLImageTypes.def"
272     case BuiltinType::OCLClkEvent:
273     case BuiltinType::OCLQueue:
274     case BuiltinType::OCLReserveID:
275       return LangAS::opencl_global;
276 
277     default:
278       return TargetInfo::getOpenCLTypeAddrSpace(T);
279     }
280   }
281 
282   llvm::Optional<LangAS> getConstantAddressSpace() const override {
283     return getLangASFromTargetAS(AS.Constant);
284   }
285 
286   /// \returns Target specific vtbl ptr address space.
287   unsigned getVtblPtrAddressSpace() const override { return AS.Constant; }
288 
289   /// \returns If a target requires an address within a target specific address
290   /// space \p AddressSpace to be converted in order to be used, then return the
291   /// corresponding target specific DWARF address space.
292   ///
293   /// \returns Otherwise return None and no conversion will be emitted in the
294   /// DWARF.
295   Optional<unsigned>
296   getDWARFAddressSpace(unsigned AddressSpace) const override {
297     const unsigned DWARF_Private = 1;
298     const unsigned DWARF_Local = 2;
299     if (AddressSpace == AS.Private) {
300       return DWARF_Private;
301     } else if (AddressSpace == AS.Local) {
302       return DWARF_Local;
303     } else {
304       return None;
305     }
306   }
307 
308   CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
309     switch (CC) {
310     default:
311       return CCCR_Warning;
312     case CC_C:
313     case CC_OpenCLKernel:
314       return CCCR_OK;
315     }
316   }
317 
318   // In amdgcn target the null pointer in global, constant, and generic
319   // address space has value 0 but in private and local address space has
320   // value ~0.
321   uint64_t getNullPointerValue(LangAS AS) const override {
322     return AS == LangAS::opencl_local ? ~0 : 0;
323   }
324 };
325 
326 } // namespace targets
327 } // namespace clang
328 
329 #endif // LLVM_CLANG_LIB_BASIC_TARGETS_AMDGPU_H
330