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