validate_annotation.cpp 20 KB

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