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 
19 namespace llvm {
20 namespace SPIRV {
21 struct SymbolicOperand {
22   OperandCategory::OperandCategory Category;
23   uint32_t Value;
24   StringRef Mnemonic;
25   uint32_t MinVersion;
26   uint32_t MaxVersion;
27 };
28 
29 struct ExtensionEntry {
30   OperandCategory::OperandCategory Category;
31   uint32_t Value;
32   Extension::Extension ReqExtension;
33 };
34 
35 struct CapabilityEntry {
36   OperandCategory::OperandCategory Category;
37   uint32_t Value;
38   Capability::Capability ReqCapability;
39 };
40 
41 using namespace OperandCategory;
42 using namespace Extension;
43 using namespace Capability;
44 using 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 
56 std::string
57 getSymbolicOperandMnemonic(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     return "UNKNOWN";
73   // Value that encodes many enum values (one bit per enum value).
74   std::string Name;
75   std::string Separator;
76   const SPIRV::SymbolicOperand *EnumValueInCategory =
77       SPIRV::lookupSymbolicOperandByCategory(Category);
78 
79   while (EnumValueInCategory && EnumValueInCategory->Category == Category) {
80     if ((EnumValueInCategory->Value != 0) &&
81         (Value & EnumValueInCategory->Value)) {
82       Name += Separator + EnumValueInCategory->Mnemonic.str();
83       Separator = "|";
84     }
85     ++EnumValueInCategory;
86   }
87 
88   return Name;
89 }
90 
91 uint32_t
92 getSymbolicOperandMinVersion(SPIRV::OperandCategory::OperandCategory Category,
93                              uint32_t Value) {
94   const SPIRV::SymbolicOperand *Lookup =
95       SPIRV::lookupSymbolicOperandByCategoryAndValue(Category, Value);
96 
97   if (Lookup)
98     return Lookup->MinVersion;
99 
100   return 0;
101 }
102 
103 uint32_t
104 getSymbolicOperandMaxVersion(SPIRV::OperandCategory::OperandCategory Category,
105                              uint32_t Value) {
106   const SPIRV::SymbolicOperand *Lookup =
107       SPIRV::lookupSymbolicOperandByCategoryAndValue(Category, Value);
108 
109   if (Lookup)
110     return Lookup->MaxVersion;
111 
112   return 0;
113 }
114 
115 CapabilityList
116 getSymbolicOperandCapabilities(SPIRV::OperandCategory::OperandCategory Category,
117                                uint32_t Value) {
118   const SPIRV::CapabilityEntry *Capability =
119       SPIRV::lookupCapabilityByCategoryAndValue(Category, Value);
120 
121   CapabilityList Capabilities;
122   while (Capability && Capability->Category == Category &&
123          Capability->Value == Value) {
124     Capabilities.push_back(
125         static_cast<SPIRV::Capability::Capability>(Capability->ReqCapability));
126     ++Capability;
127   }
128 
129   return Capabilities;
130 }
131 
132 ExtensionList
133 getSymbolicOperandExtensions(SPIRV::OperandCategory::OperandCategory Category,
134                              uint32_t Value) {
135   const SPIRV::ExtensionEntry *Extension =
136       SPIRV::lookupExtensionByCategoryAndValue(Category, Value);
137 
138   ExtensionList Extensions;
139   while (Extension && Extension->Category == Category &&
140          Extension->Value == Value) {
141     Extensions.push_back(
142         static_cast<SPIRV::Extension::Extension>(Extension->ReqExtension));
143     ++Extension;
144   }
145 
146   return Extensions;
147 }
148 
149 std::string getLinkStringForBuiltIn(SPIRV::BuiltIn::BuiltIn BuiltInValue) {
150   const SPIRV::SymbolicOperand *Lookup =
151       SPIRV::lookupSymbolicOperandByCategoryAndValue(
152           SPIRV::OperandCategory::BuiltInOperand, BuiltInValue);
153 
154   if (Lookup)
155     return "__spirv_BuiltIn" + Lookup->Mnemonic.str();
156   return "UNKNOWN_BUILTIN";
157 }
158 
159 bool getSpirvBuiltInIdByName(llvm::StringRef Name,
160                              SPIRV::BuiltIn::BuiltIn &BI) {
161   const std::string Prefix = "__spirv_BuiltIn";
162   if (!Name.startswith(Prefix))
163     return false;
164 
165   const SPIRV::SymbolicOperand *Lookup =
166       SPIRV::lookupSymbolicOperandByCategoryAndMnemonic(
167           SPIRV::OperandCategory::BuiltInOperand,
168           Name.drop_front(Prefix.length()));
169 
170   if (!Lookup)
171     return false;
172 
173   BI = static_cast<SPIRV::BuiltIn::BuiltIn>(Lookup->Value);
174   return true;
175 }
176 
177 std::string getExtInstSetName(SPIRV::InstructionSet::InstructionSet Set) {
178   switch (Set) {
179   case SPIRV::InstructionSet::OpenCL_std:
180     return "OpenCL.std";
181   case SPIRV::InstructionSet::GLSL_std_450:
182     return "GLSL.std.450";
183   case SPIRV::InstructionSet::SPV_AMD_shader_trinary_minmax:
184     return "SPV_AMD_shader_trinary_minmax";
185   }
186   return "UNKNOWN_EXT_INST_SET";
187 }
188 
189 SPIRV::InstructionSet::InstructionSet
190 getExtInstSetFromString(std::string SetName) {
191   for (auto Set : {SPIRV::InstructionSet::GLSL_std_450,
192                    SPIRV::InstructionSet::OpenCL_std}) {
193     if (SetName == getExtInstSetName(Set))
194       return Set;
195   }
196   llvm_unreachable("UNKNOWN_EXT_INST_SET");
197 }
198 
199 std::string getExtInstName(SPIRV::InstructionSet::InstructionSet Set,
200                            uint32_t InstructionNumber) {
201   const SPIRV::ExtendedBuiltin *Lookup =
202       SPIRV::lookupExtendedBuiltinBySetAndNumber(
203           SPIRV::InstructionSet::OpenCL_std, InstructionNumber);
204 
205   if (!Lookup)
206     return "UNKNOWN_EXT_INST";
207 
208   return Lookup->Name.str();
209 }
210 } // namespace llvm
211