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/val/validate.h" |
18 | |
19 | #include "source/diagnostic.h" |
20 | #include "source/opcode.h" |
21 | #include "source/spirv_constant.h" |
22 | #include "source/val/instruction.h" |
23 | #include "source/val/validation_state.h" |
24 | |
25 | namespace spvtools { |
26 | namespace val { |
27 | |
28 | // Validates correctness of conversion instructions. |
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() == |
267 | SpvAddressingModelPhysicalStorageBuffer64EXT) { |
268 | uint32_t input_storage_class = 0; |
269 | uint32_t input_data_type = 0; |
270 | _.GetPointerTypeInfo(input_type, &input_data_type, |
271 | &input_storage_class); |
272 | if (input_storage_class != SpvStorageClassPhysicalStorageBufferEXT) |
273 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
274 | << "Pointer storage class must be PhysicalStorageBufferEXT: " |
275 | << spvOpcodeString(opcode); |
276 | } |
277 | break; |
278 | } |
279 | |
280 | case SpvOpSatConvertSToU: |
281 | case SpvOpSatConvertUToS: { |
282 | if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type)) |
283 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
284 | << "Expected int scalar or vector type as Result Type: " |
285 | << spvOpcodeString(opcode); |
286 | |
287 | const uint32_t input_type = _.GetOperandTypeId(inst, 2); |
288 | if (!input_type || |
289 | (!_.IsIntScalarType(input_type) && !_.IsIntVectorType(input_type))) |
290 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
291 | << "Expected int scalar or vector as input: " |
292 | << spvOpcodeString(opcode); |
293 | |
294 | if (_.GetDimension(result_type) != _.GetDimension(input_type)) |
295 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
296 | << "Expected input to have the same dimension as Result Type: " |
297 | << spvOpcodeString(opcode); |
298 | break; |
299 | } |
300 | |
301 | case SpvOpConvertUToPtr: { |
302 | if (!_.IsPointerType(result_type)) |
303 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
304 | << "Expected Result Type to be a pointer: " |
305 | << spvOpcodeString(opcode); |
306 | |
307 | const uint32_t input_type = _.GetOperandTypeId(inst, 2); |
308 | if (!input_type || !_.IsIntScalarType(input_type)) |
309 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
310 | << "Expected int scalar as input: " << spvOpcodeString(opcode); |
311 | |
312 | if (_.addressing_model() == SpvAddressingModelLogical) |
313 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
314 | << "Logical addressing not supported: " |
315 | << spvOpcodeString(opcode); |
316 | |
317 | if (_.addressing_model() == |
318 | SpvAddressingModelPhysicalStorageBuffer64EXT) { |
319 | uint32_t result_storage_class = 0; |
320 | uint32_t result_data_type = 0; |
321 | _.GetPointerTypeInfo(result_type, &result_data_type, |
322 | &result_storage_class); |
323 | if (result_storage_class != SpvStorageClassPhysicalStorageBufferEXT) |
324 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
325 | << "Pointer storage class must be PhysicalStorageBufferEXT: " |
326 | << spvOpcodeString(opcode); |
327 | } |
328 | break; |
329 | } |
330 | |
331 | case SpvOpPtrCastToGeneric: { |
332 | uint32_t result_storage_class = 0; |
333 | uint32_t result_data_type = 0; |
334 | if (!_.GetPointerTypeInfo(result_type, &result_data_type, |
335 | &result_storage_class)) |
336 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
337 | << "Expected Result Type to be a pointer: " |
338 | << spvOpcodeString(opcode); |
339 | |
340 | if (result_storage_class != SpvStorageClassGeneric) |
341 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
342 | << "Expected Result Type to have storage class Generic: " |
343 | << spvOpcodeString(opcode); |
344 | |
345 | const uint32_t input_type = _.GetOperandTypeId(inst, 2); |
346 | uint32_t input_storage_class = 0; |
347 | uint32_t input_data_type = 0; |
348 | if (!_.GetPointerTypeInfo(input_type, &input_data_type, |
349 | &input_storage_class)) |
350 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
351 | << "Expected input to be a pointer: " << spvOpcodeString(opcode); |
352 | |
353 | if (input_storage_class != SpvStorageClassWorkgroup && |
354 | input_storage_class != SpvStorageClassCrossWorkgroup && |
355 | input_storage_class != SpvStorageClassFunction) |
356 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
357 | << "Expected input to have storage class Workgroup, " |
358 | << "CrossWorkgroup or Function: " << spvOpcodeString(opcode); |
359 | |
360 | if (result_data_type != input_data_type) |
361 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
362 | << "Expected input and Result Type to point to the same type: " |
363 | << spvOpcodeString(opcode); |
364 | break; |
365 | } |
366 | |
367 | case SpvOpGenericCastToPtr: { |
368 | uint32_t result_storage_class = 0; |
369 | uint32_t result_data_type = 0; |
370 | if (!_.GetPointerTypeInfo(result_type, &result_data_type, |
371 | &result_storage_class)) |
372 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
373 | << "Expected Result Type to be a pointer: " |
374 | << spvOpcodeString(opcode); |
375 | |
376 | if (result_storage_class != SpvStorageClassWorkgroup && |
377 | result_storage_class != SpvStorageClassCrossWorkgroup && |
378 | result_storage_class != SpvStorageClassFunction) |
379 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
380 | << "Expected Result Type to have storage class Workgroup, " |
381 | << "CrossWorkgroup or Function: " << spvOpcodeString(opcode); |
382 | |
383 | const uint32_t input_type = _.GetOperandTypeId(inst, 2); |
384 | uint32_t input_storage_class = 0; |
385 | uint32_t input_data_type = 0; |
386 | if (!_.GetPointerTypeInfo(input_type, &input_data_type, |
387 | &input_storage_class)) |
388 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
389 | << "Expected input to be a pointer: " << spvOpcodeString(opcode); |
390 | |
391 | if (input_storage_class != SpvStorageClassGeneric) |
392 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
393 | << "Expected input to have storage class Generic: " |
394 | << spvOpcodeString(opcode); |
395 | |
396 | if (result_data_type != input_data_type) |
397 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
398 | << "Expected input and Result Type to point to the same type: " |
399 | << spvOpcodeString(opcode); |
400 | break; |
401 | } |
402 | |
403 | case SpvOpGenericCastToPtrExplicit: { |
404 | uint32_t result_storage_class = 0; |
405 | uint32_t result_data_type = 0; |
406 | if (!_.GetPointerTypeInfo(result_type, &result_data_type, |
407 | &result_storage_class)) |
408 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
409 | << "Expected Result Type to be a pointer: " |
410 | << spvOpcodeString(opcode); |
411 | |
412 | const uint32_t target_storage_class = inst->word(4); |
413 | if (result_storage_class != target_storage_class) |
414 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
415 | << "Expected Result Type to be of target storage class: " |
416 | << spvOpcodeString(opcode); |
417 | |
418 | const uint32_t input_type = _.GetOperandTypeId(inst, 2); |
419 | uint32_t input_storage_class = 0; |
420 | uint32_t input_data_type = 0; |
421 | if (!_.GetPointerTypeInfo(input_type, &input_data_type, |
422 | &input_storage_class)) |
423 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
424 | << "Expected input to be a pointer: " << spvOpcodeString(opcode); |
425 | |
426 | if (input_storage_class != SpvStorageClassGeneric) |
427 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
428 | << "Expected input to have storage class Generic: " |
429 | << spvOpcodeString(opcode); |
430 | |
431 | if (result_data_type != input_data_type) |
432 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
433 | << "Expected input and Result Type to point to the same type: " |
434 | << spvOpcodeString(opcode); |
435 | |
436 | if (target_storage_class != SpvStorageClassWorkgroup && |
437 | target_storage_class != SpvStorageClassCrossWorkgroup && |
438 | target_storage_class != SpvStorageClassFunction) |
439 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
440 | << "Expected target storage class to be Workgroup, " |
441 | << "CrossWorkgroup or Function: " << spvOpcodeString(opcode); |
442 | break; |
443 | } |
444 | |
445 | case SpvOpBitcast: { |
446 | const uint32_t input_type = _.GetOperandTypeId(inst, 2); |
447 | if (!input_type) |
448 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
449 | << "Expected input to have a type: " << spvOpcodeString(opcode); |
450 | |
451 | const bool result_is_pointer = _.IsPointerType(result_type); |
452 | const bool result_is_int_scalar = _.IsIntScalarType(result_type); |
453 | const bool input_is_pointer = _.IsPointerType(input_type); |
454 | const bool input_is_int_scalar = _.IsIntScalarType(input_type); |
455 | |
456 | if (!result_is_pointer && !result_is_int_scalar && |
457 | !_.IsIntVectorType(result_type) && |
458 | !_.IsFloatScalarType(result_type) && |
459 | !_.IsFloatVectorType(result_type)) |
460 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
461 | << "Expected Result Type to be a pointer or int or float vector " |
462 | << "or scalar type: " << spvOpcodeString(opcode); |
463 | |
464 | if (!input_is_pointer && !input_is_int_scalar && |
465 | !_.IsIntVectorType(input_type) && !_.IsFloatScalarType(input_type) && |
466 | !_.IsFloatVectorType(input_type)) |
467 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
468 | << "Expected input to be a pointer or int or float vector " |
469 | << "or scalar: " << spvOpcodeString(opcode); |
470 | |
471 | if (_.version() >= SPV_SPIRV_VERSION_WORD(1, 5) || |
472 | _.HasExtension(kSPV_KHR_physical_storage_buffer)) { |
473 | const bool result_is_int_vector = _.IsIntVectorType(result_type); |
474 | const bool result_has_int32 = |
475 | _.ContainsSizedIntOrFloatType(result_type, SpvOpTypeInt, 32); |
476 | const bool input_is_int_vector = _.IsIntVectorType(input_type); |
477 | const bool input_has_int32 = |
478 | _.ContainsSizedIntOrFloatType(input_type, SpvOpTypeInt, 32); |
479 | if (result_is_pointer && !input_is_pointer && !input_is_int_scalar && |
480 | !(input_is_int_vector && input_has_int32)) |
481 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
482 | << "Expected input to be a pointer, int scalar or 32-bit int " |
483 | "vector if Result Type is pointer: " |
484 | << spvOpcodeString(opcode); |
485 | |
486 | if (input_is_pointer && !result_is_pointer && !result_is_int_scalar && |
487 | !(result_is_int_vector && result_has_int32)) |
488 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
489 | << "Pointer can only be converted to another pointer, int " |
490 | "scalar or 32-bit int vector: " |
491 | << spvOpcodeString(opcode); |
492 | } else { |
493 | if (result_is_pointer && !input_is_pointer && !input_is_int_scalar) |
494 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
495 | << "Expected input to be a pointer or int scalar if Result " |
496 | "Type is pointer: " |
497 | << spvOpcodeString(opcode); |
498 | |
499 | if (input_is_pointer && !result_is_pointer && !result_is_int_scalar) |
500 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
501 | << "Pointer can only be converted to another pointer or int " |
502 | "scalar: " |
503 | << spvOpcodeString(opcode); |
504 | } |
505 | |
506 | if (!result_is_pointer && !input_is_pointer) { |
507 | const uint32_t result_size = |
508 | _.GetBitWidth(result_type) * _.GetDimension(result_type); |
509 | const uint32_t input_size = |
510 | _.GetBitWidth(input_type) * _.GetDimension(input_type); |
511 | if (result_size != input_size) |
512 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
513 | << "Expected input to have the same total bit width as " |
514 | << "Result Type: " << spvOpcodeString(opcode); |
515 | } |
516 | break; |
517 | } |
518 | |
519 | default: |
520 | break; |
521 | } |
522 | |
523 | if (_.HasCapability(SpvCapabilityShader)) { |
524 | switch (inst->opcode()) { |
525 | case SpvOpConvertFToU: |
526 | case SpvOpConvertFToS: |
527 | case SpvOpConvertSToF: |
528 | case SpvOpConvertUToF: |
529 | case SpvOpBitcast: |
530 | if (_.ContainsLimitedUseIntOrFloatType(inst->type_id()) || |
531 | _.ContainsLimitedUseIntOrFloatType(_.GetOperandTypeId(inst, 2u))) { |
532 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
533 | << "8- or 16-bit types can only be used with width-only " |
534 | "conversions" ; |
535 | } |
536 | break; |
537 | default: |
538 | break; |
539 | } |
540 | } |
541 | |
542 | return SPV_SUCCESS; |
543 | } |
544 | |
545 | } // namespace val |
546 | } // namespace spvtools |
547 | |