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