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