validate_layout.cpp 16 KB

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