1//===-- SPIRVBaseInfo.cpp - Top level SPIRV definitions ---------*- 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 contains the implementation for helper mnemonic lookup functions,
10// versioning/capabilities/extensions getters for symbolic/named operands used
11// in various SPIR-V instructions.
12//
13//===----------------------------------------------------------------------===//
14
15#include "SPIRVBaseInfo.h"
16#include "llvm/ADT/ArrayRef.h"
17#include "llvm/ADT/StringRef.h"
18#include "llvm/ADT/StringTable.h"
19
20namespace llvm {
21namespace SPIRV {
22struct SymbolicOperand {
23 OperandCategory::OperandCategory Category;
24 uint32_t Value;
25 StringTable::Offset Mnemonic;
26 uint32_t MinVersion;
27 uint32_t MaxVersion;
28};
29
30struct ExtensionEntry {
31 OperandCategory::OperandCategory Category;
32 uint32_t Value;
33 Extension::Extension ReqExtension;
34};
35
36struct CapabilityEntry {
37 OperandCategory::OperandCategory Category;
38 uint32_t Value;
39 Capability::Capability ReqCapability;
40};
41
42struct EnvironmentEntry {
43 OperandCategory::OperandCategory Category;
44 uint32_t Value;
45 Environment::Environment AllowedEnvironment;
46};
47
48using namespace OperandCategory;
49using namespace Extension;
50using namespace Environment;
51using namespace Capability;
52using namespace InstructionSet;
53#define GET_SymbolicOperands_DECL
54#define GET_SymbolicOperands_IMPL
55#define GET_ExtensionEntries_DECL
56#define GET_ExtensionEntries_IMPL
57#define GET_CapabilityEntries_DECL
58#define GET_CapabilityEntries_IMPL
59#define GET_EnvironmentEntries_DECL
60#define GET_EnvironmentEntries_IMPL
61#define GET_ExtendedBuiltins_DECL
62#define GET_ExtendedBuiltins_IMPL
63#include "SPIRVGenTables.inc"
64} // namespace SPIRV
65
66std::string
67getSymbolicOperandMnemonic(SPIRV::OperandCategory::OperandCategory Category,
68 int32_t Value) {
69 const SPIRV::SymbolicOperand *Lookup =
70 SPIRV::lookupSymbolicOperandByCategoryAndValue(Category, Value);
71 // Value that encodes just one enum value.
72 if (Lookup)
73 return SPIRV::getSymbolicOperandStr(Offset: Lookup->Mnemonic).str();
74 if (Category != SPIRV::OperandCategory::ImageOperandOperand &&
75 Category != SPIRV::OperandCategory::FPFastMathModeOperand &&
76 Category != SPIRV::OperandCategory::SelectionControlOperand &&
77 Category != SPIRV::OperandCategory::LoopControlOperand &&
78 Category != SPIRV::OperandCategory::FunctionControlOperand &&
79 Category != SPIRV::OperandCategory::MemorySemanticsOperand &&
80 Category != SPIRV::OperandCategory::MemoryOperandOperand &&
81 Category != SPIRV::OperandCategory::KernelProfilingInfoOperand &&
82 Category != SPIRV::OperandCategory::SpecConstantOpOperandsOperand)
83 return "UNKNOWN";
84 // Value that encodes many enum values (one bit per enum value).
85 std::string Name;
86 std::string Separator;
87 const SPIRV::SymbolicOperand *EnumValueInCategory =
88 SPIRV::lookupSymbolicOperandByCategory(Category);
89
90 auto TableEnd = ArrayRef(SPIRV::SymbolicOperands).end();
91 while (EnumValueInCategory && EnumValueInCategory->Category == Category) {
92 if ((EnumValueInCategory->Value != 0) &&
93 (Value & EnumValueInCategory->Value)) {
94 Name += Separator +
95 SPIRV::getSymbolicOperandStr(Offset: EnumValueInCategory->Mnemonic).str();
96 Separator = "|";
97 }
98 if (++EnumValueInCategory == TableEnd)
99 break;
100 }
101
102 return Name;
103}
104
105VersionTuple
106getSymbolicOperandMinVersion(SPIRV::OperandCategory::OperandCategory Category,
107 uint32_t Value) {
108 const SPIRV::SymbolicOperand *Lookup =
109 SPIRV::lookupSymbolicOperandByCategoryAndValue(Category, Value);
110
111 if (Lookup)
112 return VersionTuple(Lookup->MinVersion / 10, Lookup->MinVersion % 10);
113
114 return VersionTuple(0);
115}
116
117VersionTuple
118getSymbolicOperandMaxVersion(SPIRV::OperandCategory::OperandCategory Category,
119 uint32_t Value) {
120 const SPIRV::SymbolicOperand *Lookup =
121 SPIRV::lookupSymbolicOperandByCategoryAndValue(Category, Value);
122
123 if (Lookup)
124 return VersionTuple(Lookup->MaxVersion / 10, Lookup->MaxVersion % 10);
125
126 return VersionTuple();
127}
128
129CapabilityList
130getSymbolicOperandCapabilities(SPIRV::OperandCategory::OperandCategory Category,
131 uint32_t Value) {
132 CapabilityList Capabilities;
133 const SPIRV::CapabilityEntry *Capability =
134 SPIRV::lookupCapabilityByCategoryAndValue(Category, Value);
135 auto TableEnd = ArrayRef(SPIRV::CapabilityEntries).end();
136 while (Capability && Capability->Category == Category &&
137 Capability->Value == Value) {
138 Capabilities.push_back(
139 Elt: static_cast<SPIRV::Capability::Capability>(Capability->ReqCapability));
140 if (++Capability == TableEnd)
141 break;
142 }
143
144 return Capabilities;
145}
146
147EnvironmentList getSymbolicOperandAllowedEnvironments(
148 SPIRV::OperandCategory::OperandCategory Category, uint32_t Value) {
149 EnvironmentList Environments;
150 const SPIRV::EnvironmentEntry *Environment =
151 SPIRV::lookupEnvironmentByCategoryAndValue(Category, Value);
152 auto TableEnd = ArrayRef(SPIRV::EnvironmentEntries).end();
153 while (Environment && Environment->Category == Category &&
154 Environment->Value == Value) {
155 Environments.push_back(Elt: static_cast<SPIRV::Environment::Environment>(
156 Environment->AllowedEnvironment));
157 if (++Environment == TableEnd)
158 break;
159 }
160
161 return Environments;
162}
163
164CapabilityList
165getCapabilitiesEnabledByExtension(SPIRV::Extension::Extension Extension) {
166 const SPIRV::ExtensionEntry *Entry =
167 SPIRV::lookupSymbolicOperandsEnabledByExtension(
168 ReqExtension: Extension, Category: SPIRV::OperandCategory::CapabilityOperand);
169
170 CapabilityList Capabilities;
171 auto TableEnd = ArrayRef(SPIRV::ExtensionEntries).end();
172 while (Entry &&
173 Entry->Category == SPIRV::OperandCategory::CapabilityOperand) {
174 // Some capabilities' codes might go not in order.
175 if (Entry->ReqExtension == Extension)
176 Capabilities.push_back(
177 Elt: static_cast<SPIRV::Capability::Capability>(Entry->Value));
178 if (++Entry == TableEnd)
179 break;
180 }
181
182 return Capabilities;
183}
184
185ExtensionList
186getSymbolicOperandExtensions(SPIRV::OperandCategory::OperandCategory Category,
187 uint32_t Value) {
188 const SPIRV::ExtensionEntry *Extension =
189 SPIRV::lookupExtensionByCategoryAndValue(Category, Value);
190
191 ExtensionList Extensions;
192 auto TableEnd = ArrayRef(SPIRV::ExtensionEntries).end();
193 while (Extension && Extension->Category == Category &&
194 Extension->Value == Value) {
195 Extensions.push_back(
196 Elt: static_cast<SPIRV::Extension::Extension>(Extension->ReqExtension));
197 if (++Extension == TableEnd)
198 break;
199 }
200
201 return Extensions;
202}
203
204std::string getLinkStringForBuiltIn(SPIRV::BuiltIn::BuiltIn BuiltInValue) {
205 const SPIRV::SymbolicOperand *Lookup =
206 SPIRV::lookupSymbolicOperandByCategoryAndValue(
207 Category: SPIRV::OperandCategory::BuiltInOperand, Value: BuiltInValue);
208
209 if (Lookup)
210 return "__spirv_BuiltIn" +
211 SPIRV::getSymbolicOperandStr(Offset: Lookup->Mnemonic).str();
212 return "UNKNOWN_BUILTIN";
213}
214
215bool getSpirvBuiltInIdByName(llvm::StringRef Name,
216 SPIRV::BuiltIn::BuiltIn &BI) {
217 const std::string Prefix = "__spirv_BuiltIn";
218 if (!Name.starts_with(Prefix))
219 return false;
220
221 const SPIRV::SymbolicOperand *Lookup =
222 SPIRV::lookupSymbolicOperandByCategoryAndMnemonic(
223 Category: SPIRV::OperandCategory::BuiltInOperand,
224 Mnemonic: Name.drop_front(N: Prefix.length()));
225
226 if (!Lookup)
227 return false;
228
229 BI = static_cast<SPIRV::BuiltIn::BuiltIn>(Lookup->Value);
230 return true;
231}
232
233std::string getExtInstSetName(SPIRV::InstructionSet::InstructionSet Set) {
234 switch (Set) {
235 case SPIRV::InstructionSet::OpenCL_std:
236 return "OpenCL.std";
237 case SPIRV::InstructionSet::GLSL_std_450:
238 return "GLSL.std.450";
239 case SPIRV::InstructionSet::NonSemantic_Shader_DebugInfo_100:
240 return "NonSemantic.Shader.DebugInfo.100";
241 case SPIRV::InstructionSet::NonSemantic_AuxData:
242 return "NonSemantic.AuxData";
243 case SPIRV::InstructionSet::SPV_AMD_shader_trinary_minmax:
244 return "SPV_AMD_shader_trinary_minmax";
245 }
246 return "UNKNOWN_EXT_INST_SET";
247}
248
249SPIRV::InstructionSet::InstructionSet
250getExtInstSetFromString(std::string SetName) {
251 for (auto Set :
252 {SPIRV::InstructionSet::GLSL_std_450, SPIRV::InstructionSet::OpenCL_std,
253 SPIRV::InstructionSet::NonSemantic_Shader_DebugInfo_100,
254 SPIRV::InstructionSet::NonSemantic_AuxData}) {
255 if (SetName == getExtInstSetName(Set))
256 return Set;
257 }
258 llvm_unreachable("UNKNOWN_EXT_INST_SET");
259}
260
261std::string getExtInstName(SPIRV::InstructionSet::InstructionSet Set,
262 uint32_t InstructionNumber) {
263 const SPIRV::ExtendedBuiltin *Lookup =
264 SPIRV::lookupExtendedBuiltinBySetAndNumber(Set, Number: InstructionNumber);
265
266 if (!Lookup)
267 return "UNKNOWN_EXT_INST";
268
269 return SPIRV::getExtendedBuiltinStr(Offset: Lookup->Name).str();
270}
271} // namespace llvm
272