validate_annotation.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  1. // Copyright (c) 2018 Google LLC.
  2. // Modifications Copyright (C) 2024 Advanced Micro Devices, Inc. All rights
  3. // reserved.
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. #include "source/opcode.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. namespace {
  24. // Returns true if the decoration takes ID parameters.
  25. // TODO(dneto): This can be generated from the grammar.
  26. bool DecorationTakesIdParameters(spv::Decoration type) {
  27. switch (type) {
  28. case spv::Decoration::UniformId:
  29. case spv::Decoration::AlignmentId:
  30. case spv::Decoration::MaxByteOffsetId:
  31. case spv::Decoration::HlslCounterBufferGOOGLE:
  32. case spv::Decoration::NodeMaxPayloadsAMDX:
  33. case spv::Decoration::NodeSharesPayloadLimitsWithAMDX:
  34. case spv::Decoration::PayloadNodeArraySizeAMDX:
  35. case spv::Decoration::PayloadNodeNameAMDX:
  36. case spv::Decoration::PayloadNodeBaseIndexAMDX:
  37. return true;
  38. default:
  39. break;
  40. }
  41. return false;
  42. }
  43. bool IsMemberDecorationOnly(spv::Decoration dec) {
  44. switch (dec) {
  45. case spv::Decoration::RowMajor:
  46. case spv::Decoration::ColMajor:
  47. case spv::Decoration::MatrixStride:
  48. // SPIR-V spec bug? Offset is generated on variables when dealing with
  49. // transform feedback.
  50. // case spv::Decoration::Offset:
  51. return true;
  52. default:
  53. break;
  54. }
  55. return false;
  56. }
  57. bool IsNotMemberDecoration(spv::Decoration dec) {
  58. switch (dec) {
  59. case spv::Decoration::SpecId:
  60. case spv::Decoration::Block:
  61. case spv::Decoration::BufferBlock:
  62. case spv::Decoration::ArrayStride:
  63. case spv::Decoration::GLSLShared:
  64. case spv::Decoration::GLSLPacked:
  65. case spv::Decoration::CPacked:
  66. // TODO: https://github.com/KhronosGroup/glslang/issues/703:
  67. // glslang applies Restrict to structure members.
  68. // case spv::Decoration::Restrict:
  69. case spv::Decoration::Aliased:
  70. case spv::Decoration::Constant:
  71. case spv::Decoration::Uniform:
  72. case spv::Decoration::UniformId:
  73. case spv::Decoration::SaturatedConversion:
  74. case spv::Decoration::Index:
  75. case spv::Decoration::Binding:
  76. case spv::Decoration::DescriptorSet:
  77. case spv::Decoration::FuncParamAttr:
  78. case spv::Decoration::FPRoundingMode:
  79. case spv::Decoration::FPFastMathMode:
  80. case spv::Decoration::LinkageAttributes:
  81. case spv::Decoration::NoContraction:
  82. case spv::Decoration::InputAttachmentIndex:
  83. case spv::Decoration::Alignment:
  84. case spv::Decoration::MaxByteOffset:
  85. case spv::Decoration::AlignmentId:
  86. case spv::Decoration::MaxByteOffsetId:
  87. case spv::Decoration::NoSignedWrap:
  88. case spv::Decoration::NoUnsignedWrap:
  89. case spv::Decoration::NonUniform:
  90. case spv::Decoration::RestrictPointer:
  91. case spv::Decoration::AliasedPointer:
  92. case spv::Decoration::CounterBuffer:
  93. return true;
  94. default:
  95. break;
  96. }
  97. return false;
  98. }
  99. spv_result_t ValidateDecorationTarget(ValidationState_t& _, spv::Decoration dec,
  100. const Instruction* inst,
  101. const Instruction* target) {
  102. auto fail = [&_, dec, inst, target](uint32_t vuid) -> DiagnosticStream {
  103. DiagnosticStream ds = std::move(
  104. _.diag(SPV_ERROR_INVALID_ID, inst)
  105. << _.VkErrorID(vuid) << _.SpvDecorationString(dec)
  106. << " decoration on target <id> " << _.getIdName(target->id()) << " ");
  107. return ds;
  108. };
  109. switch (dec) {
  110. case spv::Decoration::SpecId:
  111. if (!spvOpcodeIsScalarSpecConstant(target->opcode())) {
  112. return fail(0) << "must be a scalar specialization constant";
  113. }
  114. break;
  115. case spv::Decoration::Block:
  116. case spv::Decoration::BufferBlock:
  117. case spv::Decoration::GLSLShared:
  118. case spv::Decoration::GLSLPacked:
  119. case spv::Decoration::CPacked:
  120. if (target->opcode() != spv::Op::OpTypeStruct) {
  121. return fail(0) << "must be a structure type";
  122. }
  123. break;
  124. case spv::Decoration::ArrayStride:
  125. if (target->opcode() != spv::Op::OpTypeArray &&
  126. target->opcode() != spv::Op::OpTypeRuntimeArray &&
  127. target->opcode() != spv::Op::OpTypePointer &&
  128. target->opcode() != spv::Op::OpTypeUntypedPointerKHR) {
  129. return fail(0) << "must be an array or pointer type";
  130. }
  131. break;
  132. case spv::Decoration::BuiltIn:
  133. if (target->opcode() != spv::Op::OpVariable &&
  134. target->opcode() != spv::Op::OpUntypedVariableKHR &&
  135. !spvOpcodeIsConstant(target->opcode())) {
  136. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  137. << "BuiltIns can only target variables, structure members or "
  138. "constants";
  139. }
  140. if (_.HasCapability(spv::Capability::Shader) &&
  141. inst->GetOperandAs<spv::BuiltIn>(2) == spv::BuiltIn::WorkgroupSize) {
  142. if (!spvOpcodeIsConstant(target->opcode())) {
  143. return fail(0) << "must be a constant for WorkgroupSize";
  144. }
  145. } else if (target->opcode() != spv::Op::OpVariable &&
  146. target->opcode() != spv::Op::OpUntypedVariableKHR) {
  147. return fail(0) << "must be a variable";
  148. }
  149. break;
  150. case spv::Decoration::NoPerspective:
  151. case spv::Decoration::Flat:
  152. case spv::Decoration::Patch:
  153. case spv::Decoration::Centroid:
  154. case spv::Decoration::Sample:
  155. case spv::Decoration::Restrict:
  156. case spv::Decoration::Aliased:
  157. case spv::Decoration::Volatile:
  158. case spv::Decoration::Coherent:
  159. case spv::Decoration::NonWritable:
  160. case spv::Decoration::NonReadable:
  161. case spv::Decoration::XfbBuffer:
  162. case spv::Decoration::XfbStride:
  163. case spv::Decoration::Component:
  164. case spv::Decoration::Stream:
  165. case spv::Decoration::RestrictPointer:
  166. case spv::Decoration::AliasedPointer:
  167. case spv::Decoration::PerPrimitiveEXT:
  168. if (target->opcode() != spv::Op::OpVariable &&
  169. target->opcode() != spv::Op::OpUntypedVariableKHR &&
  170. target->opcode() != spv::Op::OpFunctionParameter &&
  171. target->opcode() != spv::Op::OpRawAccessChainNV) {
  172. return fail(0) << "must be a memory object declaration";
  173. }
  174. if (!_.IsPointerType(target->type_id())) {
  175. return fail(0) << "must be a pointer type";
  176. }
  177. break;
  178. case spv::Decoration::Invariant:
  179. case spv::Decoration::Constant:
  180. case spv::Decoration::Location:
  181. case spv::Decoration::Index:
  182. case spv::Decoration::Binding:
  183. case spv::Decoration::DescriptorSet:
  184. case spv::Decoration::InputAttachmentIndex:
  185. if (target->opcode() != spv::Op::OpVariable &&
  186. target->opcode() != spv::Op::OpUntypedVariableKHR) {
  187. return fail(0) << "must be a variable";
  188. }
  189. break;
  190. default:
  191. break;
  192. }
  193. if (spvIsVulkanEnv(_.context()->target_env)) {
  194. // The following were all checked as pointer types above.
  195. spv::StorageClass sc = spv::StorageClass::Uniform;
  196. const auto type = _.FindDef(target->type_id());
  197. if (type && type->operands().size() > 2) {
  198. sc = type->GetOperandAs<spv::StorageClass>(1);
  199. }
  200. switch (dec) {
  201. case spv::Decoration::Location:
  202. case spv::Decoration::Component:
  203. // Location is used for input, output, tile image, and ray tracing
  204. // stages.
  205. if (sc != spv::StorageClass::Input && sc != spv::StorageClass::Output &&
  206. sc != spv::StorageClass::RayPayloadKHR &&
  207. sc != spv::StorageClass::IncomingRayPayloadKHR &&
  208. sc != spv::StorageClass::HitAttributeKHR &&
  209. sc != spv::StorageClass::CallableDataKHR &&
  210. sc != spv::StorageClass::IncomingCallableDataKHR &&
  211. sc != spv::StorageClass::ShaderRecordBufferKHR &&
  212. sc != spv::StorageClass::HitObjectAttributeNV &&
  213. sc != spv::StorageClass::TileImageEXT) {
  214. return _.diag(SPV_ERROR_INVALID_ID, target)
  215. << _.VkErrorID(6672) << _.SpvDecorationString(dec)
  216. << " decoration must not be applied to this storage class";
  217. }
  218. break;
  219. case spv::Decoration::Index:
  220. // Langauge from SPIR-V definition of Index
  221. if (sc != spv::StorageClass::Output) {
  222. return fail(0) << "must be in the Output storage class";
  223. }
  224. break;
  225. case spv::Decoration::Binding:
  226. case spv::Decoration::DescriptorSet:
  227. if (sc != spv::StorageClass::StorageBuffer &&
  228. sc != spv::StorageClass::Uniform &&
  229. sc != spv::StorageClass::UniformConstant) {
  230. return fail(6491) << "must be in the StorageBuffer, Uniform, or "
  231. "UniformConstant storage class";
  232. }
  233. break;
  234. case spv::Decoration::InputAttachmentIndex:
  235. if (sc != spv::StorageClass::UniformConstant) {
  236. return fail(6678) << "must be in the UniformConstant storage class";
  237. }
  238. break;
  239. case spv::Decoration::Flat:
  240. case spv::Decoration::NoPerspective:
  241. case spv::Decoration::Centroid:
  242. case spv::Decoration::Sample:
  243. if (sc != spv::StorageClass::Input && sc != spv::StorageClass::Output) {
  244. return fail(4670) << "storage class must be Input or Output";
  245. }
  246. break;
  247. case spv::Decoration::PerVertexKHR:
  248. if (sc != spv::StorageClass::Input) {
  249. return fail(6777) << "storage class must be Input";
  250. }
  251. break;
  252. default:
  253. break;
  254. }
  255. }
  256. return SPV_SUCCESS;
  257. }
  258. spv_result_t ValidateDecorate(ValidationState_t& _, const Instruction* inst) {
  259. const auto decoration = inst->GetOperandAs<spv::Decoration>(1);
  260. const auto target_id = inst->GetOperandAs<uint32_t>(0);
  261. const auto target = _.FindDef(target_id);
  262. if (!target) {
  263. return _.diag(SPV_ERROR_INVALID_ID, inst) << "target is not defined";
  264. }
  265. if (spvIsVulkanEnv(_.context()->target_env)) {
  266. if ((decoration == spv::Decoration::GLSLShared) ||
  267. (decoration == spv::Decoration::GLSLPacked)) {
  268. return _.diag(SPV_ERROR_INVALID_ID, inst)
  269. << _.VkErrorID(4669) << "OpDecorate decoration '"
  270. << _.SpvDecorationString(decoration)
  271. << "' is not valid for the Vulkan execution environment.";
  272. }
  273. }
  274. if (decoration == spv::Decoration::FPFastMathMode) {
  275. if (_.HasDecoration(target_id, spv::Decoration::NoContraction)) {
  276. return _.diag(SPV_ERROR_INVALID_ID, inst)
  277. << "FPFastMathMode and NoContraction cannot decorate the same "
  278. "target";
  279. }
  280. auto mask = inst->GetOperandAs<spv::FPFastMathModeMask>(2);
  281. if ((mask & spv::FPFastMathModeMask::AllowTransform) !=
  282. spv::FPFastMathModeMask::MaskNone &&
  283. ((mask & (spv::FPFastMathModeMask::AllowContract |
  284. spv::FPFastMathModeMask::AllowReassoc)) !=
  285. (spv::FPFastMathModeMask::AllowContract |
  286. spv::FPFastMathModeMask::AllowReassoc))) {
  287. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  288. << "AllowReassoc and AllowContract must be specified when "
  289. "AllowTransform is specified";
  290. }
  291. }
  292. // This is checked from both sides since we register decorations as we go.
  293. if (decoration == spv::Decoration::NoContraction) {
  294. if (_.HasDecoration(target_id, spv::Decoration::FPFastMathMode)) {
  295. return _.diag(SPV_ERROR_INVALID_ID, inst)
  296. << "FPFastMathMode and NoContraction cannot decorate the same "
  297. "target";
  298. }
  299. }
  300. if (DecorationTakesIdParameters(decoration)) {
  301. return _.diag(SPV_ERROR_INVALID_ID, inst)
  302. << "Decorations taking ID parameters may not be used with "
  303. "OpDecorateId";
  304. }
  305. if (target->opcode() != spv::Op::OpDecorationGroup) {
  306. if (IsMemberDecorationOnly(decoration)) {
  307. return _.diag(SPV_ERROR_INVALID_ID, inst)
  308. << _.SpvDecorationString(decoration)
  309. << " can only be applied to structure members";
  310. }
  311. if (auto error = ValidateDecorationTarget(_, decoration, inst, target)) {
  312. return error;
  313. }
  314. }
  315. // TODO: Add validations for all decorations.
  316. return SPV_SUCCESS;
  317. }
  318. spv_result_t ValidateDecorateId(ValidationState_t& _, const Instruction* inst) {
  319. const auto decoration = inst->GetOperandAs<spv::Decoration>(1);
  320. if (!DecorationTakesIdParameters(decoration)) {
  321. return _.diag(SPV_ERROR_INVALID_ID, inst)
  322. << "Decorations that don't take ID parameters may not be used with "
  323. "OpDecorateId";
  324. }
  325. // No member decorations take id parameters, so we don't bother checking if
  326. // we are using a member only decoration here.
  327. // TODO: Add validations for these decorations.
  328. // UniformId is covered elsewhere.
  329. return SPV_SUCCESS;
  330. }
  331. spv_result_t ValidateMemberDecorate(ValidationState_t& _,
  332. const Instruction* inst) {
  333. const auto struct_type_id = inst->GetOperandAs<uint32_t>(0);
  334. const auto struct_type = _.FindDef(struct_type_id);
  335. if (!struct_type || spv::Op::OpTypeStruct != struct_type->opcode()) {
  336. return _.diag(SPV_ERROR_INVALID_ID, inst)
  337. << "OpMemberDecorate Structure type <id> "
  338. << _.getIdName(struct_type_id) << " is not a struct type.";
  339. }
  340. const auto member = inst->GetOperandAs<uint32_t>(1);
  341. const auto member_count =
  342. static_cast<uint32_t>(struct_type->words().size() - 2);
  343. if (member_count <= member) {
  344. return _.diag(SPV_ERROR_INVALID_ID, inst)
  345. << "Index " << member
  346. << " provided in OpMemberDecorate for struct <id> "
  347. << _.getIdName(struct_type_id)
  348. << " is out of bounds. The structure has " << member_count
  349. << " members. Largest valid index is " << member_count - 1 << ".";
  350. }
  351. const auto decoration = inst->GetOperandAs<spv::Decoration>(2);
  352. if (IsNotMemberDecoration(decoration)) {
  353. return _.diag(SPV_ERROR_INVALID_ID, inst)
  354. << _.SpvDecorationString(decoration)
  355. << " cannot be applied to structure members";
  356. }
  357. return SPV_SUCCESS;
  358. }
  359. spv_result_t ValidateDecorationGroup(ValidationState_t& _,
  360. const Instruction* inst) {
  361. const auto decoration_group_id = inst->GetOperandAs<uint32_t>(0);
  362. const auto decoration_group = _.FindDef(decoration_group_id);
  363. for (auto pair : decoration_group->uses()) {
  364. auto use = pair.first;
  365. if (use->opcode() != spv::Op::OpDecorate &&
  366. use->opcode() != spv::Op::OpGroupDecorate &&
  367. use->opcode() != spv::Op::OpGroupMemberDecorate &&
  368. use->opcode() != spv::Op::OpName &&
  369. use->opcode() != spv::Op::OpDecorateId && !use->IsNonSemantic()) {
  370. return _.diag(SPV_ERROR_INVALID_ID, inst)
  371. << "Result id of OpDecorationGroup can only "
  372. << "be targeted by OpName, OpGroupDecorate, "
  373. << "OpDecorate, OpDecorateId, and OpGroupMemberDecorate";
  374. }
  375. }
  376. return SPV_SUCCESS;
  377. }
  378. spv_result_t ValidateGroupDecorate(ValidationState_t& _,
  379. const Instruction* inst) {
  380. const auto decoration_group_id = inst->GetOperandAs<uint32_t>(0);
  381. auto decoration_group = _.FindDef(decoration_group_id);
  382. if (!decoration_group ||
  383. spv::Op::OpDecorationGroup != decoration_group->opcode()) {
  384. return _.diag(SPV_ERROR_INVALID_ID, inst)
  385. << "OpGroupDecorate Decoration group <id> "
  386. << _.getIdName(decoration_group_id) << " is not a decoration group.";
  387. }
  388. for (unsigned i = 1; i < inst->operands().size(); ++i) {
  389. auto target_id = inst->GetOperandAs<uint32_t>(i);
  390. auto target = _.FindDef(target_id);
  391. if (!target || target->opcode() == spv::Op::OpDecorationGroup) {
  392. return _.diag(SPV_ERROR_INVALID_ID, inst)
  393. << "OpGroupDecorate may not target OpDecorationGroup <id> "
  394. << _.getIdName(target_id);
  395. }
  396. }
  397. return SPV_SUCCESS;
  398. }
  399. spv_result_t ValidateGroupMemberDecorate(ValidationState_t& _,
  400. const Instruction* inst) {
  401. const auto decoration_group_id = inst->GetOperandAs<uint32_t>(0);
  402. const auto decoration_group = _.FindDef(decoration_group_id);
  403. if (!decoration_group ||
  404. spv::Op::OpDecorationGroup != decoration_group->opcode()) {
  405. return _.diag(SPV_ERROR_INVALID_ID, inst)
  406. << "OpGroupMemberDecorate Decoration group <id> "
  407. << _.getIdName(decoration_group_id) << " is not a decoration group.";
  408. }
  409. // Grammar checks ensures that the number of arguments to this instruction
  410. // is an odd number: 1 decoration group + (id,literal) pairs.
  411. for (size_t i = 1; i + 1 < inst->operands().size(); i += 2) {
  412. const uint32_t struct_id = inst->GetOperandAs<uint32_t>(i);
  413. const uint32_t index = inst->GetOperandAs<uint32_t>(i + 1);
  414. auto struct_instr = _.FindDef(struct_id);
  415. if (!struct_instr || spv::Op::OpTypeStruct != struct_instr->opcode()) {
  416. return _.diag(SPV_ERROR_INVALID_ID, inst)
  417. << "OpGroupMemberDecorate Structure type <id> "
  418. << _.getIdName(struct_id) << " is not a struct type.";
  419. }
  420. const uint32_t num_struct_members =
  421. static_cast<uint32_t>(struct_instr->words().size() - 2);
  422. if (index >= num_struct_members) {
  423. return _.diag(SPV_ERROR_INVALID_ID, inst)
  424. << "Index " << index
  425. << " provided in OpGroupMemberDecorate for struct <id> "
  426. << _.getIdName(struct_id)
  427. << " is out of bounds. The structure has " << num_struct_members
  428. << " members. Largest valid index is " << num_struct_members - 1
  429. << ".";
  430. }
  431. }
  432. return SPV_SUCCESS;
  433. }
  434. // Registers necessary decoration(s) for the appropriate IDs based on the
  435. // instruction.
  436. spv_result_t RegisterDecorations(ValidationState_t& _,
  437. const Instruction* inst) {
  438. switch (inst->opcode()) {
  439. case spv::Op::OpDecorate:
  440. case spv::Op::OpDecorateId: {
  441. const uint32_t target_id = inst->word(1);
  442. const spv::Decoration dec_type =
  443. static_cast<spv::Decoration>(inst->word(2));
  444. std::vector<uint32_t> dec_params;
  445. if (inst->words().size() > 3) {
  446. dec_params.insert(dec_params.end(), inst->words().begin() + 3,
  447. inst->words().end());
  448. }
  449. _.RegisterDecorationForId(target_id, Decoration(dec_type, dec_params));
  450. break;
  451. }
  452. case spv::Op::OpMemberDecorate: {
  453. const uint32_t struct_id = inst->word(1);
  454. const uint32_t index = inst->word(2);
  455. const spv::Decoration dec_type =
  456. static_cast<spv::Decoration>(inst->word(3));
  457. std::vector<uint32_t> dec_params;
  458. if (inst->words().size() > 4) {
  459. dec_params.insert(dec_params.end(), inst->words().begin() + 4,
  460. inst->words().end());
  461. }
  462. _.RegisterDecorationForId(struct_id,
  463. Decoration(dec_type, dec_params, index));
  464. break;
  465. }
  466. case spv::Op::OpDecorationGroup: {
  467. // We don't need to do anything right now. Assigning decorations to groups
  468. // will be taken care of via OpGroupDecorate.
  469. break;
  470. }
  471. case spv::Op::OpGroupDecorate: {
  472. // Word 1 is the group <id>. All subsequent words are target <id>s that
  473. // are going to be decorated with the decorations.
  474. const uint32_t decoration_group_id = inst->word(1);
  475. std::set<Decoration>& group_decorations =
  476. _.id_decorations(decoration_group_id);
  477. for (size_t i = 2; i < inst->words().size(); ++i) {
  478. const uint32_t target_id = inst->word(i);
  479. _.RegisterDecorationsForId(target_id, group_decorations.begin(),
  480. group_decorations.end());
  481. }
  482. break;
  483. }
  484. case spv::Op::OpGroupMemberDecorate: {
  485. // Word 1 is the Decoration Group <id> followed by (struct<id>,literal)
  486. // pairs. All decorations of the group should be applied to all the struct
  487. // members that are specified in the instructions.
  488. const uint32_t decoration_group_id = inst->word(1);
  489. std::set<Decoration>& group_decorations =
  490. _.id_decorations(decoration_group_id);
  491. // Grammar checks ensures that the number of arguments to this instruction
  492. // is an odd number: 1 decoration group + (id,literal) pairs.
  493. for (size_t i = 2; i + 1 < inst->words().size(); i = i + 2) {
  494. const uint32_t struct_id = inst->word(i);
  495. const uint32_t index = inst->word(i + 1);
  496. // ID validation phase ensures this is in fact a struct instruction and
  497. // that the index is not out of bound.
  498. _.RegisterDecorationsForStructMember(struct_id, index,
  499. group_decorations.begin(),
  500. group_decorations.end());
  501. }
  502. break;
  503. }
  504. default:
  505. break;
  506. }
  507. return SPV_SUCCESS;
  508. }
  509. } // namespace
  510. spv_result_t AnnotationPass(ValidationState_t& _, const Instruction* inst) {
  511. switch (inst->opcode()) {
  512. case spv::Op::OpDecorate:
  513. if (auto error = ValidateDecorate(_, inst)) return error;
  514. break;
  515. case spv::Op::OpDecorateId:
  516. if (auto error = ValidateDecorateId(_, inst)) return error;
  517. break;
  518. // TODO(dneto): spv::Op::OpDecorateStringGOOGLE
  519. // See https://github.com/KhronosGroup/SPIRV-Tools/issues/2253
  520. case spv::Op::OpMemberDecorate:
  521. if (auto error = ValidateMemberDecorate(_, inst)) return error;
  522. break;
  523. case spv::Op::OpDecorationGroup:
  524. if (auto error = ValidateDecorationGroup(_, inst)) return error;
  525. break;
  526. case spv::Op::OpGroupDecorate:
  527. if (auto error = ValidateGroupDecorate(_, inst)) return error;
  528. break;
  529. case spv::Op::OpGroupMemberDecorate:
  530. if (auto error = ValidateGroupMemberDecorate(_, inst)) return error;
  531. break;
  532. default:
  533. break;
  534. }
  535. // In order to validate decoration rules, we need to know all the decorations
  536. // that are applied to any given <id>.
  537. RegisterDecorations(_, inst);
  538. return SPV_SUCCESS;
  539. }
  540. } // namespace val
  541. } // namespace spvtools