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 "source/val/validate.h"
18
19 #include <sstream>
20 #include <string>
21 #include <vector>
22
23 #include "source/diagnostic.h"
24 #include "source/enum_string_mapping.h"
25 #include "source/extensions.h"
26 #include "source/latest_version_glsl_std_450_header.h"
27 #include "source/latest_version_opencl_std_header.h"
28 #include "source/opcode.h"
29 #include "source/spirv_target_env.h"
30 #include "source/val/instruction.h"
31 #include "source/val/validation_state.h"
32
33 namespace spvtools {
34 namespace val {
35 namespace {
36
GetSizeTBitWidth(const ValidationState_t & _)37 uint32_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 } // anonymous namespace
46
ValidateExtension(ValidationState_t & _,const Instruction * inst)47 spv_result_t ValidateExtension(ValidationState_t& _, const Instruction* inst) {
48 if (spvIsWebGPUEnv(_.context()->target_env)) {
49 std::string extension = GetExtensionString(&(inst->c_inst()));
50
51 if (extension != ExtensionToString(kSPV_KHR_vulkan_memory_model)) {
52 return _.diag(SPV_ERROR_INVALID_DATA, inst)
53 << "For WebGPU, the only valid parameter to OpExtension is "
54 << "\"" << ExtensionToString(kSPV_KHR_vulkan_memory_model)
55 << "\".";
56 }
57 }
58
59 return SPV_SUCCESS;
60 }
61
ValidateExtInstImport(ValidationState_t & _,const Instruction * inst)62 spv_result_t ValidateExtInstImport(ValidationState_t& _,
63 const Instruction* inst) {
64 if (spvIsWebGPUEnv(_.context()->target_env)) {
65 const auto name_id = 1;
66 const std::string name(reinterpret_cast<const char*>(
67 inst->words().data() + inst->operands()[name_id].offset));
68 if (name != "GLSL.std.450") {
69 return _.diag(SPV_ERROR_INVALID_DATA, inst)
70 << "For WebGPU, the only valid parameter to OpExtInstImport is "
71 "\"GLSL.std.450\".";
72 }
73 }
74
75 return SPV_SUCCESS;
76 }
77
ValidateExtInst(ValidationState_t & _,const Instruction * inst)78 spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) {
79 const uint32_t result_type = inst->type_id();
80 const uint32_t num_operands = static_cast<uint32_t>(inst->operands().size());
81
82 const uint32_t ext_inst_set = inst->word(3);
83 const uint32_t ext_inst_index = inst->word(4);
84 const spv_ext_inst_type_t ext_inst_type =
85 spv_ext_inst_type_t(inst->ext_inst_type());
86
87 auto ext_inst_name = [&_, ext_inst_set, ext_inst_type, ext_inst_index]() {
88 spv_ext_inst_desc desc = nullptr;
89 if (_.grammar().lookupExtInst(ext_inst_type, ext_inst_index, &desc) !=
90 SPV_SUCCESS ||
91 !desc) {
92 return std::string("Unknown ExtInst");
93 }
94
95 auto* import_inst = _.FindDef(ext_inst_set);
96 assert(import_inst);
97
98 std::ostringstream ss;
99 ss << reinterpret_cast<const char*>(import_inst->words().data() + 2);
100 ss << " ";
101 ss << desc->name;
102
103 return ss.str();
104 };
105
106 if (ext_inst_type == SPV_EXT_INST_TYPE_GLSL_STD_450) {
107 const GLSLstd450 ext_inst_key = GLSLstd450(ext_inst_index);
108 switch (ext_inst_key) {
109 case GLSLstd450Round:
110 case GLSLstd450RoundEven:
111 case GLSLstd450FAbs:
112 case GLSLstd450Trunc:
113 case GLSLstd450FSign:
114 case GLSLstd450Floor:
115 case GLSLstd450Ceil:
116 case GLSLstd450Fract:
117 case GLSLstd450Sqrt:
118 case GLSLstd450InverseSqrt:
119 case GLSLstd450FMin:
120 case GLSLstd450FMax:
121 case GLSLstd450FClamp:
122 case GLSLstd450FMix:
123 case GLSLstd450Step:
124 case GLSLstd450SmoothStep:
125 case GLSLstd450Fma:
126 case GLSLstd450Normalize:
127 case GLSLstd450FaceForward:
128 case GLSLstd450Reflect:
129 case GLSLstd450NMin:
130 case GLSLstd450NMax:
131 case GLSLstd450NClamp: {
132 if (!_.IsFloatScalarOrVectorType(result_type)) {
133 return _.diag(SPV_ERROR_INVALID_DATA, inst)
134 << ext_inst_name() << ": "
135 << "expected Result Type to be a float scalar or vector type";
136 }
137
138 for (uint32_t operand_index = 4; operand_index < num_operands;
139 ++operand_index) {
140 const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
141 if (result_type != operand_type) {
142 return _.diag(SPV_ERROR_INVALID_DATA, inst)
143 << ext_inst_name() << ": "
144 << "expected types of all operands to be equal to Result "
145 "Type";
146 }
147 }
148 break;
149 }
150
151 case GLSLstd450SAbs:
152 case GLSLstd450SSign:
153 case GLSLstd450UMin:
154 case GLSLstd450SMin:
155 case GLSLstd450UMax:
156 case GLSLstd450SMax:
157 case GLSLstd450UClamp:
158 case GLSLstd450SClamp:
159 case GLSLstd450FindILsb:
160 case GLSLstd450FindUMsb:
161 case GLSLstd450FindSMsb: {
162 if (!_.IsIntScalarOrVectorType(result_type)) {
163 return _.diag(SPV_ERROR_INVALID_DATA, inst)
164 << ext_inst_name() << ": "
165 << "expected Result Type to be an int scalar or vector type";
166 }
167
168 const uint32_t result_type_bit_width = _.GetBitWidth(result_type);
169 const uint32_t result_type_dimension = _.GetDimension(result_type);
170
171 for (uint32_t operand_index = 4; operand_index < num_operands;
172 ++operand_index) {
173 const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
174 if (!_.IsIntScalarOrVectorType(operand_type)) {
175 return _.diag(SPV_ERROR_INVALID_DATA, inst)
176 << ext_inst_name() << ": "
177 << "expected all operands to be int scalars or vectors";
178 }
179
180 if (result_type_dimension != _.GetDimension(operand_type)) {
181 return _.diag(SPV_ERROR_INVALID_DATA, inst)
182 << ext_inst_name() << ": "
183 << "expected all operands to have the same dimension as "
184 << "Result Type";
185 }
186
187 if (result_type_bit_width != _.GetBitWidth(operand_type)) {
188 return _.diag(SPV_ERROR_INVALID_DATA, inst)
189 << ext_inst_name() << ": "
190 << "expected all operands to have the same bit width as "
191 << "Result Type";
192 }
193
194 if (ext_inst_key == GLSLstd450FindUMsb ||
195 ext_inst_key == GLSLstd450FindSMsb) {
196 if (result_type_bit_width != 32) {
197 return _.diag(SPV_ERROR_INVALID_DATA, inst)
198 << ext_inst_name() << ": "
199 << "this instruction is currently limited to 32-bit width "
200 << "components";
201 }
202 }
203 }
204 break;
205 }
206
207 case GLSLstd450Radians:
208 case GLSLstd450Degrees:
209 case GLSLstd450Sin:
210 case GLSLstd450Cos:
211 case GLSLstd450Tan:
212 case GLSLstd450Asin:
213 case GLSLstd450Acos:
214 case GLSLstd450Atan:
215 case GLSLstd450Sinh:
216 case GLSLstd450Cosh:
217 case GLSLstd450Tanh:
218 case GLSLstd450Asinh:
219 case GLSLstd450Acosh:
220 case GLSLstd450Atanh:
221 case GLSLstd450Exp:
222 case GLSLstd450Exp2:
223 case GLSLstd450Log:
224 case GLSLstd450Log2:
225 case GLSLstd450Atan2:
226 case GLSLstd450Pow: {
227 if (!_.IsFloatScalarOrVectorType(result_type)) {
228 return _.diag(SPV_ERROR_INVALID_DATA, inst)
229 << ext_inst_name() << ": "
230 << "expected Result Type to be a 16 or 32-bit scalar or "
231 "vector float type";
232 }
233
234 const uint32_t result_type_bit_width = _.GetBitWidth(result_type);
235 if (result_type_bit_width != 16 && result_type_bit_width != 32) {
236 return _.diag(SPV_ERROR_INVALID_DATA, inst)
237 << ext_inst_name() << ": "
238 << "expected Result Type to be a 16 or 32-bit scalar or "
239 "vector float type";
240 }
241
242 for (uint32_t operand_index = 4; operand_index < num_operands;
243 ++operand_index) {
244 const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
245 if (result_type != operand_type) {
246 return _.diag(SPV_ERROR_INVALID_DATA, inst)
247 << ext_inst_name() << ": "
248 << "expected types of all operands to be equal to Result "
249 "Type";
250 }
251 }
252 break;
253 }
254
255 case GLSLstd450Determinant: {
256 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
257 uint32_t num_rows = 0;
258 uint32_t num_cols = 0;
259 uint32_t col_type = 0;
260 uint32_t component_type = 0;
261 if (!_.GetMatrixTypeInfo(x_type, &num_rows, &num_cols, &col_type,
262 &component_type) ||
263 num_rows != num_cols) {
264 return _.diag(SPV_ERROR_INVALID_DATA, inst)
265 << ext_inst_name() << ": "
266 << "expected operand X to be a square matrix";
267 }
268
269 if (result_type != component_type) {
270 return _.diag(SPV_ERROR_INVALID_DATA, inst)
271 << ext_inst_name() << ": "
272 << "expected operand X component type to be equal to "
273 << "Result Type";
274 }
275 break;
276 }
277
278 case GLSLstd450MatrixInverse: {
279 uint32_t num_rows = 0;
280 uint32_t num_cols = 0;
281 uint32_t col_type = 0;
282 uint32_t component_type = 0;
283 if (!_.GetMatrixTypeInfo(result_type, &num_rows, &num_cols, &col_type,
284 &component_type) ||
285 num_rows != num_cols) {
286 return _.diag(SPV_ERROR_INVALID_DATA, inst)
287 << ext_inst_name() << ": "
288 << "expected Result Type to be a square matrix";
289 }
290
291 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
292 if (result_type != x_type) {
293 return _.diag(SPV_ERROR_INVALID_DATA, inst)
294 << ext_inst_name() << ": "
295 << "expected operand X type to be equal to Result Type";
296 }
297 break;
298 }
299
300 case GLSLstd450Modf: {
301 if (!_.IsFloatScalarOrVectorType(result_type)) {
302 return _.diag(SPV_ERROR_INVALID_DATA, inst)
303 << ext_inst_name() << ": "
304 << "expected Result Type to be a scalar or vector float type";
305 }
306
307 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
308 const uint32_t i_type = _.GetOperandTypeId(inst, 5);
309
310 if (x_type != result_type) {
311 return _.diag(SPV_ERROR_INVALID_DATA, inst)
312 << ext_inst_name() << ": "
313 << "expected operand X type to be equal to Result Type";
314 }
315
316 uint32_t i_storage_class = 0;
317 uint32_t i_data_type = 0;
318 if (!_.GetPointerTypeInfo(i_type, &i_data_type, &i_storage_class)) {
319 return _.diag(SPV_ERROR_INVALID_DATA, inst)
320 << ext_inst_name() << ": "
321 << "expected operand I to be a pointer";
322 }
323
324 if (i_data_type != result_type) {
325 return _.diag(SPV_ERROR_INVALID_DATA, inst)
326 << ext_inst_name() << ": "
327 << "expected operand I data type to be equal to Result Type";
328 }
329
330 break;
331 }
332
333 case GLSLstd450ModfStruct: {
334 std::vector<uint32_t> result_types;
335 if (!_.GetStructMemberTypes(result_type, &result_types) ||
336 result_types.size() != 2 ||
337 !_.IsFloatScalarOrVectorType(result_types[0]) ||
338 result_types[1] != result_types[0]) {
339 return _.diag(SPV_ERROR_INVALID_DATA, inst)
340 << ext_inst_name() << ": "
341 << "expected Result Type to be a struct with two identical "
342 << "scalar or vector float type members";
343 }
344
345 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
346 if (x_type != result_types[0]) {
347 return _.diag(SPV_ERROR_INVALID_DATA, inst)
348 << ext_inst_name() << ": "
349 << "expected operand X type to be equal to members of "
350 << "Result Type struct";
351 }
352 break;
353 }
354
355 case GLSLstd450Frexp: {
356 if (!_.IsFloatScalarOrVectorType(result_type)) {
357 return _.diag(SPV_ERROR_INVALID_DATA, inst)
358 << ext_inst_name() << ": "
359 << "expected Result Type to be a scalar or vector float type";
360 }
361
362 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
363 const uint32_t exp_type = _.GetOperandTypeId(inst, 5);
364
365 if (x_type != result_type) {
366 return _.diag(SPV_ERROR_INVALID_DATA, inst)
367 << ext_inst_name() << ": "
368 << "expected operand X type to be equal to Result Type";
369 }
370
371 uint32_t exp_storage_class = 0;
372 uint32_t exp_data_type = 0;
373 if (!_.GetPointerTypeInfo(exp_type, &exp_data_type,
374 &exp_storage_class)) {
375 return _.diag(SPV_ERROR_INVALID_DATA, inst)
376 << ext_inst_name() << ": "
377 << "expected operand Exp to be a pointer";
378 }
379
380 if (!_.IsIntScalarOrVectorType(exp_data_type) ||
381 (!_.HasExtension(kSPV_AMD_gpu_shader_int16) &&
382 _.GetBitWidth(exp_data_type) != 32) ||
383 (_.HasExtension(kSPV_AMD_gpu_shader_int16) &&
384 _.GetBitWidth(exp_data_type) != 16 &&
385 _.GetBitWidth(exp_data_type) != 32)) {
386 return _.diag(SPV_ERROR_INVALID_DATA, inst)
387 << ext_inst_name() << ": "
388 << "expected operand Exp data type to be a "
389 << (_.HasExtension(kSPV_AMD_gpu_shader_int16)
390 ? "16-bit or 32-bit "
391 : "32-bit ")
392 << "int scalar or vector type";
393 }
394
395 if (_.GetDimension(result_type) != _.GetDimension(exp_data_type)) {
396 return _.diag(SPV_ERROR_INVALID_DATA, inst)
397 << ext_inst_name() << ": "
398 << "expected operand Exp data type to have the same component "
399 << "number as Result Type";
400 }
401
402 break;
403 }
404
405 case GLSLstd450Ldexp: {
406 if (!_.IsFloatScalarOrVectorType(result_type)) {
407 return _.diag(SPV_ERROR_INVALID_DATA, inst)
408 << ext_inst_name() << ": "
409 << "expected Result Type to be a scalar or vector float type";
410 }
411
412 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
413 const uint32_t exp_type = _.GetOperandTypeId(inst, 5);
414
415 if (x_type != result_type) {
416 return _.diag(SPV_ERROR_INVALID_DATA, inst)
417 << ext_inst_name() << ": "
418 << "expected operand X type to be equal to Result Type";
419 }
420
421 if (!_.IsIntScalarOrVectorType(exp_type)) {
422 return _.diag(SPV_ERROR_INVALID_DATA, inst)
423 << ext_inst_name() << ": "
424 << "expected operand Exp to be a 32-bit int scalar "
425 << "or vector type";
426 }
427
428 if (_.GetDimension(result_type) != _.GetDimension(exp_type)) {
429 return _.diag(SPV_ERROR_INVALID_DATA, inst)
430 << ext_inst_name() << ": "
431 << "expected operand Exp to have the same component "
432 << "number as Result Type";
433 }
434
435 break;
436 }
437
438 case GLSLstd450FrexpStruct: {
439 std::vector<uint32_t> result_types;
440 if (!_.GetStructMemberTypes(result_type, &result_types) ||
441 result_types.size() != 2 ||
442 !_.IsFloatScalarOrVectorType(result_types[0]) ||
443 !_.IsIntScalarOrVectorType(result_types[1]) ||
444 (!_.HasExtension(kSPV_AMD_gpu_shader_int16) &&
445 _.GetBitWidth(result_types[1]) != 32) ||
446 (_.HasExtension(kSPV_AMD_gpu_shader_int16) &&
447 _.GetBitWidth(result_types[1]) != 16 &&
448 _.GetBitWidth(result_types[1]) != 32) ||
449 _.GetDimension(result_types[0]) !=
450 _.GetDimension(result_types[1])) {
451 return _.diag(SPV_ERROR_INVALID_DATA, inst)
452 << ext_inst_name() << ": "
453 << "expected Result Type to be a struct with two members, "
454 << "first member a float scalar or vector, second member a "
455 << (_.HasExtension(kSPV_AMD_gpu_shader_int16)
456 ? "16-bit or 32-bit "
457 : "32-bit ")
458 << "int scalar or vector with the same number of "
459 << "components as the first member";
460 }
461
462 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
463 if (x_type != result_types[0]) {
464 return _.diag(SPV_ERROR_INVALID_DATA, inst)
465 << ext_inst_name() << ": "
466 << "expected operand X type to be equal to the first member "
467 << "of Result Type struct";
468 }
469 break;
470 }
471
472 case GLSLstd450PackSnorm4x8:
473 case GLSLstd450PackUnorm4x8: {
474 if (!_.IsIntScalarType(result_type) ||
475 _.GetBitWidth(result_type) != 32) {
476 return _.diag(SPV_ERROR_INVALID_DATA, inst)
477 << ext_inst_name() << ": "
478 << "expected Result Type to be 32-bit int scalar type";
479 }
480
481 const uint32_t v_type = _.GetOperandTypeId(inst, 4);
482 if (!_.IsFloatVectorType(v_type) || _.GetDimension(v_type) != 4 ||
483 _.GetBitWidth(v_type) != 32) {
484 return _.diag(SPV_ERROR_INVALID_DATA, inst)
485 << ext_inst_name() << ": "
486 << "expected operand V to be a 32-bit float vector of size 4";
487 }
488 break;
489 }
490
491 case GLSLstd450PackSnorm2x16:
492 case GLSLstd450PackUnorm2x16:
493 case GLSLstd450PackHalf2x16: {
494 if (!_.IsIntScalarType(result_type) ||
495 _.GetBitWidth(result_type) != 32) {
496 return _.diag(SPV_ERROR_INVALID_DATA, inst)
497 << ext_inst_name() << ": "
498 << "expected Result Type to be 32-bit int scalar type";
499 }
500
501 const uint32_t v_type = _.GetOperandTypeId(inst, 4);
502 if (!_.IsFloatVectorType(v_type) || _.GetDimension(v_type) != 2 ||
503 _.GetBitWidth(v_type) != 32) {
504 return _.diag(SPV_ERROR_INVALID_DATA, inst)
505 << ext_inst_name() << ": "
506 << "expected operand V to be a 32-bit float vector of size 2";
507 }
508 break;
509 }
510
511 case GLSLstd450PackDouble2x32: {
512 if (!_.IsFloatScalarType(result_type) ||
513 _.GetBitWidth(result_type) != 64) {
514 return _.diag(SPV_ERROR_INVALID_DATA, inst)
515 << ext_inst_name() << ": "
516 << "expected Result Type to be 64-bit float scalar type";
517 }
518
519 const uint32_t v_type = _.GetOperandTypeId(inst, 4);
520 if (!_.IsIntVectorType(v_type) || _.GetDimension(v_type) != 2 ||
521 _.GetBitWidth(v_type) != 32) {
522 return _.diag(SPV_ERROR_INVALID_DATA, inst)
523 << ext_inst_name() << ": "
524 << "expected operand V to be a 32-bit int vector of size 2";
525 }
526 break;
527 }
528
529 case GLSLstd450UnpackSnorm4x8:
530 case GLSLstd450UnpackUnorm4x8: {
531 if (!_.IsFloatVectorType(result_type) ||
532 _.GetDimension(result_type) != 4 ||
533 _.GetBitWidth(result_type) != 32) {
534 return _.diag(SPV_ERROR_INVALID_DATA, inst)
535 << ext_inst_name() << ": "
536 << "expected Result Type to be a 32-bit float vector of size "
537 "4";
538 }
539
540 const uint32_t v_type = _.GetOperandTypeId(inst, 4);
541 if (!_.IsIntScalarType(v_type) || _.GetBitWidth(v_type) != 32) {
542 return _.diag(SPV_ERROR_INVALID_DATA, inst)
543 << ext_inst_name() << ": "
544 << "expected operand P to be a 32-bit int scalar";
545 }
546 break;
547 }
548
549 case GLSLstd450UnpackSnorm2x16:
550 case GLSLstd450UnpackUnorm2x16:
551 case GLSLstd450UnpackHalf2x16: {
552 if (!_.IsFloatVectorType(result_type) ||
553 _.GetDimension(result_type) != 2 ||
554 _.GetBitWidth(result_type) != 32) {
555 return _.diag(SPV_ERROR_INVALID_DATA, inst)
556 << ext_inst_name() << ": "
557 << "expected Result Type to be a 32-bit float vector of size "
558 "2";
559 }
560
561 const uint32_t v_type = _.GetOperandTypeId(inst, 4);
562 if (!_.IsIntScalarType(v_type) || _.GetBitWidth(v_type) != 32) {
563 return _.diag(SPV_ERROR_INVALID_DATA, inst)
564 << ext_inst_name() << ": "
565 << "expected operand P to be a 32-bit int scalar";
566 }
567 break;
568 }
569
570 case GLSLstd450UnpackDouble2x32: {
571 if (!_.IsIntVectorType(result_type) ||
572 _.GetDimension(result_type) != 2 ||
573 _.GetBitWidth(result_type) != 32) {
574 return _.diag(SPV_ERROR_INVALID_DATA, inst)
575 << ext_inst_name() << ": "
576 << "expected Result Type to be a 32-bit int vector of size "
577 "2";
578 }
579
580 const uint32_t v_type = _.GetOperandTypeId(inst, 4);
581 if (!_.IsFloatScalarType(v_type) || _.GetBitWidth(v_type) != 64) {
582 return _.diag(SPV_ERROR_INVALID_DATA, inst)
583 << ext_inst_name() << ": "
584 << "expected operand V to be a 64-bit float scalar";
585 }
586 break;
587 }
588
589 case GLSLstd450Length: {
590 if (!_.IsFloatScalarType(result_type)) {
591 return _.diag(SPV_ERROR_INVALID_DATA, inst)
592 << ext_inst_name() << ": "
593 << "expected Result Type to be a float scalar type";
594 }
595
596 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
597 if (!_.IsFloatScalarOrVectorType(x_type)) {
598 return _.diag(SPV_ERROR_INVALID_DATA, inst)
599 << ext_inst_name() << ": "
600 << "expected operand X to be of float scalar or vector type";
601 }
602
603 if (result_type != _.GetComponentType(x_type)) {
604 return _.diag(SPV_ERROR_INVALID_DATA, inst)
605 << ext_inst_name() << ": "
606 << "expected operand X component type to be equal to Result "
607 "Type";
608 }
609 break;
610 }
611
612 case GLSLstd450Distance: {
613 if (!_.IsFloatScalarType(result_type)) {
614 return _.diag(SPV_ERROR_INVALID_DATA, inst)
615 << ext_inst_name() << ": "
616 << "expected Result Type to be a float scalar type";
617 }
618
619 const uint32_t p0_type = _.GetOperandTypeId(inst, 4);
620 if (!_.IsFloatScalarOrVectorType(p0_type)) {
621 return _.diag(SPV_ERROR_INVALID_DATA, inst)
622 << ext_inst_name() << ": "
623 << "expected operand P0 to be of float scalar or vector type";
624 }
625
626 if (result_type != _.GetComponentType(p0_type)) {
627 return _.diag(SPV_ERROR_INVALID_DATA, inst)
628 << ext_inst_name() << ": "
629 << "expected operand P0 component type to be equal to "
630 << "Result Type";
631 }
632
633 const uint32_t p1_type = _.GetOperandTypeId(inst, 5);
634 if (!_.IsFloatScalarOrVectorType(p1_type)) {
635 return _.diag(SPV_ERROR_INVALID_DATA, inst)
636 << ext_inst_name() << ": "
637 << "expected operand P1 to be of float scalar or vector type";
638 }
639
640 if (result_type != _.GetComponentType(p1_type)) {
641 return _.diag(SPV_ERROR_INVALID_DATA, inst)
642 << ext_inst_name() << ": "
643 << "expected operand P1 component type to be equal to "
644 << "Result Type";
645 }
646
647 if (_.GetDimension(p0_type) != _.GetDimension(p1_type)) {
648 return _.diag(SPV_ERROR_INVALID_DATA, inst)
649 << ext_inst_name() << ": "
650 << "expected operands P0 and P1 to have the same number of "
651 << "components";
652 }
653 break;
654 }
655
656 case GLSLstd450Cross: {
657 if (!_.IsFloatVectorType(result_type)) {
658 return _.diag(SPV_ERROR_INVALID_DATA, inst)
659 << ext_inst_name() << ": "
660 << "expected Result Type to be a float vector type";
661 }
662
663 if (_.GetDimension(result_type) != 3) {
664 return _.diag(SPV_ERROR_INVALID_DATA, inst)
665 << ext_inst_name() << ": "
666 << "expected Result Type to have 3 components";
667 }
668
669 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
670 const uint32_t y_type = _.GetOperandTypeId(inst, 5);
671
672 if (x_type != result_type) {
673 return _.diag(SPV_ERROR_INVALID_DATA, inst)
674 << ext_inst_name() << ": "
675 << "expected operand X type to be equal to Result Type";
676 }
677
678 if (y_type != result_type) {
679 return _.diag(SPV_ERROR_INVALID_DATA, inst)
680 << ext_inst_name() << ": "
681 << "expected operand Y type to be equal to Result Type";
682 }
683 break;
684 }
685
686 case GLSLstd450Refract: {
687 if (!_.IsFloatScalarOrVectorType(result_type)) {
688 return _.diag(SPV_ERROR_INVALID_DATA, inst)
689 << ext_inst_name() << ": "
690 << "expected Result Type to be a float scalar or vector type";
691 }
692
693 const uint32_t i_type = _.GetOperandTypeId(inst, 4);
694 const uint32_t n_type = _.GetOperandTypeId(inst, 5);
695 const uint32_t eta_type = _.GetOperandTypeId(inst, 6);
696
697 if (result_type != i_type) {
698 return _.diag(SPV_ERROR_INVALID_DATA, inst)
699 << ext_inst_name() << ": "
700 << "expected operand I to be of type equal to Result Type";
701 }
702
703 if (result_type != n_type) {
704 return _.diag(SPV_ERROR_INVALID_DATA, inst)
705 << ext_inst_name() << ": "
706 << "expected operand N to be of type equal to Result Type";
707 }
708
709 if (!_.IsFloatScalarType(eta_type)) {
710 return _.diag(SPV_ERROR_INVALID_DATA, inst)
711 << ext_inst_name() << ": "
712 << "expected operand Eta to be a float scalar";
713 }
714 break;
715 }
716
717 case GLSLstd450InterpolateAtCentroid:
718 case GLSLstd450InterpolateAtSample:
719 case GLSLstd450InterpolateAtOffset: {
720 if (!_.HasCapability(SpvCapabilityInterpolationFunction)) {
721 return _.diag(SPV_ERROR_INVALID_CAPABILITY, inst)
722 << ext_inst_name()
723 << " requires capability InterpolationFunction";
724 }
725
726 if (!_.IsFloatScalarOrVectorType(result_type) ||
727 _.GetBitWidth(result_type) != 32) {
728 return _.diag(SPV_ERROR_INVALID_DATA, inst)
729 << ext_inst_name() << ": "
730 << "expected Result Type to be a 32-bit float scalar "
731 << "or vector type";
732 }
733
734 const uint32_t interpolant_type = _.GetOperandTypeId(inst, 4);
735 uint32_t interpolant_storage_class = 0;
736 uint32_t interpolant_data_type = 0;
737 if (!_.GetPointerTypeInfo(interpolant_type, &interpolant_data_type,
738 &interpolant_storage_class)) {
739 return _.diag(SPV_ERROR_INVALID_DATA, inst)
740 << ext_inst_name() << ": "
741 << "expected Interpolant to be a pointer";
742 }
743
744 if (result_type != interpolant_data_type) {
745 return _.diag(SPV_ERROR_INVALID_DATA, inst)
746 << ext_inst_name() << ": "
747 << "expected Interpolant data type to be equal to Result Type";
748 }
749
750 if (interpolant_storage_class != SpvStorageClassInput) {
751 return _.diag(SPV_ERROR_INVALID_DATA, inst)
752 << ext_inst_name() << ": "
753 << "expected Interpolant storage class to be Input";
754 }
755
756 if (ext_inst_key == GLSLstd450InterpolateAtSample) {
757 const uint32_t sample_type = _.GetOperandTypeId(inst, 5);
758 if (!_.IsIntScalarType(sample_type) ||
759 _.GetBitWidth(sample_type) != 32) {
760 return _.diag(SPV_ERROR_INVALID_DATA, inst)
761 << ext_inst_name() << ": "
762 << "expected Sample to be 32-bit integer";
763 }
764 }
765
766 if (ext_inst_key == GLSLstd450InterpolateAtOffset) {
767 const uint32_t offset_type = _.GetOperandTypeId(inst, 5);
768 if (!_.IsFloatVectorType(offset_type) ||
769 _.GetDimension(offset_type) != 2 ||
770 _.GetBitWidth(offset_type) != 32) {
771 return _.diag(SPV_ERROR_INVALID_DATA, inst)
772 << ext_inst_name() << ": "
773 << "expected Offset to be a vector of 2 32-bit floats";
774 }
775 }
776
777 _.function(inst->function()->id())
778 ->RegisterExecutionModelLimitation(
779 SpvExecutionModelFragment,
780 ext_inst_name() +
781 std::string(" requires Fragment execution model"));
782 break;
783 }
784
785 case GLSLstd450IMix: {
786 return _.diag(SPV_ERROR_INVALID_DATA, inst)
787 << "Extended instruction GLSLstd450IMix is not supported";
788 }
789
790 case GLSLstd450Bad: {
791 return _.diag(SPV_ERROR_INVALID_DATA, inst)
792 << "Encountered extended instruction GLSLstd450Bad";
793 }
794
795 case GLSLstd450Count: {
796 assert(0);
797 break;
798 }
799 }
800 } else if (ext_inst_type == SPV_EXT_INST_TYPE_OPENCL_STD) {
801 const OpenCLLIB::Entrypoints ext_inst_key =
802 OpenCLLIB::Entrypoints(ext_inst_index);
803 switch (ext_inst_key) {
804 case OpenCLLIB::Acos:
805 case OpenCLLIB::Acosh:
806 case OpenCLLIB::Acospi:
807 case OpenCLLIB::Asin:
808 case OpenCLLIB::Asinh:
809 case OpenCLLIB::Asinpi:
810 case OpenCLLIB::Atan:
811 case OpenCLLIB::Atan2:
812 case OpenCLLIB::Atanh:
813 case OpenCLLIB::Atanpi:
814 case OpenCLLIB::Atan2pi:
815 case OpenCLLIB::Cbrt:
816 case OpenCLLIB::Ceil:
817 case OpenCLLIB::Copysign:
818 case OpenCLLIB::Cos:
819 case OpenCLLIB::Cosh:
820 case OpenCLLIB::Cospi:
821 case OpenCLLIB::Erfc:
822 case OpenCLLIB::Erf:
823 case OpenCLLIB::Exp:
824 case OpenCLLIB::Exp2:
825 case OpenCLLIB::Exp10:
826 case OpenCLLIB::Expm1:
827 case OpenCLLIB::Fabs:
828 case OpenCLLIB::Fdim:
829 case OpenCLLIB::Floor:
830 case OpenCLLIB::Fma:
831 case OpenCLLIB::Fmax:
832 case OpenCLLIB::Fmin:
833 case OpenCLLIB::Fmod:
834 case OpenCLLIB::Hypot:
835 case OpenCLLIB::Lgamma:
836 case OpenCLLIB::Log:
837 case OpenCLLIB::Log2:
838 case OpenCLLIB::Log10:
839 case OpenCLLIB::Log1p:
840 case OpenCLLIB::Logb:
841 case OpenCLLIB::Mad:
842 case OpenCLLIB::Maxmag:
843 case OpenCLLIB::Minmag:
844 case OpenCLLIB::Nextafter:
845 case OpenCLLIB::Pow:
846 case OpenCLLIB::Powr:
847 case OpenCLLIB::Remainder:
848 case OpenCLLIB::Rint:
849 case OpenCLLIB::Round:
850 case OpenCLLIB::Rsqrt:
851 case OpenCLLIB::Sin:
852 case OpenCLLIB::Sinh:
853 case OpenCLLIB::Sinpi:
854 case OpenCLLIB::Sqrt:
855 case OpenCLLIB::Tan:
856 case OpenCLLIB::Tanh:
857 case OpenCLLIB::Tanpi:
858 case OpenCLLIB::Tgamma:
859 case OpenCLLIB::Trunc:
860 case OpenCLLIB::Half_cos:
861 case OpenCLLIB::Half_divide:
862 case OpenCLLIB::Half_exp:
863 case OpenCLLIB::Half_exp2:
864 case OpenCLLIB::Half_exp10:
865 case OpenCLLIB::Half_log:
866 case OpenCLLIB::Half_log2:
867 case OpenCLLIB::Half_log10:
868 case OpenCLLIB::Half_powr:
869 case OpenCLLIB::Half_recip:
870 case OpenCLLIB::Half_rsqrt:
871 case OpenCLLIB::Half_sin:
872 case OpenCLLIB::Half_sqrt:
873 case OpenCLLIB::Half_tan:
874 case OpenCLLIB::Native_cos:
875 case OpenCLLIB::Native_divide:
876 case OpenCLLIB::Native_exp:
877 case OpenCLLIB::Native_exp2:
878 case OpenCLLIB::Native_exp10:
879 case OpenCLLIB::Native_log:
880 case OpenCLLIB::Native_log2:
881 case OpenCLLIB::Native_log10:
882 case OpenCLLIB::Native_powr:
883 case OpenCLLIB::Native_recip:
884 case OpenCLLIB::Native_rsqrt:
885 case OpenCLLIB::Native_sin:
886 case OpenCLLIB::Native_sqrt:
887 case OpenCLLIB::Native_tan:
888 case OpenCLLIB::FClamp:
889 case OpenCLLIB::Degrees:
890 case OpenCLLIB::FMax_common:
891 case OpenCLLIB::FMin_common:
892 case OpenCLLIB::Mix:
893 case OpenCLLIB::Radians:
894 case OpenCLLIB::Step:
895 case OpenCLLIB::Smoothstep:
896 case OpenCLLIB::Sign: {
897 if (!_.IsFloatScalarOrVectorType(result_type)) {
898 return _.diag(SPV_ERROR_INVALID_DATA, inst)
899 << ext_inst_name() << ": "
900 << "expected Result Type to be a float scalar or vector type";
901 }
902
903 const uint32_t num_components = _.GetDimension(result_type);
904 if (num_components > 4 && num_components != 8 && num_components != 16) {
905 return _.diag(SPV_ERROR_INVALID_DATA, inst)
906 << ext_inst_name() << ": "
907 << "expected Result Type to be a scalar or a vector with 2, "
908 "3, 4, 8 or 16 components";
909 }
910
911 for (uint32_t operand_index = 4; operand_index < num_operands;
912 ++operand_index) {
913 const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
914 if (result_type != operand_type) {
915 return _.diag(SPV_ERROR_INVALID_DATA, inst)
916 << ext_inst_name() << ": "
917 << "expected types of all operands to be equal to Result "
918 "Type";
919 }
920 }
921 break;
922 }
923
924 case OpenCLLIB::Fract:
925 case OpenCLLIB::Modf:
926 case OpenCLLIB::Sincos:
927 case OpenCLLIB::Remquo: {
928 if (!_.IsFloatScalarOrVectorType(result_type)) {
929 return _.diag(SPV_ERROR_INVALID_DATA, inst)
930 << ext_inst_name() << ": "
931 << "expected Result Type to be a float scalar or vector type";
932 }
933
934 const uint32_t num_components = _.GetDimension(result_type);
935 if (num_components > 4 && num_components != 8 && num_components != 16) {
936 return _.diag(SPV_ERROR_INVALID_DATA, inst)
937 << ext_inst_name() << ": "
938 << "expected Result Type to be a scalar or a vector with 2, "
939 "3, 4, 8 or 16 components";
940 }
941
942 uint32_t operand_index = 4;
943 const uint32_t x_type = _.GetOperandTypeId(inst, operand_index++);
944 if (result_type != x_type) {
945 return _.diag(SPV_ERROR_INVALID_DATA, inst)
946 << ext_inst_name() << ": "
947 << "expected type of operand X to be equal to Result Type";
948 }
949
950 if (ext_inst_key == OpenCLLIB::Remquo) {
951 const uint32_t y_type = _.GetOperandTypeId(inst, operand_index++);
952 if (result_type != y_type) {
953 return _.diag(SPV_ERROR_INVALID_DATA, inst)
954 << ext_inst_name() << ": "
955 << "expected type of operand Y to be equal to Result Type";
956 }
957 }
958
959 const uint32_t p_type = _.GetOperandTypeId(inst, operand_index++);
960 uint32_t p_storage_class = 0;
961 uint32_t p_data_type = 0;
962 if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
963 return _.diag(SPV_ERROR_INVALID_DATA, inst)
964 << ext_inst_name() << ": "
965 << "expected the last operand to be a pointer";
966 }
967
968 if (p_storage_class != SpvStorageClassGeneric &&
969 p_storage_class != SpvStorageClassCrossWorkgroup &&
970 p_storage_class != SpvStorageClassWorkgroup &&
971 p_storage_class != SpvStorageClassFunction) {
972 return _.diag(SPV_ERROR_INVALID_DATA, inst)
973 << ext_inst_name() << ": "
974 << "expected storage class of the pointer to be Generic, "
975 "CrossWorkgroup, Workgroup or Function";
976 }
977
978 if (result_type != p_data_type) {
979 return _.diag(SPV_ERROR_INVALID_DATA, inst)
980 << ext_inst_name() << ": "
981 << "expected data type of the pointer to be equal to Result "
982 "Type";
983 }
984 break;
985 }
986
987 case OpenCLLIB::Frexp:
988 case OpenCLLIB::Lgamma_r: {
989 if (!_.IsFloatScalarOrVectorType(result_type)) {
990 return _.diag(SPV_ERROR_INVALID_DATA, inst)
991 << ext_inst_name() << ": "
992 << "expected Result Type to be a float scalar or vector type";
993 }
994
995 const uint32_t num_components = _.GetDimension(result_type);
996 if (num_components > 4 && num_components != 8 && num_components != 16) {
997 return _.diag(SPV_ERROR_INVALID_DATA, inst)
998 << ext_inst_name() << ": "
999 << "expected Result Type to be a scalar or a vector with 2, "
1000 "3, 4, 8 or 16 components";
1001 }
1002
1003 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
1004 if (result_type != x_type) {
1005 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1006 << ext_inst_name() << ": "
1007 << "expected type of operand X to be equal to Result Type";
1008 }
1009
1010 const uint32_t p_type = _.GetOperandTypeId(inst, 5);
1011 uint32_t p_storage_class = 0;
1012 uint32_t p_data_type = 0;
1013 if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
1014 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1015 << ext_inst_name() << ": "
1016 << "expected the last operand to be a pointer";
1017 }
1018
1019 if (p_storage_class != SpvStorageClassGeneric &&
1020 p_storage_class != SpvStorageClassCrossWorkgroup &&
1021 p_storage_class != SpvStorageClassWorkgroup &&
1022 p_storage_class != SpvStorageClassFunction) {
1023 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1024 << ext_inst_name() << ": "
1025 << "expected storage class of the pointer to be Generic, "
1026 "CrossWorkgroup, Workgroup or Function";
1027 }
1028
1029 if (!_.IsIntScalarOrVectorType(p_data_type) ||
1030 _.GetBitWidth(p_data_type) != 32) {
1031 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1032 << ext_inst_name() << ": "
1033 << "expected data type of the pointer to be a 32-bit int "
1034 "scalar or vector type";
1035 }
1036
1037 if (_.GetDimension(p_data_type) != num_components) {
1038 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1039 << ext_inst_name() << ": "
1040 << "expected data type of the pointer to have the same number "
1041 "of components as Result Type";
1042 }
1043 break;
1044 }
1045
1046 case OpenCLLIB::Ilogb: {
1047 if (!_.IsIntScalarOrVectorType(result_type) ||
1048 _.GetBitWidth(result_type) != 32) {
1049 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1050 << ext_inst_name() << ": "
1051 << "expected Result Type to be a 32-bit int scalar or vector "
1052 "type";
1053 }
1054
1055 const uint32_t num_components = _.GetDimension(result_type);
1056 if (num_components > 4 && num_components != 8 && num_components != 16) {
1057 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1058 << ext_inst_name() << ": "
1059 << "expected Result Type to be a scalar or a vector with 2, "
1060 "3, 4, 8 or 16 components";
1061 }
1062
1063 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
1064 if (!_.IsFloatScalarOrVectorType(x_type)) {
1065 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1066 << ext_inst_name() << ": "
1067 << "expected operand X to be a float scalar or vector";
1068 }
1069
1070 if (_.GetDimension(x_type) != num_components) {
1071 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1072 << ext_inst_name() << ": "
1073 << "expected operand X to have the same number of components "
1074 "as Result Type";
1075 }
1076 break;
1077 }
1078
1079 case OpenCLLIB::Ldexp:
1080 case OpenCLLIB::Pown:
1081 case OpenCLLIB::Rootn: {
1082 if (!_.IsFloatScalarOrVectorType(result_type)) {
1083 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1084 << ext_inst_name() << ": "
1085 << "expected Result Type to be a float scalar or vector type";
1086 }
1087
1088 const uint32_t num_components = _.GetDimension(result_type);
1089 if (num_components > 4 && num_components != 8 && num_components != 16) {
1090 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1091 << ext_inst_name() << ": "
1092 << "expected Result Type to be a scalar or a vector with 2, "
1093 "3, 4, 8 or 16 components";
1094 }
1095
1096 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
1097 if (result_type != x_type) {
1098 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1099 << ext_inst_name() << ": "
1100 << "expected type of operand X to be equal to Result Type";
1101 }
1102
1103 const uint32_t exp_type = _.GetOperandTypeId(inst, 5);
1104 if (!_.IsIntScalarOrVectorType(exp_type) ||
1105 _.GetBitWidth(exp_type) != 32) {
1106 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1107 << ext_inst_name() << ": "
1108 << "expected the exponent to be a 32-bit int scalar or vector";
1109 }
1110
1111 if (_.GetDimension(exp_type) != num_components) {
1112 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1113 << ext_inst_name() << ": "
1114 << "expected the exponent to have the same number of "
1115 "components as Result Type";
1116 }
1117 break;
1118 }
1119
1120 case OpenCLLIB::Nan: {
1121 if (!_.IsFloatScalarOrVectorType(result_type)) {
1122 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1123 << ext_inst_name() << ": "
1124 << "expected Result Type to be a float scalar or vector type";
1125 }
1126
1127 const uint32_t num_components = _.GetDimension(result_type);
1128 if (num_components > 4 && num_components != 8 && num_components != 16) {
1129 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1130 << ext_inst_name() << ": "
1131 << "expected Result Type to be a scalar or a vector with 2, "
1132 "3, 4, 8 or 16 components";
1133 }
1134
1135 const uint32_t nancode_type = _.GetOperandTypeId(inst, 4);
1136 if (!_.IsIntScalarOrVectorType(nancode_type)) {
1137 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1138 << ext_inst_name() << ": "
1139 << "expected Nancode to be an int scalar or vector type";
1140 }
1141
1142 if (_.GetDimension(nancode_type) != num_components) {
1143 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1144 << ext_inst_name() << ": "
1145 << "expected Nancode to have the same number of components as "
1146 "Result Type";
1147 }
1148
1149 if (_.GetBitWidth(result_type) != _.GetBitWidth(nancode_type)) {
1150 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1151 << ext_inst_name() << ": "
1152 << "expected Nancode to have the same bit width as Result "
1153 "Type";
1154 }
1155 break;
1156 }
1157
1158 case OpenCLLIB::SAbs:
1159 case OpenCLLIB::SAbs_diff:
1160 case OpenCLLIB::SAdd_sat:
1161 case OpenCLLIB::UAdd_sat:
1162 case OpenCLLIB::SHadd:
1163 case OpenCLLIB::UHadd:
1164 case OpenCLLIB::SRhadd:
1165 case OpenCLLIB::URhadd:
1166 case OpenCLLIB::SClamp:
1167 case OpenCLLIB::UClamp:
1168 case OpenCLLIB::Clz:
1169 case OpenCLLIB::Ctz:
1170 case OpenCLLIB::SMad_hi:
1171 case OpenCLLIB::UMad_sat:
1172 case OpenCLLIB::SMad_sat:
1173 case OpenCLLIB::SMax:
1174 case OpenCLLIB::UMax:
1175 case OpenCLLIB::SMin:
1176 case OpenCLLIB::UMin:
1177 case OpenCLLIB::SMul_hi:
1178 case OpenCLLIB::Rotate:
1179 case OpenCLLIB::SSub_sat:
1180 case OpenCLLIB::USub_sat:
1181 case OpenCLLIB::Popcount:
1182 case OpenCLLIB::UAbs:
1183 case OpenCLLIB::UAbs_diff:
1184 case OpenCLLIB::UMul_hi:
1185 case OpenCLLIB::UMad_hi: {
1186 if (!_.IsIntScalarOrVectorType(result_type)) {
1187 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1188 << ext_inst_name() << ": "
1189 << "expected Result Type to be an int scalar or vector type";
1190 }
1191
1192 const uint32_t num_components = _.GetDimension(result_type);
1193 if (num_components > 4 && num_components != 8 && num_components != 16) {
1194 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1195 << ext_inst_name() << ": "
1196 << "expected Result Type to be a scalar or a vector with 2, "
1197 "3, 4, 8 or 16 components";
1198 }
1199
1200 for (uint32_t operand_index = 4; operand_index < num_operands;
1201 ++operand_index) {
1202 const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
1203 if (result_type != operand_type) {
1204 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1205 << ext_inst_name() << ": "
1206 << "expected types of all operands to be equal to Result "
1207 "Type";
1208 }
1209 }
1210 break;
1211 }
1212
1213 case OpenCLLIB::U_Upsample:
1214 case OpenCLLIB::S_Upsample: {
1215 if (!_.IsIntScalarOrVectorType(result_type)) {
1216 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1217 << ext_inst_name() << ": "
1218 << "expected Result Type to be an int scalar or vector "
1219 "type";
1220 }
1221
1222 const uint32_t result_num_components = _.GetDimension(result_type);
1223 if (result_num_components > 4 && result_num_components != 8 &&
1224 result_num_components != 16) {
1225 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1226 << ext_inst_name() << ": "
1227 << "expected Result Type to be a scalar or a vector with 2, "
1228 "3, 4, 8 or 16 components";
1229 }
1230
1231 const uint32_t result_bit_width = _.GetBitWidth(result_type);
1232 if (result_bit_width != 16 && result_bit_width != 32 &&
1233 result_bit_width != 64) {
1234 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1235 << ext_inst_name() << ": "
1236 << "expected bit width of Result Type components to be 16, 32 "
1237 "or 64";
1238 }
1239
1240 const uint32_t hi_type = _.GetOperandTypeId(inst, 4);
1241 const uint32_t lo_type = _.GetOperandTypeId(inst, 5);
1242
1243 if (hi_type != lo_type) {
1244 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1245 << ext_inst_name() << ": "
1246 << "expected Hi and Lo operands to have the same type";
1247 }
1248
1249 if (result_num_components != _.GetDimension(hi_type)) {
1250 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1251 << ext_inst_name() << ": "
1252 << "expected Hi and Lo operands to have the same number of "
1253 "components as Result Type";
1254 }
1255
1256 if (result_bit_width != 2 * _.GetBitWidth(hi_type)) {
1257 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1258 << ext_inst_name() << ": "
1259 << "expected bit width of components of Hi and Lo operands to "
1260 "be half of the bit width of components of Result Type";
1261 }
1262 break;
1263 }
1264
1265 case OpenCLLIB::SMad24:
1266 case OpenCLLIB::UMad24:
1267 case OpenCLLIB::SMul24:
1268 case OpenCLLIB::UMul24: {
1269 if (!_.IsIntScalarOrVectorType(result_type) ||
1270 _.GetBitWidth(result_type) != 32) {
1271 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1272 << ext_inst_name() << ": "
1273 << "expected Result Type to be a 32-bit int scalar or vector "
1274 "type";
1275 }
1276
1277 const uint32_t num_components = _.GetDimension(result_type);
1278 if (num_components > 4 && num_components != 8 && num_components != 16) {
1279 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1280 << ext_inst_name() << ": "
1281 << "expected Result Type to be a scalar or a vector with 2, "
1282 "3, 4, 8 or 16 components";
1283 }
1284
1285 for (uint32_t operand_index = 4; operand_index < num_operands;
1286 ++operand_index) {
1287 const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
1288 if (result_type != operand_type) {
1289 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1290 << ext_inst_name() << ": "
1291 << "expected types of all operands to be equal to Result "
1292 "Type";
1293 }
1294 }
1295 break;
1296 }
1297
1298 case OpenCLLIB::Cross: {
1299 if (!_.IsFloatVectorType(result_type)) {
1300 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1301 << ext_inst_name() << ": "
1302 << "expected Result Type to be a float vector type";
1303 }
1304
1305 const uint32_t num_components = _.GetDimension(result_type);
1306 if (num_components != 3 && num_components != 4) {
1307 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1308 << ext_inst_name() << ": "
1309 << "expected Result Type to have 3 or 4 components";
1310 }
1311
1312 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
1313 const uint32_t y_type = _.GetOperandTypeId(inst, 5);
1314
1315 if (x_type != result_type) {
1316 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1317 << ext_inst_name() << ": "
1318 << "expected operand X type to be equal to Result Type";
1319 }
1320
1321 if (y_type != result_type) {
1322 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1323 << ext_inst_name() << ": "
1324 << "expected operand Y type to be equal to Result Type";
1325 }
1326 break;
1327 }
1328
1329 case OpenCLLIB::Distance:
1330 case OpenCLLIB::Fast_distance: {
1331 if (!_.IsFloatScalarType(result_type)) {
1332 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1333 << ext_inst_name() << ": "
1334 << "expected Result Type to be a float scalar type";
1335 }
1336
1337 const uint32_t p0_type = _.GetOperandTypeId(inst, 4);
1338 if (!_.IsFloatScalarOrVectorType(p0_type)) {
1339 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1340 << ext_inst_name() << ": "
1341 << "expected operand P0 to be of float scalar or vector type";
1342 }
1343
1344 const uint32_t num_components = _.GetDimension(p0_type);
1345 if (num_components > 4) {
1346 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1347 << ext_inst_name() << ": "
1348 << "expected operand P0 to have no more than 4 components";
1349 }
1350
1351 if (result_type != _.GetComponentType(p0_type)) {
1352 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1353 << ext_inst_name() << ": "
1354 << "expected operand P0 component type to be equal to "
1355 << "Result Type";
1356 }
1357
1358 const uint32_t p1_type = _.GetOperandTypeId(inst, 5);
1359 if (p0_type != p1_type) {
1360 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1361 << ext_inst_name() << ": "
1362 << "expected operands P0 and P1 to be of the same type";
1363 }
1364 break;
1365 }
1366
1367 case OpenCLLIB::Length:
1368 case OpenCLLIB::Fast_length: {
1369 if (!_.IsFloatScalarType(result_type)) {
1370 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1371 << ext_inst_name() << ": "
1372 << "expected Result Type to be a float scalar type";
1373 }
1374
1375 const uint32_t p_type = _.GetOperandTypeId(inst, 4);
1376 if (!_.IsFloatScalarOrVectorType(p_type)) {
1377 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1378 << ext_inst_name() << ": "
1379 << "expected operand P to be a float scalar or vector";
1380 }
1381
1382 const uint32_t num_components = _.GetDimension(p_type);
1383 if (num_components > 4) {
1384 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1385 << ext_inst_name() << ": "
1386 << "expected operand P to have no more than 4 components";
1387 }
1388
1389 if (result_type != _.GetComponentType(p_type)) {
1390 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1391 << ext_inst_name() << ": "
1392 << "expected operand P component type to be equal to Result "
1393 "Type";
1394 }
1395 break;
1396 }
1397
1398 case OpenCLLIB::Normalize:
1399 case OpenCLLIB::Fast_normalize: {
1400 if (!_.IsFloatScalarOrVectorType(result_type)) {
1401 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1402 << ext_inst_name() << ": "
1403 << "expected Result Type to be a float scalar or vector type";
1404 }
1405
1406 const uint32_t num_components = _.GetDimension(result_type);
1407 if (num_components > 4) {
1408 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1409 << ext_inst_name() << ": "
1410 << "expected Result Type to have no more than 4 components";
1411 }
1412
1413 const uint32_t p_type = _.GetOperandTypeId(inst, 4);
1414 if (p_type != result_type) {
1415 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1416 << ext_inst_name() << ": "
1417 << "expected operand P type to be equal to Result Type";
1418 }
1419 break;
1420 }
1421
1422 case OpenCLLIB::Bitselect: {
1423 if (!_.IsFloatScalarOrVectorType(result_type) &&
1424 !_.IsIntScalarOrVectorType(result_type)) {
1425 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1426 << ext_inst_name() << ": "
1427 << "expected Result Type to be an int or float scalar or "
1428 "vector type";
1429 }
1430
1431 const uint32_t num_components = _.GetDimension(result_type);
1432 if (num_components > 4 && num_components != 8 && num_components != 16) {
1433 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1434 << ext_inst_name() << ": "
1435 << "expected Result Type to be a scalar or a vector with 2, "
1436 "3, 4, 8 or 16 components";
1437 }
1438
1439 for (uint32_t operand_index = 4; operand_index < num_operands;
1440 ++operand_index) {
1441 const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
1442 if (result_type != operand_type) {
1443 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1444 << ext_inst_name() << ": "
1445 << "expected types of all operands to be equal to Result "
1446 "Type";
1447 }
1448 }
1449 break;
1450 }
1451
1452 case OpenCLLIB::Select: {
1453 if (!_.IsFloatScalarOrVectorType(result_type) &&
1454 !_.IsIntScalarOrVectorType(result_type)) {
1455 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1456 << ext_inst_name() << ": "
1457 << "expected Result Type to be an int or float scalar or "
1458 "vector type";
1459 }
1460
1461 const uint32_t num_components = _.GetDimension(result_type);
1462 if (num_components > 4 && num_components != 8 && num_components != 16) {
1463 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1464 << ext_inst_name() << ": "
1465 << "expected Result Type to be a scalar or a vector with 2, "
1466 "3, 4, 8 or 16 components";
1467 }
1468
1469 const uint32_t a_type = _.GetOperandTypeId(inst, 4);
1470 const uint32_t b_type = _.GetOperandTypeId(inst, 5);
1471 const uint32_t c_type = _.GetOperandTypeId(inst, 6);
1472
1473 if (result_type != a_type) {
1474 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1475 << ext_inst_name() << ": "
1476 << "expected operand A type to be equal to Result Type";
1477 }
1478
1479 if (result_type != b_type) {
1480 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1481 << ext_inst_name() << ": "
1482 << "expected operand B type to be equal to Result Type";
1483 }
1484
1485 if (!_.IsIntScalarOrVectorType(c_type)) {
1486 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1487 << ext_inst_name() << ": "
1488 << "expected operand C to be an int scalar or vector";
1489 }
1490
1491 if (num_components != _.GetDimension(c_type)) {
1492 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1493 << ext_inst_name() << ": "
1494 << "expected operand C to have the same number of components "
1495 "as Result Type";
1496 }
1497
1498 if (_.GetBitWidth(result_type) != _.GetBitWidth(c_type)) {
1499 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1500 << ext_inst_name() << ": "
1501 << "expected operand C to have the same bit width as Result "
1502 "Type";
1503 }
1504 break;
1505 }
1506
1507 case OpenCLLIB::Vloadn: {
1508 if (!_.IsFloatVectorType(result_type) &&
1509 !_.IsIntVectorType(result_type)) {
1510 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1511 << ext_inst_name() << ": "
1512 << "expected Result Type to be an int or float vector type";
1513 }
1514
1515 const uint32_t num_components = _.GetDimension(result_type);
1516 if (num_components > 4 && num_components != 8 && num_components != 16) {
1517 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1518 << ext_inst_name() << ": "
1519 << "expected Result Type to have 2, 3, 4, 8 or 16 components";
1520 }
1521
1522 const uint32_t offset_type = _.GetOperandTypeId(inst, 4);
1523 const uint32_t p_type = _.GetOperandTypeId(inst, 5);
1524
1525 const uint32_t size_t_bit_width = GetSizeTBitWidth(_);
1526 if (!size_t_bit_width) {
1527 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1528 << ext_inst_name()
1529 << " can only be used with physical addressing models";
1530 }
1531
1532 if (!_.IsIntScalarType(offset_type) ||
1533 _.GetBitWidth(offset_type) != size_t_bit_width) {
1534 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1535 << ext_inst_name() << ": "
1536 << "expected operand Offset to be of type size_t ("
1537 << size_t_bit_width
1538 << "-bit integer for the addressing model used in the module)";
1539 }
1540
1541 uint32_t p_storage_class = 0;
1542 uint32_t p_data_type = 0;
1543 if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
1544 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1545 << ext_inst_name() << ": "
1546 << "expected operand P to be a pointer";
1547 }
1548
1549 if (p_storage_class != SpvStorageClassUniformConstant &&
1550 p_storage_class != SpvStorageClassGeneric) {
1551 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1552 << ext_inst_name() << ": "
1553 << "expected operand P storage class to be UniformConstant or "
1554 "Generic";
1555 }
1556
1557 if (_.GetComponentType(result_type) != p_data_type) {
1558 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1559 << ext_inst_name() << ": "
1560 << "expected operand P data type to be equal to component "
1561 "type of Result Type";
1562 }
1563
1564 const uint32_t n_value = inst->word(7);
1565 if (num_components != n_value) {
1566 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1567 << ext_inst_name() << ": "
1568 << "expected literal N to be equal to the number of "
1569 "components of Result Type";
1570 }
1571 break;
1572 }
1573
1574 case OpenCLLIB::Vstoren: {
1575 if (_.GetIdOpcode(result_type) != SpvOpTypeVoid) {
1576 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1577 << ext_inst_name() << ": expected Result Type to be void";
1578 }
1579
1580 const uint32_t data_type = _.GetOperandTypeId(inst, 4);
1581 const uint32_t offset_type = _.GetOperandTypeId(inst, 5);
1582 const uint32_t p_type = _.GetOperandTypeId(inst, 6);
1583
1584 if (!_.IsFloatVectorType(data_type) && !_.IsIntVectorType(data_type)) {
1585 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1586 << ext_inst_name() << ": "
1587 << "expected Data to be an int or float vector";
1588 }
1589
1590 const uint32_t num_components = _.GetDimension(data_type);
1591 if (num_components > 4 && num_components != 8 && num_components != 16) {
1592 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1593 << ext_inst_name() << ": "
1594 << "expected Data to have 2, 3, 4, 8 or 16 components";
1595 }
1596
1597 const uint32_t size_t_bit_width = GetSizeTBitWidth(_);
1598 if (!size_t_bit_width) {
1599 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1600 << ext_inst_name()
1601 << " can only be used with physical addressing models";
1602 }
1603
1604 if (!_.IsIntScalarType(offset_type) ||
1605 _.GetBitWidth(offset_type) != size_t_bit_width) {
1606 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1607 << ext_inst_name() << ": "
1608 << "expected operand Offset to be of type size_t ("
1609 << size_t_bit_width
1610 << "-bit integer for the addressing model used in the module)";
1611 }
1612
1613 uint32_t p_storage_class = 0;
1614 uint32_t p_data_type = 0;
1615 if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
1616 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1617 << ext_inst_name() << ": "
1618 << "expected operand P to be a pointer";
1619 }
1620
1621 if (p_storage_class != SpvStorageClassGeneric) {
1622 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1623 << ext_inst_name() << ": "
1624 << "expected operand P storage class to be Generic";
1625 }
1626
1627 if (_.GetComponentType(data_type) != p_data_type) {
1628 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1629 << ext_inst_name() << ": "
1630 << "expected operand P data type to be equal to the type of "
1631 "operand Data components";
1632 }
1633 break;
1634 }
1635
1636 case OpenCLLIB::Vload_half: {
1637 if (!_.IsFloatScalarType(result_type)) {
1638 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1639 << ext_inst_name() << ": "
1640 << "expected Result Type to be a float scalar type";
1641 }
1642
1643 const uint32_t offset_type = _.GetOperandTypeId(inst, 4);
1644 const uint32_t p_type = _.GetOperandTypeId(inst, 5);
1645
1646 const uint32_t size_t_bit_width = GetSizeTBitWidth(_);
1647 if (!size_t_bit_width) {
1648 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1649 << ext_inst_name()
1650 << " can only be used with physical addressing models";
1651 }
1652
1653 if (!_.IsIntScalarType(offset_type) ||
1654 _.GetBitWidth(offset_type) != size_t_bit_width) {
1655 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1656 << ext_inst_name() << ": "
1657 << "expected operand Offset to be of type size_t ("
1658 << size_t_bit_width
1659 << "-bit integer for the addressing model used in the module)";
1660 }
1661
1662 uint32_t p_storage_class = 0;
1663 uint32_t p_data_type = 0;
1664 if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
1665 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1666 << ext_inst_name() << ": "
1667 << "expected operand P to be a pointer";
1668 }
1669
1670 if (p_storage_class != SpvStorageClassUniformConstant &&
1671 p_storage_class != SpvStorageClassGeneric &&
1672 p_storage_class != SpvStorageClassCrossWorkgroup &&
1673 p_storage_class != SpvStorageClassWorkgroup &&
1674 p_storage_class != SpvStorageClassFunction) {
1675 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1676 << ext_inst_name() << ": "
1677 << "expected operand P storage class to be UniformConstant, "
1678 "Generic, CrossWorkgroup, Workgroup or Function";
1679 }
1680
1681 if (!_.IsFloatScalarType(p_data_type) ||
1682 _.GetBitWidth(p_data_type) != 16) {
1683 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1684 << ext_inst_name() << ": "
1685 << "expected operand P data type to be 16-bit float scalar";
1686 }
1687 break;
1688 }
1689
1690 case OpenCLLIB::Vload_halfn:
1691 case OpenCLLIB::Vloada_halfn: {
1692 if (!_.IsFloatVectorType(result_type)) {
1693 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1694 << ext_inst_name() << ": "
1695 << "expected Result Type to be a float vector type";
1696 }
1697
1698 const uint32_t num_components = _.GetDimension(result_type);
1699 if (num_components > 4 && num_components != 8 && num_components != 16) {
1700 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1701 << ext_inst_name() << ": "
1702 << "expected Result Type to have 2, 3, 4, 8 or 16 components";
1703 }
1704
1705 const uint32_t offset_type = _.GetOperandTypeId(inst, 4);
1706 const uint32_t p_type = _.GetOperandTypeId(inst, 5);
1707
1708 const uint32_t size_t_bit_width = GetSizeTBitWidth(_);
1709 if (!size_t_bit_width) {
1710 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1711 << ext_inst_name()
1712 << " can only be used with physical addressing models";
1713 }
1714
1715 if (!_.IsIntScalarType(offset_type) ||
1716 _.GetBitWidth(offset_type) != size_t_bit_width) {
1717 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1718 << ext_inst_name() << ": "
1719 << "expected operand Offset to be of type size_t ("
1720 << size_t_bit_width
1721 << "-bit integer for the addressing model used in the module)";
1722 }
1723
1724 uint32_t p_storage_class = 0;
1725 uint32_t p_data_type = 0;
1726 if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
1727 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1728 << ext_inst_name() << ": "
1729 << "expected operand P to be a pointer";
1730 }
1731
1732 if (p_storage_class != SpvStorageClassUniformConstant &&
1733 p_storage_class != SpvStorageClassGeneric &&
1734 p_storage_class != SpvStorageClassCrossWorkgroup &&
1735 p_storage_class != SpvStorageClassWorkgroup &&
1736 p_storage_class != SpvStorageClassFunction) {
1737 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1738 << ext_inst_name() << ": "
1739 << "expected operand P storage class to be UniformConstant, "
1740 "Generic, CrossWorkgroup, Workgroup or Function";
1741 }
1742
1743 if (!_.IsFloatScalarType(p_data_type) ||
1744 _.GetBitWidth(p_data_type) != 16) {
1745 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1746 << ext_inst_name() << ": "
1747 << "expected operand P data type to be 16-bit float scalar";
1748 }
1749
1750 const uint32_t n_value = inst->word(7);
1751 if (num_components != n_value) {
1752 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1753 << ext_inst_name() << ": "
1754 << "expected literal N to be equal to the number of "
1755 "components of Result Type";
1756 }
1757 break;
1758 }
1759
1760 case OpenCLLIB::Vstore_half:
1761 case OpenCLLIB::Vstore_half_r:
1762 case OpenCLLIB::Vstore_halfn:
1763 case OpenCLLIB::Vstore_halfn_r:
1764 case OpenCLLIB::Vstorea_halfn:
1765 case OpenCLLIB::Vstorea_halfn_r: {
1766 if (_.GetIdOpcode(result_type) != SpvOpTypeVoid) {
1767 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1768 << ext_inst_name() << ": expected Result Type to be void";
1769 }
1770
1771 const uint32_t data_type = _.GetOperandTypeId(inst, 4);
1772 const uint32_t offset_type = _.GetOperandTypeId(inst, 5);
1773 const uint32_t p_type = _.GetOperandTypeId(inst, 6);
1774 const uint32_t data_type_bit_width = _.GetBitWidth(data_type);
1775
1776 if (ext_inst_key == OpenCLLIB::Vstore_half ||
1777 ext_inst_key == OpenCLLIB::Vstore_half_r) {
1778 if (!_.IsFloatScalarType(data_type) ||
1779 (data_type_bit_width != 32 && data_type_bit_width != 64)) {
1780 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1781 << ext_inst_name() << ": "
1782 << "expected Data to be a 32 or 64-bit float scalar";
1783 }
1784 } else {
1785 if (!_.IsFloatVectorType(data_type) ||
1786 (data_type_bit_width != 32 && data_type_bit_width != 64)) {
1787 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1788 << ext_inst_name() << ": "
1789 << "expected Data to be a 32 or 64-bit float vector";
1790 }
1791
1792 const uint32_t num_components = _.GetDimension(data_type);
1793 if (num_components > 4 && num_components != 8 &&
1794 num_components != 16) {
1795 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1796 << ext_inst_name() << ": "
1797 << "expected Data to have 2, 3, 4, 8 or 16 components";
1798 }
1799 }
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 != SpvStorageClassGeneric &&
1826 p_storage_class != SpvStorageClassCrossWorkgroup &&
1827 p_storage_class != SpvStorageClassWorkgroup &&
1828 p_storage_class != SpvStorageClassFunction) {
1829 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1830 << ext_inst_name() << ": "
1831 << "expected operand P storage class to be Generic, "
1832 "CrossWorkgroup, Workgroup or Function";
1833 }
1834
1835 if (!_.IsFloatScalarType(p_data_type) ||
1836 _.GetBitWidth(p_data_type) != 16) {
1837 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1838 << ext_inst_name() << ": "
1839 << "expected operand P data type to be 16-bit float scalar";
1840 }
1841
1842 // Rounding mode enum is checked by assembler.
1843 break;
1844 }
1845
1846 case OpenCLLIB::Shuffle:
1847 case OpenCLLIB::Shuffle2: {
1848 if (!_.IsFloatVectorType(result_type) &&
1849 !_.IsIntVectorType(result_type)) {
1850 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1851 << ext_inst_name() << ": "
1852 << "expected Result Type to be an int or float vector type";
1853 }
1854
1855 const uint32_t result_num_components = _.GetDimension(result_type);
1856 if (result_num_components != 2 && result_num_components != 4 &&
1857 result_num_components != 8 && result_num_components != 16) {
1858 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1859 << ext_inst_name() << ": "
1860 << "expected Result Type to have 2, 4, 8 or 16 components";
1861 }
1862
1863 uint32_t operand_index = 4;
1864 const uint32_t x_type = _.GetOperandTypeId(inst, operand_index++);
1865
1866 if (ext_inst_key == OpenCLLIB::Shuffle2) {
1867 const uint32_t y_type = _.GetOperandTypeId(inst, operand_index++);
1868 if (x_type != y_type) {
1869 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1870 << ext_inst_name() << ": "
1871 << "expected operands X and Y to be of the same type";
1872 }
1873 }
1874
1875 const uint32_t shuffle_mask_type =
1876 _.GetOperandTypeId(inst, operand_index++);
1877
1878 if (!_.IsFloatVectorType(x_type) && !_.IsIntVectorType(x_type)) {
1879 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1880 << ext_inst_name() << ": "
1881 << "expected operand X to be an int or float vector";
1882 }
1883
1884 const uint32_t x_num_components = _.GetDimension(x_type);
1885 if (x_num_components != 2 && x_num_components != 4 &&
1886 x_num_components != 8 && x_num_components != 16) {
1887 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1888 << ext_inst_name() << ": "
1889 << "expected operand X to have 2, 4, 8 or 16 components";
1890 }
1891
1892 const uint32_t result_component_type = _.GetComponentType(result_type);
1893
1894 if (result_component_type != _.GetComponentType(x_type)) {
1895 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1896 << ext_inst_name() << ": "
1897 << "expected operand X and Result Type to have equal "
1898 "component types";
1899 }
1900
1901 if (!_.IsIntVectorType(shuffle_mask_type)) {
1902 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1903 << ext_inst_name() << ": "
1904 << "expected operand Shuffle Mask to be an int vector";
1905 }
1906
1907 if (result_num_components != _.GetDimension(shuffle_mask_type)) {
1908 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1909 << ext_inst_name() << ": "
1910 << "expected operand Shuffle Mask to have the same number of "
1911 "components as Result Type";
1912 }
1913
1914 if (_.GetBitWidth(result_component_type) !=
1915 _.GetBitWidth(shuffle_mask_type)) {
1916 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1917 << ext_inst_name() << ": "
1918 << "expected operand Shuffle Mask components to have the same "
1919 "bit width as Result Type components";
1920 }
1921 break;
1922 }
1923
1924 case OpenCLLIB::Printf: {
1925 if (!_.IsIntScalarType(result_type) ||
1926 _.GetBitWidth(result_type) != 32) {
1927 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1928 << ext_inst_name() << ": "
1929 << "expected Result Type to be a 32-bit int type";
1930 }
1931
1932 const uint32_t format_type = _.GetOperandTypeId(inst, 4);
1933 uint32_t format_storage_class = 0;
1934 uint32_t format_data_type = 0;
1935 if (!_.GetPointerTypeInfo(format_type, &format_data_type,
1936 &format_storage_class)) {
1937 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1938 << ext_inst_name() << ": "
1939 << "expected operand Format to be a pointer";
1940 }
1941
1942 if (format_storage_class != SpvStorageClassUniformConstant) {
1943 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1944 << ext_inst_name() << ": "
1945 << "expected Format storage class to be UniformConstant";
1946 }
1947
1948 if (!_.IsIntScalarType(format_data_type) ||
1949 _.GetBitWidth(format_data_type) != 8) {
1950 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1951 << ext_inst_name() << ": "
1952 << "expected Format data type to be 8-bit int";
1953 }
1954 break;
1955 }
1956
1957 case OpenCLLIB::Prefetch: {
1958 if (_.GetIdOpcode(result_type) != SpvOpTypeVoid) {
1959 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1960 << ext_inst_name() << ": expected Result Type to be void";
1961 }
1962
1963 const uint32_t p_type = _.GetOperandTypeId(inst, 4);
1964 const uint32_t num_elements_type = _.GetOperandTypeId(inst, 5);
1965
1966 uint32_t p_storage_class = 0;
1967 uint32_t p_data_type = 0;
1968 if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
1969 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1970 << ext_inst_name() << ": "
1971 << "expected operand Ptr to be a pointer";
1972 }
1973
1974 if (p_storage_class != SpvStorageClassCrossWorkgroup) {
1975 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1976 << ext_inst_name() << ": "
1977 << "expected operand Ptr storage class to be CrossWorkgroup";
1978 }
1979
1980 if (!_.IsFloatScalarOrVectorType(p_data_type) &&
1981 !_.IsIntScalarOrVectorType(p_data_type)) {
1982 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1983 << ext_inst_name() << ": "
1984 << "expected Ptr data type to be int or float scalar or "
1985 "vector";
1986 }
1987
1988 const uint32_t num_components = _.GetDimension(p_data_type);
1989 if (num_components > 4 && num_components != 8 && num_components != 16) {
1990 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1991 << ext_inst_name() << ": "
1992 << "expected Result Type to be a scalar or a vector with 2, "
1993 "3, 4, 8 or 16 components";
1994 }
1995
1996 const uint32_t size_t_bit_width = GetSizeTBitWidth(_);
1997 if (!size_t_bit_width) {
1998 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1999 << ext_inst_name()
2000 << " can only be used with physical addressing models";
2001 }
2002
2003 if (!_.IsIntScalarType(num_elements_type) ||
2004 _.GetBitWidth(num_elements_type) != size_t_bit_width) {
2005 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2006 << ext_inst_name() << ": "
2007 << "expected operand Num Elements to be of type size_t ("
2008 << size_t_bit_width
2009 << "-bit integer for the addressing model used in the module)";
2010 }
2011 break;
2012 }
2013 }
2014 }
2015
2016 return SPV_SUCCESS;
2017 }
2018
ExtensionPass(ValidationState_t & _,const Instruction * inst)2019 spv_result_t ExtensionPass(ValidationState_t& _, const Instruction* inst) {
2020 const SpvOp opcode = inst->opcode();
2021 if (opcode == SpvOpExtension) return ValidateExtension(_, inst);
2022 if (opcode == SpvOpExtInstImport) return ValidateExtInstImport(_, inst);
2023 if (opcode == SpvOpExtInst) return ValidateExtInst(_, inst);
2024
2025 return SPV_SUCCESS;
2026 }
2027
2028 } // namespace val
2029 } // namespace spvtools
2030