validate_conversion.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  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 spv::Op opcode = inst->opcode();
  27. const uint32_t result_type = inst->type_id();
  28. switch (opcode) {
  29. case spv::Op::OpConvertFToU: {
  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 spv::Op::OpConvertFToS: {
  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 spv::Op::OpConvertSToF:
  83. case spv::Op::OpConvertUToF: {
  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 spv::Op::OpUConvert: {
  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 spv::Op::OpSConvert: {
  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 spv::Op::OpFConvert: {
  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 spv::Op::OpQuantizeToF16: {
  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 spv::Op::OpConvertPtrToU: {
  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() == spv::AddressingModel::Logical)
  229. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  230. << "Logical addressing not supported: "
  231. << spvOpcodeString(opcode);
  232. if (_.addressing_model() ==
  233. spv::AddressingModel::PhysicalStorageBuffer64) {
  234. spv::StorageClass input_storage_class;
  235. uint32_t input_data_type = 0;
  236. _.GetPointerTypeInfo(input_type, &input_data_type,
  237. &input_storage_class);
  238. if (input_storage_class != spv::StorageClass::PhysicalStorageBuffer)
  239. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  240. << "Pointer storage class must be PhysicalStorageBuffer: "
  241. << spvOpcodeString(opcode);
  242. if (spvIsVulkanEnv(_.context()->target_env)) {
  243. if (_.GetBitWidth(result_type) != 64) {
  244. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  245. << _.VkErrorID(4710)
  246. << "PhysicalStorageBuffer64 addressing mode requires the "
  247. "result integer type to have a 64-bit width for Vulkan "
  248. "environment.";
  249. }
  250. }
  251. }
  252. break;
  253. }
  254. case spv::Op::OpSatConvertSToU:
  255. case spv::Op::OpSatConvertUToS: {
  256. if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type))
  257. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  258. << "Expected int scalar or vector type as Result Type: "
  259. << spvOpcodeString(opcode);
  260. const uint32_t input_type = _.GetOperandTypeId(inst, 2);
  261. if (!input_type ||
  262. (!_.IsIntScalarType(input_type) && !_.IsIntVectorType(input_type)))
  263. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  264. << "Expected int scalar or vector as input: "
  265. << spvOpcodeString(opcode);
  266. if (_.GetDimension(result_type) != _.GetDimension(input_type))
  267. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  268. << "Expected input to have the same dimension as Result Type: "
  269. << spvOpcodeString(opcode);
  270. break;
  271. }
  272. case spv::Op::OpConvertUToPtr: {
  273. if (!_.IsPointerType(result_type))
  274. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  275. << "Expected Result Type to be a pointer: "
  276. << spvOpcodeString(opcode);
  277. const uint32_t input_type = _.GetOperandTypeId(inst, 2);
  278. if (!input_type || !_.IsIntScalarType(input_type))
  279. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  280. << "Expected int scalar as input: " << spvOpcodeString(opcode);
  281. if (_.addressing_model() == spv::AddressingModel::Logical)
  282. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  283. << "Logical addressing not supported: "
  284. << spvOpcodeString(opcode);
  285. if (_.addressing_model() ==
  286. spv::AddressingModel::PhysicalStorageBuffer64) {
  287. spv::StorageClass result_storage_class;
  288. uint32_t result_data_type = 0;
  289. _.GetPointerTypeInfo(result_type, &result_data_type,
  290. &result_storage_class);
  291. if (result_storage_class != spv::StorageClass::PhysicalStorageBuffer)
  292. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  293. << "Pointer storage class must be PhysicalStorageBuffer: "
  294. << spvOpcodeString(opcode);
  295. if (spvIsVulkanEnv(_.context()->target_env)) {
  296. if (_.GetBitWidth(input_type) != 64) {
  297. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  298. << _.VkErrorID(4710)
  299. << "PhysicalStorageBuffer64 addressing mode requires the "
  300. "input integer to have a 64-bit width for Vulkan "
  301. "environment.";
  302. }
  303. }
  304. }
  305. break;
  306. }
  307. case spv::Op::OpPtrCastToGeneric: {
  308. spv::StorageClass result_storage_class;
  309. uint32_t result_data_type = 0;
  310. if (!_.GetPointerTypeInfo(result_type, &result_data_type,
  311. &result_storage_class))
  312. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  313. << "Expected Result Type to be a pointer: "
  314. << spvOpcodeString(opcode);
  315. if (result_storage_class != spv::StorageClass::Generic)
  316. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  317. << "Expected Result Type to have storage class Generic: "
  318. << spvOpcodeString(opcode);
  319. const uint32_t input_type = _.GetOperandTypeId(inst, 2);
  320. spv::StorageClass input_storage_class;
  321. uint32_t input_data_type = 0;
  322. if (!_.GetPointerTypeInfo(input_type, &input_data_type,
  323. &input_storage_class))
  324. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  325. << "Expected input to be a pointer: " << spvOpcodeString(opcode);
  326. if (input_storage_class != spv::StorageClass::Workgroup &&
  327. input_storage_class != spv::StorageClass::CrossWorkgroup &&
  328. input_storage_class != spv::StorageClass::Function)
  329. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  330. << "Expected input to have storage class Workgroup, "
  331. << "CrossWorkgroup or Function: " << spvOpcodeString(opcode);
  332. if (result_data_type != input_data_type)
  333. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  334. << "Expected input and Result Type to point to the same type: "
  335. << spvOpcodeString(opcode);
  336. break;
  337. }
  338. case spv::Op::OpGenericCastToPtr: {
  339. spv::StorageClass result_storage_class;
  340. uint32_t result_data_type = 0;
  341. if (!_.GetPointerTypeInfo(result_type, &result_data_type,
  342. &result_storage_class))
  343. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  344. << "Expected Result Type to be a pointer: "
  345. << spvOpcodeString(opcode);
  346. if (result_storage_class != spv::StorageClass::Workgroup &&
  347. result_storage_class != spv::StorageClass::CrossWorkgroup &&
  348. result_storage_class != spv::StorageClass::Function)
  349. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  350. << "Expected Result Type to have storage class Workgroup, "
  351. << "CrossWorkgroup or Function: " << spvOpcodeString(opcode);
  352. const uint32_t input_type = _.GetOperandTypeId(inst, 2);
  353. spv::StorageClass input_storage_class;
  354. uint32_t input_data_type = 0;
  355. if (!_.GetPointerTypeInfo(input_type, &input_data_type,
  356. &input_storage_class))
  357. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  358. << "Expected input to be a pointer: " << spvOpcodeString(opcode);
  359. if (input_storage_class != spv::StorageClass::Generic)
  360. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  361. << "Expected input to have storage class Generic: "
  362. << spvOpcodeString(opcode);
  363. if (result_data_type != input_data_type)
  364. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  365. << "Expected input and Result Type to point to the same type: "
  366. << spvOpcodeString(opcode);
  367. break;
  368. }
  369. case spv::Op::OpGenericCastToPtrExplicit: {
  370. spv::StorageClass result_storage_class;
  371. uint32_t result_data_type = 0;
  372. if (!_.GetPointerTypeInfo(result_type, &result_data_type,
  373. &result_storage_class))
  374. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  375. << "Expected Result Type to be a pointer: "
  376. << spvOpcodeString(opcode);
  377. const auto target_storage_class =
  378. inst->GetOperandAs<spv::StorageClass>(3);
  379. if (result_storage_class != target_storage_class)
  380. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  381. << "Expected Result Type to be of target storage class: "
  382. << spvOpcodeString(opcode);
  383. const uint32_t input_type = _.GetOperandTypeId(inst, 2);
  384. spv::StorageClass input_storage_class;
  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. if (input_storage_class != spv::StorageClass::Generic)
  391. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  392. << "Expected input to have storage class Generic: "
  393. << spvOpcodeString(opcode);
  394. if (result_data_type != input_data_type)
  395. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  396. << "Expected input and Result Type to point to the same type: "
  397. << spvOpcodeString(opcode);
  398. if (target_storage_class != spv::StorageClass::Workgroup &&
  399. target_storage_class != spv::StorageClass::CrossWorkgroup &&
  400. target_storage_class != spv::StorageClass::Function)
  401. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  402. << "Expected target storage class to be Workgroup, "
  403. << "CrossWorkgroup or Function: " << spvOpcodeString(opcode);
  404. break;
  405. }
  406. case spv::Op::OpBitcast: {
  407. const uint32_t input_type = _.GetOperandTypeId(inst, 2);
  408. if (!input_type)
  409. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  410. << "Expected input to have a type: " << spvOpcodeString(opcode);
  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. if (!result_is_pointer && !result_is_int_scalar &&
  416. !_.IsIntVectorType(result_type) &&
  417. !_.IsFloatScalarType(result_type) &&
  418. !_.IsFloatVectorType(result_type))
  419. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  420. << "Expected Result Type to be a pointer or int or float vector "
  421. << "or scalar type: " << spvOpcodeString(opcode);
  422. if (!input_is_pointer && !input_is_int_scalar &&
  423. !_.IsIntVectorType(input_type) && !_.IsFloatScalarType(input_type) &&
  424. !_.IsFloatVectorType(input_type))
  425. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  426. << "Expected input to be a pointer or int or float vector "
  427. << "or scalar: " << spvOpcodeString(opcode);
  428. if (_.version() >= SPV_SPIRV_VERSION_WORD(1, 5) ||
  429. _.HasExtension(kSPV_KHR_physical_storage_buffer)) {
  430. const bool result_is_int_vector = _.IsIntVectorType(result_type);
  431. const bool result_has_int32 =
  432. _.ContainsSizedIntOrFloatType(result_type, spv::Op::OpTypeInt, 32);
  433. const bool input_is_int_vector = _.IsIntVectorType(input_type);
  434. const bool input_has_int32 =
  435. _.ContainsSizedIntOrFloatType(input_type, spv::Op::OpTypeInt, 32);
  436. if (result_is_pointer && !input_is_pointer && !input_is_int_scalar &&
  437. !(input_is_int_vector && input_has_int32))
  438. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  439. << "Expected input to be a pointer, int scalar or 32-bit int "
  440. "vector if Result Type is pointer: "
  441. << spvOpcodeString(opcode);
  442. if (input_is_pointer && !result_is_pointer && !result_is_int_scalar &&
  443. !(result_is_int_vector && result_has_int32))
  444. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  445. << "Pointer can only be converted to another pointer, int "
  446. "scalar or 32-bit int vector: "
  447. << spvOpcodeString(opcode);
  448. } else {
  449. if (result_is_pointer && !input_is_pointer && !input_is_int_scalar)
  450. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  451. << "Expected input to be a pointer or int scalar if Result "
  452. "Type is pointer: "
  453. << spvOpcodeString(opcode);
  454. if (input_is_pointer && !result_is_pointer && !result_is_int_scalar)
  455. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  456. << "Pointer can only be converted to another pointer or int "
  457. "scalar: "
  458. << spvOpcodeString(opcode);
  459. }
  460. if (!result_is_pointer && !input_is_pointer) {
  461. const uint32_t result_size =
  462. _.GetBitWidth(result_type) * _.GetDimension(result_type);
  463. const uint32_t input_size =
  464. _.GetBitWidth(input_type) * _.GetDimension(input_type);
  465. if (result_size != input_size)
  466. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  467. << "Expected input to have the same total bit width as "
  468. << "Result Type: " << spvOpcodeString(opcode);
  469. }
  470. break;
  471. }
  472. case spv::Op::OpConvertUToAccelerationStructureKHR: {
  473. if (!_.IsAccelerationStructureType(result_type)) {
  474. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  475. << "Expected Result Type to be a Acceleration Structure: "
  476. << spvOpcodeString(opcode);
  477. }
  478. const uint32_t input_type = _.GetOperandTypeId(inst, 2);
  479. if (!input_type || !_.IsUnsigned64BitHandle(input_type)) {
  480. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  481. << "Expected 64-bit uint scalar or 2-component 32-bit uint "
  482. "vector as input: "
  483. << spvOpcodeString(opcode);
  484. }
  485. break;
  486. }
  487. default:
  488. break;
  489. }
  490. if (_.HasCapability(spv::Capability::Shader)) {
  491. switch (inst->opcode()) {
  492. case spv::Op::OpConvertFToU:
  493. case spv::Op::OpConvertFToS:
  494. case spv::Op::OpConvertSToF:
  495. case spv::Op::OpConvertUToF:
  496. case spv::Op::OpBitcast:
  497. if (_.ContainsLimitedUseIntOrFloatType(inst->type_id()) ||
  498. _.ContainsLimitedUseIntOrFloatType(_.GetOperandTypeId(inst, 2u))) {
  499. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  500. << "8- or 16-bit types can only be used with width-only "
  501. "conversions";
  502. }
  503. break;
  504. default:
  505. break;
  506. }
  507. }
  508. return SPV_SUCCESS;
  509. }
  510. } // namespace val
  511. } // namespace spvtools