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