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