| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387 |
- // Copyright (c) 2015-2016 The Khronos Group Inc.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- // Source code for logical layout validation as described in section 2.4
- #include "DebugInfo.h"
- #include "NonSemanticShaderDebugInfo100.h"
- #include "OpenCLDebugInfo100.h"
- #include "source/opcode.h"
- #include "source/operand.h"
- #include "source/val/function.h"
- #include "source/val/instruction.h"
- #include "source/val/validate.h"
- #include "source/val/validation_state.h"
- namespace spvtools {
- namespace val {
- namespace {
- // Module scoped instructions are processed by determining if the opcode
- // is part of the current layout section. If it is not then the next sections is
- // checked.
- spv_result_t ModuleScopedInstructions(ValidationState_t& _,
- const Instruction* inst, spv::Op opcode) {
- switch (opcode) {
- case spv::Op::OpExtInst:
- case spv::Op::OpExtInstWithForwardRefsKHR:
- if (spvExtInstIsDebugInfo(inst->ext_inst_type())) {
- const uint32_t ext_inst_index = inst->word(4);
- bool local_debug_info = false;
- if (inst->ext_inst_type() == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100) {
- const OpenCLDebugInfo100Instructions ext_inst_key =
- OpenCLDebugInfo100Instructions(ext_inst_index);
- if (ext_inst_key == OpenCLDebugInfo100DebugScope ||
- ext_inst_key == OpenCLDebugInfo100DebugNoScope ||
- ext_inst_key == OpenCLDebugInfo100DebugDeclare ||
- ext_inst_key == OpenCLDebugInfo100DebugValue) {
- local_debug_info = true;
- }
- } else if (inst->ext_inst_type() ==
- SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100) {
- const NonSemanticShaderDebugInfo100Instructions ext_inst_key =
- NonSemanticShaderDebugInfo100Instructions(ext_inst_index);
- if (ext_inst_key == NonSemanticShaderDebugInfo100DebugScope ||
- ext_inst_key == NonSemanticShaderDebugInfo100DebugNoScope ||
- ext_inst_key == NonSemanticShaderDebugInfo100DebugDeclare ||
- ext_inst_key == NonSemanticShaderDebugInfo100DebugValue ||
- ext_inst_key == NonSemanticShaderDebugInfo100DebugLine ||
- ext_inst_key == NonSemanticShaderDebugInfo100DebugNoLine ||
- ext_inst_key ==
- NonSemanticShaderDebugInfo100DebugFunctionDefinition) {
- local_debug_info = true;
- }
- } else {
- const DebugInfoInstructions ext_inst_key =
- DebugInfoInstructions(ext_inst_index);
- if (ext_inst_key == DebugInfoDebugScope ||
- ext_inst_key == DebugInfoDebugNoScope ||
- ext_inst_key == DebugInfoDebugDeclare ||
- ext_inst_key == DebugInfoDebugValue) {
- local_debug_info = true;
- }
- }
- if (local_debug_info) {
- if (_.in_function_body() == false) {
- // TODO - Print the actual name of the instruction as this list is
- // not complete (see ext_inst_name in ValidateExtInst() for example)
- return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
- << "DebugScope, DebugNoScope, DebugDeclare, DebugValue "
- << "of debug info extension must appear in a function "
- << "body";
- }
- } else {
- // Debug info extinst opcodes other than DebugScope, DebugNoScope,
- // DebugDeclare, DebugValue must be placed between section 9 (types,
- // constants, global variables) and section 10 (function
- // declarations).
- if (_.current_layout_section() < kLayoutTypes ||
- _.current_layout_section() >= kLayoutFunctionDeclarations) {
- return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
- << "Debug info extension instructions other than "
- << "DebugScope, DebugNoScope, DebugDeclare, DebugValue "
- << "must appear between section 9 (types, constants, "
- << "global variables) and section 10 (function "
- << "declarations)";
- }
- }
- } else if (spvExtInstIsNonSemantic(inst->ext_inst_type())) {
- // non-semantic extinst opcodes are allowed beginning in the types
- // section, but since they must name a return type they cannot be the
- // first instruction in the types section. Therefore check that we are
- // already in it.
- if (_.current_layout_section() < kLayoutTypes) {
- return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
- << "Non-semantic OpExtInst must not appear before types "
- << "section";
- }
- } else {
- // otherwise they must be used in a block
- if (_.current_layout_section() < kLayoutFunctionDefinitions) {
- return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
- << spvOpcodeString(opcode) << " must appear in a block";
- }
- }
- break;
- default:
- break;
- }
- while (_.IsOpcodeInCurrentLayoutSection(opcode) == false) {
- if (_.IsOpcodeInPreviousLayoutSection(opcode)) {
- return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
- << spvOpcodeString(opcode) << " is in an invalid layout section";
- }
- _.ProgressToNextLayoutSectionOrder();
- switch (_.current_layout_section()) {
- case kLayoutMemoryModel:
- if (opcode != spv::Op::OpMemoryModel) {
- return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
- << spvOpcodeString(opcode)
- << " cannot appear before the memory model instruction";
- }
- break;
- case kLayoutFunctionDeclarations:
- // All module sections have been processed. Recursively call
- // ModuleLayoutPass to process the next section of the module
- return ModuleLayoutPass(_, inst);
- default:
- break;
- }
- }
- return SPV_SUCCESS;
- }
- // Function declaration validation is performed by making sure that the
- // FunctionParameter and FunctionEnd instructions only appear inside of
- // functions. It also ensures that the Function instruction does not appear
- // inside of another function. This stage ends when the first label is
- // encountered inside of a function.
- spv_result_t FunctionScopedInstructions(ValidationState_t& _,
- const Instruction* inst,
- spv::Op opcode) {
- // Make sure we advance into the function definitions when we hit
- // non-function declaration instructions.
- if (_.current_layout_section() == kLayoutFunctionDeclarations &&
- !_.IsOpcodeInCurrentLayoutSection(opcode)) {
- _.ProgressToNextLayoutSectionOrder();
- if (_.in_function_body()) {
- if (auto error = _.current_function().RegisterSetFunctionDeclType(
- FunctionDecl::kFunctionDeclDefinition)) {
- return error;
- }
- }
- }
- if (_.IsOpcodeInCurrentLayoutSection(opcode)) {
- switch (opcode) {
- case spv::Op::OpFunction: {
- if (_.in_function_body()) {
- return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
- << "Cannot declare a function in a function body";
- }
- auto control_mask = inst->GetOperandAs<spv::FunctionControlMask>(2);
- if (auto error =
- _.RegisterFunction(inst->id(), inst->type_id(), control_mask,
- inst->GetOperandAs<uint32_t>(3)))
- return error;
- if (_.current_layout_section() == kLayoutFunctionDefinitions) {
- if (auto error = _.current_function().RegisterSetFunctionDeclType(
- FunctionDecl::kFunctionDeclDefinition))
- return error;
- }
- } break;
- case spv::Op::OpFunctionParameter:
- if (_.in_function_body() == false) {
- return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
- << "Function parameter instructions must be in a "
- "function body";
- }
- if (_.current_function().block_count() != 0) {
- return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
- << "Function parameters must only appear immediately after "
- "the function definition";
- }
- if (auto error = _.current_function().RegisterFunctionParameter(
- inst->id(), inst->type_id()))
- return error;
- break;
- case spv::Op::OpFunctionEnd:
- if (_.in_function_body() == false) {
- return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
- << "Function end instructions must be in a function body";
- }
- if (_.in_block()) {
- return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
- << "Function end cannot be called in blocks";
- }
- if (_.current_function().block_count() == 0 &&
- _.current_layout_section() == kLayoutFunctionDefinitions) {
- return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
- << "Function declarations must appear before "
- "function definitions.";
- }
- if (_.current_layout_section() == kLayoutFunctionDeclarations) {
- if (auto error = _.current_function().RegisterSetFunctionDeclType(
- FunctionDecl::kFunctionDeclDeclaration))
- return error;
- }
- if (auto error = _.RegisterFunctionEnd()) return error;
- break;
- case spv::Op::OpLine:
- case spv::Op::OpNoLine:
- break;
- case spv::Op::OpLabel:
- // If the label is encountered then the current function is a
- // definition so set the function to a declaration and update the
- // module section
- if (_.in_function_body() == false) {
- return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
- << "Label instructions must be in a function body";
- }
- if (_.in_block()) {
- return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
- << "A block must end with a branch instruction.";
- }
- break;
- case spv::Op::OpExtInst:
- case spv::Op::OpExtInstWithForwardRefsKHR:
- if (spvExtInstIsDebugInfo(inst->ext_inst_type())) {
- const uint32_t ext_inst_index = inst->word(4);
- bool local_debug_info = false;
- if (inst->ext_inst_type() == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100) {
- const OpenCLDebugInfo100Instructions ext_inst_key =
- OpenCLDebugInfo100Instructions(ext_inst_index);
- if (ext_inst_key == OpenCLDebugInfo100DebugScope ||
- ext_inst_key == OpenCLDebugInfo100DebugNoScope ||
- ext_inst_key == OpenCLDebugInfo100DebugDeclare ||
- ext_inst_key == OpenCLDebugInfo100DebugValue) {
- local_debug_info = true;
- }
- } else if (inst->ext_inst_type() ==
- SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100) {
- const NonSemanticShaderDebugInfo100Instructions ext_inst_key =
- NonSemanticShaderDebugInfo100Instructions(ext_inst_index);
- if (ext_inst_key == NonSemanticShaderDebugInfo100DebugScope ||
- ext_inst_key == NonSemanticShaderDebugInfo100DebugNoScope ||
- ext_inst_key == NonSemanticShaderDebugInfo100DebugDeclare ||
- ext_inst_key == NonSemanticShaderDebugInfo100DebugValue ||
- ext_inst_key == NonSemanticShaderDebugInfo100DebugLine ||
- ext_inst_key == NonSemanticShaderDebugInfo100DebugNoLine ||
- ext_inst_key ==
- NonSemanticShaderDebugInfo100DebugFunctionDefinition) {
- local_debug_info = true;
- }
- } else {
- const DebugInfoInstructions ext_inst_key =
- DebugInfoInstructions(ext_inst_index);
- if (ext_inst_key == DebugInfoDebugScope ||
- ext_inst_key == DebugInfoDebugNoScope ||
- ext_inst_key == DebugInfoDebugDeclare ||
- ext_inst_key == DebugInfoDebugValue) {
- local_debug_info = true;
- }
- }
- if (local_debug_info) {
- if (_.in_function_body() == false) {
- // DebugScope, DebugNoScope, DebugDeclare, DebugValue must
- // appear in a function body.
- return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
- << "DebugScope, DebugNoScope, DebugDeclare, DebugValue "
- << "of debug info extension must appear in a function "
- << "body";
- }
- } else {
- // Debug info extinst opcodes other than DebugScope, DebugNoScope,
- // DebugDeclare, DebugValue must be placed between section 9 (types,
- // constants, global variables) and section 10 (function
- // declarations).
- if (_.current_layout_section() < kLayoutTypes ||
- _.current_layout_section() >= kLayoutFunctionDeclarations) {
- return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
- << "Debug info extension instructions other than "
- << "DebugScope, DebugNoScope, DebugDeclare, DebugValue "
- << "must appear between section 9 (types, constants, "
- << "global variables) and section 10 (function "
- << "declarations)";
- }
- }
- } else if (spvExtInstIsNonSemantic(inst->ext_inst_type())) {
- // non-semantic extinst opcodes are allowed beginning in the types
- // section, but must either be placed outside a function declaration,
- // or inside a block.
- if (_.current_layout_section() < kLayoutTypes) {
- return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
- << "Non-semantic OpExtInst must not appear before types "
- << "section";
- } else if (_.in_function_body() && _.in_block() == false) {
- return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
- << "Non-semantic OpExtInst within function definition must "
- "appear in a block";
- }
- } else {
- // otherwise they must be used in a block
- if (_.in_block() == false) {
- return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
- << spvOpcodeString(opcode) << " must appear in a block";
- }
- }
- break;
- default:
- if (_.current_layout_section() == kLayoutFunctionDeclarations &&
- _.in_function_body()) {
- return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
- << "A function must begin with a label";
- } else {
- if (_.in_block() == false) {
- return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
- << spvOpcodeString(opcode) << " must appear in a block";
- }
- }
- break;
- }
- } else {
- return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
- << spvOpcodeString(opcode)
- << " cannot appear in a function declaration";
- }
- return SPV_SUCCESS;
- }
- } // namespace
- // TODO(umar): Check linkage capabilities for function declarations
- // TODO(umar): Better error messages
- // NOTE: This function does not handle CFG related validation
- // Performs logical layout validation. See Section 2.4
- spv_result_t ModuleLayoutPass(ValidationState_t& _, const Instruction* inst) {
- const spv::Op opcode = inst->opcode();
- switch (_.current_layout_section()) {
- case kLayoutCapabilities:
- case kLayoutExtensions:
- case kLayoutExtInstImport:
- case kLayoutMemoryModel:
- case kLayoutSamplerImageAddressMode:
- case kLayoutEntryPoint:
- case kLayoutExecutionMode:
- case kLayoutDebug1:
- case kLayoutDebug2:
- case kLayoutDebug3:
- case kLayoutAnnotations:
- case kLayoutTypes:
- if (auto error = ModuleScopedInstructions(_, inst, opcode)) return error;
- break;
- case kLayoutFunctionDeclarations:
- case kLayoutFunctionDefinitions:
- if (auto error = FunctionScopedInstructions(_, inst, opcode)) {
- return error;
- }
- break;
- }
- return SPV_SUCCESS;
- }
- } // namespace val
- } // namespace spvtools
|