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