xref: /freebsd/contrib/llvm-project/clang/lib/Basic/Targets/SPIR.h (revision b64c5a0ace59af62eff52bfe110a521dc73c937b)
1 //===--- SPIR.h - Declare SPIR and SPIR-V 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 SPIR and SPIR-V TargetInfo objects.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_CLANG_LIB_BASIC_TARGETS_SPIR_H
14 #define LLVM_CLANG_LIB_BASIC_TARGETS_SPIR_H
15 
16 #include "Targets.h"
17 #include "clang/Basic/TargetInfo.h"
18 #include "clang/Basic/TargetOptions.h"
19 #include "llvm/Support/Compiler.h"
20 #include "llvm/Support/VersionTuple.h"
21 #include "llvm/TargetParser/Triple.h"
22 #include <optional>
23 
24 namespace clang {
25 namespace targets {
26 
27 // Used by both the SPIR and SPIR-V targets.
28 static const unsigned SPIRDefIsPrivMap[] = {
29     0, // Default
30     1, // opencl_global
31     3, // opencl_local
32     2, // opencl_constant
33     0, // opencl_private
34     4, // opencl_generic
35     5, // opencl_global_device
36     6, // opencl_global_host
37     0, // cuda_device
38     0, // cuda_constant
39     0, // cuda_shared
40     // SYCL address space values for this map are dummy
41     0, // sycl_global
42     0, // sycl_global_device
43     0, // sycl_global_host
44     0, // sycl_local
45     0, // sycl_private
46     0, // ptr32_sptr
47     0, // ptr32_uptr
48     0, // ptr64
49     0, // hlsl_groupshared
50     // Wasm address space values for this target are dummy values,
51     // as it is only enabled for Wasm targets.
52     20, // wasm_funcref
53 };
54 
55 // Used by both the SPIR and SPIR-V targets.
56 static const unsigned SPIRDefIsGenMap[] = {
57     4, // Default
58     // OpenCL address space values for this map are dummy and they can't be used
59     0, // opencl_global
60     0, // opencl_local
61     0, // opencl_constant
62     0, // opencl_private
63     0, // opencl_generic
64     0, // opencl_global_device
65     0, // opencl_global_host
66     // cuda_* address space mapping is intended for HIPSPV (HIP to SPIR-V
67     // translation). This mapping is enabled when the language mode is HIP.
68     1, // cuda_device
69     // cuda_constant pointer can be casted to default/"flat" pointer, but in
70     // SPIR-V casts between constant and generic pointers are not allowed. For
71     // this reason cuda_constant is mapped to SPIR-V CrossWorkgroup.
72     1, // cuda_constant
73     3, // cuda_shared
74     1, // sycl_global
75     5, // sycl_global_device
76     6, // sycl_global_host
77     3, // sycl_local
78     0, // sycl_private
79     0, // ptr32_sptr
80     0, // ptr32_uptr
81     0, // ptr64
82     0, // hlsl_groupshared
83     // Wasm address space values for this target are dummy values,
84     // as it is only enabled for Wasm targets.
85     20, // wasm_funcref
86 };
87 
88 // Base class for SPIR and SPIR-V target info.
89 class LLVM_LIBRARY_VISIBILITY BaseSPIRTargetInfo : public TargetInfo {
90   std::unique_ptr<TargetInfo> HostTarget;
91 
92 protected:
93   BaseSPIRTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
94       : TargetInfo(Triple) {
95     assert((Triple.isSPIR() || Triple.isSPIRV()) &&
96            "Invalid architecture for SPIR or SPIR-V.");
97     TLSSupported = false;
98     VLASupported = false;
99     LongWidth = LongAlign = 64;
100     AddrSpaceMap = &SPIRDefIsPrivMap;
101     UseAddrSpaceMapMangling = true;
102     HasLegalHalfType = true;
103     HasFloat16 = true;
104     // Define available target features
105     // These must be defined in sorted order!
106     NoAsmVariants = true;
107 
108     llvm::Triple HostTriple(Opts.HostTriple);
109     if (!HostTriple.isSPIR() && !HostTriple.isSPIRV() &&
110         HostTriple.getArch() != llvm::Triple::UnknownArch) {
111       HostTarget = AllocateTarget(llvm::Triple(Opts.HostTriple), Opts);
112 
113       // Copy properties from host target.
114       BoolWidth = HostTarget->getBoolWidth();
115       BoolAlign = HostTarget->getBoolAlign();
116       IntWidth = HostTarget->getIntWidth();
117       IntAlign = HostTarget->getIntAlign();
118       HalfWidth = HostTarget->getHalfWidth();
119       HalfAlign = HostTarget->getHalfAlign();
120       FloatWidth = HostTarget->getFloatWidth();
121       FloatAlign = HostTarget->getFloatAlign();
122       DoubleWidth = HostTarget->getDoubleWidth();
123       DoubleAlign = HostTarget->getDoubleAlign();
124       LongWidth = HostTarget->getLongWidth();
125       LongAlign = HostTarget->getLongAlign();
126       LongLongWidth = HostTarget->getLongLongWidth();
127       LongLongAlign = HostTarget->getLongLongAlign();
128       MinGlobalAlign =
129           HostTarget->getMinGlobalAlign(/* TypeSize = */ 0,
130                                         /* HasNonWeakDef = */ true);
131       NewAlign = HostTarget->getNewAlign();
132       DefaultAlignForAttributeAligned =
133           HostTarget->getDefaultAlignForAttributeAligned();
134       IntMaxType = HostTarget->getIntMaxType();
135       WCharType = HostTarget->getWCharType();
136       WIntType = HostTarget->getWIntType();
137       Char16Type = HostTarget->getChar16Type();
138       Char32Type = HostTarget->getChar32Type();
139       Int64Type = HostTarget->getInt64Type();
140       SigAtomicType = HostTarget->getSigAtomicType();
141       ProcessIDType = HostTarget->getProcessIDType();
142 
143       UseBitFieldTypeAlignment = HostTarget->useBitFieldTypeAlignment();
144       UseZeroLengthBitfieldAlignment =
145           HostTarget->useZeroLengthBitfieldAlignment();
146       UseExplicitBitFieldAlignment = HostTarget->useExplicitBitFieldAlignment();
147       ZeroLengthBitfieldBoundary = HostTarget->getZeroLengthBitfieldBoundary();
148 
149       // This is a bit of a lie, but it controls __GCC_ATOMIC_XXX_LOCK_FREE, and
150       // we need those macros to be identical on host and device, because (among
151       // other things) they affect which standard library classes are defined,
152       // and we need all classes to be defined on both the host and device.
153       MaxAtomicInlineWidth = HostTarget->getMaxAtomicInlineWidth();
154     }
155   }
156 
157 public:
158   // SPIR supports the half type and the only llvm intrinsic allowed in SPIR is
159   // memcpy as per section 3 of the SPIR spec.
160   bool useFP16ConversionIntrinsics() const override { return false; }
161 
162   ArrayRef<Builtin::Info> getTargetBuiltins() const override {
163     return std::nullopt;
164   }
165 
166   std::string_view getClobbers() const override { return ""; }
167 
168   ArrayRef<const char *> getGCCRegNames() const override {
169     return std::nullopt;
170   }
171 
172   bool validateAsmConstraint(const char *&Name,
173                              TargetInfo::ConstraintInfo &info) const override {
174     return true;
175   }
176 
177   ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
178     return std::nullopt;
179   }
180 
181   BuiltinVaListKind getBuiltinVaListKind() const override {
182     return TargetInfo::VoidPtrBuiltinVaList;
183   }
184 
185   std::optional<unsigned>
186   getDWARFAddressSpace(unsigned AddressSpace) const override {
187     return AddressSpace;
188   }
189 
190   CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
191     return (CC == CC_SpirFunction || CC == CC_OpenCLKernel) ? CCCR_OK
192                                                             : CCCR_Warning;
193   }
194 
195   CallingConv getDefaultCallingConv() const override {
196     return CC_SpirFunction;
197   }
198 
199   void setAddressSpaceMap(bool DefaultIsGeneric) {
200     AddrSpaceMap = DefaultIsGeneric ? &SPIRDefIsGenMap : &SPIRDefIsPrivMap;
201   }
202 
203   void adjust(DiagnosticsEngine &Diags, LangOptions &Opts) override {
204     TargetInfo::adjust(Diags, Opts);
205     // FIXME: SYCL specification considers unannotated pointers and references
206     // to be pointing to the generic address space. See section 5.9.3 of
207     // SYCL 2020 specification.
208     // Currently, there is no way of representing SYCL's and HIP/CUDA's default
209     // address space language semantic along with the semantics of embedded C's
210     // default address space in the same address space map. Hence the map needs
211     // to be reset to allow mapping to the desired value of 'Default' entry for
212     // SYCL and HIP/CUDA.
213     setAddressSpaceMap(
214         /*DefaultIsGeneric=*/Opts.SYCLIsDevice ||
215         // The address mapping from HIP/CUDA language for device code is only
216         // defined for SPIR-V.
217         (getTriple().isSPIRV() && Opts.CUDAIsDevice));
218   }
219 
220   void setSupportedOpenCLOpts() override {
221     // Assume all OpenCL extensions and optional core features are supported
222     // for SPIR and SPIR-V since they are generic targets.
223     supportAllOpenCLOpts();
224   }
225 
226   bool hasBitIntType() const override { return true; }
227 
228   bool hasInt128Type() const override { return false; }
229 };
230 
231 class LLVM_LIBRARY_VISIBILITY SPIRTargetInfo : public BaseSPIRTargetInfo {
232 public:
233   SPIRTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
234       : BaseSPIRTargetInfo(Triple, Opts) {
235     assert(Triple.isSPIR() && "Invalid architecture for SPIR.");
236     assert(getTriple().getOS() == llvm::Triple::UnknownOS &&
237            "SPIR target must use unknown OS");
238     assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment &&
239            "SPIR target must use unknown environment type");
240   }
241 
242   void getTargetDefines(const LangOptions &Opts,
243                         MacroBuilder &Builder) const override;
244 
245   bool hasFeature(StringRef Feature) const override {
246     return Feature == "spir";
247   }
248 
249   bool checkArithmeticFenceSupported() const override { return true; }
250 };
251 
252 class LLVM_LIBRARY_VISIBILITY SPIR32TargetInfo : public SPIRTargetInfo {
253 public:
254   SPIR32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
255       : SPIRTargetInfo(Triple, Opts) {
256     assert(Triple.getArch() == llvm::Triple::spir &&
257            "Invalid architecture for 32-bit SPIR.");
258     PointerWidth = PointerAlign = 32;
259     SizeType = TargetInfo::UnsignedInt;
260     PtrDiffType = IntPtrType = TargetInfo::SignedInt;
261     resetDataLayout("e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-"
262                     "v96:128-v192:256-v256:256-v512:512-v1024:1024-G1");
263   }
264 
265   void getTargetDefines(const LangOptions &Opts,
266                         MacroBuilder &Builder) const override;
267 };
268 
269 class LLVM_LIBRARY_VISIBILITY SPIR64TargetInfo : public SPIRTargetInfo {
270 public:
271   SPIR64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
272       : SPIRTargetInfo(Triple, Opts) {
273     assert(Triple.getArch() == llvm::Triple::spir64 &&
274            "Invalid architecture for 64-bit SPIR.");
275     PointerWidth = PointerAlign = 64;
276     SizeType = TargetInfo::UnsignedLong;
277     PtrDiffType = IntPtrType = TargetInfo::SignedLong;
278     resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-"
279                     "v96:128-v192:256-v256:256-v512:512-v1024:1024-G1");
280   }
281 
282   void getTargetDefines(const LangOptions &Opts,
283                         MacroBuilder &Builder) const override;
284 };
285 
286 class LLVM_LIBRARY_VISIBILITY BaseSPIRVTargetInfo : public BaseSPIRTargetInfo {
287 public:
288   BaseSPIRVTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
289       : BaseSPIRTargetInfo(Triple, Opts) {
290     assert(Triple.isSPIRV() && "Invalid architecture for SPIR-V.");
291   }
292 
293   bool hasFeature(StringRef Feature) const override {
294     return Feature == "spirv";
295   }
296 
297   void getTargetDefines(const LangOptions &Opts,
298                         MacroBuilder &Builder) const override;
299 };
300 
301 class LLVM_LIBRARY_VISIBILITY SPIRVTargetInfo : public BaseSPIRVTargetInfo {
302 public:
303   SPIRVTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
304       : BaseSPIRVTargetInfo(Triple, Opts) {
305     assert(Triple.getArch() == llvm::Triple::spirv &&
306            "Invalid architecture for Logical SPIR-V.");
307     assert(Triple.getOS() == llvm::Triple::Vulkan &&
308            Triple.getVulkanVersion() != llvm::VersionTuple(0) &&
309            "Logical SPIR-V requires a valid Vulkan environment.");
310     assert(Triple.getEnvironment() >= llvm::Triple::Pixel &&
311            Triple.getEnvironment() <= llvm::Triple::Amplification &&
312            "Logical SPIR-V environment must be a valid shader stage.");
313     PointerWidth = PointerAlign = 64;
314 
315     // SPIR-V IDs are represented with a single 32-bit word.
316     SizeType = TargetInfo::UnsignedInt;
317     resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-"
318                     "v96:128-v192:256-v256:256-v512:512-v1024:1024-G1");
319   }
320 
321   void getTargetDefines(const LangOptions &Opts,
322                         MacroBuilder &Builder) const override;
323 };
324 
325 class LLVM_LIBRARY_VISIBILITY SPIRV32TargetInfo : public BaseSPIRVTargetInfo {
326 public:
327   SPIRV32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
328       : BaseSPIRVTargetInfo(Triple, Opts) {
329     assert(Triple.getArch() == llvm::Triple::spirv32 &&
330            "Invalid architecture for 32-bit SPIR-V.");
331     assert(getTriple().getOS() == llvm::Triple::UnknownOS &&
332            "32-bit SPIR-V target must use unknown OS");
333     assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment &&
334            "32-bit SPIR-V target must use unknown environment type");
335     PointerWidth = PointerAlign = 32;
336     SizeType = TargetInfo::UnsignedInt;
337     PtrDiffType = IntPtrType = TargetInfo::SignedInt;
338     resetDataLayout("e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-"
339                     "v96:128-v192:256-v256:256-v512:512-v1024:1024-G1");
340   }
341 
342   void getTargetDefines(const LangOptions &Opts,
343                         MacroBuilder &Builder) const override;
344 };
345 
346 class LLVM_LIBRARY_VISIBILITY SPIRV64TargetInfo : public BaseSPIRVTargetInfo {
347 public:
348   SPIRV64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
349       : BaseSPIRVTargetInfo(Triple, Opts) {
350     assert(Triple.getArch() == llvm::Triple::spirv64 &&
351            "Invalid architecture for 64-bit SPIR-V.");
352     assert(getTriple().getOS() == llvm::Triple::UnknownOS &&
353            "64-bit SPIR-V target must use unknown OS");
354     assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment &&
355            "64-bit SPIR-V target must use unknown environment type");
356     PointerWidth = PointerAlign = 64;
357     SizeType = TargetInfo::UnsignedLong;
358     PtrDiffType = IntPtrType = TargetInfo::SignedLong;
359     resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-"
360                     "v96:128-v192:256-v256:256-v512:512-v1024:1024-G1");
361   }
362 
363   void getTargetDefines(const LangOptions &Opts,
364                         MacroBuilder &Builder) const override;
365 };
366 
367 class LLVM_LIBRARY_VISIBILITY SPIRV64AMDGCNTargetInfo final
368     : public BaseSPIRVTargetInfo {
369 public:
370   SPIRV64AMDGCNTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
371       : BaseSPIRVTargetInfo(Triple, Opts) {
372     assert(Triple.getArch() == llvm::Triple::spirv64 &&
373            "Invalid architecture for 64-bit AMDGCN SPIR-V.");
374     assert(Triple.getVendor() == llvm::Triple::VendorType::AMD &&
375            "64-bit AMDGCN SPIR-V target must use AMD vendor");
376     assert(getTriple().getOS() == llvm::Triple::OSType::AMDHSA &&
377            "64-bit AMDGCN SPIR-V target must use AMDHSA OS");
378     assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment &&
379            "64-bit SPIR-V target must use unknown environment type");
380     PointerWidth = PointerAlign = 64;
381     SizeType = TargetInfo::UnsignedLong;
382     PtrDiffType = IntPtrType = TargetInfo::SignedLong;
383 
384     resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-"
385                     "v96:128-v192:256-v256:256-v512:512-v1024:1024-G1-P4-A0");
386 
387     BFloat16Width = BFloat16Align = 16;
388     BFloat16Format = &llvm::APFloat::BFloat();
389 
390     HasLegalHalfType = true;
391     HasFloat16 = true;
392     HalfArgsAndReturns = true;
393   }
394 
395   bool hasBFloat16Type() const override { return true; }
396 
397   ArrayRef<const char *> getGCCRegNames() const override;
398 
399   bool initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
400                       StringRef,
401                       const std::vector<std::string> &) const override;
402 
403   bool validateAsmConstraint(const char *&Name,
404                              TargetInfo::ConstraintInfo &Info) const override;
405 
406   std::string convertConstraint(const char *&Constraint) const override;
407 
408   ArrayRef<Builtin::Info> getTargetBuiltins() const override;
409 
410   void getTargetDefines(const LangOptions &Opts,
411                         MacroBuilder &Builder) const override;
412 
413   void setAuxTarget(const TargetInfo *Aux) override;
414 
415   bool hasInt128Type() const override { return TargetInfo::hasInt128Type(); }
416 };
417 
418 } // namespace targets
419 } // namespace clang
420 #endif // LLVM_CLANG_LIB_BASIC_TARGETS_SPIR_H
421