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