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