xref: /aosp_15_r20/external/angle/third_party/spirv-tools/src/source/operand.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 // Copyright (c) 2015-2020 The Khronos Group Inc.
2 // Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights
3 // reserved.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 
17 #include "source/operand.h"
18 
19 #include <assert.h>
20 #include <string.h>
21 
22 #include <algorithm>
23 
24 #include "DebugInfo.h"
25 #include "OpenCLDebugInfo100.h"
26 #include "source/macro.h"
27 #include "source/opcode.h"
28 #include "source/spirv_constant.h"
29 
30 // For now, assume unified1 contains up to SPIR-V 1.3 and no later
31 // SPIR-V version.
32 // TODO(dneto): Make one set of tables, but with version tags on a
33 // per-item basis. https://github.com/KhronosGroup/SPIRV-Tools/issues/1195
34 
35 #include "operand.kinds-unified1.inc"
36 #include "spirv-tools/libspirv.h"
37 
38 static const spv_operand_table_t kOperandTable = {
39     ARRAY_SIZE(pygen_variable_OperandInfoTable),
40     pygen_variable_OperandInfoTable};
41 
spvOperandTableGet(spv_operand_table * pOperandTable,spv_target_env)42 spv_result_t spvOperandTableGet(spv_operand_table* pOperandTable,
43                                 spv_target_env) {
44   if (!pOperandTable) return SPV_ERROR_INVALID_POINTER;
45 
46   *pOperandTable = &kOperandTable;
47   return SPV_SUCCESS;
48 }
49 
spvOperandTableNameLookup(spv_target_env,const spv_operand_table table,const spv_operand_type_t type,const char * name,const size_t nameLength,spv_operand_desc * pEntry)50 spv_result_t spvOperandTableNameLookup(spv_target_env,
51                                        const spv_operand_table table,
52                                        const spv_operand_type_t type,
53                                        const char* name,
54                                        const size_t nameLength,
55                                        spv_operand_desc* pEntry) {
56   if (!table) return SPV_ERROR_INVALID_TABLE;
57   if (!name || !pEntry) return SPV_ERROR_INVALID_POINTER;
58 
59   for (uint64_t typeIndex = 0; typeIndex < table->count; ++typeIndex) {
60     const auto& group = table->types[typeIndex];
61     if (type != group.type) continue;
62     for (uint64_t index = 0; index < group.count; ++index) {
63       const auto& entry = group.entries[index];
64       // We consider the current operand as available as long as
65       // it is in the grammar.  It might not be *valid* to use,
66       // but that should be checked by the validator, not by parsing.
67       //
68       // Exact match case
69       if (nameLength == strlen(entry.name) &&
70           !strncmp(entry.name, name, nameLength)) {
71         *pEntry = &entry;
72         return SPV_SUCCESS;
73       }
74 
75       // Check the aliases. Ideally we would have a version of the table sorted
76       // by name and then we could iterate between the lower and upper bounds to
77       // restrict the amount comparisons. Fortunately, name-based lookups are
78       // mostly restricted to the assembler.
79       if (entry.numAliases > 0) {
80         for (uint32_t aliasIndex = 0; aliasIndex < entry.numAliases;
81              aliasIndex++) {
82           const auto alias = entry.aliases[aliasIndex];
83           const size_t aliasLength = strlen(alias);
84           if (nameLength == aliasLength && !strncmp(name, alias, nameLength)) {
85             *pEntry = &entry;
86             return SPV_SUCCESS;
87           }
88         }
89       }
90     }
91   }
92 
93   return SPV_ERROR_INVALID_LOOKUP;
94 }
95 
spvOperandTableValueLookup(spv_target_env,const spv_operand_table table,const spv_operand_type_t type,const uint32_t value,spv_operand_desc * pEntry)96 spv_result_t spvOperandTableValueLookup(spv_target_env,
97                                         const spv_operand_table table,
98                                         const spv_operand_type_t type,
99                                         const uint32_t value,
100                                         spv_operand_desc* pEntry) {
101   if (!table) return SPV_ERROR_INVALID_TABLE;
102   if (!pEntry) return SPV_ERROR_INVALID_POINTER;
103 
104   spv_operand_desc_t needle = {"", value,   0,  nullptr, 0,  nullptr,
105                                0,  nullptr, {}, ~0u,     ~0u};
106 
107   auto comp = [](const spv_operand_desc_t& lhs, const spv_operand_desc_t& rhs) {
108     return lhs.value < rhs.value;
109   };
110 
111   for (uint64_t typeIndex = 0; typeIndex < table->count; ++typeIndex) {
112     const auto& group = table->types[typeIndex];
113     if (type != group.type) continue;
114 
115     const auto beg = group.entries;
116     const auto end = group.entries + group.count;
117 
118     // Assumes the underlying table is already sorted ascendingly according to
119     // opcode value.
120     auto it = std::lower_bound(beg, end, needle, comp);
121     if (it != end && it->value == value) {
122       // The current operand is considered available as long as
123       // it is in the grammar.  It might not be *valid* to use,
124       // but that should be checked by the validator, not by parsing.
125       *pEntry = it;
126       return SPV_SUCCESS;
127     }
128   }
129 
130   return SPV_ERROR_INVALID_LOOKUP;
131 }
132 
spvOperandTypeStr(spv_operand_type_t type)133 const char* spvOperandTypeStr(spv_operand_type_t type) {
134   switch (type) {
135     case SPV_OPERAND_TYPE_ID:
136     case SPV_OPERAND_TYPE_OPTIONAL_ID:
137       return "ID";
138     case SPV_OPERAND_TYPE_TYPE_ID:
139       return "type ID";
140     case SPV_OPERAND_TYPE_RESULT_ID:
141       return "result ID";
142     case SPV_OPERAND_TYPE_LITERAL_INTEGER:
143     case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER:
144     case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_NUMBER:
145     case SPV_OPERAND_TYPE_LITERAL_FLOAT:
146       return "literal number";
147     case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER:
148       return "possibly multi-word literal integer";
149     case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER:
150       return "possibly multi-word literal number";
151     case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER:
152       return "extension instruction number";
153     case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER:
154       return "OpSpecConstantOp opcode";
155     case SPV_OPERAND_TYPE_LITERAL_STRING:
156     case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING:
157       return "literal string";
158     case SPV_OPERAND_TYPE_SOURCE_LANGUAGE:
159       return "source language";
160     case SPV_OPERAND_TYPE_EXECUTION_MODEL:
161       return "execution model";
162     case SPV_OPERAND_TYPE_ADDRESSING_MODEL:
163       return "addressing model";
164     case SPV_OPERAND_TYPE_MEMORY_MODEL:
165       return "memory model";
166     case SPV_OPERAND_TYPE_EXECUTION_MODE:
167       return "execution mode";
168     case SPV_OPERAND_TYPE_STORAGE_CLASS:
169       return "storage class";
170     case SPV_OPERAND_TYPE_DIMENSIONALITY:
171       return "dimensionality";
172     case SPV_OPERAND_TYPE_SAMPLER_ADDRESSING_MODE:
173       return "sampler addressing mode";
174     case SPV_OPERAND_TYPE_SAMPLER_FILTER_MODE:
175       return "sampler filter mode";
176     case SPV_OPERAND_TYPE_SAMPLER_IMAGE_FORMAT:
177       return "image format";
178     case SPV_OPERAND_TYPE_FP_FAST_MATH_MODE:
179       return "floating-point fast math mode";
180     case SPV_OPERAND_TYPE_FP_ROUNDING_MODE:
181       return "floating-point rounding mode";
182     case SPV_OPERAND_TYPE_LINKAGE_TYPE:
183       return "linkage type";
184     case SPV_OPERAND_TYPE_ACCESS_QUALIFIER:
185     case SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER:
186       return "access qualifier";
187     case SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE:
188       return "function parameter attribute";
189     case SPV_OPERAND_TYPE_DECORATION:
190       return "decoration";
191     case SPV_OPERAND_TYPE_BUILT_IN:
192       return "built-in";
193     case SPV_OPERAND_TYPE_SELECTION_CONTROL:
194       return "selection control";
195     case SPV_OPERAND_TYPE_LOOP_CONTROL:
196       return "loop control";
197     case SPV_OPERAND_TYPE_FUNCTION_CONTROL:
198       return "function control";
199     case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID:
200       return "memory semantics ID";
201     case SPV_OPERAND_TYPE_MEMORY_ACCESS:
202     case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS:
203       return "memory access";
204     case SPV_OPERAND_TYPE_FRAGMENT_SHADING_RATE:
205       return "shading rate";
206     case SPV_OPERAND_TYPE_SCOPE_ID:
207       return "scope ID";
208     case SPV_OPERAND_TYPE_GROUP_OPERATION:
209       return "group operation";
210     case SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS:
211       return "kernel enqeue flags";
212     case SPV_OPERAND_TYPE_KERNEL_PROFILING_INFO:
213       return "kernel profiling info";
214     case SPV_OPERAND_TYPE_CAPABILITY:
215       return "capability";
216     case SPV_OPERAND_TYPE_RAY_FLAGS:
217       return "ray flags";
218     case SPV_OPERAND_TYPE_RAY_QUERY_INTERSECTION:
219       return "ray query intersection";
220     case SPV_OPERAND_TYPE_RAY_QUERY_COMMITTED_INTERSECTION_TYPE:
221       return "ray query committed intersection type";
222     case SPV_OPERAND_TYPE_RAY_QUERY_CANDIDATE_INTERSECTION_TYPE:
223       return "ray query candidate intersection type";
224     case SPV_OPERAND_TYPE_PACKED_VECTOR_FORMAT:
225     case SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT:
226       return "packed vector format";
227     case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_OPERANDS:
228     case SPV_OPERAND_TYPE_OPTIONAL_COOPERATIVE_MATRIX_OPERANDS:
229       return "cooperative matrix operands";
230     case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_LAYOUT:
231       return "cooperative matrix layout";
232     case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_USE:
233       return "cooperative matrix use";
234     case SPV_OPERAND_TYPE_TENSOR_CLAMP_MODE:
235       return "tensor clamp mode";
236     case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_REDUCE:
237       return "cooperative matrix reduce";
238     case SPV_OPERAND_TYPE_TENSOR_ADDRESSING_OPERANDS:
239       return "tensor addressing operands";
240     case SPV_OPERAND_TYPE_INITIALIZATION_MODE_QUALIFIER:
241       return "initialization mode qualifier";
242     case SPV_OPERAND_TYPE_HOST_ACCESS_QUALIFIER:
243       return "host access qualifier";
244     case SPV_OPERAND_TYPE_LOAD_CACHE_CONTROL:
245       return "load cache control";
246     case SPV_OPERAND_TYPE_STORE_CACHE_CONTROL:
247       return "store cache control";
248     case SPV_OPERAND_TYPE_NAMED_MAXIMUM_NUMBER_OF_REGISTERS:
249       return "named maximum number of registers";
250     case SPV_OPERAND_TYPE_RAW_ACCESS_CHAIN_OPERANDS:
251     case SPV_OPERAND_TYPE_OPTIONAL_RAW_ACCESS_CHAIN_OPERANDS:
252       return "raw access chain operands";
253     case SPV_OPERAND_TYPE_IMAGE:
254     case SPV_OPERAND_TYPE_OPTIONAL_IMAGE:
255       return "image";
256     case SPV_OPERAND_TYPE_OPTIONAL_CIV:
257       return "context-insensitive value";
258     case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS:
259       return "debug info flags";
260     case SPV_OPERAND_TYPE_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING:
261       return "debug base type encoding";
262     case SPV_OPERAND_TYPE_DEBUG_COMPOSITE_TYPE:
263       return "debug composite type";
264     case SPV_OPERAND_TYPE_DEBUG_TYPE_QUALIFIER:
265       return "debug type qualifier";
266     case SPV_OPERAND_TYPE_DEBUG_OPERATION:
267       return "debug operation";
268     case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS:
269       return "OpenCL.DebugInfo.100 debug info flags";
270     case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING:
271       return "OpenCL.DebugInfo.100 debug base type encoding";
272     case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_COMPOSITE_TYPE:
273       return "OpenCL.DebugInfo.100 debug composite type";
274     case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_TYPE_QUALIFIER:
275       return "OpenCL.DebugInfo.100 debug type qualifier";
276     case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION:
277       return "OpenCL.DebugInfo.100 debug operation";
278     case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_IMPORTED_ENTITY:
279       return "OpenCL.DebugInfo.100 debug imported entity";
280     case SPV_OPERAND_TYPE_FPENCODING:
281     case SPV_OPERAND_TYPE_OPTIONAL_FPENCODING:
282       return "FP encoding";
283 
284     // The next values are for values returned from an instruction, not actually
285     // an operand.  So the specific strings don't matter.  But let's add them
286     // for completeness and ease of testing.
287     case SPV_OPERAND_TYPE_IMAGE_CHANNEL_ORDER:
288       return "image channel order";
289     case SPV_OPERAND_TYPE_IMAGE_CHANNEL_DATA_TYPE:
290       return "image channel data type";
291 
292     case SPV_OPERAND_TYPE_FPDENORM_MODE:
293       return "FP denorm mode";
294     case SPV_OPERAND_TYPE_FPOPERATION_MODE:
295       return "FP operation mode";
296     case SPV_OPERAND_TYPE_QUANTIZATION_MODES:
297       return "quantization mode";
298     case SPV_OPERAND_TYPE_OVERFLOW_MODES:
299       return "overflow mode";
300 
301     case SPV_OPERAND_TYPE_NONE:
302       return "NONE";
303     default:
304       break;
305   }
306   return "unknown";
307 }
308 
spvPushOperandTypes(const spv_operand_type_t * types,spv_operand_pattern_t * pattern)309 void spvPushOperandTypes(const spv_operand_type_t* types,
310                          spv_operand_pattern_t* pattern) {
311   const spv_operand_type_t* endTypes;
312   for (endTypes = types; *endTypes != SPV_OPERAND_TYPE_NONE; ++endTypes) {
313   }
314 
315   while (endTypes-- != types) {
316     pattern->push_back(*endTypes);
317   }
318 }
319 
spvPushOperandTypesForMask(spv_target_env env,const spv_operand_table operandTable,const spv_operand_type_t type,const uint32_t mask,spv_operand_pattern_t * pattern)320 void spvPushOperandTypesForMask(spv_target_env env,
321                                 const spv_operand_table operandTable,
322                                 const spv_operand_type_t type,
323                                 const uint32_t mask,
324                                 spv_operand_pattern_t* pattern) {
325   // Scan from highest bits to lowest bits because we will append in LIFO
326   // fashion, and we need the operands for lower order bits to be consumed first
327   for (uint32_t candidate_bit = (1u << 31u); candidate_bit;
328        candidate_bit >>= 1) {
329     if (candidate_bit & mask) {
330       spv_operand_desc entry = nullptr;
331       if (SPV_SUCCESS == spvOperandTableValueLookup(env, operandTable, type,
332                                                     candidate_bit, &entry)) {
333         spvPushOperandTypes(entry->operandTypes, pattern);
334       }
335     }
336   }
337 }
338 
spvOperandIsConcrete(spv_operand_type_t type)339 bool spvOperandIsConcrete(spv_operand_type_t type) {
340   if (spvIsIdType(type) || spvOperandIsConcreteMask(type)) {
341     return true;
342   }
343   switch (type) {
344     case SPV_OPERAND_TYPE_LITERAL_INTEGER:
345     case SPV_OPERAND_TYPE_LITERAL_FLOAT:
346     case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER:
347     case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER:
348     case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER:
349     case SPV_OPERAND_TYPE_LITERAL_STRING:
350     case SPV_OPERAND_TYPE_SOURCE_LANGUAGE:
351     case SPV_OPERAND_TYPE_EXECUTION_MODEL:
352     case SPV_OPERAND_TYPE_ADDRESSING_MODEL:
353     case SPV_OPERAND_TYPE_MEMORY_MODEL:
354     case SPV_OPERAND_TYPE_EXECUTION_MODE:
355     case SPV_OPERAND_TYPE_STORAGE_CLASS:
356     case SPV_OPERAND_TYPE_DIMENSIONALITY:
357     case SPV_OPERAND_TYPE_SAMPLER_ADDRESSING_MODE:
358     case SPV_OPERAND_TYPE_SAMPLER_FILTER_MODE:
359     case SPV_OPERAND_TYPE_SAMPLER_IMAGE_FORMAT:
360     case SPV_OPERAND_TYPE_IMAGE_CHANNEL_ORDER:
361     case SPV_OPERAND_TYPE_IMAGE_CHANNEL_DATA_TYPE:
362     case SPV_OPERAND_TYPE_FP_ROUNDING_MODE:
363     case SPV_OPERAND_TYPE_LINKAGE_TYPE:
364     case SPV_OPERAND_TYPE_ACCESS_QUALIFIER:
365     case SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE:
366     case SPV_OPERAND_TYPE_DECORATION:
367     case SPV_OPERAND_TYPE_BUILT_IN:
368     case SPV_OPERAND_TYPE_GROUP_OPERATION:
369     case SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS:
370     case SPV_OPERAND_TYPE_KERNEL_PROFILING_INFO:
371     case SPV_OPERAND_TYPE_CAPABILITY:
372     case SPV_OPERAND_TYPE_RAY_FLAGS:
373     case SPV_OPERAND_TYPE_RAY_QUERY_INTERSECTION:
374     case SPV_OPERAND_TYPE_RAY_QUERY_COMMITTED_INTERSECTION_TYPE:
375     case SPV_OPERAND_TYPE_RAY_QUERY_CANDIDATE_INTERSECTION_TYPE:
376     case SPV_OPERAND_TYPE_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING:
377     case SPV_OPERAND_TYPE_DEBUG_COMPOSITE_TYPE:
378     case SPV_OPERAND_TYPE_DEBUG_TYPE_QUALIFIER:
379     case SPV_OPERAND_TYPE_DEBUG_OPERATION:
380     case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING:
381     case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_COMPOSITE_TYPE:
382     case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_TYPE_QUALIFIER:
383     case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION:
384     case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_IMPORTED_ENTITY:
385     case SPV_OPERAND_TYPE_FPDENORM_MODE:
386     case SPV_OPERAND_TYPE_FPOPERATION_MODE:
387     case SPV_OPERAND_TYPE_QUANTIZATION_MODES:
388     case SPV_OPERAND_TYPE_OVERFLOW_MODES:
389     case SPV_OPERAND_TYPE_PACKED_VECTOR_FORMAT:
390     case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_LAYOUT:
391     case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_USE:
392     case SPV_OPERAND_TYPE_INITIALIZATION_MODE_QUALIFIER:
393     case SPV_OPERAND_TYPE_HOST_ACCESS_QUALIFIER:
394     case SPV_OPERAND_TYPE_LOAD_CACHE_CONTROL:
395     case SPV_OPERAND_TYPE_STORE_CACHE_CONTROL:
396     case SPV_OPERAND_TYPE_NAMED_MAXIMUM_NUMBER_OF_REGISTERS:
397     case SPV_OPERAND_TYPE_FPENCODING:
398     case SPV_OPERAND_TYPE_TENSOR_CLAMP_MODE:
399       return true;
400     default:
401       break;
402   }
403   return false;
404 }
405 
spvOperandIsConcreteMask(spv_operand_type_t type)406 bool spvOperandIsConcreteMask(spv_operand_type_t type) {
407   switch (type) {
408     case SPV_OPERAND_TYPE_IMAGE:
409     case SPV_OPERAND_TYPE_FP_FAST_MATH_MODE:
410     case SPV_OPERAND_TYPE_SELECTION_CONTROL:
411     case SPV_OPERAND_TYPE_LOOP_CONTROL:
412     case SPV_OPERAND_TYPE_FUNCTION_CONTROL:
413     case SPV_OPERAND_TYPE_MEMORY_ACCESS:
414     case SPV_OPERAND_TYPE_FRAGMENT_SHADING_RATE:
415     case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS:
416     case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS:
417     case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_OPERANDS:
418     case SPV_OPERAND_TYPE_RAW_ACCESS_CHAIN_OPERANDS:
419     case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_REDUCE:
420     case SPV_OPERAND_TYPE_TENSOR_ADDRESSING_OPERANDS:
421       return true;
422     default:
423       break;
424   }
425   return false;
426 }
427 
spvOperandIsOptional(spv_operand_type_t type)428 bool spvOperandIsOptional(spv_operand_type_t type) {
429   switch (type) {
430     case SPV_OPERAND_TYPE_OPTIONAL_ID:
431     case SPV_OPERAND_TYPE_OPTIONAL_IMAGE:
432     case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS:
433     case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER:
434     case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_NUMBER:
435     case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER:
436     case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING:
437     case SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER:
438     case SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT:
439     case SPV_OPERAND_TYPE_OPTIONAL_COOPERATIVE_MATRIX_OPERANDS:
440     case SPV_OPERAND_TYPE_OPTIONAL_CIV:
441     case SPV_OPERAND_TYPE_OPTIONAL_RAW_ACCESS_CHAIN_OPERANDS:
442     case SPV_OPERAND_TYPE_OPTIONAL_FPENCODING:
443       return true;
444     default:
445       break;
446   }
447   // Any variable operand is also optional.
448   return spvOperandIsVariable(type);
449 }
450 
spvOperandIsVariable(spv_operand_type_t type)451 bool spvOperandIsVariable(spv_operand_type_t type) {
452   switch (type) {
453     case SPV_OPERAND_TYPE_VARIABLE_ID:
454     case SPV_OPERAND_TYPE_VARIABLE_LITERAL_INTEGER:
455     case SPV_OPERAND_TYPE_VARIABLE_LITERAL_INTEGER_ID:
456     case SPV_OPERAND_TYPE_VARIABLE_ID_LITERAL_INTEGER:
457       return true;
458     default:
459       break;
460   }
461   return false;
462 }
463 
spvExpandOperandSequenceOnce(spv_operand_type_t type,spv_operand_pattern_t * pattern)464 bool spvExpandOperandSequenceOnce(spv_operand_type_t type,
465                                   spv_operand_pattern_t* pattern) {
466   switch (type) {
467     case SPV_OPERAND_TYPE_VARIABLE_ID:
468       pattern->push_back(type);
469       pattern->push_back(SPV_OPERAND_TYPE_OPTIONAL_ID);
470       return true;
471     case SPV_OPERAND_TYPE_VARIABLE_LITERAL_INTEGER:
472       pattern->push_back(type);
473       pattern->push_back(SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER);
474       return true;
475     case SPV_OPERAND_TYPE_VARIABLE_LITERAL_INTEGER_ID:
476       // Represents Zero or more (Literal number, Id) pairs,
477       // where the literal number must be a scalar integer.
478       pattern->push_back(type);
479       pattern->push_back(SPV_OPERAND_TYPE_ID);
480       pattern->push_back(SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER);
481       return true;
482     case SPV_OPERAND_TYPE_VARIABLE_ID_LITERAL_INTEGER:
483       // Represents Zero or more (Id, Literal number) pairs.
484       pattern->push_back(type);
485       pattern->push_back(SPV_OPERAND_TYPE_LITERAL_INTEGER);
486       pattern->push_back(SPV_OPERAND_TYPE_OPTIONAL_ID);
487       return true;
488     default:
489       break;
490   }
491   return false;
492 }
493 
spvTakeFirstMatchableOperand(spv_operand_pattern_t * pattern)494 spv_operand_type_t spvTakeFirstMatchableOperand(
495     spv_operand_pattern_t* pattern) {
496   assert(!pattern->empty());
497   spv_operand_type_t result;
498   do {
499     result = pattern->back();
500     pattern->pop_back();
501   } while (spvExpandOperandSequenceOnce(result, pattern));
502   return result;
503 }
504 
spvAlternatePatternFollowingImmediate(const spv_operand_pattern_t & pattern)505 spv_operand_pattern_t spvAlternatePatternFollowingImmediate(
506     const spv_operand_pattern_t& pattern) {
507   auto it =
508       std::find(pattern.crbegin(), pattern.crend(), SPV_OPERAND_TYPE_RESULT_ID);
509   if (it != pattern.crend()) {
510     spv_operand_pattern_t alternatePattern(it - pattern.crbegin() + 2,
511                                            SPV_OPERAND_TYPE_OPTIONAL_CIV);
512     alternatePattern[1] = SPV_OPERAND_TYPE_RESULT_ID;
513     return alternatePattern;
514   }
515 
516   // No result-id found, so just expect CIVs.
517   return {SPV_OPERAND_TYPE_OPTIONAL_CIV};
518 }
519 
spvIsIdType(spv_operand_type_t type)520 bool spvIsIdType(spv_operand_type_t type) {
521   switch (type) {
522     case SPV_OPERAND_TYPE_ID:
523     case SPV_OPERAND_TYPE_TYPE_ID:
524     case SPV_OPERAND_TYPE_RESULT_ID:
525     case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID:
526     case SPV_OPERAND_TYPE_SCOPE_ID:
527       return true;
528     default:
529       return false;
530   }
531 }
532 
spvIsInIdType(spv_operand_type_t type)533 bool spvIsInIdType(spv_operand_type_t type) {
534   if (!spvIsIdType(type)) {
535     // If it is not an ID it cannot be an input ID.
536     return false;
537   }
538   switch (type) {
539     // Deny non-input IDs.
540     case SPV_OPERAND_TYPE_TYPE_ID:
541     case SPV_OPERAND_TYPE_RESULT_ID:
542       return false;
543     default:
544       return true;
545   }
546 }
547 
spvOperandCanBeForwardDeclaredFunction(spv::Op opcode)548 std::function<bool(unsigned)> spvOperandCanBeForwardDeclaredFunction(
549     spv::Op opcode) {
550   std::function<bool(unsigned index)> out;
551   if (spvOpcodeGeneratesType(opcode)) {
552     // All types can use forward pointers.
553     out = [](unsigned) { return true; };
554     return out;
555   }
556   switch (opcode) {
557     case spv::Op::OpExecutionMode:
558     case spv::Op::OpExecutionModeId:
559     case spv::Op::OpEntryPoint:
560     case spv::Op::OpName:
561     case spv::Op::OpMemberName:
562     case spv::Op::OpSelectionMerge:
563     case spv::Op::OpDecorate:
564     case spv::Op::OpMemberDecorate:
565     case spv::Op::OpDecorateId:
566     case spv::Op::OpDecorateStringGOOGLE:
567     case spv::Op::OpMemberDecorateStringGOOGLE:
568     case spv::Op::OpBranch:
569     case spv::Op::OpLoopMerge:
570       out = [](unsigned) { return true; };
571       break;
572     case spv::Op::OpGroupDecorate:
573     case spv::Op::OpGroupMemberDecorate:
574     case spv::Op::OpBranchConditional:
575     case spv::Op::OpSwitch:
576       out = [](unsigned index) { return index != 0; };
577       break;
578 
579     case spv::Op::OpFunctionCall:
580       // The Function parameter.
581       out = [](unsigned index) { return index == 2; };
582       break;
583 
584     case spv::Op::OpPhi:
585       out = [](unsigned index) { return index > 1; };
586       break;
587 
588     case spv::Op::OpEnqueueKernel:
589       // The Invoke parameter.
590       out = [](unsigned index) { return index == 8; };
591       break;
592 
593     case spv::Op::OpGetKernelNDrangeSubGroupCount:
594     case spv::Op::OpGetKernelNDrangeMaxSubGroupSize:
595       // The Invoke parameter.
596       out = [](unsigned index) { return index == 3; };
597       break;
598 
599     case spv::Op::OpGetKernelWorkGroupSize:
600     case spv::Op::OpGetKernelPreferredWorkGroupSizeMultiple:
601       // The Invoke parameter.
602       out = [](unsigned index) { return index == 2; };
603       break;
604     case spv::Op::OpTypeForwardPointer:
605       out = [](unsigned index) { return index == 0; };
606       break;
607     case spv::Op::OpTypeArray:
608       out = [](unsigned index) { return index == 1; };
609       break;
610     case spv::Op::OpCooperativeMatrixPerElementOpNV:
611       out = [](unsigned index) { return index == 3; };
612       break;
613     case spv::Op::OpCooperativeMatrixReduceNV:
614       out = [](unsigned index) { return index == 4; };
615       break;
616     case spv::Op::OpCooperativeMatrixLoadTensorNV:
617       // approximate, due to variable operands
618       out = [](unsigned index) { return index > 6; };
619       break;
620     default:
621       out = [](unsigned) { return false; };
622       break;
623   }
624   return out;
625 }
626 
spvDbgInfoExtOperandCanBeForwardDeclaredFunction(spv::Op opcode,spv_ext_inst_type_t ext_type,uint32_t key)627 std::function<bool(unsigned)> spvDbgInfoExtOperandCanBeForwardDeclaredFunction(
628     spv::Op opcode, spv_ext_inst_type_t ext_type, uint32_t key) {
629   // The Vulkan debug info extended instruction set is non-semantic so allows no
630   // forward references except if used through OpExtInstWithForwardRefsKHR.
631   if (ext_type == SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100) {
632     return [opcode](unsigned) {
633       return opcode == spv::Op::OpExtInstWithForwardRefsKHR;
634     };
635   }
636 
637   // TODO(https://gitlab.khronos.org/spirv/SPIR-V/issues/532): Forward
638   // references for debug info instructions are still in discussion. We must
639   // update the following lines of code when we conclude the spec.
640   std::function<bool(unsigned index)> out;
641   if (ext_type == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100) {
642     switch (OpenCLDebugInfo100Instructions(key)) {
643       case OpenCLDebugInfo100DebugFunction:
644         out = [](unsigned index) { return index == 13; };
645         break;
646       case OpenCLDebugInfo100DebugTypeComposite:
647         out = [](unsigned index) { return index >= 13; };
648         break;
649       default:
650         out = [](unsigned) { return false; };
651         break;
652     }
653   } else {
654     switch (DebugInfoInstructions(key)) {
655       case DebugInfoDebugFunction:
656         out = [](unsigned index) { return index == 13; };
657         break;
658       case DebugInfoDebugTypeComposite:
659         out = [](unsigned index) { return index >= 12; };
660         break;
661       default:
662         out = [](unsigned) { return false; };
663         break;
664     }
665   }
666   return out;
667 }
668