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