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