1 // Copyright (c) 2017 Google Inc.
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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"
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();
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
)) {
52 _
.CooperativeMatrixShapesMatch(inst
, result_type
, input_type
, true);
53 if (ret
!= SPV_SUCCESS
) return ret
;
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
);
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
)) {
82 _
.CooperativeMatrixShapesMatch(inst
, result_type
, input_type
, true);
83 if (ret
!= SPV_SUCCESS
) return ret
;
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
);
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);
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
)) {
114 _
.CooperativeMatrixShapesMatch(inst
, result_type
, input_type
, true);
115 if (ret
!= SPV_SUCCESS
) return ret
;
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
);
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);
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
)) {
145 _
.CooperativeMatrixShapesMatch(inst
, result_type
, input_type
, true);
146 if (ret
!= SPV_SUCCESS
) return ret
;
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 "
158 << spvOpcodeString(opcode
);
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);
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
)) {
180 _
.CooperativeMatrixShapesMatch(inst
, result_type
, input_type
, true);
181 if (ret
!= SPV_SUCCESS
) return ret
;
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 "
193 << spvOpcodeString(opcode
);
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
)) {
216 _
.CooperativeMatrixShapesMatch(inst
, result_type
, input_type
, true);
217 if (ret
!= SPV_SUCCESS
) return ret
;
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 "
229 << spvOpcodeString(opcode
);
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
);
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
)
280 << "PhysicalStorageBuffer64 addressing mode requires the "
281 "result integer type to have a 64-bit width for Vulkan "
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);
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
);
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
)
341 << "PhysicalStorageBuffer64 addressing mode requires the "
342 "input integer to have a 64-bit width for Vulkan "
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
);
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
);
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
);
465 case spv::Op::OpBitcast
: {
466 const uint32_t input_type
= _
.GetOperandTypeId(inst
, 2);
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
,
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
);
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 "
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 "
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
);
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 "
565 << spvOpcodeString(opcode
);
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
))
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
);
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 "
635 } // namespace spvtools