Roll external/abseil_cpp/ 8f739d18b..917bfee46 (2 commits) (#5887)
[KhronosGroup/SPIRV-Tools.git] / source / val / validate_extensions.cpp
blob74974a4fef0152edd928442ce257efeb83227b8c
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.
15 // Validates correctness of extension SPIR-V instructions.
16 #include <cstdlib>
17 #include <sstream>
18 #include <string>
19 #include <vector>
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"
34 namespace spvtools {
35 namespace val {
36 namespace {
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");
46 std::ostringstream ss;
47 ss << desc->name;
49 return ss.str();
52 uint32_t GetSizeTBitWidth(const ValidationState_t& _) {
53 if (_.addressing_model() == spv::AddressingModel::Physical32) return 32;
55 if (_.addressing_model() == spv::AddressingModel::Physical64) return 64;
57 return 0;
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;
67 if (must_len32 && type->GetOperandAs<uint32_t>(1) != 32) {
68 return false;
71 return !must_unsigned || type->GetOperandAs<uint32_t>(2) == 0;
74 bool IsUint32Constant(ValidationState_t& _, uint32_t id) {
75 auto inst = _.FindDef(id);
76 if (!inst || inst->opcode() != spv::Op::OpConstant) {
77 return false;
80 return IsIntScalar(_, inst->type_id(), true, true);
83 uint32_t GetUint32Constant(ValidationState_t& _, uint32_t id) {
84 auto inst = _.FindDef(id);
85 return inst->word(3);
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|.
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";
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;
108 return SPV_SUCCESS;
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.
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";
124 return SPV_SUCCESS;
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)
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; \
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.
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 (!spvIsExtendedInstruction(debug_inst->opcode()) ||
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;
157 return true;
160 // Overload for NonSemanticShaderDebugInfo100Instructions.
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 (!spvIsExtendedInstruction(debug_inst->opcode()) ||
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;
175 return true;
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|.
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;
189 if (DoesDebugInfoOperandMatchExpectation(_, expectation, inst, word_index))
190 return SPV_SUCCESS;
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";
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;
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)
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.
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);
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.
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;
237 if (DoesDebugInfoOperandMatchExpectation(_, expectation, inst, word_index))
238 return SPV_SUCCESS;
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";
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.
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;
261 if (DoesDebugInfoOperandMatchExpectation(_, expectation, inst, word_index))
262 return SPV_SUCCESS;
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;
273 return CommonDebugInfoDebugTypeBasic <= dbg_inst &&
274 dbg_inst <= CommonDebugInfoDebugTypeTemplate;
276 if (DoesDebugInfoOperandMatchExpectation(_, expectation, inst, word_index))
277 return SPV_SUCCESS;
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";
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";
296 bool found_kernel = false;
297 for (auto entry_point : _.entry_points()) {
298 if (entry_point == kernel_id) {
299 found_kernel = true;
300 break;
303 if (!found_kernel) {
304 return _.diag(SPV_ERROR_INVALID_ID, inst)
305 << inst_name << " does not reference an entry-point";
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";
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";
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";
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;
333 if (!found) {
334 return _.diag(SPV_ERROR_INVALID_ID, inst)
335 << "Name must match an entry-point for Kernel";
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";
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";
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";
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";
369 return SPV_SUCCESS;
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";
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";
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";
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";
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";
406 return SPV_SUCCESS;
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 || !spvIsExtendedInstruction(decl->opcode())) {
413 return _.diag(SPV_ERROR_INVALID_ID, inst)
414 << "Kernel must be a Kernel extended instruction";
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";
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";
429 return SPV_SUCCESS;
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 || !spvIsExtendedInstruction(info->opcode())) {
436 return _.diag(SPV_ERROR_INVALID_ID, inst)
437 << "ArgInfo must be an ArgumentInfo extended instruction";
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";
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";
451 return SPV_SUCCESS;
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;
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";
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";
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";
476 if (num_operands == 9) {
477 if (auto error = ValidateArgInfo(_, inst, 8)) {
478 return error;
482 return SPV_SUCCESS;
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;
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";
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";
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";
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";
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";
517 if (num_operands == 11) {
518 if (auto error = ValidateArgInfo(_, inst, 10)) {
519 return error;
523 return SPV_SUCCESS;
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;
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";
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";
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";
548 if (num_operands == 9) {
549 if (auto error = ValidateArgInfo(_, inst, 8)) {
550 return error;
554 return SPV_SUCCESS;
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;
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";
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";
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";
579 if (num_operands == 9) {
580 if (auto error = ValidateArgInfo(_, inst, 8)) {
581 return error;
585 return SPV_SUCCESS;
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";
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";
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";
605 return SPV_SUCCESS;
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";
615 return SPV_SUCCESS;
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";
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";
630 return SPV_SUCCESS;
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";
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";
645 if (_.GetIdOpcode(inst->GetOperandAs<uint32_t>(6)) != spv::Op::OpString) {
646 return _.diag(SPV_ERROR_INVALID_ID, inst) << "Data must be an OpString";
649 return SPV_SUCCESS;
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";
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";
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";
669 return SPV_SUCCESS;
672 spv_result_t ValidateClspvReflectionPropertyRequiredWorkgroupSize(
673 ValidationState_t& _, const Instruction* inst) {
674 if (auto error = ValidateKernelDecl(_, inst)) {
675 return error;
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";
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";
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";
693 return SPV_SUCCESS;
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";
704 return SPV_SUCCESS;
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";
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";
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";
724 return SPV_SUCCESS;
727 spv_result_t ValidateClspvReflectionImageMetadataPushConstant(
728 ValidationState_t& _, const Instruction* inst) {
729 if (auto error = ValidateKernelDecl(_, inst)) {
730 return error;
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";
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";
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";
748 return SPV_SUCCESS;
751 spv_result_t ValidateClspvReflectionImageMetadataUniform(
752 ValidationState_t& _, const Instruction* inst) {
753 if (auto error = ValidateKernelDecl(_, inst)) {
754 return error;
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";
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";
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";
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";
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";
782 return SPV_SUCCESS;
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";
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";
797 if (_.GetIdOpcode(inst->GetOperandAs<uint32_t>(6)) != spv::Op::OpString) {
798 return _.diag(SPV_ERROR_INVALID_ID, inst) << "Data must be an OpString";
801 return SPV_SUCCESS;
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";
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";
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";
823 return SPV_SUCCESS;
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";
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";
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";
843 return SPV_SUCCESS;
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";
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";
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";
863 return SPV_SUCCESS;
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";
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;
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;
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;
1002 return SPV_SUCCESS;
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;
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;
1020 return false;
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;
1049 return false;
1052 } // anonymous namespace
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.";
1066 return SPV_SUCCESS;
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.";
1082 return SPV_SUCCESS;
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());
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());
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");
1102 auto* import_inst = _.FindDef(ext_inst_set);
1103 assert(import_inst);
1105 std::ostringstream ss;
1106 ss << import_inst->GetOperandAs<std::string>(1);
1107 ss << " ";
1108 ss << desc->name;
1110 return ss.str();
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";
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";
1155 break;
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";
1175 const uint32_t result_type_bit_width = _.GetBitWidth(result_type);
1176 const uint32_t result_type_dimension = _.GetDimension(result_type);
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";
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";
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";
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";
1211 break;
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";
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";
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";
1259 break;
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";
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";
1282 break;
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";
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";
1304 break;
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";
1314 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
1315 const uint32_t i_type = _.GetOperandTypeId(inst, 5);
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";
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";
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";
1337 break;
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";
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";
1359 break;
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";
1369 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
1370 const uint32_t exp_type = _.GetOperandTypeId(inst, 5);
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";
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";
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";
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";
1409 break;
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";
1419 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
1420 const uint32_t exp_type = _.GetOperandTypeId(inst, 5);
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";
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";
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";
1442 break;
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";
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";
1476 break;
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";
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";
1495 break;
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";
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";
1515 break;
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";
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";
1533 break;
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";
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";
1553 break;
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";
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";
1574 break;
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";
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";
1593 break;
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";
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";
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";
1616 break;
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";
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";
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";
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";
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";
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";
1660 break;
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";
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";
1676 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
1677 const uint32_t y_type = _.GetOperandTypeId(inst, 5);
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";
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";
1690 break;
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";
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);
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";
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";
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";
1721 break;
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";
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";
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);
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";
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";
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";
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";
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";
1793 _.function(inst->function()->id())
1794 ->RegisterExecutionModelLimitation(
1795 spv::ExecutionModel::Fragment,
1796 ext_inst_name() +
1797 std::string(" requires Fragment execution model"));
1798 break;
1801 case GLSLstd450IMix: {
1802 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1803 << "Extended instruction GLSLstd450IMix is not supported";
1806 case GLSLstd450Bad: {
1807 return _.diag(SPV_ERROR_INVALID_DATA, inst)
1808 << "Encountered extended instruction GLSLstd450Bad";
1811 case GLSLstd450Count: {
1812 assert(0);
1813 break;
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";
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";
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";
1937 break;
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";
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";
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";
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";
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";
1983 if (!_.ContainsUntypedPointer(p_type) && 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";
1989 break;
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";
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";
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";
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";
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";
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";
2045 if ((!_.IsIntScalarOrVectorType(p_data_type) ||
2046 _.GetBitWidth(p_data_type) != 32) &&
2047 !_.ContainsUntypedPointer(p_type)) {
2048 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2049 << ext_inst_name() << ": "
2050 << "expected data type of the pointer to be a 32-bit int "
2051 "scalar or vector type";
2054 if (!_.ContainsUntypedPointer(p_type) &&
2055 _.GetDimension(p_data_type) != num_components) {
2056 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2057 << ext_inst_name() << ": "
2058 << "expected data type of the pointer to have the same number "
2059 "of components as Result Type";
2061 break;
2064 case OpenCLLIB::Ilogb: {
2065 if (!_.IsIntScalarOrVectorType(result_type) ||
2066 _.GetBitWidth(result_type) != 32) {
2067 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2068 << ext_inst_name() << ": "
2069 << "expected Result Type to be a 32-bit int scalar or vector "
2070 "type";
2073 const uint32_t num_components = _.GetDimension(result_type);
2074 if (num_components > 4 && num_components != 8 && num_components != 16) {
2075 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2076 << ext_inst_name() << ": "
2077 << "expected Result Type to be a scalar or a vector with 2, "
2078 "3, 4, 8 or 16 components";
2081 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
2082 if (!_.IsFloatScalarOrVectorType(x_type)) {
2083 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2084 << ext_inst_name() << ": "
2085 << "expected operand X to be a float scalar or vector";
2088 if (_.GetDimension(x_type) != num_components) {
2089 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2090 << ext_inst_name() << ": "
2091 << "expected operand X to have the same number of components "
2092 "as Result Type";
2094 break;
2097 case OpenCLLIB::Ldexp:
2098 case OpenCLLIB::Pown:
2099 case OpenCLLIB::Rootn: {
2100 if (!_.IsFloatScalarOrVectorType(result_type)) {
2101 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2102 << ext_inst_name() << ": "
2103 << "expected Result Type to be a float scalar or vector type";
2106 const uint32_t num_components = _.GetDimension(result_type);
2107 if (num_components > 4 && num_components != 8 && num_components != 16) {
2108 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2109 << ext_inst_name() << ": "
2110 << "expected Result Type to be a scalar or a vector with 2, "
2111 "3, 4, 8 or 16 components";
2114 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
2115 if (result_type != x_type) {
2116 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2117 << ext_inst_name() << ": "
2118 << "expected type of operand X to be equal to Result Type";
2121 const uint32_t exp_type = _.GetOperandTypeId(inst, 5);
2122 if (!_.IsIntScalarOrVectorType(exp_type) ||
2123 _.GetBitWidth(exp_type) != 32) {
2124 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2125 << ext_inst_name() << ": "
2126 << "expected the exponent to be a 32-bit int scalar or vector";
2129 if (_.GetDimension(exp_type) != num_components) {
2130 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2131 << ext_inst_name() << ": "
2132 << "expected the exponent to have the same number of "
2133 "components as Result Type";
2135 break;
2138 case OpenCLLIB::Nan: {
2139 if (!_.IsFloatScalarOrVectorType(result_type)) {
2140 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2141 << ext_inst_name() << ": "
2142 << "expected Result Type to be a float scalar or vector type";
2145 const uint32_t num_components = _.GetDimension(result_type);
2146 if (num_components > 4 && num_components != 8 && num_components != 16) {
2147 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2148 << ext_inst_name() << ": "
2149 << "expected Result Type to be a scalar or a vector with 2, "
2150 "3, 4, 8 or 16 components";
2153 const uint32_t nancode_type = _.GetOperandTypeId(inst, 4);
2154 if (!_.IsIntScalarOrVectorType(nancode_type)) {
2155 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2156 << ext_inst_name() << ": "
2157 << "expected Nancode to be an int scalar or vector type";
2160 if (_.GetDimension(nancode_type) != num_components) {
2161 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2162 << ext_inst_name() << ": "
2163 << "expected Nancode to have the same number of components as "
2164 "Result Type";
2167 if (_.GetBitWidth(result_type) != _.GetBitWidth(nancode_type)) {
2168 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2169 << ext_inst_name() << ": "
2170 << "expected Nancode to have the same bit width as Result "
2171 "Type";
2173 break;
2176 case OpenCLLIB::SAbs:
2177 case OpenCLLIB::SAbs_diff:
2178 case OpenCLLIB::SAdd_sat:
2179 case OpenCLLIB::UAdd_sat:
2180 case OpenCLLIB::SHadd:
2181 case OpenCLLIB::UHadd:
2182 case OpenCLLIB::SRhadd:
2183 case OpenCLLIB::URhadd:
2184 case OpenCLLIB::SClamp:
2185 case OpenCLLIB::UClamp:
2186 case OpenCLLIB::Clz:
2187 case OpenCLLIB::Ctz:
2188 case OpenCLLIB::SMad_hi:
2189 case OpenCLLIB::UMad_sat:
2190 case OpenCLLIB::SMad_sat:
2191 case OpenCLLIB::SMax:
2192 case OpenCLLIB::UMax:
2193 case OpenCLLIB::SMin:
2194 case OpenCLLIB::UMin:
2195 case OpenCLLIB::SMul_hi:
2196 case OpenCLLIB::Rotate:
2197 case OpenCLLIB::SSub_sat:
2198 case OpenCLLIB::USub_sat:
2199 case OpenCLLIB::Popcount:
2200 case OpenCLLIB::UAbs:
2201 case OpenCLLIB::UAbs_diff:
2202 case OpenCLLIB::UMul_hi:
2203 case OpenCLLIB::UMad_hi: {
2204 if (!_.IsIntScalarOrVectorType(result_type)) {
2205 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2206 << ext_inst_name() << ": "
2207 << "expected Result Type to be an int scalar or vector type";
2210 const uint32_t num_components = _.GetDimension(result_type);
2211 if (num_components > 4 && num_components != 8 && num_components != 16) {
2212 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2213 << ext_inst_name() << ": "
2214 << "expected Result Type to be a scalar or a vector with 2, "
2215 "3, 4, 8 or 16 components";
2218 for (uint32_t operand_index = 4; operand_index < num_operands;
2219 ++operand_index) {
2220 const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
2221 if (result_type != operand_type) {
2222 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2223 << ext_inst_name() << ": "
2224 << "expected types of all operands to be equal to Result "
2225 "Type";
2228 break;
2231 case OpenCLLIB::U_Upsample:
2232 case OpenCLLIB::S_Upsample: {
2233 if (!_.IsIntScalarOrVectorType(result_type)) {
2234 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2235 << ext_inst_name() << ": "
2236 << "expected Result Type to be an int scalar or vector "
2237 "type";
2240 const uint32_t result_num_components = _.GetDimension(result_type);
2241 if (result_num_components > 4 && result_num_components != 8 &&
2242 result_num_components != 16) {
2243 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2244 << ext_inst_name() << ": "
2245 << "expected Result Type to be a scalar or a vector with 2, "
2246 "3, 4, 8 or 16 components";
2249 const uint32_t result_bit_width = _.GetBitWidth(result_type);
2250 if (result_bit_width != 16 && result_bit_width != 32 &&
2251 result_bit_width != 64) {
2252 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2253 << ext_inst_name() << ": "
2254 << "expected bit width of Result Type components to be 16, 32 "
2255 "or 64";
2258 const uint32_t hi_type = _.GetOperandTypeId(inst, 4);
2259 const uint32_t lo_type = _.GetOperandTypeId(inst, 5);
2261 if (hi_type != lo_type) {
2262 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2263 << ext_inst_name() << ": "
2264 << "expected Hi and Lo operands to have the same type";
2267 if (result_num_components != _.GetDimension(hi_type)) {
2268 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2269 << ext_inst_name() << ": "
2270 << "expected Hi and Lo operands to have the same number of "
2271 "components as Result Type";
2274 if (result_bit_width != 2 * _.GetBitWidth(hi_type)) {
2275 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2276 << ext_inst_name() << ": "
2277 << "expected bit width of components of Hi and Lo operands to "
2278 "be half of the bit width of components of Result Type";
2280 break;
2283 case OpenCLLIB::SMad24:
2284 case OpenCLLIB::UMad24:
2285 case OpenCLLIB::SMul24:
2286 case OpenCLLIB::UMul24: {
2287 if (!_.IsIntScalarOrVectorType(result_type) ||
2288 _.GetBitWidth(result_type) != 32) {
2289 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2290 << ext_inst_name() << ": "
2291 << "expected Result Type to be a 32-bit int scalar or vector "
2292 "type";
2295 const uint32_t num_components = _.GetDimension(result_type);
2296 if (num_components > 4 && num_components != 8 && num_components != 16) {
2297 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2298 << ext_inst_name() << ": "
2299 << "expected Result Type to be a scalar or a vector with 2, "
2300 "3, 4, 8 or 16 components";
2303 for (uint32_t operand_index = 4; operand_index < num_operands;
2304 ++operand_index) {
2305 const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
2306 if (result_type != operand_type) {
2307 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2308 << ext_inst_name() << ": "
2309 << "expected types of all operands to be equal to Result "
2310 "Type";
2313 break;
2316 case OpenCLLIB::Cross: {
2317 if (!_.IsFloatVectorType(result_type)) {
2318 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2319 << ext_inst_name() << ": "
2320 << "expected Result Type to be a float vector type";
2323 const uint32_t num_components = _.GetDimension(result_type);
2324 if (num_components != 3 && num_components != 4) {
2325 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2326 << ext_inst_name() << ": "
2327 << "expected Result Type to have 3 or 4 components";
2330 const uint32_t x_type = _.GetOperandTypeId(inst, 4);
2331 const uint32_t y_type = _.GetOperandTypeId(inst, 5);
2333 if (x_type != result_type) {
2334 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2335 << ext_inst_name() << ": "
2336 << "expected operand X type to be equal to Result Type";
2339 if (y_type != result_type) {
2340 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2341 << ext_inst_name() << ": "
2342 << "expected operand Y type to be equal to Result Type";
2344 break;
2347 case OpenCLLIB::Distance:
2348 case OpenCLLIB::Fast_distance: {
2349 if (!_.IsFloatScalarType(result_type)) {
2350 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2351 << ext_inst_name() << ": "
2352 << "expected Result Type to be a float scalar type";
2355 const uint32_t p0_type = _.GetOperandTypeId(inst, 4);
2356 if (!_.IsFloatScalarOrVectorType(p0_type)) {
2357 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2358 << ext_inst_name() << ": "
2359 << "expected operand P0 to be of float scalar or vector type";
2362 const uint32_t num_components = _.GetDimension(p0_type);
2363 if (num_components > 4) {
2364 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2365 << ext_inst_name() << ": "
2366 << "expected operand P0 to have no more than 4 components";
2369 if (result_type != _.GetComponentType(p0_type)) {
2370 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2371 << ext_inst_name() << ": "
2372 << "expected operand P0 component type to be equal to "
2373 << "Result Type";
2376 const uint32_t p1_type = _.GetOperandTypeId(inst, 5);
2377 if (p0_type != p1_type) {
2378 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2379 << ext_inst_name() << ": "
2380 << "expected operands P0 and P1 to be of the same type";
2382 break;
2385 case OpenCLLIB::Length:
2386 case OpenCLLIB::Fast_length: {
2387 if (!_.IsFloatScalarType(result_type)) {
2388 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2389 << ext_inst_name() << ": "
2390 << "expected Result Type to be a float scalar type";
2393 const uint32_t p_type = _.GetOperandTypeId(inst, 4);
2394 if (!_.IsFloatScalarOrVectorType(p_type)) {
2395 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2396 << ext_inst_name() << ": "
2397 << "expected operand P to be a float scalar or vector";
2400 const uint32_t num_components = _.GetDimension(p_type);
2401 if (num_components > 4) {
2402 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2403 << ext_inst_name() << ": "
2404 << "expected operand P to have no more than 4 components";
2407 if (result_type != _.GetComponentType(p_type)) {
2408 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2409 << ext_inst_name() << ": "
2410 << "expected operand P component type to be equal to Result "
2411 "Type";
2413 break;
2416 case OpenCLLIB::Normalize:
2417 case OpenCLLIB::Fast_normalize: {
2418 if (!_.IsFloatScalarOrVectorType(result_type)) {
2419 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2420 << ext_inst_name() << ": "
2421 << "expected Result Type to be a float scalar or vector type";
2424 const uint32_t num_components = _.GetDimension(result_type);
2425 if (num_components > 4) {
2426 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2427 << ext_inst_name() << ": "
2428 << "expected Result Type to have no more than 4 components";
2431 const uint32_t p_type = _.GetOperandTypeId(inst, 4);
2432 if (p_type != result_type) {
2433 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2434 << ext_inst_name() << ": "
2435 << "expected operand P type to be equal to Result Type";
2437 break;
2440 case OpenCLLIB::Bitselect: {
2441 if (!_.IsFloatScalarOrVectorType(result_type) &&
2442 !_.IsIntScalarOrVectorType(result_type)) {
2443 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2444 << ext_inst_name() << ": "
2445 << "expected Result Type to be an int or float scalar or "
2446 "vector type";
2449 const uint32_t num_components = _.GetDimension(result_type);
2450 if (num_components > 4 && num_components != 8 && num_components != 16) {
2451 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2452 << ext_inst_name() << ": "
2453 << "expected Result Type to be a scalar or a vector with 2, "
2454 "3, 4, 8 or 16 components";
2457 for (uint32_t operand_index = 4; operand_index < num_operands;
2458 ++operand_index) {
2459 const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
2460 if (result_type != operand_type) {
2461 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2462 << ext_inst_name() << ": "
2463 << "expected types of all operands to be equal to Result "
2464 "Type";
2467 break;
2470 case OpenCLLIB::Select: {
2471 if (!_.IsFloatScalarOrVectorType(result_type) &&
2472 !_.IsIntScalarOrVectorType(result_type)) {
2473 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2474 << ext_inst_name() << ": "
2475 << "expected Result Type to be an int or float scalar or "
2476 "vector type";
2479 const uint32_t num_components = _.GetDimension(result_type);
2480 if (num_components > 4 && num_components != 8 && num_components != 16) {
2481 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2482 << ext_inst_name() << ": "
2483 << "expected Result Type to be a scalar or a vector with 2, "
2484 "3, 4, 8 or 16 components";
2487 const uint32_t a_type = _.GetOperandTypeId(inst, 4);
2488 const uint32_t b_type = _.GetOperandTypeId(inst, 5);
2489 const uint32_t c_type = _.GetOperandTypeId(inst, 6);
2491 if (result_type != a_type) {
2492 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2493 << ext_inst_name() << ": "
2494 << "expected operand A type to be equal to Result Type";
2497 if (result_type != b_type) {
2498 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2499 << ext_inst_name() << ": "
2500 << "expected operand B type to be equal to Result Type";
2503 if (!_.IsIntScalarOrVectorType(c_type)) {
2504 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2505 << ext_inst_name() << ": "
2506 << "expected operand C to be an int scalar or vector";
2509 if (num_components != _.GetDimension(c_type)) {
2510 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2511 << ext_inst_name() << ": "
2512 << "expected operand C to have the same number of components "
2513 "as Result Type";
2516 if (_.GetBitWidth(result_type) != _.GetBitWidth(c_type)) {
2517 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2518 << ext_inst_name() << ": "
2519 << "expected operand C to have the same bit width as Result "
2520 "Type";
2522 break;
2525 case OpenCLLIB::Vloadn: {
2526 if (!_.IsFloatVectorType(result_type) &&
2527 !_.IsIntVectorType(result_type)) {
2528 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2529 << ext_inst_name() << ": "
2530 << "expected Result Type to be an int or float vector type";
2533 const uint32_t num_components = _.GetDimension(result_type);
2534 if (num_components > 4 && num_components != 8 && num_components != 16) {
2535 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2536 << ext_inst_name() << ": "
2537 << "expected Result Type to have 2, 3, 4, 8 or 16 components";
2540 const uint32_t offset_type = _.GetOperandTypeId(inst, 4);
2541 const uint32_t p_type = _.GetOperandTypeId(inst, 5);
2543 const uint32_t size_t_bit_width = GetSizeTBitWidth(_);
2544 if (!size_t_bit_width) {
2545 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2546 << ext_inst_name()
2547 << " can only be used with physical addressing models";
2550 if (!_.IsIntScalarType(offset_type) ||
2551 _.GetBitWidth(offset_type) != size_t_bit_width) {
2552 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2553 << ext_inst_name() << ": "
2554 << "expected operand Offset to be of type size_t ("
2555 << size_t_bit_width
2556 << "-bit integer for the addressing model used in the module)";
2559 spv::StorageClass p_storage_class;
2560 uint32_t p_data_type = 0;
2561 if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
2562 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2563 << ext_inst_name() << ": "
2564 << "expected operand P to be a pointer";
2567 if (p_storage_class != spv::StorageClass::UniformConstant &&
2568 p_storage_class != spv::StorageClass::Generic &&
2569 p_storage_class != spv::StorageClass::CrossWorkgroup &&
2570 p_storage_class != spv::StorageClass::Workgroup &&
2571 p_storage_class != spv::StorageClass::Function) {
2572 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2573 << ext_inst_name() << ": "
2574 << "expected operand P storage class to be UniformConstant, "
2575 "Generic, CrossWorkgroup, Workgroup or Function";
2578 if (_.GetComponentType(result_type) != p_data_type) {
2579 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2580 << ext_inst_name() << ": "
2581 << "expected operand P data type to be equal to component "
2582 "type of Result Type";
2585 const uint32_t n_value = inst->word(7);
2586 if (num_components != n_value) {
2587 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2588 << ext_inst_name() << ": "
2589 << "expected literal N to be equal to the number of "
2590 "components of Result Type";
2592 break;
2595 case OpenCLLIB::Vstoren: {
2596 if (_.GetIdOpcode(result_type) != spv::Op::OpTypeVoid) {
2597 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2598 << ext_inst_name() << ": expected Result Type to be void";
2601 const uint32_t data_type = _.GetOperandTypeId(inst, 4);
2602 const uint32_t offset_type = _.GetOperandTypeId(inst, 5);
2603 const uint32_t p_type = _.GetOperandTypeId(inst, 6);
2605 if (!_.IsFloatVectorType(data_type) && !_.IsIntVectorType(data_type)) {
2606 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2607 << ext_inst_name() << ": "
2608 << "expected Data to be an int or float vector";
2611 const uint32_t num_components = _.GetDimension(data_type);
2612 if (num_components > 4 && num_components != 8 && num_components != 16) {
2613 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2614 << ext_inst_name() << ": "
2615 << "expected Data to have 2, 3, 4, 8 or 16 components";
2618 const uint32_t size_t_bit_width = GetSizeTBitWidth(_);
2619 if (!size_t_bit_width) {
2620 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2621 << ext_inst_name()
2622 << " can only be used with physical addressing models";
2625 if (!_.IsIntScalarType(offset_type) ||
2626 _.GetBitWidth(offset_type) != size_t_bit_width) {
2627 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2628 << ext_inst_name() << ": "
2629 << "expected operand Offset to be of type size_t ("
2630 << size_t_bit_width
2631 << "-bit integer for the addressing model used in the module)";
2634 spv::StorageClass p_storage_class;
2635 uint32_t p_data_type = 0;
2636 if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
2637 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2638 << ext_inst_name() << ": "
2639 << "expected operand P to be a pointer";
2642 if (p_storage_class != spv::StorageClass::Generic &&
2643 p_storage_class != spv::StorageClass::CrossWorkgroup &&
2644 p_storage_class != spv::StorageClass::Workgroup &&
2645 p_storage_class != spv::StorageClass::Function) {
2646 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2647 << ext_inst_name() << ": "
2648 << "expected operand P storage class to be Generic, "
2649 "CrossWorkgroup, Workgroup or Function";
2652 if (_.GetComponentType(data_type) != p_data_type) {
2653 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2654 << ext_inst_name() << ": "
2655 << "expected operand P data type to be equal to the type of "
2656 "operand Data components";
2658 break;
2661 case OpenCLLIB::Vload_half: {
2662 if (!_.IsFloatScalarType(result_type)) {
2663 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2664 << ext_inst_name() << ": "
2665 << "expected Result Type to be a float scalar type";
2668 const uint32_t offset_type = _.GetOperandTypeId(inst, 4);
2669 const uint32_t p_type = _.GetOperandTypeId(inst, 5);
2671 const uint32_t size_t_bit_width = GetSizeTBitWidth(_);
2672 if (!size_t_bit_width) {
2673 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2674 << ext_inst_name()
2675 << " can only be used with physical addressing models";
2678 if (!_.IsIntScalarType(offset_type) ||
2679 _.GetBitWidth(offset_type) != size_t_bit_width) {
2680 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2681 << ext_inst_name() << ": "
2682 << "expected operand Offset to be of type size_t ("
2683 << size_t_bit_width
2684 << "-bit integer for the addressing model used in the module)";
2687 spv::StorageClass p_storage_class;
2688 uint32_t p_data_type = 0;
2689 if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
2690 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2691 << ext_inst_name() << ": "
2692 << "expected operand P to be a pointer";
2695 if (p_storage_class != spv::StorageClass::UniformConstant &&
2696 p_storage_class != spv::StorageClass::Generic &&
2697 p_storage_class != spv::StorageClass::CrossWorkgroup &&
2698 p_storage_class != spv::StorageClass::Workgroup &&
2699 p_storage_class != spv::StorageClass::Function) {
2700 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2701 << ext_inst_name() << ": "
2702 << "expected operand P storage class to be UniformConstant, "
2703 "Generic, CrossWorkgroup, Workgroup or Function";
2706 if ((!_.IsFloatScalarType(p_data_type) ||
2707 _.GetBitWidth(p_data_type) != 16) &&
2708 !_.ContainsUntypedPointer(p_type)) {
2709 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2710 << ext_inst_name() << ": "
2711 << "expected operand P data type to be 16-bit float scalar";
2713 break;
2716 case OpenCLLIB::Vload_halfn:
2717 case OpenCLLIB::Vloada_halfn: {
2718 if (!_.IsFloatVectorType(result_type)) {
2719 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2720 << ext_inst_name() << ": "
2721 << "expected Result Type to be a float vector type";
2724 const uint32_t num_components = _.GetDimension(result_type);
2725 if (num_components > 4 && num_components != 8 && num_components != 16) {
2726 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2727 << ext_inst_name() << ": "
2728 << "expected Result Type to have 2, 3, 4, 8 or 16 components";
2731 const uint32_t offset_type = _.GetOperandTypeId(inst, 4);
2732 const uint32_t p_type = _.GetOperandTypeId(inst, 5);
2734 const uint32_t size_t_bit_width = GetSizeTBitWidth(_);
2735 if (!size_t_bit_width) {
2736 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2737 << ext_inst_name()
2738 << " can only be used with physical addressing models";
2741 if (!_.IsIntScalarType(offset_type) ||
2742 _.GetBitWidth(offset_type) != size_t_bit_width) {
2743 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2744 << ext_inst_name() << ": "
2745 << "expected operand Offset to be of type size_t ("
2746 << size_t_bit_width
2747 << "-bit integer for the addressing model used in the module)";
2750 spv::StorageClass p_storage_class;
2751 uint32_t p_data_type = 0;
2752 if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
2753 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2754 << ext_inst_name() << ": "
2755 << "expected operand P to be a pointer";
2758 if (p_storage_class != spv::StorageClass::UniformConstant &&
2759 p_storage_class != spv::StorageClass::Generic &&
2760 p_storage_class != spv::StorageClass::CrossWorkgroup &&
2761 p_storage_class != spv::StorageClass::Workgroup &&
2762 p_storage_class != spv::StorageClass::Function) {
2763 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2764 << ext_inst_name() << ": "
2765 << "expected operand P storage class to be UniformConstant, "
2766 "Generic, CrossWorkgroup, Workgroup or Function";
2769 if ((!_.IsFloatScalarType(p_data_type) ||
2770 _.GetBitWidth(p_data_type) != 16) &&
2771 !_.ContainsUntypedPointer(p_type)) {
2772 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2773 << ext_inst_name() << ": "
2774 << "expected operand P data type to be 16-bit float scalar";
2777 const uint32_t n_value = inst->word(7);
2778 if (num_components != n_value) {
2779 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2780 << ext_inst_name() << ": "
2781 << "expected literal N to be equal to the number of "
2782 "components of Result Type";
2784 break;
2787 case OpenCLLIB::Vstore_half:
2788 case OpenCLLIB::Vstore_half_r:
2789 case OpenCLLIB::Vstore_halfn:
2790 case OpenCLLIB::Vstore_halfn_r:
2791 case OpenCLLIB::Vstorea_halfn:
2792 case OpenCLLIB::Vstorea_halfn_r: {
2793 if (_.GetIdOpcode(result_type) != spv::Op::OpTypeVoid) {
2794 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2795 << ext_inst_name() << ": expected Result Type to be void";
2798 const uint32_t data_type = _.GetOperandTypeId(inst, 4);
2799 const uint32_t offset_type = _.GetOperandTypeId(inst, 5);
2800 const uint32_t p_type = _.GetOperandTypeId(inst, 6);
2801 const uint32_t data_type_bit_width = _.GetBitWidth(data_type);
2803 if (ext_inst_key == OpenCLLIB::Vstore_half ||
2804 ext_inst_key == OpenCLLIB::Vstore_half_r) {
2805 if (!_.IsFloatScalarType(data_type) ||
2806 (data_type_bit_width != 32 && data_type_bit_width != 64)) {
2807 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2808 << ext_inst_name() << ": "
2809 << "expected Data to be a 32 or 64-bit float scalar";
2811 } else {
2812 if (!_.IsFloatVectorType(data_type) ||
2813 (data_type_bit_width != 32 && data_type_bit_width != 64)) {
2814 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2815 << ext_inst_name() << ": "
2816 << "expected Data to be a 32 or 64-bit float vector";
2819 const uint32_t num_components = _.GetDimension(data_type);
2820 if (num_components > 4 && num_components != 8 &&
2821 num_components != 16) {
2822 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2823 << ext_inst_name() << ": "
2824 << "expected Data to have 2, 3, 4, 8 or 16 components";
2828 const uint32_t size_t_bit_width = GetSizeTBitWidth(_);
2829 if (!size_t_bit_width) {
2830 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2831 << ext_inst_name()
2832 << " can only be used with physical addressing models";
2835 if (!_.IsIntScalarType(offset_type) ||
2836 _.GetBitWidth(offset_type) != size_t_bit_width) {
2837 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2838 << ext_inst_name() << ": "
2839 << "expected operand Offset to be of type size_t ("
2840 << size_t_bit_width
2841 << "-bit integer for the addressing model used in the module)";
2844 spv::StorageClass p_storage_class;
2845 uint32_t p_data_type = 0;
2846 if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
2847 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2848 << ext_inst_name() << ": "
2849 << "expected operand P to be a pointer";
2852 if (p_storage_class != spv::StorageClass::Generic &&
2853 p_storage_class != spv::StorageClass::CrossWorkgroup &&
2854 p_storage_class != spv::StorageClass::Workgroup &&
2855 p_storage_class != spv::StorageClass::Function) {
2856 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2857 << ext_inst_name() << ": "
2858 << "expected operand P storage class to be Generic, "
2859 "CrossWorkgroup, Workgroup or Function";
2862 if ((!_.IsFloatScalarType(p_data_type) ||
2863 _.GetBitWidth(p_data_type) != 16) &&
2864 !_.ContainsUntypedPointer(p_type)) {
2865 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2866 << ext_inst_name() << ": "
2867 << "expected operand P data type to be 16-bit float scalar";
2870 // Rounding mode enum is checked by assembler.
2871 break;
2874 case OpenCLLIB::Shuffle:
2875 case OpenCLLIB::Shuffle2: {
2876 if (!_.IsFloatVectorType(result_type) &&
2877 !_.IsIntVectorType(result_type)) {
2878 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2879 << ext_inst_name() << ": "
2880 << "expected Result Type to be an int or float vector type";
2883 const uint32_t result_num_components = _.GetDimension(result_type);
2884 if (result_num_components != 2 && result_num_components != 4 &&
2885 result_num_components != 8 && result_num_components != 16) {
2886 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2887 << ext_inst_name() << ": "
2888 << "expected Result Type to have 2, 4, 8 or 16 components";
2891 uint32_t operand_index = 4;
2892 const uint32_t x_type = _.GetOperandTypeId(inst, operand_index++);
2894 if (ext_inst_key == OpenCLLIB::Shuffle2) {
2895 const uint32_t y_type = _.GetOperandTypeId(inst, operand_index++);
2896 if (x_type != y_type) {
2897 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2898 << ext_inst_name() << ": "
2899 << "expected operands X and Y to be of the same type";
2903 const uint32_t shuffle_mask_type =
2904 _.GetOperandTypeId(inst, operand_index++);
2906 if (!_.IsFloatVectorType(x_type) && !_.IsIntVectorType(x_type)) {
2907 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2908 << ext_inst_name() << ": "
2909 << "expected operand X to be an int or float vector";
2912 const uint32_t x_num_components = _.GetDimension(x_type);
2913 if (x_num_components != 2 && x_num_components != 4 &&
2914 x_num_components != 8 && x_num_components != 16) {
2915 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2916 << ext_inst_name() << ": "
2917 << "expected operand X to have 2, 4, 8 or 16 components";
2920 const uint32_t result_component_type = _.GetComponentType(result_type);
2922 if (result_component_type != _.GetComponentType(x_type)) {
2923 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2924 << ext_inst_name() << ": "
2925 << "expected operand X and Result Type to have equal "
2926 "component types";
2929 if (!_.IsIntVectorType(shuffle_mask_type)) {
2930 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2931 << ext_inst_name() << ": "
2932 << "expected operand Shuffle Mask to be an int vector";
2935 if (result_num_components != _.GetDimension(shuffle_mask_type)) {
2936 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2937 << ext_inst_name() << ": "
2938 << "expected operand Shuffle Mask to have the same number of "
2939 "components as Result Type";
2942 if (_.GetBitWidth(result_component_type) !=
2943 _.GetBitWidth(shuffle_mask_type)) {
2944 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2945 << ext_inst_name() << ": "
2946 << "expected operand Shuffle Mask components to have the same "
2947 "bit width as Result Type components";
2949 break;
2952 case OpenCLLIB::Printf: {
2953 if (!_.IsIntScalarType(result_type) ||
2954 _.GetBitWidth(result_type) != 32) {
2955 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2956 << ext_inst_name() << ": "
2957 << "expected Result Type to be a 32-bit int type";
2960 const uint32_t format_type = _.GetOperandTypeId(inst, 4);
2961 spv::StorageClass format_storage_class;
2962 uint32_t format_data_type = 0;
2963 if (!_.GetPointerTypeInfo(format_type, &format_data_type,
2964 &format_storage_class)) {
2965 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2966 << ext_inst_name() << ": "
2967 << "expected operand Format to be a pointer";
2970 if (_.HasExtension(
2971 Extension::kSPV_EXT_relaxed_printf_string_address_space)) {
2972 if (format_storage_class != spv::StorageClass::UniformConstant &&
2973 // Extension SPV_EXT_relaxed_printf_string_address_space allows
2974 // format strings in Global, Local, Private and Generic address
2975 // spaces
2977 // Global
2978 format_storage_class != spv::StorageClass::CrossWorkgroup &&
2979 // Local
2980 format_storage_class != spv::StorageClass::Workgroup &&
2981 // Private
2982 format_storage_class != spv::StorageClass::Function &&
2983 // Generic
2984 format_storage_class != spv::StorageClass::Generic) {
2985 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2986 << ext_inst_name() << ": "
2987 << "expected Format storage class to be UniformConstant, "
2988 "Crossworkgroup, Workgroup, Function, or Generic";
2990 } else {
2991 if (format_storage_class != spv::StorageClass::UniformConstant) {
2992 return _.diag(SPV_ERROR_INVALID_DATA, inst)
2993 << ext_inst_name() << ": "
2994 << "expected Format storage class to be UniformConstant";
2998 // If pointer points to an array, get the type of an element
2999 if (_.IsIntArrayType(format_data_type))
3000 format_data_type = _.GetComponentType(format_data_type);
3002 if ((!_.IsIntScalarType(format_data_type) ||
3003 _.GetBitWidth(format_data_type) != 8) &&
3004 !_.ContainsUntypedPointer(format_type)) {
3005 return _.diag(SPV_ERROR_INVALID_DATA, inst)
3006 << ext_inst_name() << ": "
3007 << "expected Format data type to be 8-bit int";
3009 break;
3012 case OpenCLLIB::Prefetch: {
3013 if (_.GetIdOpcode(result_type) != spv::Op::OpTypeVoid) {
3014 return _.diag(SPV_ERROR_INVALID_DATA, inst)
3015 << ext_inst_name() << ": expected Result Type to be void";
3018 const uint32_t p_type = _.GetOperandTypeId(inst, 4);
3019 const uint32_t num_elements_type = _.GetOperandTypeId(inst, 5);
3021 spv::StorageClass p_storage_class;
3022 uint32_t p_data_type = 0;
3023 if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
3024 return _.diag(SPV_ERROR_INVALID_DATA, inst)
3025 << ext_inst_name() << ": "
3026 << "expected operand Ptr to be a pointer";
3029 if (p_storage_class != spv::StorageClass::CrossWorkgroup) {
3030 return _.diag(SPV_ERROR_INVALID_DATA, inst)
3031 << ext_inst_name() << ": "
3032 << "expected operand Ptr storage class to be CrossWorkgroup";
3035 if (!_.IsFloatScalarOrVectorType(p_data_type) &&
3036 !_.IsIntScalarOrVectorType(p_data_type)) {
3037 return _.diag(SPV_ERROR_INVALID_DATA, inst)
3038 << ext_inst_name() << ": "
3039 << "expected Ptr data type to be int or float scalar or "
3040 "vector";
3043 const uint32_t num_components = _.GetDimension(p_data_type);
3044 if (num_components > 4 && num_components != 8 && num_components != 16) {
3045 return _.diag(SPV_ERROR_INVALID_DATA, inst)
3046 << ext_inst_name() << ": "
3047 << "expected Result Type to be a scalar or a vector with 2, "
3048 "3, 4, 8 or 16 components";
3051 const uint32_t size_t_bit_width = GetSizeTBitWidth(_);
3052 if (!size_t_bit_width) {
3053 return _.diag(SPV_ERROR_INVALID_DATA, inst)
3054 << ext_inst_name()
3055 << " can only be used with physical addressing models";
3058 if (!_.IsIntScalarType(num_elements_type) ||
3059 _.GetBitWidth(num_elements_type) != size_t_bit_width) {
3060 return _.diag(SPV_ERROR_INVALID_DATA, inst)
3061 << ext_inst_name() << ": "
3062 << "expected operand Num Elements to be of type size_t ("
3063 << size_t_bit_width
3064 << "-bit integer for the addressing model used in the module)";
3066 break;
3069 } else if (ext_inst_type == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100 ||
3070 ext_inst_type ==
3071 SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100) {
3072 if (!_.IsVoidType(result_type)) {
3073 return _.diag(SPV_ERROR_INVALID_DATA, inst)
3074 << ext_inst_name() << ": "
3075 << "expected result type must be a result id of "
3076 << "OpTypeVoid";
3079 const bool vulkanDebugInfo =
3080 ext_inst_type == SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100;
3082 auto num_words = inst->words().size();
3084 // Handle any non-common NonSemanticShaderDebugInfo instructions.
3085 if (vulkanDebugInfo) {
3086 const NonSemanticShaderDebugInfo100Instructions ext_inst_key =
3087 NonSemanticShaderDebugInfo100Instructions(ext_inst_index);
3088 switch (ext_inst_key) {
3089 // The following block of instructions will be handled by the common
3090 // validation.
3091 case NonSemanticShaderDebugInfo100DebugInfoNone:
3092 case NonSemanticShaderDebugInfo100DebugCompilationUnit:
3093 case NonSemanticShaderDebugInfo100DebugTypeBasic:
3094 case NonSemanticShaderDebugInfo100DebugTypePointer:
3095 case NonSemanticShaderDebugInfo100DebugTypeQualifier:
3096 case NonSemanticShaderDebugInfo100DebugTypeArray:
3097 case NonSemanticShaderDebugInfo100DebugTypeVector:
3098 case NonSemanticShaderDebugInfo100DebugTypedef:
3099 case NonSemanticShaderDebugInfo100DebugTypeFunction:
3100 case NonSemanticShaderDebugInfo100DebugTypeEnum:
3101 case NonSemanticShaderDebugInfo100DebugTypeComposite:
3102 case NonSemanticShaderDebugInfo100DebugTypeMember:
3103 case NonSemanticShaderDebugInfo100DebugTypeInheritance:
3104 case NonSemanticShaderDebugInfo100DebugTypePtrToMember:
3105 case NonSemanticShaderDebugInfo100DebugTypeTemplate:
3106 case NonSemanticShaderDebugInfo100DebugTypeTemplateParameter:
3107 case NonSemanticShaderDebugInfo100DebugTypeTemplateTemplateParameter:
3108 case NonSemanticShaderDebugInfo100DebugTypeTemplateParameterPack:
3109 case NonSemanticShaderDebugInfo100DebugGlobalVariable:
3110 case NonSemanticShaderDebugInfo100DebugFunctionDeclaration:
3111 case NonSemanticShaderDebugInfo100DebugFunction:
3112 case NonSemanticShaderDebugInfo100DebugLexicalBlock:
3113 case NonSemanticShaderDebugInfo100DebugLexicalBlockDiscriminator:
3114 case NonSemanticShaderDebugInfo100DebugScope:
3115 case NonSemanticShaderDebugInfo100DebugNoScope:
3116 case NonSemanticShaderDebugInfo100DebugInlinedAt:
3117 case NonSemanticShaderDebugInfo100DebugLocalVariable:
3118 case NonSemanticShaderDebugInfo100DebugInlinedVariable:
3119 case NonSemanticShaderDebugInfo100DebugDeclare:
3120 case NonSemanticShaderDebugInfo100DebugValue:
3121 case NonSemanticShaderDebugInfo100DebugOperation:
3122 case NonSemanticShaderDebugInfo100DebugExpression:
3123 case NonSemanticShaderDebugInfo100DebugMacroDef:
3124 case NonSemanticShaderDebugInfo100DebugMacroUndef:
3125 case NonSemanticShaderDebugInfo100DebugImportedEntity:
3126 case NonSemanticShaderDebugInfo100DebugSource:
3127 break;
3128 case NonSemanticShaderDebugInfo100DebugTypeMatrix: {
3129 CHECK_DEBUG_OPERAND("Vector Type", CommonDebugInfoDebugTypeVector, 5);
3131 CHECK_CONST_UINT_OPERAND("Vector Count", 6);
3133 uint32_t vector_count = inst->word(6);
3134 uint64_t const_val;
3135 if (!_.EvalConstantValUint64(vector_count, &const_val)) {
3136 return _.diag(SPV_ERROR_INVALID_DATA, inst)
3137 << ext_inst_name()
3138 << ": Vector Count must be 32-bit integer OpConstant";
3141 vector_count = const_val & 0xffffffff;
3142 if (!vector_count || vector_count > 4) {
3143 return _.diag(SPV_ERROR_INVALID_DATA, inst)
3144 << ext_inst_name() << ": Vector Count must be positive "
3145 << "integer less than or equal to 4";
3147 break;
3149 // TODO: Add validation rules for remaining cases as well.
3150 case NonSemanticShaderDebugInfo100DebugFunctionDefinition:
3151 case NonSemanticShaderDebugInfo100DebugSourceContinued:
3152 case NonSemanticShaderDebugInfo100DebugLine:
3153 case NonSemanticShaderDebugInfo100DebugNoLine:
3154 case NonSemanticShaderDebugInfo100DebugBuildIdentifier:
3155 case NonSemanticShaderDebugInfo100DebugStoragePath:
3156 case NonSemanticShaderDebugInfo100DebugEntryPoint:
3157 break;
3158 case NonSemanticShaderDebugInfo100InstructionsMax:
3159 assert(0);
3160 break;
3164 // Handle any non-common OpenCL insts, then common
3165 if (ext_inst_type != SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100 ||
3166 OpenCLDebugInfo100Instructions(ext_inst_index) !=
3167 OpenCLDebugInfo100DebugModuleINTEL) {
3168 const CommonDebugInfoInstructions ext_inst_key =
3169 CommonDebugInfoInstructions(ext_inst_index);
3170 switch (ext_inst_key) {
3171 case CommonDebugInfoDebugInfoNone:
3172 case CommonDebugInfoDebugNoScope:
3173 break;
3174 // The binary parser validates the opcode for DebugInfoNone,
3175 // DebugNoScope, DebugOperation. We just check the parameters to
3176 // DebugOperation are properly constants for vulkan debug info.
3177 case CommonDebugInfoDebugOperation: {
3178 CHECK_CONST_UINT_OPERAND("Operation", 5);
3179 for (uint32_t i = 6; i < num_words; ++i) {
3180 CHECK_CONST_UINT_OPERAND("Operand", i);
3182 break;
3184 case CommonDebugInfoDebugCompilationUnit: {
3185 CHECK_CONST_UINT_OPERAND("Version", 5);
3186 CHECK_CONST_UINT_OPERAND("DWARF Version", 6);
3187 CHECK_DEBUG_OPERAND("Source", CommonDebugInfoDebugSource, 7);
3188 CHECK_CONST_UINT_OPERAND("Language", 8);
3189 break;
3191 case CommonDebugInfoDebugSource: {
3192 CHECK_OPERAND("File", spv::Op::OpString, 5);
3193 if (num_words == 7) CHECK_OPERAND("Text", spv::Op::OpString, 6);
3194 break;
3196 case CommonDebugInfoDebugTypeBasic: {
3197 CHECK_OPERAND("Name", spv::Op::OpString, 5);
3198 CHECK_OPERAND("Size", spv::Op::OpConstant, 6);
3199 CHECK_CONST_UINT_OPERAND("Encoding", 7);
3200 break;
3202 case CommonDebugInfoDebugTypePointer: {
3203 auto validate_base_type = ValidateOperandDebugType(
3204 _, "Base Type", inst, 5, ext_inst_name, false);
3205 if (validate_base_type != SPV_SUCCESS) return validate_base_type;
3206 CHECK_CONST_UINT_OPERAND("Storage Class", 6);
3207 CHECK_CONST_UINT_OPERAND("Flags", 7);
3208 break;
3210 case CommonDebugInfoDebugTypeQualifier: {
3211 auto validate_base_type = ValidateOperandDebugType(
3212 _, "Base Type", inst, 5, ext_inst_name, false);
3213 if (validate_base_type != SPV_SUCCESS) return validate_base_type;
3214 CHECK_CONST_UINT_OPERAND("Type Qualifier", 6);
3215 break;
3217 case CommonDebugInfoDebugTypeVector: {
3218 auto validate_base_type =
3219 ValidateOperandBaseType(_, inst, 5, ext_inst_name);
3220 if (validate_base_type != SPV_SUCCESS) return validate_base_type;
3222 CHECK_CONST_UINT_OPERAND("Component Count", 6);
3223 uint32_t component_count = inst->word(6);
3224 if (vulkanDebugInfo) {
3225 uint64_t const_val;
3226 if (!_.EvalConstantValUint64(component_count, &const_val)) {
3227 return _.diag(SPV_ERROR_INVALID_DATA, inst)
3228 << ext_inst_name()
3229 << ": Component Count must be 32-bit integer OpConstant";
3231 component_count = const_val & 0xffffffff;
3234 if (!component_count || component_count > 4) {
3235 return _.diag(SPV_ERROR_INVALID_DATA, inst)
3236 << ext_inst_name() << ": Component Count must be positive "
3237 << "integer less than or equal to 4";
3239 break;
3241 case CommonDebugInfoDebugTypeArray: {
3242 auto validate_base_type = ValidateOperandDebugType(
3243 _, "Base Type", inst, 5, ext_inst_name, false);
3244 if (validate_base_type != SPV_SUCCESS) return validate_base_type;
3245 for (uint32_t i = 6; i < num_words; ++i) {
3246 bool invalid = false;
3247 auto* component_count = _.FindDef(inst->word(i));
3248 if (IsConstIntScalarTypeWith32Or64Bits(_, component_count)) {
3249 // TODO: We need a spec discussion for the runtime array for
3250 // OpenCL.
3251 if (!vulkanDebugInfo && !component_count->word(3)) {
3252 invalid = true;
3254 } else if (component_count->words().size() > 6 &&
3255 (CommonDebugInfoInstructions(component_count->word(4)) ==
3256 CommonDebugInfoDebugLocalVariable ||
3257 CommonDebugInfoInstructions(component_count->word(4)) ==
3258 CommonDebugInfoDebugGlobalVariable)) {
3259 auto* component_count_type = _.FindDef(component_count->word(6));
3260 if (component_count_type->words().size() > 7) {
3261 uint32_t encoding = component_count_type->word(7);
3262 if (CommonDebugInfoInstructions(component_count_type->word(
3263 4)) != CommonDebugInfoDebugTypeBasic ||
3264 (vulkanDebugInfo && !IsUint32Constant(_, encoding)) ||
3265 OpenCLDebugInfo100DebugBaseTypeAttributeEncoding(
3266 vulkanDebugInfo
3267 ? GetUint32Constant(_, encoding)
3268 : encoding) != OpenCLDebugInfo100Unsigned) {
3269 invalid = true;
3270 } else {
3271 // DebugTypeBasic for DebugLocalVariable/DebugGlobalVariable
3272 // must have Unsigned encoding and 32 or 64 as its size in
3273 // bits.
3274 Instruction* size_in_bits =
3275 _.FindDef(component_count_type->word(6));
3276 if (!_.IsIntScalarType(size_in_bits->type_id()) ||
3277 (size_in_bits->word(3) != 32 &&
3278 size_in_bits->word(3) != 64)) {
3279 invalid = true;
3282 } else {
3283 invalid = true;
3285 } else {
3286 invalid = true;
3288 if (invalid) {
3289 return _.diag(SPV_ERROR_INVALID_DATA, inst)
3290 << ext_inst_name() << ": Component Count must be "
3291 << "OpConstant with a 32- or 64-bits integer scalar type "
3292 "or "
3293 << "DebugGlobalVariable or DebugLocalVariable with a 32- "
3294 "or "
3295 << "64-bits unsigned integer scalar type";
3298 break;
3300 case CommonDebugInfoDebugTypedef: {
3301 CHECK_OPERAND("Name", spv::Op::OpString, 5);
3302 auto validate_base_type =
3303 ValidateOperandBaseType(_, inst, 6, ext_inst_name);
3304 if (validate_base_type != SPV_SUCCESS) return validate_base_type;
3305 CHECK_DEBUG_OPERAND("Source", CommonDebugInfoDebugSource, 7);
3306 CHECK_CONST_UINT_OPERAND("Line", 8);
3307 CHECK_CONST_UINT_OPERAND("Column", 9);
3308 auto validate_parent =
3309 ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name);
3310 if (validate_parent != SPV_SUCCESS) return validate_parent;
3311 break;
3313 case CommonDebugInfoDebugTypeFunction: {
3314 CHECK_CONST_UINT_OPERAND("Flags", 5);
3315 auto* return_type = _.FindDef(inst->word(6));
3316 // TODO: We need a spec discussion that we have to allow return and
3317 // parameter types of a DebugTypeFunction to have template parameter.
3318 if (return_type->opcode() != spv::Op::OpTypeVoid) {
3319 auto validate_return = ValidateOperandDebugType(
3320 _, "Return Type", inst, 6, ext_inst_name, true);
3321 if (validate_return != SPV_SUCCESS) return validate_return;
3323 for (uint32_t word_index = 7; word_index < num_words; ++word_index) {
3324 auto validate_param = ValidateOperandDebugType(
3325 _, "Parameter Types", inst, word_index, ext_inst_name, true);
3326 if (validate_param != SPV_SUCCESS) return validate_param;
3328 break;
3330 case CommonDebugInfoDebugTypeEnum: {
3331 CHECK_OPERAND("Name", spv::Op::OpString, 5);
3332 if (!DoesDebugInfoOperandMatchExpectation(
3334 [](CommonDebugInfoInstructions dbg_inst) {
3335 return dbg_inst == CommonDebugInfoDebugInfoNone;
3337 inst, 6)) {
3338 auto validate_underlying_type = ValidateOperandDebugType(
3339 _, "Underlying Types", inst, 6, ext_inst_name, false);
3340 if (validate_underlying_type != SPV_SUCCESS)
3341 return validate_underlying_type;
3343 CHECK_DEBUG_OPERAND("Source", CommonDebugInfoDebugSource, 7);
3344 CHECK_CONST_UINT_OPERAND("Line", 8);
3345 CHECK_CONST_UINT_OPERAND("Column", 9);
3346 auto validate_parent =
3347 ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name);
3348 if (validate_parent != SPV_SUCCESS) return validate_parent;
3349 CHECK_OPERAND("Size", spv::Op::OpConstant, 11);
3350 auto* size = _.FindDef(inst->word(11));
3351 if (!_.IsIntScalarType(size->type_id()) || !size->word(3)) {
3352 return _.diag(SPV_ERROR_INVALID_DATA, inst)
3353 << ext_inst_name() << ": expected operand Size is a "
3354 << "positive integer";
3356 CHECK_CONST_UINT_OPERAND("Flags", 12);
3357 for (uint32_t word_index = 13; word_index + 1 < num_words;
3358 word_index += 2) {
3359 CHECK_OPERAND("Value", spv::Op::OpConstant, word_index);
3360 CHECK_OPERAND("Name", spv::Op::OpString, word_index + 1);
3362 break;
3364 case CommonDebugInfoDebugTypeComposite: {
3365 CHECK_OPERAND("Name", spv::Op::OpString, 5);
3366 CHECK_DEBUG_OPERAND("Source", CommonDebugInfoDebugSource, 7);
3367 CHECK_CONST_UINT_OPERAND("Line", 8);
3368 CHECK_CONST_UINT_OPERAND("Column", 9);
3369 auto validate_parent =
3370 ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name);
3371 if (validate_parent != SPV_SUCCESS) return validate_parent;
3372 CHECK_OPERAND("Linkage Name", spv::Op::OpString, 11);
3373 if (!DoesDebugInfoOperandMatchExpectation(
3375 [](CommonDebugInfoInstructions dbg_inst) {
3376 return dbg_inst == CommonDebugInfoDebugInfoNone;
3378 inst, 12)) {
3379 CHECK_OPERAND("Size", spv::Op::OpConstant, 12);
3381 CHECK_CONST_UINT_OPERAND("Flags", 13);
3382 for (uint32_t word_index = 14; word_index < num_words; ++word_index) {
3383 if (!DoesDebugInfoOperandMatchExpectation(
3385 [](CommonDebugInfoInstructions dbg_inst) {
3386 return dbg_inst == CommonDebugInfoDebugTypeMember ||
3387 dbg_inst == CommonDebugInfoDebugFunction ||
3388 dbg_inst == CommonDebugInfoDebugTypeInheritance;
3390 inst, word_index)) {
3391 return _.diag(SPV_ERROR_INVALID_DATA, inst)
3392 << ext_inst_name() << ": "
3393 << "expected operand Members "
3394 << "must be DebugTypeMember, DebugFunction, or "
3395 "DebugTypeInheritance";
3398 break;
3400 case CommonDebugInfoDebugTypeMember: {
3401 CHECK_OPERAND("Name", spv::Op::OpString, 5);
3402 // TODO: We need a spec discussion that we have to allow member types
3403 // to have template parameter.
3404 auto validate_type =
3405 ValidateOperandDebugType(_, "Type", inst, 6, ext_inst_name, true);
3406 if (validate_type != SPV_SUCCESS) return validate_type;
3407 CHECK_DEBUG_OPERAND("Source", CommonDebugInfoDebugSource, 7);
3408 CHECK_CONST_UINT_OPERAND("Line", 8);
3409 CHECK_CONST_UINT_OPERAND("Column", 9);
3410 // NonSemantic.Shader.DebugInfo doesn't have the Parent operand
3411 if (vulkanDebugInfo) {
3412 CHECK_OPERAND("Offset", spv::Op::OpConstant, 10);
3413 CHECK_OPERAND("Size", spv::Op::OpConstant, 11);
3414 CHECK_CONST_UINT_OPERAND("Flags", 12);
3415 if (num_words == 14)
3416 CHECK_OPERAND("Value", spv::Op::OpConstant, 13);
3417 } else {
3418 CHECK_DEBUG_OPERAND("Parent", CommonDebugInfoDebugTypeComposite,
3419 10);
3420 CHECK_OPERAND("Offset", spv::Op::OpConstant, 11);
3421 CHECK_OPERAND("Size", spv::Op::OpConstant, 12);
3422 CHECK_CONST_UINT_OPERAND("Flags", 13);
3423 if (num_words == 15)
3424 CHECK_OPERAND("Value", spv::Op::OpConstant, 14);
3426 break;
3428 case CommonDebugInfoDebugTypeInheritance: {
3429 CHECK_DEBUG_OPERAND("Child", CommonDebugInfoDebugTypeComposite, 5);
3430 auto* debug_inst = _.FindDef(inst->word(5));
3431 auto composite_type =
3432 OpenCLDebugInfo100DebugCompositeType(debug_inst->word(6));
3433 if (composite_type != OpenCLDebugInfo100Class &&
3434 composite_type != OpenCLDebugInfo100Structure) {
3435 return _.diag(SPV_ERROR_INVALID_DATA, inst)
3436 << ext_inst_name() << ": "
3437 << "expected operand Child must be class or struct debug "
3438 "type";
3440 CHECK_DEBUG_OPERAND("Parent", CommonDebugInfoDebugTypeComposite, 6);
3441 debug_inst = _.FindDef(inst->word(6));
3442 composite_type =
3443 OpenCLDebugInfo100DebugCompositeType(debug_inst->word(6));
3444 if (composite_type != OpenCLDebugInfo100Class &&
3445 composite_type != OpenCLDebugInfo100Structure) {
3446 return _.diag(SPV_ERROR_INVALID_DATA, inst)
3447 << ext_inst_name() << ": "
3448 << "expected operand Parent must be class or struct debug "
3449 "type";
3451 CHECK_OPERAND("Offset", spv::Op::OpConstant, 7);
3452 CHECK_OPERAND("Size", spv::Op::OpConstant, 8);
3453 CHECK_CONST_UINT_OPERAND("Flags", 9);
3454 break;
3456 case CommonDebugInfoDebugFunction: {
3457 CHECK_OPERAND("Name", spv::Op::OpString, 5);
3458 auto validate_type = ValidateOperandDebugType(_, "Type", inst, 6,
3459 ext_inst_name, false);
3460 if (validate_type != SPV_SUCCESS) return validate_type;
3461 CHECK_DEBUG_OPERAND("Source", CommonDebugInfoDebugSource, 7);
3462 CHECK_CONST_UINT_OPERAND("Line", 8);
3463 CHECK_CONST_UINT_OPERAND("Column", 9);
3464 auto validate_parent =
3465 ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name);
3466 if (validate_parent != SPV_SUCCESS) return validate_parent;
3467 CHECK_OPERAND("Linkage Name", spv::Op::OpString, 11);
3468 CHECK_CONST_UINT_OPERAND("Flags", 12);
3469 CHECK_CONST_UINT_OPERAND("Scope Line", 13);
3470 // NonSemantic.Shader.DebugInfo.100 doesn't include a reference to the
3471 // OpFunction
3472 if (vulkanDebugInfo) {
3473 if (num_words == 15) {
3474 CHECK_DEBUG_OPERAND("Declaration",
3475 CommonDebugInfoDebugFunctionDeclaration, 14);
3477 } else {
3478 if (!DoesDebugInfoOperandMatchExpectation(
3480 [](CommonDebugInfoInstructions dbg_inst) {
3481 return dbg_inst == CommonDebugInfoDebugInfoNone;
3483 inst, 14)) {
3484 CHECK_OPERAND("Function", spv::Op::OpFunction, 14);
3486 if (num_words == 16) {
3487 CHECK_DEBUG_OPERAND("Declaration",
3488 CommonDebugInfoDebugFunctionDeclaration, 15);
3491 break;
3493 case CommonDebugInfoDebugFunctionDeclaration: {
3494 CHECK_OPERAND("Name", spv::Op::OpString, 5);
3495 auto validate_type = ValidateOperandDebugType(_, "Type", inst, 6,
3496 ext_inst_name, false);
3497 if (validate_type != SPV_SUCCESS) return validate_type;
3498 CHECK_DEBUG_OPERAND("Source", CommonDebugInfoDebugSource, 7);
3499 CHECK_CONST_UINT_OPERAND("Line", 8);
3500 CHECK_CONST_UINT_OPERAND("Column", 9);
3501 auto validate_parent =
3502 ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name);
3503 if (validate_parent != SPV_SUCCESS) return validate_parent;
3504 CHECK_OPERAND("Linkage Name", spv::Op::OpString, 11);
3505 CHECK_CONST_UINT_OPERAND("Flags", 12);
3506 break;
3508 case CommonDebugInfoDebugLexicalBlock: {
3509 CHECK_DEBUG_OPERAND("Source", CommonDebugInfoDebugSource, 5);
3510 CHECK_CONST_UINT_OPERAND("Line", 6);
3511 CHECK_CONST_UINT_OPERAND("Column", 7);
3512 auto validate_parent =
3513 ValidateOperandLexicalScope(_, "Parent", inst, 8, ext_inst_name);
3514 if (validate_parent != SPV_SUCCESS) return validate_parent;
3515 if (num_words == 10) CHECK_OPERAND("Name", spv::Op::OpString, 9);
3516 break;
3518 case CommonDebugInfoDebugScope: {
3519 auto validate_scope =
3520 ValidateOperandLexicalScope(_, "Scope", inst, 5, ext_inst_name);
3521 if (validate_scope != SPV_SUCCESS) return validate_scope;
3522 if (num_words == 7) {
3523 CHECK_DEBUG_OPERAND("Inlined At", CommonDebugInfoDebugInlinedAt, 6);
3525 break;
3527 case CommonDebugInfoDebugLocalVariable: {
3528 CHECK_OPERAND("Name", spv::Op::OpString, 5);
3529 // TODO: We need a spec discussion that we have to allow local
3530 // variable types to have template parameter.
3531 auto validate_type =
3532 ValidateOperandDebugType(_, "Type", inst, 6, ext_inst_name, true);
3533 if (validate_type != SPV_SUCCESS) return validate_type;
3534 CHECK_DEBUG_OPERAND("Source", CommonDebugInfoDebugSource, 7);
3535 CHECK_CONST_UINT_OPERAND("Line", 8);
3536 CHECK_CONST_UINT_OPERAND("Column", 9);
3537 auto validate_parent =
3538 ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name);
3539 if (validate_parent != SPV_SUCCESS) return validate_parent;
3540 CHECK_CONST_UINT_OPERAND("Flags", 11);
3541 if (num_words == 13) {
3542 CHECK_CONST_UINT_OPERAND("ArgNumber", 12);
3544 break;
3546 case CommonDebugInfoDebugDeclare: {
3547 CHECK_DEBUG_OPERAND("Local Variable",
3548 CommonDebugInfoDebugLocalVariable, 5);
3549 auto* operand = _.FindDef(inst->word(6));
3550 if (operand->opcode() != spv::Op::OpVariable &&
3551 operand->opcode() != spv::Op::OpFunctionParameter) {
3552 return _.diag(SPV_ERROR_INVALID_DATA, inst)
3553 << ext_inst_name() << ": "
3554 << "expected operand Variable must be a result id of "
3555 "OpVariable or OpFunctionParameter";
3558 CHECK_DEBUG_OPERAND("Expression", CommonDebugInfoDebugExpression, 7);
3560 if (vulkanDebugInfo) {
3561 for (uint32_t word_index = 8; word_index < num_words;
3562 ++word_index) {
3563 auto index_inst = _.FindDef(inst->word(word_index));
3564 auto type_id = index_inst != nullptr ? index_inst->type_id() : 0;
3565 if (type_id == 0 || !IsIntScalar(_, type_id, false, false))
3566 return _.diag(SPV_ERROR_INVALID_DATA, inst)
3567 << ext_inst_name() << ": "
3568 << "expected index must be scalar integer";
3571 break;
3573 case CommonDebugInfoDebugExpression: {
3574 for (uint32_t word_index = 5; word_index < num_words; ++word_index) {
3575 CHECK_DEBUG_OPERAND("Operation", CommonDebugInfoDebugOperation,
3576 word_index);
3578 break;
3580 case CommonDebugInfoDebugTypeTemplate: {
3581 if (!DoesDebugInfoOperandMatchExpectation(
3583 [](CommonDebugInfoInstructions dbg_inst) {
3584 return dbg_inst == CommonDebugInfoDebugTypeComposite ||
3585 dbg_inst == CommonDebugInfoDebugFunction;
3587 inst, 5)) {
3588 return _.diag(SPV_ERROR_INVALID_DATA, inst)
3589 << ext_inst_name() << ": "
3590 << "expected operand Target must be DebugTypeComposite "
3591 << "or DebugFunction";
3593 for (uint32_t word_index = 6; word_index < num_words; ++word_index) {
3594 if (!DoesDebugInfoOperandMatchExpectation(
3596 [](CommonDebugInfoInstructions dbg_inst) {
3597 return dbg_inst ==
3598 CommonDebugInfoDebugTypeTemplateParameter ||
3599 dbg_inst ==
3600 CommonDebugInfoDebugTypeTemplateTemplateParameter;
3602 inst, word_index)) {
3603 return _.diag(SPV_ERROR_INVALID_DATA, inst)
3604 << ext_inst_name() << ": "
3605 << "expected operand Parameters must be "
3606 << "DebugTypeTemplateParameter or "
3607 << "DebugTypeTemplateTemplateParameter";
3610 break;
3612 case CommonDebugInfoDebugTypeTemplateParameter: {
3613 CHECK_OPERAND("Name", spv::Op::OpString, 5);
3614 auto validate_actual_type = ValidateOperandDebugType(
3615 _, "Actual Type", inst, 6, ext_inst_name, false);
3616 if (validate_actual_type != SPV_SUCCESS) return validate_actual_type;
3617 if (!DoesDebugInfoOperandMatchExpectation(
3619 [](CommonDebugInfoInstructions dbg_inst) {
3620 return dbg_inst == CommonDebugInfoDebugInfoNone;
3622 inst, 7)) {
3623 CHECK_OPERAND("Value", spv::Op::OpConstant, 7);
3625 CHECK_DEBUG_OPERAND("Source", CommonDebugInfoDebugSource, 8);
3626 CHECK_CONST_UINT_OPERAND("Line", 9);
3627 CHECK_CONST_UINT_OPERAND("Column", 10);
3628 break;
3630 case CommonDebugInfoDebugGlobalVariable: {
3631 CHECK_OPERAND("Name", spv::Op::OpString, 5);
3632 auto validate_type = ValidateOperandDebugType(_, "Type", inst, 6,
3633 ext_inst_name, false);
3634 if (validate_type != SPV_SUCCESS) return validate_type;
3635 CHECK_DEBUG_OPERAND("Source", CommonDebugInfoDebugSource, 7);
3636 CHECK_CONST_UINT_OPERAND("Line", 8);
3637 CHECK_CONST_UINT_OPERAND("Column", 9);
3638 auto validate_scope =
3639 ValidateOperandLexicalScope(_, "Scope", inst, 10, ext_inst_name);
3640 if (validate_scope != SPV_SUCCESS) return validate_scope;
3641 CHECK_OPERAND("Linkage Name", spv::Op::OpString, 11);
3642 if (!DoesDebugInfoOperandMatchExpectation(
3644 [](CommonDebugInfoInstructions dbg_inst) {
3645 return dbg_inst == CommonDebugInfoDebugInfoNone;
3647 inst, 12)) {
3648 auto* operand = _.FindDef(inst->word(12));
3649 if (operand->opcode() != spv::Op::OpVariable &&
3650 operand->opcode() != spv::Op::OpConstant) {
3651 return _.diag(SPV_ERROR_INVALID_DATA, inst)
3652 << ext_inst_name() << ": "
3653 << "expected operand Variable must be a result id of "
3654 "OpVariable or OpConstant or DebugInfoNone";
3657 if (num_words == 15) {
3658 CHECK_DEBUG_OPERAND("Static Member Declaration",
3659 CommonDebugInfoDebugTypeMember, 14);
3661 break;
3663 case CommonDebugInfoDebugInlinedAt: {
3664 CHECK_CONST_UINT_OPERAND("Line", 5);
3665 auto validate_scope =
3666 ValidateOperandLexicalScope(_, "Scope", inst, 6, ext_inst_name);
3667 if (validate_scope != SPV_SUCCESS) return validate_scope;
3668 if (num_words == 8) {
3669 CHECK_DEBUG_OPERAND("Inlined", CommonDebugInfoDebugInlinedAt, 7);
3671 break;
3673 case CommonDebugInfoDebugValue: {
3674 CHECK_DEBUG_OPERAND("Local Variable",
3675 CommonDebugInfoDebugLocalVariable, 5);
3676 CHECK_DEBUG_OPERAND("Expression", CommonDebugInfoDebugExpression, 7);
3678 for (uint32_t word_index = 8; word_index < num_words; ++word_index) {
3679 // TODO: The following code simply checks if it is a const int
3680 // scalar or a DebugLocalVariable or DebugGlobalVariable, but we
3681 // have to check it using the same validation for Indexes of
3682 // OpAccessChain.
3683 if (!IsConstWithIntScalarType(_, inst, word_index) &&
3684 !IsDebugVariableWithIntScalarType(_, inst, word_index)) {
3685 return _.diag(SPV_ERROR_INVALID_DATA, inst)
3686 << ext_inst_name() << ": expected operand Indexes is "
3687 << "OpConstant, DebugGlobalVariable, or "
3688 << "type is OpConstant with an integer scalar type";
3691 break;
3694 // TODO: Add validation rules for remaining cases as well.
3695 case CommonDebugInfoDebugTypePtrToMember:
3696 case CommonDebugInfoDebugTypeTemplateTemplateParameter:
3697 case CommonDebugInfoDebugTypeTemplateParameterPack:
3698 case CommonDebugInfoDebugLexicalBlockDiscriminator:
3699 case CommonDebugInfoDebugInlinedVariable:
3700 case CommonDebugInfoDebugMacroDef:
3701 case CommonDebugInfoDebugMacroUndef:
3702 case CommonDebugInfoDebugImportedEntity:
3703 break;
3704 case CommonDebugInfoInstructionsMax:
3705 assert(0);
3706 break;
3709 } else if (ext_inst_type == SPV_EXT_INST_TYPE_NONSEMANTIC_CLSPVREFLECTION) {
3710 auto import_inst = _.FindDef(inst->GetOperandAs<uint32_t>(2));
3711 const std::string name = import_inst->GetOperandAs<std::string>(1);
3712 const std::string reflection = "NonSemantic.ClspvReflection.";
3713 char* end_ptr;
3714 auto version_string = name.substr(reflection.size());
3715 if (version_string.empty()) {
3716 return _.diag(SPV_ERROR_INVALID_DATA, import_inst)
3717 << "Missing NonSemantic.ClspvReflection import version";
3719 uint32_t version = static_cast<uint32_t>(
3720 std::strtoul(version_string.c_str(), &end_ptr, 10));
3721 if (end_ptr && *end_ptr != '\0') {
3722 return _.diag(SPV_ERROR_INVALID_DATA, import_inst)
3723 << "NonSemantic.ClspvReflection import does not encode the "
3724 "version correctly";
3726 if (version == 0 || version > NonSemanticClspvReflectionRevision) {
3727 return _.diag(SPV_ERROR_INVALID_DATA, import_inst)
3728 << "Unknown NonSemantic.ClspvReflection import version";
3731 return ValidateClspvReflectionInstruction(_, inst, version);
3734 return SPV_SUCCESS;
3737 spv_result_t ExtensionPass(ValidationState_t& _, const Instruction* inst) {
3738 const spv::Op opcode = inst->opcode();
3739 if (opcode == spv::Op::OpExtension) return ValidateExtension(_, inst);
3740 if (opcode == spv::Op::OpExtInstImport) return ValidateExtInstImport(_, inst);
3741 if (spvIsExtendedInstruction(opcode)) return ValidateExtInst(_, inst);
3743 return SPV_SUCCESS;
3746 } // namespace val
3747 } // namespace spvtools