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