validate_layout.cpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  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. // Source code for logical layout validation as described in section 2.4
  15. #include "validate.h"
  16. #include <cassert>
  17. #include "diagnostic.h"
  18. #include "opcode.h"
  19. #include "operand.h"
  20. #include "spirv-tools/libspirv.h"
  21. #include "val/function.h"
  22. #include "val/validation_state.h"
  23. using libspirv::FunctionDecl;
  24. using libspirv::kLayoutFunctionDeclarations;
  25. using libspirv::kLayoutFunctionDefinitions;
  26. using libspirv::kLayoutMemoryModel;
  27. using libspirv::ValidationState_t;
  28. namespace {
  29. // Module scoped instructions are processed by determining if the opcode
  30. // is part of the current layout section. If it is not then the next sections is
  31. // checked.
  32. spv_result_t ModuleScopedInstructions(ValidationState_t& _,
  33. const spv_parsed_instruction_t* inst,
  34. SpvOp opcode) {
  35. while (_.IsOpcodeInCurrentLayoutSection(opcode) == false) {
  36. _.ProgressToNextLayoutSectionOrder();
  37. switch (_.current_layout_section()) {
  38. case kLayoutMemoryModel:
  39. if (opcode != SpvOpMemoryModel) {
  40. return _.diag(SPV_ERROR_INVALID_LAYOUT)
  41. << spvOpcodeString(opcode)
  42. << " cannot appear before the memory model instruction";
  43. }
  44. break;
  45. case kLayoutFunctionDeclarations:
  46. // All module sections have been processed. Recursively call
  47. // ModuleLayoutPass to process the next section of the module
  48. return libspirv::ModuleLayoutPass(_, inst);
  49. default:
  50. break;
  51. }
  52. }
  53. return SPV_SUCCESS;
  54. }
  55. // Function declaration validation is performed by making sure that the
  56. // FunctionParameter and FunctionEnd instructions only appear inside of
  57. // functions. It also ensures that the Function instruction does not appear
  58. // inside of another function. This stage ends when the first label is
  59. // encountered inside of a function.
  60. spv_result_t FunctionScopedInstructions(ValidationState_t& _,
  61. const spv_parsed_instruction_t* inst,
  62. SpvOp opcode) {
  63. if (_.IsOpcodeInCurrentLayoutSection(opcode)) {
  64. switch (opcode) {
  65. case SpvOpFunction: {
  66. if (_.in_function_body()) {
  67. return _.diag(SPV_ERROR_INVALID_LAYOUT)
  68. << "Cannot declare a function in a function body";
  69. }
  70. auto control_mask = static_cast<SpvFunctionControlMask>(
  71. inst->words[inst->operands[2].offset]);
  72. if (auto error =
  73. _.RegisterFunction(inst->result_id, inst->type_id, control_mask,
  74. inst->words[inst->operands[3].offset]))
  75. return error;
  76. if (_.current_layout_section() == kLayoutFunctionDefinitions) {
  77. if (auto error = _.current_function().RegisterSetFunctionDeclType(
  78. FunctionDecl::kFunctionDeclDefinition))
  79. return error;
  80. }
  81. } break;
  82. case SpvOpFunctionParameter:
  83. if (_.in_function_body() == false) {
  84. return _.diag(SPV_ERROR_INVALID_LAYOUT) << "Function parameter "
  85. "instructions must be in "
  86. "a function body";
  87. }
  88. if (_.current_function().block_count() != 0) {
  89. return _.diag(SPV_ERROR_INVALID_LAYOUT)
  90. << "Function parameters must only appear immediately after "
  91. "the function definition";
  92. }
  93. if (auto error = _.current_function().RegisterFunctionParameter(
  94. inst->result_id, inst->type_id))
  95. return error;
  96. break;
  97. case SpvOpFunctionEnd:
  98. if (_.in_function_body() == false) {
  99. return _.diag(SPV_ERROR_INVALID_LAYOUT)
  100. << "Function end instructions must be in a function body";
  101. }
  102. if (_.in_block()) {
  103. return _.diag(SPV_ERROR_INVALID_LAYOUT)
  104. << "Function end cannot be called in blocks";
  105. }
  106. if (_.current_function().block_count() == 0 &&
  107. _.current_layout_section() == kLayoutFunctionDefinitions) {
  108. return _.diag(SPV_ERROR_INVALID_LAYOUT) << "Function declarations "
  109. "must appear before "
  110. "function definitions.";
  111. }
  112. if (_.current_layout_section() == kLayoutFunctionDeclarations) {
  113. if (auto error = _.current_function().RegisterSetFunctionDeclType(
  114. FunctionDecl::kFunctionDeclDeclaration))
  115. return error;
  116. }
  117. if (auto error = _.RegisterFunctionEnd()) return error;
  118. break;
  119. case SpvOpLine:
  120. case SpvOpNoLine:
  121. break;
  122. case SpvOpLabel:
  123. // If the label is encountered then the current function is a
  124. // definition so set the function to a declaration and update the
  125. // module section
  126. if (_.in_function_body() == false) {
  127. return _.diag(SPV_ERROR_INVALID_LAYOUT)
  128. << "Label instructions must be in a function body";
  129. }
  130. if (_.in_block()) {
  131. return _.diag(SPV_ERROR_INVALID_LAYOUT)
  132. << "A block must end with a branch instruction.";
  133. }
  134. if (_.current_layout_section() == kLayoutFunctionDeclarations) {
  135. _.ProgressToNextLayoutSectionOrder();
  136. if (auto error = _.current_function().RegisterSetFunctionDeclType(
  137. FunctionDecl::kFunctionDeclDefinition))
  138. return error;
  139. }
  140. break;
  141. default:
  142. if (_.current_layout_section() == kLayoutFunctionDeclarations &&
  143. _.in_function_body()) {
  144. return _.diag(SPV_ERROR_INVALID_LAYOUT)
  145. << "A function must begin with a label";
  146. } else {
  147. if (_.in_block() == false) {
  148. return _.diag(SPV_ERROR_INVALID_LAYOUT)
  149. << spvOpcodeString(opcode) << " must appear in a block";
  150. }
  151. }
  152. break;
  153. }
  154. } else {
  155. return _.diag(SPV_ERROR_INVALID_LAYOUT)
  156. << spvOpcodeString(opcode)
  157. << " cannot appear in a function declaration";
  158. }
  159. return SPV_SUCCESS;
  160. }
  161. } // namespace
  162. namespace libspirv {
  163. // TODO(umar): Check linkage capabilities for function declarations
  164. // TODO(umar): Better error messages
  165. // NOTE: This function does not handle CFG related validation
  166. // Performs logical layout validation. See Section 2.4
  167. spv_result_t ModuleLayoutPass(ValidationState_t& _,
  168. const spv_parsed_instruction_t* inst) {
  169. const SpvOp opcode = static_cast<SpvOp>(inst->opcode);
  170. switch (_.current_layout_section()) {
  171. case kLayoutCapabilities:
  172. case kLayoutExtensions:
  173. case kLayoutExtInstImport:
  174. case kLayoutMemoryModel:
  175. case kLayoutEntryPoint:
  176. case kLayoutExecutionMode:
  177. case kLayoutDebug1:
  178. case kLayoutDebug2:
  179. case kLayoutDebug3:
  180. case kLayoutAnnotations:
  181. case kLayoutTypes:
  182. if (auto error = ModuleScopedInstructions(_, inst, opcode)) return error;
  183. break;
  184. case kLayoutFunctionDeclarations:
  185. case kLayoutFunctionDefinitions:
  186. if (auto error = FunctionScopedInstructions(_, inst, opcode)) {
  187. return error;
  188. }
  189. break;
  190. }
  191. return SPV_SUCCESS;
  192. }
  193. } // namespace libspirv