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

source code of clang/lib/Basic/Targets/SPIR.h