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 SpvOp opcode = inst->opcode();
31 const uint32_t result_type = inst->type_id();
32
33 switch (opcode) {
34 case SpvOpConvertFToU: {
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 SpvOpConvertFToS: {
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 SpvOpConvertSToF:
96 case SpvOpConvertUToF: {
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 SpvOpUConvert: {
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 SpvOpSConvert: {
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 SpvOpFConvert: {
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 SpvOpQuantizeToF16: {
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 SpvOpConvertPtrToU: {
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() == SpvAddressingModelLogical)
262 return _.diag(SPV_ERROR_INVALID_DATA, inst)
263 << "Logical addressing not supported: "
264 << spvOpcodeString(opcode);
265
266 if (_.addressing_model() == SpvAddressingModelPhysicalStorageBuffer64) {
267 uint32_t input_storage_class = 0;
268 uint32_t input_data_type = 0;
269 _.GetPointerTypeInfo(input_type, &input_data_type,
270 &input_storage_class);
271 if (input_storage_class != SpvStorageClassPhysicalStorageBuffer)
272 return _.diag(SPV_ERROR_INVALID_DATA, inst)
273 << "Pointer storage class must be PhysicalStorageBuffer: "
274 << spvOpcodeString(opcode);
275
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.";
283 }
284 }
285 }
286 break;
287 }
288
289 case SpvOpSatConvertSToU:
290 case SpvOpSatConvertUToS: {
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);
295
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);
302
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;
308 }
309
310 case SpvOpConvertUToPtr: {
311 if (!_.IsPointerType(result_type))
312 return _.diag(SPV_ERROR_INVALID_DATA, inst)
313 << "Expected Result Type to be a pointer: "
314 << spvOpcodeString(opcode);
315
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);
320
321 if (_.addressing_model() == SpvAddressingModelLogical)
322 return _.diag(SPV_ERROR_INVALID_DATA, inst)
323 << "Logical addressing not supported: "
324 << spvOpcodeString(opcode);
325
326 if (_.addressing_model() == SpvAddressingModelPhysicalStorageBuffer64) {
327 uint32_t result_storage_class = 0;
328 uint32_t result_data_type = 0;
329 _.GetPointerTypeInfo(result_type, &result_data_type,
330 &result_storage_class);
331 if (result_storage_class != SpvStorageClassPhysicalStorageBuffer)
332 return _.diag(SPV_ERROR_INVALID_DATA, inst)
333 << "Pointer storage class must be PhysicalStorageBuffer: "
334 << spvOpcodeString(opcode);
335
336 if (spvIsVulkanEnv(_.context()->target_env)) {
337 if (_.GetBitWidth(input_type) != 64) {
338 return _.diag(SPV_ERROR_INVALID_DATA, inst)
339 << _.VkErrorID(4710)
340 << "PhysicalStorageBuffer64 addressing mode requires the "
341 "input integer to have a 64-bit width for Vulkan "
342 "environment.";
343 }
344 }
345 }
346 break;
347 }
348
349 case SpvOpPtrCastToGeneric: {
350 uint32_t result_storage_class = 0;
351 uint32_t result_data_type = 0;
352 if (!_.GetPointerTypeInfo(result_type, &result_data_type,
353 &result_storage_class))
354 return _.diag(SPV_ERROR_INVALID_DATA, inst)
355 << "Expected Result Type to be a pointer: "
356 << spvOpcodeString(opcode);
357
358 if (result_storage_class != SpvStorageClassGeneric)
359 return _.diag(SPV_ERROR_INVALID_DATA, inst)
360 << "Expected Result Type to have storage class Generic: "
361 << spvOpcodeString(opcode);
362
363 const uint32_t input_type = _.GetOperandTypeId(inst, 2);
364 uint32_t input_storage_class = 0;
365 uint32_t input_data_type = 0;
366 if (!_.GetPointerTypeInfo(input_type, &input_data_type,
367 &input_storage_class))
368 return _.diag(SPV_ERROR_INVALID_DATA, inst)
369 << "Expected input to be a pointer: " << spvOpcodeString(opcode);
370
371 if (input_storage_class != SpvStorageClassWorkgroup &&
372 input_storage_class != SpvStorageClassCrossWorkgroup &&
373 input_storage_class != SpvStorageClassFunction)
374 return _.diag(SPV_ERROR_INVALID_DATA, inst)
375 << "Expected input to have storage class Workgroup, "
376 << "CrossWorkgroup or Function: " << spvOpcodeString(opcode);
377
378 if (result_data_type != input_data_type)
379 return _.diag(SPV_ERROR_INVALID_DATA, inst)
380 << "Expected input and Result Type to point to the same type: "
381 << spvOpcodeString(opcode);
382 break;
383 }
384
385 case SpvOpGenericCastToPtr: {
386 uint32_t result_storage_class = 0;
387 uint32_t result_data_type = 0;
388 if (!_.GetPointerTypeInfo(result_type, &result_data_type,
389 &result_storage_class))
390 return _.diag(SPV_ERROR_INVALID_DATA, inst)
391 << "Expected Result Type to be a pointer: "
392 << spvOpcodeString(opcode);
393
394 if (result_storage_class != SpvStorageClassWorkgroup &&
395 result_storage_class != SpvStorageClassCrossWorkgroup &&
396 result_storage_class != SpvStorageClassFunction)
397 return _.diag(SPV_ERROR_INVALID_DATA, inst)
398 << "Expected Result Type to have storage class Workgroup, "
399 << "CrossWorkgroup or Function: " << spvOpcodeString(opcode);
400
401 const uint32_t input_type = _.GetOperandTypeId(inst, 2);
402 uint32_t input_storage_class = 0;
403 uint32_t input_data_type = 0;
404 if (!_.GetPointerTypeInfo(input_type, &input_data_type,
405 &input_storage_class))
406 return _.diag(SPV_ERROR_INVALID_DATA, inst)
407 << "Expected input to be a pointer: " << spvOpcodeString(opcode);
408
409 if (input_storage_class != SpvStorageClassGeneric)
410 return _.diag(SPV_ERROR_INVALID_DATA, inst)
411 << "Expected input to have storage class Generic: "
412 << spvOpcodeString(opcode);
413
414 if (result_data_type != input_data_type)
415 return _.diag(SPV_ERROR_INVALID_DATA, inst)
416 << "Expected input and Result Type to point to the same type: "
417 << spvOpcodeString(opcode);
418 break;
419 }
420
421 case SpvOpGenericCastToPtrExplicit: {
422 uint32_t result_storage_class = 0;
423 uint32_t result_data_type = 0;
424 if (!_.GetPointerTypeInfo(result_type, &result_data_type,
425 &result_storage_class))
426 return _.diag(SPV_ERROR_INVALID_DATA, inst)
427 << "Expected Result Type to be a pointer: "
428 << spvOpcodeString(opcode);
429
430 const uint32_t target_storage_class = inst->word(4);
431 if (result_storage_class != target_storage_class)
432 return _.diag(SPV_ERROR_INVALID_DATA, inst)
433 << "Expected Result Type to be of target storage class: "
434 << spvOpcodeString(opcode);
435
436 const uint32_t input_type = _.GetOperandTypeId(inst, 2);
437 uint32_t input_storage_class = 0;
438 uint32_t input_data_type = 0;
439 if (!_.GetPointerTypeInfo(input_type, &input_data_type,
440 &input_storage_class))
441 return _.diag(SPV_ERROR_INVALID_DATA, inst)
442 << "Expected input to be a pointer: " << spvOpcodeString(opcode);
443
444 if (input_storage_class != SpvStorageClassGeneric)
445 return _.diag(SPV_ERROR_INVALID_DATA, inst)
446 << "Expected input to have storage class Generic: "
447 << spvOpcodeString(opcode);
448
449 if (result_data_type != input_data_type)
450 return _.diag(SPV_ERROR_INVALID_DATA, inst)
451 << "Expected input and Result Type to point to the same type: "
452 << spvOpcodeString(opcode);
453
454 if (target_storage_class != SpvStorageClassWorkgroup &&
455 target_storage_class != SpvStorageClassCrossWorkgroup &&
456 target_storage_class != SpvStorageClassFunction)
457 return _.diag(SPV_ERROR_INVALID_DATA, inst)
458 << "Expected target storage class to be Workgroup, "
459 << "CrossWorkgroup or Function: " << spvOpcodeString(opcode);
460 break;
461 }
462
463 case SpvOpBitcast: {
464 const uint32_t input_type = _.GetOperandTypeId(inst, 2);
465 if (!input_type)
466 return _.diag(SPV_ERROR_INVALID_DATA, inst)
467 << "Expected input to have a type: " << spvOpcodeString(opcode);
468
469 const bool result_is_pointer = _.IsPointerType(result_type);
470 const bool result_is_int_scalar = _.IsIntScalarType(result_type);
471 const bool input_is_pointer = _.IsPointerType(input_type);
472 const bool input_is_int_scalar = _.IsIntScalarType(input_type);
473
474 if (!result_is_pointer && !result_is_int_scalar &&
475 !_.IsIntVectorType(result_type) &&
476 !_.IsFloatScalarType(result_type) &&
477 !_.IsFloatVectorType(result_type))
478 return _.diag(SPV_ERROR_INVALID_DATA, inst)
479 << "Expected Result Type to be a pointer or int or float vector "
480 << "or scalar type: " << spvOpcodeString(opcode);
481
482 if (!input_is_pointer && !input_is_int_scalar &&
483 !_.IsIntVectorType(input_type) && !_.IsFloatScalarType(input_type) &&
484 !_.IsFloatVectorType(input_type))
485 return _.diag(SPV_ERROR_INVALID_DATA, inst)
486 << "Expected input to be a pointer or int or float vector "
487 << "or scalar: " << spvOpcodeString(opcode);
488
489 if (_.version() >= SPV_SPIRV_VERSION_WORD(1, 5) ||
490 _.HasExtension(kSPV_KHR_physical_storage_buffer)) {
491 const bool result_is_int_vector = _.IsIntVectorType(result_type);
492 const bool result_has_int32 =
493 _.ContainsSizedIntOrFloatType(result_type, SpvOpTypeInt, 32);
494 const bool input_is_int_vector = _.IsIntVectorType(input_type);
495 const bool input_has_int32 =
496 _.ContainsSizedIntOrFloatType(input_type, SpvOpTypeInt, 32);
497 if (result_is_pointer && !input_is_pointer && !input_is_int_scalar &&
498 !(input_is_int_vector && input_has_int32))
499 return _.diag(SPV_ERROR_INVALID_DATA, inst)
500 << "Expected input to be a pointer, int scalar or 32-bit int "
501 "vector if Result Type is pointer: "
502 << spvOpcodeString(opcode);
503
504 if (input_is_pointer && !result_is_pointer && !result_is_int_scalar &&
505 !(result_is_int_vector && result_has_int32))
506 return _.diag(SPV_ERROR_INVALID_DATA, inst)
507 << "Pointer can only be converted to another pointer, int "
508 "scalar or 32-bit int vector: "
509 << spvOpcodeString(opcode);
510 } else {
511 if (result_is_pointer && !input_is_pointer && !input_is_int_scalar)
512 return _.diag(SPV_ERROR_INVALID_DATA, inst)
513 << "Expected input to be a pointer or int scalar if Result "
514 "Type is pointer: "
515 << spvOpcodeString(opcode);
516
517 if (input_is_pointer && !result_is_pointer && !result_is_int_scalar)
518 return _.diag(SPV_ERROR_INVALID_DATA, inst)
519 << "Pointer can only be converted to another pointer or int "
520 "scalar: "
521 << spvOpcodeString(opcode);
522 }
523
524 if (!result_is_pointer && !input_is_pointer) {
525 const uint32_t result_size =
526 _.GetBitWidth(result_type) * _.GetDimension(result_type);
527 const uint32_t input_size =
528 _.GetBitWidth(input_type) * _.GetDimension(input_type);
529 if (result_size != input_size)
530 return _.diag(SPV_ERROR_INVALID_DATA, inst)
531 << "Expected input to have the same total bit width as "
532 << "Result Type: " << spvOpcodeString(opcode);
533 }
534 break;
535 }
536
537 default:
538 break;
539 }
540
541 if (_.HasCapability(SpvCapabilityShader)) {
542 switch (inst->opcode()) {
543 case SpvOpConvertFToU:
544 case SpvOpConvertFToS:
545 case SpvOpConvertSToF:
546 case SpvOpConvertUToF:
547 case SpvOpBitcast:
548 if (_.ContainsLimitedUseIntOrFloatType(inst->type_id()) ||
549 _.ContainsLimitedUseIntOrFloatType(_.GetOperandTypeId(inst, 2u))) {
550 return _.diag(SPV_ERROR_INVALID_DATA, inst)
551 << "8- or 16-bit types can only be used with width-only "
552 "conversions";
553 }
554 break;
555 default:
556 break;
557 }
558 }
559
560 return SPV_SUCCESS;
561 }
562
563 } // namespace val
564 } // namespace spvtools
565