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