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