1// Copyright (c) 2018 Google Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// Validates correctness of extension SPIR-V instructions.
16
17#include <sstream>
18#include <string>
19#include <vector>
20
21#include "OpenCLDebugInfo100.h"
22#include "source/diagnostic.h"
23#include "source/enum_string_mapping.h"
24#include "source/extensions.h"
25#include "source/latest_version_glsl_std_450_header.h"
26#include "source/latest_version_opencl_std_header.h"
27#include "source/opcode.h"
28#include "source/spirv_target_env.h"
29#include "source/val/instruction.h"
30#include "source/val/validate.h"
31#include "source/val/validation_state.h"
32
33namespace spvtools {
34namespace val {
35namespace {
36
37uint32_t GetSizeTBitWidth(const ValidationState_t& _) {
38 if (_.addressing_model() == SpvAddressingModelPhysical32) return 32;
39
40 if (_.addressing_model() == SpvAddressingModelPhysical64) return 64;
41
42 return 0;
43}
44
45// Check that the operand of a debug info instruction |inst| at |word_index|
46// is a result id of an instruction with |expected_opcode|.
47spv_result_t ValidateOperandForDebugInfo(
48 ValidationState_t& _, const std::string& operand_name,
49 SpvOp expected_opcode, const Instruction* inst, uint32_t word_index,
50 const std::function<std::string()>& ext_inst_name) {
51 auto* operand = _.FindDef(inst->word(word_index));
52 if (operand->opcode() != expected_opcode) {
53 spv_opcode_desc desc = nullptr;
54 if (_.grammar().lookupOpcode(expected_opcode, &desc) != SPV_SUCCESS ||
55 !desc) {
56 return _.diag(SPV_ERROR_INVALID_DATA, inst)
57 << ext_inst_name() << ": "
58 << "expected operand " << operand_name << " is invalid";
59 }
60 return _.diag(SPV_ERROR_INVALID_DATA, inst)
61 << ext_inst_name() << ": "
62 << "expected operand " << operand_name << " must be a result id of "
63 << "Op" << desc->name;
64 }
65 return SPV_SUCCESS;
66}
67
68#define CHECK_OPERAND(NAME, opcode, index) \
69 do { \
70 auto result = ValidateOperandForDebugInfo(_, NAME, opcode, inst, index, \
71 ext_inst_name); \
72 if (result != SPV_SUCCESS) return result; \
73 } while (0)
74
75// True if the operand of a debug info instruction |inst| at |word_index|
76// satisifies |expectation| that is given as a function. Otherwise,
77// returns false.
78bool DoesDebugInfoOperandMatchExpectation(
79 const ValidationState_t& _,
80 const std::function<bool(OpenCLDebugInfo100Instructions)>& expectation,
81 const Instruction* inst, uint32_t word_index) {
82 auto* debug_inst = _.FindDef(inst->word(word_index));
83 if (debug_inst->opcode() != SpvOpExtInst ||
84 debug_inst->ext_inst_type() != SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100 ||
85 !expectation(OpenCLDebugInfo100Instructions(debug_inst->word(4)))) {
86 return false;
87 }
88 return true;
89}
90
91// Check that the operand of a debug info instruction |inst| at |word_index|
92// is a result id of an debug info instruction whose debug instruction type
93// is |expected_debug_inst|.
94spv_result_t ValidateDebugInfoOperand(
95 ValidationState_t& _, const std::string& debug_inst_name,
96 OpenCLDebugInfo100Instructions expected_debug_inst, const Instruction* inst,
97 uint32_t word_index, const std::function<std::string()>& ext_inst_name) {
98 std::function<bool(OpenCLDebugInfo100Instructions)> expectation =
99 [expected_debug_inst](OpenCLDebugInfo100Instructions dbg_inst) {
100 return dbg_inst == expected_debug_inst;
101 };
102 if (DoesDebugInfoOperandMatchExpectation(_, expectation, inst, word_index))
103 return SPV_SUCCESS;
104
105 spv_ext_inst_desc desc = nullptr;
106 _.grammar().lookupExtInst(SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100,
107 expected_debug_inst, &desc);
108 if (_.grammar().lookupExtInst(SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100,
109 expected_debug_inst, &desc) != SPV_SUCCESS ||
110 !desc) {
111 return _.diag(SPV_ERROR_INVALID_DATA, inst)
112 << ext_inst_name() << ": "
113 << "expected operand " << debug_inst_name << " is invalid";
114 }
115 return _.diag(SPV_ERROR_INVALID_DATA, inst)
116 << ext_inst_name() << ": "
117 << "expected operand " << debug_inst_name << " must be a result id of "
118 << desc->name;
119}
120
121#define CHECK_DEBUG_OPERAND(NAME, debug_opcode, index) \
122 do { \
123 auto result = ValidateDebugInfoOperand(_, NAME, debug_opcode, inst, index, \
124 ext_inst_name); \
125 if (result != SPV_SUCCESS) return result; \
126 } while (0)
127
128// Check that the operand of a debug info instruction |inst| at |word_index|
129// is a result id of an debug info instruction with DebugTypeBasic.
130spv_result_t ValidateOperandBaseType(
131 ValidationState_t& _, const Instruction* inst, uint32_t word_index,
132 const std::function<std::string()>& ext_inst_name) {
133 return ValidateDebugInfoOperand(_, "Base Type",
134 OpenCLDebugInfo100DebugTypeBasic, inst,
135 word_index, ext_inst_name);
136}
137
138// Check that the operand of a debug info instruction |inst| at |word_index|
139// is a result id of a debug lexical scope instruction which is one of
140// DebugCompilationUnit, DebugFunction, DebugLexicalBlock, or
141// DebugTypeComposite.
142spv_result_t ValidateOperandLexicalScope(
143 ValidationState_t& _, const std::string& debug_inst_name,
144 const Instruction* inst, uint32_t word_index,
145 const std::function<std::string()>& ext_inst_name) {
146 std::function<bool(OpenCLDebugInfo100Instructions)> expectation =
147 [](OpenCLDebugInfo100Instructions dbg_inst) {
148 return dbg_inst == OpenCLDebugInfo100DebugCompilationUnit ||
149 dbg_inst == OpenCLDebugInfo100DebugFunction ||
150 dbg_inst == OpenCLDebugInfo100DebugLexicalBlock ||
151 dbg_inst == OpenCLDebugInfo100DebugTypeComposite;
152 };
153 if (DoesDebugInfoOperandMatchExpectation(_, expectation, inst, word_index))
154 return SPV_SUCCESS;
155
156 return _.diag(SPV_ERROR_INVALID_DATA, inst)
157 << ext_inst_name() << ": "
158 << "expected operand " << debug_inst_name
159 << " must be a result id of a lexical scope";
160}
161
162// Check that the operand of a debug info instruction |inst| at |word_index|
163// is a result id of a debug type instruction (See DebugTypeXXX in
164// "4.3. Type instructions" section of OpenCL.DebugInfo.100 spec.
165spv_result_t ValidateOperandDebugType(
166 ValidationState_t& _, const std::string& debug_inst_name,
167 const Instruction* inst, uint32_t word_index,
168 const std::function<std::string()>& ext_inst_name) {
169 std::function<bool(OpenCLDebugInfo100Instructions)> expectation =
170 [](OpenCLDebugInfo100Instructions dbg_inst) {
171 return OpenCLDebugInfo100DebugTypeBasic <= dbg_inst &&
172 dbg_inst <= OpenCLDebugInfo100DebugTypePtrToMember;
173 };
174 if (DoesDebugInfoOperandMatchExpectation(_, expectation, inst, word_index))
175 return SPV_SUCCESS;
176
177 return _.diag(SPV_ERROR_INVALID_DATA, inst)
178 << ext_inst_name() << ": "
179 << "expected operand " << debug_inst_name
180 << " is not a valid debug type";
181}
182
183} // anonymous namespace
184
185spv_result_t ValidateExtension(ValidationState_t& _, const Instruction* inst) {
186 if (spvIsWebGPUEnv(_.context()->target_env)) {
187 std::string extension = GetExtensionString(&(inst->c_inst()));
188
189 if (extension != ExtensionToString(kSPV_KHR_vulkan_memory_model)) {
190 return _.diag(SPV_ERROR_INVALID_DATA, inst)
191 << "For WebGPU, the only valid parameter to OpExtension is "
192 << "\"" << ExtensionToString(kSPV_KHR_vulkan_memory_model)
193 << "\".";
194 }
195 }
196
197 return SPV_SUCCESS;
198}
199
200spv_result_t ValidateExtInstImport(ValidationState_t& _,
201 const Instruction* inst) {
202 const auto name_id = 1;
203 if (spvIsWebGPUEnv(_.context()->target_env)) {
204 const std::string name(reinterpret_cast<const char*>(
205 inst->words().data() + inst->operands()[name_id].offset));
206 if (name != "GLSL.std.450") {
207 return _.diag(SPV_ERROR_INVALID_DATA, inst)
208 << "For WebGPU, the only valid parameter to OpExtInstImport is "
209 "\"GLSL.std.450\".";
210 }
211 }
212
213 if (!_.HasExtension(kSPV_KHR_non_semantic_info)) {
214 const std::string name(reinterpret_cast<const char*>(
215 inst->words().data() + inst->operands()[name_id].offset));
216 if (name.find("NonSemantic.") == 0) {
217 return _.diag(SPV_ERROR_INVALID_DATA, inst)
218 << "NonSemantic extended instruction sets cannot be declared "
219 "without SPV_KHR_non_semantic_info.";
220 }
221 }
222
223 return SPV_SUCCESS;
224}
225
226spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) {
227 const uint32_t result_type = inst->type_id();
228 const uint32_t num_operands = static_cast<uint32_t>(inst->operands().size());
229
230 const uint32_t ext_inst_set = inst->word(3);
231 const uint32_t ext_inst_index = inst->word(4);
232 const spv_ext_inst_type_t ext_inst_type =
233 spv_ext_inst_type_t(inst->ext_inst_type());
234
235 auto ext_inst_name = [&_, ext_inst_set, ext_inst_type, ext_inst_index]() {
236 spv_ext_inst_desc desc = nullptr;
237 if (_.grammar().lookupExtInst(ext_inst_type, ext_inst_index, &desc) !=
238 SPV_SUCCESS ||
239 !desc) {
240 return std::string("Unknown ExtInst");
241 }
242
243 auto* import_inst = _.FindDef(ext_inst_set);
244 assert(import_inst);
245
246 std::ostringstream ss;
247 ss << reinterpret_cast<const char*>(import_inst->words().data() + 2);
248 ss << " ";
249 ss << desc->name;
250
251 return ss.str();
252 };
253
254 if (ext_inst_type == SPV_EXT_INST_TYPE_GLSL_STD_450) {
255 const GLSLstd450 ext_inst_key = GLSLstd450(ext_inst_index);
256 switch (ext_inst_key) {
257 case GLSLstd450Round:
258 case GLSLstd450RoundEven:
259 case GLSLstd450FAbs:
260 case GLSLstd450Trunc:
261 case GLSLstd450FSign:
262 case GLSLstd450Floor:
263 case GLSLstd450Ceil:
264 case GLSLstd450Fract:
265 case GLSLstd450Sqrt:
266 case GLSLstd450InverseSqrt:
267 case GLSLstd450FMin:
268 case GLSLstd450FMax:
269 case GLSLstd450FClamp:
270 case GLSLstd450FMix:
271 case GLSLstd450Step:
272 case GLSLstd450SmoothStep:
273 case GLSLstd450Fma:
274 case GLSLstd450Normalize:
275 case GLSLstd450FaceForward:
276 case GLSLstd450Reflect:
277 case GLSLstd450NMin:
278 case GLSLstd450NMax:
279 case GLSLstd450NClamp: {
280 if (!_.IsFloatScalarOrVectorType(result_type)) {
281 return _.diag(SPV_ERROR_INVALID_DATA, inst)
282 << ext_inst_name() << ": "
283 << "expected Result Type to be a float scalar or vector type";
284 }
285
286 for (uint32_t operand_index = 4; operand_index < num_operands;
287 ++operand_index) {
288 const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
289 if (result_type != operand_type) {
290 return _.diag(SPV_ERROR_INVALID_DATA, inst)
291 << ext_inst_name() << ": "
292 << "expected types of all operands to be equal to Result "
293 "Type";
294 }
295 }
296 break;
297 }
298
299 case GLSLstd450SAbs:
300 case GLSLstd450SSign:
301 case GLSLstd450UMin:
302 case GLSLstd450SMin:
303 case GLSLstd450UMax:
304 case GLSLstd450SMax:
305 case GLSLstd450UClamp:
306 case GLSLstd450SClamp:
307 case GLSLstd450FindILsb:
308 case GLSLstd450FindUMsb:
309 case GLSLstd450FindSMsb: {
310 if (!_.IsIntScalarOrVectorType(result_type)) {
311 return _.diag(SPV_ERROR_INVALID_DATA, inst)
312 << ext_inst_name() << ": "
313 << "expected Result Type to be an int scalar or vector type";
314 }
315
316 const uint32_t result_type_bit_width = _.GetBitWidth(result_type);
317 const uint32_t result_type_dimension = _.GetDimension(result_type);
318
319 for (uint32_t operand_index = 4; operand_index < num_operands;
320 ++operand_index) {
321 const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
322 if (!_.IsIntScalarOrVectorType(operand_type)) {
323 return _.diag(SPV_ERROR_INVALID_DATA, inst)
324 << ext_inst_name() << ": "
325 << "expected all operands to be int scalars or vectors";
326 }
327
328 if (result_type_dimension != _.GetDimension(operand_type)) {
329 return _.diag(SPV_ERROR_INVALID_DATA, inst)
330 << ext_inst_name() << ": "
331 << "expected all operands to have the same dimension as "
332 << "Result Type";
333 }
334
335 if (result_type_bit_width != _.GetBitWidth(operand_type)) {
336 return _.diag(SPV_ERROR_INVALID_DATA, inst)
337 << ext_inst_name() << ": "
338 << "expected all operands to have the same bit width as "
339 << "Result Type";
340 }
341
342 if (ext_inst_key == GLSLstd450FindUMsb ||
343 ext_inst_key == GLSLstd450FindSMsb) {
344 if (result_type_bit_width != 32) {
345 return _.diag(SPV_ERROR_INVALID_DATA, inst)
346 << ext_inst_name() << ": "
347 << "this instruction is currently limited to 32-bit width "
348 << "components";
349 }
350 }
351 }
352 break;
353 }
354
355 case GLSLstd450Radians:
356 case GLSLstd450Degrees:
357 case GLSLstd450Sin:
358 case GLSLstd450Cos:
359 case GLSLstd450Tan:
360 case GLSLstd450Asin:
361 case GLSLstd450Acos:
362 case GLSLstd450Atan:
363 case GLSLstd450Sinh:
364 case GLSLstd450Cosh:
365 case GLSLstd450Tanh:
366 case GLSLstd450Asinh:
367 case GLSLstd450Acosh:
368 case GLSLstd450Atanh:
369 case GLSLstd450Exp:
370 case GLSLstd450Exp2:
371 case GLSLstd450Log:
372 case GLSLstd450Log2:
373 case GLSLstd450Atan2:
374 case GLSLstd450Pow: {
375 if (!_.IsFloatScalarOrVectorType(result_type)) {
376 return _.diag(SPV_ERROR_INVALID_DATA, inst)
377 << ext_inst_name() << ": "
378 << "expected Result Type to be a 16 or 32-bit scalar or "
379 "vector float type";
380 }
381
382 const uint32_t result_type_bit_width = _.GetBitWidth(result_type);
383 if (result_type_bit_width != 16 && result_type_bit_width != 32) {
384 return _.diag(SPV_ERROR_INVALID_DATA, inst)
385 << ext_inst_name() << ": "
386 << "expected Result Type to be a 16 or 32-bit scalar or "
387 "vector float type";
388 }
389
390 for (uint32_t operand_index = 4; operand_index < num_operands;
391 ++operand_index) {
392 const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
393 if (result_type != operand_type) {
394 return _.diag(SPV_ERROR_INVALID_DATA, inst)
395 << ext_inst_name() << ": "
396 << "expected types of all operands to be equal to Result "
397 "Type";
398 }
399 }
400 break;
401 }
402
403 case GLSLstd450Determinant: {
404 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
405 uint32_t num_rows = 0;
406 uint32_t num_cols = 0;
407 uint32_t col_type = 0;
408 uint32_t component_type = 0;
409 if (!_.GetMatrixTypeInfo(x_type, &num_rows, &num_cols, &col_type,
410 &component_type) ||
411 num_rows != num_cols) {
412 return _.diag(SPV_ERROR_INVALID_DATA, inst)
413 << ext_inst_name() << ": "
414 << "expected operand X to be a square matrix";
415 }
416
417 if (result_type != component_type) {
418 return _.diag(SPV_ERROR_INVALID_DATA, inst)
419 << ext_inst_name() << ": "
420 << "expected operand X component type to be equal to "
421 << "Result Type";
422 }
423 break;
424 }
425
426 case GLSLstd450MatrixInverse: {
427 uint32_t num_rows = 0;
428 uint32_t num_cols = 0;
429 uint32_t col_type = 0;
430 uint32_t component_type = 0;
431 if (!_.GetMatrixTypeInfo(result_type, &num_rows, &num_cols, &col_type,
432 &component_type) ||
433 num_rows != num_cols) {
434 return _.diag(SPV_ERROR_INVALID_DATA, inst)
435 << ext_inst_name() << ": "
436 << "expected Result Type to be a square matrix";
437 }
438
439 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
440 if (result_type != x_type) {
441 return _.diag(SPV_ERROR_INVALID_DATA, inst)
442 << ext_inst_name() << ": "
443 << "expected operand X type to be equal to Result Type";
444 }
445 break;
446 }
447
448 case GLSLstd450Modf: {
449 if (!_.IsFloatScalarOrVectorType(result_type)) {
450 return _.diag(SPV_ERROR_INVALID_DATA, inst)
451 << ext_inst_name() << ": "
452 << "expected Result Type to be a scalar or vector float type";
453 }
454
455 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
456 const uint32_t i_type = _.GetOperandTypeId(inst, 5);
457
458 if (x_type != result_type) {
459 return _.diag(SPV_ERROR_INVALID_DATA, inst)
460 << ext_inst_name() << ": "
461 << "expected operand X type to be equal to Result Type";
462 }
463
464 uint32_t i_storage_class = 0;
465 uint32_t i_data_type = 0;
466 if (!_.GetPointerTypeInfo(i_type, &i_data_type, &i_storage_class)) {
467 return _.diag(SPV_ERROR_INVALID_DATA, inst)
468 << ext_inst_name() << ": "
469 << "expected operand I to be a pointer";
470 }
471
472 if (i_data_type != result_type) {
473 return _.diag(SPV_ERROR_INVALID_DATA, inst)
474 << ext_inst_name() << ": "
475 << "expected operand I data type to be equal to Result Type";
476 }
477
478 break;
479 }
480
481 case GLSLstd450ModfStruct: {
482 std::vector<uint32_t> result_types;
483 if (!_.GetStructMemberTypes(result_type, &result_types) ||
484 result_types.size() != 2 ||
485 !_.IsFloatScalarOrVectorType(result_types[0]) ||
486 result_types[1] != result_types[0]) {
487 return _.diag(SPV_ERROR_INVALID_DATA, inst)
488 << ext_inst_name() << ": "
489 << "expected Result Type to be a struct with two identical "
490 << "scalar or vector float type members";
491 }
492
493 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
494 if (x_type != result_types[0]) {
495 return _.diag(SPV_ERROR_INVALID_DATA, inst)
496 << ext_inst_name() << ": "
497 << "expected operand X type to be equal to members of "
498 << "Result Type struct";
499 }
500 break;
501 }
502
503 case GLSLstd450Frexp: {
504 if (!_.IsFloatScalarOrVectorType(result_type)) {
505 return _.diag(SPV_ERROR_INVALID_DATA, inst)
506 << ext_inst_name() << ": "
507 << "expected Result Type to be a scalar or vector float type";
508 }
509
510 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
511 const uint32_t exp_type = _.GetOperandTypeId(inst, 5);
512
513 if (x_type != result_type) {
514 return _.diag(SPV_ERROR_INVALID_DATA, inst)
515 << ext_inst_name() << ": "
516 << "expected operand X type to be equal to Result Type";
517 }
518
519 uint32_t exp_storage_class = 0;
520 uint32_t exp_data_type = 0;
521 if (!_.GetPointerTypeInfo(exp_type, &exp_data_type,
522 &exp_storage_class)) {
523 return _.diag(SPV_ERROR_INVALID_DATA, inst)
524 << ext_inst_name() << ": "
525 << "expected operand Exp to be a pointer";
526 }
527
528 if (!_.IsIntScalarOrVectorType(exp_data_type) ||
529 (!_.HasExtension(kSPV_AMD_gpu_shader_int16) &&
530 _.GetBitWidth(exp_data_type) != 32) ||
531 (_.HasExtension(kSPV_AMD_gpu_shader_int16) &&
532 _.GetBitWidth(exp_data_type) != 16 &&
533 _.GetBitWidth(exp_data_type) != 32)) {
534 return _.diag(SPV_ERROR_INVALID_DATA, inst)
535 << ext_inst_name() << ": "
536 << "expected operand Exp data type to be a "
537 << (_.HasExtension(kSPV_AMD_gpu_shader_int16)
538 ? "16-bit or 32-bit "
539 : "32-bit ")
540 << "int scalar or vector type";
541 }
542
543 if (_.GetDimension(result_type) != _.GetDimension(exp_data_type)) {
544 return _.diag(SPV_ERROR_INVALID_DATA, inst)
545 << ext_inst_name() << ": "
546 << "expected operand Exp data type to have the same component "
547 << "number as Result Type";
548 }
549
550 break;
551 }
552
553 case GLSLstd450Ldexp: {
554 if (!_.IsFloatScalarOrVectorType(result_type)) {
555 return _.diag(SPV_ERROR_INVALID_DATA, inst)
556 << ext_inst_name() << ": "
557 << "expected Result Type to be a scalar or vector float type";
558 }
559
560 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
561 const uint32_t exp_type = _.GetOperandTypeId(inst, 5);
562
563 if (x_type != result_type) {
564 return _.diag(SPV_ERROR_INVALID_DATA, inst)
565 << ext_inst_name() << ": "
566 << "expected operand X type to be equal to Result Type";
567 }
568
569 if (!_.IsIntScalarOrVectorType(exp_type)) {
570 return _.diag(SPV_ERROR_INVALID_DATA, inst)
571 << ext_inst_name() << ": "
572 << "expected operand Exp to be a 32-bit int scalar "
573 << "or vector type";
574 }
575
576 if (_.GetDimension(result_type) != _.GetDimension(exp_type)) {
577 return _.diag(SPV_ERROR_INVALID_DATA, inst)
578 << ext_inst_name() << ": "
579 << "expected operand Exp to have the same component "
580 << "number as Result Type";
581 }
582
583 break;
584 }
585
586 case GLSLstd450FrexpStruct: {
587 std::vector<uint32_t> result_types;
588 if (!_.GetStructMemberTypes(result_type, &result_types) ||
589 result_types.size() != 2 ||
590 !_.IsFloatScalarOrVectorType(result_types[0]) ||
591 !_.IsIntScalarOrVectorType(result_types[1]) ||
592 (!_.HasExtension(kSPV_AMD_gpu_shader_int16) &&
593 _.GetBitWidth(result_types[1]) != 32) ||
594 (_.HasExtension(kSPV_AMD_gpu_shader_int16) &&
595 _.GetBitWidth(result_types[1]) != 16 &&
596 _.GetBitWidth(result_types[1]) != 32) ||
597 _.GetDimension(result_types[0]) !=
598 _.GetDimension(result_types[1])) {
599 return _.diag(SPV_ERROR_INVALID_DATA, inst)
600 << ext_inst_name() << ": "
601 << "expected Result Type to be a struct with two members, "
602 << "first member a float scalar or vector, second member a "
603 << (_.HasExtension(kSPV_AMD_gpu_shader_int16)
604 ? "16-bit or 32-bit "
605 : "32-bit ")
606 << "int scalar or vector with the same number of "
607 << "components as the first member";
608 }
609
610 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
611 if (x_type != result_types[0]) {
612 return _.diag(SPV_ERROR_INVALID_DATA, inst)
613 << ext_inst_name() << ": "
614 << "expected operand X type to be equal to the first member "
615 << "of Result Type struct";
616 }
617 break;
618 }
619
620 case GLSLstd450PackSnorm4x8:
621 case GLSLstd450PackUnorm4x8: {
622 if (!_.IsIntScalarType(result_type) ||
623 _.GetBitWidth(result_type) != 32) {
624 return _.diag(SPV_ERROR_INVALID_DATA, inst)
625 << ext_inst_name() << ": "
626 << "expected Result Type to be 32-bit int scalar type";
627 }
628
629 const uint32_t v_type = _.GetOperandTypeId(inst, 4);
630 if (!_.IsFloatVectorType(v_type) || _.GetDimension(v_type) != 4 ||
631 _.GetBitWidth(v_type) != 32) {
632 return _.diag(SPV_ERROR_INVALID_DATA, inst)
633 << ext_inst_name() << ": "
634 << "expected operand V to be a 32-bit float vector of size 4";
635 }
636 break;
637 }
638
639 case GLSLstd450PackSnorm2x16:
640 case GLSLstd450PackUnorm2x16:
641 case GLSLstd450PackHalf2x16: {
642 if (!_.IsIntScalarType(result_type) ||
643 _.GetBitWidth(result_type) != 32) {
644 return _.diag(SPV_ERROR_INVALID_DATA, inst)
645 << ext_inst_name() << ": "
646 << "expected Result Type to be 32-bit int scalar type";
647 }
648
649 const uint32_t v_type = _.GetOperandTypeId(inst, 4);
650 if (!_.IsFloatVectorType(v_type) || _.GetDimension(v_type) != 2 ||
651 _.GetBitWidth(v_type) != 32) {
652 return _.diag(SPV_ERROR_INVALID_DATA, inst)
653 << ext_inst_name() << ": "
654 << "expected operand V to be a 32-bit float vector of size 2";
655 }
656 break;
657 }
658
659 case GLSLstd450PackDouble2x32: {
660 if (!_.IsFloatScalarType(result_type) ||
661 _.GetBitWidth(result_type) != 64) {
662 return _.diag(SPV_ERROR_INVALID_DATA, inst)
663 << ext_inst_name() << ": "
664 << "expected Result Type to be 64-bit float scalar type";
665 }
666
667 const uint32_t v_type = _.GetOperandTypeId(inst, 4);
668 if (!_.IsIntVectorType(v_type) || _.GetDimension(v_type) != 2 ||
669 _.GetBitWidth(v_type) != 32) {
670 return _.diag(SPV_ERROR_INVALID_DATA, inst)
671 << ext_inst_name() << ": "
672 << "expected operand V to be a 32-bit int vector of size 2";
673 }
674 break;
675 }
676
677 case GLSLstd450UnpackSnorm4x8:
678 case GLSLstd450UnpackUnorm4x8: {
679 if (!_.IsFloatVectorType(result_type) ||
680 _.GetDimension(result_type) != 4 ||
681 _.GetBitWidth(result_type) != 32) {
682 return _.diag(SPV_ERROR_INVALID_DATA, inst)
683 << ext_inst_name() << ": "
684 << "expected Result Type to be a 32-bit float vector of size "
685 "4";
686 }
687
688 const uint32_t v_type = _.GetOperandTypeId(inst, 4);
689 if (!_.IsIntScalarType(v_type) || _.GetBitWidth(v_type) != 32) {
690 return _.diag(SPV_ERROR_INVALID_DATA, inst)
691 << ext_inst_name() << ": "
692 << "expected operand P to be a 32-bit int scalar";
693 }
694 break;
695 }
696
697 case GLSLstd450UnpackSnorm2x16:
698 case GLSLstd450UnpackUnorm2x16:
699 case GLSLstd450UnpackHalf2x16: {
700 if (!_.IsFloatVectorType(result_type) ||
701 _.GetDimension(result_type) != 2 ||
702 _.GetBitWidth(result_type) != 32) {
703 return _.diag(SPV_ERROR_INVALID_DATA, inst)
704 << ext_inst_name() << ": "
705 << "expected Result Type to be a 32-bit float vector of size "
706 "2";
707 }
708
709 const uint32_t v_type = _.GetOperandTypeId(inst, 4);
710 if (!_.IsIntScalarType(v_type) || _.GetBitWidth(v_type) != 32) {
711 return _.diag(SPV_ERROR_INVALID_DATA, inst)
712 << ext_inst_name() << ": "
713 << "expected operand P to be a 32-bit int scalar";
714 }
715 break;
716 }
717
718 case GLSLstd450UnpackDouble2x32: {
719 if (!_.IsIntVectorType(result_type) ||
720 _.GetDimension(result_type) != 2 ||
721 _.GetBitWidth(result_type) != 32) {
722 return _.diag(SPV_ERROR_INVALID_DATA, inst)
723 << ext_inst_name() << ": "
724 << "expected Result Type to be a 32-bit int vector of size "
725 "2";
726 }
727
728 const uint32_t v_type = _.GetOperandTypeId(inst, 4);
729 if (!_.IsFloatScalarType(v_type) || _.GetBitWidth(v_type) != 64) {
730 return _.diag(SPV_ERROR_INVALID_DATA, inst)
731 << ext_inst_name() << ": "
732 << "expected operand V to be a 64-bit float scalar";
733 }
734 break;
735 }
736
737 case GLSLstd450Length: {
738 if (!_.IsFloatScalarType(result_type)) {
739 return _.diag(SPV_ERROR_INVALID_DATA, inst)
740 << ext_inst_name() << ": "
741 << "expected Result Type to be a float scalar type";
742 }
743
744 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
745 if (!_.IsFloatScalarOrVectorType(x_type)) {
746 return _.diag(SPV_ERROR_INVALID_DATA, inst)
747 << ext_inst_name() << ": "
748 << "expected operand X to be of float scalar or vector type";
749 }
750
751 if (result_type != _.GetComponentType(x_type)) {
752 return _.diag(SPV_ERROR_INVALID_DATA, inst)
753 << ext_inst_name() << ": "
754 << "expected operand X component type to be equal to Result "
755 "Type";
756 }
757 break;
758 }
759
760 case GLSLstd450Distance: {
761 if (!_.IsFloatScalarType(result_type)) {
762 return _.diag(SPV_ERROR_INVALID_DATA, inst)
763 << ext_inst_name() << ": "
764 << "expected Result Type to be a float scalar type";
765 }
766
767 const uint32_t p0_type = _.GetOperandTypeId(inst, 4);
768 if (!_.IsFloatScalarOrVectorType(p0_type)) {
769 return _.diag(SPV_ERROR_INVALID_DATA, inst)
770 << ext_inst_name() << ": "
771 << "expected operand P0 to be of float scalar or vector type";
772 }
773
774 if (result_type != _.GetComponentType(p0_type)) {
775 return _.diag(SPV_ERROR_INVALID_DATA, inst)
776 << ext_inst_name() << ": "
777 << "expected operand P0 component type to be equal to "
778 << "Result Type";
779 }
780
781 const uint32_t p1_type = _.GetOperandTypeId(inst, 5);
782 if (!_.IsFloatScalarOrVectorType(p1_type)) {
783 return _.diag(SPV_ERROR_INVALID_DATA, inst)
784 << ext_inst_name() << ": "
785 << "expected operand P1 to be of float scalar or vector type";
786 }
787
788 if (result_type != _.GetComponentType(p1_type)) {
789 return _.diag(SPV_ERROR_INVALID_DATA, inst)
790 << ext_inst_name() << ": "
791 << "expected operand P1 component type to be equal to "
792 << "Result Type";
793 }
794
795 if (_.GetDimension(p0_type) != _.GetDimension(p1_type)) {
796 return _.diag(SPV_ERROR_INVALID_DATA, inst)
797 << ext_inst_name() << ": "
798 << "expected operands P0 and P1 to have the same number of "
799 << "components";
800 }
801 break;
802 }
803
804 case GLSLstd450Cross: {
805 if (!_.IsFloatVectorType(result_type)) {
806 return _.diag(SPV_ERROR_INVALID_DATA, inst)
807 << ext_inst_name() << ": "
808 << "expected Result Type to be a float vector type";
809 }
810
811 if (_.GetDimension(result_type) != 3) {
812 return _.diag(SPV_ERROR_INVALID_DATA, inst)
813 << ext_inst_name() << ": "
814 << "expected Result Type to have 3 components";
815 }
816
817 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
818 const uint32_t y_type = _.GetOperandTypeId(inst, 5);
819
820 if (x_type != result_type) {
821 return _.diag(SPV_ERROR_INVALID_DATA, inst)
822 << ext_inst_name() << ": "
823 << "expected operand X type to be equal to Result Type";
824 }
825
826 if (y_type != result_type) {
827 return _.diag(SPV_ERROR_INVALID_DATA, inst)
828 << ext_inst_name() << ": "
829 << "expected operand Y type to be equal to Result Type";
830 }
831 break;
832 }
833
834 case GLSLstd450Refract: {
835 if (!_.IsFloatScalarOrVectorType(result_type)) {
836 return _.diag(SPV_ERROR_INVALID_DATA, inst)
837 << ext_inst_name() << ": "
838 << "expected Result Type to be a float scalar or vector type";
839 }
840
841 const uint32_t i_type = _.GetOperandTypeId(inst, 4);
842 const uint32_t n_type = _.GetOperandTypeId(inst, 5);
843 const uint32_t eta_type = _.GetOperandTypeId(inst, 6);
844
845 if (result_type != i_type) {
846 return _.diag(SPV_ERROR_INVALID_DATA, inst)
847 << ext_inst_name() << ": "
848 << "expected operand I to be of type equal to Result Type";
849 }
850
851 if (result_type != n_type) {
852 return _.diag(SPV_ERROR_INVALID_DATA, inst)
853 << ext_inst_name() << ": "
854 << "expected operand N to be of type equal to Result Type";
855 }
856
857 if (!_.IsFloatScalarType(eta_type)) {
858 return _.diag(SPV_ERROR_INVALID_DATA, inst)
859 << ext_inst_name() << ": "
860 << "expected operand Eta to be a float scalar";
861 }
862 break;
863 }
864
865 case GLSLstd450InterpolateAtCentroid:
866 case GLSLstd450InterpolateAtSample:
867 case GLSLstd450InterpolateAtOffset: {
868 if (!_.HasCapability(SpvCapabilityInterpolationFunction)) {
869 return _.diag(SPV_ERROR_INVALID_CAPABILITY, inst)
870 << ext_inst_name()
871 << " requires capability InterpolationFunction";
872 }
873
874 if (!_.IsFloatScalarOrVectorType(result_type) ||
875 _.GetBitWidth(result_type) != 32) {
876 return _.diag(SPV_ERROR_INVALID_DATA, inst)
877 << ext_inst_name() << ": "
878 << "expected Result Type to be a 32-bit float scalar "
879 << "or vector type";
880 }
881
882 const uint32_t interpolant_type = _.GetOperandTypeId(inst, 4);
883 uint32_t interpolant_storage_class = 0;
884 uint32_t interpolant_data_type = 0;
885 if (!_.GetPointerTypeInfo(interpolant_type, &interpolant_data_type,
886 &interpolant_storage_class)) {
887 return _.diag(SPV_ERROR_INVALID_DATA, inst)
888 << ext_inst_name() << ": "
889 << "expected Interpolant to be a pointer";
890 }
891
892 if (result_type != interpolant_data_type) {
893 return _.diag(SPV_ERROR_INVALID_DATA, inst)
894 << ext_inst_name() << ": "
895 << "expected Interpolant data type to be equal to Result Type";
896 }
897
898 if (interpolant_storage_class != SpvStorageClassInput) {
899 return _.diag(SPV_ERROR_INVALID_DATA, inst)
900 << ext_inst_name() << ": "
901 << "expected Interpolant storage class to be Input";
902 }
903
904 if (ext_inst_key == GLSLstd450InterpolateAtSample) {
905 const uint32_t sample_type = _.GetOperandTypeId(inst, 5);
906 if (!_.IsIntScalarType(sample_type) ||
907 _.GetBitWidth(sample_type) != 32) {
908 return _.diag(SPV_ERROR_INVALID_DATA, inst)
909 << ext_inst_name() << ": "
910 << "expected Sample to be 32-bit integer";
911 }
912 }
913
914 if (ext_inst_key == GLSLstd450InterpolateAtOffset) {
915 const uint32_t offset_type = _.GetOperandTypeId(inst, 5);
916 if (!_.IsFloatVectorType(offset_type) ||
917 _.GetDimension(offset_type) != 2 ||
918 _.GetBitWidth(offset_type) != 32) {
919 return _.diag(SPV_ERROR_INVALID_DATA, inst)
920 << ext_inst_name() << ": "
921 << "expected Offset to be a vector of 2 32-bit floats";
922 }
923 }
924
925 _.function(inst->function()->id())
926 ->RegisterExecutionModelLimitation(
927 SpvExecutionModelFragment,
928 ext_inst_name() +
929 std::string(" requires Fragment execution model"));
930 break;
931 }
932
933 case GLSLstd450IMix: {
934 return _.diag(SPV_ERROR_INVALID_DATA, inst)
935 << "Extended instruction GLSLstd450IMix is not supported";
936 }
937
938 case GLSLstd450Bad: {
939 return _.diag(SPV_ERROR_INVALID_DATA, inst)
940 << "Encountered extended instruction GLSLstd450Bad";
941 }
942
943 case GLSLstd450Count: {
944 assert(0);
945 break;
946 }
947 }
948 } else if (ext_inst_type == SPV_EXT_INST_TYPE_OPENCL_STD) {
949 const OpenCLLIB::Entrypoints ext_inst_key =
950 OpenCLLIB::Entrypoints(ext_inst_index);
951 switch (ext_inst_key) {
952 case OpenCLLIB::Acos:
953 case OpenCLLIB::Acosh:
954 case OpenCLLIB::Acospi:
955 case OpenCLLIB::Asin:
956 case OpenCLLIB::Asinh:
957 case OpenCLLIB::Asinpi:
958 case OpenCLLIB::Atan:
959 case OpenCLLIB::Atan2:
960 case OpenCLLIB::Atanh:
961 case OpenCLLIB::Atanpi:
962 case OpenCLLIB::Atan2pi:
963 case OpenCLLIB::Cbrt:
964 case OpenCLLIB::Ceil:
965 case OpenCLLIB::Copysign:
966 case OpenCLLIB::Cos:
967 case OpenCLLIB::Cosh:
968 case OpenCLLIB::Cospi:
969 case OpenCLLIB::Erfc:
970 case OpenCLLIB::Erf:
971 case OpenCLLIB::Exp:
972 case OpenCLLIB::Exp2:
973 case OpenCLLIB::Exp10:
974 case OpenCLLIB::Expm1:
975 case OpenCLLIB::Fabs:
976 case OpenCLLIB::Fdim:
977 case OpenCLLIB::Floor:
978 case OpenCLLIB::Fma:
979 case OpenCLLIB::Fmax:
980 case OpenCLLIB::Fmin:
981 case OpenCLLIB::Fmod:
982 case OpenCLLIB::Hypot:
983 case OpenCLLIB::Lgamma:
984 case OpenCLLIB::Log:
985 case OpenCLLIB::Log2:
986 case OpenCLLIB::Log10:
987 case OpenCLLIB::Log1p:
988 case OpenCLLIB::Logb:
989 case OpenCLLIB::Mad:
990 case OpenCLLIB::Maxmag:
991 case OpenCLLIB::Minmag:
992 case OpenCLLIB::Nextafter:
993 case OpenCLLIB::Pow:
994 case OpenCLLIB::Powr:
995 case OpenCLLIB::Remainder:
996 case OpenCLLIB::Rint:
997 case OpenCLLIB::Round:
998 case OpenCLLIB::Rsqrt:
999 case OpenCLLIB::Sin:
1000 case OpenCLLIB::Sinh:
1001 case OpenCLLIB::Sinpi:
1002 case OpenCLLIB::Sqrt:
1003 case OpenCLLIB::Tan:
1004 case OpenCLLIB::Tanh:
1005 case OpenCLLIB::Tanpi:
1006 case OpenCLLIB::Tgamma:
1007 case OpenCLLIB::Trunc:
1008 case OpenCLLIB::Half_cos:
1009 case OpenCLLIB::Half_divide:
1010 case OpenCLLIB::Half_exp:
1011 case OpenCLLIB::Half_exp2:
1012 case OpenCLLIB::Half_exp10:
1013 case OpenCLLIB::Half_log:
1014 case OpenCLLIB::Half_log2:
1015 case OpenCLLIB::Half_log10:
1016 case OpenCLLIB::Half_powr:
1017 case OpenCLLIB::Half_recip:
1018 case OpenCLLIB::Half_rsqrt:
1019 case OpenCLLIB::Half_sin:
1020 case OpenCLLIB::Half_sqrt:
1021 case OpenCLLIB::Half_tan:
1022 case OpenCLLIB::Native_cos:
1023 case OpenCLLIB::Native_divide:
1024 case OpenCLLIB::Native_exp:
1025 case OpenCLLIB::Native_exp2:
1026 case OpenCLLIB::Native_exp10:
1027 case OpenCLLIB::Native_log:
1028 case OpenCLLIB::Native_log2:
1029 case OpenCLLIB::Native_log10:
1030 case OpenCLLIB::Native_powr:
1031 case OpenCLLIB::Native_recip:
1032 case OpenCLLIB::Native_rsqrt:
1033 case OpenCLLIB::Native_sin:
1034 case OpenCLLIB::Native_sqrt:
1035 case OpenCLLIB::Native_tan:
1036 case OpenCLLIB::FClamp:
1037 case OpenCLLIB::Degrees:
1038 case OpenCLLIB::FMax_common:
1039 case OpenCLLIB::FMin_common:
1040 case OpenCLLIB::Mix:
1041 case OpenCLLIB::Radians:
1042 case OpenCLLIB::Step:
1043 case OpenCLLIB::Smoothstep:
1044 case OpenCLLIB::Sign: {
1045 if (!_.IsFloatScalarOrVectorType(result_type)) {
1046 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1047 << ext_inst_name() << ": "
1048 << "expected Result Type to be a float scalar or vector type";
1049 }
1050
1051 const uint32_t num_components = _.GetDimension(result_type);
1052 if (num_components > 4 && num_components != 8 && num_components != 16) {
1053 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1054 << ext_inst_name() << ": "
1055 << "expected Result Type to be a scalar or a vector with 2, "
1056 "3, 4, 8 or 16 components";
1057 }
1058
1059 for (uint32_t operand_index = 4; operand_index < num_operands;
1060 ++operand_index) {
1061 const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
1062 if (result_type != operand_type) {
1063 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1064 << ext_inst_name() << ": "
1065 << "expected types of all operands to be equal to Result "
1066 "Type";
1067 }
1068 }
1069 break;
1070 }
1071
1072 case OpenCLLIB::Fract:
1073 case OpenCLLIB::Modf:
1074 case OpenCLLIB::Sincos: {
1075 if (!_.IsFloatScalarOrVectorType(result_type)) {
1076 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1077 << ext_inst_name() << ": "
1078 << "expected Result Type to be a float scalar or vector type";
1079 }
1080
1081 const uint32_t num_components = _.GetDimension(result_type);
1082 if (num_components > 4 && num_components != 8 && num_components != 16) {
1083 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1084 << ext_inst_name() << ": "
1085 << "expected Result Type to be a scalar or a vector with 2, "
1086 "3, 4, 8 or 16 components";
1087 }
1088
1089 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
1090 if (result_type != x_type) {
1091 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1092 << ext_inst_name() << ": "
1093 << "expected type of operand X to be equal to Result Type";
1094 }
1095
1096 const uint32_t p_type = _.GetOperandTypeId(inst, 5);
1097 uint32_t p_storage_class = 0;
1098 uint32_t p_data_type = 0;
1099 if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
1100 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1101 << ext_inst_name() << ": "
1102 << "expected the last operand to be a pointer";
1103 }
1104
1105 if (p_storage_class != SpvStorageClassGeneric &&
1106 p_storage_class != SpvStorageClassCrossWorkgroup &&
1107 p_storage_class != SpvStorageClassWorkgroup &&
1108 p_storage_class != SpvStorageClassFunction) {
1109 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1110 << ext_inst_name() << ": "
1111 << "expected storage class of the pointer to be Generic, "
1112 "CrossWorkgroup, Workgroup or Function";
1113 }
1114
1115 if (result_type != p_data_type) {
1116 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1117 << ext_inst_name() << ": "
1118 << "expected data type of the pointer to be equal to Result "
1119 "Type";
1120 }
1121 break;
1122 }
1123
1124 case OpenCLLIB::Frexp:
1125 case OpenCLLIB::Lgamma_r:
1126 case OpenCLLIB::Remquo: {
1127 if (!_.IsFloatScalarOrVectorType(result_type)) {
1128 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1129 << ext_inst_name() << ": "
1130 << "expected Result Type to be a float scalar or vector type";
1131 }
1132
1133 const uint32_t num_components = _.GetDimension(result_type);
1134 if (num_components > 4 && num_components != 8 && num_components != 16) {
1135 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1136 << ext_inst_name() << ": "
1137 << "expected Result Type to be a scalar or a vector with 2, "
1138 "3, 4, 8 or 16 components";
1139 }
1140
1141 uint32_t operand_index = 4;
1142 const uint32_t x_type = _.GetOperandTypeId(inst, operand_index++);
1143 if (result_type != x_type) {
1144 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1145 << ext_inst_name() << ": "
1146 << "expected type of operand X to be equal to Result Type";
1147 }
1148
1149 if (ext_inst_key == OpenCLLIB::Remquo) {
1150 const uint32_t y_type = _.GetOperandTypeId(inst, operand_index++);
1151 if (result_type != y_type) {
1152 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1153 << ext_inst_name() << ": "
1154 << "expected type of operand Y to be equal to Result Type";
1155 }
1156 }
1157
1158 const uint32_t p_type = _.GetOperandTypeId(inst, operand_index++);
1159 uint32_t p_storage_class = 0;
1160 uint32_t p_data_type = 0;
1161 if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
1162 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1163 << ext_inst_name() << ": "
1164 << "expected the last operand to be a pointer";
1165 }
1166
1167 if (p_storage_class != SpvStorageClassGeneric &&
1168 p_storage_class != SpvStorageClassCrossWorkgroup &&
1169 p_storage_class != SpvStorageClassWorkgroup &&
1170 p_storage_class != SpvStorageClassFunction) {
1171 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1172 << ext_inst_name() << ": "
1173 << "expected storage class of the pointer to be Generic, "
1174 "CrossWorkgroup, Workgroup or Function";
1175 }
1176
1177 if (!_.IsIntScalarOrVectorType(p_data_type) ||
1178 _.GetBitWidth(p_data_type) != 32) {
1179 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1180 << ext_inst_name() << ": "
1181 << "expected data type of the pointer to be a 32-bit int "
1182 "scalar or vector type";
1183 }
1184
1185 if (_.GetDimension(p_data_type) != num_components) {
1186 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1187 << ext_inst_name() << ": "
1188 << "expected data type of the pointer to have the same number "
1189 "of components as Result Type";
1190 }
1191 break;
1192 }
1193
1194 case OpenCLLIB::Ilogb: {
1195 if (!_.IsIntScalarOrVectorType(result_type) ||
1196 _.GetBitWidth(result_type) != 32) {
1197 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1198 << ext_inst_name() << ": "
1199 << "expected Result Type to be a 32-bit int scalar or vector "
1200 "type";
1201 }
1202
1203 const uint32_t num_components = _.GetDimension(result_type);
1204 if (num_components > 4 && num_components != 8 && num_components != 16) {
1205 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1206 << ext_inst_name() << ": "
1207 << "expected Result Type to be a scalar or a vector with 2, "
1208 "3, 4, 8 or 16 components";
1209 }
1210
1211 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
1212 if (!_.IsFloatScalarOrVectorType(x_type)) {
1213 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1214 << ext_inst_name() << ": "
1215 << "expected operand X to be a float scalar or vector";
1216 }
1217
1218 if (_.GetDimension(x_type) != num_components) {
1219 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1220 << ext_inst_name() << ": "
1221 << "expected operand X to have the same number of components "
1222 "as Result Type";
1223 }
1224 break;
1225 }
1226
1227 case OpenCLLIB::Ldexp:
1228 case OpenCLLIB::Pown:
1229 case OpenCLLIB::Rootn: {
1230 if (!_.IsFloatScalarOrVectorType(result_type)) {
1231 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1232 << ext_inst_name() << ": "
1233 << "expected Result Type to be a float scalar or vector type";
1234 }
1235
1236 const uint32_t num_components = _.GetDimension(result_type);
1237 if (num_components > 4 && num_components != 8 && num_components != 16) {
1238 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1239 << ext_inst_name() << ": "
1240 << "expected Result Type to be a scalar or a vector with 2, "
1241 "3, 4, 8 or 16 components";
1242 }
1243
1244 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
1245 if (result_type != x_type) {
1246 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1247 << ext_inst_name() << ": "
1248 << "expected type of operand X to be equal to Result Type";
1249 }
1250
1251 const uint32_t exp_type = _.GetOperandTypeId(inst, 5);
1252 if (!_.IsIntScalarOrVectorType(exp_type) ||
1253 _.GetBitWidth(exp_type) != 32) {
1254 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1255 << ext_inst_name() << ": "
1256 << "expected the exponent to be a 32-bit int scalar or vector";
1257 }
1258
1259 if (_.GetDimension(exp_type) != num_components) {
1260 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1261 << ext_inst_name() << ": "
1262 << "expected the exponent to have the same number of "
1263 "components as Result Type";
1264 }
1265 break;
1266 }
1267
1268 case OpenCLLIB::Nan: {
1269 if (!_.IsFloatScalarOrVectorType(result_type)) {
1270 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1271 << ext_inst_name() << ": "
1272 << "expected Result Type to be a float scalar or vector type";
1273 }
1274
1275 const uint32_t num_components = _.GetDimension(result_type);
1276 if (num_components > 4 && num_components != 8 && num_components != 16) {
1277 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1278 << ext_inst_name() << ": "
1279 << "expected Result Type to be a scalar or a vector with 2, "
1280 "3, 4, 8 or 16 components";
1281 }
1282
1283 const uint32_t nancode_type = _.GetOperandTypeId(inst, 4);
1284 if (!_.IsIntScalarOrVectorType(nancode_type)) {
1285 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1286 << ext_inst_name() << ": "
1287 << "expected Nancode to be an int scalar or vector type";
1288 }
1289
1290 if (_.GetDimension(nancode_type) != num_components) {
1291 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1292 << ext_inst_name() << ": "
1293 << "expected Nancode to have the same number of components as "
1294 "Result Type";
1295 }
1296
1297 if (_.GetBitWidth(result_type) != _.GetBitWidth(nancode_type)) {
1298 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1299 << ext_inst_name() << ": "
1300 << "expected Nancode to have the same bit width as Result "
1301 "Type";
1302 }
1303 break;
1304 }
1305
1306 case OpenCLLIB::SAbs:
1307 case OpenCLLIB::SAbs_diff:
1308 case OpenCLLIB::SAdd_sat:
1309 case OpenCLLIB::UAdd_sat:
1310 case OpenCLLIB::SHadd:
1311 case OpenCLLIB::UHadd:
1312 case OpenCLLIB::SRhadd:
1313 case OpenCLLIB::URhadd:
1314 case OpenCLLIB::SClamp:
1315 case OpenCLLIB::UClamp:
1316 case OpenCLLIB::Clz:
1317 case OpenCLLIB::Ctz:
1318 case OpenCLLIB::SMad_hi:
1319 case OpenCLLIB::UMad_sat:
1320 case OpenCLLIB::SMad_sat:
1321 case OpenCLLIB::SMax:
1322 case OpenCLLIB::UMax:
1323 case OpenCLLIB::SMin:
1324 case OpenCLLIB::UMin:
1325 case OpenCLLIB::SMul_hi:
1326 case OpenCLLIB::Rotate:
1327 case OpenCLLIB::SSub_sat:
1328 case OpenCLLIB::USub_sat:
1329 case OpenCLLIB::Popcount:
1330 case OpenCLLIB::UAbs:
1331 case OpenCLLIB::UAbs_diff:
1332 case OpenCLLIB::UMul_hi:
1333 case OpenCLLIB::UMad_hi: {
1334 if (!_.IsIntScalarOrVectorType(result_type)) {
1335 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1336 << ext_inst_name() << ": "
1337 << "expected Result Type to be an int scalar or vector type";
1338 }
1339
1340 const uint32_t num_components = _.GetDimension(result_type);
1341 if (num_components > 4 && num_components != 8 && num_components != 16) {
1342 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1343 << ext_inst_name() << ": "
1344 << "expected Result Type to be a scalar or a vector with 2, "
1345 "3, 4, 8 or 16 components";
1346 }
1347
1348 for (uint32_t operand_index = 4; operand_index < num_operands;
1349 ++operand_index) {
1350 const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
1351 if (result_type != operand_type) {
1352 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1353 << ext_inst_name() << ": "
1354 << "expected types of all operands to be equal to Result "
1355 "Type";
1356 }
1357 }
1358 break;
1359 }
1360
1361 case OpenCLLIB::U_Upsample:
1362 case OpenCLLIB::S_Upsample: {
1363 if (!_.IsIntScalarOrVectorType(result_type)) {
1364 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1365 << ext_inst_name() << ": "
1366 << "expected Result Type to be an int scalar or vector "
1367 "type";
1368 }
1369
1370 const uint32_t result_num_components = _.GetDimension(result_type);
1371 if (result_num_components > 4 && result_num_components != 8 &&
1372 result_num_components != 16) {
1373 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1374 << ext_inst_name() << ": "
1375 << "expected Result Type to be a scalar or a vector with 2, "
1376 "3, 4, 8 or 16 components";
1377 }
1378
1379 const uint32_t result_bit_width = _.GetBitWidth(result_type);
1380 if (result_bit_width != 16 && result_bit_width != 32 &&
1381 result_bit_width != 64) {
1382 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1383 << ext_inst_name() << ": "
1384 << "expected bit width of Result Type components to be 16, 32 "
1385 "or 64";
1386 }
1387
1388 const uint32_t hi_type = _.GetOperandTypeId(inst, 4);
1389 const uint32_t lo_type = _.GetOperandTypeId(inst, 5);
1390
1391 if (hi_type != lo_type) {
1392 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1393 << ext_inst_name() << ": "
1394 << "expected Hi and Lo operands to have the same type";
1395 }
1396
1397 if (result_num_components != _.GetDimension(hi_type)) {
1398 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1399 << ext_inst_name() << ": "
1400 << "expected Hi and Lo operands to have the same number of "
1401 "components as Result Type";
1402 }
1403
1404 if (result_bit_width != 2 * _.GetBitWidth(hi_type)) {
1405 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1406 << ext_inst_name() << ": "
1407 << "expected bit width of components of Hi and Lo operands to "
1408 "be half of the bit width of components of Result Type";
1409 }
1410 break;
1411 }
1412
1413 case OpenCLLIB::SMad24:
1414 case OpenCLLIB::UMad24:
1415 case OpenCLLIB::SMul24:
1416 case OpenCLLIB::UMul24: {
1417 if (!_.IsIntScalarOrVectorType(result_type) ||
1418 _.GetBitWidth(result_type) != 32) {
1419 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1420 << ext_inst_name() << ": "
1421 << "expected Result Type to be a 32-bit int scalar or vector "
1422 "type";
1423 }
1424
1425 const uint32_t num_components = _.GetDimension(result_type);
1426 if (num_components > 4 && num_components != 8 && num_components != 16) {
1427 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1428 << ext_inst_name() << ": "
1429 << "expected Result Type to be a scalar or a vector with 2, "
1430 "3, 4, 8 or 16 components";
1431 }
1432
1433 for (uint32_t operand_index = 4; operand_index < num_operands;
1434 ++operand_index) {
1435 const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
1436 if (result_type != operand_type) {
1437 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1438 << ext_inst_name() << ": "
1439 << "expected types of all operands to be equal to Result "
1440 "Type";
1441 }
1442 }
1443 break;
1444 }
1445
1446 case OpenCLLIB::Cross: {
1447 if (!_.IsFloatVectorType(result_type)) {
1448 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1449 << ext_inst_name() << ": "
1450 << "expected Result Type to be a float vector type";
1451 }
1452
1453 const uint32_t num_components = _.GetDimension(result_type);
1454 if (num_components != 3 && num_components != 4) {
1455 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1456 << ext_inst_name() << ": "
1457 << "expected Result Type to have 3 or 4 components";
1458 }
1459
1460 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
1461 const uint32_t y_type = _.GetOperandTypeId(inst, 5);
1462
1463 if (x_type != result_type) {
1464 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1465 << ext_inst_name() << ": "
1466 << "expected operand X type to be equal to Result Type";
1467 }
1468
1469 if (y_type != result_type) {
1470 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1471 << ext_inst_name() << ": "
1472 << "expected operand Y type to be equal to Result Type";
1473 }
1474 break;
1475 }
1476
1477 case OpenCLLIB::Distance:
1478 case OpenCLLIB::Fast_distance: {
1479 if (!_.IsFloatScalarType(result_type)) {
1480 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1481 << ext_inst_name() << ": "
1482 << "expected Result Type to be a float scalar type";
1483 }
1484
1485 const uint32_t p0_type = _.GetOperandTypeId(inst, 4);
1486 if (!_.IsFloatScalarOrVectorType(p0_type)) {
1487 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1488 << ext_inst_name() << ": "
1489 << "expected operand P0 to be of float scalar or vector type";
1490 }
1491
1492 const uint32_t num_components = _.GetDimension(p0_type);
1493 if (num_components > 4) {
1494 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1495 << ext_inst_name() << ": "
1496 << "expected operand P0 to have no more than 4 components";
1497 }
1498
1499 if (result_type != _.GetComponentType(p0_type)) {
1500 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1501 << ext_inst_name() << ": "
1502 << "expected operand P0 component type to be equal to "
1503 << "Result Type";
1504 }
1505
1506 const uint32_t p1_type = _.GetOperandTypeId(inst, 5);
1507 if (p0_type != p1_type) {
1508 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1509 << ext_inst_name() << ": "
1510 << "expected operands P0 and P1 to be of the same type";
1511 }
1512 break;
1513 }
1514
1515 case OpenCLLIB::Length:
1516 case OpenCLLIB::Fast_length: {
1517 if (!_.IsFloatScalarType(result_type)) {
1518 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1519 << ext_inst_name() << ": "
1520 << "expected Result Type to be a float scalar type";
1521 }
1522
1523 const uint32_t p_type = _.GetOperandTypeId(inst, 4);
1524 if (!_.IsFloatScalarOrVectorType(p_type)) {
1525 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1526 << ext_inst_name() << ": "
1527 << "expected operand P to be a float scalar or vector";
1528 }
1529
1530 const uint32_t num_components = _.GetDimension(p_type);
1531 if (num_components > 4) {
1532 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1533 << ext_inst_name() << ": "
1534 << "expected operand P to have no more than 4 components";
1535 }
1536
1537 if (result_type != _.GetComponentType(p_type)) {
1538 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1539 << ext_inst_name() << ": "
1540 << "expected operand P component type to be equal to Result "
1541 "Type";
1542 }
1543 break;
1544 }
1545
1546 case OpenCLLIB::Normalize:
1547 case OpenCLLIB::Fast_normalize: {
1548 if (!_.IsFloatScalarOrVectorType(result_type)) {
1549 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1550 << ext_inst_name() << ": "
1551 << "expected Result Type to be a float scalar or vector type";
1552 }
1553
1554 const uint32_t num_components = _.GetDimension(result_type);
1555 if (num_components > 4) {
1556 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1557 << ext_inst_name() << ": "
1558 << "expected Result Type to have no more than 4 components";
1559 }
1560
1561 const uint32_t p_type = _.GetOperandTypeId(inst, 4);
1562 if (p_type != result_type) {
1563 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1564 << ext_inst_name() << ": "
1565 << "expected operand P type to be equal to Result Type";
1566 }
1567 break;
1568 }
1569
1570 case OpenCLLIB::Bitselect: {
1571 if (!_.IsFloatScalarOrVectorType(result_type) &&
1572 !_.IsIntScalarOrVectorType(result_type)) {
1573 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1574 << ext_inst_name() << ": "
1575 << "expected Result Type to be an int or float scalar or "
1576 "vector type";
1577 }
1578
1579 const uint32_t num_components = _.GetDimension(result_type);
1580 if (num_components > 4 && num_components != 8 && num_components != 16) {
1581 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1582 << ext_inst_name() << ": "
1583 << "expected Result Type to be a scalar or a vector with 2, "
1584 "3, 4, 8 or 16 components";
1585 }
1586
1587 for (uint32_t operand_index = 4; operand_index < num_operands;
1588 ++operand_index) {
1589 const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
1590 if (result_type != operand_type) {
1591 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1592 << ext_inst_name() << ": "
1593 << "expected types of all operands to be equal to Result "
1594 "Type";
1595 }
1596 }
1597 break;
1598 }
1599
1600 case OpenCLLIB::Select: {
1601 if (!_.IsFloatScalarOrVectorType(result_type) &&
1602 !_.IsIntScalarOrVectorType(result_type)) {
1603 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1604 << ext_inst_name() << ": "
1605 << "expected Result Type to be an int or float scalar or "
1606 "vector type";
1607 }
1608
1609 const uint32_t num_components = _.GetDimension(result_type);
1610 if (num_components > 4 && num_components != 8 && num_components != 16) {
1611 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1612 << ext_inst_name() << ": "
1613 << "expected Result Type to be a scalar or a vector with 2, "
1614 "3, 4, 8 or 16 components";
1615 }
1616
1617 const uint32_t a_type = _.GetOperandTypeId(inst, 4);
1618 const uint32_t b_type = _.GetOperandTypeId(inst, 5);
1619 const uint32_t c_type = _.GetOperandTypeId(inst, 6);
1620
1621 if (result_type != a_type) {
1622 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1623 << ext_inst_name() << ": "
1624 << "expected operand A type to be equal to Result Type";
1625 }
1626
1627 if (result_type != b_type) {
1628 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1629 << ext_inst_name() << ": "
1630 << "expected operand B type to be equal to Result Type";
1631 }
1632
1633 if (!_.IsIntScalarOrVectorType(c_type)) {
1634 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1635 << ext_inst_name() << ": "
1636 << "expected operand C to be an int scalar or vector";
1637 }
1638
1639 if (num_components != _.GetDimension(c_type)) {
1640 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1641 << ext_inst_name() << ": "
1642 << "expected operand C to have the same number of components "
1643 "as Result Type";
1644 }
1645
1646 if (_.GetBitWidth(result_type) != _.GetBitWidth(c_type)) {
1647 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1648 << ext_inst_name() << ": "
1649 << "expected operand C to have the same bit width as Result "
1650 "Type";
1651 }
1652 break;
1653 }
1654
1655 case OpenCLLIB::Vloadn: {
1656 if (!_.IsFloatVectorType(result_type) &&
1657 !_.IsIntVectorType(result_type)) {
1658 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1659 << ext_inst_name() << ": "
1660 << "expected Result Type to be an int or float vector type";
1661 }
1662
1663 const uint32_t num_components = _.GetDimension(result_type);
1664 if (num_components > 4 && num_components != 8 && num_components != 16) {
1665 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1666 << ext_inst_name() << ": "
1667 << "expected Result Type to have 2, 3, 4, 8 or 16 components";
1668 }
1669
1670 const uint32_t offset_type = _.GetOperandTypeId(inst, 4);
1671 const uint32_t p_type = _.GetOperandTypeId(inst, 5);
1672
1673 const uint32_t size_t_bit_width = GetSizeTBitWidth(_);
1674 if (!size_t_bit_width) {
1675 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1676 << ext_inst_name()
1677 << " can only be used with physical addressing models";
1678 }
1679
1680 if (!_.IsIntScalarType(offset_type) ||
1681 _.GetBitWidth(offset_type) != size_t_bit_width) {
1682 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1683 << ext_inst_name() << ": "
1684 << "expected operand Offset to be of type size_t ("
1685 << size_t_bit_width
1686 << "-bit integer for the addressing model used in the module)";
1687 }
1688
1689 uint32_t p_storage_class = 0;
1690 uint32_t p_data_type = 0;
1691 if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
1692 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1693 << ext_inst_name() << ": "
1694 << "expected operand P to be a pointer";
1695 }
1696
1697 if (p_storage_class != SpvStorageClassUniformConstant &&
1698 p_storage_class != SpvStorageClassGeneric &&
1699 p_storage_class != SpvStorageClassCrossWorkgroup &&
1700 p_storage_class != SpvStorageClassWorkgroup &&
1701 p_storage_class != SpvStorageClassFunction) {
1702 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1703 << ext_inst_name() << ": "
1704 << "expected operand P storage class to be UniformConstant, "
1705 "Generic, CrossWorkgroup, Workgroup or Function";
1706 }
1707
1708 if (_.GetComponentType(result_type) != p_data_type) {
1709 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1710 << ext_inst_name() << ": "
1711 << "expected operand P data type to be equal to component "
1712 "type of Result Type";
1713 }
1714
1715 const uint32_t n_value = inst->word(7);
1716 if (num_components != n_value) {
1717 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1718 << ext_inst_name() << ": "
1719 << "expected literal N to be equal to the number of "
1720 "components of Result Type";
1721 }
1722 break;
1723 }
1724
1725 case OpenCLLIB::Vstoren: {
1726 if (_.GetIdOpcode(result_type) != SpvOpTypeVoid) {
1727 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1728 << ext_inst_name() << ": expected Result Type to be void";
1729 }
1730
1731 const uint32_t data_type = _.GetOperandTypeId(inst, 4);
1732 const uint32_t offset_type = _.GetOperandTypeId(inst, 5);
1733 const uint32_t p_type = _.GetOperandTypeId(inst, 6);
1734
1735 if (!_.IsFloatVectorType(data_type) && !_.IsIntVectorType(data_type)) {
1736 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1737 << ext_inst_name() << ": "
1738 << "expected Data to be an int or float vector";
1739 }
1740
1741 const uint32_t num_components = _.GetDimension(data_type);
1742 if (num_components > 4 && num_components != 8 && num_components != 16) {
1743 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1744 << ext_inst_name() << ": "
1745 << "expected Data to have 2, 3, 4, 8 or 16 components";
1746 }
1747
1748 const uint32_t size_t_bit_width = GetSizeTBitWidth(_);
1749 if (!size_t_bit_width) {
1750 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1751 << ext_inst_name()
1752 << " can only be used with physical addressing models";
1753 }
1754
1755 if (!_.IsIntScalarType(offset_type) ||
1756 _.GetBitWidth(offset_type) != size_t_bit_width) {
1757 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1758 << ext_inst_name() << ": "
1759 << "expected operand Offset to be of type size_t ("
1760 << size_t_bit_width
1761 << "-bit integer for the addressing model used in the module)";
1762 }
1763
1764 uint32_t p_storage_class = 0;
1765 uint32_t p_data_type = 0;
1766 if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
1767 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1768 << ext_inst_name() << ": "
1769 << "expected operand P to be a pointer";
1770 }
1771
1772 if (p_storage_class != SpvStorageClassGeneric &&
1773 p_storage_class != SpvStorageClassCrossWorkgroup &&
1774 p_storage_class != SpvStorageClassWorkgroup &&
1775 p_storage_class != SpvStorageClassFunction) {
1776 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1777 << ext_inst_name() << ": "
1778 << "expected operand P storage class to be Generic, "
1779 "CrossWorkgroup, Workgroup or Function";
1780 }
1781
1782 if (_.GetComponentType(data_type) != p_data_type) {
1783 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1784 << ext_inst_name() << ": "
1785 << "expected operand P data type to be equal to the type of "
1786 "operand Data components";
1787 }
1788 break;
1789 }
1790
1791 case OpenCLLIB::Vload_half: {
1792 if (!_.IsFloatScalarType(result_type)) {
1793 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1794 << ext_inst_name() << ": "
1795 << "expected Result Type to be a float scalar type";
1796 }
1797
1798 const uint32_t offset_type = _.GetOperandTypeId(inst, 4);
1799 const uint32_t p_type = _.GetOperandTypeId(inst, 5);
1800
1801 const uint32_t size_t_bit_width = GetSizeTBitWidth(_);
1802 if (!size_t_bit_width) {
1803 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1804 << ext_inst_name()
1805 << " can only be used with physical addressing models";
1806 }
1807
1808 if (!_.IsIntScalarType(offset_type) ||
1809 _.GetBitWidth(offset_type) != size_t_bit_width) {
1810 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1811 << ext_inst_name() << ": "
1812 << "expected operand Offset to be of type size_t ("
1813 << size_t_bit_width
1814 << "-bit integer for the addressing model used in the module)";
1815 }
1816
1817 uint32_t p_storage_class = 0;
1818 uint32_t p_data_type = 0;
1819 if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
1820 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1821 << ext_inst_name() << ": "
1822 << "expected operand P to be a pointer";
1823 }
1824
1825 if (p_storage_class != SpvStorageClassUniformConstant &&
1826 p_storage_class != SpvStorageClassGeneric &&
1827 p_storage_class != SpvStorageClassCrossWorkgroup &&
1828 p_storage_class != SpvStorageClassWorkgroup &&
1829 p_storage_class != SpvStorageClassFunction) {
1830 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1831 << ext_inst_name() << ": "
1832 << "expected operand P storage class to be UniformConstant, "
1833 "Generic, CrossWorkgroup, Workgroup or Function";
1834 }
1835
1836 if (!_.IsFloatScalarType(p_data_type) ||
1837 _.GetBitWidth(p_data_type) != 16) {
1838 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1839 << ext_inst_name() << ": "
1840 << "expected operand P data type to be 16-bit float scalar";
1841 }
1842 break;
1843 }
1844
1845 case OpenCLLIB::Vload_halfn:
1846 case OpenCLLIB::Vloada_halfn: {
1847 if (!_.IsFloatVectorType(result_type)) {
1848 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1849 << ext_inst_name() << ": "
1850 << "expected Result Type to be a float vector type";
1851 }
1852
1853 const uint32_t num_components = _.GetDimension(result_type);
1854 if (num_components > 4 && num_components != 8 && num_components != 16) {
1855 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1856 << ext_inst_name() << ": "
1857 << "expected Result Type to have 2, 3, 4, 8 or 16 components";
1858 }
1859
1860 const uint32_t offset_type = _.GetOperandTypeId(inst, 4);
1861 const uint32_t p_type = _.GetOperandTypeId(inst, 5);
1862
1863 const uint32_t size_t_bit_width = GetSizeTBitWidth(_);
1864 if (!size_t_bit_width) {
1865 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1866 << ext_inst_name()
1867 << " can only be used with physical addressing models";
1868 }
1869
1870 if (!_.IsIntScalarType(offset_type) ||
1871 _.GetBitWidth(offset_type) != size_t_bit_width) {
1872 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1873 << ext_inst_name() << ": "
1874 << "expected operand Offset to be of type size_t ("
1875 << size_t_bit_width
1876 << "-bit integer for the addressing model used in the module)";
1877 }
1878
1879 uint32_t p_storage_class = 0;
1880 uint32_t p_data_type = 0;
1881 if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
1882 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1883 << ext_inst_name() << ": "
1884 << "expected operand P to be a pointer";
1885 }
1886
1887 if (p_storage_class != SpvStorageClassUniformConstant &&
1888 p_storage_class != SpvStorageClassGeneric &&
1889 p_storage_class != SpvStorageClassCrossWorkgroup &&
1890 p_storage_class != SpvStorageClassWorkgroup &&
1891 p_storage_class != SpvStorageClassFunction) {
1892 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1893 << ext_inst_name() << ": "
1894 << "expected operand P storage class to be UniformConstant, "
1895 "Generic, CrossWorkgroup, Workgroup or Function";
1896 }
1897
1898 if (!_.IsFloatScalarType(p_data_type) ||
1899 _.GetBitWidth(p_data_type) != 16) {
1900 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1901 << ext_inst_name() << ": "
1902 << "expected operand P data type to be 16-bit float scalar";
1903 }
1904
1905 const uint32_t n_value = inst->word(7);
1906 if (num_components != n_value) {
1907 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1908 << ext_inst_name() << ": "
1909 << "expected literal N to be equal to the number of "
1910 "components of Result Type";
1911 }
1912 break;
1913 }
1914
1915 case OpenCLLIB::Vstore_half:
1916 case OpenCLLIB::Vstore_half_r:
1917 case OpenCLLIB::Vstore_halfn:
1918 case OpenCLLIB::Vstore_halfn_r:
1919 case OpenCLLIB::Vstorea_halfn:
1920 case OpenCLLIB::Vstorea_halfn_r: {
1921 if (_.GetIdOpcode(result_type) != SpvOpTypeVoid) {
1922 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1923 << ext_inst_name() << ": expected Result Type to be void";
1924 }
1925
1926 const uint32_t data_type = _.GetOperandTypeId(inst, 4);
1927 const uint32_t offset_type = _.GetOperandTypeId(inst, 5);
1928 const uint32_t p_type = _.GetOperandTypeId(inst, 6);
1929 const uint32_t data_type_bit_width = _.GetBitWidth(data_type);
1930
1931 if (ext_inst_key == OpenCLLIB::Vstore_half ||
1932 ext_inst_key == OpenCLLIB::Vstore_half_r) {
1933 if (!_.IsFloatScalarType(data_type) ||
1934 (data_type_bit_width != 32 && data_type_bit_width != 64)) {
1935 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1936 << ext_inst_name() << ": "
1937 << "expected Data to be a 32 or 64-bit float scalar";
1938 }
1939 } else {
1940 if (!_.IsFloatVectorType(data_type) ||
1941 (data_type_bit_width != 32 && data_type_bit_width != 64)) {
1942 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1943 << ext_inst_name() << ": "
1944 << "expected Data to be a 32 or 64-bit float vector";
1945 }
1946
1947 const uint32_t num_components = _.GetDimension(data_type);
1948 if (num_components > 4 && num_components != 8 &&
1949 num_components != 16) {
1950 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1951 << ext_inst_name() << ": "
1952 << "expected Data to have 2, 3, 4, 8 or 16 components";
1953 }
1954 }
1955
1956 const uint32_t size_t_bit_width = GetSizeTBitWidth(_);
1957 if (!size_t_bit_width) {
1958 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1959 << ext_inst_name()
1960 << " can only be used with physical addressing models";
1961 }
1962
1963 if (!_.IsIntScalarType(offset_type) ||
1964 _.GetBitWidth(offset_type) != size_t_bit_width) {
1965 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1966 << ext_inst_name() << ": "
1967 << "expected operand Offset to be of type size_t ("
1968 << size_t_bit_width
1969 << "-bit integer for the addressing model used in the module)";
1970 }
1971
1972 uint32_t p_storage_class = 0;
1973 uint32_t p_data_type = 0;
1974 if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
1975 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1976 << ext_inst_name() << ": "
1977 << "expected operand P to be a pointer";
1978 }
1979
1980 if (p_storage_class != SpvStorageClassGeneric &&
1981 p_storage_class != SpvStorageClassCrossWorkgroup &&
1982 p_storage_class != SpvStorageClassWorkgroup &&
1983 p_storage_class != SpvStorageClassFunction) {
1984 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1985 << ext_inst_name() << ": "
1986 << "expected operand P storage class to be Generic, "
1987 "CrossWorkgroup, Workgroup or Function";
1988 }
1989
1990 if (!_.IsFloatScalarType(p_data_type) ||
1991 _.GetBitWidth(p_data_type) != 16) {
1992 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1993 << ext_inst_name() << ": "
1994 << "expected operand P data type to be 16-bit float scalar";
1995 }
1996
1997 // Rounding mode enum is checked by assembler.
1998 break;
1999 }
2000
2001 case OpenCLLIB::Shuffle:
2002 case OpenCLLIB::Shuffle2: {
2003 if (!_.IsFloatVectorType(result_type) &&
2004 !_.IsIntVectorType(result_type)) {
2005 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2006 << ext_inst_name() << ": "
2007 << "expected Result Type to be an int or float vector type";
2008 }
2009
2010 const uint32_t result_num_components = _.GetDimension(result_type);
2011 if (result_num_components != 2 && result_num_components != 4 &&
2012 result_num_components != 8 && result_num_components != 16) {
2013 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2014 << ext_inst_name() << ": "
2015 << "expected Result Type to have 2, 4, 8 or 16 components";
2016 }
2017
2018 uint32_t operand_index = 4;
2019 const uint32_t x_type = _.GetOperandTypeId(inst, operand_index++);
2020
2021 if (ext_inst_key == OpenCLLIB::Shuffle2) {
2022 const uint32_t y_type = _.GetOperandTypeId(inst, operand_index++);
2023 if (x_type != y_type) {
2024 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2025 << ext_inst_name() << ": "
2026 << "expected operands X and Y to be of the same type";
2027 }
2028 }
2029
2030 const uint32_t shuffle_mask_type =
2031 _.GetOperandTypeId(inst, operand_index++);
2032
2033 if (!_.IsFloatVectorType(x_type) && !_.IsIntVectorType(x_type)) {
2034 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2035 << ext_inst_name() << ": "
2036 << "expected operand X to be an int or float vector";
2037 }
2038
2039 const uint32_t x_num_components = _.GetDimension(x_type);
2040 if (x_num_components != 2 && x_num_components != 4 &&
2041 x_num_components != 8 && x_num_components != 16) {
2042 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2043 << ext_inst_name() << ": "
2044 << "expected operand X to have 2, 4, 8 or 16 components";
2045 }
2046
2047 const uint32_t result_component_type = _.GetComponentType(result_type);
2048
2049 if (result_component_type != _.GetComponentType(x_type)) {
2050 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2051 << ext_inst_name() << ": "
2052 << "expected operand X and Result Type to have equal "
2053 "component types";
2054 }
2055
2056 if (!_.IsIntVectorType(shuffle_mask_type)) {
2057 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2058 << ext_inst_name() << ": "
2059 << "expected operand Shuffle Mask to be an int vector";
2060 }
2061
2062 if (result_num_components != _.GetDimension(shuffle_mask_type)) {
2063 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2064 << ext_inst_name() << ": "
2065 << "expected operand Shuffle Mask to have the same number of "
2066 "components as Result Type";
2067 }
2068
2069 if (_.GetBitWidth(result_component_type) !=
2070 _.GetBitWidth(shuffle_mask_type)) {
2071 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2072 << ext_inst_name() << ": "
2073 << "expected operand Shuffle Mask components to have the same "
2074 "bit width as Result Type components";
2075 }
2076 break;
2077 }
2078
2079 case OpenCLLIB::Printf: {
2080 if (!_.IsIntScalarType(result_type) ||
2081 _.GetBitWidth(result_type) != 32) {
2082 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2083 << ext_inst_name() << ": "
2084 << "expected Result Type to be a 32-bit int type";
2085 }
2086
2087 const uint32_t format_type = _.GetOperandTypeId(inst, 4);
2088 uint32_t format_storage_class = 0;
2089 uint32_t format_data_type = 0;
2090 if (!_.GetPointerTypeInfo(format_type, &format_data_type,
2091 &format_storage_class)) {
2092 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2093 << ext_inst_name() << ": "
2094 << "expected operand Format to be a pointer";
2095 }
2096
2097 if (format_storage_class != SpvStorageClassUniformConstant) {
2098 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2099 << ext_inst_name() << ": "
2100 << "expected Format storage class to be UniformConstant";
2101 }
2102
2103 if (!_.IsIntScalarType(format_data_type) ||
2104 _.GetBitWidth(format_data_type) != 8) {
2105 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2106 << ext_inst_name() << ": "
2107 << "expected Format data type to be 8-bit int";
2108 }
2109 break;
2110 }
2111
2112 case OpenCLLIB::Prefetch: {
2113 if (_.GetIdOpcode(result_type) != SpvOpTypeVoid) {
2114 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2115 << ext_inst_name() << ": expected Result Type to be void";
2116 }
2117
2118 const uint32_t p_type = _.GetOperandTypeId(inst, 4);
2119 const uint32_t num_elements_type = _.GetOperandTypeId(inst, 5);
2120
2121 uint32_t p_storage_class = 0;
2122 uint32_t p_data_type = 0;
2123 if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
2124 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2125 << ext_inst_name() << ": "
2126 << "expected operand Ptr to be a pointer";
2127 }
2128
2129 if (p_storage_class != SpvStorageClassCrossWorkgroup) {
2130 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2131 << ext_inst_name() << ": "
2132 << "expected operand Ptr storage class to be CrossWorkgroup";
2133 }
2134
2135 if (!_.IsFloatScalarOrVectorType(p_data_type) &&
2136 !_.IsIntScalarOrVectorType(p_data_type)) {
2137 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2138 << ext_inst_name() << ": "
2139 << "expected Ptr data type to be int or float scalar or "
2140 "vector";
2141 }
2142
2143 const uint32_t num_components = _.GetDimension(p_data_type);
2144 if (num_components > 4 && num_components != 8 && num_components != 16) {
2145 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2146 << ext_inst_name() << ": "
2147 << "expected Result Type to be a scalar or a vector with 2, "
2148 "3, 4, 8 or 16 components";
2149 }
2150
2151 const uint32_t size_t_bit_width = GetSizeTBitWidth(_);
2152 if (!size_t_bit_width) {
2153 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2154 << ext_inst_name()
2155 << " can only be used with physical addressing models";
2156 }
2157
2158 if (!_.IsIntScalarType(num_elements_type) ||
2159 _.GetBitWidth(num_elements_type) != size_t_bit_width) {
2160 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2161 << ext_inst_name() << ": "
2162 << "expected operand Num Elements to be of type size_t ("
2163 << size_t_bit_width
2164 << "-bit integer for the addressing model used in the module)";
2165 }
2166 break;
2167 }
2168 }
2169 } else if (ext_inst_type == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100) {
2170 if (!_.IsVoidType(result_type)) {
2171 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2172 << ext_inst_name() << ": "
2173 << "expected result type must be a result id of "
2174 << "OpTypeVoid";
2175 }
2176
2177 auto num_words = inst->words().size();
2178
2179 const OpenCLDebugInfo100Instructions ext_inst_key =
2180 OpenCLDebugInfo100Instructions(ext_inst_index);
2181 switch (ext_inst_key) {
2182 case OpenCLDebugInfo100DebugInfoNone:
2183 case OpenCLDebugInfo100DebugNoScope:
2184 case OpenCLDebugInfo100DebugOperation:
2185 // The binary parser validates the opcode for DebugInfoNone,
2186 // DebugNoScope, DebugOperation, and the literal values don't need
2187 // further checks.
2188 break;
2189 case OpenCLDebugInfo100DebugCompilationUnit: {
2190 CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7);
2191 break;
2192 }
2193 case OpenCLDebugInfo100DebugSource: {
2194 CHECK_OPERAND("File", SpvOpString, 5);
2195 if (num_words == 7) CHECK_OPERAND("Text", SpvOpString, 6);
2196 break;
2197 }
2198 case OpenCLDebugInfo100DebugTypeBasic: {
2199 CHECK_OPERAND("Name", SpvOpString, 5);
2200 CHECK_OPERAND("Size", SpvOpConstant, 6);
2201 // "Encoding" param is already validated by the binary parsing stage.
2202 break;
2203 }
2204 case OpenCLDebugInfo100DebugTypePointer:
2205 case OpenCLDebugInfo100DebugTypeQualifier: {
2206 auto validate_base_type =
2207 ValidateOperandBaseType(_, inst, 5, ext_inst_name);
2208 if (validate_base_type != SPV_SUCCESS) return validate_base_type;
2209 break;
2210 }
2211 case OpenCLDebugInfo100DebugTypeVector: {
2212 auto validate_base_type =
2213 ValidateOperandBaseType(_, inst, 5, ext_inst_name);
2214 if (validate_base_type != SPV_SUCCESS) return validate_base_type;
2215
2216 uint32_t component_count = inst->word(6);
2217 if (!component_count || component_count > 4) {
2218 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2219 << ext_inst_name() << ": Component Count must be positive "
2220 << "integer less than or equal to 4";
2221 }
2222 break;
2223 }
2224 case OpenCLDebugInfo100DebugTypeArray: {
2225 auto validate_base_type =
2226 ValidateOperandDebugType(_, "Base Type", inst, 5, ext_inst_name);
2227 if (validate_base_type != SPV_SUCCESS) return validate_base_type;
2228 for (uint32_t i = 6; i < num_words; ++i) {
2229 CHECK_OPERAND("Component Count", SpvOpConstant, i);
2230 auto* component_count = _.FindDef(inst->word(i));
2231 if (!_.IsIntScalarType(component_count->type_id()) ||
2232 !component_count->word(3)) {
2233 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2234 << ext_inst_name() << ": Component Count must be positive "
2235 << "integer";
2236 }
2237 }
2238 break;
2239 }
2240 case OpenCLDebugInfo100DebugTypedef: {
2241 CHECK_OPERAND("Name", SpvOpString, 5);
2242 auto validate_base_type =
2243 ValidateOperandBaseType(_, inst, 6, ext_inst_name);
2244 if (validate_base_type != SPV_SUCCESS) return validate_base_type;
2245 CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7);
2246 auto validate_parent =
2247 ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name);
2248 if (validate_parent != SPV_SUCCESS) return validate_parent;
2249 break;
2250 }
2251 case OpenCLDebugInfo100DebugTypeFunction: {
2252 auto* return_type = _.FindDef(inst->word(6));
2253 if (return_type->opcode() != SpvOpTypeVoid) {
2254 auto validate_return = ValidateOperandDebugType(
2255 _, "Return Type", inst, 6, ext_inst_name);
2256 if (validate_return != SPV_SUCCESS) return validate_return;
2257 }
2258 for (uint32_t word_index = 7; word_index < num_words; ++word_index) {
2259 auto validate_param = ValidateOperandDebugType(
2260 _, "Parameter Types", inst, word_index, ext_inst_name);
2261 if (validate_param != SPV_SUCCESS) return validate_param;
2262 }
2263 break;
2264 }
2265 case OpenCLDebugInfo100DebugTypeEnum: {
2266 CHECK_OPERAND("Name", SpvOpString, 5);
2267 if (!DoesDebugInfoOperandMatchExpectation(
2268 _,
2269 [](OpenCLDebugInfo100Instructions dbg_inst) {
2270 return dbg_inst == OpenCLDebugInfo100DebugInfoNone;
2271 },
2272 inst, 6)) {
2273 auto validate_underlying_type = ValidateOperandDebugType(
2274 _, "Underlying Types", inst, 6, ext_inst_name);
2275 if (validate_underlying_type != SPV_SUCCESS)
2276 return validate_underlying_type;
2277 }
2278 CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7);
2279 auto validate_parent =
2280 ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name);
2281 if (validate_parent != SPV_SUCCESS) return validate_parent;
2282 CHECK_OPERAND("Size", SpvOpConstant, 11);
2283 auto* size = _.FindDef(inst->word(11));
2284 if (!_.IsIntScalarType(size->type_id()) || !size->word(3)) {
2285 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2286 << ext_inst_name() << ": expected operand Size is a "
2287 << "positive integer";
2288 }
2289 for (uint32_t word_index = 13; word_index + 1 < num_words;
2290 word_index += 2) {
2291 CHECK_OPERAND("Value", SpvOpConstant, word_index);
2292 CHECK_OPERAND("Name", SpvOpString, word_index + 1);
2293 }
2294 break;
2295 }
2296 case OpenCLDebugInfo100DebugTypeComposite: {
2297 CHECK_OPERAND("Name", SpvOpString, 5);
2298 CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7);
2299 auto validate_parent =
2300 ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name);
2301 if (validate_parent != SPV_SUCCESS) return validate_parent;
2302 CHECK_OPERAND("Linkage Name", SpvOpString, 11);
2303 CHECK_OPERAND("Size", SpvOpConstant, 12);
2304 for (uint32_t word_index = 14; word_index < num_words; ++word_index) {
2305 if (!DoesDebugInfoOperandMatchExpectation(
2306 _,
2307 [](OpenCLDebugInfo100Instructions dbg_inst) {
2308 return dbg_inst == OpenCLDebugInfo100DebugTypeMember ||
2309 dbg_inst == OpenCLDebugInfo100DebugFunction ||
2310 dbg_inst == OpenCLDebugInfo100DebugTypeInheritance;
2311 },
2312 inst, word_index)) {
2313 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2314 << ext_inst_name() << ": "
2315 << "expected operand Members "
2316 << "must be DebugTypeMember, DebugFunction, or "
2317 "DebugTypeInheritance";
2318 }
2319 }
2320 break;
2321 }
2322 case OpenCLDebugInfo100DebugTypeMember: {
2323 CHECK_OPERAND("Name", SpvOpString, 5);
2324 auto validate_type =
2325 ValidateOperandDebugType(_, "Type", inst, 6, ext_inst_name);
2326 if (validate_type != SPV_SUCCESS) return validate_type;
2327 CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7);
2328 CHECK_DEBUG_OPERAND("Parent", OpenCLDebugInfo100DebugTypeComposite, 10);
2329 CHECK_OPERAND("Offset", SpvOpConstant, 11);
2330 CHECK_OPERAND("Size", SpvOpConstant, 12);
2331 if (num_words == 15) CHECK_OPERAND("Value", SpvOpConstant, 14);
2332 break;
2333 }
2334 case OpenCLDebugInfo100DebugTypeInheritance: {
2335 CHECK_DEBUG_OPERAND("Child", OpenCLDebugInfo100DebugTypeComposite, 5);
2336 auto* debug_inst = _.FindDef(inst->word(5));
2337 auto composite_type =
2338 OpenCLDebugInfo100DebugCompositeType(debug_inst->word(6));
2339 if (composite_type != OpenCLDebugInfo100Class &&
2340 composite_type != OpenCLDebugInfo100Structure) {
2341 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2342 << ext_inst_name() << ": "
2343 << "expected operand Child must be class or struct debug type";
2344 }
2345 CHECK_DEBUG_OPERAND("Parent", OpenCLDebugInfo100DebugTypeComposite, 6);
2346 debug_inst = _.FindDef(inst->word(6));
2347 composite_type =
2348 OpenCLDebugInfo100DebugCompositeType(debug_inst->word(6));
2349 if (composite_type != OpenCLDebugInfo100Class &&
2350 composite_type != OpenCLDebugInfo100Structure) {
2351 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2352 << ext_inst_name() << ": "
2353 << "expected operand Parent must be class or struct debug "
2354 "type";
2355 }
2356 CHECK_OPERAND("Offset", SpvOpConstant, 7);
2357 CHECK_OPERAND("Size", SpvOpConstant, 8);
2358 break;
2359 }
2360 case OpenCLDebugInfo100DebugFunction: {
2361 CHECK_OPERAND("Name", SpvOpString, 5);
2362 auto validate_type =
2363 ValidateOperandDebugType(_, "Type", inst, 6, ext_inst_name);
2364 if (validate_type != SPV_SUCCESS) return validate_type;
2365 CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7);
2366 auto validate_parent =
2367 ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name);
2368 if (validate_parent != SPV_SUCCESS) return validate_parent;
2369 CHECK_OPERAND("Linkage Name", SpvOpString, 11);
2370 // TODO: The current OpenCL.100.DebugInfo spec says "Function
2371 // is an OpFunction which is described by this instruction.".
2372 // However, the function definition can be opted-out e.g.,
2373 // inlining. We assume that Function operand can be a
2374 // DebugInfoNone, but we must discuss it and update the spec.
2375 if (!DoesDebugInfoOperandMatchExpectation(
2376 _,
2377 [](OpenCLDebugInfo100Instructions dbg_inst) {
2378 return dbg_inst == OpenCLDebugInfo100DebugInfoNone;
2379 },
2380 inst, 14)) {
2381 CHECK_OPERAND("Function", SpvOpFunction, 14);
2382 }
2383 if (num_words == 16) {
2384 CHECK_DEBUG_OPERAND("Declaration",
2385 OpenCLDebugInfo100DebugFunctionDeclaration, 15);
2386 }
2387 break;
2388 }
2389 case OpenCLDebugInfo100DebugFunctionDeclaration: {
2390 CHECK_OPERAND("Name", SpvOpString, 5);
2391 auto validate_type =
2392 ValidateOperandDebugType(_, "Type", inst, 6, ext_inst_name);
2393 if (validate_type != SPV_SUCCESS) return validate_type;
2394 CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7);
2395 auto validate_parent =
2396 ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name);
2397 if (validate_parent != SPV_SUCCESS) return validate_parent;
2398 CHECK_OPERAND("Linkage Name", SpvOpString, 11);
2399 break;
2400 }
2401 case OpenCLDebugInfo100DebugLexicalBlock: {
2402 CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 5);
2403 auto validate_parent =
2404 ValidateOperandLexicalScope(_, "Parent", inst, 8, ext_inst_name);
2405 if (validate_parent != SPV_SUCCESS) return validate_parent;
2406 if (num_words == 10) CHECK_OPERAND("Name", SpvOpString, 9);
2407 break;
2408 }
2409 case OpenCLDebugInfo100DebugScope: {
2410 // TODO(https://gitlab.khronos.org/spirv/SPIR-V/issues/533): We are
2411 // still in spec discussion about what must be "Scope" operand of
2412 // DebugScope. Update this code if the conclusion is different.
2413 auto validate_scope =
2414 ValidateOperandLexicalScope(_, "Scope", inst, 5, ext_inst_name);
2415 if (validate_scope != SPV_SUCCESS) return validate_scope;
2416 if (num_words == 7) {
2417 CHECK_DEBUG_OPERAND("Inlined At", OpenCLDebugInfo100DebugInlinedAt,
2418 6);
2419 }
2420 break;
2421 }
2422 case OpenCLDebugInfo100DebugLocalVariable: {
2423 CHECK_OPERAND("Name", SpvOpString, 5);
2424 auto validate_type =
2425 ValidateOperandDebugType(_, "Type", inst, 6, ext_inst_name);
2426 if (validate_type != SPV_SUCCESS) return validate_type;
2427 CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7);
2428 auto validate_parent =
2429 ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name);
2430 if (validate_parent != SPV_SUCCESS) return validate_parent;
2431 break;
2432 }
2433 case OpenCLDebugInfo100DebugDeclare: {
2434 CHECK_DEBUG_OPERAND("Local Variable",
2435 OpenCLDebugInfo100DebugLocalVariable, 5);
2436
2437 // TODO: We must discuss DebugDeclare.Variable of OpenCL.100.DebugInfo.
2438 // Currently, it says "Variable must be an id of OpVariable instruction
2439 // which defines the local variable.", but we want to allow
2440 // OpFunctionParameter as well.
2441 auto* operand = _.FindDef(inst->word(6));
2442 if (operand->opcode() != SpvOpVariable &&
2443 operand->opcode() != SpvOpFunctionParameter) {
2444 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2445 << ext_inst_name() << ": "
2446 << "expected operand Variable must be a result id of "
2447 "OpVariable or OpFunctionParameter";
2448 }
2449
2450 CHECK_DEBUG_OPERAND("Expression", OpenCLDebugInfo100DebugExpression, 7);
2451 break;
2452 }
2453 case OpenCLDebugInfo100DebugExpression: {
2454 for (uint32_t word_index = 5; word_index < num_words; ++word_index) {
2455 CHECK_DEBUG_OPERAND("Operation", OpenCLDebugInfo100DebugOperation,
2456 word_index);
2457 }
2458 break;
2459 }
2460
2461 // TODO: Add validation rules for remaining cases as well.
2462 case OpenCLDebugInfo100DebugTypePtrToMember:
2463 case OpenCLDebugInfo100DebugTypeTemplate:
2464 case OpenCLDebugInfo100DebugTypeTemplateParameter:
2465 case OpenCLDebugInfo100DebugTypeTemplateTemplateParameter:
2466 case OpenCLDebugInfo100DebugTypeTemplateParameterPack:
2467 case OpenCLDebugInfo100DebugGlobalVariable:
2468 case OpenCLDebugInfo100DebugLexicalBlockDiscriminator:
2469 case OpenCLDebugInfo100DebugInlinedAt:
2470 case OpenCLDebugInfo100DebugInlinedVariable:
2471 case OpenCLDebugInfo100DebugValue:
2472 case OpenCLDebugInfo100DebugMacroDef:
2473 case OpenCLDebugInfo100DebugMacroUndef:
2474 case OpenCLDebugInfo100DebugImportedEntity:
2475 break;
2476 case OpenCLDebugInfo100InstructionsMax:
2477 assert(0);
2478 break;
2479 }
2480 }
2481
2482 return SPV_SUCCESS;
2483}
2484
2485spv_result_t ExtensionPass(ValidationState_t& _, const Instruction* inst) {
2486 const SpvOp opcode = inst->opcode();
2487 if (opcode == SpvOpExtension) return ValidateExtension(_, inst);
2488 if (opcode == SpvOpExtInstImport) return ValidateExtInstImport(_, inst);
2489 if (opcode == SpvOpExtInst) return ValidateExtInst(_, inst);
2490
2491 return SPV_SUCCESS;
2492}
2493
2494} // namespace val
2495} // namespace spvtools
2496