validate_conversion.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  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. // Validates correctness of conversion instructions.
  15. #include "validate.h"
  16. #include "diagnostic.h"
  17. #include "opcode.h"
  18. #include "val/instruction.h"
  19. #include "val/validation_state.h"
  20. namespace libspirv {
  21. // Validates correctness of conversion instructions.
  22. spv_result_t ConversionPass(ValidationState_t& _,
  23. const spv_parsed_instruction_t* inst) {
  24. const SpvOp opcode = static_cast<SpvOp>(inst->opcode);
  25. const uint32_t result_type = inst->type_id;
  26. switch (opcode) {
  27. case SpvOpConvertFToU: {
  28. if (!_.IsUnsignedIntScalarType(result_type) &&
  29. !_.IsUnsignedIntVectorType(result_type))
  30. return _.diag(SPV_ERROR_INVALID_DATA)
  31. << "Expected unsigned int scalar or vector type as Result Type: "
  32. << spvOpcodeString(opcode);
  33. const uint32_t input_type = _.GetOperandTypeId(inst, 2);
  34. if (!input_type || (!_.IsFloatScalarType(input_type) &&
  35. !_.IsFloatVectorType(input_type)))
  36. return _.diag(SPV_ERROR_INVALID_DATA)
  37. << "Expected input to be float scalar or vector: "
  38. << spvOpcodeString(opcode);
  39. if (_.GetDimension(result_type) != _.GetDimension(input_type))
  40. return _.diag(SPV_ERROR_INVALID_DATA)
  41. << "Expected input to have the same dimension as Result Type: "
  42. << spvOpcodeString(opcode);
  43. break;
  44. }
  45. case SpvOpConvertFToS: {
  46. if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type))
  47. return _.diag(SPV_ERROR_INVALID_DATA)
  48. << "Expected int scalar or vector type as Result Type: "
  49. << spvOpcodeString(opcode);
  50. const uint32_t input_type = _.GetOperandTypeId(inst, 2);
  51. if (!input_type || (!_.IsFloatScalarType(input_type) &&
  52. !_.IsFloatVectorType(input_type)))
  53. return _.diag(SPV_ERROR_INVALID_DATA)
  54. << "Expected input to be float scalar or vector: "
  55. << spvOpcodeString(opcode);
  56. if (_.GetDimension(result_type) != _.GetDimension(input_type))
  57. return _.diag(SPV_ERROR_INVALID_DATA)
  58. << "Expected input to have the same dimension as Result Type: "
  59. << spvOpcodeString(opcode);
  60. break;
  61. }
  62. case SpvOpConvertSToF:
  63. case SpvOpConvertUToF: {
  64. if (!_.IsFloatScalarType(result_type) &&
  65. !_.IsFloatVectorType(result_type))
  66. return _.diag(SPV_ERROR_INVALID_DATA)
  67. << "Expected float scalar or vector type as Result Type: "
  68. << spvOpcodeString(opcode);
  69. const uint32_t input_type = _.GetOperandTypeId(inst, 2);
  70. if (!input_type ||
  71. (!_.IsIntScalarType(input_type) && !_.IsIntVectorType(input_type)))
  72. return _.diag(SPV_ERROR_INVALID_DATA)
  73. << "Expected input to be int scalar or vector: "
  74. << spvOpcodeString(opcode);
  75. if (_.GetDimension(result_type) != _.GetDimension(input_type))
  76. return _.diag(SPV_ERROR_INVALID_DATA)
  77. << "Expected input to have the same dimension as Result Type: "
  78. << spvOpcodeString(opcode);
  79. break;
  80. }
  81. case SpvOpUConvert: {
  82. if (!_.IsUnsignedIntScalarType(result_type) &&
  83. !_.IsUnsignedIntVectorType(result_type))
  84. return _.diag(SPV_ERROR_INVALID_DATA)
  85. << "Expected unsigned int scalar or vector type as Result Type: "
  86. << spvOpcodeString(opcode);
  87. const uint32_t input_type = _.GetOperandTypeId(inst, 2);
  88. if (!input_type ||
  89. (!_.IsIntScalarType(input_type) && !_.IsIntVectorType(input_type)))
  90. return _.diag(SPV_ERROR_INVALID_DATA)
  91. << "Expected input to be int scalar or vector: "
  92. << spvOpcodeString(opcode);
  93. if (_.GetDimension(result_type) != _.GetDimension(input_type))
  94. return _.diag(SPV_ERROR_INVALID_DATA)
  95. << "Expected input to have the same dimension as Result Type: "
  96. << spvOpcodeString(opcode);
  97. if (_.GetBitWidth(result_type) == _.GetBitWidth(input_type))
  98. return _.diag(SPV_ERROR_INVALID_DATA)
  99. << "Expected input to have different bit width from Result "
  100. "Type: "
  101. << spvOpcodeString(opcode);
  102. break;
  103. }
  104. case SpvOpSConvert: {
  105. if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type))
  106. return _.diag(SPV_ERROR_INVALID_DATA)
  107. << "Expected int scalar or vector type as Result Type: "
  108. << spvOpcodeString(opcode);
  109. const uint32_t input_type = _.GetOperandTypeId(inst, 2);
  110. if (!input_type ||
  111. (!_.IsIntScalarType(input_type) && !_.IsIntVectorType(input_type)))
  112. return _.diag(SPV_ERROR_INVALID_DATA)
  113. << "Expected input to be int scalar or vector: "
  114. << spvOpcodeString(opcode);
  115. if (_.GetDimension(result_type) != _.GetDimension(input_type))
  116. return _.diag(SPV_ERROR_INVALID_DATA)
  117. << "Expected input to have the same dimension as Result Type: "
  118. << spvOpcodeString(opcode);
  119. if (_.GetBitWidth(result_type) == _.GetBitWidth(input_type))
  120. return _.diag(SPV_ERROR_INVALID_DATA)
  121. << "Expected input to have different bit width from Result "
  122. "Type: "
  123. << spvOpcodeString(opcode);
  124. break;
  125. }
  126. case SpvOpFConvert: {
  127. if (!_.IsFloatScalarType(result_type) &&
  128. !_.IsFloatVectorType(result_type))
  129. return _.diag(SPV_ERROR_INVALID_DATA)
  130. << "Expected float scalar or vector type as Result Type: "
  131. << spvOpcodeString(opcode);
  132. const uint32_t input_type = _.GetOperandTypeId(inst, 2);
  133. if (!input_type || (!_.IsFloatScalarType(input_type) &&
  134. !_.IsFloatVectorType(input_type)))
  135. return _.diag(SPV_ERROR_INVALID_DATA)
  136. << "Expected input to be float scalar or vector: "
  137. << spvOpcodeString(opcode);
  138. if (_.GetDimension(result_type) != _.GetDimension(input_type))
  139. return _.diag(SPV_ERROR_INVALID_DATA)
  140. << "Expected input to have the same dimension as Result Type: "
  141. << spvOpcodeString(opcode);
  142. if (_.GetBitWidth(result_type) == _.GetBitWidth(input_type))
  143. return _.diag(SPV_ERROR_INVALID_DATA)
  144. << "Expected input to have different bit width from Result "
  145. "Type: "
  146. << spvOpcodeString(opcode);
  147. break;
  148. }
  149. case SpvOpQuantizeToF16: {
  150. if ((!_.IsFloatScalarType(result_type) &&
  151. !_.IsFloatVectorType(result_type)) ||
  152. _.GetBitWidth(result_type) != 32)
  153. return _.diag(SPV_ERROR_INVALID_DATA)
  154. << "Expected 32-bit float scalar or vector type as Result Type: "
  155. << spvOpcodeString(opcode);
  156. const uint32_t input_type = _.GetOperandTypeId(inst, 2);
  157. if (input_type != result_type)
  158. return _.diag(SPV_ERROR_INVALID_DATA)
  159. << "Expected input type to be equal to Result Type: "
  160. << spvOpcodeString(opcode);
  161. break;
  162. }
  163. case SpvOpConvertPtrToU: {
  164. if (!_.IsUnsignedIntScalarType(result_type))
  165. return _.diag(SPV_ERROR_INVALID_DATA)
  166. << "Expected unsigned int scalar type as Result Type: "
  167. << spvOpcodeString(opcode);
  168. const uint32_t input_type = _.GetOperandTypeId(inst, 2);
  169. if (!_.IsPointerType(input_type))
  170. return _.diag(SPV_ERROR_INVALID_DATA)
  171. << "Expected input to be a pointer: " << spvOpcodeString(opcode);
  172. break;
  173. }
  174. case SpvOpSatConvertSToU:
  175. case SpvOpSatConvertUToS: {
  176. if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type))
  177. return _.diag(SPV_ERROR_INVALID_DATA)
  178. << "Expected int scalar or vector type as Result Type: "
  179. << spvOpcodeString(opcode);
  180. const uint32_t input_type = _.GetOperandTypeId(inst, 2);
  181. if (!input_type ||
  182. (!_.IsIntScalarType(input_type) && !_.IsIntVectorType(input_type)))
  183. return _.diag(SPV_ERROR_INVALID_DATA)
  184. << "Expected int scalar or vector as input: "
  185. << spvOpcodeString(opcode);
  186. if (_.GetDimension(result_type) != _.GetDimension(input_type))
  187. return _.diag(SPV_ERROR_INVALID_DATA)
  188. << "Expected input to have the same dimension as Result Type: "
  189. << spvOpcodeString(opcode);
  190. break;
  191. }
  192. case SpvOpConvertUToPtr: {
  193. if (!_.IsPointerType(result_type))
  194. return _.diag(SPV_ERROR_INVALID_DATA)
  195. << "Expected Result Type to be a pointer: "
  196. << spvOpcodeString(opcode);
  197. const uint32_t input_type = _.GetOperandTypeId(inst, 2);
  198. if (!_.IsIntScalarType(input_type))
  199. return _.diag(SPV_ERROR_INVALID_DATA)
  200. << "Expected int scalar as input: " << spvOpcodeString(opcode);
  201. break;
  202. }
  203. case SpvOpPtrCastToGeneric: {
  204. uint32_t result_storage_class = 0;
  205. uint32_t result_data_type = 0;
  206. if (!_.GetPointerTypeInfo(result_type, &result_data_type,
  207. &result_storage_class))
  208. return _.diag(SPV_ERROR_INVALID_DATA)
  209. << "Expected Result Type to be a pointer: "
  210. << spvOpcodeString(opcode);
  211. if (result_storage_class != SpvStorageClassGeneric)
  212. return _.diag(SPV_ERROR_INVALID_DATA)
  213. << "Expected Result Type to have storage class Generic: "
  214. << spvOpcodeString(opcode);
  215. const uint32_t input_type = _.GetOperandTypeId(inst, 2);
  216. uint32_t input_storage_class = 0;
  217. uint32_t input_data_type = 0;
  218. if (!_.GetPointerTypeInfo(input_type, &input_data_type,
  219. &input_storage_class))
  220. return _.diag(SPV_ERROR_INVALID_DATA)
  221. << "Expected input to be a pointer: " << spvOpcodeString(opcode);
  222. if (input_storage_class != SpvStorageClassWorkgroup &&
  223. input_storage_class != SpvStorageClassCrossWorkgroup &&
  224. input_storage_class != SpvStorageClassFunction)
  225. return _.diag(SPV_ERROR_INVALID_DATA)
  226. << "Expected input to have storage class Workgroup, "
  227. << "CrossWorkgroup or Function: " << spvOpcodeString(opcode);
  228. if (result_data_type != input_data_type)
  229. return _.diag(SPV_ERROR_INVALID_DATA)
  230. << "Expected input and Result Type to point to the same type: "
  231. << spvOpcodeString(opcode);
  232. break;
  233. }
  234. case SpvOpGenericCastToPtr: {
  235. uint32_t result_storage_class = 0;
  236. uint32_t result_data_type = 0;
  237. if (!_.GetPointerTypeInfo(result_type, &result_data_type,
  238. &result_storage_class))
  239. return _.diag(SPV_ERROR_INVALID_DATA)
  240. << "Expected Result Type to be a pointer: "
  241. << spvOpcodeString(opcode);
  242. if (result_storage_class != SpvStorageClassWorkgroup &&
  243. result_storage_class != SpvStorageClassCrossWorkgroup &&
  244. result_storage_class != SpvStorageClassFunction)
  245. return _.diag(SPV_ERROR_INVALID_DATA)
  246. << "Expected Result Type to have storage class Workgroup, "
  247. << "CrossWorkgroup or Function: " << spvOpcodeString(opcode);
  248. const uint32_t input_type = _.GetOperandTypeId(inst, 2);
  249. uint32_t input_storage_class = 0;
  250. uint32_t input_data_type = 0;
  251. if (!_.GetPointerTypeInfo(input_type, &input_data_type,
  252. &input_storage_class))
  253. return _.diag(SPV_ERROR_INVALID_DATA)
  254. << "Expected input to be a pointer: " << spvOpcodeString(opcode);
  255. if (input_storage_class != SpvStorageClassGeneric)
  256. return _.diag(SPV_ERROR_INVALID_DATA)
  257. << "Expected input to have storage class Generic: "
  258. << spvOpcodeString(opcode);
  259. if (result_data_type != input_data_type)
  260. return _.diag(SPV_ERROR_INVALID_DATA)
  261. << "Expected input and Result Type to point to the same type: "
  262. << spvOpcodeString(opcode);
  263. break;
  264. }
  265. case SpvOpGenericCastToPtrExplicit: {
  266. uint32_t result_storage_class = 0;
  267. uint32_t result_data_type = 0;
  268. if (!_.GetPointerTypeInfo(result_type, &result_data_type,
  269. &result_storage_class))
  270. return _.diag(SPV_ERROR_INVALID_DATA)
  271. << "Expected Result Type to be a pointer: "
  272. << spvOpcodeString(opcode);
  273. const uint32_t target_storage_class = inst->words[4];
  274. if (result_storage_class != target_storage_class)
  275. return _.diag(SPV_ERROR_INVALID_DATA)
  276. << "Expected Result Type to be of target storage class: "
  277. << spvOpcodeString(opcode);
  278. const uint32_t input_type = _.GetOperandTypeId(inst, 2);
  279. uint32_t input_storage_class = 0;
  280. uint32_t input_data_type = 0;
  281. if (!_.GetPointerTypeInfo(input_type, &input_data_type,
  282. &input_storage_class))
  283. return _.diag(SPV_ERROR_INVALID_DATA)
  284. << "Expected input to be a pointer: " << spvOpcodeString(opcode);
  285. if (input_storage_class != SpvStorageClassGeneric)
  286. return _.diag(SPV_ERROR_INVALID_DATA)
  287. << "Expected input to have storage class Generic: "
  288. << spvOpcodeString(opcode);
  289. if (result_data_type != input_data_type)
  290. return _.diag(SPV_ERROR_INVALID_DATA)
  291. << "Expected input and Result Type to point to the same type: "
  292. << spvOpcodeString(opcode);
  293. if (target_storage_class != SpvStorageClassWorkgroup &&
  294. target_storage_class != SpvStorageClassCrossWorkgroup &&
  295. target_storage_class != SpvStorageClassFunction)
  296. return _.diag(SPV_ERROR_INVALID_DATA)
  297. << "Expected target storage class to be Workgroup, "
  298. << "CrossWorkgroup or Function: " << spvOpcodeString(opcode);
  299. break;
  300. }
  301. case SpvOpBitcast: {
  302. const uint32_t input_type = _.GetOperandTypeId(inst, 2);
  303. if (!input_type)
  304. return _.diag(SPV_ERROR_INVALID_DATA)
  305. << "Expected input to have a type: " << spvOpcodeString(opcode);
  306. const bool result_is_pointer = _.IsPointerType(result_type);
  307. const bool result_is_int_scalar = _.IsIntScalarType(result_type);
  308. const bool input_is_pointer = _.IsPointerType(input_type);
  309. const bool input_is_int_scalar = _.IsIntScalarType(input_type);
  310. if (!result_is_pointer && !result_is_int_scalar &&
  311. !_.IsIntVectorType(result_type) &&
  312. !_.IsFloatScalarType(result_type) &&
  313. !_.IsFloatVectorType(result_type))
  314. return _.diag(SPV_ERROR_INVALID_DATA)
  315. << "Expected Result Type to be a pointer or int or float vector "
  316. << "or scalar type: " << spvOpcodeString(opcode);
  317. if (!input_is_pointer && !input_is_int_scalar &&
  318. !_.IsIntVectorType(input_type) && !_.IsFloatScalarType(input_type) &&
  319. !_.IsFloatVectorType(input_type))
  320. return _.diag(SPV_ERROR_INVALID_DATA)
  321. << "Expected input to be a pointer or int or float vector "
  322. << "or scalar: " << spvOpcodeString(opcode);
  323. if (result_is_pointer && !input_is_pointer && !input_is_int_scalar)
  324. return _.diag(SPV_ERROR_INVALID_DATA)
  325. << "Expected input to be a pointer or int scalar if Result Type "
  326. << "is pointer: " << spvOpcodeString(opcode);
  327. if (input_is_pointer && !result_is_pointer && !result_is_int_scalar)
  328. return _.diag(SPV_ERROR_INVALID_DATA)
  329. << "Pointer can only be converted to another pointer or int "
  330. << "scalar: " << spvOpcodeString(opcode);
  331. if (!result_is_pointer && !input_is_pointer) {
  332. const uint32_t result_size =
  333. _.GetBitWidth(result_type) * _.GetDimension(result_type);
  334. const uint32_t input_size =
  335. _.GetBitWidth(input_type) * _.GetDimension(input_type);
  336. if (result_size != input_size)
  337. return _.diag(SPV_ERROR_INVALID_DATA)
  338. << "Expected input to have the same total bit width as "
  339. << "Result Type: " << spvOpcodeString(opcode);
  340. }
  341. break;
  342. }
  343. default:
  344. break;
  345. }
  346. return SPV_SUCCESS;
  347. }
  348. } // namespace libspirv