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 TLSSupported = false; 97 VLASupported = false; 98 LongWidth = LongAlign = 64; 99 AddrSpaceMap = &SPIRDefIsPrivMap; 100 UseAddrSpaceMapMangling = true; 101 HasLegalHalfType = true; 102 HasFloat16 = true; 103 // Define available target features 104 // These must be defined in sorted order! 105 NoAsmVariants = true; 106 107 llvm::Triple HostTriple(Opts.HostTriple); 108 if (!HostTriple.isSPIR() && !HostTriple.isSPIRV() && 109 HostTriple.getArch() != llvm::Triple::UnknownArch) { 110 HostTarget = AllocateTarget(llvm::Triple(Opts.HostTriple), Opts); 111 112 // Copy properties from host target. 113 BoolWidth = HostTarget->getBoolWidth(); 114 BoolAlign = HostTarget->getBoolAlign(); 115 IntWidth = HostTarget->getIntWidth(); 116 IntAlign = HostTarget->getIntAlign(); 117 HalfWidth = HostTarget->getHalfWidth(); 118 HalfAlign = HostTarget->getHalfAlign(); 119 FloatWidth = HostTarget->getFloatWidth(); 120 FloatAlign = HostTarget->getFloatAlign(); 121 DoubleWidth = HostTarget->getDoubleWidth(); 122 DoubleAlign = HostTarget->getDoubleAlign(); 123 LongWidth = HostTarget->getLongWidth(); 124 LongAlign = HostTarget->getLongAlign(); 125 LongLongWidth = HostTarget->getLongLongWidth(); 126 LongLongAlign = HostTarget->getLongLongAlign(); 127 MinGlobalAlign = HostTarget->getMinGlobalAlign(/* TypeSize = */ 0); 128 NewAlign = HostTarget->getNewAlign(); 129 DefaultAlignForAttributeAligned = 130 HostTarget->getDefaultAlignForAttributeAligned(); 131 IntMaxType = HostTarget->getIntMaxType(); 132 WCharType = HostTarget->getWCharType(); 133 WIntType = HostTarget->getWIntType(); 134 Char16Type = HostTarget->getChar16Type(); 135 Char32Type = HostTarget->getChar32Type(); 136 Int64Type = HostTarget->getInt64Type(); 137 SigAtomicType = HostTarget->getSigAtomicType(); 138 ProcessIDType = HostTarget->getProcessIDType(); 139 140 UseBitFieldTypeAlignment = HostTarget->useBitFieldTypeAlignment(); 141 UseZeroLengthBitfieldAlignment = 142 HostTarget->useZeroLengthBitfieldAlignment(); 143 UseExplicitBitFieldAlignment = HostTarget->useExplicitBitFieldAlignment(); 144 ZeroLengthBitfieldBoundary = HostTarget->getZeroLengthBitfieldBoundary(); 145 146 // This is a bit of a lie, but it controls __GCC_ATOMIC_XXX_LOCK_FREE, and 147 // we need those macros to be identical on host and device, because (among 148 // other things) they affect which standard library classes are defined, 149 // and we need all classes to be defined on both the host and device. 150 MaxAtomicInlineWidth = HostTarget->getMaxAtomicInlineWidth(); 151 } 152 } 153 154 public: 155 // SPIR supports the half type and the only llvm intrinsic allowed in SPIR is 156 // memcpy as per section 3 of the SPIR spec. 157 bool useFP16ConversionIntrinsics() const override { return false; } 158 159 ArrayRef<Builtin::Info> getTargetBuiltins() const override { 160 return std::nullopt; 161 } 162 163 std::string_view getClobbers() const override { return ""; } 164 165 ArrayRef<const char *> getGCCRegNames() const override { 166 return std::nullopt; 167 } 168 169 bool validateAsmConstraint(const char *&Name, 170 TargetInfo::ConstraintInfo &info) const override { 171 return true; 172 } 173 174 ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { 175 return std::nullopt; 176 } 177 178 BuiltinVaListKind getBuiltinVaListKind() const override { 179 return TargetInfo::VoidPtrBuiltinVaList; 180 } 181 182 std::optional<unsigned> 183 getDWARFAddressSpace(unsigned AddressSpace) const override { 184 return AddressSpace; 185 } 186 187 CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { 188 return (CC == CC_SpirFunction || CC == CC_OpenCLKernel) ? CCCR_OK 189 : CCCR_Warning; 190 } 191 192 CallingConv getDefaultCallingConv() const override { 193 return CC_SpirFunction; 194 } 195 196 void setAddressSpaceMap(bool DefaultIsGeneric) { 197 AddrSpaceMap = DefaultIsGeneric ? &SPIRDefIsGenMap : &SPIRDefIsPrivMap; 198 } 199 200 void adjust(DiagnosticsEngine &Diags, LangOptions &Opts) override { 201 TargetInfo::adjust(Diags, Opts); 202 // FIXME: SYCL specification considers unannotated pointers and references 203 // to be pointing to the generic address space. See section 5.9.3 of 204 // SYCL 2020 specification. 205 // Currently, there is no way of representing SYCL's and HIP/CUDA's default 206 // address space language semantic along with the semantics of embedded C's 207 // default address space in the same address space map. Hence the map needs 208 // to be reset to allow mapping to the desired value of 'Default' entry for 209 // SYCL and HIP/CUDA. 210 setAddressSpaceMap( 211 /*DefaultIsGeneric=*/Opts.SYCLIsDevice || 212 // The address mapping from HIP/CUDA language for device code is only 213 // defined for SPIR-V. 214 (getTriple().isSPIRV() && Opts.CUDAIsDevice)); 215 } 216 217 void setSupportedOpenCLOpts() override { 218 // Assume all OpenCL extensions and optional core features are supported 219 // for SPIR and SPIR-V since they are generic targets. 220 supportAllOpenCLOpts(); 221 } 222 223 bool hasBitIntType() const override { return true; } 224 225 bool hasInt128Type() const override { return false; } 226 }; 227 228 class LLVM_LIBRARY_VISIBILITY SPIRTargetInfo : public BaseSPIRTargetInfo { 229 public: 230 SPIRTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) 231 : BaseSPIRTargetInfo(Triple, Opts) { 232 assert(Triple.isSPIR() && "Invalid architecture for SPIR."); 233 assert(getTriple().getOS() == llvm::Triple::UnknownOS && 234 "SPIR target must use unknown OS"); 235 assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment && 236 "SPIR target must use unknown environment type"); 237 } 238 239 void getTargetDefines(const LangOptions &Opts, 240 MacroBuilder &Builder) const override; 241 242 bool hasFeature(StringRef Feature) const override { 243 return Feature == "spir"; 244 } 245 246 bool checkArithmeticFenceSupported() const override { return true; } 247 }; 248 249 class LLVM_LIBRARY_VISIBILITY SPIR32TargetInfo : public SPIRTargetInfo { 250 public: 251 SPIR32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) 252 : SPIRTargetInfo(Triple, Opts) { 253 assert(Triple.getArch() == llvm::Triple::spir && 254 "Invalid architecture for 32-bit SPIR."); 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 SPIR64TargetInfo : public SPIRTargetInfo { 267 public: 268 SPIR64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) 269 : SPIRTargetInfo(Triple, Opts) { 270 assert(Triple.getArch() == llvm::Triple::spir64 && 271 "Invalid architecture for 64-bit SPIR."); 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 class LLVM_LIBRARY_VISIBILITY BaseSPIRVTargetInfo : public BaseSPIRTargetInfo { 284 public: 285 BaseSPIRVTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) 286 : BaseSPIRTargetInfo(Triple, Opts) { 287 assert(Triple.isSPIRV() && "Invalid architecture for SPIR-V."); 288 } 289 290 bool hasFeature(StringRef Feature) const override { 291 return Feature == "spirv"; 292 } 293 294 void getTargetDefines(const LangOptions &Opts, 295 MacroBuilder &Builder) const override; 296 }; 297 298 class LLVM_LIBRARY_VISIBILITY SPIRVTargetInfo : public BaseSPIRVTargetInfo { 299 public: 300 SPIRVTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) 301 : BaseSPIRVTargetInfo(Triple, Opts) { 302 assert(Triple.getArch() == llvm::Triple::spirv && 303 "Invalid architecture for Logical SPIR-V."); 304 assert(Triple.getOS() == llvm::Triple::ShaderModel && 305 "Logical SPIR-V requires a valid ShaderModel."); 306 assert(Triple.getEnvironment() >= llvm::Triple::Pixel && 307 Triple.getEnvironment() <= llvm::Triple::Amplification && 308 "Logical SPIR-V environment must be a valid shader stage."); 309 310 // SPIR-V IDs are represented with a single 32-bit word. 311 SizeType = TargetInfo::UnsignedInt; 312 resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-" 313 "v96:128-v192:256-v256:256-v512:512-v1024:1024"); 314 } 315 316 void getTargetDefines(const LangOptions &Opts, 317 MacroBuilder &Builder) const override; 318 }; 319 320 class LLVM_LIBRARY_VISIBILITY SPIRV32TargetInfo : public BaseSPIRVTargetInfo { 321 public: 322 SPIRV32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) 323 : BaseSPIRVTargetInfo(Triple, Opts) { 324 assert(Triple.getArch() == llvm::Triple::spirv32 && 325 "Invalid architecture for 32-bit SPIR-V."); 326 assert(getTriple().getOS() == llvm::Triple::UnknownOS && 327 "32-bit SPIR-V target must use unknown OS"); 328 assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment && 329 "32-bit SPIR-V target must use unknown environment type"); 330 PointerWidth = PointerAlign = 32; 331 SizeType = TargetInfo::UnsignedInt; 332 PtrDiffType = IntPtrType = TargetInfo::SignedInt; 333 resetDataLayout("e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-" 334 "v96:128-v192:256-v256:256-v512:512-v1024:1024"); 335 } 336 337 void getTargetDefines(const LangOptions &Opts, 338 MacroBuilder &Builder) const override; 339 }; 340 341 class LLVM_LIBRARY_VISIBILITY SPIRV64TargetInfo : public BaseSPIRVTargetInfo { 342 public: 343 SPIRV64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) 344 : BaseSPIRVTargetInfo(Triple, Opts) { 345 assert(Triple.getArch() == llvm::Triple::spirv64 && 346 "Invalid architecture for 64-bit SPIR-V."); 347 assert(getTriple().getOS() == llvm::Triple::UnknownOS && 348 "64-bit SPIR-V target must use unknown OS"); 349 assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment && 350 "64-bit SPIR-V target must use unknown environment type"); 351 PointerWidth = PointerAlign = 64; 352 SizeType = TargetInfo::UnsignedLong; 353 PtrDiffType = IntPtrType = TargetInfo::SignedLong; 354 resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-" 355 "v96:128-v192:256-v256:256-v512:512-v1024:1024"); 356 } 357 358 void getTargetDefines(const LangOptions &Opts, 359 MacroBuilder &Builder) const override; 360 }; 361 362 } // namespace targets 363 } // namespace clang 364 #endif // LLVM_CLANG_LIB_BASIC_TARGETS_SPIR_H 365