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
24namespace clang {
25namespace targets {
26
27// Used by both the SPIR and SPIR-V targets.
28static 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.
56static 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.
89class LLVM_LIBRARY_VISIBILITY BaseSPIRTargetInfo : public TargetInfo {
90  std::unique_ptr<TargetInfo> HostTarget;
91
92protected:
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 = HostTarget->getMinGlobalAlign(/* TypeSize = */ 0);
129      NewAlign = HostTarget->getNewAlign();
130      DefaultAlignForAttributeAligned =
131          HostTarget->getDefaultAlignForAttributeAligned();
132      IntMaxType = HostTarget->getIntMaxType();
133      WCharType = HostTarget->getWCharType();
134      WIntType = HostTarget->getWIntType();
135      Char16Type = HostTarget->getChar16Type();
136      Char32Type = HostTarget->getChar32Type();
137      Int64Type = HostTarget->getInt64Type();
138      SigAtomicType = HostTarget->getSigAtomicType();
139      ProcessIDType = HostTarget->getProcessIDType();
140
141      UseBitFieldTypeAlignment = HostTarget->useBitFieldTypeAlignment();
142      UseZeroLengthBitfieldAlignment =
143          HostTarget->useZeroLengthBitfieldAlignment();
144      UseExplicitBitFieldAlignment = HostTarget->useExplicitBitFieldAlignment();
145      ZeroLengthBitfieldBoundary = HostTarget->getZeroLengthBitfieldBoundary();
146
147      // This is a bit of a lie, but it controls __GCC_ATOMIC_XXX_LOCK_FREE, and
148      // we need those macros to be identical on host and device, because (among
149      // other things) they affect which standard library classes are defined,
150      // and we need all classes to be defined on both the host and device.
151      MaxAtomicInlineWidth = HostTarget->getMaxAtomicInlineWidth();
152    }
153  }
154
155public:
156  // SPIR supports the half type and the only llvm intrinsic allowed in SPIR is
157  // memcpy as per section 3 of the SPIR spec.
158  bool useFP16ConversionIntrinsics() const override { return false; }
159
160  ArrayRef<Builtin::Info> getTargetBuiltins() const override {
161    return std::nullopt;
162  }
163
164  std::string_view getClobbers() const override { return ""; }
165
166  ArrayRef<const char *> getGCCRegNames() const override {
167    return std::nullopt;
168  }
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 std::nullopt;
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
229class LLVM_LIBRARY_VISIBILITY SPIRTargetInfo : public BaseSPIRTargetInfo {
230public:
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
250class LLVM_LIBRARY_VISIBILITY SPIR32TargetInfo : public SPIRTargetInfo {
251public:
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");
261  }
262
263  void getTargetDefines(const LangOptions &Opts,
264                        MacroBuilder &Builder) const override;
265};
266
267class LLVM_LIBRARY_VISIBILITY SPIR64TargetInfo : public SPIRTargetInfo {
268public:
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");
278  }
279
280  void getTargetDefines(const LangOptions &Opts,
281                        MacroBuilder &Builder) const override;
282};
283
284class LLVM_LIBRARY_VISIBILITY BaseSPIRVTargetInfo : public BaseSPIRTargetInfo {
285public:
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
299class LLVM_LIBRARY_VISIBILITY SPIRVTargetInfo : public BaseSPIRVTargetInfo {
300public:
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
312    // SPIR-V IDs are represented with a single 32-bit word.
313    SizeType = TargetInfo::UnsignedInt;
314    resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-"
315                    "v96:128-v192:256-v256:256-v512:512-v1024:1024");
316  }
317
318  void getTargetDefines(const LangOptions &Opts,
319                        MacroBuilder &Builder) const override;
320};
321
322class LLVM_LIBRARY_VISIBILITY SPIRV32TargetInfo : public BaseSPIRVTargetInfo {
323public:
324  SPIRV32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
325      : BaseSPIRVTargetInfo(Triple, Opts) {
326    assert(Triple.getArch() == llvm::Triple::spirv32 &&
327           "Invalid architecture for 32-bit SPIR-V.");
328    assert(getTriple().getOS() == llvm::Triple::UnknownOS &&
329           "32-bit SPIR-V target must use unknown OS");
330    assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment &&
331           "32-bit SPIR-V target must use unknown environment type");
332    PointerWidth = PointerAlign = 32;
333    SizeType = TargetInfo::UnsignedInt;
334    PtrDiffType = IntPtrType = TargetInfo::SignedInt;
335    resetDataLayout("e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-"
336                    "v96:128-v192:256-v256:256-v512:512-v1024:1024");
337  }
338
339  void getTargetDefines(const LangOptions &Opts,
340                        MacroBuilder &Builder) const override;
341};
342
343class LLVM_LIBRARY_VISIBILITY SPIRV64TargetInfo : public BaseSPIRVTargetInfo {
344public:
345  SPIRV64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
346      : BaseSPIRVTargetInfo(Triple, Opts) {
347    assert(Triple.getArch() == llvm::Triple::spirv64 &&
348           "Invalid architecture for 64-bit SPIR-V.");
349    assert(getTriple().getOS() == llvm::Triple::UnknownOS &&
350           "64-bit SPIR-V target must use unknown OS");
351    assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment &&
352           "64-bit SPIR-V target must use unknown environment type");
353    PointerWidth = PointerAlign = 64;
354    SizeType = TargetInfo::UnsignedLong;
355    PtrDiffType = IntPtrType = TargetInfo::SignedLong;
356    resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-"
357                    "v96:128-v192:256-v256:256-v512:512-v1024:1024");
358  }
359
360  void getTargetDefines(const LangOptions &Opts,
361                        MacroBuilder &Builder) const override;
362};
363
364} // namespace targets
365} // namespace clang
366#endif // LLVM_CLANG_LIB_BASIC_TARGETS_SPIR_H
367