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