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 | |
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 | |
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 | |
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 | |
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 | return "literal number" ; |
159 | case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER: |
160 | return "possibly multi-word literal integer" ; |
161 | case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER: |
162 | return "possibly multi-word literal number" ; |
163 | case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER: |
164 | return "extension instruction number" ; |
165 | case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER: |
166 | return "OpSpecConstantOp opcode" ; |
167 | case SPV_OPERAND_TYPE_LITERAL_STRING: |
168 | case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING: |
169 | return "literal string" ; |
170 | case SPV_OPERAND_TYPE_SOURCE_LANGUAGE: |
171 | return "source language" ; |
172 | case SPV_OPERAND_TYPE_EXECUTION_MODEL: |
173 | return "execution model" ; |
174 | case SPV_OPERAND_TYPE_ADDRESSING_MODEL: |
175 | return "addressing model" ; |
176 | case SPV_OPERAND_TYPE_MEMORY_MODEL: |
177 | return "memory model" ; |
178 | case SPV_OPERAND_TYPE_EXECUTION_MODE: |
179 | return "execution mode" ; |
180 | case SPV_OPERAND_TYPE_STORAGE_CLASS: |
181 | return "storage class" ; |
182 | case SPV_OPERAND_TYPE_DIMENSIONALITY: |
183 | return "dimensionality" ; |
184 | case SPV_OPERAND_TYPE_SAMPLER_ADDRESSING_MODE: |
185 | return "sampler addressing mode" ; |
186 | case SPV_OPERAND_TYPE_SAMPLER_FILTER_MODE: |
187 | return "sampler filter mode" ; |
188 | case SPV_OPERAND_TYPE_SAMPLER_IMAGE_FORMAT: |
189 | return "image format" ; |
190 | case SPV_OPERAND_TYPE_FP_FAST_MATH_MODE: |
191 | return "floating-point fast math mode" ; |
192 | case SPV_OPERAND_TYPE_FP_ROUNDING_MODE: |
193 | return "floating-point rounding mode" ; |
194 | case SPV_OPERAND_TYPE_LINKAGE_TYPE: |
195 | return "linkage type" ; |
196 | case SPV_OPERAND_TYPE_ACCESS_QUALIFIER: |
197 | case SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER: |
198 | return "access qualifier" ; |
199 | case SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE: |
200 | return "function parameter attribute" ; |
201 | case SPV_OPERAND_TYPE_DECORATION: |
202 | return "decoration" ; |
203 | case SPV_OPERAND_TYPE_BUILT_IN: |
204 | return "built-in" ; |
205 | case SPV_OPERAND_TYPE_SELECTION_CONTROL: |
206 | return "selection control" ; |
207 | case SPV_OPERAND_TYPE_LOOP_CONTROL: |
208 | return "loop control" ; |
209 | case SPV_OPERAND_TYPE_FUNCTION_CONTROL: |
210 | return "function control" ; |
211 | case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID: |
212 | return "memory semantics ID" ; |
213 | case SPV_OPERAND_TYPE_MEMORY_ACCESS: |
214 | case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS: |
215 | return "memory access" ; |
216 | case SPV_OPERAND_TYPE_FRAGMENT_SHADING_RATE: |
217 | return "shading rate" ; |
218 | case SPV_OPERAND_TYPE_SCOPE_ID: |
219 | return "scope ID" ; |
220 | case SPV_OPERAND_TYPE_GROUP_OPERATION: |
221 | return "group operation" ; |
222 | case SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS: |
223 | return "kernel enqeue flags" ; |
224 | case SPV_OPERAND_TYPE_KERNEL_PROFILING_INFO: |
225 | return "kernel profiling info" ; |
226 | case SPV_OPERAND_TYPE_CAPABILITY: |
227 | return "capability" ; |
228 | case SPV_OPERAND_TYPE_RAY_FLAGS: |
229 | return "ray flags" ; |
230 | case SPV_OPERAND_TYPE_RAY_QUERY_INTERSECTION: |
231 | return "ray query intersection" ; |
232 | case SPV_OPERAND_TYPE_RAY_QUERY_COMMITTED_INTERSECTION_TYPE: |
233 | return "ray query committed intersection type" ; |
234 | case SPV_OPERAND_TYPE_RAY_QUERY_CANDIDATE_INTERSECTION_TYPE: |
235 | return "ray query candidate intersection type" ; |
236 | case SPV_OPERAND_TYPE_PACKED_VECTOR_FORMAT: |
237 | case SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT: |
238 | return "packed vector format" ; |
239 | case SPV_OPERAND_TYPE_IMAGE: |
240 | case SPV_OPERAND_TYPE_OPTIONAL_IMAGE: |
241 | return "image" ; |
242 | case SPV_OPERAND_TYPE_OPTIONAL_CIV: |
243 | return "context-insensitive value" ; |
244 | case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS: |
245 | return "debug info flags" ; |
246 | case SPV_OPERAND_TYPE_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING: |
247 | return "debug base type encoding" ; |
248 | case SPV_OPERAND_TYPE_DEBUG_COMPOSITE_TYPE: |
249 | return "debug composite type" ; |
250 | case SPV_OPERAND_TYPE_DEBUG_TYPE_QUALIFIER: |
251 | return "debug type qualifier" ; |
252 | case SPV_OPERAND_TYPE_DEBUG_OPERATION: |
253 | return "debug operation" ; |
254 | case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS: |
255 | return "OpenCL.DebugInfo.100 debug info flags" ; |
256 | case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING: |
257 | return "OpenCL.DebugInfo.100 debug base type encoding" ; |
258 | case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_COMPOSITE_TYPE: |
259 | return "OpenCL.DebugInfo.100 debug composite type" ; |
260 | case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_TYPE_QUALIFIER: |
261 | return "OpenCL.DebugInfo.100 debug type qualifier" ; |
262 | case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION: |
263 | return "OpenCL.DebugInfo.100 debug operation" ; |
264 | case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_IMPORTED_ENTITY: |
265 | return "OpenCL.DebugInfo.100 debug imported entity" ; |
266 | |
267 | // The next values are for values returned from an instruction, not actually |
268 | // an operand. So the specific strings don't matter. But let's add them |
269 | // for completeness and ease of testing. |
270 | case SPV_OPERAND_TYPE_IMAGE_CHANNEL_ORDER: |
271 | return "image channel order" ; |
272 | case SPV_OPERAND_TYPE_IMAGE_CHANNEL_DATA_TYPE: |
273 | return "image channel data type" ; |
274 | |
275 | case SPV_OPERAND_TYPE_FPDENORM_MODE: |
276 | return "FP denorm mode" ; |
277 | case SPV_OPERAND_TYPE_FPOPERATION_MODE: |
278 | return "FP operation mode" ; |
279 | case SPV_OPERAND_TYPE_QUANTIZATION_MODES: |
280 | return "quantization mode" ; |
281 | case SPV_OPERAND_TYPE_OVERFLOW_MODES: |
282 | return "overflow mode" ; |
283 | |
284 | case SPV_OPERAND_TYPE_NONE: |
285 | return "NONE" ; |
286 | default: |
287 | break; |
288 | } |
289 | return "unknown" ; |
290 | } |
291 | |
292 | void spvPushOperandTypes(const spv_operand_type_t* types, |
293 | spv_operand_pattern_t* pattern) { |
294 | const spv_operand_type_t* endTypes; |
295 | for (endTypes = types; *endTypes != SPV_OPERAND_TYPE_NONE; ++endTypes) { |
296 | } |
297 | |
298 | while (endTypes-- != types) { |
299 | pattern->push_back(*endTypes); |
300 | } |
301 | } |
302 | |
303 | void spvPushOperandTypesForMask(spv_target_env env, |
304 | const spv_operand_table operandTable, |
305 | const spv_operand_type_t type, |
306 | const uint32_t mask, |
307 | spv_operand_pattern_t* pattern) { |
308 | // Scan from highest bits to lowest bits because we will append in LIFO |
309 | // fashion, and we need the operands for lower order bits to be consumed first |
310 | for (uint32_t candidate_bit = (1u << 31u); candidate_bit; |
311 | candidate_bit >>= 1) { |
312 | if (candidate_bit & mask) { |
313 | spv_operand_desc entry = nullptr; |
314 | if (SPV_SUCCESS == spvOperandTableValueLookup(env, operandTable, type, |
315 | candidate_bit, &entry)) { |
316 | spvPushOperandTypes(entry->operandTypes, pattern); |
317 | } |
318 | } |
319 | } |
320 | } |
321 | |
322 | bool spvOperandIsConcrete(spv_operand_type_t type) { |
323 | if (spvIsIdType(type) || spvOperandIsConcreteMask(type)) { |
324 | return true; |
325 | } |
326 | switch (type) { |
327 | case SPV_OPERAND_TYPE_LITERAL_INTEGER: |
328 | case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER: |
329 | case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER: |
330 | case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER: |
331 | case SPV_OPERAND_TYPE_LITERAL_STRING: |
332 | case SPV_OPERAND_TYPE_SOURCE_LANGUAGE: |
333 | case SPV_OPERAND_TYPE_EXECUTION_MODEL: |
334 | case SPV_OPERAND_TYPE_ADDRESSING_MODEL: |
335 | case SPV_OPERAND_TYPE_MEMORY_MODEL: |
336 | case SPV_OPERAND_TYPE_EXECUTION_MODE: |
337 | case SPV_OPERAND_TYPE_STORAGE_CLASS: |
338 | case SPV_OPERAND_TYPE_DIMENSIONALITY: |
339 | case SPV_OPERAND_TYPE_SAMPLER_ADDRESSING_MODE: |
340 | case SPV_OPERAND_TYPE_SAMPLER_FILTER_MODE: |
341 | case SPV_OPERAND_TYPE_SAMPLER_IMAGE_FORMAT: |
342 | case SPV_OPERAND_TYPE_IMAGE_CHANNEL_ORDER: |
343 | case SPV_OPERAND_TYPE_IMAGE_CHANNEL_DATA_TYPE: |
344 | case SPV_OPERAND_TYPE_FP_ROUNDING_MODE: |
345 | case SPV_OPERAND_TYPE_LINKAGE_TYPE: |
346 | case SPV_OPERAND_TYPE_ACCESS_QUALIFIER: |
347 | case SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE: |
348 | case SPV_OPERAND_TYPE_DECORATION: |
349 | case SPV_OPERAND_TYPE_BUILT_IN: |
350 | case SPV_OPERAND_TYPE_GROUP_OPERATION: |
351 | case SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS: |
352 | case SPV_OPERAND_TYPE_KERNEL_PROFILING_INFO: |
353 | case SPV_OPERAND_TYPE_CAPABILITY: |
354 | case SPV_OPERAND_TYPE_RAY_FLAGS: |
355 | case SPV_OPERAND_TYPE_RAY_QUERY_INTERSECTION: |
356 | case SPV_OPERAND_TYPE_RAY_QUERY_COMMITTED_INTERSECTION_TYPE: |
357 | case SPV_OPERAND_TYPE_RAY_QUERY_CANDIDATE_INTERSECTION_TYPE: |
358 | case SPV_OPERAND_TYPE_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING: |
359 | case SPV_OPERAND_TYPE_DEBUG_COMPOSITE_TYPE: |
360 | case SPV_OPERAND_TYPE_DEBUG_TYPE_QUALIFIER: |
361 | case SPV_OPERAND_TYPE_DEBUG_OPERATION: |
362 | case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING: |
363 | case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_COMPOSITE_TYPE: |
364 | case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_TYPE_QUALIFIER: |
365 | case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION: |
366 | case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_IMPORTED_ENTITY: |
367 | case SPV_OPERAND_TYPE_FPDENORM_MODE: |
368 | case SPV_OPERAND_TYPE_FPOPERATION_MODE: |
369 | case SPV_OPERAND_TYPE_QUANTIZATION_MODES: |
370 | case SPV_OPERAND_TYPE_OVERFLOW_MODES: |
371 | case SPV_OPERAND_TYPE_PACKED_VECTOR_FORMAT: |
372 | return true; |
373 | default: |
374 | break; |
375 | } |
376 | return false; |
377 | } |
378 | |
379 | bool spvOperandIsConcreteMask(spv_operand_type_t type) { |
380 | switch (type) { |
381 | case SPV_OPERAND_TYPE_IMAGE: |
382 | case SPV_OPERAND_TYPE_FP_FAST_MATH_MODE: |
383 | case SPV_OPERAND_TYPE_SELECTION_CONTROL: |
384 | case SPV_OPERAND_TYPE_LOOP_CONTROL: |
385 | case SPV_OPERAND_TYPE_FUNCTION_CONTROL: |
386 | case SPV_OPERAND_TYPE_MEMORY_ACCESS: |
387 | case SPV_OPERAND_TYPE_FRAGMENT_SHADING_RATE: |
388 | case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS: |
389 | case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS: |
390 | return true; |
391 | default: |
392 | break; |
393 | } |
394 | return false; |
395 | } |
396 | |
397 | bool spvOperandIsOptional(spv_operand_type_t type) { |
398 | switch (type) { |
399 | case SPV_OPERAND_TYPE_OPTIONAL_ID: |
400 | case SPV_OPERAND_TYPE_OPTIONAL_IMAGE: |
401 | case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS: |
402 | case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER: |
403 | case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_NUMBER: |
404 | case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER: |
405 | case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING: |
406 | case SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER: |
407 | case SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT: |
408 | case SPV_OPERAND_TYPE_OPTIONAL_CIV: |
409 | return true; |
410 | default: |
411 | break; |
412 | } |
413 | // Any variable operand is also optional. |
414 | return spvOperandIsVariable(type); |
415 | } |
416 | |
417 | bool spvOperandIsVariable(spv_operand_type_t type) { |
418 | switch (type) { |
419 | case SPV_OPERAND_TYPE_VARIABLE_ID: |
420 | case SPV_OPERAND_TYPE_VARIABLE_LITERAL_INTEGER: |
421 | case SPV_OPERAND_TYPE_VARIABLE_LITERAL_INTEGER_ID: |
422 | case SPV_OPERAND_TYPE_VARIABLE_ID_LITERAL_INTEGER: |
423 | return true; |
424 | default: |
425 | break; |
426 | } |
427 | return false; |
428 | } |
429 | |
430 | bool spvExpandOperandSequenceOnce(spv_operand_type_t type, |
431 | spv_operand_pattern_t* pattern) { |
432 | switch (type) { |
433 | case SPV_OPERAND_TYPE_VARIABLE_ID: |
434 | pattern->push_back(type); |
435 | pattern->push_back(SPV_OPERAND_TYPE_OPTIONAL_ID); |
436 | return true; |
437 | case SPV_OPERAND_TYPE_VARIABLE_LITERAL_INTEGER: |
438 | pattern->push_back(type); |
439 | pattern->push_back(SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER); |
440 | return true; |
441 | case SPV_OPERAND_TYPE_VARIABLE_LITERAL_INTEGER_ID: |
442 | // Represents Zero or more (Literal number, Id) pairs, |
443 | // where the literal number must be a scalar integer. |
444 | pattern->push_back(type); |
445 | pattern->push_back(SPV_OPERAND_TYPE_ID); |
446 | pattern->push_back(SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER); |
447 | return true; |
448 | case SPV_OPERAND_TYPE_VARIABLE_ID_LITERAL_INTEGER: |
449 | // Represents Zero or more (Id, Literal number) pairs. |
450 | pattern->push_back(type); |
451 | pattern->push_back(SPV_OPERAND_TYPE_LITERAL_INTEGER); |
452 | pattern->push_back(SPV_OPERAND_TYPE_OPTIONAL_ID); |
453 | return true; |
454 | default: |
455 | break; |
456 | } |
457 | return false; |
458 | } |
459 | |
460 | spv_operand_type_t spvTakeFirstMatchableOperand( |
461 | spv_operand_pattern_t* pattern) { |
462 | assert(!pattern->empty()); |
463 | spv_operand_type_t result; |
464 | do { |
465 | result = pattern->back(); |
466 | pattern->pop_back(); |
467 | } while (spvExpandOperandSequenceOnce(result, pattern)); |
468 | return result; |
469 | } |
470 | |
471 | spv_operand_pattern_t spvAlternatePatternFollowingImmediate( |
472 | const spv_operand_pattern_t& pattern) { |
473 | auto it = |
474 | std::find(pattern.crbegin(), pattern.crend(), SPV_OPERAND_TYPE_RESULT_ID); |
475 | if (it != pattern.crend()) { |
476 | spv_operand_pattern_t alternatePattern(it - pattern.crbegin() + 2, |
477 | SPV_OPERAND_TYPE_OPTIONAL_CIV); |
478 | alternatePattern[1] = SPV_OPERAND_TYPE_RESULT_ID; |
479 | return alternatePattern; |
480 | } |
481 | |
482 | // No result-id found, so just expect CIVs. |
483 | return {SPV_OPERAND_TYPE_OPTIONAL_CIV}; |
484 | } |
485 | |
486 | bool spvIsIdType(spv_operand_type_t type) { |
487 | switch (type) { |
488 | case SPV_OPERAND_TYPE_ID: |
489 | case SPV_OPERAND_TYPE_TYPE_ID: |
490 | case SPV_OPERAND_TYPE_RESULT_ID: |
491 | case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID: |
492 | case SPV_OPERAND_TYPE_SCOPE_ID: |
493 | return true; |
494 | default: |
495 | return false; |
496 | } |
497 | } |
498 | |
499 | bool spvIsInIdType(spv_operand_type_t type) { |
500 | if (!spvIsIdType(type)) { |
501 | // If it is not an ID it cannot be an input ID. |
502 | return false; |
503 | } |
504 | switch (type) { |
505 | // Deny non-input IDs. |
506 | case SPV_OPERAND_TYPE_TYPE_ID: |
507 | case SPV_OPERAND_TYPE_RESULT_ID: |
508 | return false; |
509 | default: |
510 | return true; |
511 | } |
512 | } |
513 | |
514 | std::function<bool(unsigned)> spvOperandCanBeForwardDeclaredFunction( |
515 | SpvOp opcode) { |
516 | std::function<bool(unsigned index)> out; |
517 | if (spvOpcodeGeneratesType(opcode)) { |
518 | // All types can use forward pointers. |
519 | out = [](unsigned) { return true; }; |
520 | return out; |
521 | } |
522 | switch (opcode) { |
523 | case SpvOpExecutionMode: |
524 | case SpvOpExecutionModeId: |
525 | case SpvOpEntryPoint: |
526 | case SpvOpName: |
527 | case SpvOpMemberName: |
528 | case SpvOpSelectionMerge: |
529 | case SpvOpDecorate: |
530 | case SpvOpMemberDecorate: |
531 | case SpvOpDecorateId: |
532 | case SpvOpDecorateStringGOOGLE: |
533 | case SpvOpMemberDecorateStringGOOGLE: |
534 | case SpvOpBranch: |
535 | case SpvOpLoopMerge: |
536 | out = [](unsigned) { return true; }; |
537 | break; |
538 | case SpvOpGroupDecorate: |
539 | case SpvOpGroupMemberDecorate: |
540 | case SpvOpBranchConditional: |
541 | case SpvOpSwitch: |
542 | out = [](unsigned index) { return index != 0; }; |
543 | break; |
544 | |
545 | case SpvOpFunctionCall: |
546 | // The Function parameter. |
547 | out = [](unsigned index) { return index == 2; }; |
548 | break; |
549 | |
550 | case SpvOpPhi: |
551 | out = [](unsigned index) { return index > 1; }; |
552 | break; |
553 | |
554 | case SpvOpEnqueueKernel: |
555 | // The Invoke parameter. |
556 | out = [](unsigned index) { return index == 8; }; |
557 | break; |
558 | |
559 | case SpvOpGetKernelNDrangeSubGroupCount: |
560 | case SpvOpGetKernelNDrangeMaxSubGroupSize: |
561 | // The Invoke parameter. |
562 | out = [](unsigned index) { return index == 3; }; |
563 | break; |
564 | |
565 | case SpvOpGetKernelWorkGroupSize: |
566 | case SpvOpGetKernelPreferredWorkGroupSizeMultiple: |
567 | // The Invoke parameter. |
568 | out = [](unsigned index) { return index == 2; }; |
569 | break; |
570 | case SpvOpTypeForwardPointer: |
571 | out = [](unsigned index) { return index == 0; }; |
572 | break; |
573 | case SpvOpTypeArray: |
574 | out = [](unsigned index) { return index == 1; }; |
575 | break; |
576 | default: |
577 | out = [](unsigned) { return false; }; |
578 | break; |
579 | } |
580 | return out; |
581 | } |
582 | |
583 | std::function<bool(unsigned)> spvDbgInfoExtOperandCanBeForwardDeclaredFunction( |
584 | spv_ext_inst_type_t ext_type, uint32_t key) { |
585 | // The Vulkan debug info extended instruction set is non-semantic so allows no |
586 | // forward references ever |
587 | if (ext_type == SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100) { |
588 | return [](unsigned) { return false; }; |
589 | } |
590 | |
591 | // TODO(https://gitlab.khronos.org/spirv/SPIR-V/issues/532): Forward |
592 | // references for debug info instructions are still in discussion. We must |
593 | // update the following lines of code when we conclude the spec. |
594 | std::function<bool(unsigned index)> out; |
595 | if (ext_type == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100) { |
596 | switch (OpenCLDebugInfo100Instructions(key)) { |
597 | case OpenCLDebugInfo100DebugFunction: |
598 | out = [](unsigned index) { return index == 13; }; |
599 | break; |
600 | case OpenCLDebugInfo100DebugTypeComposite: |
601 | out = [](unsigned index) { return index >= 13; }; |
602 | break; |
603 | default: |
604 | out = [](unsigned) { return false; }; |
605 | break; |
606 | } |
607 | } else { |
608 | switch (DebugInfoInstructions(key)) { |
609 | case DebugInfoDebugFunction: |
610 | out = [](unsigned index) { return index == 13; }; |
611 | break; |
612 | case DebugInfoDebugTypeComposite: |
613 | out = [](unsigned index) { return index >= 12; }; |
614 | break; |
615 | default: |
616 | out = [](unsigned) { return false; }; |
617 | break; |
618 | } |
619 | } |
620 | return out; |
621 | } |
622 | |