Roll external/abseil_cpp/ 8f739d18b..917bfee46 (2 commits) (#5887)
[KhronosGroup/SPIRV-Tools.git] / source / val / validate_conversion.cpp
blob770b8e2e33b9ced5a3482fafefce14f309c05c76
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.
15 // Validates correctness of conversion instructions.
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"
24 namespace spvtools {
25 namespace val {
27 // Validates correctness of conversion instructions.
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();
32 switch (opcode) {
33 case spv::Op::OpConvertFToU: {
34 if (!_.IsUnsignedIntScalarType(result_type) &&
35 !_.IsUnsignedIntVectorType(result_type) &&
36 !_.IsUnsignedIntCooperativeMatrixType(result_type))
37 return _.diag(SPV_ERROR_INVALID_DATA, inst)
38 << "Expected unsigned int scalar or vector type as Result Type: "
39 << spvOpcodeString(opcode);
41 const uint32_t input_type = _.GetOperandTypeId(inst, 2);
42 if (!input_type || (!_.IsFloatScalarType(input_type) &&
43 !_.IsFloatVectorType(input_type) &&
44 !_.IsFloatCooperativeMatrixType(input_type)))
45 return _.diag(SPV_ERROR_INVALID_DATA, inst)
46 << "Expected input to be float scalar or vector: "
47 << spvOpcodeString(opcode);
49 if (_.IsCooperativeMatrixType(result_type) ||
50 _.IsCooperativeMatrixType(input_type)) {
51 spv_result_t ret =
52 _.CooperativeMatrixShapesMatch(inst, result_type, input_type, true);
53 if (ret != SPV_SUCCESS) return ret;
54 } else {
55 if (_.GetDimension(result_type) != _.GetDimension(input_type))
56 return _.diag(SPV_ERROR_INVALID_DATA, inst)
57 << "Expected input to have the same dimension as Result Type: "
58 << spvOpcodeString(opcode);
61 break;
64 case spv::Op::OpConvertFToS: {
65 if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type) &&
66 !_.IsIntCooperativeMatrixType(result_type))
67 return _.diag(SPV_ERROR_INVALID_DATA, inst)
68 << "Expected int scalar or vector type as Result Type: "
69 << spvOpcodeString(opcode);
71 const uint32_t input_type = _.GetOperandTypeId(inst, 2);
72 if (!input_type || (!_.IsFloatScalarType(input_type) &&
73 !_.IsFloatVectorType(input_type) &&
74 !_.IsFloatCooperativeMatrixType(input_type)))
75 return _.diag(SPV_ERROR_INVALID_DATA, inst)
76 << "Expected input to be float scalar or vector: "
77 << spvOpcodeString(opcode);
79 if (_.IsCooperativeMatrixType(result_type) ||
80 _.IsCooperativeMatrixType(input_type)) {
81 spv_result_t ret =
82 _.CooperativeMatrixShapesMatch(inst, result_type, input_type, true);
83 if (ret != SPV_SUCCESS) return ret;
84 } else {
85 if (_.GetDimension(result_type) != _.GetDimension(input_type))
86 return _.diag(SPV_ERROR_INVALID_DATA, inst)
87 << "Expected input to have the same dimension as Result Type: "
88 << spvOpcodeString(opcode);
91 break;
94 case spv::Op::OpConvertSToF:
95 case spv::Op::OpConvertUToF: {
96 if (!_.IsFloatScalarType(result_type) &&
97 !_.IsFloatVectorType(result_type) &&
98 !_.IsFloatCooperativeMatrixType(result_type))
99 return _.diag(SPV_ERROR_INVALID_DATA, inst)
100 << "Expected float scalar or vector type as Result Type: "
101 << spvOpcodeString(opcode);
103 const uint32_t input_type = _.GetOperandTypeId(inst, 2);
104 if (!input_type ||
105 (!_.IsIntScalarType(input_type) && !_.IsIntVectorType(input_type) &&
106 !_.IsIntCooperativeMatrixType(input_type)))
107 return _.diag(SPV_ERROR_INVALID_DATA, inst)
108 << "Expected input to be int scalar or vector: "
109 << spvOpcodeString(opcode);
111 if (_.IsCooperativeMatrixType(result_type) ||
112 _.IsCooperativeMatrixType(input_type)) {
113 spv_result_t ret =
114 _.CooperativeMatrixShapesMatch(inst, result_type, input_type, true);
115 if (ret != SPV_SUCCESS) return ret;
116 } else {
117 if (_.GetDimension(result_type) != _.GetDimension(input_type))
118 return _.diag(SPV_ERROR_INVALID_DATA, inst)
119 << "Expected input to have the same dimension as Result Type: "
120 << spvOpcodeString(opcode);
123 break;
126 case spv::Op::OpUConvert: {
127 if (!_.IsUnsignedIntScalarType(result_type) &&
128 !_.IsUnsignedIntVectorType(result_type) &&
129 !_.IsUnsignedIntCooperativeMatrixType(result_type))
130 return _.diag(SPV_ERROR_INVALID_DATA, inst)
131 << "Expected unsigned int scalar or vector type as Result Type: "
132 << spvOpcodeString(opcode);
134 const uint32_t input_type = _.GetOperandTypeId(inst, 2);
135 if (!input_type ||
136 (!_.IsIntScalarType(input_type) && !_.IsIntVectorType(input_type) &&
137 !_.IsIntCooperativeMatrixType(input_type)))
138 return _.diag(SPV_ERROR_INVALID_DATA, inst)
139 << "Expected input to be int scalar or vector: "
140 << spvOpcodeString(opcode);
142 if (_.IsCooperativeMatrixType(result_type) ||
143 _.IsCooperativeMatrixType(input_type)) {
144 spv_result_t ret =
145 _.CooperativeMatrixShapesMatch(inst, result_type, input_type, true);
146 if (ret != SPV_SUCCESS) return ret;
147 } else {
148 if (_.GetDimension(result_type) != _.GetDimension(input_type))
149 return _.diag(SPV_ERROR_INVALID_DATA, inst)
150 << "Expected input to have the same dimension as Result Type: "
151 << spvOpcodeString(opcode);
154 if (_.GetBitWidth(result_type) == _.GetBitWidth(input_type))
155 return _.diag(SPV_ERROR_INVALID_DATA, inst)
156 << "Expected input to have different bit width from Result "
157 "Type: "
158 << spvOpcodeString(opcode);
159 break;
162 case spv::Op::OpSConvert: {
163 if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type) &&
164 !_.IsIntCooperativeMatrixType(result_type))
165 return _.diag(SPV_ERROR_INVALID_DATA, inst)
166 << "Expected int scalar or vector type as Result Type: "
167 << spvOpcodeString(opcode);
169 const uint32_t input_type = _.GetOperandTypeId(inst, 2);
170 if (!input_type ||
171 (!_.IsIntScalarType(input_type) && !_.IsIntVectorType(input_type) &&
172 !_.IsIntCooperativeMatrixType(input_type)))
173 return _.diag(SPV_ERROR_INVALID_DATA, inst)
174 << "Expected input to be int scalar or vector: "
175 << spvOpcodeString(opcode);
177 if (_.IsCooperativeMatrixType(result_type) ||
178 _.IsCooperativeMatrixType(input_type)) {
179 spv_result_t ret =
180 _.CooperativeMatrixShapesMatch(inst, result_type, input_type, true);
181 if (ret != SPV_SUCCESS) return ret;
182 } else {
183 if (_.GetDimension(result_type) != _.GetDimension(input_type))
184 return _.diag(SPV_ERROR_INVALID_DATA, inst)
185 << "Expected input to have the same dimension as Result Type: "
186 << spvOpcodeString(opcode);
189 if (_.GetBitWidth(result_type) == _.GetBitWidth(input_type))
190 return _.diag(SPV_ERROR_INVALID_DATA, inst)
191 << "Expected input to have different bit width from Result "
192 "Type: "
193 << spvOpcodeString(opcode);
194 break;
197 case spv::Op::OpFConvert: {
198 if (!_.IsFloatScalarType(result_type) &&
199 !_.IsFloatVectorType(result_type) &&
200 !_.IsFloatCooperativeMatrixType(result_type))
201 return _.diag(SPV_ERROR_INVALID_DATA, inst)
202 << "Expected float scalar or vector type as Result Type: "
203 << spvOpcodeString(opcode);
205 const uint32_t input_type = _.GetOperandTypeId(inst, 2);
206 if (!input_type || (!_.IsFloatScalarType(input_type) &&
207 !_.IsFloatVectorType(input_type) &&
208 !_.IsFloatCooperativeMatrixType(input_type)))
209 return _.diag(SPV_ERROR_INVALID_DATA, inst)
210 << "Expected input to be float scalar or vector: "
211 << spvOpcodeString(opcode);
213 if (_.IsCooperativeMatrixType(result_type) ||
214 _.IsCooperativeMatrixType(input_type)) {
215 spv_result_t ret =
216 _.CooperativeMatrixShapesMatch(inst, result_type, input_type, true);
217 if (ret != SPV_SUCCESS) return ret;
218 } else {
219 if (_.GetDimension(result_type) != _.GetDimension(input_type))
220 return _.diag(SPV_ERROR_INVALID_DATA, inst)
221 << "Expected input to have the same dimension as Result Type: "
222 << spvOpcodeString(opcode);
225 if (_.GetBitWidth(result_type) == _.GetBitWidth(input_type))
226 return _.diag(SPV_ERROR_INVALID_DATA, inst)
227 << "Expected input to have different bit width from Result "
228 "Type: "
229 << spvOpcodeString(opcode);
230 break;
233 case spv::Op::OpQuantizeToF16: {
234 if ((!_.IsFloatScalarType(result_type) &&
235 !_.IsFloatVectorType(result_type)) ||
236 _.GetBitWidth(result_type) != 32)
237 return _.diag(SPV_ERROR_INVALID_DATA, inst)
238 << "Expected 32-bit float scalar or vector type as Result Type: "
239 << spvOpcodeString(opcode);
241 const uint32_t input_type = _.GetOperandTypeId(inst, 2);
242 if (input_type != result_type)
243 return _.diag(SPV_ERROR_INVALID_DATA, inst)
244 << "Expected input type to be equal to Result Type: "
245 << spvOpcodeString(opcode);
246 break;
249 case spv::Op::OpConvertPtrToU: {
250 if (!_.IsUnsignedIntScalarType(result_type))
251 return _.diag(SPV_ERROR_INVALID_DATA, inst)
252 << "Expected unsigned int scalar type as Result Type: "
253 << spvOpcodeString(opcode);
255 const uint32_t input_type = _.GetOperandTypeId(inst, 2);
256 if (!_.IsPointerType(input_type))
257 return _.diag(SPV_ERROR_INVALID_DATA, inst)
258 << "Expected input to be a pointer: " << spvOpcodeString(opcode);
260 if (_.addressing_model() == spv::AddressingModel::Logical)
261 return _.diag(SPV_ERROR_INVALID_DATA, inst)
262 << "Logical addressing not supported: "
263 << spvOpcodeString(opcode);
265 if (_.addressing_model() ==
266 spv::AddressingModel::PhysicalStorageBuffer64) {
267 spv::StorageClass input_storage_class;
268 uint32_t input_data_type = 0;
269 _.GetPointerTypeInfo(input_type, &input_data_type,
270 &input_storage_class);
271 if (input_storage_class != spv::StorageClass::PhysicalStorageBuffer)
272 return _.diag(SPV_ERROR_INVALID_DATA, inst)
273 << "Pointer storage class must be PhysicalStorageBuffer: "
274 << spvOpcodeString(opcode);
276 if (spvIsVulkanEnv(_.context()->target_env)) {
277 if (_.GetBitWidth(result_type) != 64) {
278 return _.diag(SPV_ERROR_INVALID_DATA, inst)
279 << _.VkErrorID(4710)
280 << "PhysicalStorageBuffer64 addressing mode requires the "
281 "result integer type to have a 64-bit width for Vulkan "
282 "environment.";
286 break;
289 case spv::Op::OpSatConvertSToU:
290 case spv::Op::OpSatConvertUToS: {
291 if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type))
292 return _.diag(SPV_ERROR_INVALID_DATA, inst)
293 << "Expected int scalar or vector type as Result Type: "
294 << spvOpcodeString(opcode);
296 const uint32_t input_type = _.GetOperandTypeId(inst, 2);
297 if (!input_type ||
298 (!_.IsIntScalarType(input_type) && !_.IsIntVectorType(input_type)))
299 return _.diag(SPV_ERROR_INVALID_DATA, inst)
300 << "Expected int scalar or vector as input: "
301 << spvOpcodeString(opcode);
303 if (_.GetDimension(result_type) != _.GetDimension(input_type))
304 return _.diag(SPV_ERROR_INVALID_DATA, inst)
305 << "Expected input to have the same dimension as Result Type: "
306 << spvOpcodeString(opcode);
307 break;
310 case spv::Op::OpConvertUToPtr: {
311 if (!_.IsPointerType(result_type))
312 return _.diag(SPV_ERROR_INVALID_DATA, inst)
313 << "Expected Result Type to be a pointer: "
314 << spvOpcodeString(opcode);
316 const uint32_t input_type = _.GetOperandTypeId(inst, 2);
317 if (!input_type || !_.IsIntScalarType(input_type))
318 return _.diag(SPV_ERROR_INVALID_DATA, inst)
319 << "Expected int scalar as input: " << spvOpcodeString(opcode);
321 if (_.addressing_model() == spv::AddressingModel::Logical)
322 return _.diag(SPV_ERROR_INVALID_DATA, inst)
323 << "Logical addressing not supported: "
324 << spvOpcodeString(opcode);
326 if (_.addressing_model() ==
327 spv::AddressingModel::PhysicalStorageBuffer64) {
328 spv::StorageClass result_storage_class;
329 uint32_t result_data_type = 0;
330 _.GetPointerTypeInfo(result_type, &result_data_type,
331 &result_storage_class);
332 if (result_storage_class != spv::StorageClass::PhysicalStorageBuffer)
333 return _.diag(SPV_ERROR_INVALID_DATA, inst)
334 << "Pointer storage class must be PhysicalStorageBuffer: "
335 << spvOpcodeString(opcode);
337 if (spvIsVulkanEnv(_.context()->target_env)) {
338 if (_.GetBitWidth(input_type) != 64) {
339 return _.diag(SPV_ERROR_INVALID_DATA, inst)
340 << _.VkErrorID(4710)
341 << "PhysicalStorageBuffer64 addressing mode requires the "
342 "input integer to have a 64-bit width for Vulkan "
343 "environment.";
347 break;
350 case spv::Op::OpPtrCastToGeneric: {
351 spv::StorageClass result_storage_class;
352 uint32_t result_data_type = 0;
353 if (!_.GetPointerTypeInfo(result_type, &result_data_type,
354 &result_storage_class))
355 return _.diag(SPV_ERROR_INVALID_DATA, inst)
356 << "Expected Result Type to be a pointer: "
357 << spvOpcodeString(opcode);
359 if (result_storage_class != spv::StorageClass::Generic)
360 return _.diag(SPV_ERROR_INVALID_DATA, inst)
361 << "Expected Result Type to have storage class Generic: "
362 << spvOpcodeString(opcode);
364 const uint32_t input_type = _.GetOperandTypeId(inst, 2);
365 spv::StorageClass input_storage_class;
366 uint32_t input_data_type = 0;
367 if (!_.GetPointerTypeInfo(input_type, &input_data_type,
368 &input_storage_class))
369 return _.diag(SPV_ERROR_INVALID_DATA, inst)
370 << "Expected input to be a pointer: " << spvOpcodeString(opcode);
372 if (input_storage_class != spv::StorageClass::Workgroup &&
373 input_storage_class != spv::StorageClass::CrossWorkgroup &&
374 input_storage_class != spv::StorageClass::Function)
375 return _.diag(SPV_ERROR_INVALID_DATA, inst)
376 << "Expected input to have storage class Workgroup, "
377 << "CrossWorkgroup or Function: " << spvOpcodeString(opcode);
379 if (result_data_type != input_data_type)
380 return _.diag(SPV_ERROR_INVALID_DATA, inst)
381 << "Expected input and Result Type to point to the same type: "
382 << spvOpcodeString(opcode);
383 break;
386 case spv::Op::OpGenericCastToPtr: {
387 spv::StorageClass result_storage_class;
388 uint32_t result_data_type = 0;
389 if (!_.GetPointerTypeInfo(result_type, &result_data_type,
390 &result_storage_class))
391 return _.diag(SPV_ERROR_INVALID_DATA, inst)
392 << "Expected Result Type to be a pointer: "
393 << spvOpcodeString(opcode);
395 if (result_storage_class != spv::StorageClass::Workgroup &&
396 result_storage_class != spv::StorageClass::CrossWorkgroup &&
397 result_storage_class != spv::StorageClass::Function)
398 return _.diag(SPV_ERROR_INVALID_DATA, inst)
399 << "Expected Result Type to have storage class Workgroup, "
400 << "CrossWorkgroup or Function: " << spvOpcodeString(opcode);
402 const uint32_t input_type = _.GetOperandTypeId(inst, 2);
403 spv::StorageClass input_storage_class;
404 uint32_t input_data_type = 0;
405 if (!_.GetPointerTypeInfo(input_type, &input_data_type,
406 &input_storage_class))
407 return _.diag(SPV_ERROR_INVALID_DATA, inst)
408 << "Expected input to be a pointer: " << spvOpcodeString(opcode);
410 if (input_storage_class != spv::StorageClass::Generic)
411 return _.diag(SPV_ERROR_INVALID_DATA, inst)
412 << "Expected input to have storage class Generic: "
413 << spvOpcodeString(opcode);
415 if (result_data_type != input_data_type)
416 return _.diag(SPV_ERROR_INVALID_DATA, inst)
417 << "Expected input and Result Type to point to the same type: "
418 << spvOpcodeString(opcode);
419 break;
422 case spv::Op::OpGenericCastToPtrExplicit: {
423 spv::StorageClass result_storage_class;
424 uint32_t result_data_type = 0;
425 if (!_.GetPointerTypeInfo(result_type, &result_data_type,
426 &result_storage_class))
427 return _.diag(SPV_ERROR_INVALID_DATA, inst)
428 << "Expected Result Type to be a pointer: "
429 << spvOpcodeString(opcode);
431 const auto target_storage_class =
432 inst->GetOperandAs<spv::StorageClass>(3);
433 if (result_storage_class != target_storage_class)
434 return _.diag(SPV_ERROR_INVALID_DATA, inst)
435 << "Expected Result Type to be of target storage class: "
436 << spvOpcodeString(opcode);
438 const uint32_t input_type = _.GetOperandTypeId(inst, 2);
439 spv::StorageClass input_storage_class;
440 uint32_t input_data_type = 0;
441 if (!_.GetPointerTypeInfo(input_type, &input_data_type,
442 &input_storage_class))
443 return _.diag(SPV_ERROR_INVALID_DATA, inst)
444 << "Expected input to be a pointer: " << spvOpcodeString(opcode);
446 if (input_storage_class != spv::StorageClass::Generic)
447 return _.diag(SPV_ERROR_INVALID_DATA, inst)
448 << "Expected input to have storage class Generic: "
449 << spvOpcodeString(opcode);
451 if (result_data_type != input_data_type)
452 return _.diag(SPV_ERROR_INVALID_DATA, inst)
453 << "Expected input and Result Type to point to the same type: "
454 << spvOpcodeString(opcode);
456 if (target_storage_class != spv::StorageClass::Workgroup &&
457 target_storage_class != spv::StorageClass::CrossWorkgroup &&
458 target_storage_class != spv::StorageClass::Function)
459 return _.diag(SPV_ERROR_INVALID_DATA, inst)
460 << "Expected target storage class to be Workgroup, "
461 << "CrossWorkgroup or Function: " << spvOpcodeString(opcode);
462 break;
465 case spv::Op::OpBitcast: {
466 const uint32_t input_type = _.GetOperandTypeId(inst, 2);
467 if (!input_type)
468 return _.diag(SPV_ERROR_INVALID_DATA, inst)
469 << "Expected input to have a type: " << spvOpcodeString(opcode);
471 const bool result_is_pointer = _.IsPointerType(result_type);
472 const bool result_is_int_scalar = _.IsIntScalarType(result_type);
473 const bool input_is_pointer = _.IsPointerType(input_type);
474 const bool input_is_int_scalar = _.IsIntScalarType(input_type);
476 const bool result_is_coopmat = _.IsCooperativeMatrixType(result_type);
477 const bool input_is_coopmat = _.IsCooperativeMatrixType(input_type);
479 if (!result_is_pointer && !result_is_int_scalar && !result_is_coopmat &&
480 !_.IsIntVectorType(result_type) &&
481 !_.IsFloatScalarType(result_type) &&
482 !_.IsFloatVectorType(result_type))
483 return _.diag(SPV_ERROR_INVALID_DATA, inst)
484 << "Expected Result Type to be a pointer or int or float vector "
485 << "or scalar type: " << spvOpcodeString(opcode);
487 if (!input_is_pointer && !input_is_int_scalar && !input_is_coopmat &&
488 !_.IsIntVectorType(input_type) && !_.IsFloatScalarType(input_type) &&
489 !_.IsFloatVectorType(input_type))
490 return _.diag(SPV_ERROR_INVALID_DATA, inst)
491 << "Expected input to be a pointer or int or float vector "
492 << "or scalar: " << spvOpcodeString(opcode);
494 if (result_is_coopmat != input_is_coopmat)
495 return _.diag(SPV_ERROR_INVALID_DATA, inst)
496 << "Cooperative matrix can only be cast to another cooperative "
497 << "matrix: " << spvOpcodeString(opcode);
499 if (result_is_coopmat) {
500 spv_result_t ret = _.CooperativeMatrixShapesMatch(inst, result_type,
501 input_type, false);
502 if (ret != SPV_SUCCESS) return ret;
505 if (_.version() >= SPV_SPIRV_VERSION_WORD(1, 5) ||
506 _.HasExtension(kSPV_KHR_physical_storage_buffer)) {
507 const bool result_is_int_vector = _.IsIntVectorType(result_type);
508 const bool result_has_int32 =
509 _.ContainsSizedIntOrFloatType(result_type, spv::Op::OpTypeInt, 32);
510 const bool input_is_int_vector = _.IsIntVectorType(input_type);
511 const bool input_has_int32 =
512 _.ContainsSizedIntOrFloatType(input_type, spv::Op::OpTypeInt, 32);
513 if (result_is_pointer && !input_is_pointer && !input_is_int_scalar &&
514 !(input_is_int_vector && input_has_int32))
515 return _.diag(SPV_ERROR_INVALID_DATA, inst)
516 << "Expected input to be a pointer, int scalar or 32-bit int "
517 "vector if Result Type is pointer: "
518 << spvOpcodeString(opcode);
520 if (input_is_pointer && !result_is_pointer && !result_is_int_scalar &&
521 !(result_is_int_vector && result_has_int32))
522 return _.diag(SPV_ERROR_INVALID_DATA, inst)
523 << "Pointer can only be converted to another pointer, int "
524 "scalar or 32-bit int vector: "
525 << spvOpcodeString(opcode);
526 } else {
527 if (result_is_pointer && !input_is_pointer && !input_is_int_scalar)
528 return _.diag(SPV_ERROR_INVALID_DATA, inst)
529 << "Expected input to be a pointer or int scalar if Result "
530 "Type is pointer: "
531 << spvOpcodeString(opcode);
533 if (input_is_pointer && !result_is_pointer && !result_is_int_scalar)
534 return _.diag(SPV_ERROR_INVALID_DATA, inst)
535 << "Pointer can only be converted to another pointer or int "
536 "scalar: "
537 << spvOpcodeString(opcode);
540 if (!result_is_pointer && !input_is_pointer) {
541 const uint32_t result_size =
542 _.GetBitWidth(result_type) * _.GetDimension(result_type);
543 const uint32_t input_size =
544 _.GetBitWidth(input_type) * _.GetDimension(input_type);
545 if (result_size != input_size)
546 return _.diag(SPV_ERROR_INVALID_DATA, inst)
547 << "Expected input to have the same total bit width as "
548 << "Result Type: " << spvOpcodeString(opcode);
550 break;
553 case spv::Op::OpConvertUToAccelerationStructureKHR: {
554 if (!_.IsAccelerationStructureType(result_type)) {
555 return _.diag(SPV_ERROR_INVALID_DATA, inst)
556 << "Expected Result Type to be a Acceleration Structure: "
557 << spvOpcodeString(opcode);
560 const uint32_t input_type = _.GetOperandTypeId(inst, 2);
561 if (!input_type || !_.IsUnsigned64BitHandle(input_type)) {
562 return _.diag(SPV_ERROR_INVALID_DATA, inst)
563 << "Expected 64-bit uint scalar or 2-component 32-bit uint "
564 "vector as input: "
565 << spvOpcodeString(opcode);
568 break;
571 case spv::Op::OpCooperativeMatrixConvertNV:
572 case spv::Op::OpCooperativeMatrixTransposeNV: {
573 if (!_.IsCooperativeMatrixType(result_type)) {
574 return _.diag(SPV_ERROR_INVALID_DATA, inst)
575 << "Expected cooperative matrix Result Type: "
576 << spvOpcodeString(opcode);
578 const uint32_t input_type = _.GetOperandTypeId(inst, 2);
579 if (!_.IsCooperativeMatrixType(input_type)) {
580 return _.diag(SPV_ERROR_INVALID_DATA, inst)
581 << "Expected cooperative matrix type for Matrix input: "
582 << spvOpcodeString(opcode);
585 bool swap_row_col = (opcode == spv::Op::OpCooperativeMatrixTransposeNV);
586 if (auto error = _.CooperativeMatrixShapesMatch(
587 inst, result_type, input_type, true, swap_row_col))
588 return error;
590 if (opcode == spv::Op::OpCooperativeMatrixConvertNV) {
591 if (_.FindDef(result_type)->GetOperandAs<uint32_t>(1) !=
592 _.FindDef(input_type)->GetOperandAs<uint32_t>(1)) {
593 return _.diag(SPV_ERROR_INVALID_DATA, inst)
594 << "Result Type and Matrix component types mismatch: "
595 << spvOpcodeString(opcode);
599 if (opcode == spv::Op::OpCooperativeMatrixTransposeNV) {
600 if (!_.IsCooperativeMatrixBType(result_type)) {
601 return _.diag(SPV_ERROR_INVALID_DATA, inst)
602 << "Result Type must have UseB: " << spvOpcodeString(opcode);
605 break;
608 default:
609 break;
612 if (_.HasCapability(spv::Capability::Shader)) {
613 switch (inst->opcode()) {
614 case spv::Op::OpConvertFToU:
615 case spv::Op::OpConvertFToS:
616 case spv::Op::OpConvertSToF:
617 case spv::Op::OpConvertUToF:
618 case spv::Op::OpBitcast:
619 if (_.ContainsLimitedUseIntOrFloatType(inst->type_id()) ||
620 _.ContainsLimitedUseIntOrFloatType(_.GetOperandTypeId(inst, 2u))) {
621 return _.diag(SPV_ERROR_INVALID_DATA, inst)
622 << "8- or 16-bit types can only be used with width-only "
623 "conversions";
625 break;
626 default:
627 break;
631 return SPV_SUCCESS;
634 } // namespace val
635 } // namespace spvtools