2
0

validate_annotation.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. // Copyright (c) 2018 Google LLC.
  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. #include "source/opcode.h"
  15. #include "source/spirv_target_env.h"
  16. #include "source/val/instruction.h"
  17. #include "source/val/validate.h"
  18. #include "source/val/validation_state.h"
  19. namespace spvtools {
  20. namespace val {
  21. namespace {
  22. std::string LogStringForDecoration(uint32_t decoration) {
  23. switch (decoration) {
  24. case SpvDecorationRelaxedPrecision:
  25. return "RelaxedPrecision";
  26. case SpvDecorationSpecId:
  27. return "SpecId";
  28. case SpvDecorationBlock:
  29. return "Block";
  30. case SpvDecorationBufferBlock:
  31. return "BufferBlock";
  32. case SpvDecorationRowMajor:
  33. return "RowMajor";
  34. case SpvDecorationColMajor:
  35. return "ColMajor";
  36. case SpvDecorationArrayStride:
  37. return "ArrayStride";
  38. case SpvDecorationMatrixStride:
  39. return "MatrixStride";
  40. case SpvDecorationGLSLShared:
  41. return "GLSLShared";
  42. case SpvDecorationGLSLPacked:
  43. return "GLSLPacked";
  44. case SpvDecorationCPacked:
  45. return "CPacked";
  46. case SpvDecorationBuiltIn:
  47. return "BuiltIn";
  48. case SpvDecorationNoPerspective:
  49. return "NoPerspective";
  50. case SpvDecorationFlat:
  51. return "Flat";
  52. case SpvDecorationPatch:
  53. return "Patch";
  54. case SpvDecorationCentroid:
  55. return "Centroid";
  56. case SpvDecorationSample:
  57. return "Sample";
  58. case SpvDecorationInvariant:
  59. return "Invariant";
  60. case SpvDecorationRestrict:
  61. return "Restrict";
  62. case SpvDecorationAliased:
  63. return "Aliased";
  64. case SpvDecorationVolatile:
  65. return "Volatile";
  66. case SpvDecorationConstant:
  67. return "Constant";
  68. case SpvDecorationCoherent:
  69. return "Coherent";
  70. case SpvDecorationNonWritable:
  71. return "NonWritable";
  72. case SpvDecorationNonReadable:
  73. return "NonReadable";
  74. case SpvDecorationUniform:
  75. return "Uniform";
  76. case SpvDecorationSaturatedConversion:
  77. return "SaturatedConversion";
  78. case SpvDecorationStream:
  79. return "Stream";
  80. case SpvDecorationLocation:
  81. return "Location";
  82. case SpvDecorationComponent:
  83. return "Component";
  84. case SpvDecorationIndex:
  85. return "Index";
  86. case SpvDecorationBinding:
  87. return "Binding";
  88. case SpvDecorationDescriptorSet:
  89. return "DescriptorSet";
  90. case SpvDecorationOffset:
  91. return "Offset";
  92. case SpvDecorationXfbBuffer:
  93. return "XfbBuffer";
  94. case SpvDecorationXfbStride:
  95. return "XfbStride";
  96. case SpvDecorationFuncParamAttr:
  97. return "FuncParamAttr";
  98. case SpvDecorationFPRoundingMode:
  99. return "FPRoundingMode";
  100. case SpvDecorationFPFastMathMode:
  101. return "FPFastMathMode";
  102. case SpvDecorationLinkageAttributes:
  103. return "LinkageAttributes";
  104. case SpvDecorationNoContraction:
  105. return "NoContraction";
  106. case SpvDecorationInputAttachmentIndex:
  107. return "InputAttachmentIndex";
  108. case SpvDecorationAlignment:
  109. return "Alignment";
  110. case SpvDecorationMaxByteOffset:
  111. return "MaxByteOffset";
  112. case SpvDecorationAlignmentId:
  113. return "AlignmentId";
  114. case SpvDecorationMaxByteOffsetId:
  115. return "MaxByteOffsetId";
  116. case SpvDecorationNoSignedWrap:
  117. return "NoSignedWrap";
  118. case SpvDecorationNoUnsignedWrap:
  119. return "NoUnsignedWrap";
  120. case SpvDecorationExplicitInterpAMD:
  121. return "ExplicitInterpAMD";
  122. case SpvDecorationOverrideCoverageNV:
  123. return "OverrideCoverageNV";
  124. case SpvDecorationPassthroughNV:
  125. return "PassthroughNV";
  126. case SpvDecorationViewportRelativeNV:
  127. return "ViewportRelativeNV";
  128. case SpvDecorationSecondaryViewportRelativeNV:
  129. return "SecondaryViewportRelativeNV";
  130. case SpvDecorationPerPrimitiveNV:
  131. return "PerPrimitiveNV";
  132. case SpvDecorationPerViewNV:
  133. return "PerViewNV";
  134. case SpvDecorationPerTaskNV:
  135. return "PerTaskNV";
  136. case SpvDecorationPerVertexNV:
  137. return "PerVertexNV";
  138. case SpvDecorationNonUniformEXT:
  139. return "NonUniformEXT";
  140. case SpvDecorationRestrictPointerEXT:
  141. return "RestrictPointerEXT";
  142. case SpvDecorationAliasedPointerEXT:
  143. return "AliasedPointerEXT";
  144. case SpvDecorationHlslCounterBufferGOOGLE:
  145. return "HlslCounterBufferGOOGLE";
  146. case SpvDecorationHlslSemanticGOOGLE:
  147. return "HlslSemanticGOOGLE";
  148. default:
  149. break;
  150. }
  151. return "Unknown";
  152. }
  153. // Returns true if the decoration takes ID parameters.
  154. // TODO(dneto): This can be generated from the grammar.
  155. bool DecorationTakesIdParameters(uint32_t type) {
  156. switch (static_cast<SpvDecoration>(type)) {
  157. case SpvDecorationUniformId:
  158. case SpvDecorationAlignmentId:
  159. case SpvDecorationMaxByteOffsetId:
  160. case SpvDecorationHlslCounterBufferGOOGLE:
  161. return true;
  162. default:
  163. break;
  164. }
  165. return false;
  166. }
  167. spv_result_t ValidateDecorate(ValidationState_t& _, const Instruction* inst) {
  168. const auto decoration = inst->GetOperandAs<uint32_t>(1);
  169. if (decoration == SpvDecorationSpecId) {
  170. const auto target_id = inst->GetOperandAs<uint32_t>(0);
  171. const auto target = _.FindDef(target_id);
  172. if (!target || !spvOpcodeIsScalarSpecConstant(target->opcode())) {
  173. return _.diag(SPV_ERROR_INVALID_ID, inst)
  174. << "OpDecorate SpecId decoration target <id> '"
  175. << _.getIdName(target_id)
  176. << "' is not a scalar specialization constant.";
  177. }
  178. }
  179. if (spvIsVulkanEnv(_.context()->target_env)) {
  180. if ((decoration == SpvDecorationGLSLShared) ||
  181. (decoration == SpvDecorationGLSLPacked)) {
  182. return _.diag(SPV_ERROR_INVALID_ID, inst)
  183. << _.VkErrorID(4669) << "OpDecorate decoration '"
  184. << LogStringForDecoration(decoration)
  185. << "' is not valid for the Vulkan execution environment.";
  186. }
  187. }
  188. if (DecorationTakesIdParameters(decoration)) {
  189. return _.diag(SPV_ERROR_INVALID_ID, inst)
  190. << "Decorations taking ID parameters may not be used with "
  191. "OpDecorateId";
  192. }
  193. // TODO: Add validations for all decorations.
  194. return SPV_SUCCESS;
  195. }
  196. spv_result_t ValidateDecorateId(ValidationState_t& _, const Instruction* inst) {
  197. const auto decoration = inst->GetOperandAs<uint32_t>(1);
  198. if (!DecorationTakesIdParameters(decoration)) {
  199. return _.diag(SPV_ERROR_INVALID_ID, inst)
  200. << "Decorations that don't take ID parameters may not be used with "
  201. "OpDecorateId";
  202. }
  203. // TODO: Add validations for these decorations.
  204. // UniformId is covered elsewhere.
  205. return SPV_SUCCESS;
  206. }
  207. spv_result_t ValidateMemberDecorate(ValidationState_t& _,
  208. const Instruction* inst) {
  209. const auto struct_type_id = inst->GetOperandAs<uint32_t>(0);
  210. const auto struct_type = _.FindDef(struct_type_id);
  211. if (!struct_type || SpvOpTypeStruct != struct_type->opcode()) {
  212. return _.diag(SPV_ERROR_INVALID_ID, inst)
  213. << "OpMemberDecorate Structure type <id> '"
  214. << _.getIdName(struct_type_id) << "' is not a struct type.";
  215. }
  216. const auto member = inst->GetOperandAs<uint32_t>(1);
  217. const auto member_count =
  218. static_cast<uint32_t>(struct_type->words().size() - 2);
  219. if (member_count <= member) {
  220. return _.diag(SPV_ERROR_INVALID_ID, inst)
  221. << "Index " << member
  222. << " provided in OpMemberDecorate for struct <id> "
  223. << _.getIdName(struct_type_id)
  224. << " is out of bounds. The structure has " << member_count
  225. << " members. Largest valid index is " << member_count - 1 << ".";
  226. }
  227. return SPV_SUCCESS;
  228. }
  229. spv_result_t ValidateDecorationGroup(ValidationState_t& _,
  230. const Instruction* inst) {
  231. const auto decoration_group_id = inst->GetOperandAs<uint32_t>(0);
  232. const auto decoration_group = _.FindDef(decoration_group_id);
  233. for (auto pair : decoration_group->uses()) {
  234. auto use = pair.first;
  235. if (use->opcode() != SpvOpDecorate && use->opcode() != SpvOpGroupDecorate &&
  236. use->opcode() != SpvOpGroupMemberDecorate &&
  237. use->opcode() != SpvOpName && use->opcode() != SpvOpDecorateId &&
  238. !use->IsNonSemantic()) {
  239. return _.diag(SPV_ERROR_INVALID_ID, inst)
  240. << "Result id of OpDecorationGroup can only "
  241. << "be targeted by OpName, OpGroupDecorate, "
  242. << "OpDecorate, OpDecorateId, and OpGroupMemberDecorate";
  243. }
  244. }
  245. return SPV_SUCCESS;
  246. }
  247. spv_result_t ValidateGroupDecorate(ValidationState_t& _,
  248. const Instruction* inst) {
  249. const auto decoration_group_id = inst->GetOperandAs<uint32_t>(0);
  250. auto decoration_group = _.FindDef(decoration_group_id);
  251. if (!decoration_group || SpvOpDecorationGroup != decoration_group->opcode()) {
  252. return _.diag(SPV_ERROR_INVALID_ID, inst)
  253. << "OpGroupDecorate Decoration group <id> '"
  254. << _.getIdName(decoration_group_id)
  255. << "' is not a decoration group.";
  256. }
  257. for (unsigned i = 1; i < inst->operands().size(); ++i) {
  258. auto target_id = inst->GetOperandAs<uint32_t>(i);
  259. auto target = _.FindDef(target_id);
  260. if (!target || target->opcode() == SpvOpDecorationGroup) {
  261. return _.diag(SPV_ERROR_INVALID_ID, inst)
  262. << "OpGroupDecorate may not target OpDecorationGroup <id> '"
  263. << _.getIdName(target_id) << "'";
  264. }
  265. }
  266. return SPV_SUCCESS;
  267. }
  268. spv_result_t ValidateGroupMemberDecorate(ValidationState_t& _,
  269. const Instruction* inst) {
  270. const auto decoration_group_id = inst->GetOperandAs<uint32_t>(0);
  271. const auto decoration_group = _.FindDef(decoration_group_id);
  272. if (!decoration_group || SpvOpDecorationGroup != decoration_group->opcode()) {
  273. return _.diag(SPV_ERROR_INVALID_ID, inst)
  274. << "OpGroupMemberDecorate Decoration group <id> '"
  275. << _.getIdName(decoration_group_id)
  276. << "' is not a decoration group.";
  277. }
  278. // Grammar checks ensures that the number of arguments to this instruction
  279. // is an odd number: 1 decoration group + (id,literal) pairs.
  280. for (size_t i = 1; i + 1 < inst->operands().size(); i += 2) {
  281. const uint32_t struct_id = inst->GetOperandAs<uint32_t>(i);
  282. const uint32_t index = inst->GetOperandAs<uint32_t>(i + 1);
  283. auto struct_instr = _.FindDef(struct_id);
  284. if (!struct_instr || SpvOpTypeStruct != struct_instr->opcode()) {
  285. return _.diag(SPV_ERROR_INVALID_ID, inst)
  286. << "OpGroupMemberDecorate Structure type <id> '"
  287. << _.getIdName(struct_id) << "' is not a struct type.";
  288. }
  289. const uint32_t num_struct_members =
  290. static_cast<uint32_t>(struct_instr->words().size() - 2);
  291. if (index >= num_struct_members) {
  292. return _.diag(SPV_ERROR_INVALID_ID, inst)
  293. << "Index " << index
  294. << " provided in OpGroupMemberDecorate for struct <id> "
  295. << _.getIdName(struct_id)
  296. << " is out of bounds. The structure has " << num_struct_members
  297. << " members. Largest valid index is " << num_struct_members - 1
  298. << ".";
  299. }
  300. }
  301. return SPV_SUCCESS;
  302. }
  303. // Registers necessary decoration(s) for the appropriate IDs based on the
  304. // instruction.
  305. spv_result_t RegisterDecorations(ValidationState_t& _,
  306. const Instruction* inst) {
  307. switch (inst->opcode()) {
  308. case SpvOpDecorate:
  309. case SpvOpDecorateId: {
  310. const uint32_t target_id = inst->word(1);
  311. const SpvDecoration dec_type = static_cast<SpvDecoration>(inst->word(2));
  312. std::vector<uint32_t> dec_params;
  313. if (inst->words().size() > 3) {
  314. dec_params.insert(dec_params.end(), inst->words().begin() + 3,
  315. inst->words().end());
  316. }
  317. _.RegisterDecorationForId(target_id, Decoration(dec_type, dec_params));
  318. break;
  319. }
  320. case SpvOpMemberDecorate: {
  321. const uint32_t struct_id = inst->word(1);
  322. const uint32_t index = inst->word(2);
  323. const SpvDecoration dec_type = static_cast<SpvDecoration>(inst->word(3));
  324. std::vector<uint32_t> dec_params;
  325. if (inst->words().size() > 4) {
  326. dec_params.insert(dec_params.end(), inst->words().begin() + 4,
  327. inst->words().end());
  328. }
  329. _.RegisterDecorationForId(struct_id,
  330. Decoration(dec_type, dec_params, index));
  331. break;
  332. }
  333. case SpvOpDecorationGroup: {
  334. // We don't need to do anything right now. Assigning decorations to groups
  335. // will be taken care of via OpGroupDecorate.
  336. break;
  337. }
  338. case SpvOpGroupDecorate: {
  339. // Word 1 is the group <id>. All subsequent words are target <id>s that
  340. // are going to be decorated with the decorations.
  341. const uint32_t decoration_group_id = inst->word(1);
  342. std::vector<Decoration>& group_decorations =
  343. _.id_decorations(decoration_group_id);
  344. for (size_t i = 2; i < inst->words().size(); ++i) {
  345. const uint32_t target_id = inst->word(i);
  346. _.RegisterDecorationsForId(target_id, group_decorations.begin(),
  347. group_decorations.end());
  348. }
  349. break;
  350. }
  351. case SpvOpGroupMemberDecorate: {
  352. // Word 1 is the Decoration Group <id> followed by (struct<id>,literal)
  353. // pairs. All decorations of the group should be applied to all the struct
  354. // members that are specified in the instructions.
  355. const uint32_t decoration_group_id = inst->word(1);
  356. std::vector<Decoration>& group_decorations =
  357. _.id_decorations(decoration_group_id);
  358. // Grammar checks ensures that the number of arguments to this instruction
  359. // is an odd number: 1 decoration group + (id,literal) pairs.
  360. for (size_t i = 2; i + 1 < inst->words().size(); i = i + 2) {
  361. const uint32_t struct_id = inst->word(i);
  362. const uint32_t index = inst->word(i + 1);
  363. // ID validation phase ensures this is in fact a struct instruction and
  364. // that the index is not out of bound.
  365. _.RegisterDecorationsForStructMember(struct_id, index,
  366. group_decorations.begin(),
  367. group_decorations.end());
  368. }
  369. break;
  370. }
  371. default:
  372. break;
  373. }
  374. return SPV_SUCCESS;
  375. }
  376. } // namespace
  377. spv_result_t AnnotationPass(ValidationState_t& _, const Instruction* inst) {
  378. switch (inst->opcode()) {
  379. case SpvOpDecorate:
  380. if (auto error = ValidateDecorate(_, inst)) return error;
  381. break;
  382. case SpvOpDecorateId:
  383. if (auto error = ValidateDecorateId(_, inst)) return error;
  384. break;
  385. // TODO(dneto): SpvOpDecorateStringGOOGLE
  386. // See https://github.com/KhronosGroup/SPIRV-Tools/issues/2253
  387. case SpvOpMemberDecorate:
  388. if (auto error = ValidateMemberDecorate(_, inst)) return error;
  389. break;
  390. case SpvOpDecorationGroup:
  391. if (auto error = ValidateDecorationGroup(_, inst)) return error;
  392. break;
  393. case SpvOpGroupDecorate:
  394. if (auto error = ValidateGroupDecorate(_, inst)) return error;
  395. break;
  396. case SpvOpGroupMemberDecorate:
  397. if (auto error = ValidateGroupMemberDecorate(_, inst)) return error;
  398. break;
  399. default:
  400. break;
  401. }
  402. // In order to validate decoration rules, we need to know all the decorations
  403. // that are applied to any given <id>.
  404. RegisterDecorations(_, inst);
  405. return SPV_SUCCESS;
  406. }
  407. } // namespace val
  408. } // namespace spvtools