• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/val/instruction.h"
22 #include "source/val/validation_state.h"
23 
24 namespace spvtools {
25 namespace val {
26 
27 // Validates correctness of conversion instructions.
ConversionPass(ValidationState_t & _,const Instruction * inst)28 spv_result_t ConversionPass(ValidationState_t& _, const Instruction* inst) {
29   const SpvOp opcode = inst->opcode();
30   const uint32_t result_type = inst->type_id();
31 
32   switch (opcode) {
33     case SpvOpConvertFToU: {
34       if (!_.IsUnsignedIntScalarType(result_type) &&
35           !_.IsUnsignedIntVectorType(result_type))
36         return _.diag(SPV_ERROR_INVALID_DATA, inst)
37                << "Expected unsigned int scalar or vector type as Result Type: "
38                << spvOpcodeString(opcode);
39 
40       const uint32_t input_type = _.GetOperandTypeId(inst, 2);
41       if (!input_type || (!_.IsFloatScalarType(input_type) &&
42                           !_.IsFloatVectorType(input_type)))
43         return _.diag(SPV_ERROR_INVALID_DATA, inst)
44                << "Expected input to be float scalar or vector: "
45                << spvOpcodeString(opcode);
46 
47       if (_.GetDimension(result_type) != _.GetDimension(input_type))
48         return _.diag(SPV_ERROR_INVALID_DATA, inst)
49                << "Expected input to have the same dimension as Result Type: "
50                << spvOpcodeString(opcode);
51 
52       if (!_.features().use_int8_type && (8 == _.GetBitWidth(result_type)))
53         return _.diag(SPV_ERROR_INVALID_DATA, inst)
54                << "Invalid cast to 8-bit integer from a floating-point: "
55                << spvOpcodeString(opcode);
56 
57       break;
58     }
59 
60     case SpvOpConvertFToS: {
61       if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type))
62         return _.diag(SPV_ERROR_INVALID_DATA, inst)
63                << "Expected int scalar or vector type as Result Type: "
64                << spvOpcodeString(opcode);
65 
66       const uint32_t input_type = _.GetOperandTypeId(inst, 2);
67       if (!input_type || (!_.IsFloatScalarType(input_type) &&
68                           !_.IsFloatVectorType(input_type)))
69         return _.diag(SPV_ERROR_INVALID_DATA, inst)
70                << "Expected input to be float scalar or vector: "
71                << spvOpcodeString(opcode);
72 
73       if (_.GetDimension(result_type) != _.GetDimension(input_type))
74         return _.diag(SPV_ERROR_INVALID_DATA, inst)
75                << "Expected input to have the same dimension as Result Type: "
76                << spvOpcodeString(opcode);
77 
78       if (!_.features().use_int8_type && (8 == _.GetBitWidth(result_type)))
79         return _.diag(SPV_ERROR_INVALID_DATA, inst)
80                << "Invalid cast to 8-bit integer from a floating-point: "
81                << spvOpcodeString(opcode);
82 
83       break;
84     }
85 
86     case SpvOpConvertSToF:
87     case SpvOpConvertUToF: {
88       if (!_.IsFloatScalarType(result_type) &&
89           !_.IsFloatVectorType(result_type))
90         return _.diag(SPV_ERROR_INVALID_DATA, inst)
91                << "Expected float scalar or vector type as Result Type: "
92                << spvOpcodeString(opcode);
93 
94       const uint32_t input_type = _.GetOperandTypeId(inst, 2);
95       if (!input_type ||
96           (!_.IsIntScalarType(input_type) && !_.IsIntVectorType(input_type)))
97         return _.diag(SPV_ERROR_INVALID_DATA, inst)
98                << "Expected input to be int scalar or vector: "
99                << spvOpcodeString(opcode);
100 
101       if (_.GetDimension(result_type) != _.GetDimension(input_type))
102         return _.diag(SPV_ERROR_INVALID_DATA, inst)
103                << "Expected input to have the same dimension as Result Type: "
104                << spvOpcodeString(opcode);
105 
106       if (!_.features().use_int8_type && (8 == _.GetBitWidth(input_type)))
107         return _.diag(SPV_ERROR_INVALID_DATA, inst)
108                << "Invalid cast to floating-point from an 8-bit integer: "
109                << spvOpcodeString(opcode);
110 
111       break;
112     }
113 
114     case SpvOpUConvert: {
115       if (!_.IsUnsignedIntScalarType(result_type) &&
116           !_.IsUnsignedIntVectorType(result_type))
117         return _.diag(SPV_ERROR_INVALID_DATA, inst)
118                << "Expected unsigned int scalar or vector type as Result Type: "
119                << spvOpcodeString(opcode);
120 
121       const uint32_t input_type = _.GetOperandTypeId(inst, 2);
122       if (!input_type ||
123           (!_.IsIntScalarType(input_type) && !_.IsIntVectorType(input_type)))
124         return _.diag(SPV_ERROR_INVALID_DATA, inst)
125                << "Expected input to be int scalar or vector: "
126                << spvOpcodeString(opcode);
127 
128       if (_.GetDimension(result_type) != _.GetDimension(input_type))
129         return _.diag(SPV_ERROR_INVALID_DATA, inst)
130                << "Expected input to have the same dimension as Result Type: "
131                << spvOpcodeString(opcode);
132 
133       if (_.GetBitWidth(result_type) == _.GetBitWidth(input_type))
134         return _.diag(SPV_ERROR_INVALID_DATA, inst)
135                << "Expected input to have different bit width from Result "
136                   "Type: "
137                << spvOpcodeString(opcode);
138       break;
139     }
140 
141     case SpvOpSConvert: {
142       if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type))
143         return _.diag(SPV_ERROR_INVALID_DATA, inst)
144                << "Expected int scalar or vector type as Result Type: "
145                << spvOpcodeString(opcode);
146 
147       const uint32_t input_type = _.GetOperandTypeId(inst, 2);
148       if (!input_type ||
149           (!_.IsIntScalarType(input_type) && !_.IsIntVectorType(input_type)))
150         return _.diag(SPV_ERROR_INVALID_DATA, inst)
151                << "Expected input to be int scalar or vector: "
152                << spvOpcodeString(opcode);
153 
154       if (_.GetDimension(result_type) != _.GetDimension(input_type))
155         return _.diag(SPV_ERROR_INVALID_DATA, inst)
156                << "Expected input to have the same dimension as Result Type: "
157                << spvOpcodeString(opcode);
158 
159       if (_.GetBitWidth(result_type) == _.GetBitWidth(input_type))
160         return _.diag(SPV_ERROR_INVALID_DATA, inst)
161                << "Expected input to have different bit width from Result "
162                   "Type: "
163                << spvOpcodeString(opcode);
164       break;
165     }
166 
167     case SpvOpFConvert: {
168       if (!_.IsFloatScalarType(result_type) &&
169           !_.IsFloatVectorType(result_type))
170         return _.diag(SPV_ERROR_INVALID_DATA, inst)
171                << "Expected float scalar or vector type as Result Type: "
172                << spvOpcodeString(opcode);
173 
174       const uint32_t input_type = _.GetOperandTypeId(inst, 2);
175       if (!input_type || (!_.IsFloatScalarType(input_type) &&
176                           !_.IsFloatVectorType(input_type)))
177         return _.diag(SPV_ERROR_INVALID_DATA, inst)
178                << "Expected input to be float scalar or vector: "
179                << spvOpcodeString(opcode);
180 
181       if (_.GetDimension(result_type) != _.GetDimension(input_type))
182         return _.diag(SPV_ERROR_INVALID_DATA, inst)
183                << "Expected input to have the same dimension as Result Type: "
184                << spvOpcodeString(opcode);
185 
186       if (_.GetBitWidth(result_type) == _.GetBitWidth(input_type))
187         return _.diag(SPV_ERROR_INVALID_DATA, inst)
188                << "Expected input to have different bit width from Result "
189                   "Type: "
190                << spvOpcodeString(opcode);
191       break;
192     }
193 
194     case SpvOpQuantizeToF16: {
195       if ((!_.IsFloatScalarType(result_type) &&
196            !_.IsFloatVectorType(result_type)) ||
197           _.GetBitWidth(result_type) != 32)
198         return _.diag(SPV_ERROR_INVALID_DATA, inst)
199                << "Expected 32-bit float scalar or vector type as Result Type: "
200                << spvOpcodeString(opcode);
201 
202       const uint32_t input_type = _.GetOperandTypeId(inst, 2);
203       if (input_type != result_type)
204         return _.diag(SPV_ERROR_INVALID_DATA, inst)
205                << "Expected input type to be equal to Result Type: "
206                << spvOpcodeString(opcode);
207       break;
208     }
209 
210     case SpvOpConvertPtrToU: {
211       if (!_.IsUnsignedIntScalarType(result_type))
212         return _.diag(SPV_ERROR_INVALID_DATA, inst)
213                << "Expected unsigned int scalar type as Result Type: "
214                << spvOpcodeString(opcode);
215 
216       const uint32_t input_type = _.GetOperandTypeId(inst, 2);
217       if (!_.IsPointerType(input_type))
218         return _.diag(SPV_ERROR_INVALID_DATA, inst)
219                << "Expected input to be a pointer: " << spvOpcodeString(opcode);
220 
221       if (_.addressing_model() == SpvAddressingModelLogical)
222         return _.diag(SPV_ERROR_INVALID_DATA, inst)
223                << "Logical addressing not supported: "
224                << spvOpcodeString(opcode);
225 
226       if (_.addressing_model() ==
227           SpvAddressingModelPhysicalStorageBuffer64EXT) {
228         uint32_t input_storage_class = 0;
229         uint32_t input_data_type = 0;
230         _.GetPointerTypeInfo(input_type, &input_data_type,
231                              &input_storage_class);
232         if (input_storage_class != SpvStorageClassPhysicalStorageBufferEXT)
233           return _.diag(SPV_ERROR_INVALID_DATA, inst)
234                  << "Pointer storage class must be PhysicalStorageBufferEXT: "
235                  << spvOpcodeString(opcode);
236       }
237       break;
238     }
239 
240     case SpvOpSatConvertSToU:
241     case SpvOpSatConvertUToS: {
242       if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type))
243         return _.diag(SPV_ERROR_INVALID_DATA, inst)
244                << "Expected int scalar or vector type as Result Type: "
245                << spvOpcodeString(opcode);
246 
247       const uint32_t input_type = _.GetOperandTypeId(inst, 2);
248       if (!input_type ||
249           (!_.IsIntScalarType(input_type) && !_.IsIntVectorType(input_type)))
250         return _.diag(SPV_ERROR_INVALID_DATA, inst)
251                << "Expected int scalar or vector as input: "
252                << spvOpcodeString(opcode);
253 
254       if (_.GetDimension(result_type) != _.GetDimension(input_type))
255         return _.diag(SPV_ERROR_INVALID_DATA, inst)
256                << "Expected input to have the same dimension as Result Type: "
257                << spvOpcodeString(opcode);
258       break;
259     }
260 
261     case SpvOpConvertUToPtr: {
262       if (!_.IsPointerType(result_type))
263         return _.diag(SPV_ERROR_INVALID_DATA, inst)
264                << "Expected Result Type to be a pointer: "
265                << spvOpcodeString(opcode);
266 
267       const uint32_t input_type = _.GetOperandTypeId(inst, 2);
268       if (!input_type || !_.IsIntScalarType(input_type))
269         return _.diag(SPV_ERROR_INVALID_DATA, inst)
270                << "Expected int scalar as input: " << spvOpcodeString(opcode);
271 
272       if (_.addressing_model() == SpvAddressingModelLogical)
273         return _.diag(SPV_ERROR_INVALID_DATA, inst)
274                << "Logical addressing not supported: "
275                << spvOpcodeString(opcode);
276 
277       if (_.addressing_model() ==
278           SpvAddressingModelPhysicalStorageBuffer64EXT) {
279         uint32_t result_storage_class = 0;
280         uint32_t result_data_type = 0;
281         _.GetPointerTypeInfo(result_type, &result_data_type,
282                              &result_storage_class);
283         if (result_storage_class != SpvStorageClassPhysicalStorageBufferEXT)
284           return _.diag(SPV_ERROR_INVALID_DATA, inst)
285                  << "Pointer storage class must be PhysicalStorageBufferEXT: "
286                  << spvOpcodeString(opcode);
287       }
288       break;
289     }
290 
291     case SpvOpPtrCastToGeneric: {
292       uint32_t result_storage_class = 0;
293       uint32_t result_data_type = 0;
294       if (!_.GetPointerTypeInfo(result_type, &result_data_type,
295                                 &result_storage_class))
296         return _.diag(SPV_ERROR_INVALID_DATA, inst)
297                << "Expected Result Type to be a pointer: "
298                << spvOpcodeString(opcode);
299 
300       if (result_storage_class != SpvStorageClassGeneric)
301         return _.diag(SPV_ERROR_INVALID_DATA, inst)
302                << "Expected Result Type to have storage class Generic: "
303                << spvOpcodeString(opcode);
304 
305       const uint32_t input_type = _.GetOperandTypeId(inst, 2);
306       uint32_t input_storage_class = 0;
307       uint32_t input_data_type = 0;
308       if (!_.GetPointerTypeInfo(input_type, &input_data_type,
309                                 &input_storage_class))
310         return _.diag(SPV_ERROR_INVALID_DATA, inst)
311                << "Expected input to be a pointer: " << spvOpcodeString(opcode);
312 
313       if (input_storage_class != SpvStorageClassWorkgroup &&
314           input_storage_class != SpvStorageClassCrossWorkgroup &&
315           input_storage_class != SpvStorageClassFunction)
316         return _.diag(SPV_ERROR_INVALID_DATA, inst)
317                << "Expected input to have storage class Workgroup, "
318                << "CrossWorkgroup or Function: " << spvOpcodeString(opcode);
319 
320       if (result_data_type != input_data_type)
321         return _.diag(SPV_ERROR_INVALID_DATA, inst)
322                << "Expected input and Result Type to point to the same type: "
323                << spvOpcodeString(opcode);
324       break;
325     }
326 
327     case SpvOpGenericCastToPtr: {
328       uint32_t result_storage_class = 0;
329       uint32_t result_data_type = 0;
330       if (!_.GetPointerTypeInfo(result_type, &result_data_type,
331                                 &result_storage_class))
332         return _.diag(SPV_ERROR_INVALID_DATA, inst)
333                << "Expected Result Type to be a pointer: "
334                << spvOpcodeString(opcode);
335 
336       if (result_storage_class != SpvStorageClassWorkgroup &&
337           result_storage_class != SpvStorageClassCrossWorkgroup &&
338           result_storage_class != SpvStorageClassFunction)
339         return _.diag(SPV_ERROR_INVALID_DATA, inst)
340                << "Expected Result Type to have storage class Workgroup, "
341                << "CrossWorkgroup or Function: " << spvOpcodeString(opcode);
342 
343       const uint32_t input_type = _.GetOperandTypeId(inst, 2);
344       uint32_t input_storage_class = 0;
345       uint32_t input_data_type = 0;
346       if (!_.GetPointerTypeInfo(input_type, &input_data_type,
347                                 &input_storage_class))
348         return _.diag(SPV_ERROR_INVALID_DATA, inst)
349                << "Expected input to be a pointer: " << spvOpcodeString(opcode);
350 
351       if (input_storage_class != SpvStorageClassGeneric)
352         return _.diag(SPV_ERROR_INVALID_DATA, inst)
353                << "Expected input to have storage class Generic: "
354                << spvOpcodeString(opcode);
355 
356       if (result_data_type != input_data_type)
357         return _.diag(SPV_ERROR_INVALID_DATA, inst)
358                << "Expected input and Result Type to point to the same type: "
359                << spvOpcodeString(opcode);
360       break;
361     }
362 
363     case SpvOpGenericCastToPtrExplicit: {
364       uint32_t result_storage_class = 0;
365       uint32_t result_data_type = 0;
366       if (!_.GetPointerTypeInfo(result_type, &result_data_type,
367                                 &result_storage_class))
368         return _.diag(SPV_ERROR_INVALID_DATA, inst)
369                << "Expected Result Type to be a pointer: "
370                << spvOpcodeString(opcode);
371 
372       const uint32_t target_storage_class = inst->word(4);
373       if (result_storage_class != target_storage_class)
374         return _.diag(SPV_ERROR_INVALID_DATA, inst)
375                << "Expected Result Type to be of target storage class: "
376                << spvOpcodeString(opcode);
377 
378       const uint32_t input_type = _.GetOperandTypeId(inst, 2);
379       uint32_t input_storage_class = 0;
380       uint32_t input_data_type = 0;
381       if (!_.GetPointerTypeInfo(input_type, &input_data_type,
382                                 &input_storage_class))
383         return _.diag(SPV_ERROR_INVALID_DATA, inst)
384                << "Expected input to be a pointer: " << spvOpcodeString(opcode);
385 
386       if (input_storage_class != SpvStorageClassGeneric)
387         return _.diag(SPV_ERROR_INVALID_DATA, inst)
388                << "Expected input to have storage class Generic: "
389                << spvOpcodeString(opcode);
390 
391       if (result_data_type != input_data_type)
392         return _.diag(SPV_ERROR_INVALID_DATA, inst)
393                << "Expected input and Result Type to point to the same type: "
394                << spvOpcodeString(opcode);
395 
396       if (target_storage_class != SpvStorageClassWorkgroup &&
397           target_storage_class != SpvStorageClassCrossWorkgroup &&
398           target_storage_class != SpvStorageClassFunction)
399         return _.diag(SPV_ERROR_INVALID_DATA, inst)
400                << "Expected target storage class to be Workgroup, "
401                << "CrossWorkgroup or Function: " << spvOpcodeString(opcode);
402       break;
403     }
404 
405     case SpvOpBitcast: {
406       const uint32_t input_type = _.GetOperandTypeId(inst, 2);
407       if (!input_type)
408         return _.diag(SPV_ERROR_INVALID_DATA, inst)
409                << "Expected input to have a type: " << spvOpcodeString(opcode);
410 
411       const bool result_is_pointer = _.IsPointerType(result_type);
412       const bool result_is_int_scalar = _.IsIntScalarType(result_type);
413       const bool input_is_pointer = _.IsPointerType(input_type);
414       const bool input_is_int_scalar = _.IsIntScalarType(input_type);
415 
416       if (!result_is_pointer && !result_is_int_scalar &&
417           !_.IsIntVectorType(result_type) &&
418           !_.IsFloatScalarType(result_type) &&
419           !_.IsFloatVectorType(result_type))
420         return _.diag(SPV_ERROR_INVALID_DATA, inst)
421                << "Expected Result Type to be a pointer or int or float vector "
422                << "or scalar type: " << spvOpcodeString(opcode);
423 
424       if (!input_is_pointer && !input_is_int_scalar &&
425           !_.IsIntVectorType(input_type) && !_.IsFloatScalarType(input_type) &&
426           !_.IsFloatVectorType(input_type))
427         return _.diag(SPV_ERROR_INVALID_DATA, inst)
428                << "Expected input to be a pointer or int or float vector "
429                << "or scalar: " << spvOpcodeString(opcode);
430 
431       if (result_is_pointer && !input_is_pointer && !input_is_int_scalar)
432         return _.diag(SPV_ERROR_INVALID_DATA, inst)
433                << "Expected input to be a pointer or int scalar if Result Type "
434                << "is pointer: " << spvOpcodeString(opcode);
435 
436       if (input_is_pointer && !result_is_pointer && !result_is_int_scalar)
437         return _.diag(SPV_ERROR_INVALID_DATA, inst)
438                << "Pointer can only be converted to another pointer or int "
439                << "scalar: " << spvOpcodeString(opcode);
440 
441       if (!result_is_pointer && !input_is_pointer) {
442         const uint32_t result_size =
443             _.GetBitWidth(result_type) * _.GetDimension(result_type);
444         const uint32_t input_size =
445             _.GetBitWidth(input_type) * _.GetDimension(input_type);
446         if (result_size != input_size)
447           return _.diag(SPV_ERROR_INVALID_DATA, inst)
448                  << "Expected input to have the same total bit width as "
449                  << "Result Type: " << spvOpcodeString(opcode);
450       }
451       break;
452     }
453 
454     default:
455       break;
456   }
457 
458   return SPV_SUCCESS;
459 }
460 
461 }  // namespace val
462 }  // namespace spvtools
463