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 "clang/Basic/TargetInfo.h"
17 #include "clang/Basic/TargetOptions.h"
18 #include "llvm/ADT/Triple.h"
19 #include "llvm/Support/Compiler.h"
20 #include <optional>
21 
22 namespace clang {
23 namespace targets {
24 
25 // Used by both the SPIR and SPIR-V targets.
26 static const unsigned SPIRDefIsPrivMap[] = {
27     0, // Default
28     1, // opencl_global
29     3, // opencl_local
30     2, // opencl_constant
31     0, // opencl_private
32     4, // opencl_generic
33     5, // opencl_global_device
34     6, // opencl_global_host
35     0, // cuda_device
36     0, // cuda_constant
37     0, // cuda_shared
38     // SYCL address space values for this map are dummy
39     0, // sycl_global
40     0, // sycl_global_device
41     0, // sycl_global_host
42     0, // sycl_local
43     0, // sycl_private
44     0, // ptr32_sptr
45     0, // ptr32_uptr
46     0, // ptr64
47     0, // hlsl_groupshared
48 };
49 
50 // Used by both the SPIR and SPIR-V targets.
51 static const unsigned SPIRDefIsGenMap[] = {
52     4, // Default
53     // OpenCL address space values for this map are dummy and they can't be used
54     0, // opencl_global
55     0, // opencl_local
56     0, // opencl_constant
57     0, // opencl_private
58     0, // opencl_generic
59     0, // opencl_global_device
60     0, // opencl_global_host
61     // cuda_* address space mapping is intended for HIPSPV (HIP to SPIR-V
62     // translation). This mapping is enabled when the language mode is HIP.
63     1, // cuda_device
64     // cuda_constant pointer can be casted to default/"flat" pointer, but in
65     // SPIR-V casts between constant and generic pointers are not allowed. For
66     // this reason cuda_constant is mapped to SPIR-V CrossWorkgroup.
67     1, // cuda_constant
68     3, // cuda_shared
69     1, // sycl_global
70     5, // sycl_global_device
71     6, // sycl_global_host
72     3, // sycl_local
73     0, // sycl_private
74     0, // ptr32_sptr
75     0, // ptr32_uptr
76     0, // ptr64
77     0, // hlsl_groupshared
78 };
79 
80 // Base class for SPIR and SPIR-V target info.
81 class LLVM_LIBRARY_VISIBILITY BaseSPIRTargetInfo : public TargetInfo {
82 protected:
83   BaseSPIRTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
84       : TargetInfo(Triple) {
85     assert((Triple.isSPIR() || Triple.isSPIRV()) &&
86            "Invalid architecture for SPIR or SPIR-V.");
87     assert(getTriple().getOS() == llvm::Triple::UnknownOS &&
88            "SPIR(-V) target must use unknown OS");
89     assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment &&
90            "SPIR(-V) target must use unknown environment type");
91     TLSSupported = false;
92     VLASupported = false;
93     LongWidth = LongAlign = 64;
94     AddrSpaceMap = &SPIRDefIsPrivMap;
95     UseAddrSpaceMapMangling = true;
96     HasLegalHalfType = true;
97     HasFloat16 = true;
98     // Define available target features
99     // These must be defined in sorted order!
100     NoAsmVariants = true;
101   }
102 
103 public:
104   // SPIR supports the half type and the only llvm intrinsic allowed in SPIR is
105   // memcpy as per section 3 of the SPIR spec.
106   bool useFP16ConversionIntrinsics() const override { return false; }
107 
108   ArrayRef<Builtin::Info> getTargetBuiltins() const override {
109     return std::nullopt;
110   }
111 
112   const char *getClobbers() const override { return ""; }
113 
114   ArrayRef<const char *> getGCCRegNames() const override {
115     return std::nullopt;
116   }
117 
118   bool validateAsmConstraint(const char *&Name,
119                              TargetInfo::ConstraintInfo &info) const override {
120     return true;
121   }
122 
123   ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
124     return std::nullopt;
125   }
126 
127   BuiltinVaListKind getBuiltinVaListKind() const override {
128     return TargetInfo::VoidPtrBuiltinVaList;
129   }
130 
131   std::optional<unsigned>
132   getDWARFAddressSpace(unsigned AddressSpace) const override {
133     return AddressSpace;
134   }
135 
136   CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
137     return (CC == CC_SpirFunction || CC == CC_OpenCLKernel) ? CCCR_OK
138                                                             : CCCR_Warning;
139   }
140 
141   CallingConv getDefaultCallingConv() const override {
142     return CC_SpirFunction;
143   }
144 
145   void setAddressSpaceMap(bool DefaultIsGeneric) {
146     AddrSpaceMap = DefaultIsGeneric ? &SPIRDefIsGenMap : &SPIRDefIsPrivMap;
147   }
148 
149   void adjust(DiagnosticsEngine &Diags, LangOptions &Opts) override {
150     TargetInfo::adjust(Diags, Opts);
151     // FIXME: SYCL specification considers unannotated pointers and references
152     // to be pointing to the generic address space. See section 5.9.3 of
153     // SYCL 2020 specification.
154     // Currently, there is no way of representing SYCL's and HIP/CUDA's default
155     // address space language semantic along with the semantics of embedded C's
156     // default address space in the same address space map. Hence the map needs
157     // to be reset to allow mapping to the desired value of 'Default' entry for
158     // SYCL and HIP/CUDA.
159     setAddressSpaceMap(
160         /*DefaultIsGeneric=*/Opts.SYCLIsDevice ||
161         // The address mapping from HIP/CUDA language for device code is only
162         // defined for SPIR-V.
163         (getTriple().isSPIRV() && Opts.CUDAIsDevice));
164   }
165 
166   void setSupportedOpenCLOpts() override {
167     // Assume all OpenCL extensions and optional core features are supported
168     // for SPIR and SPIR-V since they are generic targets.
169     supportAllOpenCLOpts();
170   }
171 
172   bool hasBitIntType() const override { return true; }
173 
174   bool hasInt128Type() const override { return false; }
175 };
176 
177 class LLVM_LIBRARY_VISIBILITY SPIRTargetInfo : public BaseSPIRTargetInfo {
178 public:
179   SPIRTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
180       : BaseSPIRTargetInfo(Triple, Opts) {
181     assert(Triple.isSPIR() && "Invalid architecture for SPIR.");
182     assert(getTriple().getOS() == llvm::Triple::UnknownOS &&
183            "SPIR target must use unknown OS");
184     assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment &&
185            "SPIR target must use unknown environment type");
186   }
187 
188   void getTargetDefines(const LangOptions &Opts,
189                         MacroBuilder &Builder) const override;
190 
191   bool hasFeature(StringRef Feature) const override {
192     return Feature == "spir";
193   }
194 };
195 
196 class LLVM_LIBRARY_VISIBILITY SPIR32TargetInfo : public SPIRTargetInfo {
197 public:
198   SPIR32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
199       : SPIRTargetInfo(Triple, Opts) {
200     assert(Triple.getArch() == llvm::Triple::spir &&
201            "Invalid architecture for 32-bit SPIR.");
202     PointerWidth = PointerAlign = 32;
203     SizeType = TargetInfo::UnsignedInt;
204     PtrDiffType = IntPtrType = TargetInfo::SignedInt;
205     resetDataLayout("e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-"
206                     "v96:128-v192:256-v256:256-v512:512-v1024:1024");
207   }
208 
209   void getTargetDefines(const LangOptions &Opts,
210                         MacroBuilder &Builder) const override;
211 };
212 
213 class LLVM_LIBRARY_VISIBILITY SPIR64TargetInfo : public SPIRTargetInfo {
214 public:
215   SPIR64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
216       : SPIRTargetInfo(Triple, Opts) {
217     assert(Triple.getArch() == llvm::Triple::spir64 &&
218            "Invalid architecture for 64-bit SPIR.");
219     PointerWidth = PointerAlign = 64;
220     SizeType = TargetInfo::UnsignedLong;
221     PtrDiffType = IntPtrType = TargetInfo::SignedLong;
222     resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-"
223                     "v96:128-v192:256-v256:256-v512:512-v1024:1024");
224   }
225 
226   void getTargetDefines(const LangOptions &Opts,
227                         MacroBuilder &Builder) const override;
228 };
229 
230 class LLVM_LIBRARY_VISIBILITY SPIRVTargetInfo : public BaseSPIRTargetInfo {
231 public:
232   SPIRVTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
233       : BaseSPIRTargetInfo(Triple, Opts) {
234     assert(Triple.isSPIRV() && "Invalid architecture for SPIR-V.");
235     assert(getTriple().getOS() == llvm::Triple::UnknownOS &&
236            "SPIR-V target must use unknown OS");
237     assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment &&
238            "SPIR-V target must use unknown environment type");
239   }
240 
241   void getTargetDefines(const LangOptions &Opts,
242                         MacroBuilder &Builder) const override;
243 
244   bool hasFeature(StringRef Feature) const override {
245     return Feature == "spirv";
246   }
247 };
248 
249 class LLVM_LIBRARY_VISIBILITY SPIRV32TargetInfo : public SPIRVTargetInfo {
250 public:
251   SPIRV32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
252       : SPIRVTargetInfo(Triple, Opts) {
253     assert(Triple.getArch() == llvm::Triple::spirv32 &&
254            "Invalid architecture for 32-bit SPIR-V.");
255     PointerWidth = PointerAlign = 32;
256     SizeType = TargetInfo::UnsignedInt;
257     PtrDiffType = IntPtrType = TargetInfo::SignedInt;
258     resetDataLayout("e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-"
259                     "v96:128-v192:256-v256:256-v512:512-v1024:1024");
260   }
261 
262   void getTargetDefines(const LangOptions &Opts,
263                         MacroBuilder &Builder) const override;
264 };
265 
266 class LLVM_LIBRARY_VISIBILITY SPIRV64TargetInfo : public SPIRVTargetInfo {
267 public:
268   SPIRV64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
269       : SPIRVTargetInfo(Triple, Opts) {
270     assert(Triple.getArch() == llvm::Triple::spirv64 &&
271            "Invalid architecture for 64-bit SPIR-V.");
272     PointerWidth = PointerAlign = 64;
273     SizeType = TargetInfo::UnsignedLong;
274     PtrDiffType = IntPtrType = TargetInfo::SignedLong;
275     resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-"
276                     "v96:128-v192:256-v256:256-v512:512-v1024:1024");
277   }
278 
279   void getTargetDefines(const LangOptions &Opts,
280                         MacroBuilder &Builder) const override;
281 };
282 
283 } // namespace targets
284 } // namespace clang
285 #endif // LLVM_CLANG_LIB_BASIC_TARGETS_SPIR_H
286