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