485 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file declares SPIR and SPIR-V TargetInfo objects.10//11//===----------------------------------------------------------------------===//12 13#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_SPIR_H14#define LLVM_CLANG_LIB_BASIC_TARGETS_SPIR_H15 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 24namespace clang {25namespace targets {26 27// Used by both the SPIR and SPIR-V targets.28static const unsigned SPIRDefIsPrivMap[] = {29 0, // Default30 1, // opencl_global31 3, // opencl_local32 2, // opencl_constant33 0, // opencl_private34 4, // opencl_generic35 5, // opencl_global_device36 6, // opencl_global_host37 0, // cuda_device38 0, // cuda_constant39 0, // cuda_shared40 // SYCL address space values for this map are dummy41 0, // sycl_global42 0, // sycl_global_device43 0, // sycl_global_host44 0, // sycl_local45 0, // sycl_private46 0, // ptr32_sptr47 0, // ptr32_uptr48 0, // ptr6449 3, // hlsl_groupshared50 12, // hlsl_constant51 10, // hlsl_private52 11, // hlsl_device53 7, // hlsl_input54 // Wasm address space values for this target are dummy values,55 // as it is only enabled for Wasm targets.56 20, // wasm_funcref57};58 59// Used by both the SPIR and SPIR-V targets.60static const unsigned SPIRDefIsGenMap[] = {61 4, // Default62 1, // opencl_global63 3, // opencl_local64 2, // opencl_constant65 0, // opencl_private66 4, // opencl_generic67 5, // opencl_global_device68 6, // opencl_global_host69 // cuda_* address space mapping is intended for HIPSPV (HIP to SPIR-V70 // translation). This mapping is enabled when the language mode is HIP.71 1, // cuda_device72 // cuda_constant pointer can be casted to default/"flat" pointer, but in73 // SPIR-V casts between constant and generic pointers are not allowed. For74 // this reason cuda_constant is mapped to SPIR-V CrossWorkgroup.75 1, // cuda_constant76 3, // cuda_shared77 1, // sycl_global78 5, // sycl_global_device79 6, // sycl_global_host80 3, // sycl_local81 0, // sycl_private82 0, // ptr32_sptr83 0, // ptr32_uptr84 0, // ptr6485 3, // hlsl_groupshared86 0, // hlsl_constant87 10, // hlsl_private88 11, // hlsl_device89 7, // hlsl_input90 // Wasm address space values for this target are dummy values,91 // as it is only enabled for Wasm targets.92 20, // wasm_funcref93};94 95// Base class for SPIR and SPIR-V target info.96class LLVM_LIBRARY_VISIBILITY BaseSPIRTargetInfo : public TargetInfo {97 std::unique_ptr<TargetInfo> HostTarget;98 99protected: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 HasFastHalfType = true;110 HasFloat16 = true;111 HasBFloat16 = true;112 HasFullBFloat16 = true;113 BFloat16Width = BFloat16Align = 16;114 BFloat16Format = &llvm::APFloat::BFloat();115 // Define available target features116 // These must be defined in sorted order!117 NoAsmVariants = true;118 119 llvm::Triple HostTriple(Opts.HostTriple);120 if (!HostTriple.isSPIR() && !HostTriple.isSPIRV() &&121 HostTriple.getArch() != llvm::Triple::UnknownArch) {122 HostTarget = AllocateTarget(llvm::Triple(Opts.HostTriple), Opts);123 124 // Copy properties from host target.125 BoolWidth = HostTarget->getBoolWidth();126 BoolAlign = HostTarget->getBoolAlign();127 IntWidth = HostTarget->getIntWidth();128 IntAlign = HostTarget->getIntAlign();129 HalfWidth = HostTarget->getHalfWidth();130 HalfAlign = HostTarget->getHalfAlign();131 FloatWidth = HostTarget->getFloatWidth();132 FloatAlign = HostTarget->getFloatAlign();133 DoubleWidth = HostTarget->getDoubleWidth();134 DoubleAlign = HostTarget->getDoubleAlign();135 LongWidth = HostTarget->getLongWidth();136 LongAlign = HostTarget->getLongAlign();137 LongLongWidth = HostTarget->getLongLongWidth();138 LongLongAlign = HostTarget->getLongLongAlign();139 MinGlobalAlign =140 HostTarget->getMinGlobalAlign(/* TypeSize = */ 0,141 /* HasNonWeakDef = */ true);142 NewAlign = HostTarget->getNewAlign();143 DefaultAlignForAttributeAligned =144 HostTarget->getDefaultAlignForAttributeAligned();145 IntMaxType = HostTarget->getIntMaxType();146 WCharType = HostTarget->getWCharType();147 WIntType = HostTarget->getWIntType();148 Char16Type = HostTarget->getChar16Type();149 Char32Type = HostTarget->getChar32Type();150 Int64Type = HostTarget->getInt64Type();151 SigAtomicType = HostTarget->getSigAtomicType();152 ProcessIDType = HostTarget->getProcessIDType();153 154 UseBitFieldTypeAlignment = HostTarget->useBitFieldTypeAlignment();155 UseZeroLengthBitfieldAlignment =156 HostTarget->useZeroLengthBitfieldAlignment();157 UseExplicitBitFieldAlignment = HostTarget->useExplicitBitFieldAlignment();158 ZeroLengthBitfieldBoundary = HostTarget->getZeroLengthBitfieldBoundary();159 160 // This is a bit of a lie, but it controls __GCC_ATOMIC_XXX_LOCK_FREE, and161 // we need those macros to be identical on host and device, because (among162 // other things) they affect which standard library classes are defined,163 // and we need all classes to be defined on both the host and device.164 MaxAtomicInlineWidth = HostTarget->getMaxAtomicInlineWidth();165 }166 }167 168public:169 // SPIR supports the half type and the only llvm intrinsic allowed in SPIR is170 // memcpy as per section 3 of the SPIR spec.171 bool useFP16ConversionIntrinsics() const override { return false; }172 173 llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override {174 return {};175 }176 177 std::string_view getClobbers() const override { return ""; }178 179 ArrayRef<const char *> getGCCRegNames() const override { return {}; }180 181 bool validateAsmConstraint(const char *&Name,182 TargetInfo::ConstraintInfo &info) const override {183 return true;184 }185 186 ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {187 return {};188 }189 190 BuiltinVaListKind getBuiltinVaListKind() const override {191 return TargetInfo::VoidPtrBuiltinVaList;192 }193 194 std::optional<unsigned>195 getDWARFAddressSpace(unsigned AddressSpace) const override {196 return AddressSpace;197 }198 199 CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {200 return (CC == CC_SpirFunction || CC == CC_DeviceKernel) ? CCCR_OK201 : CCCR_Warning;202 }203 204 CallingConv getDefaultCallingConv() const override {205 return CC_SpirFunction;206 }207 208 void setAddressSpaceMap(bool DefaultIsGeneric) {209 AddrSpaceMap = DefaultIsGeneric ? &SPIRDefIsGenMap : &SPIRDefIsPrivMap;210 }211 212 void adjust(DiagnosticsEngine &Diags, LangOptions &Opts,213 const TargetInfo *Aux) override {214 TargetInfo::adjust(Diags, Opts, Aux);215 // FIXME: SYCL specification considers unannotated pointers and references216 // to be pointing to the generic address space. See section 5.9.3 of217 // SYCL 2020 specification.218 // Currently, there is no way of representing SYCL's and HIP/CUDA's default219 // address space language semantic along with the semantics of embedded C's220 // default address space in the same address space map. Hence the map needs221 // to be reset to allow mapping to the desired value of 'Default' entry for222 // SYCL and HIP/CUDA.223 setAddressSpaceMap(224 /*DefaultIsGeneric=*/Opts.SYCLIsDevice ||225 // The address mapping from HIP/CUDA language for device code is only226 // defined for SPIR-V, and all Intel SPIR-V code should have the default227 // AS as generic.228 (getTriple().isSPIRV() &&229 (Opts.CUDAIsDevice ||230 getTriple().getVendor() == llvm::Triple::Intel)));231 }232 233 void setSupportedOpenCLOpts() override {234 // Assume all OpenCL extensions and optional core features are supported235 // for SPIR and SPIR-V since they are generic targets.236 supportAllOpenCLOpts();237 }238 239 bool hasBitIntType() const override { return true; }240 241 bool hasInt128Type() const override { return false; }242};243 244class LLVM_LIBRARY_VISIBILITY SPIRTargetInfo : public BaseSPIRTargetInfo {245public:246 SPIRTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)247 : BaseSPIRTargetInfo(Triple, Opts) {248 assert(Triple.isSPIR() && "Invalid architecture for SPIR.");249 assert(getTriple().getOS() == llvm::Triple::UnknownOS &&250 "SPIR target must use unknown OS");251 assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment &&252 "SPIR target must use unknown environment type");253 }254 255 void getTargetDefines(const LangOptions &Opts,256 MacroBuilder &Builder) const override;257 258 bool hasFeature(StringRef Feature) const override {259 return Feature == "spir";260 }261 262 bool checkArithmeticFenceSupported() const override { return true; }263};264 265class LLVM_LIBRARY_VISIBILITY SPIR32TargetInfo : public SPIRTargetInfo {266public:267 SPIR32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)268 : SPIRTargetInfo(Triple, Opts) {269 assert(Triple.getArch() == llvm::Triple::spir &&270 "Invalid architecture for 32-bit SPIR.");271 PointerWidth = PointerAlign = 32;272 SizeType = TargetInfo::UnsignedInt;273 PtrDiffType = IntPtrType = TargetInfo::SignedInt;274 // SPIR32 has support for atomic ops if atomic extension is enabled.275 // Take the maximum because it's possible the Host supports wider types.276 MaxAtomicInlineWidth = std::max<unsigned char>(MaxAtomicInlineWidth, 32);277 resetDataLayout("e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-"278 "v96:128-v192:256-v256:256-v512:512-v1024:1024-G1");279 }280 281 void getTargetDefines(const LangOptions &Opts,282 MacroBuilder &Builder) const override;283};284 285class LLVM_LIBRARY_VISIBILITY SPIR64TargetInfo : public SPIRTargetInfo {286public:287 SPIR64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)288 : SPIRTargetInfo(Triple, Opts) {289 assert(Triple.getArch() == llvm::Triple::spir64 &&290 "Invalid architecture for 64-bit SPIR.");291 PointerWidth = PointerAlign = 64;292 SizeType = TargetInfo::UnsignedLong;293 PtrDiffType = IntPtrType = TargetInfo::SignedLong;294 // SPIR64 has support for atomic ops if atomic extension is enabled.295 // Take the maximum because it's possible the Host supports wider types.296 MaxAtomicInlineWidth = std::max<unsigned char>(MaxAtomicInlineWidth, 64);297 resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-"298 "v96:128-v192:256-v256:256-v512:512-v1024:1024-G1");299 }300 301 void getTargetDefines(const LangOptions &Opts,302 MacroBuilder &Builder) const override;303};304 305class LLVM_LIBRARY_VISIBILITY BaseSPIRVTargetInfo : public BaseSPIRTargetInfo {306public:307 BaseSPIRVTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)308 : BaseSPIRTargetInfo(Triple, Opts) {309 assert(Triple.isSPIRV() && "Invalid architecture for SPIR-V.");310 }311 312 llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override;313 314 bool hasFeature(StringRef Feature) const override {315 return Feature == "spirv";316 }317 318 void getTargetDefines(const LangOptions &Opts,319 MacroBuilder &Builder) const override;320};321 322class LLVM_LIBRARY_VISIBILITY SPIRVTargetInfo : public BaseSPIRVTargetInfo {323public:324 SPIRVTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)325 : BaseSPIRVTargetInfo(Triple, Opts) {326 assert(Triple.getArch() == llvm::Triple::spirv &&327 "Invalid architecture for Logical SPIR-V.");328 assert(Triple.getOS() == llvm::Triple::Vulkan &&329 Triple.getVulkanVersion() != llvm::VersionTuple(0) &&330 "Logical SPIR-V requires a valid Vulkan environment.");331 assert(Triple.getEnvironment() >= llvm::Triple::Pixel &&332 Triple.getEnvironment() <= llvm::Triple::Amplification &&333 "Logical SPIR-V environment must be a valid shader stage.");334 PointerWidth = PointerAlign = 64;335 336 // SPIR-V IDs are represented with a single 32-bit word.337 SizeType = TargetInfo::UnsignedInt;338 resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-"339 "v256:256-v512:512-v1024:1024-n8:16:32:64-G10");340 }341 342 void getTargetDefines(const LangOptions &Opts,343 MacroBuilder &Builder) const override;344};345 346class LLVM_LIBRARY_VISIBILITY SPIRV32TargetInfo : public BaseSPIRVTargetInfo {347public:348 SPIRV32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)349 : BaseSPIRVTargetInfo(Triple, Opts) {350 assert(Triple.getArch() == llvm::Triple::spirv32 &&351 "Invalid architecture for 32-bit SPIR-V.");352 assert(getTriple().getOS() == llvm::Triple::UnknownOS &&353 "32-bit SPIR-V target must use unknown OS");354 assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment &&355 "32-bit SPIR-V target must use unknown environment type");356 PointerWidth = PointerAlign = 32;357 SizeType = TargetInfo::UnsignedInt;358 PtrDiffType = IntPtrType = TargetInfo::SignedInt;359 // SPIR-V has core support for atomic ops, and Int32 is always available;360 // we take the maximum because it's possible the Host supports wider types.361 MaxAtomicInlineWidth = std::max<unsigned char>(MaxAtomicInlineWidth, 32);362 resetDataLayout("e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-"363 "v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64-G1");364 }365 366 void getTargetDefines(const LangOptions &Opts,367 MacroBuilder &Builder) const override;368};369 370class LLVM_LIBRARY_VISIBILITY SPIRV64TargetInfo : public BaseSPIRVTargetInfo {371public:372 SPIRV64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)373 : BaseSPIRVTargetInfo(Triple, Opts) {374 assert(Triple.getArch() == llvm::Triple::spirv64 &&375 "Invalid architecture for 64-bit SPIR-V.");376 assert(getTriple().getOS() == llvm::Triple::UnknownOS &&377 "64-bit SPIR-V target must use unknown 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 // SPIR-V has core support for atomic ops, and Int64 is always available;384 // we take the maximum because it's possible the Host supports wider types.385 MaxAtomicInlineWidth = std::max<unsigned char>(MaxAtomicInlineWidth, 64);386 resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-"387 "v256:256-v512:512-v1024:1024-n8:16:32:64-G1");388 }389 390 void getTargetDefines(const LangOptions &Opts,391 MacroBuilder &Builder) const override;392 393 const llvm::omp::GV &getGridValue() const override {394 return llvm::omp::SPIRVGridValues;395 }396 397 std::optional<LangAS> getConstantAddressSpace() const override {398 return ConstantAS;399 }400 void adjust(DiagnosticsEngine &Diags, LangOptions &Opts,401 const TargetInfo *Aux) override {402 BaseSPIRVTargetInfo::adjust(Diags, Opts, Aux);403 // opencl_constant will map to UniformConstant in SPIR-V404 if (Opts.OpenCL)405 ConstantAS = LangAS::opencl_constant;406 }407 408private:409 // opencl_global will map to CrossWorkgroup in SPIR-V410 LangAS ConstantAS = LangAS::opencl_global;411};412 413class LLVM_LIBRARY_VISIBILITY SPIRV64AMDGCNTargetInfo final414 : public BaseSPIRVTargetInfo {415public:416 SPIRV64AMDGCNTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)417 : BaseSPIRVTargetInfo(Triple, Opts) {418 assert(Triple.getArch() == llvm::Triple::spirv64 &&419 "Invalid architecture for 64-bit AMDGCN SPIR-V.");420 assert(Triple.getVendor() == llvm::Triple::VendorType::AMD &&421 "64-bit AMDGCN SPIR-V target must use AMD vendor");422 assert(getTriple().getOS() == llvm::Triple::OSType::AMDHSA &&423 "64-bit AMDGCN SPIR-V target must use AMDHSA OS");424 assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment &&425 "64-bit SPIR-V target must use unknown environment type");426 PointerWidth = PointerAlign = 64;427 SizeType = TargetInfo::UnsignedLong;428 PtrDiffType = IntPtrType = TargetInfo::SignedLong;429 AddrSpaceMap = &SPIRDefIsGenMap;430 431 resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-"432 "v256:256-v512:512-v1024:1024-n32:64-S32-G1-P4-A0");433 434 HasFastHalfType = true;435 HasFloat16 = true;436 HalfArgsAndReturns = true;437 438 MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;439 }440 441 ArrayRef<const char *> getGCCRegNames() const override;442 443 BuiltinVaListKind getBuiltinVaListKind() const override {444 return TargetInfo::CharPtrBuiltinVaList;445 }446 447 bool initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,448 StringRef,449 const std::vector<std::string> &) const override;450 451 bool validateAsmConstraint(const char *&Name,452 TargetInfo::ConstraintInfo &Info) const override;453 454 std::string convertConstraint(const char *&Constraint) const override;455 456 llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override;457 458 void getTargetDefines(const LangOptions &Opts,459 MacroBuilder &Builder) const override;460 461 void setAuxTarget(const TargetInfo *Aux) override;462 463 void adjust(DiagnosticsEngine &Diags, LangOptions &Opts,464 const TargetInfo *Aux) override {465 TargetInfo::adjust(Diags, Opts, Aux);466 }467 468 bool hasInt128Type() const override { return TargetInfo::hasInt128Type(); }469};470 471class LLVM_LIBRARY_VISIBILITY SPIRV64IntelTargetInfo final472 : public SPIRV64TargetInfo {473public:474 SPIRV64IntelTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)475 : SPIRV64TargetInfo(Triple, Opts) {476 assert(Triple.getVendor() == llvm::Triple::VendorType::Intel &&477 "64-bit Intel SPIR-V target must use Intel vendor");478 resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-"479 "v256:256-v512:512-v1024:1024-n8:16:32:64-G1-P9-A0");480 }481};482} // namespace targets483} // namespace clang484#endif // LLVM_CLANG_LIB_BASIC_TARGETS_SPIR_H485