mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2025-01-10 08:30:09 +00:00
961f5dc544
Replace two other, imperfect mechanisms for use-def tracking. Use ValidationState_t::entry_points to track entry points. Concentrate undefined-ID diagnostics in a single place. Move validate_types.h content into validate.h due to increased inter-dependency. Track uses of all IDs: TYPE_ID, SCOPE_ID, ... Also update some blurbs. Fix entry-point accumulation and move it outside ProcessIds(). Remove validate_types.h from CMakeLists.txt. Blurb for spvIsIdType. Remove redundant diagnostics for undefined IDs. Join "can not" and reformat.
210 lines
8.1 KiB
C++
210 lines
8.1 KiB
C++
// Copyright (c) 2015-2016 The Khronos Group Inc.
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
// copy of this software and/or associated documentation files (the
|
|
// "Materials"), to deal in the Materials without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, sublicense, and/or sell copies of the Materials, and to
|
|
// permit persons to whom the Materials are furnished to do so, subject to
|
|
// the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included
|
|
// in all copies or substantial portions of the Materials.
|
|
//
|
|
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
|
|
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
|
|
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
|
|
// https://www.khronos.org/registry/
|
|
//
|
|
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
|
|
|
// Source code for logical layout validation as described in section 2.4
|
|
|
|
#include "validate_passes.h"
|
|
#include "libspirv/libspirv.h"
|
|
|
|
#include "diagnostic.h"
|
|
#include "opcode.h"
|
|
#include "operand.h"
|
|
|
|
#include <cassert>
|
|
|
|
using libspirv::ValidationState_t;
|
|
using libspirv::kLayoutMemoryModel;
|
|
using libspirv::kLayoutFunctionDeclarations;
|
|
using libspirv::kLayoutFunctionDefinitions;
|
|
using libspirv::FunctionDecl;
|
|
|
|
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 spv_parsed_instruction_t* inst,
|
|
SpvOp opcode) {
|
|
while (_.isOpcodeInCurrentLayoutSection(opcode) == false) {
|
|
_.progressToNextLayoutSectionOrder();
|
|
|
|
switch (_.getLayoutSection()) {
|
|
case kLayoutMemoryModel:
|
|
if (opcode != SpvOpMemoryModel) {
|
|
return _.diag(SPV_ERROR_INVALID_LAYOUT)
|
|
<< spvOpcodeString(opcode)
|
|
<< " cannot appear before the memory model instruction";
|
|
}
|
|
break;
|
|
case kLayoutFunctionDeclarations:
|
|
// All module sections have been processed. Recursivly call
|
|
// ModuleLayoutPass to process the next section of the module
|
|
return libspirv::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 spv_parsed_instruction_t* inst,
|
|
SpvOp opcode) {
|
|
if (_.isOpcodeInCurrentLayoutSection(opcode)) {
|
|
switch (opcode) {
|
|
case SpvOpFunction:
|
|
if (_.in_function_body()) {
|
|
return _.diag(SPV_ERROR_INVALID_LAYOUT)
|
|
<< "Cannot declare a function in a function body";
|
|
}
|
|
spvCheckReturn(_.get_functions().RegisterFunction(
|
|
inst->result_id, inst->type_id,
|
|
inst->words[inst->operands[2].offset],
|
|
inst->words[inst->operands[3].offset]));
|
|
if (_.getLayoutSection() == kLayoutFunctionDefinitions)
|
|
spvCheckReturn(_.get_functions().RegisterSetFunctionDeclType(
|
|
FunctionDecl::kFunctionDeclDefinition));
|
|
break;
|
|
|
|
case SpvOpFunctionParameter:
|
|
if (_.in_function_body() == false) {
|
|
return _.diag(SPV_ERROR_INVALID_LAYOUT) << "Function parameter "
|
|
"instructions must be in "
|
|
"a function body";
|
|
}
|
|
if (_.get_functions().get_block_count() != 0) {
|
|
return _.diag(SPV_ERROR_INVALID_LAYOUT)
|
|
<< "Function parameters must only appear immediatly after the "
|
|
"function definition";
|
|
}
|
|
spvCheckReturn(_.get_functions().RegisterFunctionParameter(
|
|
inst->result_id, inst->type_id));
|
|
break;
|
|
|
|
case SpvOpFunctionEnd:
|
|
if (_.in_function_body() == false) {
|
|
return _.diag(SPV_ERROR_INVALID_LAYOUT)
|
|
<< "Function end instructions must be in a function body";
|
|
}
|
|
if (_.in_block()) {
|
|
return _.diag(SPV_ERROR_INVALID_LAYOUT)
|
|
<< "Function end cannot be called in blocks";
|
|
}
|
|
if (_.get_functions().get_block_count() == 0 &&
|
|
_.getLayoutSection() == kLayoutFunctionDefinitions) {
|
|
return _.diag(SPV_ERROR_INVALID_LAYOUT) << "Function declarations "
|
|
"must appear before "
|
|
"function definitions.";
|
|
}
|
|
spvCheckReturn(_.get_functions().RegisterFunctionEnd());
|
|
if (_.getLayoutSection() == kLayoutFunctionDeclarations) {
|
|
spvCheckReturn(_.get_functions().RegisterSetFunctionDeclType(
|
|
FunctionDecl::kFunctionDeclDeclaration));
|
|
}
|
|
break;
|
|
|
|
case SpvOpLine:
|
|
case SpvOpNoLine:
|
|
break;
|
|
case SpvOpLabel:
|
|
// 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)
|
|
<< "Label instructions must be in a function body";
|
|
}
|
|
if (_.in_block()) {
|
|
return _.diag(SPV_ERROR_INVALID_LAYOUT)
|
|
<< "A block must end with a branch instruction.";
|
|
}
|
|
if (_.getLayoutSection() == kLayoutFunctionDeclarations) {
|
|
_.progressToNextLayoutSectionOrder();
|
|
spvCheckReturn(_.get_functions().RegisterSetFunctionDeclType(
|
|
FunctionDecl::kFunctionDeclDefinition));
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if (_.getLayoutSection() == kLayoutFunctionDeclarations) {
|
|
return _.diag(SPV_ERROR_INVALID_LAYOUT)
|
|
<< "A function must begin with a label";
|
|
} else {
|
|
if (_.in_block() == false) {
|
|
return _.diag(SPV_ERROR_INVALID_LAYOUT)
|
|
<< spvOpcodeString(opcode) << " must appear in a block";
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
} else {
|
|
return _.diag(SPV_ERROR_INVALID_LAYOUT)
|
|
<< spvOpcodeString(opcode)
|
|
<< " cannot appear in a function declaration";
|
|
}
|
|
return SPV_SUCCESS;
|
|
}
|
|
}
|
|
|
|
namespace libspirv {
|
|
// 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 spv_parsed_instruction_t* inst) {
|
|
if (_.is_enabled(SPV_VALIDATE_LAYOUT_BIT)) {
|
|
SpvOp opcode = inst->opcode;
|
|
|
|
switch (_.getLayoutSection()) {
|
|
case kLayoutCapabilities:
|
|
case kLayoutExtensions:
|
|
case kLayoutExtInstImport:
|
|
case kLayoutMemoryModel:
|
|
case kLayoutEntryPoint:
|
|
case kLayoutExecutionMode:
|
|
case kLayoutDebug1:
|
|
case kLayoutDebug2:
|
|
case kLayoutAnnotations:
|
|
case kLayoutTypes:
|
|
spvCheckReturn(ModuleScopedInstructions(_, inst, opcode));
|
|
break;
|
|
case kLayoutFunctionDeclarations:
|
|
case kLayoutFunctionDefinitions:
|
|
spvCheckReturn(FunctionScopedInstructions(_, inst, opcode));
|
|
break;
|
|
} // switch(getLayoutSection())
|
|
}
|
|
return SPV_SUCCESS;
|
|
}
|
|
}
|