validate_conversion.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690
  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/opcode.h"
  16. #include "source/spirv_constant.h"
  17. #include "source/spirv_target_env.h"
  18. #include "source/val/instruction.h"
  19. #include "source/val/validate.h"
  20. #include "source/val/validation_state.h"
  21. namespace spvtools {
  22. namespace val {
  23. // Validates correctness of conversion instructions.
  24. spv_result_t ConversionPass(ValidationState_t& _, const Instruction* inst) {
  25. const spv::Op opcode = inst->opcode();
  26. const uint32_t result_type = inst->type_id();
  27. switch (opcode) {
  28. case spv::Op::OpConvertFToU: {
  29. if (!_.IsUnsignedIntScalarType(result_type) &&
  30. !_.IsUnsignedIntVectorType(result_type) &&
  31. !_.IsUnsignedIntCooperativeMatrixType(result_type) &&
  32. !_.IsUnsignedIntCooperativeVectorNVType(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. !_.IsFloatCooperativeVectorNVType(input_type)))
  41. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  42. << "Expected input to be float scalar or vector: "
  43. << spvOpcodeString(opcode);
  44. if (_.IsCooperativeVectorNVType(result_type) ||
  45. _.IsCooperativeVectorNVType(input_type)) {
  46. spv_result_t ret =
  47. _.CooperativeVectorDimensionsMatch(inst, result_type, input_type);
  48. if (ret != SPV_SUCCESS) return ret;
  49. } else if (_.IsCooperativeMatrixType(result_type) ||
  50. _.IsCooperativeMatrixType(input_type)) {
  51. spv_result_t ret =
  52. _.CooperativeMatrixShapesMatch(inst, result_type, input_type, true);
  53. if (ret != SPV_SUCCESS) return ret;
  54. } else {
  55. if (_.GetDimension(result_type) != _.GetDimension(input_type))
  56. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  57. << "Expected input to have the same dimension as Result Type: "
  58. << spvOpcodeString(opcode);
  59. }
  60. break;
  61. }
  62. case spv::Op::OpConvertFToS: {
  63. if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type) &&
  64. !_.IsIntCooperativeMatrixType(result_type) &&
  65. !_.IsIntCooperativeVectorNVType(result_type))
  66. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  67. << "Expected int scalar or vector type as Result Type: "
  68. << spvOpcodeString(opcode);
  69. const uint32_t input_type = _.GetOperandTypeId(inst, 2);
  70. if (!input_type || (!_.IsFloatScalarType(input_type) &&
  71. !_.IsFloatVectorType(input_type) &&
  72. !_.IsFloatCooperativeMatrixType(input_type) &&
  73. !_.IsFloatCooperativeVectorNVType(input_type)))
  74. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  75. << "Expected input to be float scalar or vector: "
  76. << spvOpcodeString(opcode);
  77. if (_.IsCooperativeVectorNVType(result_type) ||
  78. _.IsCooperativeVectorNVType(input_type)) {
  79. spv_result_t ret =
  80. _.CooperativeVectorDimensionsMatch(inst, result_type, input_type);
  81. if (ret != SPV_SUCCESS) return ret;
  82. } else if (_.IsCooperativeMatrixType(result_type) ||
  83. _.IsCooperativeMatrixType(input_type)) {
  84. spv_result_t ret =
  85. _.CooperativeMatrixShapesMatch(inst, result_type, input_type, true);
  86. if (ret != SPV_SUCCESS) return ret;
  87. } else {
  88. if (_.GetDimension(result_type) != _.GetDimension(input_type))
  89. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  90. << "Expected input to have the same dimension as Result Type: "
  91. << spvOpcodeString(opcode);
  92. }
  93. break;
  94. }
  95. case spv::Op::OpConvertSToF:
  96. case spv::Op::OpConvertUToF: {
  97. if (!_.IsFloatScalarType(result_type) &&
  98. !_.IsFloatVectorType(result_type) &&
  99. !_.IsFloatCooperativeMatrixType(result_type) &&
  100. !_.IsFloatCooperativeVectorNVType(result_type))
  101. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  102. << "Expected float scalar or vector type as Result Type: "
  103. << spvOpcodeString(opcode);
  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. !_.IsIntCooperativeVectorNVType(input_type)))
  109. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  110. << "Expected input to be int scalar or vector: "
  111. << spvOpcodeString(opcode);
  112. if (_.IsCooperativeVectorNVType(result_type) ||
  113. _.IsCooperativeVectorNVType(input_type)) {
  114. spv_result_t ret =
  115. _.CooperativeVectorDimensionsMatch(inst, result_type, input_type);
  116. if (ret != SPV_SUCCESS) return ret;
  117. } else if (_.IsCooperativeMatrixType(result_type) ||
  118. _.IsCooperativeMatrixType(input_type)) {
  119. spv_result_t ret =
  120. _.CooperativeMatrixShapesMatch(inst, result_type, input_type, true);
  121. if (ret != SPV_SUCCESS) return ret;
  122. } else {
  123. if (_.GetDimension(result_type) != _.GetDimension(input_type))
  124. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  125. << "Expected input to have the same dimension as Result Type: "
  126. << spvOpcodeString(opcode);
  127. }
  128. break;
  129. }
  130. case spv::Op::OpUConvert: {
  131. if (!_.IsUnsignedIntScalarType(result_type) &&
  132. !_.IsUnsignedIntVectorType(result_type) &&
  133. !_.IsUnsignedIntCooperativeMatrixType(result_type) &&
  134. !_.IsUnsignedIntCooperativeVectorNVType(result_type))
  135. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  136. << "Expected unsigned int scalar or vector type as Result Type: "
  137. << spvOpcodeString(opcode);
  138. const uint32_t input_type = _.GetOperandTypeId(inst, 2);
  139. if (!input_type ||
  140. (!_.IsIntScalarType(input_type) && !_.IsIntVectorType(input_type) &&
  141. !_.IsIntCooperativeMatrixType(input_type) &&
  142. !_.IsIntCooperativeVectorNVType(input_type)))
  143. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  144. << "Expected input to be int scalar or vector: "
  145. << spvOpcodeString(opcode);
  146. if (_.IsCooperativeVectorNVType(result_type) ||
  147. _.IsCooperativeVectorNVType(input_type)) {
  148. spv_result_t ret =
  149. _.CooperativeVectorDimensionsMatch(inst, result_type, input_type);
  150. if (ret != SPV_SUCCESS) return ret;
  151. } else if (_.IsCooperativeMatrixType(result_type) ||
  152. _.IsCooperativeMatrixType(input_type)) {
  153. spv_result_t ret =
  154. _.CooperativeMatrixShapesMatch(inst, result_type, input_type, true);
  155. if (ret != SPV_SUCCESS) return ret;
  156. } else {
  157. if (_.GetDimension(result_type) != _.GetDimension(input_type))
  158. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  159. << "Expected input to have the same dimension as Result Type: "
  160. << spvOpcodeString(opcode);
  161. }
  162. if (_.GetBitWidth(result_type) == _.GetBitWidth(input_type))
  163. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  164. << "Expected input to have different bit width from Result "
  165. "Type: "
  166. << spvOpcodeString(opcode);
  167. break;
  168. }
  169. case spv::Op::OpSConvert: {
  170. if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type) &&
  171. !_.IsIntCooperativeMatrixType(result_type) &&
  172. !_.IsIntCooperativeVectorNVType(result_type))
  173. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  174. << "Expected int scalar or vector type as Result Type: "
  175. << spvOpcodeString(opcode);
  176. const uint32_t input_type = _.GetOperandTypeId(inst, 2);
  177. if (!input_type ||
  178. (!_.IsIntScalarType(input_type) && !_.IsIntVectorType(input_type) &&
  179. !_.IsIntCooperativeMatrixType(input_type) &&
  180. !_.IsIntCooperativeVectorNVType(input_type)))
  181. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  182. << "Expected input to be int scalar or vector: "
  183. << spvOpcodeString(opcode);
  184. if (_.IsCooperativeVectorNVType(result_type) ||
  185. _.IsCooperativeVectorNVType(input_type)) {
  186. spv_result_t ret =
  187. _.CooperativeVectorDimensionsMatch(inst, result_type, input_type);
  188. if (ret != SPV_SUCCESS) return ret;
  189. } else if (_.IsCooperativeMatrixType(result_type) ||
  190. _.IsCooperativeMatrixType(input_type)) {
  191. spv_result_t ret =
  192. _.CooperativeMatrixShapesMatch(inst, result_type, input_type, true);
  193. if (ret != SPV_SUCCESS) return ret;
  194. } else {
  195. if (_.GetDimension(result_type) != _.GetDimension(input_type))
  196. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  197. << "Expected input to have the same dimension as Result Type: "
  198. << spvOpcodeString(opcode);
  199. }
  200. if (_.GetBitWidth(result_type) == _.GetBitWidth(input_type))
  201. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  202. << "Expected input to have different bit width from Result "
  203. "Type: "
  204. << spvOpcodeString(opcode);
  205. break;
  206. }
  207. case spv::Op::OpFConvert: {
  208. if (!_.IsFloatScalarType(result_type) &&
  209. !_.IsFloatVectorType(result_type) &&
  210. !_.IsFloatCooperativeMatrixType(result_type) &&
  211. !_.IsFloatCooperativeVectorNVType(result_type))
  212. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  213. << "Expected float scalar or vector type as Result Type: "
  214. << spvOpcodeString(opcode);
  215. const uint32_t input_type = _.GetOperandTypeId(inst, 2);
  216. if (!input_type || (!_.IsFloatScalarType(input_type) &&
  217. !_.IsFloatVectorType(input_type) &&
  218. !_.IsFloatCooperativeMatrixType(input_type) &&
  219. !_.IsFloatCooperativeVectorNVType(input_type)))
  220. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  221. << "Expected input to be float scalar or vector: "
  222. << spvOpcodeString(opcode);
  223. if (_.IsCooperativeVectorNVType(result_type) ||
  224. _.IsCooperativeVectorNVType(input_type)) {
  225. spv_result_t ret =
  226. _.CooperativeVectorDimensionsMatch(inst, result_type, input_type);
  227. if (ret != SPV_SUCCESS) return ret;
  228. } else if (_.IsCooperativeMatrixType(result_type) ||
  229. _.IsCooperativeMatrixType(input_type)) {
  230. spv_result_t ret =
  231. _.CooperativeMatrixShapesMatch(inst, result_type, input_type, true);
  232. if (ret != SPV_SUCCESS) return ret;
  233. } else {
  234. if (_.GetDimension(result_type) != _.GetDimension(input_type))
  235. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  236. << "Expected input to have the same dimension as Result Type: "
  237. << spvOpcodeString(opcode);
  238. }
  239. if (_.GetBitWidth(result_type) == _.GetBitWidth(input_type))
  240. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  241. << "Expected input to have different bit width from Result "
  242. "Type: "
  243. << spvOpcodeString(opcode);
  244. break;
  245. }
  246. case spv::Op::OpQuantizeToF16: {
  247. if ((!_.IsFloatScalarType(result_type) &&
  248. !_.IsFloatVectorType(result_type)) ||
  249. _.GetBitWidth(result_type) != 32)
  250. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  251. << "Expected 32-bit float scalar or vector type as Result Type: "
  252. << spvOpcodeString(opcode);
  253. const uint32_t input_type = _.GetOperandTypeId(inst, 2);
  254. if (input_type != result_type)
  255. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  256. << "Expected input type to be equal to Result Type: "
  257. << spvOpcodeString(opcode);
  258. break;
  259. }
  260. case spv::Op::OpConvertPtrToU: {
  261. if (!_.IsUnsignedIntScalarType(result_type))
  262. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  263. << "Expected unsigned int scalar type as Result Type: "
  264. << spvOpcodeString(opcode);
  265. const uint32_t input_type = _.GetOperandTypeId(inst, 2);
  266. if (!_.IsPointerType(input_type))
  267. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  268. << "Expected input to be a pointer: " << spvOpcodeString(opcode);
  269. if (_.addressing_model() == spv::AddressingModel::Logical)
  270. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  271. << "Logical addressing not supported: "
  272. << spvOpcodeString(opcode);
  273. if (_.addressing_model() ==
  274. spv::AddressingModel::PhysicalStorageBuffer64) {
  275. spv::StorageClass input_storage_class;
  276. uint32_t input_data_type = 0;
  277. _.GetPointerTypeInfo(input_type, &input_data_type,
  278. &input_storage_class);
  279. if (input_storage_class != spv::StorageClass::PhysicalStorageBuffer)
  280. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  281. << "Pointer storage class must be PhysicalStorageBuffer: "
  282. << spvOpcodeString(opcode);
  283. if (spvIsVulkanEnv(_.context()->target_env)) {
  284. if (_.GetBitWidth(result_type) != 64) {
  285. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  286. << _.VkErrorID(4710)
  287. << "PhysicalStorageBuffer64 addressing mode requires the "
  288. "result integer type to have a 64-bit width for Vulkan "
  289. "environment.";
  290. }
  291. }
  292. }
  293. break;
  294. }
  295. case spv::Op::OpSatConvertSToU:
  296. case spv::Op::OpSatConvertUToS: {
  297. if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type))
  298. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  299. << "Expected int scalar or vector type as Result Type: "
  300. << spvOpcodeString(opcode);
  301. const uint32_t input_type = _.GetOperandTypeId(inst, 2);
  302. if (!input_type ||
  303. (!_.IsIntScalarType(input_type) && !_.IsIntVectorType(input_type)))
  304. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  305. << "Expected int scalar or vector as input: "
  306. << spvOpcodeString(opcode);
  307. if (_.GetDimension(result_type) != _.GetDimension(input_type))
  308. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  309. << "Expected input to have the same dimension as Result Type: "
  310. << spvOpcodeString(opcode);
  311. break;
  312. }
  313. case spv::Op::OpConvertUToPtr: {
  314. if (!_.IsPointerType(result_type))
  315. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  316. << "Expected Result Type to be a pointer: "
  317. << spvOpcodeString(opcode);
  318. const uint32_t input_type = _.GetOperandTypeId(inst, 2);
  319. if (!input_type || !_.IsIntScalarType(input_type))
  320. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  321. << "Expected int scalar as input: " << spvOpcodeString(opcode);
  322. if (_.addressing_model() == spv::AddressingModel::Logical)
  323. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  324. << "Logical addressing not supported: "
  325. << spvOpcodeString(opcode);
  326. if (_.addressing_model() ==
  327. spv::AddressingModel::PhysicalStorageBuffer64) {
  328. spv::StorageClass result_storage_class;
  329. uint32_t result_data_type = 0;
  330. _.GetPointerTypeInfo(result_type, &result_data_type,
  331. &result_storage_class);
  332. if (result_storage_class != spv::StorageClass::PhysicalStorageBuffer)
  333. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  334. << "Pointer storage class must be PhysicalStorageBuffer: "
  335. << spvOpcodeString(opcode);
  336. if (spvIsVulkanEnv(_.context()->target_env)) {
  337. if (_.GetBitWidth(input_type) != 64) {
  338. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  339. << _.VkErrorID(4710)
  340. << "PhysicalStorageBuffer64 addressing mode requires the "
  341. "input integer to have a 64-bit width for Vulkan "
  342. "environment.";
  343. }
  344. }
  345. }
  346. break;
  347. }
  348. case spv::Op::OpPtrCastToGeneric: {
  349. spv::StorageClass result_storage_class;
  350. uint32_t result_data_type = 0;
  351. if (!_.GetPointerTypeInfo(result_type, &result_data_type,
  352. &result_storage_class))
  353. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  354. << "Expected Result Type to be a pointer: "
  355. << spvOpcodeString(opcode);
  356. if (result_storage_class != spv::StorageClass::Generic)
  357. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  358. << "Expected Result Type to have storage class Generic: "
  359. << spvOpcodeString(opcode);
  360. const uint32_t input_type = _.GetOperandTypeId(inst, 2);
  361. spv::StorageClass input_storage_class;
  362. uint32_t input_data_type = 0;
  363. if (!_.GetPointerTypeInfo(input_type, &input_data_type,
  364. &input_storage_class))
  365. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  366. << "Expected input to be a pointer: " << spvOpcodeString(opcode);
  367. if (input_storage_class != spv::StorageClass::Workgroup &&
  368. input_storage_class != spv::StorageClass::CrossWorkgroup &&
  369. input_storage_class != spv::StorageClass::Function)
  370. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  371. << "Expected input to have storage class Workgroup, "
  372. << "CrossWorkgroup or Function: " << spvOpcodeString(opcode);
  373. if (result_data_type != input_data_type)
  374. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  375. << "Expected input and Result Type to point to the same type: "
  376. << spvOpcodeString(opcode);
  377. break;
  378. }
  379. case spv::Op::OpGenericCastToPtr: {
  380. spv::StorageClass result_storage_class;
  381. uint32_t result_data_type = 0;
  382. if (!_.GetPointerTypeInfo(result_type, &result_data_type,
  383. &result_storage_class))
  384. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  385. << "Expected Result Type to be a pointer: "
  386. << spvOpcodeString(opcode);
  387. if (result_storage_class != spv::StorageClass::Workgroup &&
  388. result_storage_class != spv::StorageClass::CrossWorkgroup &&
  389. result_storage_class != spv::StorageClass::Function)
  390. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  391. << "Expected Result Type to have storage class Workgroup, "
  392. << "CrossWorkgroup or Function: " << spvOpcodeString(opcode);
  393. const uint32_t input_type = _.GetOperandTypeId(inst, 2);
  394. spv::StorageClass input_storage_class;
  395. uint32_t input_data_type = 0;
  396. if (!_.GetPointerTypeInfo(input_type, &input_data_type,
  397. &input_storage_class))
  398. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  399. << "Expected input to be a pointer: " << spvOpcodeString(opcode);
  400. if (input_storage_class != spv::StorageClass::Generic)
  401. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  402. << "Expected input to have storage class Generic: "
  403. << spvOpcodeString(opcode);
  404. if (result_data_type != input_data_type)
  405. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  406. << "Expected input and Result Type to point to the same type: "
  407. << spvOpcodeString(opcode);
  408. break;
  409. }
  410. case spv::Op::OpGenericCastToPtrExplicit: {
  411. spv::StorageClass result_storage_class;
  412. uint32_t result_data_type = 0;
  413. if (!_.GetPointerTypeInfo(result_type, &result_data_type,
  414. &result_storage_class))
  415. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  416. << "Expected Result Type to be a pointer: "
  417. << spvOpcodeString(opcode);
  418. const auto target_storage_class =
  419. inst->GetOperandAs<spv::StorageClass>(3);
  420. if (result_storage_class != target_storage_class)
  421. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  422. << "Expected Result Type to be of target storage class: "
  423. << spvOpcodeString(opcode);
  424. const uint32_t input_type = _.GetOperandTypeId(inst, 2);
  425. spv::StorageClass input_storage_class;
  426. uint32_t input_data_type = 0;
  427. if (!_.GetPointerTypeInfo(input_type, &input_data_type,
  428. &input_storage_class))
  429. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  430. << "Expected input to be a pointer: " << spvOpcodeString(opcode);
  431. if (input_storage_class != spv::StorageClass::Generic)
  432. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  433. << "Expected input to have storage class Generic: "
  434. << spvOpcodeString(opcode);
  435. if (result_data_type != input_data_type)
  436. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  437. << "Expected input and Result Type to point to the same type: "
  438. << spvOpcodeString(opcode);
  439. if (target_storage_class != spv::StorageClass::Workgroup &&
  440. target_storage_class != spv::StorageClass::CrossWorkgroup &&
  441. target_storage_class != spv::StorageClass::Function)
  442. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  443. << "Expected target storage class to be Workgroup, "
  444. << "CrossWorkgroup or Function: " << spvOpcodeString(opcode);
  445. break;
  446. }
  447. case spv::Op::OpBitcast: {
  448. const uint32_t input_type = _.GetOperandTypeId(inst, 2);
  449. if (!input_type)
  450. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  451. << "Expected input to have a type: " << spvOpcodeString(opcode);
  452. const bool result_is_pointer = _.IsPointerType(result_type);
  453. const bool result_is_int_scalar = _.IsIntScalarType(result_type);
  454. const bool input_is_pointer = _.IsPointerType(input_type);
  455. const bool input_is_int_scalar = _.IsIntScalarType(input_type);
  456. const bool result_is_coopmat = _.IsCooperativeMatrixType(result_type);
  457. const bool input_is_coopmat = _.IsCooperativeMatrixType(input_type);
  458. const bool result_is_coopvec = _.IsCooperativeVectorNVType(result_type);
  459. const bool input_is_coopvec = _.IsCooperativeVectorNVType(input_type);
  460. if (!result_is_pointer && !result_is_int_scalar && !result_is_coopmat &&
  461. !result_is_coopvec && !_.IsIntVectorType(result_type) &&
  462. !_.IsFloatScalarType(result_type) &&
  463. !_.IsFloatVectorType(result_type))
  464. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  465. << "Expected Result Type to be a pointer or int or float vector "
  466. << "or scalar type: " << spvOpcodeString(opcode);
  467. if (!input_is_pointer && !input_is_int_scalar && !input_is_coopmat &&
  468. !input_is_coopvec && !_.IsIntVectorType(input_type) &&
  469. !_.IsFloatScalarType(input_type) && !_.IsFloatVectorType(input_type))
  470. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  471. << "Expected input to be a pointer or int or float vector "
  472. << "or scalar: " << spvOpcodeString(opcode);
  473. if (result_is_coopvec != input_is_coopvec)
  474. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  475. << "Cooperative vector can only be cast to another cooperative "
  476. << "vector: " << spvOpcodeString(opcode);
  477. if (result_is_coopmat != input_is_coopmat)
  478. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  479. << "Cooperative matrix can only be cast to another cooperative "
  480. << "matrix: " << spvOpcodeString(opcode);
  481. if (result_is_coopvec) {
  482. spv_result_t ret =
  483. _.CooperativeVectorDimensionsMatch(inst, result_type, input_type);
  484. if (ret != SPV_SUCCESS) return ret;
  485. }
  486. if (result_is_coopmat) {
  487. spv_result_t ret = _.CooperativeMatrixShapesMatch(inst, result_type,
  488. input_type, false);
  489. if (ret != SPV_SUCCESS) return ret;
  490. }
  491. if (_.version() >= SPV_SPIRV_VERSION_WORD(1, 5) ||
  492. _.HasExtension(kSPV_KHR_physical_storage_buffer)) {
  493. const bool result_is_int_vector = _.IsIntVectorType(result_type);
  494. const bool result_has_int32 =
  495. _.ContainsSizedIntOrFloatType(result_type, spv::Op::OpTypeInt, 32);
  496. const bool input_is_int_vector = _.IsIntVectorType(input_type);
  497. const bool input_has_int32 =
  498. _.ContainsSizedIntOrFloatType(input_type, spv::Op::OpTypeInt, 32);
  499. if (result_is_pointer && !input_is_pointer && !input_is_int_scalar &&
  500. !(input_is_int_vector && input_has_int32))
  501. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  502. << "Expected input to be a pointer, int scalar or 32-bit int "
  503. "vector if Result Type is pointer: "
  504. << spvOpcodeString(opcode);
  505. if (input_is_pointer && !result_is_pointer && !result_is_int_scalar &&
  506. !(result_is_int_vector && result_has_int32))
  507. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  508. << "Pointer can only be converted to another pointer, int "
  509. "scalar or 32-bit int vector: "
  510. << spvOpcodeString(opcode);
  511. } else {
  512. if (result_is_pointer && !input_is_pointer && !input_is_int_scalar)
  513. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  514. << "Expected input to be a pointer or int scalar if Result "
  515. "Type is pointer: "
  516. << spvOpcodeString(opcode);
  517. if (input_is_pointer && !result_is_pointer && !result_is_int_scalar)
  518. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  519. << "Pointer can only be converted to another pointer or int "
  520. "scalar: "
  521. << spvOpcodeString(opcode);
  522. }
  523. if (!result_is_pointer && !input_is_pointer) {
  524. const uint32_t result_size =
  525. _.GetBitWidth(result_type) * _.GetDimension(result_type);
  526. const uint32_t input_size =
  527. _.GetBitWidth(input_type) * _.GetDimension(input_type);
  528. if (result_size != input_size)
  529. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  530. << "Expected input to have the same total bit width as "
  531. << "Result Type: " << spvOpcodeString(opcode);
  532. }
  533. break;
  534. }
  535. case spv::Op::OpConvertUToAccelerationStructureKHR: {
  536. if (!_.IsAccelerationStructureType(result_type)) {
  537. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  538. << "Expected Result Type to be a Acceleration Structure: "
  539. << spvOpcodeString(opcode);
  540. }
  541. const uint32_t input_type = _.GetOperandTypeId(inst, 2);
  542. if (!input_type || !_.IsUnsigned64BitHandle(input_type)) {
  543. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  544. << "Expected 64-bit uint scalar or 2-component 32-bit uint "
  545. "vector as input: "
  546. << spvOpcodeString(opcode);
  547. }
  548. break;
  549. }
  550. case spv::Op::OpCooperativeMatrixConvertNV:
  551. case spv::Op::OpCooperativeMatrixTransposeNV: {
  552. if (!_.IsCooperativeMatrixType(result_type)) {
  553. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  554. << "Expected cooperative matrix Result Type: "
  555. << spvOpcodeString(opcode);
  556. }
  557. const uint32_t input_type = _.GetOperandTypeId(inst, 2);
  558. if (!_.IsCooperativeMatrixType(input_type)) {
  559. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  560. << "Expected cooperative matrix type for Matrix input: "
  561. << spvOpcodeString(opcode);
  562. }
  563. bool swap_row_col = (opcode == spv::Op::OpCooperativeMatrixTransposeNV);
  564. if (auto error = _.CooperativeMatrixShapesMatch(
  565. inst, result_type, input_type, true, swap_row_col))
  566. return error;
  567. if (opcode == spv::Op::OpCooperativeMatrixConvertNV) {
  568. if (_.FindDef(result_type)->GetOperandAs<uint32_t>(1) !=
  569. _.FindDef(input_type)->GetOperandAs<uint32_t>(1)) {
  570. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  571. << "Result Type and Matrix component types mismatch: "
  572. << spvOpcodeString(opcode);
  573. }
  574. }
  575. if (opcode == spv::Op::OpCooperativeMatrixTransposeNV) {
  576. if (!_.IsCooperativeMatrixBType(result_type)) {
  577. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  578. << "Result Type must have UseB: " << spvOpcodeString(opcode);
  579. }
  580. }
  581. break;
  582. }
  583. default:
  584. break;
  585. }
  586. if (_.HasCapability(spv::Capability::Shader)) {
  587. switch (inst->opcode()) {
  588. case spv::Op::OpConvertFToU:
  589. case spv::Op::OpConvertFToS:
  590. case spv::Op::OpConvertSToF:
  591. case spv::Op::OpConvertUToF:
  592. case spv::Op::OpBitcast:
  593. if (_.ContainsLimitedUseIntOrFloatType(inst->type_id()) ||
  594. _.ContainsLimitedUseIntOrFloatType(_.GetOperandTypeId(inst, 2u))) {
  595. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  596. << "8- or 16-bit types can only be used with width-only "
  597. "conversions";
  598. }
  599. break;
  600. default:
  601. break;
  602. }
  603. }
  604. return SPV_SUCCESS;
  605. }
  606. } // namespace val
  607. } // namespace spvtools