validate_conversion.cpp 24 KB

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