• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2017 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 conversion instructions.
16 
17 #include "source/diagnostic.h"
18 #include "source/opcode.h"
19 #include "source/spirv_constant.h"
20 #include "source/spirv_target_env.h"
21 #include "source/val/instruction.h"
22 #include "source/val/validate.h"
23 #include "source/val/validation_state.h"
24 
25 namespace spvtools {
26 namespace val {
27 
28 // Validates correctness of conversion instructions.
ConversionPass(ValidationState_t & _,const Instruction * inst)29 spv_result_t ConversionPass(ValidationState_t& _, const Instruction* inst) {
30   const spv::Op opcode = inst->opcode();
31   const uint32_t result_type = inst->type_id();
32 
33   switch (opcode) {
34     case spv::Op::OpConvertFToU: {
35       if (!_.IsUnsignedIntScalarType(result_type) &&
36           !_.IsUnsignedIntVectorType(result_type) &&
37           !_.IsUnsignedIntCooperativeMatrixType(result_type))
38         return _.diag(SPV_ERROR_INVALID_DATA, inst)
39                << "Expected unsigned int scalar or vector type as Result Type: "
40                << spvOpcodeString(opcode);
41 
42       const uint32_t input_type = _.GetOperandTypeId(inst, 2);
43       if (!input_type || (!_.IsFloatScalarType(input_type) &&
44                           !_.IsFloatVectorType(input_type) &&
45                           !_.IsFloatCooperativeMatrixType(input_type)))
46         return _.diag(SPV_ERROR_INVALID_DATA, inst)
47                << "Expected input to be float scalar or vector: "
48                << spvOpcodeString(opcode);
49 
50       if (_.IsCooperativeMatrixType(result_type) ||
51           _.IsCooperativeMatrixType(input_type)) {
52         spv_result_t ret =
53             _.CooperativeMatrixShapesMatch(inst, result_type, input_type);
54         if (ret != SPV_SUCCESS) return ret;
55       } else {
56         if (_.GetDimension(result_type) != _.GetDimension(input_type))
57           return _.diag(SPV_ERROR_INVALID_DATA, inst)
58                  << "Expected input to have the same dimension as Result Type: "
59                  << spvOpcodeString(opcode);
60       }
61 
62       break;
63     }
64 
65     case spv::Op::OpConvertFToS: {
66       if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type) &&
67           !_.IsIntCooperativeMatrixType(result_type))
68         return _.diag(SPV_ERROR_INVALID_DATA, inst)
69                << "Expected int scalar or vector type as Result Type: "
70                << spvOpcodeString(opcode);
71 
72       const uint32_t input_type = _.GetOperandTypeId(inst, 2);
73       if (!input_type || (!_.IsFloatScalarType(input_type) &&
74                           !_.IsFloatVectorType(input_type) &&
75                           !_.IsFloatCooperativeMatrixType(input_type)))
76         return _.diag(SPV_ERROR_INVALID_DATA, inst)
77                << "Expected input to be float scalar or vector: "
78                << spvOpcodeString(opcode);
79 
80       if (_.IsCooperativeMatrixType(result_type) ||
81           _.IsCooperativeMatrixType(input_type)) {
82         spv_result_t ret =
83             _.CooperativeMatrixShapesMatch(inst, result_type, input_type);
84         if (ret != SPV_SUCCESS) return ret;
85       } else {
86         if (_.GetDimension(result_type) != _.GetDimension(input_type))
87           return _.diag(SPV_ERROR_INVALID_DATA, inst)
88                  << "Expected input to have the same dimension as Result Type: "
89                  << spvOpcodeString(opcode);
90       }
91 
92       break;
93     }
94 
95     case spv::Op::OpConvertSToF:
96     case spv::Op::OpConvertUToF: {
97       if (!_.IsFloatScalarType(result_type) &&
98           !_.IsFloatVectorType(result_type) &&
99           !_.IsFloatCooperativeMatrixType(result_type))
100         return _.diag(SPV_ERROR_INVALID_DATA, inst)
101                << "Expected float scalar or vector type as Result Type: "
102                << spvOpcodeString(opcode);
103 
104       const uint32_t input_type = _.GetOperandTypeId(inst, 2);
105       if (!input_type ||
106           (!_.IsIntScalarType(input_type) && !_.IsIntVectorType(input_type) &&
107            !_.IsIntCooperativeMatrixType(input_type)))
108         return _.diag(SPV_ERROR_INVALID_DATA, inst)
109                << "Expected input to be int scalar or vector: "
110                << spvOpcodeString(opcode);
111 
112       if (_.IsCooperativeMatrixType(result_type) ||
113           _.IsCooperativeMatrixType(input_type)) {
114         spv_result_t ret =
115             _.CooperativeMatrixShapesMatch(inst, result_type, input_type);
116         if (ret != SPV_SUCCESS) return ret;
117       } else {
118         if (_.GetDimension(result_type) != _.GetDimension(input_type))
119           return _.diag(SPV_ERROR_INVALID_DATA, inst)
120                  << "Expected input to have the same dimension as Result Type: "
121                  << spvOpcodeString(opcode);
122       }
123 
124       break;
125     }
126 
127     case spv::Op::OpUConvert: {
128       if (!_.IsUnsignedIntScalarType(result_type) &&
129           !_.IsUnsignedIntVectorType(result_type) &&
130           !_.IsUnsignedIntCooperativeMatrixType(result_type))
131         return _.diag(SPV_ERROR_INVALID_DATA, inst)
132                << "Expected unsigned int scalar or vector type as Result Type: "
133                << spvOpcodeString(opcode);
134 
135       const uint32_t input_type = _.GetOperandTypeId(inst, 2);
136       if (!input_type ||
137           (!_.IsIntScalarType(input_type) && !_.IsIntVectorType(input_type) &&
138            !_.IsIntCooperativeMatrixType(input_type)))
139         return _.diag(SPV_ERROR_INVALID_DATA, inst)
140                << "Expected input to be int scalar or vector: "
141                << spvOpcodeString(opcode);
142 
143       if (_.IsCooperativeMatrixType(result_type) ||
144           _.IsCooperativeMatrixType(input_type)) {
145         spv_result_t ret =
146             _.CooperativeMatrixShapesMatch(inst, result_type, input_type);
147         if (ret != SPV_SUCCESS) return ret;
148       } else {
149         if (_.GetDimension(result_type) != _.GetDimension(input_type))
150           return _.diag(SPV_ERROR_INVALID_DATA, inst)
151                  << "Expected input to have the same dimension as Result Type: "
152                  << spvOpcodeString(opcode);
153       }
154 
155       if (_.GetBitWidth(result_type) == _.GetBitWidth(input_type))
156         return _.diag(SPV_ERROR_INVALID_DATA, inst)
157                << "Expected input to have different bit width from Result "
158                   "Type: "
159                << spvOpcodeString(opcode);
160       break;
161     }
162 
163     case spv::Op::OpSConvert: {
164       if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type) &&
165           !_.IsIntCooperativeMatrixType(result_type))
166         return _.diag(SPV_ERROR_INVALID_DATA, inst)
167                << "Expected int scalar or vector type as Result Type: "
168                << spvOpcodeString(opcode);
169 
170       const uint32_t input_type = _.GetOperandTypeId(inst, 2);
171       if (!input_type ||
172           (!_.IsIntScalarType(input_type) && !_.IsIntVectorType(input_type) &&
173            !_.IsIntCooperativeMatrixType(input_type)))
174         return _.diag(SPV_ERROR_INVALID_DATA, inst)
175                << "Expected input to be int scalar or vector: "
176                << spvOpcodeString(opcode);
177 
178       if (_.IsCooperativeMatrixType(result_type) ||
179           _.IsCooperativeMatrixType(input_type)) {
180         spv_result_t ret =
181             _.CooperativeMatrixShapesMatch(inst, result_type, input_type);
182         if (ret != SPV_SUCCESS) return ret;
183       } else {
184         if (_.GetDimension(result_type) != _.GetDimension(input_type))
185           return _.diag(SPV_ERROR_INVALID_DATA, inst)
186                  << "Expected input to have the same dimension as Result Type: "
187                  << spvOpcodeString(opcode);
188       }
189 
190       if (_.GetBitWidth(result_type) == _.GetBitWidth(input_type))
191         return _.diag(SPV_ERROR_INVALID_DATA, inst)
192                << "Expected input to have different bit width from Result "
193                   "Type: "
194                << spvOpcodeString(opcode);
195       break;
196     }
197 
198     case spv::Op::OpFConvert: {
199       if (!_.IsFloatScalarType(result_type) &&
200           !_.IsFloatVectorType(result_type) &&
201           !_.IsFloatCooperativeMatrixType(result_type))
202         return _.diag(SPV_ERROR_INVALID_DATA, inst)
203                << "Expected float scalar or vector type as Result Type: "
204                << spvOpcodeString(opcode);
205 
206       const uint32_t input_type = _.GetOperandTypeId(inst, 2);
207       if (!input_type || (!_.IsFloatScalarType(input_type) &&
208                           !_.IsFloatVectorType(input_type) &&
209                           !_.IsFloatCooperativeMatrixType(input_type)))
210         return _.diag(SPV_ERROR_INVALID_DATA, inst)
211                << "Expected input to be float scalar or vector: "
212                << spvOpcodeString(opcode);
213 
214       if (_.IsCooperativeMatrixType(result_type) ||
215           _.IsCooperativeMatrixType(input_type)) {
216         spv_result_t ret =
217             _.CooperativeMatrixShapesMatch(inst, result_type, input_type);
218         if (ret != SPV_SUCCESS) return ret;
219       } else {
220         if (_.GetDimension(result_type) != _.GetDimension(input_type))
221           return _.diag(SPV_ERROR_INVALID_DATA, inst)
222                  << "Expected input to have the same dimension as Result Type: "
223                  << spvOpcodeString(opcode);
224       }
225 
226       if (_.GetBitWidth(result_type) == _.GetBitWidth(input_type))
227         return _.diag(SPV_ERROR_INVALID_DATA, inst)
228                << "Expected input to have different bit width from Result "
229                   "Type: "
230                << spvOpcodeString(opcode);
231       break;
232     }
233 
234     case spv::Op::OpQuantizeToF16: {
235       if ((!_.IsFloatScalarType(result_type) &&
236            !_.IsFloatVectorType(result_type)) ||
237           _.GetBitWidth(result_type) != 32)
238         return _.diag(SPV_ERROR_INVALID_DATA, inst)
239                << "Expected 32-bit float scalar or vector type as Result Type: "
240                << spvOpcodeString(opcode);
241 
242       const uint32_t input_type = _.GetOperandTypeId(inst, 2);
243       if (input_type != result_type)
244         return _.diag(SPV_ERROR_INVALID_DATA, inst)
245                << "Expected input type to be equal to Result Type: "
246                << spvOpcodeString(opcode);
247       break;
248     }
249 
250     case spv::Op::OpConvertPtrToU: {
251       if (!_.IsUnsignedIntScalarType(result_type))
252         return _.diag(SPV_ERROR_INVALID_DATA, inst)
253                << "Expected unsigned int scalar type as Result Type: "
254                << spvOpcodeString(opcode);
255 
256       const uint32_t input_type = _.GetOperandTypeId(inst, 2);
257       if (!_.IsPointerType(input_type))
258         return _.diag(SPV_ERROR_INVALID_DATA, inst)
259                << "Expected input to be a pointer: " << spvOpcodeString(opcode);
260 
261       if (_.addressing_model() == spv::AddressingModel::Logical)
262         return _.diag(SPV_ERROR_INVALID_DATA, inst)
263                << "Logical addressing not supported: "
264                << spvOpcodeString(opcode);
265 
266       if (_.addressing_model() ==
267           spv::AddressingModel::PhysicalStorageBuffer64) {
268         spv::StorageClass input_storage_class;
269         uint32_t input_data_type = 0;
270         _.GetPointerTypeInfo(input_type, &input_data_type,
271                              &input_storage_class);
272         if (input_storage_class != spv::StorageClass::PhysicalStorageBuffer)
273           return _.diag(SPV_ERROR_INVALID_DATA, inst)
274                  << "Pointer storage class must be PhysicalStorageBuffer: "
275                  << spvOpcodeString(opcode);
276 
277         if (spvIsVulkanEnv(_.context()->target_env)) {
278           if (_.GetBitWidth(result_type) != 64) {
279             return _.diag(SPV_ERROR_INVALID_DATA, inst)
280                    << _.VkErrorID(4710)
281                    << "PhysicalStorageBuffer64 addressing mode requires the "
282                       "result integer type to have a 64-bit width for Vulkan "
283                       "environment.";
284           }
285         }
286       }
287       break;
288     }
289 
290     case spv::Op::OpSatConvertSToU:
291     case spv::Op::OpSatConvertUToS: {
292       if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type))
293         return _.diag(SPV_ERROR_INVALID_DATA, inst)
294                << "Expected int scalar or vector type as Result Type: "
295                << spvOpcodeString(opcode);
296 
297       const uint32_t input_type = _.GetOperandTypeId(inst, 2);
298       if (!input_type ||
299           (!_.IsIntScalarType(input_type) && !_.IsIntVectorType(input_type)))
300         return _.diag(SPV_ERROR_INVALID_DATA, inst)
301                << "Expected int scalar or vector as input: "
302                << spvOpcodeString(opcode);
303 
304       if (_.GetDimension(result_type) != _.GetDimension(input_type))
305         return _.diag(SPV_ERROR_INVALID_DATA, inst)
306                << "Expected input to have the same dimension as Result Type: "
307                << spvOpcodeString(opcode);
308       break;
309     }
310 
311     case spv::Op::OpConvertUToPtr: {
312       if (!_.IsPointerType(result_type))
313         return _.diag(SPV_ERROR_INVALID_DATA, inst)
314                << "Expected Result Type to be a pointer: "
315                << spvOpcodeString(opcode);
316 
317       const uint32_t input_type = _.GetOperandTypeId(inst, 2);
318       if (!input_type || !_.IsIntScalarType(input_type))
319         return _.diag(SPV_ERROR_INVALID_DATA, inst)
320                << "Expected int scalar as input: " << spvOpcodeString(opcode);
321 
322       if (_.addressing_model() == spv::AddressingModel::Logical)
323         return _.diag(SPV_ERROR_INVALID_DATA, inst)
324                << "Logical addressing not supported: "
325                << spvOpcodeString(opcode);
326 
327       if (_.addressing_model() ==
328           spv::AddressingModel::PhysicalStorageBuffer64) {
329         spv::StorageClass result_storage_class;
330         uint32_t result_data_type = 0;
331         _.GetPointerTypeInfo(result_type, &result_data_type,
332                              &result_storage_class);
333         if (result_storage_class != spv::StorageClass::PhysicalStorageBuffer)
334           return _.diag(SPV_ERROR_INVALID_DATA, inst)
335                  << "Pointer storage class must be PhysicalStorageBuffer: "
336                  << spvOpcodeString(opcode);
337 
338         if (spvIsVulkanEnv(_.context()->target_env)) {
339           if (_.GetBitWidth(input_type) != 64) {
340             return _.diag(SPV_ERROR_INVALID_DATA, inst)
341                    << _.VkErrorID(4710)
342                    << "PhysicalStorageBuffer64 addressing mode requires the "
343                       "input integer to have a 64-bit width for Vulkan "
344                       "environment.";
345           }
346         }
347       }
348       break;
349     }
350 
351     case spv::Op::OpPtrCastToGeneric: {
352       spv::StorageClass result_storage_class;
353       uint32_t result_data_type = 0;
354       if (!_.GetPointerTypeInfo(result_type, &result_data_type,
355                                 &result_storage_class))
356         return _.diag(SPV_ERROR_INVALID_DATA, inst)
357                << "Expected Result Type to be a pointer: "
358                << spvOpcodeString(opcode);
359 
360       if (result_storage_class != spv::StorageClass::Generic)
361         return _.diag(SPV_ERROR_INVALID_DATA, inst)
362                << "Expected Result Type to have storage class Generic: "
363                << spvOpcodeString(opcode);
364 
365       const uint32_t input_type = _.GetOperandTypeId(inst, 2);
366       spv::StorageClass input_storage_class;
367       uint32_t input_data_type = 0;
368       if (!_.GetPointerTypeInfo(input_type, &input_data_type,
369                                 &input_storage_class))
370         return _.diag(SPV_ERROR_INVALID_DATA, inst)
371                << "Expected input to be a pointer: " << spvOpcodeString(opcode);
372 
373       if (input_storage_class != spv::StorageClass::Workgroup &&
374           input_storage_class != spv::StorageClass::CrossWorkgroup &&
375           input_storage_class != spv::StorageClass::Function)
376         return _.diag(SPV_ERROR_INVALID_DATA, inst)
377                << "Expected input to have storage class Workgroup, "
378                << "CrossWorkgroup or Function: " << spvOpcodeString(opcode);
379 
380       if (result_data_type != input_data_type)
381         return _.diag(SPV_ERROR_INVALID_DATA, inst)
382                << "Expected input and Result Type to point to the same type: "
383                << spvOpcodeString(opcode);
384       break;
385     }
386 
387     case spv::Op::OpGenericCastToPtr: {
388       spv::StorageClass result_storage_class;
389       uint32_t result_data_type = 0;
390       if (!_.GetPointerTypeInfo(result_type, &result_data_type,
391                                 &result_storage_class))
392         return _.diag(SPV_ERROR_INVALID_DATA, inst)
393                << "Expected Result Type to be a pointer: "
394                << spvOpcodeString(opcode);
395 
396       if (result_storage_class != spv::StorageClass::Workgroup &&
397           result_storage_class != spv::StorageClass::CrossWorkgroup &&
398           result_storage_class != spv::StorageClass::Function)
399         return _.diag(SPV_ERROR_INVALID_DATA, inst)
400                << "Expected Result Type to have storage class Workgroup, "
401                << "CrossWorkgroup or Function: " << spvOpcodeString(opcode);
402 
403       const uint32_t input_type = _.GetOperandTypeId(inst, 2);
404       spv::StorageClass input_storage_class;
405       uint32_t input_data_type = 0;
406       if (!_.GetPointerTypeInfo(input_type, &input_data_type,
407                                 &input_storage_class))
408         return _.diag(SPV_ERROR_INVALID_DATA, inst)
409                << "Expected input to be a pointer: " << spvOpcodeString(opcode);
410 
411       if (input_storage_class != spv::StorageClass::Generic)
412         return _.diag(SPV_ERROR_INVALID_DATA, inst)
413                << "Expected input to have storage class Generic: "
414                << spvOpcodeString(opcode);
415 
416       if (result_data_type != input_data_type)
417         return _.diag(SPV_ERROR_INVALID_DATA, inst)
418                << "Expected input and Result Type to point to the same type: "
419                << spvOpcodeString(opcode);
420       break;
421     }
422 
423     case spv::Op::OpGenericCastToPtrExplicit: {
424       spv::StorageClass result_storage_class;
425       uint32_t result_data_type = 0;
426       if (!_.GetPointerTypeInfo(result_type, &result_data_type,
427                                 &result_storage_class))
428         return _.diag(SPV_ERROR_INVALID_DATA, inst)
429                << "Expected Result Type to be a pointer: "
430                << spvOpcodeString(opcode);
431 
432       const auto target_storage_class =
433           inst->GetOperandAs<spv::StorageClass>(3);
434       if (result_storage_class != target_storage_class)
435         return _.diag(SPV_ERROR_INVALID_DATA, inst)
436                << "Expected Result Type to be of target storage class: "
437                << spvOpcodeString(opcode);
438 
439       const uint32_t input_type = _.GetOperandTypeId(inst, 2);
440       spv::StorageClass input_storage_class;
441       uint32_t input_data_type = 0;
442       if (!_.GetPointerTypeInfo(input_type, &input_data_type,
443                                 &input_storage_class))
444         return _.diag(SPV_ERROR_INVALID_DATA, inst)
445                << "Expected input to be a pointer: " << spvOpcodeString(opcode);
446 
447       if (input_storage_class != spv::StorageClass::Generic)
448         return _.diag(SPV_ERROR_INVALID_DATA, inst)
449                << "Expected input to have storage class Generic: "
450                << spvOpcodeString(opcode);
451 
452       if (result_data_type != input_data_type)
453         return _.diag(SPV_ERROR_INVALID_DATA, inst)
454                << "Expected input and Result Type to point to the same type: "
455                << spvOpcodeString(opcode);
456 
457       if (target_storage_class != spv::StorageClass::Workgroup &&
458           target_storage_class != spv::StorageClass::CrossWorkgroup &&
459           target_storage_class != spv::StorageClass::Function)
460         return _.diag(SPV_ERROR_INVALID_DATA, inst)
461                << "Expected target storage class to be Workgroup, "
462                << "CrossWorkgroup or Function: " << spvOpcodeString(opcode);
463       break;
464     }
465 
466     case spv::Op::OpBitcast: {
467       const uint32_t input_type = _.GetOperandTypeId(inst, 2);
468       if (!input_type)
469         return _.diag(SPV_ERROR_INVALID_DATA, inst)
470                << "Expected input to have a type: " << spvOpcodeString(opcode);
471 
472       const bool result_is_pointer = _.IsPointerType(result_type);
473       const bool result_is_int_scalar = _.IsIntScalarType(result_type);
474       const bool input_is_pointer = _.IsPointerType(input_type);
475       const bool input_is_int_scalar = _.IsIntScalarType(input_type);
476 
477       if (!result_is_pointer && !result_is_int_scalar &&
478           !_.IsIntVectorType(result_type) &&
479           !_.IsFloatScalarType(result_type) &&
480           !_.IsFloatVectorType(result_type))
481         return _.diag(SPV_ERROR_INVALID_DATA, inst)
482                << "Expected Result Type to be a pointer or int or float vector "
483                << "or scalar type: " << spvOpcodeString(opcode);
484 
485       if (!input_is_pointer && !input_is_int_scalar &&
486           !_.IsIntVectorType(input_type) && !_.IsFloatScalarType(input_type) &&
487           !_.IsFloatVectorType(input_type))
488         return _.diag(SPV_ERROR_INVALID_DATA, inst)
489                << "Expected input to be a pointer or int or float vector "
490                << "or scalar: " << spvOpcodeString(opcode);
491 
492       if (_.version() >= SPV_SPIRV_VERSION_WORD(1, 5) ||
493           _.HasExtension(kSPV_KHR_physical_storage_buffer)) {
494         const bool result_is_int_vector = _.IsIntVectorType(result_type);
495         const bool result_has_int32 =
496             _.ContainsSizedIntOrFloatType(result_type, spv::Op::OpTypeInt, 32);
497         const bool input_is_int_vector = _.IsIntVectorType(input_type);
498         const bool input_has_int32 =
499             _.ContainsSizedIntOrFloatType(input_type, spv::Op::OpTypeInt, 32);
500         if (result_is_pointer && !input_is_pointer && !input_is_int_scalar &&
501             !(input_is_int_vector && input_has_int32))
502           return _.diag(SPV_ERROR_INVALID_DATA, inst)
503                  << "Expected input to be a pointer, int scalar or 32-bit int "
504                     "vector if Result Type is pointer: "
505                  << spvOpcodeString(opcode);
506 
507         if (input_is_pointer && !result_is_pointer && !result_is_int_scalar &&
508             !(result_is_int_vector && result_has_int32))
509           return _.diag(SPV_ERROR_INVALID_DATA, inst)
510                  << "Pointer can only be converted to another pointer, int "
511                     "scalar or 32-bit int vector: "
512                  << spvOpcodeString(opcode);
513       } else {
514         if (result_is_pointer && !input_is_pointer && !input_is_int_scalar)
515           return _.diag(SPV_ERROR_INVALID_DATA, inst)
516                  << "Expected input to be a pointer or int scalar if Result "
517                     "Type is pointer: "
518                  << spvOpcodeString(opcode);
519 
520         if (input_is_pointer && !result_is_pointer && !result_is_int_scalar)
521           return _.diag(SPV_ERROR_INVALID_DATA, inst)
522                  << "Pointer can only be converted to another pointer or int "
523                     "scalar: "
524                  << spvOpcodeString(opcode);
525       }
526 
527       if (!result_is_pointer && !input_is_pointer) {
528         const uint32_t result_size =
529             _.GetBitWidth(result_type) * _.GetDimension(result_type);
530         const uint32_t input_size =
531             _.GetBitWidth(input_type) * _.GetDimension(input_type);
532         if (result_size != input_size)
533           return _.diag(SPV_ERROR_INVALID_DATA, inst)
534                  << "Expected input to have the same total bit width as "
535                  << "Result Type: " << spvOpcodeString(opcode);
536       }
537       break;
538     }
539 
540     case spv::Op::OpConvertUToAccelerationStructureKHR: {
541       if (!_.IsAccelerationStructureType(result_type)) {
542         return _.diag(SPV_ERROR_INVALID_DATA, inst)
543                << "Expected Result Type to be a Acceleration Structure: "
544                << spvOpcodeString(opcode);
545       }
546 
547       const uint32_t input_type = _.GetOperandTypeId(inst, 2);
548       if (!input_type || !_.IsUnsigned64BitHandle(input_type)) {
549         return _.diag(SPV_ERROR_INVALID_DATA, inst)
550                << "Expected 64-bit uint scalar or 2-component 32-bit uint "
551                   "vector as input: "
552                << spvOpcodeString(opcode);
553       }
554 
555       break;
556     }
557 
558     default:
559       break;
560   }
561 
562   if (_.HasCapability(spv::Capability::Shader)) {
563     switch (inst->opcode()) {
564       case spv::Op::OpConvertFToU:
565       case spv::Op::OpConvertFToS:
566       case spv::Op::OpConvertSToF:
567       case spv::Op::OpConvertUToF:
568       case spv::Op::OpBitcast:
569         if (_.ContainsLimitedUseIntOrFloatType(inst->type_id()) ||
570             _.ContainsLimitedUseIntOrFloatType(_.GetOperandTypeId(inst, 2u))) {
571           return _.diag(SPV_ERROR_INVALID_DATA, inst)
572                  << "8- or 16-bit types can only be used with width-only "
573                     "conversions";
574         }
575         break;
576       default:
577         break;
578     }
579   }
580 
581   return SPV_SUCCESS;
582 }
583 
584 }  // namespace val
585 }  // namespace spvtools
586