1 //===--- SPIR.cpp - Implement SPIR and SPIR-V target feature support ------===// 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 implements SPIR and SPIR-V TargetInfo objects. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "SPIR.h" 14 #include "AMDGPU.h" 15 #include "clang/Basic/MacroBuilder.h" 16 #include "clang/Basic/TargetBuiltins.h" 17 #include "llvm/TargetParser/TargetParser.h" 18 19 using namespace clang; 20 using namespace clang::targets; 21 22 static constexpr int NumBuiltins = 23 clang::SPIRV::LastTSBuiltin - Builtin::FirstTSBuiltin; 24 25 #define GET_BUILTIN_STR_TABLE 26 #include "clang/Basic/BuiltinsSPIRVCommon.inc" 27 #undef GET_BUILTIN_STR_TABLE 28 29 static constexpr Builtin::Info BuiltinInfos[] = { 30 #define GET_BUILTIN_INFOS 31 #include "clang/Basic/BuiltinsSPIRVCommon.inc" 32 #undef GET_BUILTIN_INFOS 33 }; 34 35 namespace CL { 36 #define GET_BUILTIN_STR_TABLE 37 #include "clang/Basic/BuiltinsSPIRVCL.inc" 38 #undef GET_BUILTIN_STR_TABLE 39 40 static constexpr Builtin::Info BuiltinInfos[] = { 41 #define GET_BUILTIN_INFOS 42 #include "clang/Basic/BuiltinsSPIRVCL.inc" 43 #undef GET_BUILTIN_INFOS 44 }; 45 } // namespace CL 46 47 namespace VK { 48 #define GET_BUILTIN_STR_TABLE 49 #include "clang/Basic/BuiltinsSPIRVVK.inc" 50 #undef GET_BUILTIN_STR_TABLE 51 52 static constexpr Builtin::Info BuiltinInfos[] = { 53 #define GET_BUILTIN_INFOS 54 #include "clang/Basic/BuiltinsSPIRVVK.inc" 55 #undef GET_BUILTIN_INFOS 56 }; 57 } // namespace VK 58 59 static_assert(std::size(BuiltinInfos) + std::size(CL::BuiltinInfos) + 60 std::size(VK::BuiltinInfos) == 61 NumBuiltins); 62 63 llvm::SmallVector<Builtin::InfosShard> 64 BaseSPIRVTargetInfo::getTargetBuiltins() const { 65 return {{&BuiltinStrings, BuiltinInfos}, 66 {&VK::BuiltinStrings, VK::BuiltinInfos}, 67 {&CL::BuiltinStrings, CL::BuiltinInfos}}; 68 } 69 70 void SPIRTargetInfo::getTargetDefines(const LangOptions &Opts, 71 MacroBuilder &Builder) const { 72 DefineStd(Builder, "SPIR", Opts); 73 } 74 75 void SPIR32TargetInfo::getTargetDefines(const LangOptions &Opts, 76 MacroBuilder &Builder) const { 77 SPIRTargetInfo::getTargetDefines(Opts, Builder); 78 DefineStd(Builder, "SPIR32", Opts); 79 } 80 81 void SPIR64TargetInfo::getTargetDefines(const LangOptions &Opts, 82 MacroBuilder &Builder) const { 83 SPIRTargetInfo::getTargetDefines(Opts, Builder); 84 DefineStd(Builder, "SPIR64", Opts); 85 } 86 87 void BaseSPIRVTargetInfo::getTargetDefines(const LangOptions &Opts, 88 MacroBuilder &Builder) const { 89 DefineStd(Builder, "SPIRV", Opts); 90 if (Opts.HLSL) 91 DefineStd(Builder, "spirv", Opts); 92 } 93 94 void SPIRVTargetInfo::getTargetDefines(const LangOptions &Opts, 95 MacroBuilder &Builder) const { 96 BaseSPIRVTargetInfo::getTargetDefines(Opts, Builder); 97 } 98 99 void SPIRV32TargetInfo::getTargetDefines(const LangOptions &Opts, 100 MacroBuilder &Builder) const { 101 BaseSPIRVTargetInfo::getTargetDefines(Opts, Builder); 102 DefineStd(Builder, "SPIRV32", Opts); 103 } 104 105 void SPIRV64TargetInfo::getTargetDefines(const LangOptions &Opts, 106 MacroBuilder &Builder) const { 107 BaseSPIRVTargetInfo::getTargetDefines(Opts, Builder); 108 DefineStd(Builder, "SPIRV64", Opts); 109 } 110 111 static const AMDGPUTargetInfo AMDGPUTI(llvm::Triple("amdgcn-amd-amdhsa"), {}); 112 113 ArrayRef<const char *> SPIRV64AMDGCNTargetInfo::getGCCRegNames() const { 114 return AMDGPUTI.getGCCRegNames(); 115 } 116 117 bool SPIRV64AMDGCNTargetInfo::initFeatureMap( 118 llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef, 119 const std::vector<std::string> &FeatureVec) const { 120 llvm::AMDGPU::fillAMDGPUFeatureMap({}, getTriple(), Features); 121 122 return TargetInfo::initFeatureMap(Features, Diags, {}, FeatureVec); 123 } 124 125 bool SPIRV64AMDGCNTargetInfo::validateAsmConstraint( 126 const char *&Name, TargetInfo::ConstraintInfo &Info) const { 127 return AMDGPUTI.validateAsmConstraint(Name, Info); 128 } 129 130 std::string 131 SPIRV64AMDGCNTargetInfo::convertConstraint(const char *&Constraint) const { 132 return AMDGPUTI.convertConstraint(Constraint); 133 } 134 135 llvm::SmallVector<Builtin::InfosShard> 136 SPIRV64AMDGCNTargetInfo::getTargetBuiltins() const { 137 return AMDGPUTI.getTargetBuiltins(); 138 } 139 140 void SPIRV64AMDGCNTargetInfo::getTargetDefines(const LangOptions &Opts, 141 MacroBuilder &Builder) const { 142 BaseSPIRVTargetInfo::getTargetDefines(Opts, Builder); 143 DefineStd(Builder, "SPIRV64", Opts); 144 145 Builder.defineMacro("__AMD__"); 146 Builder.defineMacro("__AMDGPU__"); 147 Builder.defineMacro("__AMDGCN__"); 148 } 149 150 void SPIRV64AMDGCNTargetInfo::setAuxTarget(const TargetInfo *Aux) { 151 assert(Aux && "Cannot invoke setAuxTarget without a valid auxiliary target!"); 152 153 // This is a 1:1 copy of AMDGPUTargetInfo::setAuxTarget() 154 assert(HalfFormat == Aux->HalfFormat); 155 assert(FloatFormat == Aux->FloatFormat); 156 assert(DoubleFormat == Aux->DoubleFormat); 157 158 // On x86_64 long double is 80-bit extended precision format, which is 159 // not supported by AMDGPU. 128-bit floating point format is also not 160 // supported by AMDGPU. Therefore keep its own format for these two types. 161 auto SaveLongDoubleFormat = LongDoubleFormat; 162 auto SaveFloat128Format = Float128Format; 163 auto SaveLongDoubleWidth = LongDoubleWidth; 164 auto SaveLongDoubleAlign = LongDoubleAlign; 165 copyAuxTarget(Aux); 166 LongDoubleFormat = SaveLongDoubleFormat; 167 Float128Format = SaveFloat128Format; 168 LongDoubleWidth = SaveLongDoubleWidth; 169 LongDoubleAlign = SaveLongDoubleAlign; 170 // For certain builtin types support on the host target, claim they are 171 // supported to pass the compilation of the host code during the device-side 172 // compilation. 173 // FIXME: As the side effect, we also accept `__float128` uses in the device 174 // code. To reject these builtin types supported in the host target but not in 175 // the device target, one approach would support `device_builtin` attribute 176 // so that we could tell the device builtin types from the host ones. This 177 // also solves the different representations of the same builtin type, such 178 // as `size_t` in the MSVC environment. 179 if (Aux->hasFloat128Type()) { 180 HasFloat128 = true; 181 Float128Format = DoubleFormat; 182 } 183 } 184