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 | |
17 | #include <sstream> |
18 | #include <string> |
19 | #include <vector> |
20 | |
21 | #include "OpenCLDebugInfo100.h" |
22 | #include "source/diagnostic.h" |
23 | #include "source/enum_string_mapping.h" |
24 | #include "source/extensions.h" |
25 | #include "source/latest_version_glsl_std_450_header.h" |
26 | #include "source/latest_version_opencl_std_header.h" |
27 | #include "source/opcode.h" |
28 | #include "source/spirv_target_env.h" |
29 | #include "source/val/instruction.h" |
30 | #include "source/val/validate.h" |
31 | #include "source/val/validation_state.h" |
32 | |
33 | namespace spvtools { |
34 | namespace val { |
35 | namespace { |
36 | |
37 | uint32_t GetSizeTBitWidth(const ValidationState_t& _) { |
38 | if (_.addressing_model() == SpvAddressingModelPhysical32) return 32; |
39 | |
40 | if (_.addressing_model() == SpvAddressingModelPhysical64) return 64; |
41 | |
42 | return 0; |
43 | } |
44 | |
45 | // Check that the operand of a debug info instruction |inst| at |word_index| |
46 | // is a result id of an instruction with |expected_opcode|. |
47 | spv_result_t ValidateOperandForDebugInfo( |
48 | ValidationState_t& _, const std::string& operand_name, |
49 | SpvOp expected_opcode, const Instruction* inst, uint32_t word_index, |
50 | const std::function<std::string()>& ext_inst_name) { |
51 | auto* operand = _.FindDef(inst->word(word_index)); |
52 | if (operand->opcode() != expected_opcode) { |
53 | spv_opcode_desc desc = nullptr; |
54 | if (_.grammar().lookupOpcode(expected_opcode, &desc) != SPV_SUCCESS || |
55 | !desc) { |
56 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
57 | << ext_inst_name() << ": " |
58 | << "expected operand " << operand_name << " is invalid" ; |
59 | } |
60 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
61 | << ext_inst_name() << ": " |
62 | << "expected operand " << operand_name << " must be a result id of " |
63 | << "Op" << desc->name; |
64 | } |
65 | return SPV_SUCCESS; |
66 | } |
67 | |
68 | #define CHECK_OPERAND(NAME, opcode, index) \ |
69 | do { \ |
70 | auto result = ValidateOperandForDebugInfo(_, NAME, opcode, inst, index, \ |
71 | ext_inst_name); \ |
72 | if (result != SPV_SUCCESS) return result; \ |
73 | } while (0) |
74 | |
75 | // True if the operand of a debug info instruction |inst| at |word_index| |
76 | // satisifies |expectation| that is given as a function. Otherwise, |
77 | // returns false. |
78 | bool DoesDebugInfoOperandMatchExpectation( |
79 | const ValidationState_t& _, |
80 | const std::function<bool(OpenCLDebugInfo100Instructions)>& expectation, |
81 | const Instruction* inst, uint32_t word_index) { |
82 | auto* debug_inst = _.FindDef(inst->word(word_index)); |
83 | if (debug_inst->opcode() != SpvOpExtInst || |
84 | debug_inst->ext_inst_type() != SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100 || |
85 | !expectation(OpenCLDebugInfo100Instructions(debug_inst->word(4)))) { |
86 | return false; |
87 | } |
88 | return true; |
89 | } |
90 | |
91 | // Check that the operand of a debug info instruction |inst| at |word_index| |
92 | // is a result id of an debug info instruction whose debug instruction type |
93 | // is |expected_debug_inst|. |
94 | spv_result_t ValidateDebugInfoOperand( |
95 | ValidationState_t& _, const std::string& debug_inst_name, |
96 | OpenCLDebugInfo100Instructions expected_debug_inst, const Instruction* inst, |
97 | uint32_t word_index, const std::function<std::string()>& ext_inst_name) { |
98 | std::function<bool(OpenCLDebugInfo100Instructions)> expectation = |
99 | [expected_debug_inst](OpenCLDebugInfo100Instructions dbg_inst) { |
100 | return dbg_inst == expected_debug_inst; |
101 | }; |
102 | if (DoesDebugInfoOperandMatchExpectation(_, expectation, inst, word_index)) |
103 | return SPV_SUCCESS; |
104 | |
105 | spv_ext_inst_desc desc = nullptr; |
106 | _.grammar().lookupExtInst(SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100, |
107 | expected_debug_inst, &desc); |
108 | if (_.grammar().lookupExtInst(SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100, |
109 | expected_debug_inst, &desc) != SPV_SUCCESS || |
110 | !desc) { |
111 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
112 | << ext_inst_name() << ": " |
113 | << "expected operand " << debug_inst_name << " is invalid" ; |
114 | } |
115 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
116 | << ext_inst_name() << ": " |
117 | << "expected operand " << debug_inst_name << " must be a result id of " |
118 | << desc->name; |
119 | } |
120 | |
121 | #define CHECK_DEBUG_OPERAND(NAME, debug_opcode, index) \ |
122 | do { \ |
123 | auto result = ValidateDebugInfoOperand(_, NAME, debug_opcode, inst, index, \ |
124 | ext_inst_name); \ |
125 | if (result != SPV_SUCCESS) return result; \ |
126 | } while (0) |
127 | |
128 | // Check that the operand of a debug info instruction |inst| at |word_index| |
129 | // is a result id of an debug info instruction with DebugTypeBasic. |
130 | spv_result_t ValidateOperandBaseType( |
131 | ValidationState_t& _, const Instruction* inst, uint32_t word_index, |
132 | const std::function<std::string()>& ext_inst_name) { |
133 | return ValidateDebugInfoOperand(_, "Base Type" , |
134 | OpenCLDebugInfo100DebugTypeBasic, inst, |
135 | word_index, ext_inst_name); |
136 | } |
137 | |
138 | // Check that the operand of a debug info instruction |inst| at |word_index| |
139 | // is a result id of a debug lexical scope instruction which is one of |
140 | // DebugCompilationUnit, DebugFunction, DebugLexicalBlock, or |
141 | // DebugTypeComposite. |
142 | spv_result_t ValidateOperandLexicalScope( |
143 | ValidationState_t& _, const std::string& debug_inst_name, |
144 | const Instruction* inst, uint32_t word_index, |
145 | const std::function<std::string()>& ext_inst_name) { |
146 | std::function<bool(OpenCLDebugInfo100Instructions)> expectation = |
147 | [](OpenCLDebugInfo100Instructions dbg_inst) { |
148 | return dbg_inst == OpenCLDebugInfo100DebugCompilationUnit || |
149 | dbg_inst == OpenCLDebugInfo100DebugFunction || |
150 | dbg_inst == OpenCLDebugInfo100DebugLexicalBlock || |
151 | dbg_inst == OpenCLDebugInfo100DebugTypeComposite; |
152 | }; |
153 | if (DoesDebugInfoOperandMatchExpectation(_, expectation, inst, word_index)) |
154 | return SPV_SUCCESS; |
155 | |
156 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
157 | << ext_inst_name() << ": " |
158 | << "expected operand " << debug_inst_name |
159 | << " must be a result id of a lexical scope" ; |
160 | } |
161 | |
162 | // Check that the operand of a debug info instruction |inst| at |word_index| |
163 | // is a result id of a debug type instruction (See DebugTypeXXX in |
164 | // "4.3. Type instructions" section of OpenCL.DebugInfo.100 spec. |
165 | spv_result_t ValidateOperandDebugType( |
166 | ValidationState_t& _, const std::string& debug_inst_name, |
167 | const Instruction* inst, uint32_t word_index, |
168 | const std::function<std::string()>& ext_inst_name) { |
169 | std::function<bool(OpenCLDebugInfo100Instructions)> expectation = |
170 | [](OpenCLDebugInfo100Instructions dbg_inst) { |
171 | return OpenCLDebugInfo100DebugTypeBasic <= dbg_inst && |
172 | dbg_inst <= OpenCLDebugInfo100DebugTypePtrToMember; |
173 | }; |
174 | if (DoesDebugInfoOperandMatchExpectation(_, expectation, inst, word_index)) |
175 | return SPV_SUCCESS; |
176 | |
177 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
178 | << ext_inst_name() << ": " |
179 | << "expected operand " << debug_inst_name |
180 | << " is not a valid debug type" ; |
181 | } |
182 | |
183 | } // anonymous namespace |
184 | |
185 | spv_result_t ValidateExtension(ValidationState_t& _, const Instruction* inst) { |
186 | if (spvIsWebGPUEnv(_.context()->target_env)) { |
187 | std::string extension = GetExtensionString(&(inst->c_inst())); |
188 | |
189 | if (extension != ExtensionToString(kSPV_KHR_vulkan_memory_model)) { |
190 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
191 | << "For WebGPU, the only valid parameter to OpExtension is " |
192 | << "\"" << ExtensionToString(kSPV_KHR_vulkan_memory_model) |
193 | << "\"." ; |
194 | } |
195 | } |
196 | |
197 | return SPV_SUCCESS; |
198 | } |
199 | |
200 | spv_result_t ValidateExtInstImport(ValidationState_t& _, |
201 | const Instruction* inst) { |
202 | const auto name_id = 1; |
203 | if (spvIsWebGPUEnv(_.context()->target_env)) { |
204 | const std::string name(reinterpret_cast<const char*>( |
205 | inst->words().data() + inst->operands()[name_id].offset)); |
206 | if (name != "GLSL.std.450" ) { |
207 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
208 | << "For WebGPU, the only valid parameter to OpExtInstImport is " |
209 | "\"GLSL.std.450\"." ; |
210 | } |
211 | } |
212 | |
213 | if (!_.HasExtension(kSPV_KHR_non_semantic_info)) { |
214 | const std::string name(reinterpret_cast<const char*>( |
215 | inst->words().data() + inst->operands()[name_id].offset)); |
216 | if (name.find("NonSemantic." ) == 0) { |
217 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
218 | << "NonSemantic extended instruction sets cannot be declared " |
219 | "without SPV_KHR_non_semantic_info." ; |
220 | } |
221 | } |
222 | |
223 | return SPV_SUCCESS; |
224 | } |
225 | |
226 | spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) { |
227 | const uint32_t result_type = inst->type_id(); |
228 | const uint32_t num_operands = static_cast<uint32_t>(inst->operands().size()); |
229 | |
230 | const uint32_t ext_inst_set = inst->word(3); |
231 | const uint32_t ext_inst_index = inst->word(4); |
232 | const spv_ext_inst_type_t ext_inst_type = |
233 | spv_ext_inst_type_t(inst->ext_inst_type()); |
234 | |
235 | auto ext_inst_name = [&_, ext_inst_set, ext_inst_type, ext_inst_index]() { |
236 | spv_ext_inst_desc desc = nullptr; |
237 | if (_.grammar().lookupExtInst(ext_inst_type, ext_inst_index, &desc) != |
238 | SPV_SUCCESS || |
239 | !desc) { |
240 | return std::string("Unknown ExtInst" ); |
241 | } |
242 | |
243 | auto* import_inst = _.FindDef(ext_inst_set); |
244 | assert(import_inst); |
245 | |
246 | std::ostringstream ss; |
247 | ss << reinterpret_cast<const char*>(import_inst->words().data() + 2); |
248 | ss << " " ; |
249 | ss << desc->name; |
250 | |
251 | return ss.str(); |
252 | }; |
253 | |
254 | if (ext_inst_type == SPV_EXT_INST_TYPE_GLSL_STD_450) { |
255 | const GLSLstd450 ext_inst_key = GLSLstd450(ext_inst_index); |
256 | switch (ext_inst_key) { |
257 | case GLSLstd450Round: |
258 | case GLSLstd450RoundEven: |
259 | case GLSLstd450FAbs: |
260 | case GLSLstd450Trunc: |
261 | case GLSLstd450FSign: |
262 | case GLSLstd450Floor: |
263 | case GLSLstd450Ceil: |
264 | case GLSLstd450Fract: |
265 | case GLSLstd450Sqrt: |
266 | case GLSLstd450InverseSqrt: |
267 | case GLSLstd450FMin: |
268 | case GLSLstd450FMax: |
269 | case GLSLstd450FClamp: |
270 | case GLSLstd450FMix: |
271 | case GLSLstd450Step: |
272 | case GLSLstd450SmoothStep: |
273 | case GLSLstd450Fma: |
274 | case GLSLstd450Normalize: |
275 | case GLSLstd450FaceForward: |
276 | case GLSLstd450Reflect: |
277 | case GLSLstd450NMin: |
278 | case GLSLstd450NMax: |
279 | case GLSLstd450NClamp: { |
280 | if (!_.IsFloatScalarOrVectorType(result_type)) { |
281 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
282 | << ext_inst_name() << ": " |
283 | << "expected Result Type to be a float scalar or vector type" ; |
284 | } |
285 | |
286 | for (uint32_t operand_index = 4; operand_index < num_operands; |
287 | ++operand_index) { |
288 | const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index); |
289 | if (result_type != operand_type) { |
290 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
291 | << ext_inst_name() << ": " |
292 | << "expected types of all operands to be equal to Result " |
293 | "Type" ; |
294 | } |
295 | } |
296 | break; |
297 | } |
298 | |
299 | case GLSLstd450SAbs: |
300 | case GLSLstd450SSign: |
301 | case GLSLstd450UMin: |
302 | case GLSLstd450SMin: |
303 | case GLSLstd450UMax: |
304 | case GLSLstd450SMax: |
305 | case GLSLstd450UClamp: |
306 | case GLSLstd450SClamp: |
307 | case GLSLstd450FindILsb: |
308 | case GLSLstd450FindUMsb: |
309 | case GLSLstd450FindSMsb: { |
310 | if (!_.IsIntScalarOrVectorType(result_type)) { |
311 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
312 | << ext_inst_name() << ": " |
313 | << "expected Result Type to be an int scalar or vector type" ; |
314 | } |
315 | |
316 | const uint32_t result_type_bit_width = _.GetBitWidth(result_type); |
317 | const uint32_t result_type_dimension = _.GetDimension(result_type); |
318 | |
319 | for (uint32_t operand_index = 4; operand_index < num_operands; |
320 | ++operand_index) { |
321 | const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index); |
322 | if (!_.IsIntScalarOrVectorType(operand_type)) { |
323 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
324 | << ext_inst_name() << ": " |
325 | << "expected all operands to be int scalars or vectors" ; |
326 | } |
327 | |
328 | if (result_type_dimension != _.GetDimension(operand_type)) { |
329 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
330 | << ext_inst_name() << ": " |
331 | << "expected all operands to have the same dimension as " |
332 | << "Result Type" ; |
333 | } |
334 | |
335 | if (result_type_bit_width != _.GetBitWidth(operand_type)) { |
336 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
337 | << ext_inst_name() << ": " |
338 | << "expected all operands to have the same bit width as " |
339 | << "Result Type" ; |
340 | } |
341 | |
342 | if (ext_inst_key == GLSLstd450FindUMsb || |
343 | ext_inst_key == GLSLstd450FindSMsb) { |
344 | if (result_type_bit_width != 32) { |
345 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
346 | << ext_inst_name() << ": " |
347 | << "this instruction is currently limited to 32-bit width " |
348 | << "components" ; |
349 | } |
350 | } |
351 | } |
352 | break; |
353 | } |
354 | |
355 | case GLSLstd450Radians: |
356 | case GLSLstd450Degrees: |
357 | case GLSLstd450Sin: |
358 | case GLSLstd450Cos: |
359 | case GLSLstd450Tan: |
360 | case GLSLstd450Asin: |
361 | case GLSLstd450Acos: |
362 | case GLSLstd450Atan: |
363 | case GLSLstd450Sinh: |
364 | case GLSLstd450Cosh: |
365 | case GLSLstd450Tanh: |
366 | case GLSLstd450Asinh: |
367 | case GLSLstd450Acosh: |
368 | case GLSLstd450Atanh: |
369 | case GLSLstd450Exp: |
370 | case GLSLstd450Exp2: |
371 | case GLSLstd450Log: |
372 | case GLSLstd450Log2: |
373 | case GLSLstd450Atan2: |
374 | case GLSLstd450Pow: { |
375 | if (!_.IsFloatScalarOrVectorType(result_type)) { |
376 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
377 | << ext_inst_name() << ": " |
378 | << "expected Result Type to be a 16 or 32-bit scalar or " |
379 | "vector float type" ; |
380 | } |
381 | |
382 | const uint32_t result_type_bit_width = _.GetBitWidth(result_type); |
383 | if (result_type_bit_width != 16 && result_type_bit_width != 32) { |
384 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
385 | << ext_inst_name() << ": " |
386 | << "expected Result Type to be a 16 or 32-bit scalar or " |
387 | "vector float type" ; |
388 | } |
389 | |
390 | for (uint32_t operand_index = 4; operand_index < num_operands; |
391 | ++operand_index) { |
392 | const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index); |
393 | if (result_type != operand_type) { |
394 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
395 | << ext_inst_name() << ": " |
396 | << "expected types of all operands to be equal to Result " |
397 | "Type" ; |
398 | } |
399 | } |
400 | break; |
401 | } |
402 | |
403 | case GLSLstd450Determinant: { |
404 | const uint32_t x_type = _.GetOperandTypeId(inst, 4); |
405 | uint32_t num_rows = 0; |
406 | uint32_t num_cols = 0; |
407 | uint32_t col_type = 0; |
408 | uint32_t component_type = 0; |
409 | if (!_.GetMatrixTypeInfo(x_type, &num_rows, &num_cols, &col_type, |
410 | &component_type) || |
411 | num_rows != num_cols) { |
412 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
413 | << ext_inst_name() << ": " |
414 | << "expected operand X to be a square matrix" ; |
415 | } |
416 | |
417 | if (result_type != component_type) { |
418 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
419 | << ext_inst_name() << ": " |
420 | << "expected operand X component type to be equal to " |
421 | << "Result Type" ; |
422 | } |
423 | break; |
424 | } |
425 | |
426 | case GLSLstd450MatrixInverse: { |
427 | uint32_t num_rows = 0; |
428 | uint32_t num_cols = 0; |
429 | uint32_t col_type = 0; |
430 | uint32_t component_type = 0; |
431 | if (!_.GetMatrixTypeInfo(result_type, &num_rows, &num_cols, &col_type, |
432 | &component_type) || |
433 | num_rows != num_cols) { |
434 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
435 | << ext_inst_name() << ": " |
436 | << "expected Result Type to be a square matrix" ; |
437 | } |
438 | |
439 | const uint32_t x_type = _.GetOperandTypeId(inst, 4); |
440 | if (result_type != x_type) { |
441 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
442 | << ext_inst_name() << ": " |
443 | << "expected operand X type to be equal to Result Type" ; |
444 | } |
445 | break; |
446 | } |
447 | |
448 | case GLSLstd450Modf: { |
449 | if (!_.IsFloatScalarOrVectorType(result_type)) { |
450 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
451 | << ext_inst_name() << ": " |
452 | << "expected Result Type to be a scalar or vector float type" ; |
453 | } |
454 | |
455 | const uint32_t x_type = _.GetOperandTypeId(inst, 4); |
456 | const uint32_t i_type = _.GetOperandTypeId(inst, 5); |
457 | |
458 | if (x_type != result_type) { |
459 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
460 | << ext_inst_name() << ": " |
461 | << "expected operand X type to be equal to Result Type" ; |
462 | } |
463 | |
464 | uint32_t i_storage_class = 0; |
465 | uint32_t i_data_type = 0; |
466 | if (!_.GetPointerTypeInfo(i_type, &i_data_type, &i_storage_class)) { |
467 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
468 | << ext_inst_name() << ": " |
469 | << "expected operand I to be a pointer" ; |
470 | } |
471 | |
472 | if (i_data_type != result_type) { |
473 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
474 | << ext_inst_name() << ": " |
475 | << "expected operand I data type to be equal to Result Type" ; |
476 | } |
477 | |
478 | break; |
479 | } |
480 | |
481 | case GLSLstd450ModfStruct: { |
482 | std::vector<uint32_t> result_types; |
483 | if (!_.GetStructMemberTypes(result_type, &result_types) || |
484 | result_types.size() != 2 || |
485 | !_.IsFloatScalarOrVectorType(result_types[0]) || |
486 | result_types[1] != result_types[0]) { |
487 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
488 | << ext_inst_name() << ": " |
489 | << "expected Result Type to be a struct with two identical " |
490 | << "scalar or vector float type members" ; |
491 | } |
492 | |
493 | const uint32_t x_type = _.GetOperandTypeId(inst, 4); |
494 | if (x_type != result_types[0]) { |
495 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
496 | << ext_inst_name() << ": " |
497 | << "expected operand X type to be equal to members of " |
498 | << "Result Type struct" ; |
499 | } |
500 | break; |
501 | } |
502 | |
503 | case GLSLstd450Frexp: { |
504 | if (!_.IsFloatScalarOrVectorType(result_type)) { |
505 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
506 | << ext_inst_name() << ": " |
507 | << "expected Result Type to be a scalar or vector float type" ; |
508 | } |
509 | |
510 | const uint32_t x_type = _.GetOperandTypeId(inst, 4); |
511 | const uint32_t exp_type = _.GetOperandTypeId(inst, 5); |
512 | |
513 | if (x_type != result_type) { |
514 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
515 | << ext_inst_name() << ": " |
516 | << "expected operand X type to be equal to Result Type" ; |
517 | } |
518 | |
519 | uint32_t exp_storage_class = 0; |
520 | uint32_t exp_data_type = 0; |
521 | if (!_.GetPointerTypeInfo(exp_type, &exp_data_type, |
522 | &exp_storage_class)) { |
523 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
524 | << ext_inst_name() << ": " |
525 | << "expected operand Exp to be a pointer" ; |
526 | } |
527 | |
528 | if (!_.IsIntScalarOrVectorType(exp_data_type) || |
529 | (!_.HasExtension(kSPV_AMD_gpu_shader_int16) && |
530 | _.GetBitWidth(exp_data_type) != 32) || |
531 | (_.HasExtension(kSPV_AMD_gpu_shader_int16) && |
532 | _.GetBitWidth(exp_data_type) != 16 && |
533 | _.GetBitWidth(exp_data_type) != 32)) { |
534 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
535 | << ext_inst_name() << ": " |
536 | << "expected operand Exp data type to be a " |
537 | << (_.HasExtension(kSPV_AMD_gpu_shader_int16) |
538 | ? "16-bit or 32-bit " |
539 | : "32-bit " ) |
540 | << "int scalar or vector type" ; |
541 | } |
542 | |
543 | if (_.GetDimension(result_type) != _.GetDimension(exp_data_type)) { |
544 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
545 | << ext_inst_name() << ": " |
546 | << "expected operand Exp data type to have the same component " |
547 | << "number as Result Type" ; |
548 | } |
549 | |
550 | break; |
551 | } |
552 | |
553 | case GLSLstd450Ldexp: { |
554 | if (!_.IsFloatScalarOrVectorType(result_type)) { |
555 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
556 | << ext_inst_name() << ": " |
557 | << "expected Result Type to be a scalar or vector float type" ; |
558 | } |
559 | |
560 | const uint32_t x_type = _.GetOperandTypeId(inst, 4); |
561 | const uint32_t exp_type = _.GetOperandTypeId(inst, 5); |
562 | |
563 | if (x_type != result_type) { |
564 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
565 | << ext_inst_name() << ": " |
566 | << "expected operand X type to be equal to Result Type" ; |
567 | } |
568 | |
569 | if (!_.IsIntScalarOrVectorType(exp_type)) { |
570 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
571 | << ext_inst_name() << ": " |
572 | << "expected operand Exp to be a 32-bit int scalar " |
573 | << "or vector type" ; |
574 | } |
575 | |
576 | if (_.GetDimension(result_type) != _.GetDimension(exp_type)) { |
577 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
578 | << ext_inst_name() << ": " |
579 | << "expected operand Exp to have the same component " |
580 | << "number as Result Type" ; |
581 | } |
582 | |
583 | break; |
584 | } |
585 | |
586 | case GLSLstd450FrexpStruct: { |
587 | std::vector<uint32_t> result_types; |
588 | if (!_.GetStructMemberTypes(result_type, &result_types) || |
589 | result_types.size() != 2 || |
590 | !_.IsFloatScalarOrVectorType(result_types[0]) || |
591 | !_.IsIntScalarOrVectorType(result_types[1]) || |
592 | (!_.HasExtension(kSPV_AMD_gpu_shader_int16) && |
593 | _.GetBitWidth(result_types[1]) != 32) || |
594 | (_.HasExtension(kSPV_AMD_gpu_shader_int16) && |
595 | _.GetBitWidth(result_types[1]) != 16 && |
596 | _.GetBitWidth(result_types[1]) != 32) || |
597 | _.GetDimension(result_types[0]) != |
598 | _.GetDimension(result_types[1])) { |
599 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
600 | << ext_inst_name() << ": " |
601 | << "expected Result Type to be a struct with two members, " |
602 | << "first member a float scalar or vector, second member a " |
603 | << (_.HasExtension(kSPV_AMD_gpu_shader_int16) |
604 | ? "16-bit or 32-bit " |
605 | : "32-bit " ) |
606 | << "int scalar or vector with the same number of " |
607 | << "components as the first member" ; |
608 | } |
609 | |
610 | const uint32_t x_type = _.GetOperandTypeId(inst, 4); |
611 | if (x_type != result_types[0]) { |
612 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
613 | << ext_inst_name() << ": " |
614 | << "expected operand X type to be equal to the first member " |
615 | << "of Result Type struct" ; |
616 | } |
617 | break; |
618 | } |
619 | |
620 | case GLSLstd450PackSnorm4x8: |
621 | case GLSLstd450PackUnorm4x8: { |
622 | if (!_.IsIntScalarType(result_type) || |
623 | _.GetBitWidth(result_type) != 32) { |
624 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
625 | << ext_inst_name() << ": " |
626 | << "expected Result Type to be 32-bit int scalar type" ; |
627 | } |
628 | |
629 | const uint32_t v_type = _.GetOperandTypeId(inst, 4); |
630 | if (!_.IsFloatVectorType(v_type) || _.GetDimension(v_type) != 4 || |
631 | _.GetBitWidth(v_type) != 32) { |
632 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
633 | << ext_inst_name() << ": " |
634 | << "expected operand V to be a 32-bit float vector of size 4" ; |
635 | } |
636 | break; |
637 | } |
638 | |
639 | case GLSLstd450PackSnorm2x16: |
640 | case GLSLstd450PackUnorm2x16: |
641 | case GLSLstd450PackHalf2x16: { |
642 | if (!_.IsIntScalarType(result_type) || |
643 | _.GetBitWidth(result_type) != 32) { |
644 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
645 | << ext_inst_name() << ": " |
646 | << "expected Result Type to be 32-bit int scalar type" ; |
647 | } |
648 | |
649 | const uint32_t v_type = _.GetOperandTypeId(inst, 4); |
650 | if (!_.IsFloatVectorType(v_type) || _.GetDimension(v_type) != 2 || |
651 | _.GetBitWidth(v_type) != 32) { |
652 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
653 | << ext_inst_name() << ": " |
654 | << "expected operand V to be a 32-bit float vector of size 2" ; |
655 | } |
656 | break; |
657 | } |
658 | |
659 | case GLSLstd450PackDouble2x32: { |
660 | if (!_.IsFloatScalarType(result_type) || |
661 | _.GetBitWidth(result_type) != 64) { |
662 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
663 | << ext_inst_name() << ": " |
664 | << "expected Result Type to be 64-bit float scalar type" ; |
665 | } |
666 | |
667 | const uint32_t v_type = _.GetOperandTypeId(inst, 4); |
668 | if (!_.IsIntVectorType(v_type) || _.GetDimension(v_type) != 2 || |
669 | _.GetBitWidth(v_type) != 32) { |
670 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
671 | << ext_inst_name() << ": " |
672 | << "expected operand V to be a 32-bit int vector of size 2" ; |
673 | } |
674 | break; |
675 | } |
676 | |
677 | case GLSLstd450UnpackSnorm4x8: |
678 | case GLSLstd450UnpackUnorm4x8: { |
679 | if (!_.IsFloatVectorType(result_type) || |
680 | _.GetDimension(result_type) != 4 || |
681 | _.GetBitWidth(result_type) != 32) { |
682 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
683 | << ext_inst_name() << ": " |
684 | << "expected Result Type to be a 32-bit float vector of size " |
685 | "4" ; |
686 | } |
687 | |
688 | const uint32_t v_type = _.GetOperandTypeId(inst, 4); |
689 | if (!_.IsIntScalarType(v_type) || _.GetBitWidth(v_type) != 32) { |
690 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
691 | << ext_inst_name() << ": " |
692 | << "expected operand P to be a 32-bit int scalar" ; |
693 | } |
694 | break; |
695 | } |
696 | |
697 | case GLSLstd450UnpackSnorm2x16: |
698 | case GLSLstd450UnpackUnorm2x16: |
699 | case GLSLstd450UnpackHalf2x16: { |
700 | if (!_.IsFloatVectorType(result_type) || |
701 | _.GetDimension(result_type) != 2 || |
702 | _.GetBitWidth(result_type) != 32) { |
703 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
704 | << ext_inst_name() << ": " |
705 | << "expected Result Type to be a 32-bit float vector of size " |
706 | "2" ; |
707 | } |
708 | |
709 | const uint32_t v_type = _.GetOperandTypeId(inst, 4); |
710 | if (!_.IsIntScalarType(v_type) || _.GetBitWidth(v_type) != 32) { |
711 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
712 | << ext_inst_name() << ": " |
713 | << "expected operand P to be a 32-bit int scalar" ; |
714 | } |
715 | break; |
716 | } |
717 | |
718 | case GLSLstd450UnpackDouble2x32: { |
719 | if (!_.IsIntVectorType(result_type) || |
720 | _.GetDimension(result_type) != 2 || |
721 | _.GetBitWidth(result_type) != 32) { |
722 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
723 | << ext_inst_name() << ": " |
724 | << "expected Result Type to be a 32-bit int vector of size " |
725 | "2" ; |
726 | } |
727 | |
728 | const uint32_t v_type = _.GetOperandTypeId(inst, 4); |
729 | if (!_.IsFloatScalarType(v_type) || _.GetBitWidth(v_type) != 64) { |
730 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
731 | << ext_inst_name() << ": " |
732 | << "expected operand V to be a 64-bit float scalar" ; |
733 | } |
734 | break; |
735 | } |
736 | |
737 | case GLSLstd450Length: { |
738 | if (!_.IsFloatScalarType(result_type)) { |
739 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
740 | << ext_inst_name() << ": " |
741 | << "expected Result Type to be a float scalar type" ; |
742 | } |
743 | |
744 | const uint32_t x_type = _.GetOperandTypeId(inst, 4); |
745 | if (!_.IsFloatScalarOrVectorType(x_type)) { |
746 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
747 | << ext_inst_name() << ": " |
748 | << "expected operand X to be of float scalar or vector type" ; |
749 | } |
750 | |
751 | if (result_type != _.GetComponentType(x_type)) { |
752 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
753 | << ext_inst_name() << ": " |
754 | << "expected operand X component type to be equal to Result " |
755 | "Type" ; |
756 | } |
757 | break; |
758 | } |
759 | |
760 | case GLSLstd450Distance: { |
761 | if (!_.IsFloatScalarType(result_type)) { |
762 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
763 | << ext_inst_name() << ": " |
764 | << "expected Result Type to be a float scalar type" ; |
765 | } |
766 | |
767 | const uint32_t p0_type = _.GetOperandTypeId(inst, 4); |
768 | if (!_.IsFloatScalarOrVectorType(p0_type)) { |
769 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
770 | << ext_inst_name() << ": " |
771 | << "expected operand P0 to be of float scalar or vector type" ; |
772 | } |
773 | |
774 | if (result_type != _.GetComponentType(p0_type)) { |
775 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
776 | << ext_inst_name() << ": " |
777 | << "expected operand P0 component type to be equal to " |
778 | << "Result Type" ; |
779 | } |
780 | |
781 | const uint32_t p1_type = _.GetOperandTypeId(inst, 5); |
782 | if (!_.IsFloatScalarOrVectorType(p1_type)) { |
783 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
784 | << ext_inst_name() << ": " |
785 | << "expected operand P1 to be of float scalar or vector type" ; |
786 | } |
787 | |
788 | if (result_type != _.GetComponentType(p1_type)) { |
789 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
790 | << ext_inst_name() << ": " |
791 | << "expected operand P1 component type to be equal to " |
792 | << "Result Type" ; |
793 | } |
794 | |
795 | if (_.GetDimension(p0_type) != _.GetDimension(p1_type)) { |
796 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
797 | << ext_inst_name() << ": " |
798 | << "expected operands P0 and P1 to have the same number of " |
799 | << "components" ; |
800 | } |
801 | break; |
802 | } |
803 | |
804 | case GLSLstd450Cross: { |
805 | if (!_.IsFloatVectorType(result_type)) { |
806 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
807 | << ext_inst_name() << ": " |
808 | << "expected Result Type to be a float vector type" ; |
809 | } |
810 | |
811 | if (_.GetDimension(result_type) != 3) { |
812 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
813 | << ext_inst_name() << ": " |
814 | << "expected Result Type to have 3 components" ; |
815 | } |
816 | |
817 | const uint32_t x_type = _.GetOperandTypeId(inst, 4); |
818 | const uint32_t y_type = _.GetOperandTypeId(inst, 5); |
819 | |
820 | if (x_type != result_type) { |
821 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
822 | << ext_inst_name() << ": " |
823 | << "expected operand X type to be equal to Result Type" ; |
824 | } |
825 | |
826 | if (y_type != result_type) { |
827 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
828 | << ext_inst_name() << ": " |
829 | << "expected operand Y type to be equal to Result Type" ; |
830 | } |
831 | break; |
832 | } |
833 | |
834 | case GLSLstd450Refract: { |
835 | if (!_.IsFloatScalarOrVectorType(result_type)) { |
836 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
837 | << ext_inst_name() << ": " |
838 | << "expected Result Type to be a float scalar or vector type" ; |
839 | } |
840 | |
841 | const uint32_t i_type = _.GetOperandTypeId(inst, 4); |
842 | const uint32_t n_type = _.GetOperandTypeId(inst, 5); |
843 | const uint32_t eta_type = _.GetOperandTypeId(inst, 6); |
844 | |
845 | if (result_type != i_type) { |
846 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
847 | << ext_inst_name() << ": " |
848 | << "expected operand I to be of type equal to Result Type" ; |
849 | } |
850 | |
851 | if (result_type != n_type) { |
852 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
853 | << ext_inst_name() << ": " |
854 | << "expected operand N to be of type equal to Result Type" ; |
855 | } |
856 | |
857 | if (!_.IsFloatScalarType(eta_type)) { |
858 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
859 | << ext_inst_name() << ": " |
860 | << "expected operand Eta to be a float scalar" ; |
861 | } |
862 | break; |
863 | } |
864 | |
865 | case GLSLstd450InterpolateAtCentroid: |
866 | case GLSLstd450InterpolateAtSample: |
867 | case GLSLstd450InterpolateAtOffset: { |
868 | if (!_.HasCapability(SpvCapabilityInterpolationFunction)) { |
869 | return _.diag(SPV_ERROR_INVALID_CAPABILITY, inst) |
870 | << ext_inst_name() |
871 | << " requires capability InterpolationFunction" ; |
872 | } |
873 | |
874 | if (!_.IsFloatScalarOrVectorType(result_type) || |
875 | _.GetBitWidth(result_type) != 32) { |
876 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
877 | << ext_inst_name() << ": " |
878 | << "expected Result Type to be a 32-bit float scalar " |
879 | << "or vector type" ; |
880 | } |
881 | |
882 | const uint32_t interpolant_type = _.GetOperandTypeId(inst, 4); |
883 | uint32_t interpolant_storage_class = 0; |
884 | uint32_t interpolant_data_type = 0; |
885 | if (!_.GetPointerTypeInfo(interpolant_type, &interpolant_data_type, |
886 | &interpolant_storage_class)) { |
887 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
888 | << ext_inst_name() << ": " |
889 | << "expected Interpolant to be a pointer" ; |
890 | } |
891 | |
892 | if (result_type != interpolant_data_type) { |
893 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
894 | << ext_inst_name() << ": " |
895 | << "expected Interpolant data type to be equal to Result Type" ; |
896 | } |
897 | |
898 | if (interpolant_storage_class != SpvStorageClassInput) { |
899 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
900 | << ext_inst_name() << ": " |
901 | << "expected Interpolant storage class to be Input" ; |
902 | } |
903 | |
904 | if (ext_inst_key == GLSLstd450InterpolateAtSample) { |
905 | const uint32_t sample_type = _.GetOperandTypeId(inst, 5); |
906 | if (!_.IsIntScalarType(sample_type) || |
907 | _.GetBitWidth(sample_type) != 32) { |
908 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
909 | << ext_inst_name() << ": " |
910 | << "expected Sample to be 32-bit integer" ; |
911 | } |
912 | } |
913 | |
914 | if (ext_inst_key == GLSLstd450InterpolateAtOffset) { |
915 | const uint32_t offset_type = _.GetOperandTypeId(inst, 5); |
916 | if (!_.IsFloatVectorType(offset_type) || |
917 | _.GetDimension(offset_type) != 2 || |
918 | _.GetBitWidth(offset_type) != 32) { |
919 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
920 | << ext_inst_name() << ": " |
921 | << "expected Offset to be a vector of 2 32-bit floats" ; |
922 | } |
923 | } |
924 | |
925 | _.function(inst->function()->id()) |
926 | ->RegisterExecutionModelLimitation( |
927 | SpvExecutionModelFragment, |
928 | ext_inst_name() + |
929 | std::string(" requires Fragment execution model" )); |
930 | break; |
931 | } |
932 | |
933 | case GLSLstd450IMix: { |
934 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
935 | << "Extended instruction GLSLstd450IMix is not supported" ; |
936 | } |
937 | |
938 | case GLSLstd450Bad: { |
939 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
940 | << "Encountered extended instruction GLSLstd450Bad" ; |
941 | } |
942 | |
943 | case GLSLstd450Count: { |
944 | assert(0); |
945 | break; |
946 | } |
947 | } |
948 | } else if (ext_inst_type == SPV_EXT_INST_TYPE_OPENCL_STD) { |
949 | const OpenCLLIB::Entrypoints ext_inst_key = |
950 | OpenCLLIB::Entrypoints(ext_inst_index); |
951 | switch (ext_inst_key) { |
952 | case OpenCLLIB::Acos: |
953 | case OpenCLLIB::Acosh: |
954 | case OpenCLLIB::Acospi: |
955 | case OpenCLLIB::Asin: |
956 | case OpenCLLIB::Asinh: |
957 | case OpenCLLIB::Asinpi: |
958 | case OpenCLLIB::Atan: |
959 | case OpenCLLIB::Atan2: |
960 | case OpenCLLIB::Atanh: |
961 | case OpenCLLIB::Atanpi: |
962 | case OpenCLLIB::Atan2pi: |
963 | case OpenCLLIB::Cbrt: |
964 | case OpenCLLIB::Ceil: |
965 | case OpenCLLIB::Copysign: |
966 | case OpenCLLIB::Cos: |
967 | case OpenCLLIB::Cosh: |
968 | case OpenCLLIB::Cospi: |
969 | case OpenCLLIB::Erfc: |
970 | case OpenCLLIB::Erf: |
971 | case OpenCLLIB::Exp: |
972 | case OpenCLLIB::Exp2: |
973 | case OpenCLLIB::Exp10: |
974 | case OpenCLLIB::Expm1: |
975 | case OpenCLLIB::Fabs: |
976 | case OpenCLLIB::Fdim: |
977 | case OpenCLLIB::Floor: |
978 | case OpenCLLIB::Fma: |
979 | case OpenCLLIB::Fmax: |
980 | case OpenCLLIB::Fmin: |
981 | case OpenCLLIB::Fmod: |
982 | case OpenCLLIB::Hypot: |
983 | case OpenCLLIB::Lgamma: |
984 | case OpenCLLIB::Log: |
985 | case OpenCLLIB::Log2: |
986 | case OpenCLLIB::Log10: |
987 | case OpenCLLIB::Log1p: |
988 | case OpenCLLIB::Logb: |
989 | case OpenCLLIB::Mad: |
990 | case OpenCLLIB::Maxmag: |
991 | case OpenCLLIB::Minmag: |
992 | case OpenCLLIB::Nextafter: |
993 | case OpenCLLIB::Pow: |
994 | case OpenCLLIB::Powr: |
995 | case OpenCLLIB::Remainder: |
996 | case OpenCLLIB::Rint: |
997 | case OpenCLLIB::Round: |
998 | case OpenCLLIB::Rsqrt: |
999 | case OpenCLLIB::Sin: |
1000 | case OpenCLLIB::Sinh: |
1001 | case OpenCLLIB::Sinpi: |
1002 | case OpenCLLIB::Sqrt: |
1003 | case OpenCLLIB::Tan: |
1004 | case OpenCLLIB::Tanh: |
1005 | case OpenCLLIB::Tanpi: |
1006 | case OpenCLLIB::Tgamma: |
1007 | case OpenCLLIB::Trunc: |
1008 | case OpenCLLIB::Half_cos: |
1009 | case OpenCLLIB::Half_divide: |
1010 | case OpenCLLIB::Half_exp: |
1011 | case OpenCLLIB::Half_exp2: |
1012 | case OpenCLLIB::Half_exp10: |
1013 | case OpenCLLIB::Half_log: |
1014 | case OpenCLLIB::Half_log2: |
1015 | case OpenCLLIB::Half_log10: |
1016 | case OpenCLLIB::Half_powr: |
1017 | case OpenCLLIB::Half_recip: |
1018 | case OpenCLLIB::Half_rsqrt: |
1019 | case OpenCLLIB::Half_sin: |
1020 | case OpenCLLIB::Half_sqrt: |
1021 | case OpenCLLIB::Half_tan: |
1022 | case OpenCLLIB::Native_cos: |
1023 | case OpenCLLIB::Native_divide: |
1024 | case OpenCLLIB::Native_exp: |
1025 | case OpenCLLIB::Native_exp2: |
1026 | case OpenCLLIB::Native_exp10: |
1027 | case OpenCLLIB::Native_log: |
1028 | case OpenCLLIB::Native_log2: |
1029 | case OpenCLLIB::Native_log10: |
1030 | case OpenCLLIB::Native_powr: |
1031 | case OpenCLLIB::Native_recip: |
1032 | case OpenCLLIB::Native_rsqrt: |
1033 | case OpenCLLIB::Native_sin: |
1034 | case OpenCLLIB::Native_sqrt: |
1035 | case OpenCLLIB::Native_tan: |
1036 | case OpenCLLIB::FClamp: |
1037 | case OpenCLLIB::Degrees: |
1038 | case OpenCLLIB::FMax_common: |
1039 | case OpenCLLIB::FMin_common: |
1040 | case OpenCLLIB::Mix: |
1041 | case OpenCLLIB::Radians: |
1042 | case OpenCLLIB::Step: |
1043 | case OpenCLLIB::Smoothstep: |
1044 | case OpenCLLIB::Sign: { |
1045 | if (!_.IsFloatScalarOrVectorType(result_type)) { |
1046 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1047 | << ext_inst_name() << ": " |
1048 | << "expected Result Type to be a float scalar or vector type" ; |
1049 | } |
1050 | |
1051 | const uint32_t num_components = _.GetDimension(result_type); |
1052 | if (num_components > 4 && num_components != 8 && num_components != 16) { |
1053 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1054 | << ext_inst_name() << ": " |
1055 | << "expected Result Type to be a scalar or a vector with 2, " |
1056 | "3, 4, 8 or 16 components" ; |
1057 | } |
1058 | |
1059 | for (uint32_t operand_index = 4; operand_index < num_operands; |
1060 | ++operand_index) { |
1061 | const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index); |
1062 | if (result_type != operand_type) { |
1063 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1064 | << ext_inst_name() << ": " |
1065 | << "expected types of all operands to be equal to Result " |
1066 | "Type" ; |
1067 | } |
1068 | } |
1069 | break; |
1070 | } |
1071 | |
1072 | case OpenCLLIB::Fract: |
1073 | case OpenCLLIB::Modf: |
1074 | case OpenCLLIB::Sincos: { |
1075 | if (!_.IsFloatScalarOrVectorType(result_type)) { |
1076 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1077 | << ext_inst_name() << ": " |
1078 | << "expected Result Type to be a float scalar or vector type" ; |
1079 | } |
1080 | |
1081 | const uint32_t num_components = _.GetDimension(result_type); |
1082 | if (num_components > 4 && num_components != 8 && num_components != 16) { |
1083 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1084 | << ext_inst_name() << ": " |
1085 | << "expected Result Type to be a scalar or a vector with 2, " |
1086 | "3, 4, 8 or 16 components" ; |
1087 | } |
1088 | |
1089 | const uint32_t x_type = _.GetOperandTypeId(inst, 4); |
1090 | if (result_type != x_type) { |
1091 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1092 | << ext_inst_name() << ": " |
1093 | << "expected type of operand X to be equal to Result Type" ; |
1094 | } |
1095 | |
1096 | const uint32_t p_type = _.GetOperandTypeId(inst, 5); |
1097 | uint32_t p_storage_class = 0; |
1098 | uint32_t p_data_type = 0; |
1099 | if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) { |
1100 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1101 | << ext_inst_name() << ": " |
1102 | << "expected the last operand to be a pointer" ; |
1103 | } |
1104 | |
1105 | if (p_storage_class != SpvStorageClassGeneric && |
1106 | p_storage_class != SpvStorageClassCrossWorkgroup && |
1107 | p_storage_class != SpvStorageClassWorkgroup && |
1108 | p_storage_class != SpvStorageClassFunction) { |
1109 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1110 | << ext_inst_name() << ": " |
1111 | << "expected storage class of the pointer to be Generic, " |
1112 | "CrossWorkgroup, Workgroup or Function" ; |
1113 | } |
1114 | |
1115 | if (result_type != p_data_type) { |
1116 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1117 | << ext_inst_name() << ": " |
1118 | << "expected data type of the pointer to be equal to Result " |
1119 | "Type" ; |
1120 | } |
1121 | break; |
1122 | } |
1123 | |
1124 | case OpenCLLIB::Frexp: |
1125 | case OpenCLLIB::Lgamma_r: |
1126 | case OpenCLLIB::Remquo: { |
1127 | if (!_.IsFloatScalarOrVectorType(result_type)) { |
1128 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1129 | << ext_inst_name() << ": " |
1130 | << "expected Result Type to be a float scalar or vector type" ; |
1131 | } |
1132 | |
1133 | const uint32_t num_components = _.GetDimension(result_type); |
1134 | if (num_components > 4 && num_components != 8 && num_components != 16) { |
1135 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1136 | << ext_inst_name() << ": " |
1137 | << "expected Result Type to be a scalar or a vector with 2, " |
1138 | "3, 4, 8 or 16 components" ; |
1139 | } |
1140 | |
1141 | uint32_t operand_index = 4; |
1142 | const uint32_t x_type = _.GetOperandTypeId(inst, operand_index++); |
1143 | if (result_type != x_type) { |
1144 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1145 | << ext_inst_name() << ": " |
1146 | << "expected type of operand X to be equal to Result Type" ; |
1147 | } |
1148 | |
1149 | if (ext_inst_key == OpenCLLIB::Remquo) { |
1150 | const uint32_t y_type = _.GetOperandTypeId(inst, operand_index++); |
1151 | if (result_type != y_type) { |
1152 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1153 | << ext_inst_name() << ": " |
1154 | << "expected type of operand Y to be equal to Result Type" ; |
1155 | } |
1156 | } |
1157 | |
1158 | const uint32_t p_type = _.GetOperandTypeId(inst, operand_index++); |
1159 | uint32_t p_storage_class = 0; |
1160 | uint32_t p_data_type = 0; |
1161 | if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) { |
1162 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1163 | << ext_inst_name() << ": " |
1164 | << "expected the last operand to be a pointer" ; |
1165 | } |
1166 | |
1167 | if (p_storage_class != SpvStorageClassGeneric && |
1168 | p_storage_class != SpvStorageClassCrossWorkgroup && |
1169 | p_storage_class != SpvStorageClassWorkgroup && |
1170 | p_storage_class != SpvStorageClassFunction) { |
1171 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1172 | << ext_inst_name() << ": " |
1173 | << "expected storage class of the pointer to be Generic, " |
1174 | "CrossWorkgroup, Workgroup or Function" ; |
1175 | } |
1176 | |
1177 | if (!_.IsIntScalarOrVectorType(p_data_type) || |
1178 | _.GetBitWidth(p_data_type) != 32) { |
1179 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1180 | << ext_inst_name() << ": " |
1181 | << "expected data type of the pointer to be a 32-bit int " |
1182 | "scalar or vector type" ; |
1183 | } |
1184 | |
1185 | if (_.GetDimension(p_data_type) != num_components) { |
1186 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1187 | << ext_inst_name() << ": " |
1188 | << "expected data type of the pointer to have the same number " |
1189 | "of components as Result Type" ; |
1190 | } |
1191 | break; |
1192 | } |
1193 | |
1194 | case OpenCLLIB::Ilogb: { |
1195 | if (!_.IsIntScalarOrVectorType(result_type) || |
1196 | _.GetBitWidth(result_type) != 32) { |
1197 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1198 | << ext_inst_name() << ": " |
1199 | << "expected Result Type to be a 32-bit int scalar or vector " |
1200 | "type" ; |
1201 | } |
1202 | |
1203 | const uint32_t num_components = _.GetDimension(result_type); |
1204 | if (num_components > 4 && num_components != 8 && num_components != 16) { |
1205 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1206 | << ext_inst_name() << ": " |
1207 | << "expected Result Type to be a scalar or a vector with 2, " |
1208 | "3, 4, 8 or 16 components" ; |
1209 | } |
1210 | |
1211 | const uint32_t x_type = _.GetOperandTypeId(inst, 4); |
1212 | if (!_.IsFloatScalarOrVectorType(x_type)) { |
1213 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1214 | << ext_inst_name() << ": " |
1215 | << "expected operand X to be a float scalar or vector" ; |
1216 | } |
1217 | |
1218 | if (_.GetDimension(x_type) != num_components) { |
1219 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1220 | << ext_inst_name() << ": " |
1221 | << "expected operand X to have the same number of components " |
1222 | "as Result Type" ; |
1223 | } |
1224 | break; |
1225 | } |
1226 | |
1227 | case OpenCLLIB::Ldexp: |
1228 | case OpenCLLIB::Pown: |
1229 | case OpenCLLIB::Rootn: { |
1230 | if (!_.IsFloatScalarOrVectorType(result_type)) { |
1231 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1232 | << ext_inst_name() << ": " |
1233 | << "expected Result Type to be a float scalar or vector type" ; |
1234 | } |
1235 | |
1236 | const uint32_t num_components = _.GetDimension(result_type); |
1237 | if (num_components > 4 && num_components != 8 && num_components != 16) { |
1238 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1239 | << ext_inst_name() << ": " |
1240 | << "expected Result Type to be a scalar or a vector with 2, " |
1241 | "3, 4, 8 or 16 components" ; |
1242 | } |
1243 | |
1244 | const uint32_t x_type = _.GetOperandTypeId(inst, 4); |
1245 | if (result_type != x_type) { |
1246 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1247 | << ext_inst_name() << ": " |
1248 | << "expected type of operand X to be equal to Result Type" ; |
1249 | } |
1250 | |
1251 | const uint32_t exp_type = _.GetOperandTypeId(inst, 5); |
1252 | if (!_.IsIntScalarOrVectorType(exp_type) || |
1253 | _.GetBitWidth(exp_type) != 32) { |
1254 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1255 | << ext_inst_name() << ": " |
1256 | << "expected the exponent to be a 32-bit int scalar or vector" ; |
1257 | } |
1258 | |
1259 | if (_.GetDimension(exp_type) != num_components) { |
1260 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1261 | << ext_inst_name() << ": " |
1262 | << "expected the exponent to have the same number of " |
1263 | "components as Result Type" ; |
1264 | } |
1265 | break; |
1266 | } |
1267 | |
1268 | case OpenCLLIB::Nan: { |
1269 | if (!_.IsFloatScalarOrVectorType(result_type)) { |
1270 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1271 | << ext_inst_name() << ": " |
1272 | << "expected Result Type to be a float scalar or vector type" ; |
1273 | } |
1274 | |
1275 | const uint32_t num_components = _.GetDimension(result_type); |
1276 | if (num_components > 4 && num_components != 8 && num_components != 16) { |
1277 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1278 | << ext_inst_name() << ": " |
1279 | << "expected Result Type to be a scalar or a vector with 2, " |
1280 | "3, 4, 8 or 16 components" ; |
1281 | } |
1282 | |
1283 | const uint32_t nancode_type = _.GetOperandTypeId(inst, 4); |
1284 | if (!_.IsIntScalarOrVectorType(nancode_type)) { |
1285 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1286 | << ext_inst_name() << ": " |
1287 | << "expected Nancode to be an int scalar or vector type" ; |
1288 | } |
1289 | |
1290 | if (_.GetDimension(nancode_type) != num_components) { |
1291 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1292 | << ext_inst_name() << ": " |
1293 | << "expected Nancode to have the same number of components as " |
1294 | "Result Type" ; |
1295 | } |
1296 | |
1297 | if (_.GetBitWidth(result_type) != _.GetBitWidth(nancode_type)) { |
1298 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1299 | << ext_inst_name() << ": " |
1300 | << "expected Nancode to have the same bit width as Result " |
1301 | "Type" ; |
1302 | } |
1303 | break; |
1304 | } |
1305 | |
1306 | case OpenCLLIB::SAbs: |
1307 | case OpenCLLIB::SAbs_diff: |
1308 | case OpenCLLIB::SAdd_sat: |
1309 | case OpenCLLIB::UAdd_sat: |
1310 | case OpenCLLIB::SHadd: |
1311 | case OpenCLLIB::UHadd: |
1312 | case OpenCLLIB::SRhadd: |
1313 | case OpenCLLIB::URhadd: |
1314 | case OpenCLLIB::SClamp: |
1315 | case OpenCLLIB::UClamp: |
1316 | case OpenCLLIB::Clz: |
1317 | case OpenCLLIB::Ctz: |
1318 | case OpenCLLIB::SMad_hi: |
1319 | case OpenCLLIB::UMad_sat: |
1320 | case OpenCLLIB::SMad_sat: |
1321 | case OpenCLLIB::SMax: |
1322 | case OpenCLLIB::UMax: |
1323 | case OpenCLLIB::SMin: |
1324 | case OpenCLLIB::UMin: |
1325 | case OpenCLLIB::SMul_hi: |
1326 | case OpenCLLIB::Rotate: |
1327 | case OpenCLLIB::SSub_sat: |
1328 | case OpenCLLIB::USub_sat: |
1329 | case OpenCLLIB::Popcount: |
1330 | case OpenCLLIB::UAbs: |
1331 | case OpenCLLIB::UAbs_diff: |
1332 | case OpenCLLIB::UMul_hi: |
1333 | case OpenCLLIB::UMad_hi: { |
1334 | if (!_.IsIntScalarOrVectorType(result_type)) { |
1335 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1336 | << ext_inst_name() << ": " |
1337 | << "expected Result Type to be an int scalar or vector type" ; |
1338 | } |
1339 | |
1340 | const uint32_t num_components = _.GetDimension(result_type); |
1341 | if (num_components > 4 && num_components != 8 && num_components != 16) { |
1342 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1343 | << ext_inst_name() << ": " |
1344 | << "expected Result Type to be a scalar or a vector with 2, " |
1345 | "3, 4, 8 or 16 components" ; |
1346 | } |
1347 | |
1348 | for (uint32_t operand_index = 4; operand_index < num_operands; |
1349 | ++operand_index) { |
1350 | const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index); |
1351 | if (result_type != operand_type) { |
1352 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1353 | << ext_inst_name() << ": " |
1354 | << "expected types of all operands to be equal to Result " |
1355 | "Type" ; |
1356 | } |
1357 | } |
1358 | break; |
1359 | } |
1360 | |
1361 | case OpenCLLIB::U_Upsample: |
1362 | case OpenCLLIB::S_Upsample: { |
1363 | if (!_.IsIntScalarOrVectorType(result_type)) { |
1364 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1365 | << ext_inst_name() << ": " |
1366 | << "expected Result Type to be an int scalar or vector " |
1367 | "type" ; |
1368 | } |
1369 | |
1370 | const uint32_t result_num_components = _.GetDimension(result_type); |
1371 | if (result_num_components > 4 && result_num_components != 8 && |
1372 | result_num_components != 16) { |
1373 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1374 | << ext_inst_name() << ": " |
1375 | << "expected Result Type to be a scalar or a vector with 2, " |
1376 | "3, 4, 8 or 16 components" ; |
1377 | } |
1378 | |
1379 | const uint32_t result_bit_width = _.GetBitWidth(result_type); |
1380 | if (result_bit_width != 16 && result_bit_width != 32 && |
1381 | result_bit_width != 64) { |
1382 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1383 | << ext_inst_name() << ": " |
1384 | << "expected bit width of Result Type components to be 16, 32 " |
1385 | "or 64" ; |
1386 | } |
1387 | |
1388 | const uint32_t hi_type = _.GetOperandTypeId(inst, 4); |
1389 | const uint32_t lo_type = _.GetOperandTypeId(inst, 5); |
1390 | |
1391 | if (hi_type != lo_type) { |
1392 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1393 | << ext_inst_name() << ": " |
1394 | << "expected Hi and Lo operands to have the same type" ; |
1395 | } |
1396 | |
1397 | if (result_num_components != _.GetDimension(hi_type)) { |
1398 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1399 | << ext_inst_name() << ": " |
1400 | << "expected Hi and Lo operands to have the same number of " |
1401 | "components as Result Type" ; |
1402 | } |
1403 | |
1404 | if (result_bit_width != 2 * _.GetBitWidth(hi_type)) { |
1405 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1406 | << ext_inst_name() << ": " |
1407 | << "expected bit width of components of Hi and Lo operands to " |
1408 | "be half of the bit width of components of Result Type" ; |
1409 | } |
1410 | break; |
1411 | } |
1412 | |
1413 | case OpenCLLIB::SMad24: |
1414 | case OpenCLLIB::UMad24: |
1415 | case OpenCLLIB::SMul24: |
1416 | case OpenCLLIB::UMul24: { |
1417 | if (!_.IsIntScalarOrVectorType(result_type) || |
1418 | _.GetBitWidth(result_type) != 32) { |
1419 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1420 | << ext_inst_name() << ": " |
1421 | << "expected Result Type to be a 32-bit int scalar or vector " |
1422 | "type" ; |
1423 | } |
1424 | |
1425 | const uint32_t num_components = _.GetDimension(result_type); |
1426 | if (num_components > 4 && num_components != 8 && num_components != 16) { |
1427 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1428 | << ext_inst_name() << ": " |
1429 | << "expected Result Type to be a scalar or a vector with 2, " |
1430 | "3, 4, 8 or 16 components" ; |
1431 | } |
1432 | |
1433 | for (uint32_t operand_index = 4; operand_index < num_operands; |
1434 | ++operand_index) { |
1435 | const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index); |
1436 | if (result_type != operand_type) { |
1437 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1438 | << ext_inst_name() << ": " |
1439 | << "expected types of all operands to be equal to Result " |
1440 | "Type" ; |
1441 | } |
1442 | } |
1443 | break; |
1444 | } |
1445 | |
1446 | case OpenCLLIB::Cross: { |
1447 | if (!_.IsFloatVectorType(result_type)) { |
1448 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1449 | << ext_inst_name() << ": " |
1450 | << "expected Result Type to be a float vector type" ; |
1451 | } |
1452 | |
1453 | const uint32_t num_components = _.GetDimension(result_type); |
1454 | if (num_components != 3 && num_components != 4) { |
1455 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1456 | << ext_inst_name() << ": " |
1457 | << "expected Result Type to have 3 or 4 components" ; |
1458 | } |
1459 | |
1460 | const uint32_t x_type = _.GetOperandTypeId(inst, 4); |
1461 | const uint32_t y_type = _.GetOperandTypeId(inst, 5); |
1462 | |
1463 | if (x_type != result_type) { |
1464 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1465 | << ext_inst_name() << ": " |
1466 | << "expected operand X type to be equal to Result Type" ; |
1467 | } |
1468 | |
1469 | if (y_type != result_type) { |
1470 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1471 | << ext_inst_name() << ": " |
1472 | << "expected operand Y type to be equal to Result Type" ; |
1473 | } |
1474 | break; |
1475 | } |
1476 | |
1477 | case OpenCLLIB::Distance: |
1478 | case OpenCLLIB::Fast_distance: { |
1479 | if (!_.IsFloatScalarType(result_type)) { |
1480 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1481 | << ext_inst_name() << ": " |
1482 | << "expected Result Type to be a float scalar type" ; |
1483 | } |
1484 | |
1485 | const uint32_t p0_type = _.GetOperandTypeId(inst, 4); |
1486 | if (!_.IsFloatScalarOrVectorType(p0_type)) { |
1487 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1488 | << ext_inst_name() << ": " |
1489 | << "expected operand P0 to be of float scalar or vector type" ; |
1490 | } |
1491 | |
1492 | const uint32_t num_components = _.GetDimension(p0_type); |
1493 | if (num_components > 4) { |
1494 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1495 | << ext_inst_name() << ": " |
1496 | << "expected operand P0 to have no more than 4 components" ; |
1497 | } |
1498 | |
1499 | if (result_type != _.GetComponentType(p0_type)) { |
1500 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1501 | << ext_inst_name() << ": " |
1502 | << "expected operand P0 component type to be equal to " |
1503 | << "Result Type" ; |
1504 | } |
1505 | |
1506 | const uint32_t p1_type = _.GetOperandTypeId(inst, 5); |
1507 | if (p0_type != p1_type) { |
1508 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1509 | << ext_inst_name() << ": " |
1510 | << "expected operands P0 and P1 to be of the same type" ; |
1511 | } |
1512 | break; |
1513 | } |
1514 | |
1515 | case OpenCLLIB::Length: |
1516 | case OpenCLLIB::Fast_length: { |
1517 | if (!_.IsFloatScalarType(result_type)) { |
1518 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1519 | << ext_inst_name() << ": " |
1520 | << "expected Result Type to be a float scalar type" ; |
1521 | } |
1522 | |
1523 | const uint32_t p_type = _.GetOperandTypeId(inst, 4); |
1524 | if (!_.IsFloatScalarOrVectorType(p_type)) { |
1525 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1526 | << ext_inst_name() << ": " |
1527 | << "expected operand P to be a float scalar or vector" ; |
1528 | } |
1529 | |
1530 | const uint32_t num_components = _.GetDimension(p_type); |
1531 | if (num_components > 4) { |
1532 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1533 | << ext_inst_name() << ": " |
1534 | << "expected operand P to have no more than 4 components" ; |
1535 | } |
1536 | |
1537 | if (result_type != _.GetComponentType(p_type)) { |
1538 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1539 | << ext_inst_name() << ": " |
1540 | << "expected operand P component type to be equal to Result " |
1541 | "Type" ; |
1542 | } |
1543 | break; |
1544 | } |
1545 | |
1546 | case OpenCLLIB::Normalize: |
1547 | case OpenCLLIB::Fast_normalize: { |
1548 | if (!_.IsFloatScalarOrVectorType(result_type)) { |
1549 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1550 | << ext_inst_name() << ": " |
1551 | << "expected Result Type to be a float scalar or vector type" ; |
1552 | } |
1553 | |
1554 | const uint32_t num_components = _.GetDimension(result_type); |
1555 | if (num_components > 4) { |
1556 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1557 | << ext_inst_name() << ": " |
1558 | << "expected Result Type to have no more than 4 components" ; |
1559 | } |
1560 | |
1561 | const uint32_t p_type = _.GetOperandTypeId(inst, 4); |
1562 | if (p_type != result_type) { |
1563 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1564 | << ext_inst_name() << ": " |
1565 | << "expected operand P type to be equal to Result Type" ; |
1566 | } |
1567 | break; |
1568 | } |
1569 | |
1570 | case OpenCLLIB::Bitselect: { |
1571 | if (!_.IsFloatScalarOrVectorType(result_type) && |
1572 | !_.IsIntScalarOrVectorType(result_type)) { |
1573 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1574 | << ext_inst_name() << ": " |
1575 | << "expected Result Type to be an int or float scalar or " |
1576 | "vector type" ; |
1577 | } |
1578 | |
1579 | const uint32_t num_components = _.GetDimension(result_type); |
1580 | if (num_components > 4 && num_components != 8 && num_components != 16) { |
1581 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1582 | << ext_inst_name() << ": " |
1583 | << "expected Result Type to be a scalar or a vector with 2, " |
1584 | "3, 4, 8 or 16 components" ; |
1585 | } |
1586 | |
1587 | for (uint32_t operand_index = 4; operand_index < num_operands; |
1588 | ++operand_index) { |
1589 | const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index); |
1590 | if (result_type != operand_type) { |
1591 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1592 | << ext_inst_name() << ": " |
1593 | << "expected types of all operands to be equal to Result " |
1594 | "Type" ; |
1595 | } |
1596 | } |
1597 | break; |
1598 | } |
1599 | |
1600 | case OpenCLLIB::Select: { |
1601 | if (!_.IsFloatScalarOrVectorType(result_type) && |
1602 | !_.IsIntScalarOrVectorType(result_type)) { |
1603 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1604 | << ext_inst_name() << ": " |
1605 | << "expected Result Type to be an int or float scalar or " |
1606 | "vector type" ; |
1607 | } |
1608 | |
1609 | const uint32_t num_components = _.GetDimension(result_type); |
1610 | if (num_components > 4 && num_components != 8 && num_components != 16) { |
1611 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1612 | << ext_inst_name() << ": " |
1613 | << "expected Result Type to be a scalar or a vector with 2, " |
1614 | "3, 4, 8 or 16 components" ; |
1615 | } |
1616 | |
1617 | const uint32_t a_type = _.GetOperandTypeId(inst, 4); |
1618 | const uint32_t b_type = _.GetOperandTypeId(inst, 5); |
1619 | const uint32_t c_type = _.GetOperandTypeId(inst, 6); |
1620 | |
1621 | if (result_type != a_type) { |
1622 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1623 | << ext_inst_name() << ": " |
1624 | << "expected operand A type to be equal to Result Type" ; |
1625 | } |
1626 | |
1627 | if (result_type != b_type) { |
1628 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1629 | << ext_inst_name() << ": " |
1630 | << "expected operand B type to be equal to Result Type" ; |
1631 | } |
1632 | |
1633 | if (!_.IsIntScalarOrVectorType(c_type)) { |
1634 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1635 | << ext_inst_name() << ": " |
1636 | << "expected operand C to be an int scalar or vector" ; |
1637 | } |
1638 | |
1639 | if (num_components != _.GetDimension(c_type)) { |
1640 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1641 | << ext_inst_name() << ": " |
1642 | << "expected operand C to have the same number of components " |
1643 | "as Result Type" ; |
1644 | } |
1645 | |
1646 | if (_.GetBitWidth(result_type) != _.GetBitWidth(c_type)) { |
1647 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1648 | << ext_inst_name() << ": " |
1649 | << "expected operand C to have the same bit width as Result " |
1650 | "Type" ; |
1651 | } |
1652 | break; |
1653 | } |
1654 | |
1655 | case OpenCLLIB::Vloadn: { |
1656 | if (!_.IsFloatVectorType(result_type) && |
1657 | !_.IsIntVectorType(result_type)) { |
1658 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1659 | << ext_inst_name() << ": " |
1660 | << "expected Result Type to be an int or float vector type" ; |
1661 | } |
1662 | |
1663 | const uint32_t num_components = _.GetDimension(result_type); |
1664 | if (num_components > 4 && num_components != 8 && num_components != 16) { |
1665 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1666 | << ext_inst_name() << ": " |
1667 | << "expected Result Type to have 2, 3, 4, 8 or 16 components" ; |
1668 | } |
1669 | |
1670 | const uint32_t offset_type = _.GetOperandTypeId(inst, 4); |
1671 | const uint32_t p_type = _.GetOperandTypeId(inst, 5); |
1672 | |
1673 | const uint32_t size_t_bit_width = GetSizeTBitWidth(_); |
1674 | if (!size_t_bit_width) { |
1675 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1676 | << ext_inst_name() |
1677 | << " can only be used with physical addressing models" ; |
1678 | } |
1679 | |
1680 | if (!_.IsIntScalarType(offset_type) || |
1681 | _.GetBitWidth(offset_type) != size_t_bit_width) { |
1682 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1683 | << ext_inst_name() << ": " |
1684 | << "expected operand Offset to be of type size_t (" |
1685 | << size_t_bit_width |
1686 | << "-bit integer for the addressing model used in the module)" ; |
1687 | } |
1688 | |
1689 | uint32_t p_storage_class = 0; |
1690 | uint32_t p_data_type = 0; |
1691 | if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) { |
1692 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1693 | << ext_inst_name() << ": " |
1694 | << "expected operand P to be a pointer" ; |
1695 | } |
1696 | |
1697 | if (p_storage_class != SpvStorageClassUniformConstant && |
1698 | p_storage_class != SpvStorageClassGeneric && |
1699 | p_storage_class != SpvStorageClassCrossWorkgroup && |
1700 | p_storage_class != SpvStorageClassWorkgroup && |
1701 | p_storage_class != SpvStorageClassFunction) { |
1702 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1703 | << ext_inst_name() << ": " |
1704 | << "expected operand P storage class to be UniformConstant, " |
1705 | "Generic, CrossWorkgroup, Workgroup or Function" ; |
1706 | } |
1707 | |
1708 | if (_.GetComponentType(result_type) != p_data_type) { |
1709 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1710 | << ext_inst_name() << ": " |
1711 | << "expected operand P data type to be equal to component " |
1712 | "type of Result Type" ; |
1713 | } |
1714 | |
1715 | const uint32_t n_value = inst->word(7); |
1716 | if (num_components != n_value) { |
1717 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1718 | << ext_inst_name() << ": " |
1719 | << "expected literal N to be equal to the number of " |
1720 | "components of Result Type" ; |
1721 | } |
1722 | break; |
1723 | } |
1724 | |
1725 | case OpenCLLIB::Vstoren: { |
1726 | if (_.GetIdOpcode(result_type) != SpvOpTypeVoid) { |
1727 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1728 | << ext_inst_name() << ": expected Result Type to be void" ; |
1729 | } |
1730 | |
1731 | const uint32_t data_type = _.GetOperandTypeId(inst, 4); |
1732 | const uint32_t offset_type = _.GetOperandTypeId(inst, 5); |
1733 | const uint32_t p_type = _.GetOperandTypeId(inst, 6); |
1734 | |
1735 | if (!_.IsFloatVectorType(data_type) && !_.IsIntVectorType(data_type)) { |
1736 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1737 | << ext_inst_name() << ": " |
1738 | << "expected Data to be an int or float vector" ; |
1739 | } |
1740 | |
1741 | const uint32_t num_components = _.GetDimension(data_type); |
1742 | if (num_components > 4 && num_components != 8 && num_components != 16) { |
1743 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1744 | << ext_inst_name() << ": " |
1745 | << "expected Data to have 2, 3, 4, 8 or 16 components" ; |
1746 | } |
1747 | |
1748 | const uint32_t size_t_bit_width = GetSizeTBitWidth(_); |
1749 | if (!size_t_bit_width) { |
1750 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1751 | << ext_inst_name() |
1752 | << " can only be used with physical addressing models" ; |
1753 | } |
1754 | |
1755 | if (!_.IsIntScalarType(offset_type) || |
1756 | _.GetBitWidth(offset_type) != size_t_bit_width) { |
1757 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1758 | << ext_inst_name() << ": " |
1759 | << "expected operand Offset to be of type size_t (" |
1760 | << size_t_bit_width |
1761 | << "-bit integer for the addressing model used in the module)" ; |
1762 | } |
1763 | |
1764 | uint32_t p_storage_class = 0; |
1765 | uint32_t p_data_type = 0; |
1766 | if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) { |
1767 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1768 | << ext_inst_name() << ": " |
1769 | << "expected operand P to be a pointer" ; |
1770 | } |
1771 | |
1772 | if (p_storage_class != SpvStorageClassGeneric && |
1773 | p_storage_class != SpvStorageClassCrossWorkgroup && |
1774 | p_storage_class != SpvStorageClassWorkgroup && |
1775 | p_storage_class != SpvStorageClassFunction) { |
1776 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1777 | << ext_inst_name() << ": " |
1778 | << "expected operand P storage class to be Generic, " |
1779 | "CrossWorkgroup, Workgroup or Function" ; |
1780 | } |
1781 | |
1782 | if (_.GetComponentType(data_type) != p_data_type) { |
1783 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1784 | << ext_inst_name() << ": " |
1785 | << "expected operand P data type to be equal to the type of " |
1786 | "operand Data components" ; |
1787 | } |
1788 | break; |
1789 | } |
1790 | |
1791 | case OpenCLLIB::Vload_half: { |
1792 | if (!_.IsFloatScalarType(result_type)) { |
1793 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1794 | << ext_inst_name() << ": " |
1795 | << "expected Result Type to be a float scalar type" ; |
1796 | } |
1797 | |
1798 | const uint32_t offset_type = _.GetOperandTypeId(inst, 4); |
1799 | const uint32_t p_type = _.GetOperandTypeId(inst, 5); |
1800 | |
1801 | const uint32_t size_t_bit_width = GetSizeTBitWidth(_); |
1802 | if (!size_t_bit_width) { |
1803 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1804 | << ext_inst_name() |
1805 | << " can only be used with physical addressing models" ; |
1806 | } |
1807 | |
1808 | if (!_.IsIntScalarType(offset_type) || |
1809 | _.GetBitWidth(offset_type) != size_t_bit_width) { |
1810 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1811 | << ext_inst_name() << ": " |
1812 | << "expected operand Offset to be of type size_t (" |
1813 | << size_t_bit_width |
1814 | << "-bit integer for the addressing model used in the module)" ; |
1815 | } |
1816 | |
1817 | uint32_t p_storage_class = 0; |
1818 | uint32_t p_data_type = 0; |
1819 | if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) { |
1820 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1821 | << ext_inst_name() << ": " |
1822 | << "expected operand P to be a pointer" ; |
1823 | } |
1824 | |
1825 | if (p_storage_class != SpvStorageClassUniformConstant && |
1826 | p_storage_class != SpvStorageClassGeneric && |
1827 | p_storage_class != SpvStorageClassCrossWorkgroup && |
1828 | p_storage_class != SpvStorageClassWorkgroup && |
1829 | p_storage_class != SpvStorageClassFunction) { |
1830 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1831 | << ext_inst_name() << ": " |
1832 | << "expected operand P storage class to be UniformConstant, " |
1833 | "Generic, CrossWorkgroup, Workgroup or Function" ; |
1834 | } |
1835 | |
1836 | if (!_.IsFloatScalarType(p_data_type) || |
1837 | _.GetBitWidth(p_data_type) != 16) { |
1838 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1839 | << ext_inst_name() << ": " |
1840 | << "expected operand P data type to be 16-bit float scalar" ; |
1841 | } |
1842 | break; |
1843 | } |
1844 | |
1845 | case OpenCLLIB::Vload_halfn: |
1846 | case OpenCLLIB::Vloada_halfn: { |
1847 | if (!_.IsFloatVectorType(result_type)) { |
1848 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1849 | << ext_inst_name() << ": " |
1850 | << "expected Result Type to be a float vector type" ; |
1851 | } |
1852 | |
1853 | const uint32_t num_components = _.GetDimension(result_type); |
1854 | if (num_components > 4 && num_components != 8 && num_components != 16) { |
1855 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1856 | << ext_inst_name() << ": " |
1857 | << "expected Result Type to have 2, 3, 4, 8 or 16 components" ; |
1858 | } |
1859 | |
1860 | const uint32_t offset_type = _.GetOperandTypeId(inst, 4); |
1861 | const uint32_t p_type = _.GetOperandTypeId(inst, 5); |
1862 | |
1863 | const uint32_t size_t_bit_width = GetSizeTBitWidth(_); |
1864 | if (!size_t_bit_width) { |
1865 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1866 | << ext_inst_name() |
1867 | << " can only be used with physical addressing models" ; |
1868 | } |
1869 | |
1870 | if (!_.IsIntScalarType(offset_type) || |
1871 | _.GetBitWidth(offset_type) != size_t_bit_width) { |
1872 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1873 | << ext_inst_name() << ": " |
1874 | << "expected operand Offset to be of type size_t (" |
1875 | << size_t_bit_width |
1876 | << "-bit integer for the addressing model used in the module)" ; |
1877 | } |
1878 | |
1879 | uint32_t p_storage_class = 0; |
1880 | uint32_t p_data_type = 0; |
1881 | if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) { |
1882 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1883 | << ext_inst_name() << ": " |
1884 | << "expected operand P to be a pointer" ; |
1885 | } |
1886 | |
1887 | if (p_storage_class != SpvStorageClassUniformConstant && |
1888 | p_storage_class != SpvStorageClassGeneric && |
1889 | p_storage_class != SpvStorageClassCrossWorkgroup && |
1890 | p_storage_class != SpvStorageClassWorkgroup && |
1891 | p_storage_class != SpvStorageClassFunction) { |
1892 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1893 | << ext_inst_name() << ": " |
1894 | << "expected operand P storage class to be UniformConstant, " |
1895 | "Generic, CrossWorkgroup, Workgroup or Function" ; |
1896 | } |
1897 | |
1898 | if (!_.IsFloatScalarType(p_data_type) || |
1899 | _.GetBitWidth(p_data_type) != 16) { |
1900 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1901 | << ext_inst_name() << ": " |
1902 | << "expected operand P data type to be 16-bit float scalar" ; |
1903 | } |
1904 | |
1905 | const uint32_t n_value = inst->word(7); |
1906 | if (num_components != n_value) { |
1907 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1908 | << ext_inst_name() << ": " |
1909 | << "expected literal N to be equal to the number of " |
1910 | "components of Result Type" ; |
1911 | } |
1912 | break; |
1913 | } |
1914 | |
1915 | case OpenCLLIB::Vstore_half: |
1916 | case OpenCLLIB::Vstore_half_r: |
1917 | case OpenCLLIB::Vstore_halfn: |
1918 | case OpenCLLIB::Vstore_halfn_r: |
1919 | case OpenCLLIB::Vstorea_halfn: |
1920 | case OpenCLLIB::Vstorea_halfn_r: { |
1921 | if (_.GetIdOpcode(result_type) != SpvOpTypeVoid) { |
1922 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1923 | << ext_inst_name() << ": expected Result Type to be void" ; |
1924 | } |
1925 | |
1926 | const uint32_t data_type = _.GetOperandTypeId(inst, 4); |
1927 | const uint32_t offset_type = _.GetOperandTypeId(inst, 5); |
1928 | const uint32_t p_type = _.GetOperandTypeId(inst, 6); |
1929 | const uint32_t data_type_bit_width = _.GetBitWidth(data_type); |
1930 | |
1931 | if (ext_inst_key == OpenCLLIB::Vstore_half || |
1932 | ext_inst_key == OpenCLLIB::Vstore_half_r) { |
1933 | if (!_.IsFloatScalarType(data_type) || |
1934 | (data_type_bit_width != 32 && data_type_bit_width != 64)) { |
1935 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1936 | << ext_inst_name() << ": " |
1937 | << "expected Data to be a 32 or 64-bit float scalar" ; |
1938 | } |
1939 | } else { |
1940 | if (!_.IsFloatVectorType(data_type) || |
1941 | (data_type_bit_width != 32 && data_type_bit_width != 64)) { |
1942 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1943 | << ext_inst_name() << ": " |
1944 | << "expected Data to be a 32 or 64-bit float vector" ; |
1945 | } |
1946 | |
1947 | const uint32_t num_components = _.GetDimension(data_type); |
1948 | if (num_components > 4 && num_components != 8 && |
1949 | num_components != 16) { |
1950 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1951 | << ext_inst_name() << ": " |
1952 | << "expected Data to have 2, 3, 4, 8 or 16 components" ; |
1953 | } |
1954 | } |
1955 | |
1956 | const uint32_t size_t_bit_width = GetSizeTBitWidth(_); |
1957 | if (!size_t_bit_width) { |
1958 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1959 | << ext_inst_name() |
1960 | << " can only be used with physical addressing models" ; |
1961 | } |
1962 | |
1963 | if (!_.IsIntScalarType(offset_type) || |
1964 | _.GetBitWidth(offset_type) != size_t_bit_width) { |
1965 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1966 | << ext_inst_name() << ": " |
1967 | << "expected operand Offset to be of type size_t (" |
1968 | << size_t_bit_width |
1969 | << "-bit integer for the addressing model used in the module)" ; |
1970 | } |
1971 | |
1972 | uint32_t p_storage_class = 0; |
1973 | uint32_t p_data_type = 0; |
1974 | if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) { |
1975 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1976 | << ext_inst_name() << ": " |
1977 | << "expected operand P to be a pointer" ; |
1978 | } |
1979 | |
1980 | if (p_storage_class != SpvStorageClassGeneric && |
1981 | p_storage_class != SpvStorageClassCrossWorkgroup && |
1982 | p_storage_class != SpvStorageClassWorkgroup && |
1983 | p_storage_class != SpvStorageClassFunction) { |
1984 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1985 | << ext_inst_name() << ": " |
1986 | << "expected operand P storage class to be Generic, " |
1987 | "CrossWorkgroup, Workgroup or Function" ; |
1988 | } |
1989 | |
1990 | if (!_.IsFloatScalarType(p_data_type) || |
1991 | _.GetBitWidth(p_data_type) != 16) { |
1992 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
1993 | << ext_inst_name() << ": " |
1994 | << "expected operand P data type to be 16-bit float scalar" ; |
1995 | } |
1996 | |
1997 | // Rounding mode enum is checked by assembler. |
1998 | break; |
1999 | } |
2000 | |
2001 | case OpenCLLIB::Shuffle: |
2002 | case OpenCLLIB::Shuffle2: { |
2003 | if (!_.IsFloatVectorType(result_type) && |
2004 | !_.IsIntVectorType(result_type)) { |
2005 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
2006 | << ext_inst_name() << ": " |
2007 | << "expected Result Type to be an int or float vector type" ; |
2008 | } |
2009 | |
2010 | const uint32_t result_num_components = _.GetDimension(result_type); |
2011 | if (result_num_components != 2 && result_num_components != 4 && |
2012 | result_num_components != 8 && result_num_components != 16) { |
2013 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
2014 | << ext_inst_name() << ": " |
2015 | << "expected Result Type to have 2, 4, 8 or 16 components" ; |
2016 | } |
2017 | |
2018 | uint32_t operand_index = 4; |
2019 | const uint32_t x_type = _.GetOperandTypeId(inst, operand_index++); |
2020 | |
2021 | if (ext_inst_key == OpenCLLIB::Shuffle2) { |
2022 | const uint32_t y_type = _.GetOperandTypeId(inst, operand_index++); |
2023 | if (x_type != y_type) { |
2024 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
2025 | << ext_inst_name() << ": " |
2026 | << "expected operands X and Y to be of the same type" ; |
2027 | } |
2028 | } |
2029 | |
2030 | const uint32_t shuffle_mask_type = |
2031 | _.GetOperandTypeId(inst, operand_index++); |
2032 | |
2033 | if (!_.IsFloatVectorType(x_type) && !_.IsIntVectorType(x_type)) { |
2034 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
2035 | << ext_inst_name() << ": " |
2036 | << "expected operand X to be an int or float vector" ; |
2037 | } |
2038 | |
2039 | const uint32_t x_num_components = _.GetDimension(x_type); |
2040 | if (x_num_components != 2 && x_num_components != 4 && |
2041 | x_num_components != 8 && x_num_components != 16) { |
2042 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
2043 | << ext_inst_name() << ": " |
2044 | << "expected operand X to have 2, 4, 8 or 16 components" ; |
2045 | } |
2046 | |
2047 | const uint32_t result_component_type = _.GetComponentType(result_type); |
2048 | |
2049 | if (result_component_type != _.GetComponentType(x_type)) { |
2050 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
2051 | << ext_inst_name() << ": " |
2052 | << "expected operand X and Result Type to have equal " |
2053 | "component types" ; |
2054 | } |
2055 | |
2056 | if (!_.IsIntVectorType(shuffle_mask_type)) { |
2057 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
2058 | << ext_inst_name() << ": " |
2059 | << "expected operand Shuffle Mask to be an int vector" ; |
2060 | } |
2061 | |
2062 | if (result_num_components != _.GetDimension(shuffle_mask_type)) { |
2063 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
2064 | << ext_inst_name() << ": " |
2065 | << "expected operand Shuffle Mask to have the same number of " |
2066 | "components as Result Type" ; |
2067 | } |
2068 | |
2069 | if (_.GetBitWidth(result_component_type) != |
2070 | _.GetBitWidth(shuffle_mask_type)) { |
2071 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
2072 | << ext_inst_name() << ": " |
2073 | << "expected operand Shuffle Mask components to have the same " |
2074 | "bit width as Result Type components" ; |
2075 | } |
2076 | break; |
2077 | } |
2078 | |
2079 | case OpenCLLIB::Printf: { |
2080 | if (!_.IsIntScalarType(result_type) || |
2081 | _.GetBitWidth(result_type) != 32) { |
2082 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
2083 | << ext_inst_name() << ": " |
2084 | << "expected Result Type to be a 32-bit int type" ; |
2085 | } |
2086 | |
2087 | const uint32_t format_type = _.GetOperandTypeId(inst, 4); |
2088 | uint32_t format_storage_class = 0; |
2089 | uint32_t format_data_type = 0; |
2090 | if (!_.GetPointerTypeInfo(format_type, &format_data_type, |
2091 | &format_storage_class)) { |
2092 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
2093 | << ext_inst_name() << ": " |
2094 | << "expected operand Format to be a pointer" ; |
2095 | } |
2096 | |
2097 | if (format_storage_class != SpvStorageClassUniformConstant) { |
2098 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
2099 | << ext_inst_name() << ": " |
2100 | << "expected Format storage class to be UniformConstant" ; |
2101 | } |
2102 | |
2103 | if (!_.IsIntScalarType(format_data_type) || |
2104 | _.GetBitWidth(format_data_type) != 8) { |
2105 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
2106 | << ext_inst_name() << ": " |
2107 | << "expected Format data type to be 8-bit int" ; |
2108 | } |
2109 | break; |
2110 | } |
2111 | |
2112 | case OpenCLLIB::Prefetch: { |
2113 | if (_.GetIdOpcode(result_type) != SpvOpTypeVoid) { |
2114 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
2115 | << ext_inst_name() << ": expected Result Type to be void" ; |
2116 | } |
2117 | |
2118 | const uint32_t p_type = _.GetOperandTypeId(inst, 4); |
2119 | const uint32_t num_elements_type = _.GetOperandTypeId(inst, 5); |
2120 | |
2121 | uint32_t p_storage_class = 0; |
2122 | uint32_t p_data_type = 0; |
2123 | if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) { |
2124 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
2125 | << ext_inst_name() << ": " |
2126 | << "expected operand Ptr to be a pointer" ; |
2127 | } |
2128 | |
2129 | if (p_storage_class != SpvStorageClassCrossWorkgroup) { |
2130 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
2131 | << ext_inst_name() << ": " |
2132 | << "expected operand Ptr storage class to be CrossWorkgroup" ; |
2133 | } |
2134 | |
2135 | if (!_.IsFloatScalarOrVectorType(p_data_type) && |
2136 | !_.IsIntScalarOrVectorType(p_data_type)) { |
2137 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
2138 | << ext_inst_name() << ": " |
2139 | << "expected Ptr data type to be int or float scalar or " |
2140 | "vector" ; |
2141 | } |
2142 | |
2143 | const uint32_t num_components = _.GetDimension(p_data_type); |
2144 | if (num_components > 4 && num_components != 8 && num_components != 16) { |
2145 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
2146 | << ext_inst_name() << ": " |
2147 | << "expected Result Type to be a scalar or a vector with 2, " |
2148 | "3, 4, 8 or 16 components" ; |
2149 | } |
2150 | |
2151 | const uint32_t size_t_bit_width = GetSizeTBitWidth(_); |
2152 | if (!size_t_bit_width) { |
2153 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
2154 | << ext_inst_name() |
2155 | << " can only be used with physical addressing models" ; |
2156 | } |
2157 | |
2158 | if (!_.IsIntScalarType(num_elements_type) || |
2159 | _.GetBitWidth(num_elements_type) != size_t_bit_width) { |
2160 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
2161 | << ext_inst_name() << ": " |
2162 | << "expected operand Num Elements to be of type size_t (" |
2163 | << size_t_bit_width |
2164 | << "-bit integer for the addressing model used in the module)" ; |
2165 | } |
2166 | break; |
2167 | } |
2168 | } |
2169 | } else if (ext_inst_type == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100) { |
2170 | if (!_.IsVoidType(result_type)) { |
2171 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
2172 | << ext_inst_name() << ": " |
2173 | << "expected result type must be a result id of " |
2174 | << "OpTypeVoid" ; |
2175 | } |
2176 | |
2177 | auto num_words = inst->words().size(); |
2178 | |
2179 | const OpenCLDebugInfo100Instructions ext_inst_key = |
2180 | OpenCLDebugInfo100Instructions(ext_inst_index); |
2181 | switch (ext_inst_key) { |
2182 | case OpenCLDebugInfo100DebugInfoNone: |
2183 | case OpenCLDebugInfo100DebugNoScope: |
2184 | case OpenCLDebugInfo100DebugOperation: |
2185 | // The binary parser validates the opcode for DebugInfoNone, |
2186 | // DebugNoScope, DebugOperation, and the literal values don't need |
2187 | // further checks. |
2188 | break; |
2189 | case OpenCLDebugInfo100DebugCompilationUnit: { |
2190 | CHECK_DEBUG_OPERAND("Source" , OpenCLDebugInfo100DebugSource, 7); |
2191 | break; |
2192 | } |
2193 | case OpenCLDebugInfo100DebugSource: { |
2194 | CHECK_OPERAND("File" , SpvOpString, 5); |
2195 | if (num_words == 7) CHECK_OPERAND("Text" , SpvOpString, 6); |
2196 | break; |
2197 | } |
2198 | case OpenCLDebugInfo100DebugTypeBasic: { |
2199 | CHECK_OPERAND("Name" , SpvOpString, 5); |
2200 | CHECK_OPERAND("Size" , SpvOpConstant, 6); |
2201 | // "Encoding" param is already validated by the binary parsing stage. |
2202 | break; |
2203 | } |
2204 | case OpenCLDebugInfo100DebugTypePointer: |
2205 | case OpenCLDebugInfo100DebugTypeQualifier: { |
2206 | auto validate_base_type = |
2207 | ValidateOperandBaseType(_, inst, 5, ext_inst_name); |
2208 | if (validate_base_type != SPV_SUCCESS) return validate_base_type; |
2209 | break; |
2210 | } |
2211 | case OpenCLDebugInfo100DebugTypeVector: { |
2212 | auto validate_base_type = |
2213 | ValidateOperandBaseType(_, inst, 5, ext_inst_name); |
2214 | if (validate_base_type != SPV_SUCCESS) return validate_base_type; |
2215 | |
2216 | uint32_t component_count = inst->word(6); |
2217 | if (!component_count || component_count > 4) { |
2218 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
2219 | << ext_inst_name() << ": Component Count must be positive " |
2220 | << "integer less than or equal to 4" ; |
2221 | } |
2222 | break; |
2223 | } |
2224 | case OpenCLDebugInfo100DebugTypeArray: { |
2225 | auto validate_base_type = |
2226 | ValidateOperandDebugType(_, "Base Type" , inst, 5, ext_inst_name); |
2227 | if (validate_base_type != SPV_SUCCESS) return validate_base_type; |
2228 | for (uint32_t i = 6; i < num_words; ++i) { |
2229 | CHECK_OPERAND("Component Count" , SpvOpConstant, i); |
2230 | auto* component_count = _.FindDef(inst->word(i)); |
2231 | if (!_.IsIntScalarType(component_count->type_id()) || |
2232 | !component_count->word(3)) { |
2233 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
2234 | << ext_inst_name() << ": Component Count must be positive " |
2235 | << "integer" ; |
2236 | } |
2237 | } |
2238 | break; |
2239 | } |
2240 | case OpenCLDebugInfo100DebugTypedef: { |
2241 | CHECK_OPERAND("Name" , SpvOpString, 5); |
2242 | auto validate_base_type = |
2243 | ValidateOperandBaseType(_, inst, 6, ext_inst_name); |
2244 | if (validate_base_type != SPV_SUCCESS) return validate_base_type; |
2245 | CHECK_DEBUG_OPERAND("Source" , OpenCLDebugInfo100DebugSource, 7); |
2246 | auto validate_parent = |
2247 | ValidateOperandLexicalScope(_, "Parent" , inst, 10, ext_inst_name); |
2248 | if (validate_parent != SPV_SUCCESS) return validate_parent; |
2249 | break; |
2250 | } |
2251 | case OpenCLDebugInfo100DebugTypeFunction: { |
2252 | auto* return_type = _.FindDef(inst->word(6)); |
2253 | if (return_type->opcode() != SpvOpTypeVoid) { |
2254 | auto validate_return = ValidateOperandDebugType( |
2255 | _, "Return Type" , inst, 6, ext_inst_name); |
2256 | if (validate_return != SPV_SUCCESS) return validate_return; |
2257 | } |
2258 | for (uint32_t word_index = 7; word_index < num_words; ++word_index) { |
2259 | auto validate_param = ValidateOperandDebugType( |
2260 | _, "Parameter Types" , inst, word_index, ext_inst_name); |
2261 | if (validate_param != SPV_SUCCESS) return validate_param; |
2262 | } |
2263 | break; |
2264 | } |
2265 | case OpenCLDebugInfo100DebugTypeEnum: { |
2266 | CHECK_OPERAND("Name" , SpvOpString, 5); |
2267 | if (!DoesDebugInfoOperandMatchExpectation( |
2268 | _, |
2269 | [](OpenCLDebugInfo100Instructions dbg_inst) { |
2270 | return dbg_inst == OpenCLDebugInfo100DebugInfoNone; |
2271 | }, |
2272 | inst, 6)) { |
2273 | auto validate_underlying_type = ValidateOperandDebugType( |
2274 | _, "Underlying Types" , inst, 6, ext_inst_name); |
2275 | if (validate_underlying_type != SPV_SUCCESS) |
2276 | return validate_underlying_type; |
2277 | } |
2278 | CHECK_DEBUG_OPERAND("Source" , OpenCLDebugInfo100DebugSource, 7); |
2279 | auto validate_parent = |
2280 | ValidateOperandLexicalScope(_, "Parent" , inst, 10, ext_inst_name); |
2281 | if (validate_parent != SPV_SUCCESS) return validate_parent; |
2282 | CHECK_OPERAND("Size" , SpvOpConstant, 11); |
2283 | auto* size = _.FindDef(inst->word(11)); |
2284 | if (!_.IsIntScalarType(size->type_id()) || !size->word(3)) { |
2285 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
2286 | << ext_inst_name() << ": expected operand Size is a " |
2287 | << "positive integer" ; |
2288 | } |
2289 | for (uint32_t word_index = 13; word_index + 1 < num_words; |
2290 | word_index += 2) { |
2291 | CHECK_OPERAND("Value" , SpvOpConstant, word_index); |
2292 | CHECK_OPERAND("Name" , SpvOpString, word_index + 1); |
2293 | } |
2294 | break; |
2295 | } |
2296 | case OpenCLDebugInfo100DebugTypeComposite: { |
2297 | CHECK_OPERAND("Name" , SpvOpString, 5); |
2298 | CHECK_DEBUG_OPERAND("Source" , OpenCLDebugInfo100DebugSource, 7); |
2299 | auto validate_parent = |
2300 | ValidateOperandLexicalScope(_, "Parent" , inst, 10, ext_inst_name); |
2301 | if (validate_parent != SPV_SUCCESS) return validate_parent; |
2302 | CHECK_OPERAND("Linkage Name" , SpvOpString, 11); |
2303 | CHECK_OPERAND("Size" , SpvOpConstant, 12); |
2304 | for (uint32_t word_index = 14; word_index < num_words; ++word_index) { |
2305 | if (!DoesDebugInfoOperandMatchExpectation( |
2306 | _, |
2307 | [](OpenCLDebugInfo100Instructions dbg_inst) { |
2308 | return dbg_inst == OpenCLDebugInfo100DebugTypeMember || |
2309 | dbg_inst == OpenCLDebugInfo100DebugFunction || |
2310 | dbg_inst == OpenCLDebugInfo100DebugTypeInheritance; |
2311 | }, |
2312 | inst, word_index)) { |
2313 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
2314 | << ext_inst_name() << ": " |
2315 | << "expected operand Members " |
2316 | << "must be DebugTypeMember, DebugFunction, or " |
2317 | "DebugTypeInheritance" ; |
2318 | } |
2319 | } |
2320 | break; |
2321 | } |
2322 | case OpenCLDebugInfo100DebugTypeMember: { |
2323 | CHECK_OPERAND("Name" , SpvOpString, 5); |
2324 | auto validate_type = |
2325 | ValidateOperandDebugType(_, "Type" , inst, 6, ext_inst_name); |
2326 | if (validate_type != SPV_SUCCESS) return validate_type; |
2327 | CHECK_DEBUG_OPERAND("Source" , OpenCLDebugInfo100DebugSource, 7); |
2328 | CHECK_DEBUG_OPERAND("Parent" , OpenCLDebugInfo100DebugTypeComposite, 10); |
2329 | CHECK_OPERAND("Offset" , SpvOpConstant, 11); |
2330 | CHECK_OPERAND("Size" , SpvOpConstant, 12); |
2331 | if (num_words == 15) CHECK_OPERAND("Value" , SpvOpConstant, 14); |
2332 | break; |
2333 | } |
2334 | case OpenCLDebugInfo100DebugTypeInheritance: { |
2335 | CHECK_DEBUG_OPERAND("Child" , OpenCLDebugInfo100DebugTypeComposite, 5); |
2336 | auto* debug_inst = _.FindDef(inst->word(5)); |
2337 | auto composite_type = |
2338 | OpenCLDebugInfo100DebugCompositeType(debug_inst->word(6)); |
2339 | if (composite_type != OpenCLDebugInfo100Class && |
2340 | composite_type != OpenCLDebugInfo100Structure) { |
2341 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
2342 | << ext_inst_name() << ": " |
2343 | << "expected operand Child must be class or struct debug type" ; |
2344 | } |
2345 | CHECK_DEBUG_OPERAND("Parent" , OpenCLDebugInfo100DebugTypeComposite, 6); |
2346 | debug_inst = _.FindDef(inst->word(6)); |
2347 | composite_type = |
2348 | OpenCLDebugInfo100DebugCompositeType(debug_inst->word(6)); |
2349 | if (composite_type != OpenCLDebugInfo100Class && |
2350 | composite_type != OpenCLDebugInfo100Structure) { |
2351 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
2352 | << ext_inst_name() << ": " |
2353 | << "expected operand Parent must be class or struct debug " |
2354 | "type" ; |
2355 | } |
2356 | CHECK_OPERAND("Offset" , SpvOpConstant, 7); |
2357 | CHECK_OPERAND("Size" , SpvOpConstant, 8); |
2358 | break; |
2359 | } |
2360 | case OpenCLDebugInfo100DebugFunction: { |
2361 | CHECK_OPERAND("Name" , SpvOpString, 5); |
2362 | auto validate_type = |
2363 | ValidateOperandDebugType(_, "Type" , inst, 6, ext_inst_name); |
2364 | if (validate_type != SPV_SUCCESS) return validate_type; |
2365 | CHECK_DEBUG_OPERAND("Source" , OpenCLDebugInfo100DebugSource, 7); |
2366 | auto validate_parent = |
2367 | ValidateOperandLexicalScope(_, "Parent" , inst, 10, ext_inst_name); |
2368 | if (validate_parent != SPV_SUCCESS) return validate_parent; |
2369 | CHECK_OPERAND("Linkage Name" , SpvOpString, 11); |
2370 | // TODO: The current OpenCL.100.DebugInfo spec says "Function |
2371 | // is an OpFunction which is described by this instruction.". |
2372 | // However, the function definition can be opted-out e.g., |
2373 | // inlining. We assume that Function operand can be a |
2374 | // DebugInfoNone, but we must discuss it and update the spec. |
2375 | if (!DoesDebugInfoOperandMatchExpectation( |
2376 | _, |
2377 | [](OpenCLDebugInfo100Instructions dbg_inst) { |
2378 | return dbg_inst == OpenCLDebugInfo100DebugInfoNone; |
2379 | }, |
2380 | inst, 14)) { |
2381 | CHECK_OPERAND("Function" , SpvOpFunction, 14); |
2382 | } |
2383 | if (num_words == 16) { |
2384 | CHECK_DEBUG_OPERAND("Declaration" , |
2385 | OpenCLDebugInfo100DebugFunctionDeclaration, 15); |
2386 | } |
2387 | break; |
2388 | } |
2389 | case OpenCLDebugInfo100DebugFunctionDeclaration: { |
2390 | CHECK_OPERAND("Name" , SpvOpString, 5); |
2391 | auto validate_type = |
2392 | ValidateOperandDebugType(_, "Type" , inst, 6, ext_inst_name); |
2393 | if (validate_type != SPV_SUCCESS) return validate_type; |
2394 | CHECK_DEBUG_OPERAND("Source" , OpenCLDebugInfo100DebugSource, 7); |
2395 | auto validate_parent = |
2396 | ValidateOperandLexicalScope(_, "Parent" , inst, 10, ext_inst_name); |
2397 | if (validate_parent != SPV_SUCCESS) return validate_parent; |
2398 | CHECK_OPERAND("Linkage Name" , SpvOpString, 11); |
2399 | break; |
2400 | } |
2401 | case OpenCLDebugInfo100DebugLexicalBlock: { |
2402 | CHECK_DEBUG_OPERAND("Source" , OpenCLDebugInfo100DebugSource, 5); |
2403 | auto validate_parent = |
2404 | ValidateOperandLexicalScope(_, "Parent" , inst, 8, ext_inst_name); |
2405 | if (validate_parent != SPV_SUCCESS) return validate_parent; |
2406 | if (num_words == 10) CHECK_OPERAND("Name" , SpvOpString, 9); |
2407 | break; |
2408 | } |
2409 | case OpenCLDebugInfo100DebugScope: { |
2410 | // TODO(https://gitlab.khronos.org/spirv/SPIR-V/issues/533): We are |
2411 | // still in spec discussion about what must be "Scope" operand of |
2412 | // DebugScope. Update this code if the conclusion is different. |
2413 | auto validate_scope = |
2414 | ValidateOperandLexicalScope(_, "Scope" , inst, 5, ext_inst_name); |
2415 | if (validate_scope != SPV_SUCCESS) return validate_scope; |
2416 | if (num_words == 7) { |
2417 | CHECK_DEBUG_OPERAND("Inlined At" , OpenCLDebugInfo100DebugInlinedAt, |
2418 | 6); |
2419 | } |
2420 | break; |
2421 | } |
2422 | case OpenCLDebugInfo100DebugLocalVariable: { |
2423 | CHECK_OPERAND("Name" , SpvOpString, 5); |
2424 | auto validate_type = |
2425 | ValidateOperandDebugType(_, "Type" , inst, 6, ext_inst_name); |
2426 | if (validate_type != SPV_SUCCESS) return validate_type; |
2427 | CHECK_DEBUG_OPERAND("Source" , OpenCLDebugInfo100DebugSource, 7); |
2428 | auto validate_parent = |
2429 | ValidateOperandLexicalScope(_, "Parent" , inst, 10, ext_inst_name); |
2430 | if (validate_parent != SPV_SUCCESS) return validate_parent; |
2431 | break; |
2432 | } |
2433 | case OpenCLDebugInfo100DebugDeclare: { |
2434 | CHECK_DEBUG_OPERAND("Local Variable" , |
2435 | OpenCLDebugInfo100DebugLocalVariable, 5); |
2436 | |
2437 | // TODO: We must discuss DebugDeclare.Variable of OpenCL.100.DebugInfo. |
2438 | // Currently, it says "Variable must be an id of OpVariable instruction |
2439 | // which defines the local variable.", but we want to allow |
2440 | // OpFunctionParameter as well. |
2441 | auto* operand = _.FindDef(inst->word(6)); |
2442 | if (operand->opcode() != SpvOpVariable && |
2443 | operand->opcode() != SpvOpFunctionParameter) { |
2444 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
2445 | << ext_inst_name() << ": " |
2446 | << "expected operand Variable must be a result id of " |
2447 | "OpVariable or OpFunctionParameter" ; |
2448 | } |
2449 | |
2450 | CHECK_DEBUG_OPERAND("Expression" , OpenCLDebugInfo100DebugExpression, 7); |
2451 | break; |
2452 | } |
2453 | case OpenCLDebugInfo100DebugExpression: { |
2454 | for (uint32_t word_index = 5; word_index < num_words; ++word_index) { |
2455 | CHECK_DEBUG_OPERAND("Operation" , OpenCLDebugInfo100DebugOperation, |
2456 | word_index); |
2457 | } |
2458 | break; |
2459 | } |
2460 | |
2461 | // TODO: Add validation rules for remaining cases as well. |
2462 | case OpenCLDebugInfo100DebugTypePtrToMember: |
2463 | case OpenCLDebugInfo100DebugTypeTemplate: |
2464 | case OpenCLDebugInfo100DebugTypeTemplateParameter: |
2465 | case OpenCLDebugInfo100DebugTypeTemplateTemplateParameter: |
2466 | case OpenCLDebugInfo100DebugTypeTemplateParameterPack: |
2467 | case OpenCLDebugInfo100DebugGlobalVariable: |
2468 | case OpenCLDebugInfo100DebugLexicalBlockDiscriminator: |
2469 | case OpenCLDebugInfo100DebugInlinedAt: |
2470 | case OpenCLDebugInfo100DebugInlinedVariable: |
2471 | case OpenCLDebugInfo100DebugValue: |
2472 | case OpenCLDebugInfo100DebugMacroDef: |
2473 | case OpenCLDebugInfo100DebugMacroUndef: |
2474 | case OpenCLDebugInfo100DebugImportedEntity: |
2475 | break; |
2476 | case OpenCLDebugInfo100InstructionsMax: |
2477 | assert(0); |
2478 | break; |
2479 | } |
2480 | } |
2481 | |
2482 | return SPV_SUCCESS; |
2483 | } |
2484 | |
2485 | spv_result_t ExtensionPass(ValidationState_t& _, const Instruction* inst) { |
2486 | const SpvOp opcode = inst->opcode(); |
2487 | if (opcode == SpvOpExtension) return ValidateExtension(_, inst); |
2488 | if (opcode == SpvOpExtInstImport) return ValidateExtInstImport(_, inst); |
2489 | if (opcode == SpvOpExtInst) return ValidateExtInst(_, inst); |
2490 | |
2491 | return SPV_SUCCESS; |
2492 | } |
2493 | |
2494 | } // namespace val |
2495 | } // namespace spvtools |
2496 | |