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