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