xref: /aosp_15_r20/external/angle/third_party/spirv-tools/src/source/assembly_grammar.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 // Copyright (c) 2015-2016 The Khronos Group Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "source/assembly_grammar.h"
16 
17 #include <algorithm>
18 #include <cassert>
19 #include <cstring>
20 
21 #include "source/ext_inst.h"
22 #include "source/opcode.h"
23 #include "source/operand.h"
24 #include "source/spirv_target_env.h"
25 #include "source/table.h"
26 
27 namespace spvtools {
28 namespace {
29 
30 /// @brief Parses a mask expression string for the given operand type.
31 ///
32 /// A mask expression is a sequence of one or more terms separated by '|',
33 /// where each term a named enum value for the given type.  No whitespace
34 /// is permitted.
35 ///
36 /// On success, the value is written to pValue.
37 ///
38 /// @param[in] operandTable operand lookup table
39 /// @param[in] type of the operand
40 /// @param[in] textValue word of text to be parsed
41 /// @param[out] pValue where the resulting value is written
42 ///
43 /// @return result code
spvTextParseMaskOperand(spv_target_env env,const spv_operand_table operandTable,const spv_operand_type_t type,const char * textValue,uint32_t * pValue)44 spv_result_t spvTextParseMaskOperand(spv_target_env env,
45                                      const spv_operand_table operandTable,
46                                      const spv_operand_type_t type,
47                                      const char* textValue, uint32_t* pValue) {
48   if (textValue == nullptr) return SPV_ERROR_INVALID_TEXT;
49   size_t text_length = strlen(textValue);
50   if (text_length == 0) return SPV_ERROR_INVALID_TEXT;
51   const char* text_end = textValue + text_length;
52 
53   // We only support mask expressions in ASCII, so the separator value is a
54   // char.
55   const char separator = '|';
56 
57   // Accumulate the result by interpreting one word at a time, scanning
58   // from left to right.
59   uint32_t value = 0;
60   const char* begin = textValue;  // The left end of the current word.
61   const char* end = nullptr;  // One character past the end of the current word.
62   do {
63     end = std::find(begin, text_end, separator);
64 
65     spv_operand_desc entry = nullptr;
66     if (auto error = spvOperandTableNameLookup(env, operandTable, type, begin,
67                                                end - begin, &entry)) {
68       return error;
69     }
70     value |= entry->value;
71 
72     // Advance to the next word by skipping over the separator.
73     begin = end + 1;
74   } while (end != text_end);
75 
76   *pValue = value;
77   return SPV_SUCCESS;
78 }
79 
80 // Associates an opcode with its name.
81 struct SpecConstantOpcodeEntry {
82   spv::Op opcode;
83   const char* name;
84 };
85 
86 // All the opcodes allowed as the operation for OpSpecConstantOp.
87 // The name does not have the usual "Op" prefix. For example opcode
88 // spv::Op::IAdd is associated with the name "IAdd".
89 //
90 // clang-format off
91 #define CASE(NAME) { spv::Op::Op##NAME, #NAME }
92 const SpecConstantOpcodeEntry kOpSpecConstantOpcodes[] = {
93     // Conversion
94     CASE(SConvert),
95     CASE(FConvert),
96     CASE(ConvertFToS),
97     CASE(ConvertSToF),
98     CASE(ConvertFToU),
99     CASE(ConvertUToF),
100     CASE(UConvert),
101     CASE(ConvertPtrToU),
102     CASE(ConvertUToPtr),
103     CASE(GenericCastToPtr),
104     CASE(PtrCastToGeneric),
105     CASE(Bitcast),
106     CASE(QuantizeToF16),
107     // Arithmetic
108     CASE(SNegate),
109     CASE(Not),
110     CASE(IAdd),
111     CASE(ISub),
112     CASE(IMul),
113     CASE(UDiv),
114     CASE(SDiv),
115     CASE(UMod),
116     CASE(SRem),
117     CASE(SMod),
118     CASE(ShiftRightLogical),
119     CASE(ShiftRightArithmetic),
120     CASE(ShiftLeftLogical),
121     CASE(BitwiseOr),
122     CASE(BitwiseAnd),
123     CASE(BitwiseXor),
124     CASE(FNegate),
125     CASE(FAdd),
126     CASE(FSub),
127     CASE(FMul),
128     CASE(FDiv),
129     CASE(FRem),
130     CASE(FMod),
131     // Composite
132     CASE(VectorShuffle),
133     CASE(CompositeExtract),
134     CASE(CompositeInsert),
135     // Logical
136     CASE(LogicalOr),
137     CASE(LogicalAnd),
138     CASE(LogicalNot),
139     CASE(LogicalEqual),
140     CASE(LogicalNotEqual),
141     CASE(Select),
142     // Comparison
143     CASE(IEqual),
144     CASE(INotEqual),
145     CASE(ULessThan),
146     CASE(SLessThan),
147     CASE(UGreaterThan),
148     CASE(SGreaterThan),
149     CASE(ULessThanEqual),
150     CASE(SLessThanEqual),
151     CASE(UGreaterThanEqual),
152     CASE(SGreaterThanEqual),
153     // Memory
154     CASE(AccessChain),
155     CASE(InBoundsAccessChain),
156     CASE(PtrAccessChain),
157     CASE(InBoundsPtrAccessChain),
158     CASE(CooperativeMatrixLengthNV),
159     CASE(CooperativeMatrixLengthKHR)
160 };
161 
162 // The 60 is determined by counting the opcodes listed in the spec.
163 static_assert(61 == sizeof(kOpSpecConstantOpcodes)/sizeof(kOpSpecConstantOpcodes[0]),
164               "OpSpecConstantOp opcode table is incomplete");
165 #undef CASE
166 // clang-format on
167 
168 const size_t kNumOpSpecConstantOpcodes =
169     sizeof(kOpSpecConstantOpcodes) / sizeof(kOpSpecConstantOpcodes[0]);
170 
171 }  // namespace
172 
isValid() const173 bool AssemblyGrammar::isValid() const {
174   return operandTable_ && opcodeTable_ && extInstTable_;
175 }
176 
filterCapsAgainstTargetEnv(const spv::Capability * cap_array,uint32_t count) const177 CapabilitySet AssemblyGrammar::filterCapsAgainstTargetEnv(
178     const spv::Capability* cap_array, uint32_t count) const {
179   CapabilitySet cap_set;
180   const auto version = spvVersionForTargetEnv(target_env_);
181   for (uint32_t i = 0; i < count; ++i) {
182     spv_operand_desc entry = {};
183     if (SPV_SUCCESS == lookupOperand(SPV_OPERAND_TYPE_CAPABILITY,
184                                      static_cast<uint32_t>(cap_array[i]),
185                                      &entry)) {
186       // This token is visible in this environment if it's in an appropriate
187       // core version, or it is enabled by a capability or an extension.
188       if ((version >= entry->minVersion && version <= entry->lastVersion) ||
189           entry->numExtensions > 0u || entry->numCapabilities > 0u) {
190         cap_set.insert(cap_array[i]);
191       }
192     }
193   }
194   return cap_set;
195 }
196 
lookupOpcode(const char * name,spv_opcode_desc * desc) const197 spv_result_t AssemblyGrammar::lookupOpcode(const char* name,
198                                            spv_opcode_desc* desc) const {
199   return spvOpcodeTableNameLookup(target_env_, opcodeTable_, name, desc);
200 }
201 
lookupOpcode(spv::Op opcode,spv_opcode_desc * desc) const202 spv_result_t AssemblyGrammar::lookupOpcode(spv::Op opcode,
203                                            spv_opcode_desc* desc) const {
204   return spvOpcodeTableValueLookup(target_env_, opcodeTable_, opcode, desc);
205 }
206 
lookupOperand(spv_operand_type_t type,const char * name,size_t name_len,spv_operand_desc * desc) const207 spv_result_t AssemblyGrammar::lookupOperand(spv_operand_type_t type,
208                                             const char* name, size_t name_len,
209                                             spv_operand_desc* desc) const {
210   return spvOperandTableNameLookup(target_env_, operandTable_, type, name,
211                                    name_len, desc);
212 }
213 
lookupOperand(spv_operand_type_t type,uint32_t operand,spv_operand_desc * desc) const214 spv_result_t AssemblyGrammar::lookupOperand(spv_operand_type_t type,
215                                             uint32_t operand,
216                                             spv_operand_desc* desc) const {
217   return spvOperandTableValueLookup(target_env_, operandTable_, type, operand,
218                                     desc);
219 }
220 
lookupSpecConstantOpcode(const char * name,spv::Op * opcode) const221 spv_result_t AssemblyGrammar::lookupSpecConstantOpcode(const char* name,
222                                                        spv::Op* opcode) const {
223   const auto* last = kOpSpecConstantOpcodes + kNumOpSpecConstantOpcodes;
224   const auto* found =
225       std::find_if(kOpSpecConstantOpcodes, last,
226                    [name](const SpecConstantOpcodeEntry& entry) {
227                      return 0 == strcmp(name, entry.name);
228                    });
229   if (found == last) return SPV_ERROR_INVALID_LOOKUP;
230   *opcode = found->opcode;
231   return SPV_SUCCESS;
232 }
233 
lookupSpecConstantOpcode(spv::Op opcode) const234 spv_result_t AssemblyGrammar::lookupSpecConstantOpcode(spv::Op opcode) const {
235   const auto* last = kOpSpecConstantOpcodes + kNumOpSpecConstantOpcodes;
236   const auto* found =
237       std::find_if(kOpSpecConstantOpcodes, last,
238                    [opcode](const SpecConstantOpcodeEntry& entry) {
239                      return opcode == entry.opcode;
240                    });
241   if (found == last) return SPV_ERROR_INVALID_LOOKUP;
242   return SPV_SUCCESS;
243 }
244 
parseMaskOperand(const spv_operand_type_t type,const char * textValue,uint32_t * pValue) const245 spv_result_t AssemblyGrammar::parseMaskOperand(const spv_operand_type_t type,
246                                                const char* textValue,
247                                                uint32_t* pValue) const {
248   return spvTextParseMaskOperand(target_env_, operandTable_, type, textValue,
249                                  pValue);
250 }
lookupExtInst(spv_ext_inst_type_t type,const char * textValue,spv_ext_inst_desc * extInst) const251 spv_result_t AssemblyGrammar::lookupExtInst(spv_ext_inst_type_t type,
252                                             const char* textValue,
253                                             spv_ext_inst_desc* extInst) const {
254   return spvExtInstTableNameLookup(extInstTable_, type, textValue, extInst);
255 }
256 
lookupExtInst(spv_ext_inst_type_t type,uint32_t firstWord,spv_ext_inst_desc * extInst) const257 spv_result_t AssemblyGrammar::lookupExtInst(spv_ext_inst_type_t type,
258                                             uint32_t firstWord,
259                                             spv_ext_inst_desc* extInst) const {
260   return spvExtInstTableValueLookup(extInstTable_, type, firstWord, extInst);
261 }
262 
pushOperandTypesForMask(const spv_operand_type_t type,const uint32_t mask,spv_operand_pattern_t * pattern) const263 void AssemblyGrammar::pushOperandTypesForMask(
264     const spv_operand_type_t type, const uint32_t mask,
265     spv_operand_pattern_t* pattern) const {
266   spvPushOperandTypesForMask(target_env_, operandTable_, type, mask, pattern);
267 }
268 
269 }  // namespace spvtools
270