1 //===--- AMDGPU.h - Declare AMDGPU target feature support -------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file declares AMDGPU TargetInfo objects.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_CLANG_LIB_BASIC_TARGETS_AMDGPU_H
14 #define LLVM_CLANG_LIB_BASIC_TARGETS_AMDGPU_H
15 
16 #include "clang/Basic/TargetID.h"
17 #include "clang/Basic/TargetInfo.h"
18 #include "clang/Basic/TargetOptions.h"
19 #include "llvm/ADT/StringSet.h"
20 #include "llvm/ADT/Triple.h"
21 #include "llvm/Support/Compiler.h"
22 #include "llvm/Support/TargetParser.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   enum AddrSpace {
33     Generic = 0,
34     Global = 1,
35     Local = 3,
36     Constant = 4,
37     Private = 5
38   };
39   static const LangASMap AMDGPUDefIsGenMap;
40   static const LangASMap AMDGPUDefIsPrivMap;
41 
42   llvm::AMDGPU::GPUKind GPUKind;
43   unsigned GPUFeatures;
44 
45   /// Target ID is device name followed by optional feature name postfixed
46   /// by plus or minus sign delimitted by colon, e.g. gfx908:xnack+:sram-ecc-.
47   /// If the target ID contains feature+, map it to true.
48   /// If the target ID contains feature-, map it to false.
49   /// If the target ID does not contain a feature (default), do not map it.
50   llvm::StringMap<bool> OffloadArchFeatures;
51   std::string TargetID;
52 
53   bool hasFP64() const {
54     return getTriple().getArch() == llvm::Triple::amdgcn ||
55            !!(GPUFeatures & llvm::AMDGPU::FEATURE_FP64);
56   }
57 
58   /// Has fast fma f32
59   bool hasFastFMAF() const {
60     return !!(GPUFeatures & llvm::AMDGPU::FEATURE_FAST_FMA_F32);
61   }
62 
63   /// Has fast fma f64
64   bool hasFastFMA() const {
65     return getTriple().getArch() == llvm::Triple::amdgcn;
66   }
67 
68   bool hasFMAF() const {
69     return getTriple().getArch() == llvm::Triple::amdgcn ||
70            !!(GPUFeatures & llvm::AMDGPU::FEATURE_FMA);
71   }
72 
73   bool hasFullRateDenormalsF32() const {
74     return !!(GPUFeatures & llvm::AMDGPU::FEATURE_FAST_DENORMAL_F32);
75   }
76 
77   bool hasLDEXPF() const {
78     return getTriple().getArch() == llvm::Triple::amdgcn ||
79            !!(GPUFeatures & llvm::AMDGPU::FEATURE_LDEXP);
80   }
81 
82   static bool isAMDGCN(const llvm::Triple &TT) {
83     return TT.getArch() == llvm::Triple::amdgcn;
84   }
85 
86   static bool isR600(const llvm::Triple &TT) {
87     return TT.getArch() == llvm::Triple::r600;
88   }
89 
90 public:
91   AMDGPUTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts);
92 
93   void setAddressSpaceMap(bool DefaultIsPrivate);
94 
95   void adjust(LangOptions &Opts) override;
96 
97   uint64_t getPointerWidthV(unsigned AddrSpace) const override {
98     if (isR600(getTriple()))
99       return 32;
100 
101     if (AddrSpace == Private || AddrSpace == Local)
102       return 32;
103 
104     return 64;
105   }
106 
107   uint64_t getPointerAlignV(unsigned AddrSpace) const override {
108     return getPointerWidthV(AddrSpace);
109   }
110 
111   uint64_t getMaxPointerWidth() const override {
112     return getTriple().getArch() == llvm::Triple::amdgcn ? 64 : 32;
113   }
114 
115   const char *getClobbers() const override { return ""; }
116 
117   ArrayRef<const char *> getGCCRegNames() const override;
118 
119   ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
120     return None;
121   }
122 
123   /// Accepted register names: (n, m is unsigned integer, n < m)
124   /// v
125   /// s
126   /// a
127   /// {vn}, {v[n]}
128   /// {sn}, {s[n]}
129   /// {an}, {a[n]}
130   /// {S} , where S is a special register name
131   ////{v[n:m]}
132   /// {s[n:m]}
133   /// {a[n:m]}
134   bool validateAsmConstraint(const char *&Name,
135                              TargetInfo::ConstraintInfo &Info) const override {
136     static const ::llvm::StringSet<> SpecialRegs({
137         "exec", "vcc", "flat_scratch", "m0", "scc", "tba", "tma",
138         "flat_scratch_lo", "flat_scratch_hi", "vcc_lo", "vcc_hi", "exec_lo",
139         "exec_hi", "tma_lo", "tma_hi", "tba_lo", "tba_hi",
140     });
141 
142     switch (*Name) {
143     case 'I':
144       Info.setRequiresImmediate(-16, 64);
145       return true;
146     case 'J':
147       Info.setRequiresImmediate(-32768, 32767);
148       return true;
149     case 'A':
150     case 'B':
151     case 'C':
152       Info.setRequiresImmediate();
153       return true;
154     default:
155       break;
156     }
157 
158     StringRef S(Name);
159 
160     if (S == "DA" || S == "DB") {
161       Name++;
162       Info.setRequiresImmediate();
163       return true;
164     }
165 
166     bool HasLeftParen = false;
167     if (S.front() == '{') {
168       HasLeftParen = true;
169       S = S.drop_front();
170     }
171     if (S.empty())
172       return false;
173     if (S.front() != 'v' && S.front() != 's' && S.front() != 'a') {
174       if (!HasLeftParen)
175         return false;
176       auto E = S.find('}');
177       if (!SpecialRegs.count(S.substr(0, E)))
178         return false;
179       S = S.drop_front(E + 1);
180       if (!S.empty())
181         return false;
182       // Found {S} where S is a special register.
183       Info.setAllowsRegister();
184       Name = S.data() - 1;
185       return true;
186     }
187     S = S.drop_front();
188     if (!HasLeftParen) {
189       if (!S.empty())
190         return false;
191       // Found s, v or a.
192       Info.setAllowsRegister();
193       Name = S.data() - 1;
194       return true;
195     }
196     bool HasLeftBracket = false;
197     if (!S.empty() && S.front() == '[') {
198       HasLeftBracket = true;
199       S = S.drop_front();
200     }
201     unsigned long long N;
202     if (S.empty() || consumeUnsignedInteger(S, 10, N))
203       return false;
204     if (!S.empty() && S.front() == ':') {
205       if (!HasLeftBracket)
206         return false;
207       S = S.drop_front();
208       unsigned long long M;
209       if (consumeUnsignedInteger(S, 10, M) || N >= M)
210         return false;
211     }
212     if (HasLeftBracket) {
213       if (S.empty() || S.front() != ']')
214         return false;
215       S = S.drop_front();
216     }
217     if (S.empty() || S.front() != '}')
218       return false;
219     S = S.drop_front();
220     if (!S.empty())
221       return false;
222     // Found {vn}, {sn}, {an}, {v[n]}, {s[n]}, {a[n]}, {v[n:m]}, {s[n:m]}
223     // or {a[n:m]}.
224     Info.setAllowsRegister();
225     Name = S.data() - 1;
226     return true;
227   }
228 
229   // \p Constraint will be left pointing at the last character of
230   // the constraint.  In practice, it won't be changed unless the
231   // constraint is longer than one character.
232   std::string convertConstraint(const char *&Constraint) const override {
233 
234     StringRef S(Constraint);
235     if (S == "DA" || S == "DB") {
236       return std::string("^") + std::string(Constraint++, 2);
237     }
238 
239     const char *Begin = Constraint;
240     TargetInfo::ConstraintInfo Info("", "");
241     if (validateAsmConstraint(Constraint, Info))
242       return std::string(Begin).substr(0, Constraint - Begin + 1);
243 
244     Constraint = Begin;
245     return std::string(1, *Constraint);
246   }
247 
248   bool
249   initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
250                  StringRef CPU,
251                  const std::vector<std::string> &FeatureVec) const override;
252 
253   ArrayRef<Builtin::Info> getTargetBuiltins() const override;
254 
255   bool useFP16ConversionIntrinsics() const override { return false; }
256 
257   void getTargetDefines(const LangOptions &Opts,
258                         MacroBuilder &Builder) const override;
259 
260   BuiltinVaListKind getBuiltinVaListKind() const override {
261     return TargetInfo::CharPtrBuiltinVaList;
262   }
263 
264   bool isValidCPUName(StringRef Name) const override {
265     if (getTriple().getArch() == llvm::Triple::amdgcn)
266       return llvm::AMDGPU::parseArchAMDGCN(Name) != llvm::AMDGPU::GK_NONE;
267     return llvm::AMDGPU::parseArchR600(Name) != llvm::AMDGPU::GK_NONE;
268   }
269 
270   void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override;
271 
272   bool setCPU(const std::string &Name) override {
273     if (getTriple().getArch() == llvm::Triple::amdgcn) {
274       GPUKind = llvm::AMDGPU::parseArchAMDGCN(Name);
275       GPUFeatures = llvm::AMDGPU::getArchAttrAMDGCN(GPUKind);
276     } else {
277       GPUKind = llvm::AMDGPU::parseArchR600(Name);
278       GPUFeatures = llvm::AMDGPU::getArchAttrR600(GPUKind);
279     }
280 
281     return GPUKind != llvm::AMDGPU::GK_NONE;
282   }
283 
284   void setSupportedOpenCLOpts() override {
285     auto &Opts = getSupportedOpenCLOpts();
286     Opts.support("cl_clang_storage_class_specifiers");
287     Opts.support("cl_khr_icd");
288 
289     bool IsAMDGCN = isAMDGCN(getTriple());
290 
291     if (hasFP64())
292       Opts.support("cl_khr_fp64");
293 
294     if (IsAMDGCN || GPUKind >= llvm::AMDGPU::GK_CEDAR) {
295       Opts.support("cl_khr_byte_addressable_store");
296       Opts.support("cl_khr_global_int32_base_atomics");
297       Opts.support("cl_khr_global_int32_extended_atomics");
298       Opts.support("cl_khr_local_int32_base_atomics");
299       Opts.support("cl_khr_local_int32_extended_atomics");
300     }
301 
302     if (IsAMDGCN) {
303       Opts.support("cl_khr_fp16");
304       Opts.support("cl_khr_int64_base_atomics");
305       Opts.support("cl_khr_int64_extended_atomics");
306       Opts.support("cl_khr_mipmap_image");
307       Opts.support("cl_khr_mipmap_image_writes");
308       Opts.support("cl_khr_subgroups");
309       Opts.support("cl_khr_3d_image_writes");
310       Opts.support("cl_amd_media_ops");
311       Opts.support("cl_amd_media_ops2");
312     }
313   }
314 
315   LangAS getOpenCLTypeAddrSpace(OpenCLTypeKind TK) const override {
316     switch (TK) {
317     case OCLTK_Image:
318       return LangAS::opencl_constant;
319 
320     case OCLTK_ClkEvent:
321     case OCLTK_Queue:
322     case OCLTK_ReserveID:
323       return LangAS::opencl_global;
324 
325     default:
326       return TargetInfo::getOpenCLTypeAddrSpace(TK);
327     }
328   }
329 
330   LangAS getOpenCLBuiltinAddressSpace(unsigned AS) const override {
331     switch (AS) {
332     case 0:
333       return LangAS::opencl_generic;
334     case 1:
335       return LangAS::opencl_global;
336     case 3:
337       return LangAS::opencl_local;
338     case 4:
339       return LangAS::opencl_constant;
340     case 5:
341       return LangAS::opencl_private;
342     default:
343       return getLangASFromTargetAS(AS);
344     }
345   }
346 
347   LangAS getCUDABuiltinAddressSpace(unsigned AS) const override {
348     return LangAS::Default;
349   }
350 
351   llvm::Optional<LangAS> getConstantAddressSpace() const override {
352     return getLangASFromTargetAS(Constant);
353   }
354 
355   /// \returns Target specific vtbl ptr address space.
356   unsigned getVtblPtrAddressSpace() const override {
357     return static_cast<unsigned>(Constant);
358   }
359 
360   /// \returns If a target requires an address within a target specific address
361   /// space \p AddressSpace to be converted in order to be used, then return the
362   /// corresponding target specific DWARF address space.
363   ///
364   /// \returns Otherwise return None and no conversion will be emitted in the
365   /// DWARF.
366   Optional<unsigned>
367   getDWARFAddressSpace(unsigned AddressSpace) const override {
368     const unsigned DWARF_Private = 1;
369     const unsigned DWARF_Local = 2;
370     if (AddressSpace == Private) {
371       return DWARF_Private;
372     } else if (AddressSpace == Local) {
373       return DWARF_Local;
374     } else {
375       return None;
376     }
377   }
378 
379   CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
380     switch (CC) {
381     default:
382       return CCCR_Warning;
383     case CC_C:
384     case CC_OpenCLKernel:
385       return CCCR_OK;
386     }
387   }
388 
389   // In amdgcn target the null pointer in global, constant, and generic
390   // address space has value 0 but in private and local address space has
391   // value ~0.
392   uint64_t getNullPointerValue(LangAS AS) const override {
393     // FIXME: Also should handle region.
394     return (AS == LangAS::opencl_local || AS == LangAS::opencl_private)
395       ? ~0 : 0;
396   }
397 
398   void setAuxTarget(const TargetInfo *Aux) override;
399 
400   bool hasExtIntType() const override { return true; }
401 
402   // Record offload arch features since they are needed for defining the
403   // pre-defined macros.
404   bool handleTargetFeatures(std::vector<std::string> &Features,
405                             DiagnosticsEngine &Diags) override {
406     auto TargetIDFeatures =
407         getAllPossibleTargetIDFeatures(getTriple(), getArchNameAMDGCN(GPUKind));
408     llvm::for_each(Features, [&](const auto &F) {
409       assert(F.front() == '+' || F.front() == '-');
410       bool IsOn = F.front() == '+';
411       StringRef Name = StringRef(F).drop_front();
412       if (llvm::find(TargetIDFeatures, Name) == TargetIDFeatures.end())
413         return;
414       assert(OffloadArchFeatures.find(Name) == OffloadArchFeatures.end());
415       OffloadArchFeatures[Name] = IsOn;
416     });
417     return true;
418   }
419 
420   Optional<std::string> getTargetID() const override {
421     if (!isAMDGCN(getTriple()))
422       return llvm::None;
423     // When -target-cpu is not set, we assume generic code that it is valid
424     // for all GPU and use an empty string as target ID to represent that.
425     if (GPUKind == llvm::AMDGPU::GK_NONE)
426       return std::string("");
427     return getCanonicalTargetID(getArchNameAMDGCN(GPUKind),
428                                 OffloadArchFeatures);
429   }
430 };
431 
432 } // namespace targets
433 } // namespace clang
434 
435 #endif // LLVM_CLANG_LIB_BASIC_TARGETS_AMDGPU_H
436