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