validate_layout.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  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 <cassert>
  16. #include "DebugInfo.h"
  17. #include "OpenCLDebugInfo100.h"
  18. #include "source/diagnostic.h"
  19. #include "source/opcode.h"
  20. #include "source/operand.h"
  21. #include "source/val/function.h"
  22. #include "source/val/instruction.h"
  23. #include "source/val/validate.h"
  24. #include "source/val/validation_state.h"
  25. namespace spvtools {
  26. namespace val {
  27. namespace {
  28. // Module scoped instructions are processed by determining if the opcode
  29. // is part of the current layout section. If it is not then the next sections is
  30. // checked.
  31. spv_result_t ModuleScopedInstructions(ValidationState_t& _,
  32. const Instruction* inst, SpvOp opcode) {
  33. switch (opcode) {
  34. case SpvOpExtInst:
  35. if (spvExtInstIsNonSemantic(inst->ext_inst_type())) {
  36. // non-semantic extinst opcodes are allowed beginning in the types
  37. // section, but since they must name a return type they cannot be the
  38. // first instruction in the types section. Therefore check that we are
  39. // already in it.
  40. if (_.current_layout_section() < kLayoutTypes) {
  41. return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
  42. << "Non-semantic OpExtInst must not appear before types "
  43. << "section";
  44. }
  45. } else if (spvExtInstIsDebugInfo(inst->ext_inst_type())) {
  46. const uint32_t ext_inst_index = inst->word(4);
  47. bool local_debug_info = false;
  48. if (inst->ext_inst_type() == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100) {
  49. const OpenCLDebugInfo100Instructions ext_inst_key =
  50. OpenCLDebugInfo100Instructions(ext_inst_index);
  51. if (ext_inst_key == OpenCLDebugInfo100DebugScope ||
  52. ext_inst_key == OpenCLDebugInfo100DebugNoScope ||
  53. ext_inst_key == OpenCLDebugInfo100DebugDeclare ||
  54. ext_inst_key == OpenCLDebugInfo100DebugValue) {
  55. local_debug_info = true;
  56. }
  57. } else {
  58. const DebugInfoInstructions ext_inst_key =
  59. DebugInfoInstructions(ext_inst_index);
  60. if (ext_inst_key == DebugInfoDebugScope ||
  61. ext_inst_key == DebugInfoDebugNoScope ||
  62. ext_inst_key == DebugInfoDebugDeclare ||
  63. ext_inst_key == DebugInfoDebugValue) {
  64. local_debug_info = true;
  65. }
  66. }
  67. if (local_debug_info) {
  68. if (_.in_function_body() == false) {
  69. // DebugScope, DebugNoScope, DebugDeclare, DebugValue must
  70. // appear in a function body.
  71. return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
  72. << "DebugScope, DebugNoScope, DebugDeclare, DebugValue "
  73. << "of debug info extension must appear in a function "
  74. << "body";
  75. }
  76. } else {
  77. // Debug info extinst opcodes other than DebugScope, DebugNoScope,
  78. // DebugDeclare, DebugValue must be placed between section 9 (types,
  79. // constants, global variables) and section 10 (function
  80. // declarations).
  81. if (_.current_layout_section() < kLayoutTypes ||
  82. _.current_layout_section() >= kLayoutFunctionDeclarations) {
  83. return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
  84. << "Debug info extension instructions other than "
  85. << "DebugScope, DebugNoScope, DebugDeclare, DebugValue "
  86. << "must appear between section 9 (types, constants, "
  87. << "global variables) and section 10 (function "
  88. << "declarations)";
  89. }
  90. }
  91. } else {
  92. // otherwise they must be used in a block
  93. if (_.current_layout_section() < kLayoutFunctionDefinitions) {
  94. return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
  95. << spvOpcodeString(opcode) << " must appear in a block";
  96. }
  97. }
  98. break;
  99. default:
  100. break;
  101. }
  102. while (_.IsOpcodeInCurrentLayoutSection(opcode) == false) {
  103. _.ProgressToNextLayoutSectionOrder();
  104. switch (_.current_layout_section()) {
  105. case kLayoutMemoryModel:
  106. if (opcode != SpvOpMemoryModel) {
  107. return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
  108. << spvOpcodeString(opcode)
  109. << " cannot appear before the memory model instruction";
  110. }
  111. break;
  112. case kLayoutFunctionDeclarations:
  113. // All module sections have been processed. Recursively call
  114. // ModuleLayoutPass to process the next section of the module
  115. return ModuleLayoutPass(_, inst);
  116. default:
  117. break;
  118. }
  119. }
  120. return SPV_SUCCESS;
  121. }
  122. // Function declaration validation is performed by making sure that the
  123. // FunctionParameter and FunctionEnd instructions only appear inside of
  124. // functions. It also ensures that the Function instruction does not appear
  125. // inside of another function. This stage ends when the first label is
  126. // encountered inside of a function.
  127. spv_result_t FunctionScopedInstructions(ValidationState_t& _,
  128. const Instruction* inst, SpvOp opcode) {
  129. if (_.IsOpcodeInCurrentLayoutSection(opcode)) {
  130. switch (opcode) {
  131. case SpvOpFunction: {
  132. if (_.in_function_body()) {
  133. return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
  134. << "Cannot declare a function in a function body";
  135. }
  136. auto control_mask = inst->GetOperandAs<SpvFunctionControlMask>(2);
  137. if (auto error =
  138. _.RegisterFunction(inst->id(), inst->type_id(), control_mask,
  139. inst->GetOperandAs<uint32_t>(3)))
  140. return error;
  141. if (_.current_layout_section() == kLayoutFunctionDefinitions) {
  142. if (auto error = _.current_function().RegisterSetFunctionDeclType(
  143. FunctionDecl::kFunctionDeclDefinition))
  144. return error;
  145. }
  146. } break;
  147. case SpvOpFunctionParameter:
  148. if (_.in_function_body() == false) {
  149. return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
  150. << "Function parameter instructions must be in a "
  151. "function body";
  152. }
  153. if (_.current_function().block_count() != 0) {
  154. return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
  155. << "Function parameters must only appear immediately after "
  156. "the function definition";
  157. }
  158. if (auto error = _.current_function().RegisterFunctionParameter(
  159. inst->id(), inst->type_id()))
  160. return error;
  161. break;
  162. case SpvOpFunctionEnd:
  163. if (_.in_function_body() == false) {
  164. return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
  165. << "Function end instructions must be in a function body";
  166. }
  167. if (_.in_block()) {
  168. return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
  169. << "Function end cannot be called in blocks";
  170. }
  171. if (_.current_function().block_count() == 0 &&
  172. _.current_layout_section() == kLayoutFunctionDefinitions) {
  173. return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
  174. << "Function declarations must appear before "
  175. "function definitions.";
  176. }
  177. if (_.current_layout_section() == kLayoutFunctionDeclarations) {
  178. if (auto error = _.current_function().RegisterSetFunctionDeclType(
  179. FunctionDecl::kFunctionDeclDeclaration))
  180. return error;
  181. }
  182. if (auto error = _.RegisterFunctionEnd()) return error;
  183. break;
  184. case SpvOpLine:
  185. case SpvOpNoLine:
  186. break;
  187. case SpvOpLabel:
  188. // If the label is encountered then the current function is a
  189. // definition so set the function to a declaration and update the
  190. // module section
  191. if (_.in_function_body() == false) {
  192. return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
  193. << "Label instructions must be in a function body";
  194. }
  195. if (_.in_block()) {
  196. return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
  197. << "A block must end with a branch instruction.";
  198. }
  199. if (_.current_layout_section() == kLayoutFunctionDeclarations) {
  200. _.ProgressToNextLayoutSectionOrder();
  201. if (auto error = _.current_function().RegisterSetFunctionDeclType(
  202. FunctionDecl::kFunctionDeclDefinition))
  203. return error;
  204. }
  205. break;
  206. case SpvOpExtInst:
  207. if (spvExtInstIsNonSemantic(inst->ext_inst_type())) {
  208. // non-semantic extinst opcodes are allowed beginning in the types
  209. // section, but must either be placed outside a function declaration,
  210. // or inside a block.
  211. if (_.current_layout_section() < kLayoutTypes) {
  212. return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
  213. << "Non-semantic OpExtInst must not appear before types "
  214. << "section";
  215. } else if (_.in_function_body() && _.in_block() == false) {
  216. return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
  217. << "Non-semantic OpExtInst within function definition must "
  218. "appear in a block";
  219. }
  220. } else if (spvExtInstIsDebugInfo(inst->ext_inst_type())) {
  221. const uint32_t ext_inst_index = inst->word(4);
  222. bool local_debug_info = false;
  223. if (inst->ext_inst_type() == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100) {
  224. const OpenCLDebugInfo100Instructions ext_inst_key =
  225. OpenCLDebugInfo100Instructions(ext_inst_index);
  226. if (ext_inst_key == OpenCLDebugInfo100DebugScope ||
  227. ext_inst_key == OpenCLDebugInfo100DebugNoScope ||
  228. ext_inst_key == OpenCLDebugInfo100DebugDeclare ||
  229. ext_inst_key == OpenCLDebugInfo100DebugValue) {
  230. local_debug_info = true;
  231. }
  232. } else {
  233. const DebugInfoInstructions ext_inst_key =
  234. DebugInfoInstructions(ext_inst_index);
  235. if (ext_inst_key == DebugInfoDebugScope ||
  236. ext_inst_key == DebugInfoDebugNoScope ||
  237. ext_inst_key == DebugInfoDebugDeclare ||
  238. ext_inst_key == DebugInfoDebugValue) {
  239. local_debug_info = true;
  240. }
  241. }
  242. if (local_debug_info) {
  243. if (_.in_function_body() == false) {
  244. // DebugScope, DebugNoScope, DebugDeclare, DebugValue must
  245. // appear in a function body.
  246. return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
  247. << "DebugScope, DebugNoScope, DebugDeclare, DebugValue "
  248. << "of debug info extension must appear in a function "
  249. << "body";
  250. }
  251. } else {
  252. // Debug info extinst opcodes other than DebugScope, DebugNoScope,
  253. // DebugDeclare, DebugValue must be placed between section 9 (types,
  254. // constants, global variables) and section 10 (function
  255. // declarations).
  256. if (_.current_layout_section() < kLayoutTypes ||
  257. _.current_layout_section() >= kLayoutFunctionDeclarations) {
  258. return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
  259. << "Debug info extension instructions other than "
  260. << "DebugScope, DebugNoScope, DebugDeclare, DebugValue "
  261. << "must appear between section 9 (types, constants, "
  262. << "global variables) and section 10 (function "
  263. << "declarations)";
  264. }
  265. }
  266. } else {
  267. // otherwise they must be used in a block
  268. if (_.in_block() == false) {
  269. return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
  270. << spvOpcodeString(opcode) << " must appear in a block";
  271. }
  272. }
  273. break;
  274. default:
  275. if (_.current_layout_section() == kLayoutFunctionDeclarations &&
  276. _.in_function_body()) {
  277. return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
  278. << "A function must begin with a label";
  279. } else {
  280. if (_.in_block() == false) {
  281. return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
  282. << spvOpcodeString(opcode) << " must appear in a block";
  283. }
  284. }
  285. break;
  286. }
  287. } else {
  288. return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
  289. << spvOpcodeString(opcode)
  290. << " cannot appear in a function declaration";
  291. }
  292. return SPV_SUCCESS;
  293. }
  294. } // namespace
  295. // TODO(umar): Check linkage capabilities for function declarations
  296. // TODO(umar): Better error messages
  297. // NOTE: This function does not handle CFG related validation
  298. // Performs logical layout validation. See Section 2.4
  299. spv_result_t ModuleLayoutPass(ValidationState_t& _, const Instruction* inst) {
  300. const SpvOp opcode = inst->opcode();
  301. switch (_.current_layout_section()) {
  302. case kLayoutCapabilities:
  303. case kLayoutExtensions:
  304. case kLayoutExtInstImport:
  305. case kLayoutMemoryModel:
  306. case kLayoutEntryPoint:
  307. case kLayoutExecutionMode:
  308. case kLayoutDebug1:
  309. case kLayoutDebug2:
  310. case kLayoutDebug3:
  311. case kLayoutAnnotations:
  312. case kLayoutTypes:
  313. if (auto error = ModuleScopedInstructions(_, inst, opcode)) return error;
  314. break;
  315. case kLayoutFunctionDeclarations:
  316. case kLayoutFunctionDefinitions:
  317. if (auto error = FunctionScopedInstructions(_, inst, opcode)) {
  318. return error;
  319. }
  320. break;
  321. }
  322. return SPV_SUCCESS;
  323. }
  324. } // namespace val
  325. } // namespace spvtools