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(Triple: 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 = */ Size: 0,
130 /* HasNonWeakDef = */ 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
157public:
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
231class LLVM_LIBRARY_VISIBILITY SPIRTargetInfo : public BaseSPIRTargetInfo {
232public:
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
252class LLVM_LIBRARY_VISIBILITY SPIR32TargetInfo : public SPIRTargetInfo {
253public:
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(DL: "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
269class LLVM_LIBRARY_VISIBILITY SPIR64TargetInfo : public SPIRTargetInfo {
270public:
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(DL: "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
286class LLVM_LIBRARY_VISIBILITY BaseSPIRVTargetInfo : public BaseSPIRTargetInfo {
287public:
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
301class LLVM_LIBRARY_VISIBILITY SPIRVTargetInfo : public BaseSPIRVTargetInfo {
302public:
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(DL: "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
325class LLVM_LIBRARY_VISIBILITY SPIRV32TargetInfo : public BaseSPIRVTargetInfo {
326public:
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(DL: "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
346class LLVM_LIBRARY_VISIBILITY SPIRV64TargetInfo : public BaseSPIRVTargetInfo {
347public:
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(DL: "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
367class LLVM_LIBRARY_VISIBILITY SPIRV64AMDGCNTargetInfo final
368 : public BaseSPIRVTargetInfo {
369public:
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(DL: "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