validate_id.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. // Copyright (c) 2015-2016 The Khronos Group 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. #include <unordered_set>
  15. #include <vector>
  16. #include "source/instruction.h"
  17. #include "source/opcode.h"
  18. #include "source/operand.h"
  19. #include "source/val/function.h"
  20. #include "source/val/validate.h"
  21. #include "source/val/validation_state.h"
  22. #include "spirv-tools/libspirv.h"
  23. namespace spvtools {
  24. namespace val {
  25. spv_result_t UpdateIdUse(ValidationState_t& _, const Instruction* inst) {
  26. for (auto& operand : inst->operands()) {
  27. const spv_operand_type_t& type = operand.type;
  28. const uint32_t operand_id = inst->word(operand.offset);
  29. if (spvIsIdType(type) && type != SPV_OPERAND_TYPE_RESULT_ID) {
  30. if (auto def = _.FindDef(operand_id))
  31. def->RegisterUse(inst, operand.offset);
  32. }
  33. }
  34. return SPV_SUCCESS;
  35. }
  36. /// This function checks all ID definitions dominate their use in the CFG.
  37. ///
  38. /// This function will iterate over all ID definitions that are defined in the
  39. /// functions of a module and make sure that the definitions appear in a
  40. /// block that dominates their use.
  41. ///
  42. /// NOTE: This function does NOT check module scoped functions which are
  43. /// checked during the initial binary parse in the IdPass below
  44. spv_result_t CheckIdDefinitionDominateUse(ValidationState_t& _) {
  45. std::vector<const Instruction*> phi_instructions;
  46. std::unordered_set<uint32_t> phi_ids;
  47. for (const auto& inst : _.ordered_instructions()) {
  48. if (inst.id() == 0) continue;
  49. if (const Function* func = inst.function()) {
  50. if (const BasicBlock* block = inst.block()) {
  51. // If the Id is defined within a block then make sure all references to
  52. // that Id appear in a blocks that are dominated by the defining block
  53. for (auto& use_index_pair : inst.uses()) {
  54. const Instruction* use = use_index_pair.first;
  55. if (const BasicBlock* use_block = use->block()) {
  56. if (use_block->reachable() == false) continue;
  57. if (use->opcode() == spv::Op::OpPhi) {
  58. if (phi_ids.insert(use->id()).second) {
  59. phi_instructions.push_back(use);
  60. }
  61. } else if (!block->dominates(*use->block())) {
  62. return _.diag(SPV_ERROR_INVALID_ID, use_block->label())
  63. << "ID " << _.getIdName(inst.id()) << " defined in block "
  64. << _.getIdName(block->id())
  65. << " does not dominate its use in block "
  66. << _.getIdName(use_block->id());
  67. }
  68. }
  69. }
  70. } else {
  71. // If the Ids defined within a function but not in a block(i.e. function
  72. // parameters, block ids), then make sure all references to that Id
  73. // appear within the same function
  74. for (auto use : inst.uses()) {
  75. const Instruction* user = use.first;
  76. if (user->function() && user->function() != func) {
  77. return _.diag(SPV_ERROR_INVALID_ID, _.FindDef(func->id()))
  78. << "ID " << _.getIdName(inst.id()) << " used in function "
  79. << _.getIdName(user->function()->id())
  80. << " is used outside of it's defining function "
  81. << _.getIdName(func->id());
  82. }
  83. }
  84. }
  85. }
  86. // NOTE: Ids defined outside of functions must appear before they are used
  87. // This check is being performed in the IdPass function
  88. }
  89. // Check all OpPhi parent blocks are dominated by the variable's defining
  90. // blocks
  91. for (const Instruction* phi : phi_instructions) {
  92. if (phi->block()->reachable() == false) continue;
  93. for (size_t i = 3; i < phi->operands().size(); i += 2) {
  94. const Instruction* variable = _.FindDef(phi->word(i));
  95. const BasicBlock* parent =
  96. phi->function()->GetBlock(phi->word(i + 1)).first;
  97. if (variable->block() && parent->reachable() &&
  98. !variable->block()->dominates(*parent)) {
  99. return _.diag(SPV_ERROR_INVALID_ID, phi)
  100. << "In OpPhi instruction " << _.getIdName(phi->id()) << ", ID "
  101. << _.getIdName(variable->id())
  102. << " definition does not dominate its parent "
  103. << _.getIdName(parent->id());
  104. }
  105. }
  106. }
  107. return SPV_SUCCESS;
  108. }
  109. // Performs SSA validation on the IDs of an instruction. The
  110. // can_have_forward_declared_ids functor should return true if the
  111. // instruction operand's ID can be forward referenced.
  112. spv_result_t IdPass(ValidationState_t& _, Instruction* inst) {
  113. auto can_have_forward_declared_ids =
  114. spvIsExtendedInstruction(inst->opcode()) &&
  115. spvExtInstIsDebugInfo(inst->ext_inst_type())
  116. ? spvDbgInfoExtOperandCanBeForwardDeclaredFunction(
  117. inst->opcode(), inst->ext_inst_type(), inst->word(4))
  118. : spvOperandCanBeForwardDeclaredFunction(inst->opcode());
  119. // Keep track of a result id defined by this instruction. 0 means it
  120. // does not define an id.
  121. uint32_t result_id = 0;
  122. bool has_forward_declared_ids = false;
  123. for (unsigned i = 0; i < inst->operands().size(); i++) {
  124. const spv_parsed_operand_t& operand = inst->operand(i);
  125. const spv_operand_type_t& type = operand.type;
  126. // We only care about Id operands, which are a single word.
  127. const uint32_t operand_word = inst->word(operand.offset);
  128. auto ret = SPV_ERROR_INTERNAL;
  129. switch (type) {
  130. case SPV_OPERAND_TYPE_RESULT_ID:
  131. // NOTE: Multiple Id definitions are being checked by the binary parser.
  132. //
  133. // Defer undefined-forward-reference removal until after we've analyzed
  134. // the remaining operands to this instruction. Deferral only matters
  135. // for OpPhi since it's the only case where it defines its own forward
  136. // reference. Other instructions that can have forward references
  137. // either don't define a value or the forward reference is to a function
  138. // Id (and hence defined outside of a function body).
  139. result_id = operand_word;
  140. // NOTE: The result Id is added (in RegisterInstruction) *after* all of
  141. // the other Ids have been checked to avoid premature use in the same
  142. // instruction.
  143. ret = SPV_SUCCESS;
  144. break;
  145. case SPV_OPERAND_TYPE_ID:
  146. case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID:
  147. case SPV_OPERAND_TYPE_SCOPE_ID:
  148. if (const auto def = _.FindDef(operand_word)) {
  149. const auto opcode = inst->opcode();
  150. if (spvOpcodeGeneratesType(def->opcode()) &&
  151. !spvOpcodeGeneratesType(opcode) && !spvOpcodeIsDebug(opcode) &&
  152. !inst->IsDebugInfo() && !inst->IsNonSemantic() &&
  153. !spvOpcodeIsDecoration(opcode) && opcode != spv::Op::OpFunction &&
  154. opcode != spv::Op::OpSizeOf &&
  155. opcode != spv::Op::OpCooperativeMatrixLengthNV &&
  156. opcode != spv::Op::OpCooperativeMatrixLengthKHR &&
  157. !spvOpcodeGeneratesUntypedPointer(opcode) &&
  158. opcode != spv::Op::OpUntypedArrayLengthKHR &&
  159. !(opcode == spv::Op::OpSpecConstantOp &&
  160. (spv::Op(inst->word(3)) ==
  161. spv::Op::OpCooperativeMatrixLengthNV ||
  162. spv::Op(inst->word(3)) ==
  163. spv::Op::OpCooperativeMatrixLengthKHR))) {
  164. return _.diag(SPV_ERROR_INVALID_ID, inst)
  165. << "Operand " << _.getIdName(operand_word)
  166. << " cannot be a type";
  167. } else if (def->type_id() == 0 && !spvOpcodeGeneratesType(opcode) &&
  168. !spvOpcodeIsDebug(opcode) && !inst->IsDebugInfo() &&
  169. !inst->IsNonSemantic() && !spvOpcodeIsDecoration(opcode) &&
  170. !spvOpcodeIsBranch(opcode) && opcode != spv::Op::OpPhi &&
  171. opcode != spv::Op::OpExtInst &&
  172. opcode != spv::Op::OpExtInstWithForwardRefsKHR &&
  173. opcode != spv::Op::OpExtInstImport &&
  174. opcode != spv::Op::OpSelectionMerge &&
  175. opcode != spv::Op::OpLoopMerge &&
  176. opcode != spv::Op::OpFunction &&
  177. opcode != spv::Op::OpSizeOf &&
  178. opcode != spv::Op::OpCooperativeMatrixLengthNV &&
  179. opcode != spv::Op::OpCooperativeMatrixLengthKHR &&
  180. !spvOpcodeGeneratesUntypedPointer(opcode) &&
  181. opcode != spv::Op::OpUntypedArrayLengthKHR &&
  182. !(opcode == spv::Op::OpSpecConstantOp &&
  183. (spv::Op(inst->word(3)) ==
  184. spv::Op::OpCooperativeMatrixLengthNV ||
  185. spv::Op(inst->word(3)) ==
  186. spv::Op::OpCooperativeMatrixLengthKHR))) {
  187. return _.diag(SPV_ERROR_INVALID_ID, inst)
  188. << "Operand " << _.getIdName(operand_word)
  189. << " requires a type";
  190. } else if (def->IsNonSemantic() && !inst->IsNonSemantic()) {
  191. return _.diag(SPV_ERROR_INVALID_ID, inst)
  192. << "Operand " << _.getIdName(operand_word)
  193. << " in semantic instruction cannot be a non-semantic "
  194. "instruction";
  195. } else {
  196. ret = SPV_SUCCESS;
  197. }
  198. } else if (can_have_forward_declared_ids(i)) {
  199. has_forward_declared_ids = true;
  200. if (spvOpcodeGeneratesType(inst->opcode()) &&
  201. !_.IsForwardPointer(operand_word)) {
  202. ret = _.diag(SPV_ERROR_INVALID_ID, inst)
  203. << "Operand " << _.getIdName(operand_word)
  204. << " requires a previous definition";
  205. } else {
  206. ret = _.ForwardDeclareId(operand_word);
  207. }
  208. } else {
  209. ret = _.diag(SPV_ERROR_INVALID_ID, inst)
  210. << "ID " << _.getIdName(operand_word)
  211. << " has not been defined";
  212. }
  213. break;
  214. case SPV_OPERAND_TYPE_TYPE_ID:
  215. if (_.IsDefinedId(operand_word)) {
  216. auto* def = _.FindDef(operand_word);
  217. if (!spvOpcodeGeneratesType(def->opcode())) {
  218. ret = _.diag(SPV_ERROR_INVALID_ID, inst)
  219. << "ID " << _.getIdName(operand_word) << " is not a type id";
  220. } else {
  221. ret = SPV_SUCCESS;
  222. }
  223. } else {
  224. ret = _.diag(SPV_ERROR_INVALID_ID, inst)
  225. << "ID " << _.getIdName(operand_word)
  226. << " has not been defined";
  227. }
  228. break;
  229. case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER:
  230. // Ideally, this check would live in validate_extensions.cpp. But since
  231. // forward references are only allowed on non-semantic instructions, and
  232. // ID validation is done first, we would fail with a "ID had not been
  233. // defined" error before we could give a more helpful message. For this
  234. // reason, this test is done here, so we can be more helpful to the
  235. // user.
  236. if (inst->opcode() == spv::Op::OpExtInstWithForwardRefsKHR &&
  237. !inst->IsNonSemantic())
  238. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  239. << "OpExtInstWithForwardRefsKHR is only allowed with "
  240. "non-semantic instructions.";
  241. ret = SPV_SUCCESS;
  242. break;
  243. default:
  244. ret = SPV_SUCCESS;
  245. break;
  246. }
  247. if (SPV_SUCCESS != ret) return ret;
  248. }
  249. const bool must_have_forward_declared_ids =
  250. inst->opcode() == spv::Op::OpExtInstWithForwardRefsKHR;
  251. if (must_have_forward_declared_ids && !has_forward_declared_ids) {
  252. return _.diag(SPV_ERROR_INVALID_ID, inst)
  253. << "Opcode OpExtInstWithForwardRefsKHR must have at least one "
  254. "forward "
  255. "declared ID.";
  256. }
  257. if (result_id) _.RemoveIfForwardDeclared(result_id);
  258. return SPV_SUCCESS;
  259. }
  260. } // namespace val
  261. } // namespace spvtools