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/TargetParser/Triple.h" 21 #include <optional> 22 23 namespace clang { 24 namespace targets { 25 26 // Used by both the SPIR and SPIR-V targets. 27 static const unsigned SPIRDefIsPrivMap[] = { 28 0, // Default 29 1, // opencl_global 30 3, // opencl_local 31 2, // opencl_constant 32 0, // opencl_private 33 4, // opencl_generic 34 5, // opencl_global_device 35 6, // opencl_global_host 36 0, // cuda_device 37 0, // cuda_constant 38 0, // cuda_shared 39 // SYCL address space values for this map are dummy 40 0, // sycl_global 41 0, // sycl_global_device 42 0, // sycl_global_host 43 0, // sycl_local 44 0, // sycl_private 45 0, // ptr32_sptr 46 0, // ptr32_uptr 47 0, // ptr64 48 0, // hlsl_groupshared 49 // Wasm address space values for this target are dummy values, 50 // as it is only enabled for Wasm targets. 51 20, // wasm_funcref 52 }; 53 54 // Used by both the SPIR and SPIR-V targets. 55 static const unsigned SPIRDefIsGenMap[] = { 56 4, // Default 57 // OpenCL address space values for this map are dummy and they can't be used 58 0, // opencl_global 59 0, // opencl_local 60 0, // opencl_constant 61 0, // opencl_private 62 0, // opencl_generic 63 0, // opencl_global_device 64 0, // opencl_global_host 65 // cuda_* address space mapping is intended for HIPSPV (HIP to SPIR-V 66 // translation). This mapping is enabled when the language mode is HIP. 67 1, // cuda_device 68 // cuda_constant pointer can be casted to default/"flat" pointer, but in 69 // SPIR-V casts between constant and generic pointers are not allowed. For 70 // this reason cuda_constant is mapped to SPIR-V CrossWorkgroup. 71 1, // cuda_constant 72 3, // cuda_shared 73 1, // sycl_global 74 5, // sycl_global_device 75 6, // sycl_global_host 76 3, // sycl_local 77 0, // sycl_private 78 0, // ptr32_sptr 79 0, // ptr32_uptr 80 0, // ptr64 81 0, // hlsl_groupshared 82 // Wasm address space values for this target are dummy values, 83 // as it is only enabled for Wasm targets. 84 20, // wasm_funcref 85 }; 86 87 // Base class for SPIR and SPIR-V target info. 88 class LLVM_LIBRARY_VISIBILITY BaseSPIRTargetInfo : public TargetInfo { 89 std::unique_ptr<TargetInfo> HostTarget; 90 91 protected: 92 BaseSPIRTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) 93 : TargetInfo(Triple) { 94 assert((Triple.isSPIR() || Triple.isSPIRV()) && 95 "Invalid architecture for SPIR or SPIR-V."); 96 assert(getTriple().getOS() == llvm::Triple::UnknownOS && 97 "SPIR(-V) target must use unknown OS"); 98 assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment && 99 "SPIR(-V) target must use unknown environment type"); 100 TLSSupported = false; 101 VLASupported = false; 102 LongWidth = LongAlign = 64; 103 AddrSpaceMap = &SPIRDefIsPrivMap; 104 UseAddrSpaceMapMangling = true; 105 HasLegalHalfType = true; 106 HasFloat16 = true; 107 // Define available target features 108 // These must be defined in sorted order! 109 NoAsmVariants = true; 110 111 llvm::Triple HostTriple(Opts.HostTriple); 112 if (!HostTriple.isSPIR() && !HostTriple.isSPIRV() && 113 HostTriple.getArch() != llvm::Triple::UnknownArch) { 114 HostTarget = AllocateTarget(llvm::Triple(Opts.HostTriple), Opts); 115 116 // Copy properties from host target. 117 BoolWidth = HostTarget->getBoolWidth(); 118 BoolAlign = HostTarget->getBoolAlign(); 119 IntWidth = HostTarget->getIntWidth(); 120 IntAlign = HostTarget->getIntAlign(); 121 HalfWidth = HostTarget->getHalfWidth(); 122 HalfAlign = HostTarget->getHalfAlign(); 123 FloatWidth = HostTarget->getFloatWidth(); 124 FloatAlign = HostTarget->getFloatAlign(); 125 DoubleWidth = HostTarget->getDoubleWidth(); 126 DoubleAlign = HostTarget->getDoubleAlign(); 127 LongWidth = HostTarget->getLongWidth(); 128 LongAlign = HostTarget->getLongAlign(); 129 LongLongWidth = HostTarget->getLongLongWidth(); 130 LongLongAlign = HostTarget->getLongLongAlign(); 131 MinGlobalAlign = HostTarget->getMinGlobalAlign(/* TypeSize = */ 0); 132 NewAlign = HostTarget->getNewAlign(); 133 DefaultAlignForAttributeAligned = 134 HostTarget->getDefaultAlignForAttributeAligned(); 135 IntMaxType = HostTarget->getIntMaxType(); 136 WCharType = HostTarget->getWCharType(); 137 WIntType = HostTarget->getWIntType(); 138 Char16Type = HostTarget->getChar16Type(); 139 Char32Type = HostTarget->getChar32Type(); 140 Int64Type = HostTarget->getInt64Type(); 141 SigAtomicType = HostTarget->getSigAtomicType(); 142 ProcessIDType = HostTarget->getProcessIDType(); 143 144 UseBitFieldTypeAlignment = HostTarget->useBitFieldTypeAlignment(); 145 UseZeroLengthBitfieldAlignment = 146 HostTarget->useZeroLengthBitfieldAlignment(); 147 UseExplicitBitFieldAlignment = HostTarget->useExplicitBitFieldAlignment(); 148 ZeroLengthBitfieldBoundary = HostTarget->getZeroLengthBitfieldBoundary(); 149 150 // This is a bit of a lie, but it controls __GCC_ATOMIC_XXX_LOCK_FREE, and 151 // we need those macros to be identical on host and device, because (among 152 // other things) they affect which standard library classes are defined, 153 // and we need all classes to be defined on both the host and device. 154 MaxAtomicInlineWidth = HostTarget->getMaxAtomicInlineWidth(); 155 } 156 } 157 158 public: 159 // SPIR supports the half type and the only llvm intrinsic allowed in SPIR is 160 // memcpy as per section 3 of the SPIR spec. 161 bool useFP16ConversionIntrinsics() const override { return false; } 162 163 ArrayRef<Builtin::Info> getTargetBuiltins() const override { 164 return std::nullopt; 165 } 166 167 std::string_view getClobbers() const override { return ""; } 168 169 ArrayRef<const char *> getGCCRegNames() const override { 170 return std::nullopt; 171 } 172 173 bool validateAsmConstraint(const char *&Name, 174 TargetInfo::ConstraintInfo &info) const override { 175 return true; 176 } 177 178 ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { 179 return std::nullopt; 180 } 181 182 BuiltinVaListKind getBuiltinVaListKind() const override { 183 return TargetInfo::VoidPtrBuiltinVaList; 184 } 185 186 std::optional<unsigned> 187 getDWARFAddressSpace(unsigned AddressSpace) const override { 188 return AddressSpace; 189 } 190 191 CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { 192 return (CC == CC_SpirFunction || CC == CC_OpenCLKernel) ? CCCR_OK 193 : CCCR_Warning; 194 } 195 196 CallingConv getDefaultCallingConv() const override { 197 return CC_SpirFunction; 198 } 199 200 void setAddressSpaceMap(bool DefaultIsGeneric) { 201 AddrSpaceMap = DefaultIsGeneric ? &SPIRDefIsGenMap : &SPIRDefIsPrivMap; 202 } 203 204 void adjust(DiagnosticsEngine &Diags, LangOptions &Opts) override { 205 TargetInfo::adjust(Diags, Opts); 206 // FIXME: SYCL specification considers unannotated pointers and references 207 // to be pointing to the generic address space. See section 5.9.3 of 208 // SYCL 2020 specification. 209 // Currently, there is no way of representing SYCL's and HIP/CUDA's default 210 // address space language semantic along with the semantics of embedded C's 211 // default address space in the same address space map. Hence the map needs 212 // to be reset to allow mapping to the desired value of 'Default' entry for 213 // SYCL and HIP/CUDA. 214 setAddressSpaceMap( 215 /*DefaultIsGeneric=*/Opts.SYCLIsDevice || 216 // The address mapping from HIP/CUDA language for device code is only 217 // defined for SPIR-V. 218 (getTriple().isSPIRV() && Opts.CUDAIsDevice)); 219 } 220 221 void setSupportedOpenCLOpts() override { 222 // Assume all OpenCL extensions and optional core features are supported 223 // for SPIR and SPIR-V since they are generic targets. 224 supportAllOpenCLOpts(); 225 } 226 227 bool hasBitIntType() const override { return true; } 228 229 bool hasInt128Type() const override { return false; } 230 }; 231 232 class LLVM_LIBRARY_VISIBILITY SPIRTargetInfo : public BaseSPIRTargetInfo { 233 public: 234 SPIRTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) 235 : BaseSPIRTargetInfo(Triple, Opts) { 236 assert(Triple.isSPIR() && "Invalid architecture for SPIR."); 237 assert(getTriple().getOS() == llvm::Triple::UnknownOS && 238 "SPIR target must use unknown OS"); 239 assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment && 240 "SPIR target must use unknown environment type"); 241 } 242 243 void getTargetDefines(const LangOptions &Opts, 244 MacroBuilder &Builder) const override; 245 246 bool hasFeature(StringRef Feature) const override { 247 return Feature == "spir"; 248 } 249 250 bool checkArithmeticFenceSupported() const override { return true; } 251 }; 252 253 class LLVM_LIBRARY_VISIBILITY SPIR32TargetInfo : public SPIRTargetInfo { 254 public: 255 SPIR32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) 256 : SPIRTargetInfo(Triple, Opts) { 257 assert(Triple.getArch() == llvm::Triple::spir && 258 "Invalid architecture for 32-bit SPIR."); 259 PointerWidth = PointerAlign = 32; 260 SizeType = TargetInfo::UnsignedInt; 261 PtrDiffType = IntPtrType = TargetInfo::SignedInt; 262 resetDataLayout("e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-" 263 "v96:128-v192:256-v256:256-v512:512-v1024:1024"); 264 } 265 266 void getTargetDefines(const LangOptions &Opts, 267 MacroBuilder &Builder) const override; 268 }; 269 270 class LLVM_LIBRARY_VISIBILITY SPIR64TargetInfo : public SPIRTargetInfo { 271 public: 272 SPIR64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) 273 : SPIRTargetInfo(Triple, Opts) { 274 assert(Triple.getArch() == llvm::Triple::spir64 && 275 "Invalid architecture for 64-bit SPIR."); 276 PointerWidth = PointerAlign = 64; 277 SizeType = TargetInfo::UnsignedLong; 278 PtrDiffType = IntPtrType = TargetInfo::SignedLong; 279 resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-" 280 "v96:128-v192:256-v256:256-v512:512-v1024:1024"); 281 } 282 283 void getTargetDefines(const LangOptions &Opts, 284 MacroBuilder &Builder) const override; 285 }; 286 287 class LLVM_LIBRARY_VISIBILITY SPIRVTargetInfo : public BaseSPIRTargetInfo { 288 public: 289 SPIRVTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) 290 : BaseSPIRTargetInfo(Triple, Opts) { 291 assert(Triple.isSPIRV() && "Invalid architecture for SPIR-V."); 292 assert(getTriple().getOS() == llvm::Triple::UnknownOS && 293 "SPIR-V target must use unknown OS"); 294 assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment && 295 "SPIR-V target must use unknown environment type"); 296 } 297 298 void getTargetDefines(const LangOptions &Opts, 299 MacroBuilder &Builder) const override; 300 301 bool hasFeature(StringRef Feature) const override { 302 return Feature == "spirv"; 303 } 304 }; 305 306 class LLVM_LIBRARY_VISIBILITY SPIRV32TargetInfo : public SPIRVTargetInfo { 307 public: 308 SPIRV32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) 309 : SPIRVTargetInfo(Triple, Opts) { 310 assert(Triple.getArch() == llvm::Triple::spirv32 && 311 "Invalid architecture for 32-bit SPIR-V."); 312 PointerWidth = PointerAlign = 32; 313 SizeType = TargetInfo::UnsignedInt; 314 PtrDiffType = IntPtrType = TargetInfo::SignedInt; 315 resetDataLayout("e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-" 316 "v96:128-v192:256-v256:256-v512:512-v1024:1024"); 317 } 318 319 void getTargetDefines(const LangOptions &Opts, 320 MacroBuilder &Builder) const override; 321 }; 322 323 class LLVM_LIBRARY_VISIBILITY SPIRV64TargetInfo : public SPIRVTargetInfo { 324 public: 325 SPIRV64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) 326 : SPIRVTargetInfo(Triple, Opts) { 327 assert(Triple.getArch() == llvm::Triple::spirv64 && 328 "Invalid architecture for 64-bit SPIR-V."); 329 PointerWidth = PointerAlign = 64; 330 SizeType = TargetInfo::UnsignedLong; 331 PtrDiffType = IntPtrType = TargetInfo::SignedLong; 332 resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-" 333 "v96:128-v192:256-v256:256-v512:512-v1024:1024"); 334 } 335 336 void getTargetDefines(const LangOptions &Opts, 337 MacroBuilder &Builder) const override; 338 }; 339 340 } // namespace targets 341 } // namespace clang 342 #endif // LLVM_CLANG_LIB_BASIC_TARGETS_SPIR_H 343