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 #include <cstdlib>
17 #include <sstream>
18 #include <string>
19 #include <vector>
20
21 #include "spirv/unified1/NonSemanticClspvReflection.h"
22
23 #include "OpenCLDebugInfo100.h"
24 #include "source/diagnostic.h"
25 #include "source/enum_string_mapping.h"
26 #include "source/extensions.h"
27 #include "source/latest_version_glsl_std_450_header.h"
28 #include "source/latest_version_opencl_std_header.h"
29 #include "source/opcode.h"
30 #include "source/spirv_target_env.h"
31 #include "source/val/instruction.h"
32 #include "source/val/validate.h"
33 #include "source/val/validation_state.h"
34
35 namespace spvtools {
36 namespace val {
37 namespace {
38
GetSizeTBitWidth(const ValidationState_t & _)39 uint32_t GetSizeTBitWidth(const ValidationState_t& _) {
40 if (_.addressing_model() == SpvAddressingModelPhysical32) return 32;
41
42 if (_.addressing_model() == SpvAddressingModelPhysical64) return 64;
43
44 return 0;
45 }
46
47 // Check that the operand of a debug info instruction |inst| at |word_index|
48 // is a result id of an instruction with |expected_opcode|.
ValidateOperandForDebugInfo(ValidationState_t & _,const std::string & operand_name,SpvOp expected_opcode,const Instruction * inst,uint32_t word_index,const std::function<std::string ()> & ext_inst_name)49 spv_result_t ValidateOperandForDebugInfo(
50 ValidationState_t& _, const std::string& operand_name,
51 SpvOp expected_opcode, const Instruction* inst, uint32_t word_index,
52 const std::function<std::string()>& ext_inst_name) {
53 auto* operand = _.FindDef(inst->word(word_index));
54 if (operand->opcode() != expected_opcode) {
55 spv_opcode_desc desc = nullptr;
56 if (_.grammar().lookupOpcode(expected_opcode, &desc) != SPV_SUCCESS ||
57 !desc) {
58 return _.diag(SPV_ERROR_INVALID_DATA, inst)
59 << ext_inst_name() << ": "
60 << "expected operand " << operand_name << " is invalid";
61 }
62 return _.diag(SPV_ERROR_INVALID_DATA, inst)
63 << ext_inst_name() << ": "
64 << "expected operand " << operand_name << " must be a result id of "
65 << "Op" << desc->name;
66 }
67 return SPV_SUCCESS;
68 }
69
70 #define CHECK_OPERAND(NAME, opcode, index) \
71 do { \
72 auto result = ValidateOperandForDebugInfo(_, NAME, opcode, inst, index, \
73 ext_inst_name); \
74 if (result != SPV_SUCCESS) return result; \
75 } while (0)
76
77 // True if the operand of a debug info instruction |inst| at |word_index|
78 // satisifies |expectation| that is given as a function. Otherwise,
79 // returns false.
DoesDebugInfoOperandMatchExpectation(const ValidationState_t & _,const std::function<bool (OpenCLDebugInfo100Instructions)> & expectation,const Instruction * inst,uint32_t word_index)80 bool DoesDebugInfoOperandMatchExpectation(
81 const ValidationState_t& _,
82 const std::function<bool(OpenCLDebugInfo100Instructions)>& expectation,
83 const Instruction* inst, uint32_t word_index) {
84 if (inst->words().size() <= word_index) return false;
85 auto* debug_inst = _.FindDef(inst->word(word_index));
86 if (debug_inst->opcode() != SpvOpExtInst ||
87 debug_inst->ext_inst_type() != SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100 ||
88 !expectation(OpenCLDebugInfo100Instructions(debug_inst->word(4)))) {
89 return false;
90 }
91 return true;
92 }
93
94 // Check that the operand of a debug info instruction |inst| at |word_index|
95 // is a result id of an debug info instruction whose debug instruction type
96 // is |expected_debug_inst|.
ValidateDebugInfoOperand(ValidationState_t & _,const std::string & debug_inst_name,OpenCLDebugInfo100Instructions expected_debug_inst,const Instruction * inst,uint32_t word_index,const std::function<std::string ()> & ext_inst_name)97 spv_result_t ValidateDebugInfoOperand(
98 ValidationState_t& _, const std::string& debug_inst_name,
99 OpenCLDebugInfo100Instructions expected_debug_inst, const Instruction* inst,
100 uint32_t word_index, const std::function<std::string()>& ext_inst_name) {
101 std::function<bool(OpenCLDebugInfo100Instructions)> expectation =
102 [expected_debug_inst](OpenCLDebugInfo100Instructions dbg_inst) {
103 return dbg_inst == expected_debug_inst;
104 };
105 if (DoesDebugInfoOperandMatchExpectation(_, expectation, inst, word_index))
106 return SPV_SUCCESS;
107
108 spv_ext_inst_desc desc = nullptr;
109 _.grammar().lookupExtInst(SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100,
110 expected_debug_inst, &desc);
111 if (_.grammar().lookupExtInst(SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100,
112 expected_debug_inst, &desc) != SPV_SUCCESS ||
113 !desc) {
114 return _.diag(SPV_ERROR_INVALID_DATA, inst)
115 << ext_inst_name() << ": "
116 << "expected operand " << debug_inst_name << " is invalid";
117 }
118 return _.diag(SPV_ERROR_INVALID_DATA, inst)
119 << ext_inst_name() << ": "
120 << "expected operand " << debug_inst_name << " must be a result id of "
121 << desc->name;
122 }
123
124 #define CHECK_DEBUG_OPERAND(NAME, debug_opcode, index) \
125 do { \
126 auto result = ValidateDebugInfoOperand(_, NAME, debug_opcode, inst, index, \
127 ext_inst_name); \
128 if (result != SPV_SUCCESS) return result; \
129 } while (0)
130
131 // Check that the operand of a debug info instruction |inst| at |word_index|
132 // is a result id of an debug info instruction with DebugTypeBasic.
ValidateOperandBaseType(ValidationState_t & _,const Instruction * inst,uint32_t word_index,const std::function<std::string ()> & ext_inst_name)133 spv_result_t ValidateOperandBaseType(
134 ValidationState_t& _, const Instruction* inst, uint32_t word_index,
135 const std::function<std::string()>& ext_inst_name) {
136 return ValidateDebugInfoOperand(_, "Base Type",
137 OpenCLDebugInfo100DebugTypeBasic, inst,
138 word_index, ext_inst_name);
139 }
140
141 // Check that the operand of a debug info instruction |inst| at |word_index|
142 // is a result id of a debug lexical scope instruction which is one of
143 // DebugCompilationUnit, DebugFunction, DebugLexicalBlock, or
144 // DebugTypeComposite.
ValidateOperandLexicalScope(ValidationState_t & _,const std::string & debug_inst_name,const Instruction * inst,uint32_t word_index,const std::function<std::string ()> & ext_inst_name)145 spv_result_t ValidateOperandLexicalScope(
146 ValidationState_t& _, const std::string& debug_inst_name,
147 const Instruction* inst, uint32_t word_index,
148 const std::function<std::string()>& ext_inst_name) {
149 std::function<bool(OpenCLDebugInfo100Instructions)> expectation =
150 [](OpenCLDebugInfo100Instructions dbg_inst) {
151 return dbg_inst == OpenCLDebugInfo100DebugCompilationUnit ||
152 dbg_inst == OpenCLDebugInfo100DebugFunction ||
153 dbg_inst == OpenCLDebugInfo100DebugLexicalBlock ||
154 dbg_inst == OpenCLDebugInfo100DebugTypeComposite;
155 };
156 if (DoesDebugInfoOperandMatchExpectation(_, expectation, inst, word_index))
157 return SPV_SUCCESS;
158
159 return _.diag(SPV_ERROR_INVALID_DATA, inst)
160 << ext_inst_name() << ": "
161 << "expected operand " << debug_inst_name
162 << " must be a result id of a lexical scope";
163 }
164
165 // Check that the operand of a debug info instruction |inst| at |word_index|
166 // is a result id of a debug type instruction (See DebugTypeXXX in
167 // "4.3. Type instructions" section of OpenCL.DebugInfo.100 spec.
ValidateOperandDebugType(ValidationState_t & _,const std::string & debug_inst_name,const Instruction * inst,uint32_t word_index,const std::function<std::string ()> & ext_inst_name,bool allow_template_param)168 spv_result_t ValidateOperandDebugType(
169 ValidationState_t& _, const std::string& debug_inst_name,
170 const Instruction* inst, uint32_t word_index,
171 const std::function<std::string()>& ext_inst_name,
172 bool allow_template_param) {
173 std::function<bool(OpenCLDebugInfo100Instructions)> expectation =
174 [&allow_template_param](OpenCLDebugInfo100Instructions dbg_inst) {
175 if (allow_template_param &&
176 (dbg_inst == OpenCLDebugInfo100DebugTypeTemplateParameter ||
177 dbg_inst ==
178 OpenCLDebugInfo100DebugTypeTemplateTemplateParameter)) {
179 return true;
180 }
181 return OpenCLDebugInfo100DebugTypeBasic <= dbg_inst &&
182 dbg_inst <= OpenCLDebugInfo100DebugTypeTemplate;
183 };
184 if (DoesDebugInfoOperandMatchExpectation(_, expectation, inst, word_index))
185 return SPV_SUCCESS;
186
187 return _.diag(SPV_ERROR_INVALID_DATA, inst)
188 << ext_inst_name() << ": "
189 << "expected operand " << debug_inst_name
190 << " is not a valid debug type";
191 }
192
IsUint32Constant(ValidationState_t & _,uint32_t id)193 bool IsUint32Constant(ValidationState_t& _, uint32_t id) {
194 auto inst = _.FindDef(id);
195 if (!inst || inst->opcode() != SpvOpConstant) {
196 return false;
197 }
198
199 auto type = _.FindDef(inst->type_id());
200 if (!type || type->opcode() != SpvOpTypeInt) {
201 return false;
202 }
203
204 if (type->GetOperandAs<uint32_t>(1) != 32) {
205 return false;
206 }
207
208 if (type->GetOperandAs<uint32_t>(2) != 0) {
209 return false;
210 }
211
212 return true;
213 }
214
ValidateClspvReflectionKernel(ValidationState_t & _,const Instruction * inst)215 spv_result_t ValidateClspvReflectionKernel(ValidationState_t& _,
216 const Instruction* inst) {
217 const auto kernel_id = inst->GetOperandAs<uint32_t>(4);
218 const auto kernel = _.FindDef(kernel_id);
219 if (kernel->opcode() != SpvOpFunction) {
220 return _.diag(SPV_ERROR_INVALID_ID, inst)
221 << "Kernel does not reference a function";
222 }
223
224 bool found_kernel = false;
225 for (auto entry_point : _.entry_points()) {
226 if (entry_point == kernel_id) {
227 found_kernel = true;
228 break;
229 }
230 }
231 if (!found_kernel) {
232 return _.diag(SPV_ERROR_INVALID_ID, inst)
233 << "Kernel does not reference an entry-point";
234 }
235
236 const auto* exec_models = _.GetExecutionModels(kernel_id);
237 if (!exec_models || exec_models->empty()) {
238 return _.diag(SPV_ERROR_INVALID_ID, inst)
239 << "Kernel does not reference an entry-point";
240 }
241 for (auto exec_model : *exec_models) {
242 if (exec_model != SpvExecutionModelGLCompute) {
243 return _.diag(SPV_ERROR_INVALID_ID, inst)
244 << "Kernel must refer only to GLCompute entry-points";
245 }
246 }
247
248 auto name = _.FindDef(inst->GetOperandAs<uint32_t>(5));
249 if (!name || name->opcode() != SpvOpString) {
250 return _.diag(SPV_ERROR_INVALID_ID, inst) << "Name must be an OpString";
251 }
252
253 const std::string name_str = reinterpret_cast<const char*>(
254 name->words().data() + name->operands()[1].offset);
255 bool found = false;
256 for (auto& desc : _.entry_point_descriptions(kernel_id)) {
257 if (name_str == desc.name) {
258 found = true;
259 break;
260 }
261 }
262 if (!found) {
263 return _.diag(SPV_ERROR_INVALID_ID, inst)
264 << "Name must match an entry-point for Kernel";
265 }
266
267 return SPV_SUCCESS;
268 }
269
ValidateClspvReflectionArgumentInfo(ValidationState_t & _,const Instruction * inst)270 spv_result_t ValidateClspvReflectionArgumentInfo(ValidationState_t& _,
271 const Instruction* inst) {
272 const auto num_operands = inst->operands().size();
273 if (_.GetIdOpcode(inst->GetOperandAs<uint32_t>(4)) != SpvOpString) {
274 return _.diag(SPV_ERROR_INVALID_ID, inst) << "Name must be an OpString";
275 }
276 if (num_operands > 5) {
277 if (_.GetIdOpcode(inst->GetOperandAs<uint32_t>(5)) != SpvOpString) {
278 return _.diag(SPV_ERROR_INVALID_ID, inst)
279 << "TypeName must be an OpString";
280 }
281 }
282 if (num_operands > 6) {
283 if (!IsUint32Constant(_, inst->GetOperandAs<uint32_t>(6))) {
284 return _.diag(SPV_ERROR_INVALID_ID, inst)
285 << "AddressQualifier must be a 32-bit unsigned integer "
286 "OpConstant";
287 }
288 }
289 if (num_operands > 7) {
290 if (!IsUint32Constant(_, inst->GetOperandAs<uint32_t>(7))) {
291 return _.diag(SPV_ERROR_INVALID_ID, inst)
292 << "AccessQualifier must be a 32-bit unsigned integer "
293 "OpConstant";
294 }
295 }
296 if (num_operands > 8) {
297 if (!IsUint32Constant(_, inst->GetOperandAs<uint32_t>(8))) {
298 return _.diag(SPV_ERROR_INVALID_ID, inst)
299 << "TypeQualifier must be a 32-bit unsigned integer "
300 "OpConstant";
301 }
302 }
303
304 return SPV_SUCCESS;
305 }
306
ValidateKernelDecl(ValidationState_t & _,const Instruction * inst)307 spv_result_t ValidateKernelDecl(ValidationState_t& _, const Instruction* inst) {
308 const auto decl_id = inst->GetOperandAs<uint32_t>(4);
309 const auto decl = _.FindDef(decl_id);
310 if (!decl || decl->opcode() != SpvOpExtInst) {
311 return _.diag(SPV_ERROR_INVALID_ID, inst)
312 << "Kernel must be a Kernel extended instruction";
313 }
314
315 if (decl->GetOperandAs<uint32_t>(2) != inst->GetOperandAs<uint32_t>(2)) {
316 return _.diag(SPV_ERROR_INVALID_ID, inst)
317 << "Kernel must be from the same extended instruction import";
318 }
319
320 const auto ext_inst =
321 decl->GetOperandAs<NonSemanticClspvReflectionInstructions>(3);
322 if (ext_inst != NonSemanticClspvReflectionKernel) {
323 return _.diag(SPV_ERROR_INVALID_ID, inst)
324 << "Kernel must be a Kernel extended instruction";
325 }
326
327 return SPV_SUCCESS;
328 }
329
ValidateArgInfo(ValidationState_t & _,const Instruction * inst,uint32_t info_index)330 spv_result_t ValidateArgInfo(ValidationState_t& _, const Instruction* inst,
331 uint32_t info_index) {
332 auto info = _.FindDef(inst->GetOperandAs<uint32_t>(info_index));
333 if (!info || info->opcode() != SpvOpExtInst) {
334 return _.diag(SPV_ERROR_INVALID_ID, inst)
335 << "ArgInfo must be an ArgumentInfo extended instruction";
336 }
337
338 if (info->GetOperandAs<uint32_t>(2) != inst->GetOperandAs<uint32_t>(2)) {
339 return _.diag(SPV_ERROR_INVALID_ID, inst)
340 << "ArgInfo must be from the same extended instruction import";
341 }
342
343 auto ext_inst = info->GetOperandAs<NonSemanticClspvReflectionInstructions>(3);
344 if (ext_inst != NonSemanticClspvReflectionArgumentInfo) {
345 return _.diag(SPV_ERROR_INVALID_ID, inst)
346 << "ArgInfo must be an ArgumentInfo extended instruction";
347 }
348
349 return SPV_SUCCESS;
350 }
351
ValidateClspvReflectionArgumentBuffer(ValidationState_t & _,const Instruction * inst)352 spv_result_t ValidateClspvReflectionArgumentBuffer(ValidationState_t& _,
353 const Instruction* inst) {
354 const auto num_operands = inst->operands().size();
355 if (auto error = ValidateKernelDecl(_, inst)) {
356 return error;
357 }
358
359 if (!IsUint32Constant(_, inst->GetOperandAs<uint32_t>(5))) {
360 return _.diag(SPV_ERROR_INVALID_ID, inst)
361 << "Ordinal must be a 32-bit unsigned integer OpConstant";
362 }
363
364 if (!IsUint32Constant(_, inst->GetOperandAs<uint32_t>(6))) {
365 return _.diag(SPV_ERROR_INVALID_ID, inst)
366 << "DescriptorSet must be a 32-bit unsigned integer OpConstant";
367 }
368
369 if (!IsUint32Constant(_, inst->GetOperandAs<uint32_t>(7))) {
370 return _.diag(SPV_ERROR_INVALID_ID, inst)
371 << "Binding must be a 32-bit unsigned integer OpConstant";
372 }
373
374 if (num_operands == 9) {
375 if (auto error = ValidateArgInfo(_, inst, 8)) {
376 return error;
377 }
378 }
379
380 return SPV_SUCCESS;
381 }
382
ValidateClspvReflectionArgumentPodBuffer(ValidationState_t & _,const Instruction * inst)383 spv_result_t ValidateClspvReflectionArgumentPodBuffer(ValidationState_t& _,
384 const Instruction* inst) {
385 const auto num_operands = inst->operands().size();
386 if (auto error = ValidateKernelDecl(_, inst)) {
387 return error;
388 }
389
390 if (!IsUint32Constant(_, inst->GetOperandAs<uint32_t>(5))) {
391 return _.diag(SPV_ERROR_INVALID_ID, inst)
392 << "Ordinal must be a 32-bit unsigned integer OpConstant";
393 }
394
395 if (!IsUint32Constant(_, inst->GetOperandAs<uint32_t>(6))) {
396 return _.diag(SPV_ERROR_INVALID_ID, inst)
397 << "DescriptorSet must be a 32-bit unsigned integer OpConstant";
398 }
399
400 if (!IsUint32Constant(_, inst->GetOperandAs<uint32_t>(7))) {
401 return _.diag(SPV_ERROR_INVALID_ID, inst)
402 << "Binding must be a 32-bit unsigned integer OpConstant";
403 }
404
405 if (!IsUint32Constant(_, inst->GetOperandAs<uint32_t>(8))) {
406 return _.diag(SPV_ERROR_INVALID_ID, inst)
407 << "Offset must be a 32-bit unsigned integer OpConstant";
408 }
409
410 if (!IsUint32Constant(_, inst->GetOperandAs<uint32_t>(9))) {
411 return _.diag(SPV_ERROR_INVALID_ID, inst)
412 << "Size must be a 32-bit unsigned integer OpConstant";
413 }
414
415 if (num_operands == 11) {
416 if (auto error = ValidateArgInfo(_, inst, 10)) {
417 return error;
418 }
419 }
420
421 return SPV_SUCCESS;
422 }
423
ValidateClspvReflectionArgumentPodPushConstant(ValidationState_t & _,const Instruction * inst)424 spv_result_t ValidateClspvReflectionArgumentPodPushConstant(
425 ValidationState_t& _, const Instruction* inst) {
426 const auto num_operands = inst->operands().size();
427 if (auto error = ValidateKernelDecl(_, inst)) {
428 return error;
429 }
430
431 if (!IsUint32Constant(_, inst->GetOperandAs<uint32_t>(5))) {
432 return _.diag(SPV_ERROR_INVALID_ID, inst)
433 << "Ordinal must be a 32-bit unsigned integer OpConstant";
434 }
435
436 if (!IsUint32Constant(_, inst->GetOperandAs<uint32_t>(6))) {
437 return _.diag(SPV_ERROR_INVALID_ID, inst)
438 << "Offset must be a 32-bit unsigned integer OpConstant";
439 }
440
441 if (!IsUint32Constant(_, inst->GetOperandAs<uint32_t>(7))) {
442 return _.diag(SPV_ERROR_INVALID_ID, inst)
443 << "Size must be a 32-bit unsigned integer OpConstant";
444 }
445
446 if (num_operands == 9) {
447 if (auto error = ValidateArgInfo(_, inst, 8)) {
448 return error;
449 }
450 }
451
452 return SPV_SUCCESS;
453 }
454
ValidateClspvReflectionArgumentWorkgroup(ValidationState_t & _,const Instruction * inst)455 spv_result_t ValidateClspvReflectionArgumentWorkgroup(ValidationState_t& _,
456 const Instruction* inst) {
457 const auto num_operands = inst->operands().size();
458 if (auto error = ValidateKernelDecl(_, inst)) {
459 return error;
460 }
461
462 if (!IsUint32Constant(_, inst->GetOperandAs<uint32_t>(5))) {
463 return _.diag(SPV_ERROR_INVALID_ID, inst)
464 << "Ordinal must be a 32-bit unsigned integer OpConstant";
465 }
466
467 if (!IsUint32Constant(_, inst->GetOperandAs<uint32_t>(6))) {
468 return _.diag(SPV_ERROR_INVALID_ID, inst)
469 << "SpecId must be a 32-bit unsigned integer OpConstant";
470 }
471
472 if (!IsUint32Constant(_, inst->GetOperandAs<uint32_t>(7))) {
473 return _.diag(SPV_ERROR_INVALID_ID, inst)
474 << "ElemSize must be a 32-bit unsigned integer OpConstant";
475 }
476
477 if (num_operands == 9) {
478 if (auto error = ValidateArgInfo(_, inst, 8)) {
479 return error;
480 }
481 }
482
483 return SPV_SUCCESS;
484 }
485
ValidateClspvReflectionSpecConstantTriple(ValidationState_t & _,const Instruction * inst)486 spv_result_t ValidateClspvReflectionSpecConstantTriple(
487 ValidationState_t& _, const Instruction* inst) {
488 if (!IsUint32Constant(_, inst->GetOperandAs<uint32_t>(4))) {
489 return _.diag(SPV_ERROR_INVALID_ID, inst)
490 << "X must be a 32-bit unsigned integer OpConstant";
491 }
492
493 if (!IsUint32Constant(_, inst->GetOperandAs<uint32_t>(5))) {
494 return _.diag(SPV_ERROR_INVALID_ID, inst)
495 << "Y must be a 32-bit unsigned integer OpConstant";
496 }
497
498 if (!IsUint32Constant(_, inst->GetOperandAs<uint32_t>(6))) {
499 return _.diag(SPV_ERROR_INVALID_ID, inst)
500 << "Z must be a 32-bit unsigned integer OpConstant";
501 }
502
503 return SPV_SUCCESS;
504 }
505
ValidateClspvReflectionSpecConstantWorkDim(ValidationState_t & _,const Instruction * inst)506 spv_result_t ValidateClspvReflectionSpecConstantWorkDim(
507 ValidationState_t& _, const Instruction* inst) {
508 if (!IsUint32Constant(_, inst->GetOperandAs<uint32_t>(4))) {
509 return _.diag(SPV_ERROR_INVALID_ID, inst)
510 << "Dim must be a 32-bit unsigned integer OpConstant";
511 }
512
513 return SPV_SUCCESS;
514 }
515
ValidateClspvReflectionPushConstant(ValidationState_t & _,const Instruction * inst)516 spv_result_t ValidateClspvReflectionPushConstant(ValidationState_t& _,
517 const Instruction* inst) {
518 if (!IsUint32Constant(_, inst->GetOperandAs<uint32_t>(4))) {
519 return _.diag(SPV_ERROR_INVALID_ID, inst)
520 << "Offset must be a 32-bit unsigned integer OpConstant";
521 }
522
523 if (!IsUint32Constant(_, inst->GetOperandAs<uint32_t>(5))) {
524 return _.diag(SPV_ERROR_INVALID_ID, inst)
525 << "Size must be a 32-bit unsigned integer OpConstant";
526 }
527
528 return SPV_SUCCESS;
529 }
530
ValidateClspvReflectionConstantData(ValidationState_t & _,const Instruction * inst)531 spv_result_t ValidateClspvReflectionConstantData(ValidationState_t& _,
532 const Instruction* inst) {
533 if (!IsUint32Constant(_, inst->GetOperandAs<uint32_t>(4))) {
534 return _.diag(SPV_ERROR_INVALID_ID, inst)
535 << "DescriptorSet must be a 32-bit unsigned integer OpConstant";
536 }
537
538 if (!IsUint32Constant(_, inst->GetOperandAs<uint32_t>(5))) {
539 return _.diag(SPV_ERROR_INVALID_ID, inst)
540 << "Binding must be a 32-bit unsigned integer OpConstant";
541 }
542
543 if (_.GetIdOpcode(inst->GetOperandAs<uint32_t>(6)) != SpvOpString) {
544 return _.diag(SPV_ERROR_INVALID_ID, inst) << "Data must be an OpString";
545 }
546
547 return SPV_SUCCESS;
548 }
549
ValidateClspvReflectionSampler(ValidationState_t & _,const Instruction * inst)550 spv_result_t ValidateClspvReflectionSampler(ValidationState_t& _,
551 const Instruction* inst) {
552 if (!IsUint32Constant(_, inst->GetOperandAs<uint32_t>(4))) {
553 return _.diag(SPV_ERROR_INVALID_ID, inst)
554 << "DescriptorSet must be a 32-bit unsigned integer OpConstant";
555 }
556
557 if (!IsUint32Constant(_, inst->GetOperandAs<uint32_t>(5))) {
558 return _.diag(SPV_ERROR_INVALID_ID, inst)
559 << "Binding must be a 32-bit unsigned integer OpConstant";
560 }
561
562 if (!IsUint32Constant(_, inst->GetOperandAs<uint32_t>(6))) {
563 return _.diag(SPV_ERROR_INVALID_ID, inst)
564 << "Mask must be a 32-bit unsigned integer OpConstant";
565 }
566
567 return SPV_SUCCESS;
568 }
569
ValidateClspvReflectionPropertyRequiredWorkgroupSize(ValidationState_t & _,const Instruction * inst)570 spv_result_t ValidateClspvReflectionPropertyRequiredWorkgroupSize(
571 ValidationState_t& _, const Instruction* inst) {
572 if (auto error = ValidateKernelDecl(_, inst)) {
573 return error;
574 }
575
576 if (!IsUint32Constant(_, inst->GetOperandAs<uint32_t>(5))) {
577 return _.diag(SPV_ERROR_INVALID_ID, inst)
578 << "X must be a 32-bit unsigned integer OpConstant";
579 }
580
581 if (!IsUint32Constant(_, inst->GetOperandAs<uint32_t>(6))) {
582 return _.diag(SPV_ERROR_INVALID_ID, inst)
583 << "Y must be a 32-bit unsigned integer OpConstant";
584 }
585
586 if (!IsUint32Constant(_, inst->GetOperandAs<uint32_t>(7))) {
587 return _.diag(SPV_ERROR_INVALID_ID, inst)
588 << "Z must be a 32-bit unsigned integer OpConstant";
589 }
590
591 return SPV_SUCCESS;
592 }
593
ValidateClspvReflectionInstruction(ValidationState_t & _,const Instruction * inst,uint32_t)594 spv_result_t ValidateClspvReflectionInstruction(ValidationState_t& _,
595 const Instruction* inst,
596 uint32_t /*version*/) {
597 if (!_.IsVoidType(inst->type_id())) {
598 return _.diag(SPV_ERROR_INVALID_ID, inst)
599 << "Return Type must be OpTypeVoid";
600 }
601
602 auto ext_inst = inst->GetOperandAs<NonSemanticClspvReflectionInstructions>(3);
603 switch (ext_inst) {
604 case NonSemanticClspvReflectionKernel:
605 return ValidateClspvReflectionKernel(_, inst);
606 case NonSemanticClspvReflectionArgumentInfo:
607 return ValidateClspvReflectionArgumentInfo(_, inst);
608 case NonSemanticClspvReflectionArgumentStorageBuffer:
609 case NonSemanticClspvReflectionArgumentUniform:
610 case NonSemanticClspvReflectionArgumentSampledImage:
611 case NonSemanticClspvReflectionArgumentStorageImage:
612 case NonSemanticClspvReflectionArgumentSampler:
613 return ValidateClspvReflectionArgumentBuffer(_, inst);
614 case NonSemanticClspvReflectionArgumentPodStorageBuffer:
615 case NonSemanticClspvReflectionArgumentPodUniform:
616 return ValidateClspvReflectionArgumentPodBuffer(_, inst);
617 case NonSemanticClspvReflectionArgumentPodPushConstant:
618 return ValidateClspvReflectionArgumentPodPushConstant(_, inst);
619 case NonSemanticClspvReflectionArgumentWorkgroup:
620 return ValidateClspvReflectionArgumentWorkgroup(_, inst);
621 case NonSemanticClspvReflectionSpecConstantWorkgroupSize:
622 case NonSemanticClspvReflectionSpecConstantGlobalOffset:
623 return ValidateClspvReflectionSpecConstantTriple(_, inst);
624 case NonSemanticClspvReflectionSpecConstantWorkDim:
625 return ValidateClspvReflectionSpecConstantWorkDim(_, inst);
626 case NonSemanticClspvReflectionPushConstantGlobalOffset:
627 case NonSemanticClspvReflectionPushConstantEnqueuedLocalSize:
628 case NonSemanticClspvReflectionPushConstantGlobalSize:
629 case NonSemanticClspvReflectionPushConstantRegionOffset:
630 case NonSemanticClspvReflectionPushConstantNumWorkgroups:
631 case NonSemanticClspvReflectionPushConstantRegionGroupOffset:
632 return ValidateClspvReflectionPushConstant(_, inst);
633 case NonSemanticClspvReflectionConstantDataStorageBuffer:
634 case NonSemanticClspvReflectionConstantDataUniform:
635 return ValidateClspvReflectionConstantData(_, inst);
636 case NonSemanticClspvReflectionLiteralSampler:
637 return ValidateClspvReflectionSampler(_, inst);
638 case NonSemanticClspvReflectionPropertyRequiredWorkgroupSize:
639 return ValidateClspvReflectionPropertyRequiredWorkgroupSize(_, inst);
640 default:
641 break;
642 }
643
644 return SPV_SUCCESS;
645 }
646
IsConstIntScalarTypeWith32Or64Bits(ValidationState_t & _,Instruction * instr)647 bool IsConstIntScalarTypeWith32Or64Bits(ValidationState_t& _,
648 Instruction* instr) {
649 if (instr->opcode() != SpvOpConstant) return false;
650 if (!_.IsIntScalarType(instr->type_id())) return false;
651 uint32_t size_in_bits = _.GetBitWidth(instr->type_id());
652 return size_in_bits == 32 || size_in_bits == 64;
653 }
654
IsConstWithIntScalarType(ValidationState_t & _,const Instruction * inst,uint32_t word_index)655 bool IsConstWithIntScalarType(ValidationState_t& _, const Instruction* inst,
656 uint32_t word_index) {
657 auto* int_scalar_const = _.FindDef(inst->word(word_index));
658 if (int_scalar_const->opcode() == SpvOpConstant &&
659 _.IsIntScalarType(int_scalar_const->type_id())) {
660 return true;
661 }
662 return false;
663 }
664
IsDebugVariableWithIntScalarType(ValidationState_t & _,const Instruction * inst,uint32_t word_index)665 bool IsDebugVariableWithIntScalarType(ValidationState_t& _,
666 const Instruction* inst,
667 uint32_t word_index) {
668 auto* dbg_int_scalar_var = _.FindDef(inst->word(word_index));
669 if (OpenCLDebugInfo100Instructions(dbg_int_scalar_var->word(4)) ==
670 OpenCLDebugInfo100DebugLocalVariable ||
671 OpenCLDebugInfo100Instructions(dbg_int_scalar_var->word(4)) ==
672 OpenCLDebugInfo100DebugGlobalVariable) {
673 auto* dbg_type = _.FindDef(dbg_int_scalar_var->word(6));
674 if (OpenCLDebugInfo100Instructions(dbg_type->word(4)) ==
675 OpenCLDebugInfo100DebugTypeBasic &&
676 (OpenCLDebugInfo100DebugBaseTypeAttributeEncoding(dbg_type->word(7)) ==
677 OpenCLDebugInfo100Signed ||
678 OpenCLDebugInfo100DebugBaseTypeAttributeEncoding(dbg_type->word(7)) ==
679 OpenCLDebugInfo100Unsigned)) {
680 return true;
681 }
682 }
683 return false;
684 }
685
686 } // anonymous namespace
687
ValidateExtension(ValidationState_t & _,const Instruction * inst)688 spv_result_t ValidateExtension(ValidationState_t& _, const Instruction* inst) {
689 if (spvIsWebGPUEnv(_.context()->target_env)) {
690 std::string extension = GetExtensionString(&(inst->c_inst()));
691
692 if (extension != ExtensionToString(kSPV_KHR_vulkan_memory_model)) {
693 return _.diag(SPV_ERROR_INVALID_DATA, inst)
694 << "For WebGPU, the only valid parameter to OpExtension is "
695 << "\"" << ExtensionToString(kSPV_KHR_vulkan_memory_model)
696 << "\".";
697 }
698 }
699
700 return SPV_SUCCESS;
701 }
702
ValidateExtInstImport(ValidationState_t & _,const Instruction * inst)703 spv_result_t ValidateExtInstImport(ValidationState_t& _,
704 const Instruction* inst) {
705 const auto name_id = 1;
706 if (spvIsWebGPUEnv(_.context()->target_env)) {
707 const std::string name(reinterpret_cast<const char*>(
708 inst->words().data() + inst->operands()[name_id].offset));
709 if (name != "GLSL.std.450") {
710 return _.diag(SPV_ERROR_INVALID_DATA, inst)
711 << "For WebGPU, the only valid parameter to OpExtInstImport is "
712 "\"GLSL.std.450\".";
713 }
714 }
715
716 if (!_.HasExtension(kSPV_KHR_non_semantic_info)) {
717 const std::string name(reinterpret_cast<const char*>(
718 inst->words().data() + inst->operands()[name_id].offset));
719 if (name.find("NonSemantic.") == 0) {
720 return _.diag(SPV_ERROR_INVALID_DATA, inst)
721 << "NonSemantic extended instruction sets cannot be declared "
722 "without SPV_KHR_non_semantic_info.";
723 }
724 }
725
726 return SPV_SUCCESS;
727 }
728
ValidateExtInst(ValidationState_t & _,const Instruction * inst)729 spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) {
730 const uint32_t result_type = inst->type_id();
731 const uint32_t num_operands = static_cast<uint32_t>(inst->operands().size());
732
733 const uint32_t ext_inst_set = inst->word(3);
734 const uint32_t ext_inst_index = inst->word(4);
735 const spv_ext_inst_type_t ext_inst_type =
736 spv_ext_inst_type_t(inst->ext_inst_type());
737
738 auto ext_inst_name = [&_, ext_inst_set, ext_inst_type, ext_inst_index]() {
739 spv_ext_inst_desc desc = nullptr;
740 if (_.grammar().lookupExtInst(ext_inst_type, ext_inst_index, &desc) !=
741 SPV_SUCCESS ||
742 !desc) {
743 return std::string("Unknown ExtInst");
744 }
745
746 auto* import_inst = _.FindDef(ext_inst_set);
747 assert(import_inst);
748
749 std::ostringstream ss;
750 ss << reinterpret_cast<const char*>(import_inst->words().data() + 2);
751 ss << " ";
752 ss << desc->name;
753
754 return ss.str();
755 };
756
757 if (ext_inst_type == SPV_EXT_INST_TYPE_GLSL_STD_450) {
758 const GLSLstd450 ext_inst_key = GLSLstd450(ext_inst_index);
759 switch (ext_inst_key) {
760 case GLSLstd450Round:
761 case GLSLstd450RoundEven:
762 case GLSLstd450FAbs:
763 case GLSLstd450Trunc:
764 case GLSLstd450FSign:
765 case GLSLstd450Floor:
766 case GLSLstd450Ceil:
767 case GLSLstd450Fract:
768 case GLSLstd450Sqrt:
769 case GLSLstd450InverseSqrt:
770 case GLSLstd450FMin:
771 case GLSLstd450FMax:
772 case GLSLstd450FClamp:
773 case GLSLstd450FMix:
774 case GLSLstd450Step:
775 case GLSLstd450SmoothStep:
776 case GLSLstd450Fma:
777 case GLSLstd450Normalize:
778 case GLSLstd450FaceForward:
779 case GLSLstd450Reflect:
780 case GLSLstd450NMin:
781 case GLSLstd450NMax:
782 case GLSLstd450NClamp: {
783 if (!_.IsFloatScalarOrVectorType(result_type)) {
784 return _.diag(SPV_ERROR_INVALID_DATA, inst)
785 << ext_inst_name() << ": "
786 << "expected Result Type to be a float scalar or vector type";
787 }
788
789 for (uint32_t operand_index = 4; operand_index < num_operands;
790 ++operand_index) {
791 const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
792 if (result_type != operand_type) {
793 return _.diag(SPV_ERROR_INVALID_DATA, inst)
794 << ext_inst_name() << ": "
795 << "expected types of all operands to be equal to Result "
796 "Type";
797 }
798 }
799 break;
800 }
801
802 case GLSLstd450SAbs:
803 case GLSLstd450SSign:
804 case GLSLstd450UMin:
805 case GLSLstd450SMin:
806 case GLSLstd450UMax:
807 case GLSLstd450SMax:
808 case GLSLstd450UClamp:
809 case GLSLstd450SClamp:
810 case GLSLstd450FindILsb:
811 case GLSLstd450FindUMsb:
812 case GLSLstd450FindSMsb: {
813 if (!_.IsIntScalarOrVectorType(result_type)) {
814 return _.diag(SPV_ERROR_INVALID_DATA, inst)
815 << ext_inst_name() << ": "
816 << "expected Result Type to be an int scalar or vector type";
817 }
818
819 const uint32_t result_type_bit_width = _.GetBitWidth(result_type);
820 const uint32_t result_type_dimension = _.GetDimension(result_type);
821
822 for (uint32_t operand_index = 4; operand_index < num_operands;
823 ++operand_index) {
824 const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
825 if (!_.IsIntScalarOrVectorType(operand_type)) {
826 return _.diag(SPV_ERROR_INVALID_DATA, inst)
827 << ext_inst_name() << ": "
828 << "expected all operands to be int scalars or vectors";
829 }
830
831 if (result_type_dimension != _.GetDimension(operand_type)) {
832 return _.diag(SPV_ERROR_INVALID_DATA, inst)
833 << ext_inst_name() << ": "
834 << "expected all operands to have the same dimension as "
835 << "Result Type";
836 }
837
838 if (result_type_bit_width != _.GetBitWidth(operand_type)) {
839 return _.diag(SPV_ERROR_INVALID_DATA, inst)
840 << ext_inst_name() << ": "
841 << "expected all operands to have the same bit width as "
842 << "Result Type";
843 }
844
845 if (ext_inst_key == GLSLstd450FindUMsb ||
846 ext_inst_key == GLSLstd450FindSMsb) {
847 if (result_type_bit_width != 32) {
848 return _.diag(SPV_ERROR_INVALID_DATA, inst)
849 << ext_inst_name() << ": "
850 << "this instruction is currently limited to 32-bit width "
851 << "components";
852 }
853 }
854 }
855 break;
856 }
857
858 case GLSLstd450Radians:
859 case GLSLstd450Degrees:
860 case GLSLstd450Sin:
861 case GLSLstd450Cos:
862 case GLSLstd450Tan:
863 case GLSLstd450Asin:
864 case GLSLstd450Acos:
865 case GLSLstd450Atan:
866 case GLSLstd450Sinh:
867 case GLSLstd450Cosh:
868 case GLSLstd450Tanh:
869 case GLSLstd450Asinh:
870 case GLSLstd450Acosh:
871 case GLSLstd450Atanh:
872 case GLSLstd450Exp:
873 case GLSLstd450Exp2:
874 case GLSLstd450Log:
875 case GLSLstd450Log2:
876 case GLSLstd450Atan2:
877 case GLSLstd450Pow: {
878 if (!_.IsFloatScalarOrVectorType(result_type)) {
879 return _.diag(SPV_ERROR_INVALID_DATA, inst)
880 << ext_inst_name() << ": "
881 << "expected Result Type to be a 16 or 32-bit scalar or "
882 "vector float type";
883 }
884
885 const uint32_t result_type_bit_width = _.GetBitWidth(result_type);
886 if (result_type_bit_width != 16 && result_type_bit_width != 32) {
887 return _.diag(SPV_ERROR_INVALID_DATA, inst)
888 << ext_inst_name() << ": "
889 << "expected Result Type to be a 16 or 32-bit scalar or "
890 "vector float type";
891 }
892
893 for (uint32_t operand_index = 4; operand_index < num_operands;
894 ++operand_index) {
895 const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
896 if (result_type != operand_type) {
897 return _.diag(SPV_ERROR_INVALID_DATA, inst)
898 << ext_inst_name() << ": "
899 << "expected types of all operands to be equal to Result "
900 "Type";
901 }
902 }
903 break;
904 }
905
906 case GLSLstd450Determinant: {
907 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
908 uint32_t num_rows = 0;
909 uint32_t num_cols = 0;
910 uint32_t col_type = 0;
911 uint32_t component_type = 0;
912 if (!_.GetMatrixTypeInfo(x_type, &num_rows, &num_cols, &col_type,
913 &component_type) ||
914 num_rows != num_cols) {
915 return _.diag(SPV_ERROR_INVALID_DATA, inst)
916 << ext_inst_name() << ": "
917 << "expected operand X to be a square matrix";
918 }
919
920 if (result_type != component_type) {
921 return _.diag(SPV_ERROR_INVALID_DATA, inst)
922 << ext_inst_name() << ": "
923 << "expected operand X component type to be equal to "
924 << "Result Type";
925 }
926 break;
927 }
928
929 case GLSLstd450MatrixInverse: {
930 uint32_t num_rows = 0;
931 uint32_t num_cols = 0;
932 uint32_t col_type = 0;
933 uint32_t component_type = 0;
934 if (!_.GetMatrixTypeInfo(result_type, &num_rows, &num_cols, &col_type,
935 &component_type) ||
936 num_rows != num_cols) {
937 return _.diag(SPV_ERROR_INVALID_DATA, inst)
938 << ext_inst_name() << ": "
939 << "expected Result Type to be a square matrix";
940 }
941
942 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
943 if (result_type != x_type) {
944 return _.diag(SPV_ERROR_INVALID_DATA, inst)
945 << ext_inst_name() << ": "
946 << "expected operand X type to be equal to Result Type";
947 }
948 break;
949 }
950
951 case GLSLstd450Modf: {
952 if (!_.IsFloatScalarOrVectorType(result_type)) {
953 return _.diag(SPV_ERROR_INVALID_DATA, inst)
954 << ext_inst_name() << ": "
955 << "expected Result Type to be a scalar or vector float type";
956 }
957
958 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
959 const uint32_t i_type = _.GetOperandTypeId(inst, 5);
960
961 if (x_type != result_type) {
962 return _.diag(SPV_ERROR_INVALID_DATA, inst)
963 << ext_inst_name() << ": "
964 << "expected operand X type to be equal to Result Type";
965 }
966
967 uint32_t i_storage_class = 0;
968 uint32_t i_data_type = 0;
969 if (!_.GetPointerTypeInfo(i_type, &i_data_type, &i_storage_class)) {
970 return _.diag(SPV_ERROR_INVALID_DATA, inst)
971 << ext_inst_name() << ": "
972 << "expected operand I to be a pointer";
973 }
974
975 if (i_data_type != result_type) {
976 return _.diag(SPV_ERROR_INVALID_DATA, inst)
977 << ext_inst_name() << ": "
978 << "expected operand I data type to be equal to Result Type";
979 }
980
981 break;
982 }
983
984 case GLSLstd450ModfStruct: {
985 std::vector<uint32_t> result_types;
986 if (!_.GetStructMemberTypes(result_type, &result_types) ||
987 result_types.size() != 2 ||
988 !_.IsFloatScalarOrVectorType(result_types[0]) ||
989 result_types[1] != result_types[0]) {
990 return _.diag(SPV_ERROR_INVALID_DATA, inst)
991 << ext_inst_name() << ": "
992 << "expected Result Type to be a struct with two identical "
993 << "scalar or vector float type members";
994 }
995
996 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
997 if (x_type != result_types[0]) {
998 return _.diag(SPV_ERROR_INVALID_DATA, inst)
999 << ext_inst_name() << ": "
1000 << "expected operand X type to be equal to members of "
1001 << "Result Type struct";
1002 }
1003 break;
1004 }
1005
1006 case GLSLstd450Frexp: {
1007 if (!_.IsFloatScalarOrVectorType(result_type)) {
1008 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1009 << ext_inst_name() << ": "
1010 << "expected Result Type to be a scalar or vector float type";
1011 }
1012
1013 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
1014 const uint32_t exp_type = _.GetOperandTypeId(inst, 5);
1015
1016 if (x_type != result_type) {
1017 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1018 << ext_inst_name() << ": "
1019 << "expected operand X type to be equal to Result Type";
1020 }
1021
1022 uint32_t exp_storage_class = 0;
1023 uint32_t exp_data_type = 0;
1024 if (!_.GetPointerTypeInfo(exp_type, &exp_data_type,
1025 &exp_storage_class)) {
1026 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1027 << ext_inst_name() << ": "
1028 << "expected operand Exp to be a pointer";
1029 }
1030
1031 if (!_.IsIntScalarOrVectorType(exp_data_type) ||
1032 (!_.HasExtension(kSPV_AMD_gpu_shader_int16) &&
1033 _.GetBitWidth(exp_data_type) != 32) ||
1034 (_.HasExtension(kSPV_AMD_gpu_shader_int16) &&
1035 _.GetBitWidth(exp_data_type) != 16 &&
1036 _.GetBitWidth(exp_data_type) != 32)) {
1037 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1038 << ext_inst_name() << ": "
1039 << "expected operand Exp data type to be a "
1040 << (_.HasExtension(kSPV_AMD_gpu_shader_int16)
1041 ? "16-bit or 32-bit "
1042 : "32-bit ")
1043 << "int scalar or vector type";
1044 }
1045
1046 if (_.GetDimension(result_type) != _.GetDimension(exp_data_type)) {
1047 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1048 << ext_inst_name() << ": "
1049 << "expected operand Exp data type to have the same component "
1050 << "number as Result Type";
1051 }
1052
1053 break;
1054 }
1055
1056 case GLSLstd450Ldexp: {
1057 if (!_.IsFloatScalarOrVectorType(result_type)) {
1058 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1059 << ext_inst_name() << ": "
1060 << "expected Result Type to be a scalar or vector float type";
1061 }
1062
1063 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
1064 const uint32_t exp_type = _.GetOperandTypeId(inst, 5);
1065
1066 if (x_type != result_type) {
1067 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1068 << ext_inst_name() << ": "
1069 << "expected operand X type to be equal to Result Type";
1070 }
1071
1072 if (!_.IsIntScalarOrVectorType(exp_type)) {
1073 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1074 << ext_inst_name() << ": "
1075 << "expected operand Exp to be a 32-bit int scalar "
1076 << "or vector type";
1077 }
1078
1079 if (_.GetDimension(result_type) != _.GetDimension(exp_type)) {
1080 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1081 << ext_inst_name() << ": "
1082 << "expected operand Exp to have the same component "
1083 << "number as Result Type";
1084 }
1085
1086 break;
1087 }
1088
1089 case GLSLstd450FrexpStruct: {
1090 std::vector<uint32_t> result_types;
1091 if (!_.GetStructMemberTypes(result_type, &result_types) ||
1092 result_types.size() != 2 ||
1093 !_.IsFloatScalarOrVectorType(result_types[0]) ||
1094 !_.IsIntScalarOrVectorType(result_types[1]) ||
1095 (!_.HasExtension(kSPV_AMD_gpu_shader_int16) &&
1096 _.GetBitWidth(result_types[1]) != 32) ||
1097 (_.HasExtension(kSPV_AMD_gpu_shader_int16) &&
1098 _.GetBitWidth(result_types[1]) != 16 &&
1099 _.GetBitWidth(result_types[1]) != 32) ||
1100 _.GetDimension(result_types[0]) !=
1101 _.GetDimension(result_types[1])) {
1102 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1103 << ext_inst_name() << ": "
1104 << "expected Result Type to be a struct with two members, "
1105 << "first member a float scalar or vector, second member a "
1106 << (_.HasExtension(kSPV_AMD_gpu_shader_int16)
1107 ? "16-bit or 32-bit "
1108 : "32-bit ")
1109 << "int scalar or vector with the same number of "
1110 << "components as the first member";
1111 }
1112
1113 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
1114 if (x_type != result_types[0]) {
1115 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1116 << ext_inst_name() << ": "
1117 << "expected operand X type to be equal to the first member "
1118 << "of Result Type struct";
1119 }
1120 break;
1121 }
1122
1123 case GLSLstd450PackSnorm4x8:
1124 case GLSLstd450PackUnorm4x8: {
1125 if (!_.IsIntScalarType(result_type) ||
1126 _.GetBitWidth(result_type) != 32) {
1127 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1128 << ext_inst_name() << ": "
1129 << "expected Result Type to be 32-bit int scalar type";
1130 }
1131
1132 const uint32_t v_type = _.GetOperandTypeId(inst, 4);
1133 if (!_.IsFloatVectorType(v_type) || _.GetDimension(v_type) != 4 ||
1134 _.GetBitWidth(v_type) != 32) {
1135 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1136 << ext_inst_name() << ": "
1137 << "expected operand V to be a 32-bit float vector of size 4";
1138 }
1139 break;
1140 }
1141
1142 case GLSLstd450PackSnorm2x16:
1143 case GLSLstd450PackUnorm2x16:
1144 case GLSLstd450PackHalf2x16: {
1145 if (!_.IsIntScalarType(result_type) ||
1146 _.GetBitWidth(result_type) != 32) {
1147 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1148 << ext_inst_name() << ": "
1149 << "expected Result Type to be 32-bit int scalar type";
1150 }
1151
1152 const uint32_t v_type = _.GetOperandTypeId(inst, 4);
1153 if (!_.IsFloatVectorType(v_type) || _.GetDimension(v_type) != 2 ||
1154 _.GetBitWidth(v_type) != 32) {
1155 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1156 << ext_inst_name() << ": "
1157 << "expected operand V to be a 32-bit float vector of size 2";
1158 }
1159 break;
1160 }
1161
1162 case GLSLstd450PackDouble2x32: {
1163 if (!_.IsFloatScalarType(result_type) ||
1164 _.GetBitWidth(result_type) != 64) {
1165 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1166 << ext_inst_name() << ": "
1167 << "expected Result Type to be 64-bit float scalar type";
1168 }
1169
1170 const uint32_t v_type = _.GetOperandTypeId(inst, 4);
1171 if (!_.IsIntVectorType(v_type) || _.GetDimension(v_type) != 2 ||
1172 _.GetBitWidth(v_type) != 32) {
1173 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1174 << ext_inst_name() << ": "
1175 << "expected operand V to be a 32-bit int vector of size 2";
1176 }
1177 break;
1178 }
1179
1180 case GLSLstd450UnpackSnorm4x8:
1181 case GLSLstd450UnpackUnorm4x8: {
1182 if (!_.IsFloatVectorType(result_type) ||
1183 _.GetDimension(result_type) != 4 ||
1184 _.GetBitWidth(result_type) != 32) {
1185 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1186 << ext_inst_name() << ": "
1187 << "expected Result Type to be a 32-bit float vector of size "
1188 "4";
1189 }
1190
1191 const uint32_t v_type = _.GetOperandTypeId(inst, 4);
1192 if (!_.IsIntScalarType(v_type) || _.GetBitWidth(v_type) != 32) {
1193 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1194 << ext_inst_name() << ": "
1195 << "expected operand P to be a 32-bit int scalar";
1196 }
1197 break;
1198 }
1199
1200 case GLSLstd450UnpackSnorm2x16:
1201 case GLSLstd450UnpackUnorm2x16:
1202 case GLSLstd450UnpackHalf2x16: {
1203 if (!_.IsFloatVectorType(result_type) ||
1204 _.GetDimension(result_type) != 2 ||
1205 _.GetBitWidth(result_type) != 32) {
1206 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1207 << ext_inst_name() << ": "
1208 << "expected Result Type to be a 32-bit float vector of size "
1209 "2";
1210 }
1211
1212 const uint32_t v_type = _.GetOperandTypeId(inst, 4);
1213 if (!_.IsIntScalarType(v_type) || _.GetBitWidth(v_type) != 32) {
1214 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1215 << ext_inst_name() << ": "
1216 << "expected operand P to be a 32-bit int scalar";
1217 }
1218 break;
1219 }
1220
1221 case GLSLstd450UnpackDouble2x32: {
1222 if (!_.IsIntVectorType(result_type) ||
1223 _.GetDimension(result_type) != 2 ||
1224 _.GetBitWidth(result_type) != 32) {
1225 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1226 << ext_inst_name() << ": "
1227 << "expected Result Type to be a 32-bit int vector of size "
1228 "2";
1229 }
1230
1231 const uint32_t v_type = _.GetOperandTypeId(inst, 4);
1232 if (!_.IsFloatScalarType(v_type) || _.GetBitWidth(v_type) != 64) {
1233 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1234 << ext_inst_name() << ": "
1235 << "expected operand V to be a 64-bit float scalar";
1236 }
1237 break;
1238 }
1239
1240 case GLSLstd450Length: {
1241 if (!_.IsFloatScalarType(result_type)) {
1242 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1243 << ext_inst_name() << ": "
1244 << "expected Result Type to be a float scalar type";
1245 }
1246
1247 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
1248 if (!_.IsFloatScalarOrVectorType(x_type)) {
1249 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1250 << ext_inst_name() << ": "
1251 << "expected operand X to be of float scalar or vector type";
1252 }
1253
1254 if (result_type != _.GetComponentType(x_type)) {
1255 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1256 << ext_inst_name() << ": "
1257 << "expected operand X component type to be equal to Result "
1258 "Type";
1259 }
1260 break;
1261 }
1262
1263 case GLSLstd450Distance: {
1264 if (!_.IsFloatScalarType(result_type)) {
1265 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1266 << ext_inst_name() << ": "
1267 << "expected Result Type to be a float scalar type";
1268 }
1269
1270 const uint32_t p0_type = _.GetOperandTypeId(inst, 4);
1271 if (!_.IsFloatScalarOrVectorType(p0_type)) {
1272 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1273 << ext_inst_name() << ": "
1274 << "expected operand P0 to be of float scalar or vector type";
1275 }
1276
1277 if (result_type != _.GetComponentType(p0_type)) {
1278 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1279 << ext_inst_name() << ": "
1280 << "expected operand P0 component type to be equal to "
1281 << "Result Type";
1282 }
1283
1284 const uint32_t p1_type = _.GetOperandTypeId(inst, 5);
1285 if (!_.IsFloatScalarOrVectorType(p1_type)) {
1286 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1287 << ext_inst_name() << ": "
1288 << "expected operand P1 to be of float scalar or vector type";
1289 }
1290
1291 if (result_type != _.GetComponentType(p1_type)) {
1292 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1293 << ext_inst_name() << ": "
1294 << "expected operand P1 component type to be equal to "
1295 << "Result Type";
1296 }
1297
1298 if (_.GetDimension(p0_type) != _.GetDimension(p1_type)) {
1299 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1300 << ext_inst_name() << ": "
1301 << "expected operands P0 and P1 to have the same number of "
1302 << "components";
1303 }
1304 break;
1305 }
1306
1307 case GLSLstd450Cross: {
1308 if (!_.IsFloatVectorType(result_type)) {
1309 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1310 << ext_inst_name() << ": "
1311 << "expected Result Type to be a float vector type";
1312 }
1313
1314 if (_.GetDimension(result_type) != 3) {
1315 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1316 << ext_inst_name() << ": "
1317 << "expected Result Type to have 3 components";
1318 }
1319
1320 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
1321 const uint32_t y_type = _.GetOperandTypeId(inst, 5);
1322
1323 if (x_type != result_type) {
1324 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1325 << ext_inst_name() << ": "
1326 << "expected operand X type to be equal to Result Type";
1327 }
1328
1329 if (y_type != result_type) {
1330 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1331 << ext_inst_name() << ": "
1332 << "expected operand Y type to be equal to Result Type";
1333 }
1334 break;
1335 }
1336
1337 case GLSLstd450Refract: {
1338 if (!_.IsFloatScalarOrVectorType(result_type)) {
1339 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1340 << ext_inst_name() << ": "
1341 << "expected Result Type to be a float scalar or vector type";
1342 }
1343
1344 const uint32_t i_type = _.GetOperandTypeId(inst, 4);
1345 const uint32_t n_type = _.GetOperandTypeId(inst, 5);
1346 const uint32_t eta_type = _.GetOperandTypeId(inst, 6);
1347
1348 if (result_type != i_type) {
1349 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1350 << ext_inst_name() << ": "
1351 << "expected operand I to be of type equal to Result Type";
1352 }
1353
1354 if (result_type != n_type) {
1355 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1356 << ext_inst_name() << ": "
1357 << "expected operand N to be of type equal to Result Type";
1358 }
1359
1360 if (!_.IsFloatScalarType(eta_type)) {
1361 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1362 << ext_inst_name() << ": "
1363 << "expected operand Eta to be a float scalar";
1364 }
1365 break;
1366 }
1367
1368 case GLSLstd450InterpolateAtCentroid:
1369 case GLSLstd450InterpolateAtSample:
1370 case GLSLstd450InterpolateAtOffset: {
1371 if (!_.HasCapability(SpvCapabilityInterpolationFunction)) {
1372 return _.diag(SPV_ERROR_INVALID_CAPABILITY, inst)
1373 << ext_inst_name()
1374 << " requires capability InterpolationFunction";
1375 }
1376
1377 if (!_.IsFloatScalarOrVectorType(result_type) ||
1378 _.GetBitWidth(result_type) != 32) {
1379 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1380 << ext_inst_name() << ": "
1381 << "expected Result Type to be a 32-bit float scalar "
1382 << "or vector type";
1383 }
1384
1385 const uint32_t interpolant_type = _.GetOperandTypeId(inst, 4);
1386 uint32_t interpolant_storage_class = 0;
1387 uint32_t interpolant_data_type = 0;
1388 if (!_.GetPointerTypeInfo(interpolant_type, &interpolant_data_type,
1389 &interpolant_storage_class)) {
1390 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1391 << ext_inst_name() << ": "
1392 << "expected Interpolant to be a pointer";
1393 }
1394
1395 if (result_type != interpolant_data_type) {
1396 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1397 << ext_inst_name() << ": "
1398 << "expected Interpolant data type to be equal to Result Type";
1399 }
1400
1401 if (interpolant_storage_class != SpvStorageClassInput) {
1402 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1403 << ext_inst_name() << ": "
1404 << "expected Interpolant storage class to be Input";
1405 }
1406
1407 if (ext_inst_key == GLSLstd450InterpolateAtSample) {
1408 const uint32_t sample_type = _.GetOperandTypeId(inst, 5);
1409 if (!_.IsIntScalarType(sample_type) ||
1410 _.GetBitWidth(sample_type) != 32) {
1411 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1412 << ext_inst_name() << ": "
1413 << "expected Sample to be 32-bit integer";
1414 }
1415 }
1416
1417 if (ext_inst_key == GLSLstd450InterpolateAtOffset) {
1418 const uint32_t offset_type = _.GetOperandTypeId(inst, 5);
1419 if (!_.IsFloatVectorType(offset_type) ||
1420 _.GetDimension(offset_type) != 2 ||
1421 _.GetBitWidth(offset_type) != 32) {
1422 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1423 << ext_inst_name() << ": "
1424 << "expected Offset to be a vector of 2 32-bit floats";
1425 }
1426 }
1427
1428 _.function(inst->function()->id())
1429 ->RegisterExecutionModelLimitation(
1430 SpvExecutionModelFragment,
1431 ext_inst_name() +
1432 std::string(" requires Fragment execution model"));
1433 break;
1434 }
1435
1436 case GLSLstd450IMix: {
1437 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1438 << "Extended instruction GLSLstd450IMix is not supported";
1439 }
1440
1441 case GLSLstd450Bad: {
1442 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1443 << "Encountered extended instruction GLSLstd450Bad";
1444 }
1445
1446 case GLSLstd450Count: {
1447 assert(0);
1448 break;
1449 }
1450 }
1451 } else if (ext_inst_type == SPV_EXT_INST_TYPE_OPENCL_STD) {
1452 const OpenCLLIB::Entrypoints ext_inst_key =
1453 OpenCLLIB::Entrypoints(ext_inst_index);
1454 switch (ext_inst_key) {
1455 case OpenCLLIB::Acos:
1456 case OpenCLLIB::Acosh:
1457 case OpenCLLIB::Acospi:
1458 case OpenCLLIB::Asin:
1459 case OpenCLLIB::Asinh:
1460 case OpenCLLIB::Asinpi:
1461 case OpenCLLIB::Atan:
1462 case OpenCLLIB::Atan2:
1463 case OpenCLLIB::Atanh:
1464 case OpenCLLIB::Atanpi:
1465 case OpenCLLIB::Atan2pi:
1466 case OpenCLLIB::Cbrt:
1467 case OpenCLLIB::Ceil:
1468 case OpenCLLIB::Copysign:
1469 case OpenCLLIB::Cos:
1470 case OpenCLLIB::Cosh:
1471 case OpenCLLIB::Cospi:
1472 case OpenCLLIB::Erfc:
1473 case OpenCLLIB::Erf:
1474 case OpenCLLIB::Exp:
1475 case OpenCLLIB::Exp2:
1476 case OpenCLLIB::Exp10:
1477 case OpenCLLIB::Expm1:
1478 case OpenCLLIB::Fabs:
1479 case OpenCLLIB::Fdim:
1480 case OpenCLLIB::Floor:
1481 case OpenCLLIB::Fma:
1482 case OpenCLLIB::Fmax:
1483 case OpenCLLIB::Fmin:
1484 case OpenCLLIB::Fmod:
1485 case OpenCLLIB::Hypot:
1486 case OpenCLLIB::Lgamma:
1487 case OpenCLLIB::Log:
1488 case OpenCLLIB::Log2:
1489 case OpenCLLIB::Log10:
1490 case OpenCLLIB::Log1p:
1491 case OpenCLLIB::Logb:
1492 case OpenCLLIB::Mad:
1493 case OpenCLLIB::Maxmag:
1494 case OpenCLLIB::Minmag:
1495 case OpenCLLIB::Nextafter:
1496 case OpenCLLIB::Pow:
1497 case OpenCLLIB::Powr:
1498 case OpenCLLIB::Remainder:
1499 case OpenCLLIB::Rint:
1500 case OpenCLLIB::Round:
1501 case OpenCLLIB::Rsqrt:
1502 case OpenCLLIB::Sin:
1503 case OpenCLLIB::Sinh:
1504 case OpenCLLIB::Sinpi:
1505 case OpenCLLIB::Sqrt:
1506 case OpenCLLIB::Tan:
1507 case OpenCLLIB::Tanh:
1508 case OpenCLLIB::Tanpi:
1509 case OpenCLLIB::Tgamma:
1510 case OpenCLLIB::Trunc:
1511 case OpenCLLIB::Half_cos:
1512 case OpenCLLIB::Half_divide:
1513 case OpenCLLIB::Half_exp:
1514 case OpenCLLIB::Half_exp2:
1515 case OpenCLLIB::Half_exp10:
1516 case OpenCLLIB::Half_log:
1517 case OpenCLLIB::Half_log2:
1518 case OpenCLLIB::Half_log10:
1519 case OpenCLLIB::Half_powr:
1520 case OpenCLLIB::Half_recip:
1521 case OpenCLLIB::Half_rsqrt:
1522 case OpenCLLIB::Half_sin:
1523 case OpenCLLIB::Half_sqrt:
1524 case OpenCLLIB::Half_tan:
1525 case OpenCLLIB::Native_cos:
1526 case OpenCLLIB::Native_divide:
1527 case OpenCLLIB::Native_exp:
1528 case OpenCLLIB::Native_exp2:
1529 case OpenCLLIB::Native_exp10:
1530 case OpenCLLIB::Native_log:
1531 case OpenCLLIB::Native_log2:
1532 case OpenCLLIB::Native_log10:
1533 case OpenCLLIB::Native_powr:
1534 case OpenCLLIB::Native_recip:
1535 case OpenCLLIB::Native_rsqrt:
1536 case OpenCLLIB::Native_sin:
1537 case OpenCLLIB::Native_sqrt:
1538 case OpenCLLIB::Native_tan:
1539 case OpenCLLIB::FClamp:
1540 case OpenCLLIB::Degrees:
1541 case OpenCLLIB::FMax_common:
1542 case OpenCLLIB::FMin_common:
1543 case OpenCLLIB::Mix:
1544 case OpenCLLIB::Radians:
1545 case OpenCLLIB::Step:
1546 case OpenCLLIB::Smoothstep:
1547 case OpenCLLIB::Sign: {
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 && num_components != 8 && num_components != 16) {
1556 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1557 << ext_inst_name() << ": "
1558 << "expected Result Type to be a scalar or a vector with 2, "
1559 "3, 4, 8 or 16 components";
1560 }
1561
1562 for (uint32_t operand_index = 4; operand_index < num_operands;
1563 ++operand_index) {
1564 const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
1565 if (result_type != operand_type) {
1566 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1567 << ext_inst_name() << ": "
1568 << "expected types of all operands to be equal to Result "
1569 "Type";
1570 }
1571 }
1572 break;
1573 }
1574
1575 case OpenCLLIB::Fract:
1576 case OpenCLLIB::Modf:
1577 case OpenCLLIB::Sincos: {
1578 if (!_.IsFloatScalarOrVectorType(result_type)) {
1579 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1580 << ext_inst_name() << ": "
1581 << "expected Result Type to be a float scalar or vector type";
1582 }
1583
1584 const uint32_t num_components = _.GetDimension(result_type);
1585 if (num_components > 4 && num_components != 8 && num_components != 16) {
1586 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1587 << ext_inst_name() << ": "
1588 << "expected Result Type to be a scalar or a vector with 2, "
1589 "3, 4, 8 or 16 components";
1590 }
1591
1592 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
1593 if (result_type != x_type) {
1594 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1595 << ext_inst_name() << ": "
1596 << "expected type of operand X to be equal to Result Type";
1597 }
1598
1599 const uint32_t p_type = _.GetOperandTypeId(inst, 5);
1600 uint32_t p_storage_class = 0;
1601 uint32_t p_data_type = 0;
1602 if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
1603 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1604 << ext_inst_name() << ": "
1605 << "expected the last operand to be a pointer";
1606 }
1607
1608 if (p_storage_class != SpvStorageClassGeneric &&
1609 p_storage_class != SpvStorageClassCrossWorkgroup &&
1610 p_storage_class != SpvStorageClassWorkgroup &&
1611 p_storage_class != SpvStorageClassFunction) {
1612 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1613 << ext_inst_name() << ": "
1614 << "expected storage class of the pointer to be Generic, "
1615 "CrossWorkgroup, Workgroup or Function";
1616 }
1617
1618 if (result_type != p_data_type) {
1619 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1620 << ext_inst_name() << ": "
1621 << "expected data type of the pointer to be equal to Result "
1622 "Type";
1623 }
1624 break;
1625 }
1626
1627 case OpenCLLIB::Frexp:
1628 case OpenCLLIB::Lgamma_r:
1629 case OpenCLLIB::Remquo: {
1630 if (!_.IsFloatScalarOrVectorType(result_type)) {
1631 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1632 << ext_inst_name() << ": "
1633 << "expected Result Type to be a float scalar or vector type";
1634 }
1635
1636 const uint32_t num_components = _.GetDimension(result_type);
1637 if (num_components > 4 && num_components != 8 && num_components != 16) {
1638 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1639 << ext_inst_name() << ": "
1640 << "expected Result Type to be a scalar or a vector with 2, "
1641 "3, 4, 8 or 16 components";
1642 }
1643
1644 uint32_t operand_index = 4;
1645 const uint32_t x_type = _.GetOperandTypeId(inst, operand_index++);
1646 if (result_type != x_type) {
1647 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1648 << ext_inst_name() << ": "
1649 << "expected type of operand X to be equal to Result Type";
1650 }
1651
1652 if (ext_inst_key == OpenCLLIB::Remquo) {
1653 const uint32_t y_type = _.GetOperandTypeId(inst, operand_index++);
1654 if (result_type != y_type) {
1655 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1656 << ext_inst_name() << ": "
1657 << "expected type of operand Y to be equal to Result Type";
1658 }
1659 }
1660
1661 const uint32_t p_type = _.GetOperandTypeId(inst, operand_index++);
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 the last operand to be a pointer";
1668 }
1669
1670 if (p_storage_class != SpvStorageClassGeneric &&
1671 p_storage_class != SpvStorageClassCrossWorkgroup &&
1672 p_storage_class != SpvStorageClassWorkgroup &&
1673 p_storage_class != SpvStorageClassFunction) {
1674 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1675 << ext_inst_name() << ": "
1676 << "expected storage class of the pointer to be Generic, "
1677 "CrossWorkgroup, Workgroup or Function";
1678 }
1679
1680 if (!_.IsIntScalarOrVectorType(p_data_type) ||
1681 _.GetBitWidth(p_data_type) != 32) {
1682 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1683 << ext_inst_name() << ": "
1684 << "expected data type of the pointer to be a 32-bit int "
1685 "scalar or vector type";
1686 }
1687
1688 if (_.GetDimension(p_data_type) != num_components) {
1689 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1690 << ext_inst_name() << ": "
1691 << "expected data type of the pointer to have the same number "
1692 "of components as Result Type";
1693 }
1694 break;
1695 }
1696
1697 case OpenCLLIB::Ilogb: {
1698 if (!_.IsIntScalarOrVectorType(result_type) ||
1699 _.GetBitWidth(result_type) != 32) {
1700 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1701 << ext_inst_name() << ": "
1702 << "expected Result Type to be a 32-bit int scalar or vector "
1703 "type";
1704 }
1705
1706 const uint32_t num_components = _.GetDimension(result_type);
1707 if (num_components > 4 && num_components != 8 && num_components != 16) {
1708 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1709 << ext_inst_name() << ": "
1710 << "expected Result Type to be a scalar or a vector with 2, "
1711 "3, 4, 8 or 16 components";
1712 }
1713
1714 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
1715 if (!_.IsFloatScalarOrVectorType(x_type)) {
1716 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1717 << ext_inst_name() << ": "
1718 << "expected operand X to be a float scalar or vector";
1719 }
1720
1721 if (_.GetDimension(x_type) != num_components) {
1722 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1723 << ext_inst_name() << ": "
1724 << "expected operand X to have the same number of components "
1725 "as Result Type";
1726 }
1727 break;
1728 }
1729
1730 case OpenCLLIB::Ldexp:
1731 case OpenCLLIB::Pown:
1732 case OpenCLLIB::Rootn: {
1733 if (!_.IsFloatScalarOrVectorType(result_type)) {
1734 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1735 << ext_inst_name() << ": "
1736 << "expected Result Type to be a float scalar or vector type";
1737 }
1738
1739 const uint32_t num_components = _.GetDimension(result_type);
1740 if (num_components > 4 && num_components != 8 && num_components != 16) {
1741 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1742 << ext_inst_name() << ": "
1743 << "expected Result Type to be a scalar or a vector with 2, "
1744 "3, 4, 8 or 16 components";
1745 }
1746
1747 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
1748 if (result_type != x_type) {
1749 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1750 << ext_inst_name() << ": "
1751 << "expected type of operand X to be equal to Result Type";
1752 }
1753
1754 const uint32_t exp_type = _.GetOperandTypeId(inst, 5);
1755 if (!_.IsIntScalarOrVectorType(exp_type) ||
1756 _.GetBitWidth(exp_type) != 32) {
1757 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1758 << ext_inst_name() << ": "
1759 << "expected the exponent to be a 32-bit int scalar or vector";
1760 }
1761
1762 if (_.GetDimension(exp_type) != num_components) {
1763 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1764 << ext_inst_name() << ": "
1765 << "expected the exponent to have the same number of "
1766 "components as Result Type";
1767 }
1768 break;
1769 }
1770
1771 case OpenCLLIB::Nan: {
1772 if (!_.IsFloatScalarOrVectorType(result_type)) {
1773 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1774 << ext_inst_name() << ": "
1775 << "expected Result Type to be a float scalar or vector type";
1776 }
1777
1778 const uint32_t num_components = _.GetDimension(result_type);
1779 if (num_components > 4 && num_components != 8 && num_components != 16) {
1780 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1781 << ext_inst_name() << ": "
1782 << "expected Result Type to be a scalar or a vector with 2, "
1783 "3, 4, 8 or 16 components";
1784 }
1785
1786 const uint32_t nancode_type = _.GetOperandTypeId(inst, 4);
1787 if (!_.IsIntScalarOrVectorType(nancode_type)) {
1788 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1789 << ext_inst_name() << ": "
1790 << "expected Nancode to be an int scalar or vector type";
1791 }
1792
1793 if (_.GetDimension(nancode_type) != num_components) {
1794 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1795 << ext_inst_name() << ": "
1796 << "expected Nancode to have the same number of components as "
1797 "Result Type";
1798 }
1799
1800 if (_.GetBitWidth(result_type) != _.GetBitWidth(nancode_type)) {
1801 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1802 << ext_inst_name() << ": "
1803 << "expected Nancode to have the same bit width as Result "
1804 "Type";
1805 }
1806 break;
1807 }
1808
1809 case OpenCLLIB::SAbs:
1810 case OpenCLLIB::SAbs_diff:
1811 case OpenCLLIB::SAdd_sat:
1812 case OpenCLLIB::UAdd_sat:
1813 case OpenCLLIB::SHadd:
1814 case OpenCLLIB::UHadd:
1815 case OpenCLLIB::SRhadd:
1816 case OpenCLLIB::URhadd:
1817 case OpenCLLIB::SClamp:
1818 case OpenCLLIB::UClamp:
1819 case OpenCLLIB::Clz:
1820 case OpenCLLIB::Ctz:
1821 case OpenCLLIB::SMad_hi:
1822 case OpenCLLIB::UMad_sat:
1823 case OpenCLLIB::SMad_sat:
1824 case OpenCLLIB::SMax:
1825 case OpenCLLIB::UMax:
1826 case OpenCLLIB::SMin:
1827 case OpenCLLIB::UMin:
1828 case OpenCLLIB::SMul_hi:
1829 case OpenCLLIB::Rotate:
1830 case OpenCLLIB::SSub_sat:
1831 case OpenCLLIB::USub_sat:
1832 case OpenCLLIB::Popcount:
1833 case OpenCLLIB::UAbs:
1834 case OpenCLLIB::UAbs_diff:
1835 case OpenCLLIB::UMul_hi:
1836 case OpenCLLIB::UMad_hi: {
1837 if (!_.IsIntScalarOrVectorType(result_type)) {
1838 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1839 << ext_inst_name() << ": "
1840 << "expected Result Type to be an int scalar or vector type";
1841 }
1842
1843 const uint32_t num_components = _.GetDimension(result_type);
1844 if (num_components > 4 && num_components != 8 && num_components != 16) {
1845 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1846 << ext_inst_name() << ": "
1847 << "expected Result Type to be a scalar or a vector with 2, "
1848 "3, 4, 8 or 16 components";
1849 }
1850
1851 for (uint32_t operand_index = 4; operand_index < num_operands;
1852 ++operand_index) {
1853 const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
1854 if (result_type != operand_type) {
1855 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1856 << ext_inst_name() << ": "
1857 << "expected types of all operands to be equal to Result "
1858 "Type";
1859 }
1860 }
1861 break;
1862 }
1863
1864 case OpenCLLIB::U_Upsample:
1865 case OpenCLLIB::S_Upsample: {
1866 if (!_.IsIntScalarOrVectorType(result_type)) {
1867 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1868 << ext_inst_name() << ": "
1869 << "expected Result Type to be an int scalar or vector "
1870 "type";
1871 }
1872
1873 const uint32_t result_num_components = _.GetDimension(result_type);
1874 if (result_num_components > 4 && result_num_components != 8 &&
1875 result_num_components != 16) {
1876 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1877 << ext_inst_name() << ": "
1878 << "expected Result Type to be a scalar or a vector with 2, "
1879 "3, 4, 8 or 16 components";
1880 }
1881
1882 const uint32_t result_bit_width = _.GetBitWidth(result_type);
1883 if (result_bit_width != 16 && result_bit_width != 32 &&
1884 result_bit_width != 64) {
1885 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1886 << ext_inst_name() << ": "
1887 << "expected bit width of Result Type components to be 16, 32 "
1888 "or 64";
1889 }
1890
1891 const uint32_t hi_type = _.GetOperandTypeId(inst, 4);
1892 const uint32_t lo_type = _.GetOperandTypeId(inst, 5);
1893
1894 if (hi_type != lo_type) {
1895 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1896 << ext_inst_name() << ": "
1897 << "expected Hi and Lo operands to have the same type";
1898 }
1899
1900 if (result_num_components != _.GetDimension(hi_type)) {
1901 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1902 << ext_inst_name() << ": "
1903 << "expected Hi and Lo operands to have the same number of "
1904 "components as Result Type";
1905 }
1906
1907 if (result_bit_width != 2 * _.GetBitWidth(hi_type)) {
1908 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1909 << ext_inst_name() << ": "
1910 << "expected bit width of components of Hi and Lo operands to "
1911 "be half of the bit width of components of Result Type";
1912 }
1913 break;
1914 }
1915
1916 case OpenCLLIB::SMad24:
1917 case OpenCLLIB::UMad24:
1918 case OpenCLLIB::SMul24:
1919 case OpenCLLIB::UMul24: {
1920 if (!_.IsIntScalarOrVectorType(result_type) ||
1921 _.GetBitWidth(result_type) != 32) {
1922 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1923 << ext_inst_name() << ": "
1924 << "expected Result Type to be a 32-bit int scalar or vector "
1925 "type";
1926 }
1927
1928 const uint32_t num_components = _.GetDimension(result_type);
1929 if (num_components > 4 && num_components != 8 && num_components != 16) {
1930 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1931 << ext_inst_name() << ": "
1932 << "expected Result Type to be a scalar or a vector with 2, "
1933 "3, 4, 8 or 16 components";
1934 }
1935
1936 for (uint32_t operand_index = 4; operand_index < num_operands;
1937 ++operand_index) {
1938 const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
1939 if (result_type != operand_type) {
1940 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1941 << ext_inst_name() << ": "
1942 << "expected types of all operands to be equal to Result "
1943 "Type";
1944 }
1945 }
1946 break;
1947 }
1948
1949 case OpenCLLIB::Cross: {
1950 if (!_.IsFloatVectorType(result_type)) {
1951 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1952 << ext_inst_name() << ": "
1953 << "expected Result Type to be a float vector type";
1954 }
1955
1956 const uint32_t num_components = _.GetDimension(result_type);
1957 if (num_components != 3 && num_components != 4) {
1958 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1959 << ext_inst_name() << ": "
1960 << "expected Result Type to have 3 or 4 components";
1961 }
1962
1963 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
1964 const uint32_t y_type = _.GetOperandTypeId(inst, 5);
1965
1966 if (x_type != result_type) {
1967 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1968 << ext_inst_name() << ": "
1969 << "expected operand X type to be equal to Result Type";
1970 }
1971
1972 if (y_type != result_type) {
1973 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1974 << ext_inst_name() << ": "
1975 << "expected operand Y type to be equal to Result Type";
1976 }
1977 break;
1978 }
1979
1980 case OpenCLLIB::Distance:
1981 case OpenCLLIB::Fast_distance: {
1982 if (!_.IsFloatScalarType(result_type)) {
1983 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1984 << ext_inst_name() << ": "
1985 << "expected Result Type to be a float scalar type";
1986 }
1987
1988 const uint32_t p0_type = _.GetOperandTypeId(inst, 4);
1989 if (!_.IsFloatScalarOrVectorType(p0_type)) {
1990 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1991 << ext_inst_name() << ": "
1992 << "expected operand P0 to be of float scalar or vector type";
1993 }
1994
1995 const uint32_t num_components = _.GetDimension(p0_type);
1996 if (num_components > 4) {
1997 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1998 << ext_inst_name() << ": "
1999 << "expected operand P0 to have no more than 4 components";
2000 }
2001
2002 if (result_type != _.GetComponentType(p0_type)) {
2003 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2004 << ext_inst_name() << ": "
2005 << "expected operand P0 component type to be equal to "
2006 << "Result Type";
2007 }
2008
2009 const uint32_t p1_type = _.GetOperandTypeId(inst, 5);
2010 if (p0_type != p1_type) {
2011 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2012 << ext_inst_name() << ": "
2013 << "expected operands P0 and P1 to be of the same type";
2014 }
2015 break;
2016 }
2017
2018 case OpenCLLIB::Length:
2019 case OpenCLLIB::Fast_length: {
2020 if (!_.IsFloatScalarType(result_type)) {
2021 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2022 << ext_inst_name() << ": "
2023 << "expected Result Type to be a float scalar type";
2024 }
2025
2026 const uint32_t p_type = _.GetOperandTypeId(inst, 4);
2027 if (!_.IsFloatScalarOrVectorType(p_type)) {
2028 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2029 << ext_inst_name() << ": "
2030 << "expected operand P to be a float scalar or vector";
2031 }
2032
2033 const uint32_t num_components = _.GetDimension(p_type);
2034 if (num_components > 4) {
2035 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2036 << ext_inst_name() << ": "
2037 << "expected operand P to have no more than 4 components";
2038 }
2039
2040 if (result_type != _.GetComponentType(p_type)) {
2041 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2042 << ext_inst_name() << ": "
2043 << "expected operand P component type to be equal to Result "
2044 "Type";
2045 }
2046 break;
2047 }
2048
2049 case OpenCLLIB::Normalize:
2050 case OpenCLLIB::Fast_normalize: {
2051 if (!_.IsFloatScalarOrVectorType(result_type)) {
2052 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2053 << ext_inst_name() << ": "
2054 << "expected Result Type to be a float scalar or vector type";
2055 }
2056
2057 const uint32_t num_components = _.GetDimension(result_type);
2058 if (num_components > 4) {
2059 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2060 << ext_inst_name() << ": "
2061 << "expected Result Type to have no more than 4 components";
2062 }
2063
2064 const uint32_t p_type = _.GetOperandTypeId(inst, 4);
2065 if (p_type != result_type) {
2066 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2067 << ext_inst_name() << ": "
2068 << "expected operand P type to be equal to Result Type";
2069 }
2070 break;
2071 }
2072
2073 case OpenCLLIB::Bitselect: {
2074 if (!_.IsFloatScalarOrVectorType(result_type) &&
2075 !_.IsIntScalarOrVectorType(result_type)) {
2076 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2077 << ext_inst_name() << ": "
2078 << "expected Result Type to be an int or float scalar or "
2079 "vector type";
2080 }
2081
2082 const uint32_t num_components = _.GetDimension(result_type);
2083 if (num_components > 4 && num_components != 8 && num_components != 16) {
2084 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2085 << ext_inst_name() << ": "
2086 << "expected Result Type to be a scalar or a vector with 2, "
2087 "3, 4, 8 or 16 components";
2088 }
2089
2090 for (uint32_t operand_index = 4; operand_index < num_operands;
2091 ++operand_index) {
2092 const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
2093 if (result_type != operand_type) {
2094 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2095 << ext_inst_name() << ": "
2096 << "expected types of all operands to be equal to Result "
2097 "Type";
2098 }
2099 }
2100 break;
2101 }
2102
2103 case OpenCLLIB::Select: {
2104 if (!_.IsFloatScalarOrVectorType(result_type) &&
2105 !_.IsIntScalarOrVectorType(result_type)) {
2106 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2107 << ext_inst_name() << ": "
2108 << "expected Result Type to be an int or float scalar or "
2109 "vector type";
2110 }
2111
2112 const uint32_t num_components = _.GetDimension(result_type);
2113 if (num_components > 4 && num_components != 8 && num_components != 16) {
2114 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2115 << ext_inst_name() << ": "
2116 << "expected Result Type to be a scalar or a vector with 2, "
2117 "3, 4, 8 or 16 components";
2118 }
2119
2120 const uint32_t a_type = _.GetOperandTypeId(inst, 4);
2121 const uint32_t b_type = _.GetOperandTypeId(inst, 5);
2122 const uint32_t c_type = _.GetOperandTypeId(inst, 6);
2123
2124 if (result_type != a_type) {
2125 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2126 << ext_inst_name() << ": "
2127 << "expected operand A type to be equal to Result Type";
2128 }
2129
2130 if (result_type != b_type) {
2131 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2132 << ext_inst_name() << ": "
2133 << "expected operand B type to be equal to Result Type";
2134 }
2135
2136 if (!_.IsIntScalarOrVectorType(c_type)) {
2137 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2138 << ext_inst_name() << ": "
2139 << "expected operand C to be an int scalar or vector";
2140 }
2141
2142 if (num_components != _.GetDimension(c_type)) {
2143 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2144 << ext_inst_name() << ": "
2145 << "expected operand C to have the same number of components "
2146 "as Result Type";
2147 }
2148
2149 if (_.GetBitWidth(result_type) != _.GetBitWidth(c_type)) {
2150 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2151 << ext_inst_name() << ": "
2152 << "expected operand C to have the same bit width as Result "
2153 "Type";
2154 }
2155 break;
2156 }
2157
2158 case OpenCLLIB::Vloadn: {
2159 if (!_.IsFloatVectorType(result_type) &&
2160 !_.IsIntVectorType(result_type)) {
2161 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2162 << ext_inst_name() << ": "
2163 << "expected Result Type to be an int or float vector type";
2164 }
2165
2166 const uint32_t num_components = _.GetDimension(result_type);
2167 if (num_components > 4 && num_components != 8 && num_components != 16) {
2168 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2169 << ext_inst_name() << ": "
2170 << "expected Result Type to have 2, 3, 4, 8 or 16 components";
2171 }
2172
2173 const uint32_t offset_type = _.GetOperandTypeId(inst, 4);
2174 const uint32_t p_type = _.GetOperandTypeId(inst, 5);
2175
2176 const uint32_t size_t_bit_width = GetSizeTBitWidth(_);
2177 if (!size_t_bit_width) {
2178 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2179 << ext_inst_name()
2180 << " can only be used with physical addressing models";
2181 }
2182
2183 if (!_.IsIntScalarType(offset_type) ||
2184 _.GetBitWidth(offset_type) != size_t_bit_width) {
2185 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2186 << ext_inst_name() << ": "
2187 << "expected operand Offset to be of type size_t ("
2188 << size_t_bit_width
2189 << "-bit integer for the addressing model used in the module)";
2190 }
2191
2192 uint32_t p_storage_class = 0;
2193 uint32_t p_data_type = 0;
2194 if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
2195 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2196 << ext_inst_name() << ": "
2197 << "expected operand P to be a pointer";
2198 }
2199
2200 if (p_storage_class != SpvStorageClassUniformConstant &&
2201 p_storage_class != SpvStorageClassGeneric &&
2202 p_storage_class != SpvStorageClassCrossWorkgroup &&
2203 p_storage_class != SpvStorageClassWorkgroup &&
2204 p_storage_class != SpvStorageClassFunction) {
2205 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2206 << ext_inst_name() << ": "
2207 << "expected operand P storage class to be UniformConstant, "
2208 "Generic, CrossWorkgroup, Workgroup or Function";
2209 }
2210
2211 if (_.GetComponentType(result_type) != p_data_type) {
2212 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2213 << ext_inst_name() << ": "
2214 << "expected operand P data type to be equal to component "
2215 "type of Result Type";
2216 }
2217
2218 const uint32_t n_value = inst->word(7);
2219 if (num_components != n_value) {
2220 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2221 << ext_inst_name() << ": "
2222 << "expected literal N to be equal to the number of "
2223 "components of Result Type";
2224 }
2225 break;
2226 }
2227
2228 case OpenCLLIB::Vstoren: {
2229 if (_.GetIdOpcode(result_type) != SpvOpTypeVoid) {
2230 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2231 << ext_inst_name() << ": expected Result Type to be void";
2232 }
2233
2234 const uint32_t data_type = _.GetOperandTypeId(inst, 4);
2235 const uint32_t offset_type = _.GetOperandTypeId(inst, 5);
2236 const uint32_t p_type = _.GetOperandTypeId(inst, 6);
2237
2238 if (!_.IsFloatVectorType(data_type) && !_.IsIntVectorType(data_type)) {
2239 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2240 << ext_inst_name() << ": "
2241 << "expected Data to be an int or float vector";
2242 }
2243
2244 const uint32_t num_components = _.GetDimension(data_type);
2245 if (num_components > 4 && num_components != 8 && num_components != 16) {
2246 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2247 << ext_inst_name() << ": "
2248 << "expected Data to have 2, 3, 4, 8 or 16 components";
2249 }
2250
2251 const uint32_t size_t_bit_width = GetSizeTBitWidth(_);
2252 if (!size_t_bit_width) {
2253 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2254 << ext_inst_name()
2255 << " can only be used with physical addressing models";
2256 }
2257
2258 if (!_.IsIntScalarType(offset_type) ||
2259 _.GetBitWidth(offset_type) != size_t_bit_width) {
2260 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2261 << ext_inst_name() << ": "
2262 << "expected operand Offset to be of type size_t ("
2263 << size_t_bit_width
2264 << "-bit integer for the addressing model used in the module)";
2265 }
2266
2267 uint32_t p_storage_class = 0;
2268 uint32_t p_data_type = 0;
2269 if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
2270 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2271 << ext_inst_name() << ": "
2272 << "expected operand P to be a pointer";
2273 }
2274
2275 if (p_storage_class != SpvStorageClassGeneric &&
2276 p_storage_class != SpvStorageClassCrossWorkgroup &&
2277 p_storage_class != SpvStorageClassWorkgroup &&
2278 p_storage_class != SpvStorageClassFunction) {
2279 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2280 << ext_inst_name() << ": "
2281 << "expected operand P storage class to be Generic, "
2282 "CrossWorkgroup, Workgroup or Function";
2283 }
2284
2285 if (_.GetComponentType(data_type) != p_data_type) {
2286 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2287 << ext_inst_name() << ": "
2288 << "expected operand P data type to be equal to the type of "
2289 "operand Data components";
2290 }
2291 break;
2292 }
2293
2294 case OpenCLLIB::Vload_half: {
2295 if (!_.IsFloatScalarType(result_type)) {
2296 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2297 << ext_inst_name() << ": "
2298 << "expected Result Type to be a float scalar type";
2299 }
2300
2301 const uint32_t offset_type = _.GetOperandTypeId(inst, 4);
2302 const uint32_t p_type = _.GetOperandTypeId(inst, 5);
2303
2304 const uint32_t size_t_bit_width = GetSizeTBitWidth(_);
2305 if (!size_t_bit_width) {
2306 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2307 << ext_inst_name()
2308 << " can only be used with physical addressing models";
2309 }
2310
2311 if (!_.IsIntScalarType(offset_type) ||
2312 _.GetBitWidth(offset_type) != size_t_bit_width) {
2313 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2314 << ext_inst_name() << ": "
2315 << "expected operand Offset to be of type size_t ("
2316 << size_t_bit_width
2317 << "-bit integer for the addressing model used in the module)";
2318 }
2319
2320 uint32_t p_storage_class = 0;
2321 uint32_t p_data_type = 0;
2322 if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
2323 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2324 << ext_inst_name() << ": "
2325 << "expected operand P to be a pointer";
2326 }
2327
2328 if (p_storage_class != SpvStorageClassUniformConstant &&
2329 p_storage_class != SpvStorageClassGeneric &&
2330 p_storage_class != SpvStorageClassCrossWorkgroup &&
2331 p_storage_class != SpvStorageClassWorkgroup &&
2332 p_storage_class != SpvStorageClassFunction) {
2333 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2334 << ext_inst_name() << ": "
2335 << "expected operand P storage class to be UniformConstant, "
2336 "Generic, CrossWorkgroup, Workgroup or Function";
2337 }
2338
2339 if (!_.IsFloatScalarType(p_data_type) ||
2340 _.GetBitWidth(p_data_type) != 16) {
2341 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2342 << ext_inst_name() << ": "
2343 << "expected operand P data type to be 16-bit float scalar";
2344 }
2345 break;
2346 }
2347
2348 case OpenCLLIB::Vload_halfn:
2349 case OpenCLLIB::Vloada_halfn: {
2350 if (!_.IsFloatVectorType(result_type)) {
2351 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2352 << ext_inst_name() << ": "
2353 << "expected Result Type to be a float vector type";
2354 }
2355
2356 const uint32_t num_components = _.GetDimension(result_type);
2357 if (num_components > 4 && num_components != 8 && num_components != 16) {
2358 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2359 << ext_inst_name() << ": "
2360 << "expected Result Type to have 2, 3, 4, 8 or 16 components";
2361 }
2362
2363 const uint32_t offset_type = _.GetOperandTypeId(inst, 4);
2364 const uint32_t p_type = _.GetOperandTypeId(inst, 5);
2365
2366 const uint32_t size_t_bit_width = GetSizeTBitWidth(_);
2367 if (!size_t_bit_width) {
2368 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2369 << ext_inst_name()
2370 << " can only be used with physical addressing models";
2371 }
2372
2373 if (!_.IsIntScalarType(offset_type) ||
2374 _.GetBitWidth(offset_type) != size_t_bit_width) {
2375 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2376 << ext_inst_name() << ": "
2377 << "expected operand Offset to be of type size_t ("
2378 << size_t_bit_width
2379 << "-bit integer for the addressing model used in the module)";
2380 }
2381
2382 uint32_t p_storage_class = 0;
2383 uint32_t p_data_type = 0;
2384 if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
2385 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2386 << ext_inst_name() << ": "
2387 << "expected operand P to be a pointer";
2388 }
2389
2390 if (p_storage_class != SpvStorageClassUniformConstant &&
2391 p_storage_class != SpvStorageClassGeneric &&
2392 p_storage_class != SpvStorageClassCrossWorkgroup &&
2393 p_storage_class != SpvStorageClassWorkgroup &&
2394 p_storage_class != SpvStorageClassFunction) {
2395 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2396 << ext_inst_name() << ": "
2397 << "expected operand P storage class to be UniformConstant, "
2398 "Generic, CrossWorkgroup, Workgroup or Function";
2399 }
2400
2401 if (!_.IsFloatScalarType(p_data_type) ||
2402 _.GetBitWidth(p_data_type) != 16) {
2403 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2404 << ext_inst_name() << ": "
2405 << "expected operand P data type to be 16-bit float scalar";
2406 }
2407
2408 const uint32_t n_value = inst->word(7);
2409 if (num_components != n_value) {
2410 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2411 << ext_inst_name() << ": "
2412 << "expected literal N to be equal to the number of "
2413 "components of Result Type";
2414 }
2415 break;
2416 }
2417
2418 case OpenCLLIB::Vstore_half:
2419 case OpenCLLIB::Vstore_half_r:
2420 case OpenCLLIB::Vstore_halfn:
2421 case OpenCLLIB::Vstore_halfn_r:
2422 case OpenCLLIB::Vstorea_halfn:
2423 case OpenCLLIB::Vstorea_halfn_r: {
2424 if (_.GetIdOpcode(result_type) != SpvOpTypeVoid) {
2425 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2426 << ext_inst_name() << ": expected Result Type to be void";
2427 }
2428
2429 const uint32_t data_type = _.GetOperandTypeId(inst, 4);
2430 const uint32_t offset_type = _.GetOperandTypeId(inst, 5);
2431 const uint32_t p_type = _.GetOperandTypeId(inst, 6);
2432 const uint32_t data_type_bit_width = _.GetBitWidth(data_type);
2433
2434 if (ext_inst_key == OpenCLLIB::Vstore_half ||
2435 ext_inst_key == OpenCLLIB::Vstore_half_r) {
2436 if (!_.IsFloatScalarType(data_type) ||
2437 (data_type_bit_width != 32 && data_type_bit_width != 64)) {
2438 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2439 << ext_inst_name() << ": "
2440 << "expected Data to be a 32 or 64-bit float scalar";
2441 }
2442 } else {
2443 if (!_.IsFloatVectorType(data_type) ||
2444 (data_type_bit_width != 32 && data_type_bit_width != 64)) {
2445 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2446 << ext_inst_name() << ": "
2447 << "expected Data to be a 32 or 64-bit float vector";
2448 }
2449
2450 const uint32_t num_components = _.GetDimension(data_type);
2451 if (num_components > 4 && num_components != 8 &&
2452 num_components != 16) {
2453 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2454 << ext_inst_name() << ": "
2455 << "expected Data to have 2, 3, 4, 8 or 16 components";
2456 }
2457 }
2458
2459 const uint32_t size_t_bit_width = GetSizeTBitWidth(_);
2460 if (!size_t_bit_width) {
2461 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2462 << ext_inst_name()
2463 << " can only be used with physical addressing models";
2464 }
2465
2466 if (!_.IsIntScalarType(offset_type) ||
2467 _.GetBitWidth(offset_type) != size_t_bit_width) {
2468 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2469 << ext_inst_name() << ": "
2470 << "expected operand Offset to be of type size_t ("
2471 << size_t_bit_width
2472 << "-bit integer for the addressing model used in the module)";
2473 }
2474
2475 uint32_t p_storage_class = 0;
2476 uint32_t p_data_type = 0;
2477 if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
2478 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2479 << ext_inst_name() << ": "
2480 << "expected operand P to be a pointer";
2481 }
2482
2483 if (p_storage_class != SpvStorageClassGeneric &&
2484 p_storage_class != SpvStorageClassCrossWorkgroup &&
2485 p_storage_class != SpvStorageClassWorkgroup &&
2486 p_storage_class != SpvStorageClassFunction) {
2487 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2488 << ext_inst_name() << ": "
2489 << "expected operand P storage class to be Generic, "
2490 "CrossWorkgroup, Workgroup or Function";
2491 }
2492
2493 if (!_.IsFloatScalarType(p_data_type) ||
2494 _.GetBitWidth(p_data_type) != 16) {
2495 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2496 << ext_inst_name() << ": "
2497 << "expected operand P data type to be 16-bit float scalar";
2498 }
2499
2500 // Rounding mode enum is checked by assembler.
2501 break;
2502 }
2503
2504 case OpenCLLIB::Shuffle:
2505 case OpenCLLIB::Shuffle2: {
2506 if (!_.IsFloatVectorType(result_type) &&
2507 !_.IsIntVectorType(result_type)) {
2508 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2509 << ext_inst_name() << ": "
2510 << "expected Result Type to be an int or float vector type";
2511 }
2512
2513 const uint32_t result_num_components = _.GetDimension(result_type);
2514 if (result_num_components != 2 && result_num_components != 4 &&
2515 result_num_components != 8 && result_num_components != 16) {
2516 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2517 << ext_inst_name() << ": "
2518 << "expected Result Type to have 2, 4, 8 or 16 components";
2519 }
2520
2521 uint32_t operand_index = 4;
2522 const uint32_t x_type = _.GetOperandTypeId(inst, operand_index++);
2523
2524 if (ext_inst_key == OpenCLLIB::Shuffle2) {
2525 const uint32_t y_type = _.GetOperandTypeId(inst, operand_index++);
2526 if (x_type != y_type) {
2527 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2528 << ext_inst_name() << ": "
2529 << "expected operands X and Y to be of the same type";
2530 }
2531 }
2532
2533 const uint32_t shuffle_mask_type =
2534 _.GetOperandTypeId(inst, operand_index++);
2535
2536 if (!_.IsFloatVectorType(x_type) && !_.IsIntVectorType(x_type)) {
2537 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2538 << ext_inst_name() << ": "
2539 << "expected operand X to be an int or float vector";
2540 }
2541
2542 const uint32_t x_num_components = _.GetDimension(x_type);
2543 if (x_num_components != 2 && x_num_components != 4 &&
2544 x_num_components != 8 && x_num_components != 16) {
2545 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2546 << ext_inst_name() << ": "
2547 << "expected operand X to have 2, 4, 8 or 16 components";
2548 }
2549
2550 const uint32_t result_component_type = _.GetComponentType(result_type);
2551
2552 if (result_component_type != _.GetComponentType(x_type)) {
2553 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2554 << ext_inst_name() << ": "
2555 << "expected operand X and Result Type to have equal "
2556 "component types";
2557 }
2558
2559 if (!_.IsIntVectorType(shuffle_mask_type)) {
2560 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2561 << ext_inst_name() << ": "
2562 << "expected operand Shuffle Mask to be an int vector";
2563 }
2564
2565 if (result_num_components != _.GetDimension(shuffle_mask_type)) {
2566 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2567 << ext_inst_name() << ": "
2568 << "expected operand Shuffle Mask to have the same number of "
2569 "components as Result Type";
2570 }
2571
2572 if (_.GetBitWidth(result_component_type) !=
2573 _.GetBitWidth(shuffle_mask_type)) {
2574 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2575 << ext_inst_name() << ": "
2576 << "expected operand Shuffle Mask components to have the same "
2577 "bit width as Result Type components";
2578 }
2579 break;
2580 }
2581
2582 case OpenCLLIB::Printf: {
2583 if (!_.IsIntScalarType(result_type) ||
2584 _.GetBitWidth(result_type) != 32) {
2585 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2586 << ext_inst_name() << ": "
2587 << "expected Result Type to be a 32-bit int type";
2588 }
2589
2590 const uint32_t format_type = _.GetOperandTypeId(inst, 4);
2591 uint32_t format_storage_class = 0;
2592 uint32_t format_data_type = 0;
2593 if (!_.GetPointerTypeInfo(format_type, &format_data_type,
2594 &format_storage_class)) {
2595 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2596 << ext_inst_name() << ": "
2597 << "expected operand Format to be a pointer";
2598 }
2599
2600 if (format_storage_class != SpvStorageClassUniformConstant) {
2601 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2602 << ext_inst_name() << ": "
2603 << "expected Format storage class to be UniformConstant";
2604 }
2605
2606 if (!_.IsIntScalarType(format_data_type) ||
2607 _.GetBitWidth(format_data_type) != 8) {
2608 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2609 << ext_inst_name() << ": "
2610 << "expected Format data type to be 8-bit int";
2611 }
2612 break;
2613 }
2614
2615 case OpenCLLIB::Prefetch: {
2616 if (_.GetIdOpcode(result_type) != SpvOpTypeVoid) {
2617 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2618 << ext_inst_name() << ": expected Result Type to be void";
2619 }
2620
2621 const uint32_t p_type = _.GetOperandTypeId(inst, 4);
2622 const uint32_t num_elements_type = _.GetOperandTypeId(inst, 5);
2623
2624 uint32_t p_storage_class = 0;
2625 uint32_t p_data_type = 0;
2626 if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
2627 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2628 << ext_inst_name() << ": "
2629 << "expected operand Ptr to be a pointer";
2630 }
2631
2632 if (p_storage_class != SpvStorageClassCrossWorkgroup) {
2633 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2634 << ext_inst_name() << ": "
2635 << "expected operand Ptr storage class to be CrossWorkgroup";
2636 }
2637
2638 if (!_.IsFloatScalarOrVectorType(p_data_type) &&
2639 !_.IsIntScalarOrVectorType(p_data_type)) {
2640 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2641 << ext_inst_name() << ": "
2642 << "expected Ptr data type to be int or float scalar or "
2643 "vector";
2644 }
2645
2646 const uint32_t num_components = _.GetDimension(p_data_type);
2647 if (num_components > 4 && num_components != 8 && num_components != 16) {
2648 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2649 << ext_inst_name() << ": "
2650 << "expected Result Type to be a scalar or a vector with 2, "
2651 "3, 4, 8 or 16 components";
2652 }
2653
2654 const uint32_t size_t_bit_width = GetSizeTBitWidth(_);
2655 if (!size_t_bit_width) {
2656 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2657 << ext_inst_name()
2658 << " can only be used with physical addressing models";
2659 }
2660
2661 if (!_.IsIntScalarType(num_elements_type) ||
2662 _.GetBitWidth(num_elements_type) != size_t_bit_width) {
2663 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2664 << ext_inst_name() << ": "
2665 << "expected operand Num Elements to be of type size_t ("
2666 << size_t_bit_width
2667 << "-bit integer for the addressing model used in the module)";
2668 }
2669 break;
2670 }
2671 }
2672 } else if (ext_inst_type == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100) {
2673 if (!_.IsVoidType(result_type)) {
2674 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2675 << ext_inst_name() << ": "
2676 << "expected result type must be a result id of "
2677 << "OpTypeVoid";
2678 }
2679
2680 auto num_words = inst->words().size();
2681
2682 const OpenCLDebugInfo100Instructions ext_inst_key =
2683 OpenCLDebugInfo100Instructions(ext_inst_index);
2684 switch (ext_inst_key) {
2685 case OpenCLDebugInfo100DebugInfoNone:
2686 case OpenCLDebugInfo100DebugNoScope:
2687 case OpenCLDebugInfo100DebugOperation:
2688 // The binary parser validates the opcode for DebugInfoNone,
2689 // DebugNoScope, DebugOperation, and the literal values don't need
2690 // further checks.
2691 break;
2692 case OpenCLDebugInfo100DebugCompilationUnit: {
2693 CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7);
2694 break;
2695 }
2696 case OpenCLDebugInfo100DebugSource: {
2697 CHECK_OPERAND("File", SpvOpString, 5);
2698 if (num_words == 7) CHECK_OPERAND("Text", SpvOpString, 6);
2699 break;
2700 }
2701 case OpenCLDebugInfo100DebugTypeBasic: {
2702 CHECK_OPERAND("Name", SpvOpString, 5);
2703 CHECK_OPERAND("Size", SpvOpConstant, 6);
2704 // "Encoding" param is already validated by the binary parsing stage.
2705 break;
2706 }
2707 case OpenCLDebugInfo100DebugTypePointer:
2708 case OpenCLDebugInfo100DebugTypeQualifier: {
2709 auto validate_base_type =
2710 ValidateOperandBaseType(_, inst, 5, ext_inst_name);
2711 if (validate_base_type != SPV_SUCCESS) return validate_base_type;
2712 break;
2713 }
2714 case OpenCLDebugInfo100DebugTypeVector: {
2715 auto validate_base_type =
2716 ValidateOperandBaseType(_, inst, 5, ext_inst_name);
2717 if (validate_base_type != SPV_SUCCESS) return validate_base_type;
2718
2719 uint32_t component_count = inst->word(6);
2720 if (!component_count || component_count > 4) {
2721 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2722 << ext_inst_name() << ": Component Count must be positive "
2723 << "integer less than or equal to 4";
2724 }
2725 break;
2726 }
2727 case OpenCLDebugInfo100DebugTypeArray: {
2728 auto validate_base_type = ValidateOperandDebugType(
2729 _, "Base Type", inst, 5, ext_inst_name, false);
2730 if (validate_base_type != SPV_SUCCESS) return validate_base_type;
2731 for (uint32_t i = 6; i < num_words; ++i) {
2732 bool invalid = false;
2733 auto* component_count = _.FindDef(inst->word(i));
2734 if (IsConstIntScalarTypeWith32Or64Bits(_, component_count)) {
2735 // TODO: We need a spec discussion for the bindless array.
2736 if (!component_count->word(3)) {
2737 invalid = true;
2738 }
2739 } else if (component_count->words().size() > 6 &&
2740 (OpenCLDebugInfo100Instructions(component_count->word(
2741 4)) == OpenCLDebugInfo100DebugLocalVariable ||
2742 OpenCLDebugInfo100Instructions(component_count->word(
2743 4)) == OpenCLDebugInfo100DebugGlobalVariable)) {
2744 auto* component_count_type = _.FindDef(component_count->word(6));
2745 if (component_count_type->words().size() > 7) {
2746 if (OpenCLDebugInfo100Instructions(component_count_type->word(
2747 4)) != OpenCLDebugInfo100DebugTypeBasic ||
2748 OpenCLDebugInfo100DebugBaseTypeAttributeEncoding(
2749 component_count_type->word(7)) !=
2750 OpenCLDebugInfo100Unsigned) {
2751 invalid = true;
2752 } else {
2753 // DebugTypeBasic for DebugLocalVariable/DebugGlobalVariable
2754 // must have Unsigned encoding and 32 or 64 as its size in bits.
2755 Instruction* size_in_bits =
2756 _.FindDef(component_count_type->word(6));
2757 if (!_.IsIntScalarType(size_in_bits->type_id()) ||
2758 (size_in_bits->word(3) != 32 &&
2759 size_in_bits->word(3) != 64)) {
2760 invalid = true;
2761 }
2762 }
2763 } else {
2764 invalid = true;
2765 }
2766 } else {
2767 invalid = true;
2768 }
2769 if (invalid) {
2770 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2771 << ext_inst_name() << ": Component Count must be "
2772 << "OpConstant with a 32- or 64-bits integer scalar type or "
2773 << "DebugGlobalVariable or DebugLocalVariable with a 32- or "
2774 << "64-bits unsigned integer scalar type";
2775 }
2776 }
2777 break;
2778 }
2779 case OpenCLDebugInfo100DebugTypedef: {
2780 CHECK_OPERAND("Name", SpvOpString, 5);
2781 auto validate_base_type =
2782 ValidateOperandBaseType(_, inst, 6, ext_inst_name);
2783 if (validate_base_type != SPV_SUCCESS) return validate_base_type;
2784 CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7);
2785 auto validate_parent =
2786 ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name);
2787 if (validate_parent != SPV_SUCCESS) return validate_parent;
2788 break;
2789 }
2790 case OpenCLDebugInfo100DebugTypeFunction: {
2791 auto* return_type = _.FindDef(inst->word(6));
2792 // TODO: We need a spec discussion that we have to allow return and
2793 // parameter types of a DebugTypeFunction to have template parameter.
2794 if (return_type->opcode() != SpvOpTypeVoid) {
2795 auto validate_return = ValidateOperandDebugType(
2796 _, "Return Type", inst, 6, ext_inst_name, true);
2797 if (validate_return != SPV_SUCCESS) return validate_return;
2798 }
2799 for (uint32_t word_index = 7; word_index < num_words; ++word_index) {
2800 auto validate_param = ValidateOperandDebugType(
2801 _, "Parameter Types", inst, word_index, ext_inst_name, true);
2802 if (validate_param != SPV_SUCCESS) return validate_param;
2803 }
2804 break;
2805 }
2806 case OpenCLDebugInfo100DebugTypeEnum: {
2807 CHECK_OPERAND("Name", SpvOpString, 5);
2808 if (!DoesDebugInfoOperandMatchExpectation(
2809 _,
2810 [](OpenCLDebugInfo100Instructions dbg_inst) {
2811 return dbg_inst == OpenCLDebugInfo100DebugInfoNone;
2812 },
2813 inst, 6)) {
2814 auto validate_underlying_type = ValidateOperandDebugType(
2815 _, "Underlying Types", inst, 6, ext_inst_name, false);
2816 if (validate_underlying_type != SPV_SUCCESS)
2817 return validate_underlying_type;
2818 }
2819 CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7);
2820 auto validate_parent =
2821 ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name);
2822 if (validate_parent != SPV_SUCCESS) return validate_parent;
2823 CHECK_OPERAND("Size", SpvOpConstant, 11);
2824 auto* size = _.FindDef(inst->word(11));
2825 if (!_.IsIntScalarType(size->type_id()) || !size->word(3)) {
2826 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2827 << ext_inst_name() << ": expected operand Size is a "
2828 << "positive integer";
2829 }
2830 for (uint32_t word_index = 13; word_index + 1 < num_words;
2831 word_index += 2) {
2832 CHECK_OPERAND("Value", SpvOpConstant, word_index);
2833 CHECK_OPERAND("Name", SpvOpString, word_index + 1);
2834 }
2835 break;
2836 }
2837 case OpenCLDebugInfo100DebugTypeComposite: {
2838 CHECK_OPERAND("Name", SpvOpString, 5);
2839 CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7);
2840 auto validate_parent =
2841 ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name);
2842 if (validate_parent != SPV_SUCCESS) return validate_parent;
2843 CHECK_OPERAND("Linkage Name", SpvOpString, 11);
2844 if (!DoesDebugInfoOperandMatchExpectation(
2845 _,
2846 [](OpenCLDebugInfo100Instructions dbg_inst) {
2847 return dbg_inst == OpenCLDebugInfo100DebugInfoNone;
2848 },
2849 inst, 12)) {
2850 CHECK_OPERAND("Size", SpvOpConstant, 12);
2851 }
2852 for (uint32_t word_index = 14; word_index < num_words; ++word_index) {
2853 if (!DoesDebugInfoOperandMatchExpectation(
2854 _,
2855 [](OpenCLDebugInfo100Instructions dbg_inst) {
2856 return dbg_inst == OpenCLDebugInfo100DebugTypeMember ||
2857 dbg_inst == OpenCLDebugInfo100DebugFunction ||
2858 dbg_inst == OpenCLDebugInfo100DebugTypeInheritance;
2859 },
2860 inst, word_index)) {
2861 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2862 << ext_inst_name() << ": "
2863 << "expected operand Members "
2864 << "must be DebugTypeMember, DebugFunction, or "
2865 "DebugTypeInheritance";
2866 }
2867 }
2868 break;
2869 }
2870 case OpenCLDebugInfo100DebugTypeMember: {
2871 CHECK_OPERAND("Name", SpvOpString, 5);
2872 // TODO: We need a spec discussion that we have to allow member types
2873 // to have template parameter.
2874 auto validate_type =
2875 ValidateOperandDebugType(_, "Type", inst, 6, ext_inst_name, true);
2876 if (validate_type != SPV_SUCCESS) return validate_type;
2877 CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7);
2878 CHECK_DEBUG_OPERAND("Parent", OpenCLDebugInfo100DebugTypeComposite, 10);
2879 CHECK_OPERAND("Offset", SpvOpConstant, 11);
2880 CHECK_OPERAND("Size", SpvOpConstant, 12);
2881 if (num_words == 15) CHECK_OPERAND("Value", SpvOpConstant, 14);
2882 break;
2883 }
2884 case OpenCLDebugInfo100DebugTypeInheritance: {
2885 CHECK_DEBUG_OPERAND("Child", OpenCLDebugInfo100DebugTypeComposite, 5);
2886 auto* debug_inst = _.FindDef(inst->word(5));
2887 auto composite_type =
2888 OpenCLDebugInfo100DebugCompositeType(debug_inst->word(6));
2889 if (composite_type != OpenCLDebugInfo100Class &&
2890 composite_type != OpenCLDebugInfo100Structure) {
2891 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2892 << ext_inst_name() << ": "
2893 << "expected operand Child must be class or struct debug type";
2894 }
2895 CHECK_DEBUG_OPERAND("Parent", OpenCLDebugInfo100DebugTypeComposite, 6);
2896 debug_inst = _.FindDef(inst->word(6));
2897 composite_type =
2898 OpenCLDebugInfo100DebugCompositeType(debug_inst->word(6));
2899 if (composite_type != OpenCLDebugInfo100Class &&
2900 composite_type != OpenCLDebugInfo100Structure) {
2901 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2902 << ext_inst_name() << ": "
2903 << "expected operand Parent must be class or struct debug "
2904 "type";
2905 }
2906 CHECK_OPERAND("Offset", SpvOpConstant, 7);
2907 CHECK_OPERAND("Size", SpvOpConstant, 8);
2908 break;
2909 }
2910 case OpenCLDebugInfo100DebugFunction: {
2911 CHECK_OPERAND("Name", SpvOpString, 5);
2912 auto validate_type =
2913 ValidateOperandDebugType(_, "Type", inst, 6, ext_inst_name, false);
2914 if (validate_type != SPV_SUCCESS) return validate_type;
2915 CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7);
2916 auto validate_parent =
2917 ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name);
2918 if (validate_parent != SPV_SUCCESS) return validate_parent;
2919 CHECK_OPERAND("Linkage Name", SpvOpString, 11);
2920 if (!DoesDebugInfoOperandMatchExpectation(
2921 _,
2922 [](OpenCLDebugInfo100Instructions dbg_inst) {
2923 return dbg_inst == OpenCLDebugInfo100DebugInfoNone;
2924 },
2925 inst, 14)) {
2926 CHECK_OPERAND("Function", SpvOpFunction, 14);
2927 }
2928 if (num_words == 16) {
2929 CHECK_DEBUG_OPERAND("Declaration",
2930 OpenCLDebugInfo100DebugFunctionDeclaration, 15);
2931 }
2932 break;
2933 }
2934 case OpenCLDebugInfo100DebugFunctionDeclaration: {
2935 CHECK_OPERAND("Name", SpvOpString, 5);
2936 auto validate_type =
2937 ValidateOperandDebugType(_, "Type", inst, 6, ext_inst_name, false);
2938 if (validate_type != SPV_SUCCESS) return validate_type;
2939 CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7);
2940 auto validate_parent =
2941 ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name);
2942 if (validate_parent != SPV_SUCCESS) return validate_parent;
2943 CHECK_OPERAND("Linkage Name", SpvOpString, 11);
2944 break;
2945 }
2946 case OpenCLDebugInfo100DebugLexicalBlock: {
2947 CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 5);
2948 auto validate_parent =
2949 ValidateOperandLexicalScope(_, "Parent", inst, 8, ext_inst_name);
2950 if (validate_parent != SPV_SUCCESS) return validate_parent;
2951 if (num_words == 10) CHECK_OPERAND("Name", SpvOpString, 9);
2952 break;
2953 }
2954 case OpenCLDebugInfo100DebugScope: {
2955 auto validate_scope =
2956 ValidateOperandLexicalScope(_, "Scope", inst, 5, ext_inst_name);
2957 if (validate_scope != SPV_SUCCESS) return validate_scope;
2958 if (num_words == 7) {
2959 CHECK_DEBUG_OPERAND("Inlined At", OpenCLDebugInfo100DebugInlinedAt,
2960 6);
2961 }
2962 break;
2963 }
2964 case OpenCLDebugInfo100DebugLocalVariable: {
2965 CHECK_OPERAND("Name", SpvOpString, 5);
2966 // TODO: We need a spec discussion that we have to allow local variable
2967 // types to have template parameter.
2968 auto validate_type =
2969 ValidateOperandDebugType(_, "Type", inst, 6, ext_inst_name, true);
2970 if (validate_type != SPV_SUCCESS) return validate_type;
2971 CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7);
2972 auto validate_parent =
2973 ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name);
2974 if (validate_parent != SPV_SUCCESS) return validate_parent;
2975 break;
2976 }
2977 case OpenCLDebugInfo100DebugDeclare: {
2978 CHECK_DEBUG_OPERAND("Local Variable",
2979 OpenCLDebugInfo100DebugLocalVariable, 5);
2980 auto* operand = _.FindDef(inst->word(6));
2981 if (operand->opcode() != SpvOpVariable &&
2982 operand->opcode() != SpvOpFunctionParameter) {
2983 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2984 << ext_inst_name() << ": "
2985 << "expected operand Variable must be a result id of "
2986 "OpVariable or OpFunctionParameter";
2987 }
2988
2989 CHECK_DEBUG_OPERAND("Expression", OpenCLDebugInfo100DebugExpression, 7);
2990 break;
2991 }
2992 case OpenCLDebugInfo100DebugExpression: {
2993 for (uint32_t word_index = 5; word_index < num_words; ++word_index) {
2994 CHECK_DEBUG_OPERAND("Operation", OpenCLDebugInfo100DebugOperation,
2995 word_index);
2996 }
2997 break;
2998 }
2999 case OpenCLDebugInfo100DebugTypeTemplate: {
3000 if (!DoesDebugInfoOperandMatchExpectation(
3001 _,
3002 [](OpenCLDebugInfo100Instructions dbg_inst) {
3003 return dbg_inst == OpenCLDebugInfo100DebugTypeComposite ||
3004 dbg_inst == OpenCLDebugInfo100DebugFunction;
3005 },
3006 inst, 5)) {
3007 return _.diag(SPV_ERROR_INVALID_DATA, inst)
3008 << ext_inst_name() << ": "
3009 << "expected operand Target must be DebugTypeComposite "
3010 << "or DebugFunction";
3011 }
3012 for (uint32_t word_index = 6; word_index < num_words; ++word_index) {
3013 if (!DoesDebugInfoOperandMatchExpectation(
3014 _,
3015 [](OpenCLDebugInfo100Instructions dbg_inst) {
3016 return dbg_inst ==
3017 OpenCLDebugInfo100DebugTypeTemplateParameter ||
3018 dbg_inst ==
3019 OpenCLDebugInfo100DebugTypeTemplateTemplateParameter;
3020 },
3021 inst, word_index)) {
3022 return _.diag(SPV_ERROR_INVALID_DATA, inst)
3023 << ext_inst_name() << ": "
3024 << "expected operand Parameters must be "
3025 << "DebugTypeTemplateParameter or "
3026 << "DebugTypeTemplateTemplateParameter";
3027 }
3028 }
3029 break;
3030 }
3031 case OpenCLDebugInfo100DebugTypeTemplateParameter: {
3032 CHECK_OPERAND("Name", SpvOpString, 5);
3033 auto validate_actual_type = ValidateOperandDebugType(
3034 _, "Actual Type", inst, 6, ext_inst_name, false);
3035 if (validate_actual_type != SPV_SUCCESS) return validate_actual_type;
3036 if (!DoesDebugInfoOperandMatchExpectation(
3037 _,
3038 [](OpenCLDebugInfo100Instructions dbg_inst) {
3039 return dbg_inst == OpenCLDebugInfo100DebugInfoNone;
3040 },
3041 inst, 7)) {
3042 CHECK_OPERAND("Value", SpvOpConstant, 7);
3043 }
3044 CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 8);
3045 break;
3046 }
3047 case OpenCLDebugInfo100DebugGlobalVariable: {
3048 CHECK_OPERAND("Name", SpvOpString, 5);
3049 auto validate_type =
3050 ValidateOperandDebugType(_, "Type", inst, 6, ext_inst_name, false);
3051 if (validate_type != SPV_SUCCESS) return validate_type;
3052 CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7);
3053 auto validate_scope =
3054 ValidateOperandLexicalScope(_, "Scope", inst, 10, ext_inst_name);
3055 if (validate_scope != SPV_SUCCESS) return validate_scope;
3056 CHECK_OPERAND("Linkage Name", SpvOpString, 11);
3057 if (!DoesDebugInfoOperandMatchExpectation(
3058 _,
3059 [](OpenCLDebugInfo100Instructions dbg_inst) {
3060 return dbg_inst == OpenCLDebugInfo100DebugInfoNone;
3061 },
3062 inst, 12)) {
3063 auto* operand = _.FindDef(inst->word(12));
3064 if (operand->opcode() != SpvOpVariable &&
3065 operand->opcode() != SpvOpConstant) {
3066 return _.diag(SPV_ERROR_INVALID_DATA, inst)
3067 << ext_inst_name() << ": "
3068 << "expected operand Variable must be a result id of "
3069 "OpVariable or OpConstant or DebugInfoNone";
3070 }
3071 }
3072 if (num_words == 15) {
3073 CHECK_DEBUG_OPERAND("Static Member Declaration",
3074 OpenCLDebugInfo100DebugTypeMember, 14);
3075 }
3076 break;
3077 }
3078 case OpenCLDebugInfo100DebugInlinedAt: {
3079 auto validate_scope =
3080 ValidateOperandLexicalScope(_, "Scope", inst, 6, ext_inst_name);
3081 if (validate_scope != SPV_SUCCESS) return validate_scope;
3082 if (num_words == 8) {
3083 CHECK_DEBUG_OPERAND("Inlined", OpenCLDebugInfo100DebugInlinedAt, 7);
3084 }
3085 break;
3086 }
3087 case OpenCLDebugInfo100DebugValue: {
3088 CHECK_DEBUG_OPERAND("Local Variable",
3089 OpenCLDebugInfo100DebugLocalVariable, 5);
3090 CHECK_DEBUG_OPERAND("Expression", OpenCLDebugInfo100DebugExpression, 7);
3091
3092 for (uint32_t word_index = 8; word_index < num_words; ++word_index) {
3093 // TODO: The following code simply checks if it is a const int scalar
3094 // or a DebugLocalVariable or DebugGlobalVariable, but we have to
3095 // check it using the same validation for Indexes of OpAccessChain.
3096 if (!IsConstWithIntScalarType(_, inst, word_index) &&
3097 !IsDebugVariableWithIntScalarType(_, inst, word_index)) {
3098 return _.diag(SPV_ERROR_INVALID_DATA, inst)
3099 << ext_inst_name() << ": expected operand Indexes is "
3100 << "OpConstant, DebugGlobalVariable, or "
3101 << "type is OpConstant with an integer scalar type";
3102 }
3103 }
3104 break;
3105 }
3106
3107 // TODO: Add validation rules for remaining cases as well.
3108 case OpenCLDebugInfo100DebugTypePtrToMember:
3109 case OpenCLDebugInfo100DebugTypeTemplateTemplateParameter:
3110 case OpenCLDebugInfo100DebugTypeTemplateParameterPack:
3111 case OpenCLDebugInfo100DebugLexicalBlockDiscriminator:
3112 case OpenCLDebugInfo100DebugInlinedVariable:
3113 case OpenCLDebugInfo100DebugMacroDef:
3114 case OpenCLDebugInfo100DebugMacroUndef:
3115 case OpenCLDebugInfo100DebugImportedEntity:
3116 break;
3117 case OpenCLDebugInfo100InstructionsMax:
3118 assert(0);
3119 break;
3120 }
3121 } else if (ext_inst_type == SPV_EXT_INST_TYPE_NONSEMANTIC_CLSPVREFLECTION) {
3122 auto import_inst = _.FindDef(inst->GetOperandAs<uint32_t>(2));
3123 const std::string name(reinterpret_cast<const char*>(
3124 import_inst->words().data() + import_inst->operands()[1].offset));
3125 const std::string reflection = "NonSemantic.ClspvReflection.";
3126 char* end_ptr;
3127 auto version_string = name.substr(reflection.size());
3128 if (version_string.empty()) {
3129 return _.diag(SPV_ERROR_INVALID_DATA, import_inst)
3130 << "Missing NonSemantic.ClspvReflection import version";
3131 }
3132 uint32_t version = static_cast<uint32_t>(
3133 std::strtoul(version_string.c_str(), &end_ptr, 10));
3134 if (end_ptr && *end_ptr != '\0') {
3135 return _.diag(SPV_ERROR_INVALID_DATA, import_inst)
3136 << "NonSemantic.ClspvReflection import does not encode the "
3137 "version correctly";
3138 }
3139 if (version == 0 || version > NonSemanticClspvReflectionRevision) {
3140 return _.diag(SPV_ERROR_INVALID_DATA, import_inst)
3141 << "Unknown NonSemantic.ClspvReflection import version";
3142 }
3143
3144 return ValidateClspvReflectionInstruction(_, inst, version);
3145 }
3146
3147 return SPV_SUCCESS;
3148 }
3149
ExtensionPass(ValidationState_t & _,const Instruction * inst)3150 spv_result_t ExtensionPass(ValidationState_t& _, const Instruction* inst) {
3151 const SpvOp opcode = inst->opcode();
3152 if (opcode == SpvOpExtension) return ValidateExtension(_, inst);
3153 if (opcode == SpvOpExtInstImport) return ValidateExtInstImport(_, inst);
3154 if (opcode == SpvOpExtInst) return ValidateExtInst(_, inst);
3155
3156 return SPV_SUCCESS;
3157 }
3158
3159 } // namespace val
3160 } // namespace spvtools
3161