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