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