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