endif()
endif()
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/source)
+
option(SPIRV_COLOR_TERMINAL "Enable color terminal output" ON)
if(${SPIRV_COLOR_TERMINAL})
add_definitions(-DSPIRV_COLOR_TERMINAL)
${CMAKE_CURRENT_SOURCE_DIR}/validate_instruction.cpp
${CMAKE_CURRENT_SOURCE_DIR}/validate_layout.cpp
${CMAKE_CURRENT_SOURCE_DIR}/validate_ssa.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/validate_types.cpp)
+ ${CMAKE_CURRENT_SOURCE_DIR}/val/BasicBlock.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/val/Construct.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/val/Function.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/val/ValidationState.cpp)
# The software_version.cpp file includes build-version.inc.
# Rebuild the software_version.cpp object file if it is older than
${CMAKE_CURRENT_SOURCE_DIR}/software_version.cpp
PROPERTIES OBJECT_DEPENDS "${SPIRV_TOOLS_BUILD_VERSION_INC}")
-
add_library(${SPIRV_TOOLS} ${SPIRV_SOURCES})
spvtools_default_compile_options(${SPIRV_TOOLS})
target_include_directories(${SPIRV_TOOLS}
return out;
}
+void message(std::string file, size_t line, std::string name) {
+ std::cout << file << ":" << line << ": " << name << std::endl;
+}
+
} // namespace libspirv
#include "spirv-tools/libspirv.h"
-namespace libspirv {
+/// For debugging purposes only
+/// Prints the string to stdout
+#define MSG(msg) \
+ do { \
+ libspirv::message(__FILE__, size_t(__LINE__), msg); \
+ } while (0)
+
+/// For debugging purposes only
+/// prints the variable value/location/and name to stdout
+#define SHOW(exp) \
+ do { \
+ libspirv::message(__FILE__, size_t(__LINE__), #exp, (exp)); \
+ } while (0)
+namespace libspirv {
class diagnostic_helper {
public:
diagnostic_helper(spv_position_t& position, spv_diagnostic* diagnostic)
std::string spvResultToString(spv_result_t res);
+/// Helper functions for printing debugging information
+void message(std::string file, size_t line, std::string name);
+
+template <typename T>
+void message(std::string file, size_t line, std::string name, T val) {
+ std::cout << file << ":" << line << ": " << name << " " << val << std::endl;
+}
+
} // namespace libspirv
#endif // LIBSPIRV_DIAGNOSTIC_H_
--- /dev/null
+// 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.
+
+#include "BasicBlock.h"
+
+#include <vector>
+
+using std::vector;
+
+namespace libspirv {
+
+BasicBlock::BasicBlock(uint32_t id)
+ : id_(id),
+ immediate_dominator_(nullptr),
+ predecessors_(),
+ successors_(),
+ reachable_(false) {}
+
+void BasicBlock::SetImmediateDominator(BasicBlock* dom_block) {
+ immediate_dominator_ = dom_block;
+}
+
+const BasicBlock* BasicBlock::GetImmediateDominator() const {
+ return immediate_dominator_;
+}
+
+BasicBlock* BasicBlock::GetImmediateDominator() { return immediate_dominator_; }
+
+void BasicBlock::RegisterSuccessors(vector<BasicBlock*> next_blocks) {
+ for (auto& block : next_blocks) {
+ block->predecessors_.push_back(this);
+ successors_.push_back(block);
+ if (block->reachable_ == false) block->set_reachability(reachable_);
+ }
+}
+
+void BasicBlock::RegisterBranchInstruction(SpvOp branch_instruction) {
+ if (branch_instruction == SpvOpUnreachable) reachable_ = false;
+ return;
+}
+
+BasicBlock::DominatorIterator::DominatorIterator() : current_(nullptr) {}
+BasicBlock::DominatorIterator::DominatorIterator(const BasicBlock* block)
+ : current_(block) {}
+
+BasicBlock::DominatorIterator& BasicBlock::DominatorIterator::operator++() {
+ if (current_ == current_->GetImmediateDominator()) {
+ current_ = nullptr;
+ } else {
+ current_ = current_->GetImmediateDominator();
+ }
+ return *this;
+}
+
+const BasicBlock::DominatorIterator BasicBlock::dom_begin() const {
+ return DominatorIterator(this);
+}
+
+BasicBlock::DominatorIterator BasicBlock::dom_begin() {
+ return DominatorIterator(this);
+}
+
+const BasicBlock::DominatorIterator BasicBlock::dom_end() const {
+ return DominatorIterator();
+}
+
+BasicBlock::DominatorIterator BasicBlock::dom_end() {
+ return DominatorIterator();
+}
+
+bool operator==(const BasicBlock::DominatorIterator& lhs,
+ const BasicBlock::DominatorIterator& rhs) {
+ return lhs.current_ == rhs.current_;
+}
+
+bool operator!=(const BasicBlock::DominatorIterator& lhs,
+ const BasicBlock::DominatorIterator& rhs) {
+ return !(lhs == rhs);
+}
+
+const BasicBlock*& BasicBlock::DominatorIterator::operator*() {
+ return current_;
+}
+} // namespace libspirv
--- /dev/null
+// 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.
+
+#ifndef LIBSPIRV_VAL_BASICBLOCK_H_
+#define LIBSPIRV_VAL_BASICBLOCK_H_
+
+#include "spirv/spirv.h"
+
+#include <cstdint>
+#include <vector>
+
+namespace libspirv {
+
+// This class represents a basic block in a SPIR-V module
+class BasicBlock {
+ public:
+ /// Constructor for a BasicBlock
+ ///
+ /// @param[in] id The ID of the basic block
+ explicit BasicBlock(uint32_t id);
+
+ /// Returns the id of the BasicBlock
+ uint32_t get_id() const { return id_; }
+
+ /// Returns the predecessors of the BasicBlock
+ const std::vector<BasicBlock*>& get_predecessors() const {
+ return predecessors_;
+ }
+
+ /// Returns the predecessors of the BasicBlock
+ std::vector<BasicBlock*>& get_predecessors() { return predecessors_; }
+
+ /// Returns the successors of the BasicBlock
+ const std::vector<BasicBlock*>& get_successors() const { return successors_; }
+
+ /// Returns the successors of the BasicBlock
+ std::vector<BasicBlock*>& get_successors() { return successors_; }
+
+ /// Returns true if the block should be reachable in the CFG
+ bool is_reachable() const { return reachable_; }
+
+ void set_reachability(bool reachability) { reachable_ = reachability; }
+
+ /// Sets the immedate dominator of this basic block
+ ///
+ /// @param[in] dom_block The dominator block
+ void SetImmediateDominator(BasicBlock* dom_block);
+
+ /// Returns the immedate dominator of this basic block
+ BasicBlock* GetImmediateDominator();
+
+ /// Returns the immedate dominator of this basic block
+ const BasicBlock* GetImmediateDominator() const;
+
+ /// Ends the block without a successor
+ void RegisterBranchInstruction(SpvOp branch_instruction);
+
+ /// Adds @p next BasicBlocks as successors of this BasicBlock
+ void RegisterSuccessors(std::vector<BasicBlock*> next = {});
+
+ /// Returns true if the id of the BasicBlock matches
+ bool operator==(const BasicBlock& other) const { return other.id_ == id_; }
+
+ /// Returns true if the id of the BasicBlock matches
+ bool operator==(const uint32_t& id) const { return id == id_; }
+
+ /// @brief A BasicBlock dominator iterator class
+ ///
+ /// This iterator will iterate over the dominators of the block
+ class DominatorIterator
+ : public std::iterator<std::forward_iterator_tag, BasicBlock*> {
+ public:
+ /// @brief Constructs the end of dominator iterator
+ ///
+ /// This will create an iterator which will represent the element
+ /// before the root node of the dominator tree
+ DominatorIterator();
+
+ /// @brief Constructs an iterator for the given block which points to
+ /// @p block
+ ///
+ /// @param block The block which is referenced by the iterator
+ explicit DominatorIterator(const BasicBlock* block);
+
+ /// @brief Advances the iterator
+ DominatorIterator& operator++();
+
+ /// @brief Returns the current element
+ const BasicBlock*& operator*();
+
+ friend bool operator==(const DominatorIterator& lhs,
+ const DominatorIterator& rhs);
+
+ private:
+ const BasicBlock* current_;
+ };
+
+ /// Returns an iterator which points to the current block
+ const DominatorIterator dom_begin() const;
+ DominatorIterator dom_begin();
+
+ /// Returns an iterator which points to one element past the first block
+ const DominatorIterator dom_end() const;
+ DominatorIterator dom_end();
+
+ private:
+ /// Id of the BasicBlock
+ const uint32_t id_;
+
+ /// Pointer to the immediate dominator of the BasicBlock
+ BasicBlock* immediate_dominator_;
+
+ /// The set of predecessors of the BasicBlock
+ std::vector<BasicBlock*> predecessors_;
+
+ /// The set of successors of the BasicBlock
+ std::vector<BasicBlock*> successors_;
+
+ bool reachable_;
+};
+
+/// @brief Returns true if the iterators point to the same element or if both
+/// iterators point to the @p dom_end block
+bool operator==(const BasicBlock::DominatorIterator& lhs,
+ const BasicBlock::DominatorIterator& rhs);
+
+/// @brief Returns true if the iterators point to different elements and they
+/// do not both point to the @p dom_end block
+bool operator!=(const BasicBlock::DominatorIterator& lhs,
+ const BasicBlock::DominatorIterator& rhs);
+
+} /// namespace libspirv
+
+#endif /// LIBSPIRV_VAL_BASICBLOCK_H_
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
-#ifndef LIBSPIRV_VALIDATE_PASSES_H_
-#define LIBSPIRV_VALIDATE_PASSES_H_
+#include "val/Construct.h"
-#include "binary.h"
-#include "validate.h"
+namespace libspirv {
-namespace libspirv
-{
-// TODO(umar): Better docs
+Construct::Construct(BasicBlock* header_block, BasicBlock* merge_block,
+ BasicBlock* continue_block)
+ : header_block_(header_block),
+ merge_block_(merge_block),
+ continue_block_(continue_block) {}
-// Performs logical layout validation as described in section 2.4 of the SPIR-V spec
-spv_result_t ModuleLayoutPass(ValidationState_t& _,
- const spv_parsed_instruction_t* inst);
-
-// Performs Control Flow Graph validation of a module
-spv_result_t CfgPass(ValidationState_t& _,
- const spv_parsed_instruction_t* inst);
-
-// Performs SSA validation of a module
-spv_result_t SsaPass(ValidationState_t& _,
- const spv_parsed_instruction_t* inst);
-
-// Performs instruction validation.
-spv_result_t InstructionPass(ValidationState_t& _,
- const spv_parsed_instruction_t* inst);
+const BasicBlock* Construct::get_header() const { return header_block_; }
+const BasicBlock* Construct::get_merge() const { return merge_block_; }
+const BasicBlock* Construct::get_continue() const { return continue_block_; }
+BasicBlock* Construct::get_header() { return header_block_; }
+BasicBlock* Construct::get_merge() { return merge_block_; }
+BasicBlock* Construct::get_continue() { return continue_block_; }
}
-
-#endif
--- /dev/null
+// 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.
+
+#ifndef LIBSPIRV_VAL_CONSTRUCT_H_
+#define LIBSPIRV_VAL_CONSTRUCT_H_
+
+#include <cstdint>
+
+namespace libspirv {
+
+class BasicBlock;
+
+/// @brief This class tracks the CFG constructs as defined in the SPIR-V spec
+class Construct {
+ public:
+ Construct(BasicBlock* header_block, BasicBlock* merge_block,
+ BasicBlock* continue_block = nullptr);
+
+ const BasicBlock* get_header() const;
+ const BasicBlock* get_merge() const;
+ const BasicBlock* get_continue() const;
+
+ BasicBlock* get_header();
+ BasicBlock* get_merge();
+ BasicBlock* get_continue();
+
+ private:
+ BasicBlock* header_block_; ///< The header block of a loop or selection
+ BasicBlock* merge_block_; ///< The merge block of a loop or selection
+ BasicBlock* continue_block_; ///< The continue block of a loop block
+};
+
+} /// namespace libspirv
+
+#endif /// LIBSPIRV_VAL_CONSTRUCT_H_
--- /dev/null
+// 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.
+
+#include "val/Function.h"
+
+#include <cassert>
+
+#include <algorithm>
+
+#include "val/BasicBlock.h"
+#include "val/Construct.h"
+#include "val/ValidationState.h"
+
+using std::list;
+using std::string;
+using std::vector;
+
+namespace libspirv {
+namespace {
+
+void printDot(const BasicBlock& other, const ValidationState_t& module) {
+ string block_string;
+ if (other.get_successors().empty()) {
+ block_string += "end ";
+ } else {
+ for (auto& block : other.get_successors()) {
+ block_string += module.getIdOrName(block->get_id()) + " ";
+ }
+ }
+ printf("%10s -> {%s\b}\n", module.getIdOrName(other.get_id()).c_str(),
+ block_string.c_str());
+}
+} /// namespace
+
+Function::Function(uint32_t id, uint32_t result_type_id,
+ SpvFunctionControlMask function_control,
+ uint32_t function_type_id, ValidationState_t& module)
+ : module_(module),
+ id_(id),
+ function_type_id_(function_type_id),
+ result_type_id_(result_type_id),
+ function_control_(function_control),
+ declaration_type_(FunctionDecl::kFunctionDeclUnknown),
+ blocks_(),
+ current_block_(nullptr),
+ cfg_constructs_(),
+ variable_ids_(),
+ parameter_ids_() {}
+
+bool Function::IsFirstBlock(uint32_t id) const {
+ return !ordered_blocks_.empty() && *get_first_block() == id;
+}
+
+spv_result_t Function::RegisterFunctionParameter(uint32_t id,
+ uint32_t type_id) {
+ assert(module_.in_function_body() == true &&
+ "RegisterFunctionParameter can only be called when parsing the binary "
+ "outside of another function");
+ assert(current_block_ == nullptr &&
+ "RegisterFunctionParameter can only be called when parsing the binary "
+ "ouside of a block");
+ // TODO(umar): Validate function parameter type order and count
+ // TODO(umar): Use these variables to validate parameter type
+ (void)id;
+ (void)type_id;
+ return SPV_SUCCESS;
+}
+
+spv_result_t Function::RegisterLoopMerge(uint32_t merge_id,
+ uint32_t continue_id) {
+ RegisterBlock(merge_id, false);
+ RegisterBlock(continue_id, false);
+ cfg_constructs_.emplace_back(get_current_block(), &blocks_.at(merge_id),
+ &blocks_.at(continue_id));
+
+ return SPV_SUCCESS;
+}
+
+spv_result_t Function::RegisterSelectionMerge(uint32_t merge_id) {
+ RegisterBlock(merge_id, false);
+ cfg_constructs_.emplace_back(get_current_block(), &blocks_.at(merge_id));
+ return SPV_SUCCESS;
+}
+
+void Function::printDotGraph() const {
+ if (get_first_block()) {
+ string func_name(module_.getIdOrName(id_));
+ printf("digraph %s {\n", func_name.c_str());
+ printBlocks();
+ printf("}\n");
+ }
+}
+
+void Function::printBlocks() const {
+ if (get_first_block()) {
+ printf("%10s -> %s\n", module_.getIdOrName(id_).c_str(),
+ module_.getIdOrName(get_first_block()->get_id()).c_str());
+ for (const auto& block : blocks_) {
+ printDot(block.second, module_);
+ }
+ }
+}
+
+spv_result_t Function::RegisterSetFunctionDeclType(FunctionDecl type) {
+ assert(declaration_type_ == FunctionDecl::kFunctionDeclUnknown);
+ declaration_type_ = type;
+ return SPV_SUCCESS;
+}
+
+spv_result_t Function::RegisterBlock(uint32_t id, bool is_definition) {
+ assert(module_.in_function_body() == true &&
+ "RegisterBlocks can only be called when parsing a binary inside of a "
+ "function");
+ assert(module_.getLayoutSection() !=
+ ModuleLayoutSection::kLayoutFunctionDeclarations &&
+ "RegisterBlocks cannot be called within a function declaration");
+ assert(
+ declaration_type_ == FunctionDecl::kFunctionDeclDefinition &&
+ "RegisterBlocks can only be called after declaration_type_ is defined");
+
+ std::unordered_map<uint32_t, BasicBlock>::iterator inserted_block;
+ bool success = false;
+ tie(inserted_block, success) = blocks_.insert({id, BasicBlock(id)});
+ if (is_definition) { // new block definition
+ assert(current_block_ == nullptr &&
+ "Register Block can only be called when parsing a binary outside of "
+ "a BasicBlock");
+
+ undefined_blocks_.erase(id);
+ current_block_ = &inserted_block->second;
+ ordered_blocks_.push_back(current_block_);
+ if (IsFirstBlock(id)) current_block_->set_reachability(true);
+ } else if (success) { // Block doesn't exsist but this is not a definition
+ undefined_blocks_.insert(id);
+ }
+
+ return SPV_SUCCESS;
+}
+
+void Function::RegisterBlockEnd(vector<uint32_t> next_list,
+ SpvOp branch_instruction) {
+ assert(module_.in_function_body() == true &&
+ "RegisterBlockEnd can only be called when parsing a binary in a "
+ "function");
+ assert(
+ current_block_ &&
+ "RegisterBlockEnd can only be called when parsing a binary in a block");
+
+ vector<BasicBlock*> next_blocks;
+ next_blocks.reserve(next_list.size());
+
+ std::unordered_map<uint32_t, BasicBlock>::iterator inserted_block;
+ bool success;
+ for (uint32_t id : next_list) {
+ tie(inserted_block, success) = blocks_.insert({id, BasicBlock(id)});
+ if (success) {
+ undefined_blocks_.insert(id);
+ }
+ next_blocks.push_back(&inserted_block->second);
+ }
+
+ current_block_->RegisterBranchInstruction(branch_instruction);
+ current_block_->RegisterSuccessors(next_blocks);
+ current_block_ = nullptr;
+ return;
+}
+
+size_t Function::get_block_count() const { return blocks_.size(); }
+
+size_t Function::get_undefined_block_count() const {
+ return undefined_blocks_.size();
+}
+
+const vector<BasicBlock*>& Function::get_blocks() const {
+ return ordered_blocks_;
+}
+vector<BasicBlock*>& Function::get_blocks() { return ordered_blocks_; }
+
+const BasicBlock* Function::get_current_block() const { return current_block_; }
+BasicBlock* Function::get_current_block() { return current_block_; }
+
+const list<Construct>& Function::get_constructs() const {
+ return cfg_constructs_;
+}
+list<Construct>& Function::get_constructs() { return cfg_constructs_; }
+
+const BasicBlock* Function::get_first_block() const {
+ if (ordered_blocks_.empty()) return nullptr;
+ return ordered_blocks_[0];
+}
+BasicBlock* Function::get_first_block() {
+ if (ordered_blocks_.empty()) return nullptr;
+ return ordered_blocks_[0];
+}
+
+bool Function::IsMergeBlock(uint32_t merge_block_id) const {
+ const auto b = blocks_.find(merge_block_id);
+ if (b != end(blocks_)) {
+ return cfg_constructs_.end() !=
+ find_if(begin(cfg_constructs_), end(cfg_constructs_),
+ [&](const Construct& construct) {
+ return construct.get_merge() == &b->second;
+ });
+ } else {
+ return false;
+ }
+}
+
+} /// namespace libspirv
--- /dev/null
+// 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.
+
+#ifndef LIBSPIRV_VAL_FUNCTION_H_
+#define LIBSPIRV_VAL_FUNCTION_H_
+
+#include <list>
+#include <vector>
+#include <unordered_set>
+#include <unordered_map>
+
+#include "spirv/spirv.h"
+#include "spirv-tools/libspirv.h"
+#include "val/BasicBlock.h"
+
+namespace libspirv {
+
+enum class FunctionDecl {
+ kFunctionDeclUnknown, /// < Unknown function declaration
+ kFunctionDeclDeclaration, /// < Function declaration
+ kFunctionDeclDefinition /// < Function definition
+};
+
+class Construct;
+class ValidationState_t;
+
+/// This class manages all function declaration and definitions in a module. It
+/// handles the state and id information while parsing a function in the SPIR-V
+/// binary.
+class Function {
+ public:
+ Function(uint32_t id, uint32_t result_type_id,
+ SpvFunctionControlMask function_control, uint32_t function_type_id,
+ ValidationState_t& module);
+
+ /// Registers a function parameter in the current function
+ /// @return Returns SPV_SUCCESS if the call was successful
+ spv_result_t RegisterFunctionParameter(uint32_t id, uint32_t type_id);
+
+ /// Sets the declaration type of the current function
+ /// @return Returns SPV_SUCCESS if the call was successful
+ spv_result_t RegisterSetFunctionDeclType(FunctionDecl type);
+
+ /// Registers a block in the current function. Subsequent block instructions
+ /// will target this block
+ /// @param id The ID of the label of the block
+ /// @return Returns SPV_SUCCESS if the call was successful
+ spv_result_t RegisterBlock(uint32_t id, bool is_definition = true);
+
+ /// Registers a variable in the current block
+ ///
+ /// @param[in] type_id The type ID of the varaible
+ /// @param[in] id The ID of the varaible
+ /// @param[in] storage The storage of the variable
+ /// @param[in] init_id The initializer ID of the variable
+ ///
+ /// @return Returns SPV_SUCCESS if the call was successful
+ spv_result_t RegisterBlockVariable(uint32_t type_id, uint32_t id,
+ SpvStorageClass storage, uint32_t init_id);
+
+ /// Registers a loop merge construct in the function
+ ///
+ /// @param[in] merge_id The merge block ID of the loop
+ /// @param[in] continue_id The continue block ID of the loop
+ ///
+ /// @return Returns SPV_SUCCESS if the call was successful
+ spv_result_t RegisterLoopMerge(uint32_t merge_id, uint32_t continue_id);
+
+ /// Registers a selection merge construct in the function
+ /// @return Returns SPV_SUCCESS if the call was successful
+ spv_result_t RegisterSelectionMerge(uint32_t merge_id);
+
+ /// Registers the end of the block
+ ///
+ /// @param[in] successors_list A list of ids to the blocks successors
+ /// @param[in] branch_instruction the branch instruction that ended the block
+ void RegisterBlockEnd(std::vector<uint32_t> successors_list,
+ SpvOp branch_instruction);
+
+ /// Returns true if the \p merge_block_id is a merge block
+ bool IsMergeBlock(uint32_t merge_block_id) const;
+
+ /// Returns true if the \p id is the first block of this function
+ bool IsFirstBlock(uint32_t id) const;
+
+ /// Returns the first block of the current function
+ const BasicBlock* get_first_block() const;
+
+ /// Returns the first block of the current function
+ BasicBlock* get_first_block();
+
+ /// Returns a vector of all the blocks in the function
+ const std::vector<BasicBlock*>& get_blocks() const;
+
+ /// Returns a vector of all the blocks in the function
+ std::vector<BasicBlock*>& get_blocks();
+
+ /// Returns a list of all the cfg constructs in the function
+ const std::list<Construct>& get_constructs() const;
+
+ /// Returns a list of all the cfg constructs in the function
+ std::list<Construct>& get_constructs();
+
+ /// Returns the number of blocks in the current function being parsed
+ size_t get_block_count() const;
+
+ /// Returns the id of the funciton
+ uint32_t get_id() const { return id_; }
+
+ /// Returns the number of blocks in the current function being parsed
+ size_t get_undefined_block_count() const;
+ const std::unordered_set<uint32_t>& get_undefined_blocks() const {
+ return undefined_blocks_;
+ }
+
+ /// Returns the block that is currently being parsed in the binary
+ BasicBlock* get_current_block();
+
+ /// Returns the block that is currently being parsed in the binary
+ const BasicBlock* get_current_block() const;
+
+ /// Prints a GraphViz digraph of the CFG of the current funciton
+ void printDotGraph() const;
+
+ /// Prints a directed graph of the CFG of the current funciton
+ void printBlocks() const;
+
+ private:
+ /// Parent module
+ ValidationState_t& module_;
+
+ /// The result id of the OpLabel that defined this block
+ uint32_t id_;
+
+ /// The type of the function
+ uint32_t function_type_id_;
+
+ /// The type of the return value
+ uint32_t result_type_id_;
+
+ /// The control fo the funciton
+ SpvFunctionControlMask function_control_;
+
+ /// The type of declaration of each function
+ FunctionDecl declaration_type_;
+
+ /// The blocks in the function mapped by block ID
+ std::unordered_map<uint32_t, BasicBlock> blocks_;
+
+ /// A list of blocks in the order they appeared in the binary
+ std::vector<BasicBlock*> ordered_blocks_;
+
+ /// Blocks which are forward referenced by blocks but not defined
+ std::unordered_set<uint32_t> undefined_blocks_;
+
+ /// The block that is currently being parsed
+ BasicBlock* current_block_;
+
+ /// The constructs that are available in this function
+ std::list<Construct> cfg_constructs_;
+
+ /// The variable IDs of the functions
+ std::vector<uint32_t> variable_ids_;
+
+ /// The function parameter ids of the functions
+ std::vector<uint32_t> parameter_ids_;
+};
+
+} /// namespace libspirv
+
+
+#endif /// LIBSPIRV_VAL_FUNCTION_H_
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
-#include <algorithm>
+#include "val/ValidationState.h"
+
#include <cassert>
-#include <iterator>
-#include <limits>
-#include <list>
-#include <map>
-#include <string>
-#include <unordered_set>
-#include <vector>
-
-#include "spirv/spirv.h"
-#include "spirv_definition.h"
-#include "validate.h"
-
-using std::find;
+
+#include "val/BasicBlock.h"
+#include "val/Construct.h"
+#include "val/Function.h"
+
using std::list;
-using std::numeric_limits;
using std::string;
-using std::unordered_set;
using std::vector;
-using libspirv::kLayoutCapabilities;
-using libspirv::kLayoutExtensions;
-using libspirv::kLayoutExtInstImport;
-using libspirv::kLayoutMemoryModel;
-using libspirv::kLayoutEntryPoint;
-using libspirv::kLayoutExecutionMode;
-using libspirv::kLayoutDebug1;
-using libspirv::kLayoutDebug2;
-using libspirv::kLayoutAnnotations;
-using libspirv::kLayoutTypes;
-using libspirv::kLayoutFunctionDeclarations;
-using libspirv::kLayoutFunctionDefinitions;
-using libspirv::ModuleLayoutSection;
+namespace libspirv {
namespace {
bool IsInstructionInLayoutSection(ModuleLayoutSection layout, SpvOp op) {
} // anonymous namespace
-namespace libspirv {
-
-void message(std::string file, size_t line, std::string name) {
- std::cout << file << ":" << line << ": " << name << std::endl;
-}
-
ValidationState_t::ValidationState_t(spv_diagnostic* diagnostic,
const spv_const_context context)
: diagnostic_(diagnostic),
return memory_model_;
}
-Function::Function(uint32_t id, uint32_t result_type_id,
- SpvFunctionControlMask function_control,
- uint32_t function_type_id, ValidationState_t& module)
- : module_(module),
- id_(id),
- function_type_id_(function_type_id),
- result_type_id_(result_type_id),
- function_control_(function_control),
- declaration_type_(FunctionDecl::kFunctionDeclUnknown),
- blocks_(),
- current_block_(nullptr),
- cfg_constructs_(),
- variable_ids_(),
- parameter_ids_() {}
-
-bool Function::IsFirstBlock(uint32_t id) const {
- return !ordered_blocks_.empty() && *get_first_block() == id;
-}
-
spv_result_t ValidationState_t::RegisterFunction(
uint32_t id, uint32_t ret_type_id, SpvFunctionControlMask function_control,
uint32_t function_type_id) {
return SPV_SUCCESS;
}
-spv_result_t Function::RegisterFunctionParameter(uint32_t id,
- uint32_t type_id) {
- assert(module_.in_function_body() == true &&
- "RegisterFunctionParameter can only be called when parsing the binary "
- "outside of another function");
- assert(get_current_block() == nullptr &&
- "RegisterFunctionParameter can only be called when parsing the binary "
- "ouside of a block");
- // TODO(umar): Validate function parameter type order and count
- // TODO(umar): Use these variables to validate parameter type
- (void)id;
- (void)type_id;
- return SPV_SUCCESS;
-}
-
-spv_result_t Function::RegisterLoopMerge(uint32_t merge_id,
- uint32_t continue_id) {
- RegisterBlock(merge_id, false);
- RegisterBlock(continue_id, false);
- cfg_constructs_.emplace_back(get_current_block(), &blocks_.at(merge_id),
- &blocks_.at(continue_id));
-
- return SPV_SUCCESS;
-}
-
-spv_result_t Function::RegisterSelectionMerge(uint32_t merge_id) {
- RegisterBlock(merge_id, false);
- cfg_constructs_.emplace_back(get_current_block(), &blocks_.at(merge_id));
- return SPV_SUCCESS;
-}
-
-void printDot(const BasicBlock& other, const ValidationState_t& module) {
- string block_string;
- if (other.get_successors().empty()) {
- block_string += "end ";
- } else {
- for (auto& block : other.get_successors()) {
- block_string += module.getIdOrName(block->get_id()) + " ";
- }
- }
- printf("%10s -> {%s\b}\n", module.getIdOrName(other.get_id()).c_str(),
- block_string.c_str());
-}
-
-void Function::printDotGraph() const {
- if (get_first_block()) {
- string func_name(module_.getIdOrName(id_));
- printf("digraph %s {\n", func_name.c_str());
- printBlocks();
- printf("}\n");
- }
-}
-
-void Function::printBlocks() const {
- if (get_first_block()) {
- printf("%10s -> %s\n", module_.getIdOrName(id_).c_str(),
- module_.getIdOrName(get_first_block()->get_id()).c_str());
- for (const auto& block : blocks_) {
- printDot(block.second, module_);
- }
- }
-}
-
-spv_result_t Function::RegisterSetFunctionDeclType(FunctionDecl type) {
- assert(declaration_type_ == FunctionDecl::kFunctionDeclUnknown);
- declaration_type_ = type;
- return SPV_SUCCESS;
-}
-
-spv_result_t Function::RegisterBlock(uint32_t id, bool is_definition) {
- assert(module_.in_function_body() == true &&
- "RegisterBlocks can only be called when parsing a binary inside of a "
- "function");
- assert(module_.getLayoutSection() !=
- ModuleLayoutSection::kLayoutFunctionDeclarations &&
- "RegisterBlocks cannot be called within a function declaration");
- assert(
- declaration_type_ == FunctionDecl::kFunctionDeclDefinition &&
- "RegisterBlocks can only be called after declaration_type_ is defined");
-
- std::unordered_map<uint32_t, BasicBlock>::iterator inserted_block;
- bool success = false;
- tie(inserted_block, success) = blocks_.insert({id, BasicBlock(id)});
- if (is_definition) { // new block definition
- assert(get_current_block() == nullptr &&
- "Register Block can only be called when parsing a binary outside of "
- "a BasicBlock");
-
- undefined_blocks_.erase(id);
- current_block_ = &inserted_block->second;
- ordered_blocks_.push_back(current_block_);
- if (IsFirstBlock(id)) current_block_->set_reachability(true);
- } else if (success) { // Block doesn't exsist but this is not a definition
- undefined_blocks_.insert(id);
- }
-
- return SPV_SUCCESS;
-}
-
-void Function::RegisterBlockEnd(vector<uint32_t> next_list,
- SpvOp branch_instruction) {
- assert(module_.in_function_body() == true &&
- "RegisterBlockEnd can only be called when parsing a binary in a "
- "function");
- assert(
- get_current_block() &&
- "RegisterBlockEnd can only be called when parsing a binary in a block");
-
- vector<BasicBlock*> next_blocks;
- next_blocks.reserve(next_list.size());
-
- std::unordered_map<uint32_t, BasicBlock>::iterator inserted_block;
- bool success;
- for (uint32_t id : next_list) {
- tie(inserted_block, success) = blocks_.insert({id, BasicBlock(id)});
- if (success) {
- undefined_blocks_.insert(id);
- }
- next_blocks.push_back(&inserted_block->second);
- }
-
- current_block_->RegisterBranchInstruction(branch_instruction);
- current_block_->RegisterSuccessors(next_blocks);
- current_block_ = nullptr;
- return;
-}
-
-size_t Function::get_block_count() const { return blocks_.size(); }
-
-size_t Function::get_undefined_block_count() const {
- return undefined_blocks_.size();
-}
-
-const vector<BasicBlock*>& Function::get_blocks() const {
- return ordered_blocks_;
-}
-vector<BasicBlock*>& Function::get_blocks() { return ordered_blocks_; }
-
-const BasicBlock* Function::get_current_block() const { return current_block_; }
-BasicBlock* Function::get_current_block() { return current_block_; }
-
-const list<CFConstruct>& Function::get_constructs() const {
- return cfg_constructs_;
-}
-list<CFConstruct>& Function::get_constructs() { return cfg_constructs_; }
-
-const BasicBlock* Function::get_first_block() const {
- if (ordered_blocks_.empty()) return nullptr;
- return ordered_blocks_[0];
-}
-BasicBlock* Function::get_first_block() {
- if (ordered_blocks_.empty()) return nullptr;
- return ordered_blocks_[0];
-}
-
-BasicBlock::BasicBlock(uint32_t id)
- : id_(id),
- immediate_dominator_(nullptr),
- predecessors_(),
- successors_(),
- reachable_(false) {}
-
-void BasicBlock::SetImmediateDominator(BasicBlock* dom_block) {
- immediate_dominator_ = dom_block;
-}
-
-const BasicBlock* BasicBlock::GetImmediateDominator() const {
- return immediate_dominator_;
-}
-
-BasicBlock* BasicBlock::GetImmediateDominator() { return immediate_dominator_; }
-
-void BasicBlock::RegisterSuccessors(vector<BasicBlock*> next_blocks) {
- for (auto& block : next_blocks) {
- block->predecessors_.push_back(this);
- successors_.push_back(block);
- if (block->reachable_ == false) block->set_reachability(reachable_);
- }
-}
-
-void BasicBlock::RegisterBranchInstruction(SpvOp branch_instruction) {
- if (branch_instruction == SpvOpUnreachable) reachable_ = false;
- return;
-}
-
-bool Function::IsMergeBlock(uint32_t merge_block_id) const {
- const auto b = blocks_.find(merge_block_id);
- if (b != end(blocks_)) {
- return cfg_constructs_.end() !=
- find_if(begin(cfg_constructs_), end(cfg_constructs_),
- [&](const CFConstruct& construct) {
- return construct.get_merge() == &b->second;
- });
- } else {
- return false;
- }
-}
-
-BasicBlock::DominatorIterator::DominatorIterator() : current_(nullptr) {}
-BasicBlock::DominatorIterator::DominatorIterator(const BasicBlock* block)
- : current_(block) {}
-
-BasicBlock::DominatorIterator& BasicBlock::DominatorIterator::operator++() {
- if (current_ == current_->GetImmediateDominator()) {
- current_ = nullptr;
- } else {
- current_ = current_->GetImmediateDominator();
- }
- return *this;
-}
-
-const BasicBlock::DominatorIterator BasicBlock::dom_begin() const {
- return DominatorIterator(this);
-}
-
-BasicBlock::DominatorIterator BasicBlock::dom_begin() {
- return DominatorIterator(this);
-}
-
-const BasicBlock::DominatorIterator BasicBlock::dom_end() const {
- return DominatorIterator();
-}
-
-BasicBlock::DominatorIterator BasicBlock::dom_end() {
- return DominatorIterator();
-}
-
-bool operator==(const BasicBlock::DominatorIterator& lhs,
- const BasicBlock::DominatorIterator& rhs) {
- return lhs.current_ == rhs.current_;
-}
-
-bool operator!=(const BasicBlock::DominatorIterator& lhs,
- const BasicBlock::DominatorIterator& rhs) {
- return !(lhs == rhs);
-}
-
-const BasicBlock*& BasicBlock::DominatorIterator::operator*() {
- return current_;
-}
-} // namespace libspirv
+} /// namespace libspirv
--- /dev/null
+// 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.
+
+#ifndef LIBSPIRV_VAL_VALIDATIONSTATE_H_
+#define LIBSPIRV_VAL_VALIDATIONSTATE_H_
+
+#include <list>
+#include <map>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include "assembly_grammar.h"
+#include "diagnostic.h"
+#include "spirv-tools/libspirv.h"
+#include "spirv/spirv.h"
+#include "spirv_definition.h"
+
+namespace libspirv {
+
+// Info about a result ID.
+typedef struct spv_id_info_t {
+ /// Id value.
+ uint32_t id;
+ /// Type id, or 0 if no type.
+ uint32_t type_id;
+ /// Opcode of the instruction defining the id.
+ SpvOp opcode;
+ /// Binary words of the instruction defining the id.
+ std::vector<uint32_t> words;
+} spv_id_info_t;
+
+/// This enum represents the sections of a SPIRV module. See section 2.4
+/// of the SPIRV spec for additional details of the order. The enumerant values
+/// are in the same order as the vector returned by GetModuleOrder
+enum ModuleLayoutSection {
+ kLayoutCapabilities, /// < Section 2.4 #1
+ kLayoutExtensions, /// < Section 2.4 #2
+ kLayoutExtInstImport, /// < Section 2.4 #3
+ kLayoutMemoryModel, /// < Section 2.4 #4
+ kLayoutEntryPoint, /// < Section 2.4 #5
+ kLayoutExecutionMode, /// < Section 2.4 #6
+ kLayoutDebug1, /// < Section 2.4 #7 > 1
+ kLayoutDebug2, /// < Section 2.4 #7 > 2
+ kLayoutAnnotations, /// < Section 2.4 #8
+ kLayoutTypes, /// < Section 2.4 #9
+ kLayoutFunctionDeclarations, /// < Section 2.4 #10
+ kLayoutFunctionDefinitions /// < Section 2.4 #11
+};
+
+class Function;
+
+/// This class manages the state of the SPIR-V validation as it is being parsed.
+class ValidationState_t {
+ public:
+ ValidationState_t(spv_diagnostic* diagnostic,
+ const spv_const_context context);
+
+ /// Forward declares the id in the module
+ spv_result_t forwardDeclareId(uint32_t id);
+
+ /// Removes a forward declared ID if it has been defined
+ spv_result_t removeIfForwardDeclared(uint32_t id);
+
+ /// Assigns a name to an ID
+ void assignNameToId(uint32_t id, std::string name);
+
+ /// Returns a string representation of the ID in the format <id>[Name] where
+ /// the <id> is the numeric valid of the id and the Name is a name assigned by
+ /// the OpName instruction
+ std::string getIdName(uint32_t id) const;
+
+ /// Like getIdName but does not display the id if the \p id has a name
+ std::string getIdOrName(uint32_t id) const;
+
+ /// Returns the number of ID which have been forward referenced but not
+ /// defined
+ size_t unresolvedForwardIdCount() const;
+
+ /// Returns a list of unresolved forward ids.
+ std::vector<uint32_t> unresolvedForwardIds() const;
+
+ /// Returns true if the id has been defined
+ bool isDefinedId(uint32_t id) const;
+
+ /// Increments the instruction count. Used for diagnostic
+ int incrementInstructionCount();
+
+ /// Returns the current layout section which is being processed
+ ModuleLayoutSection getLayoutSection() const;
+
+ /// Increments the module_layout_order_section_
+ void progressToNextLayoutSectionOrder();
+
+ /// Determines if the op instruction is part of the current section
+ bool isOpcodeInCurrentLayoutSection(SpvOp op);
+
+ libspirv::DiagnosticStream diag(spv_result_t error_code) const;
+
+ /// Returns the function states
+ std::list<Function>& get_functions();
+
+ /// Returns the function states
+ Function& get_current_function();
+
+ /// Returns true if the called after a function instruction but before the
+ /// function end instruction
+ bool in_function_body() const;
+
+ /// Returns true if called after a label instruction but before a branch
+ /// instruction
+ bool in_block() const;
+
+ /// Keeps track of ID definitions and uses.
+ class UseDefTracker {
+ public:
+ void AddDef(const spv_id_info_t& def) { defs_[def.id] = def; }
+
+ void AddUse(uint32_t id) { uses_.insert(id); }
+
+ /// Finds id's def, if it exists. If found, returns <true, def>. Otherwise,
+ /// returns <false, something>.
+ std::pair<bool, spv_id_info_t> FindDef(uint32_t id) const {
+ if (defs_.count(id) == 0) {
+ return std::make_pair(false, spv_id_info_t{});
+ } else {
+ /// We are in a const function, so we cannot use defs.operator[]().
+ /// Luckily we know the key exists, so defs_.at() won't throw an
+ /// exception.
+ return std::make_pair(true, defs_.at(id));
+ }
+ }
+
+ /// Returns uses of IDs lacking defs.
+ std::unordered_set<uint32_t> FindUsesWithoutDefs() const {
+ auto diff = uses_;
+ for (const auto d : defs_) diff.erase(d.first);
+ return diff;
+ }
+
+ private:
+ std::unordered_set<uint32_t> uses_;
+ std::unordered_map<uint32_t, spv_id_info_t> defs_;
+ };
+
+ UseDefTracker& usedefs() { return usedefs_; }
+ const UseDefTracker& usedefs() const { return usedefs_; }
+
+ /// Returns a list of entry point function ids
+ std::vector<uint32_t>& entry_points() { return entry_points_; }
+ const std::vector<uint32_t>& entry_points() const { return entry_points_; }
+
+ /// Registers the capability and its dependent capabilities
+ void RegisterCapability(SpvCapability cap);
+
+ /// Registers the function in the module. Subsequent instructions will be
+ /// called against this function
+ spv_result_t RegisterFunction(uint32_t id, uint32_t ret_type_id,
+ SpvFunctionControlMask function_control,
+ uint32_t function_type_id);
+
+ /// Register a function end instruction
+ spv_result_t RegisterFunctionEnd();
+
+ /// Returns true if the capability is enabled in the module.
+ bool hasCapability(SpvCapability cap) const;
+
+ /// Returns true if any of the capabilities are enabled. Always true for
+ /// capabilities==0.
+ bool HasAnyOf(spv_capability_mask_t capabilities) const;
+
+ /// Sets the addressing model of this module (logical/physical).
+ void setAddressingModel(SpvAddressingModel am);
+
+ /// Returns the addressing model of this module, or Logical if uninitialized.
+ SpvAddressingModel getAddressingModel() const;
+
+ /// Sets the memory model of this module.
+ void setMemoryModel(SpvMemoryModel mm);
+
+ /// Returns the memory model of this module, or Simple if uninitialized.
+ SpvMemoryModel getMemoryModel() const;
+
+ AssemblyGrammar& grammar() { return grammar_; }
+
+ private:
+ spv_diagnostic* diagnostic_;
+ /// Tracks the number of instructions evaluated by the validator
+ int instruction_counter_;
+
+ /// IDs which have been forward declared but have not been defined
+ std::unordered_set<uint32_t> unresolved_forward_ids_;
+
+ /// A map of operand IDs and their names defined by the OpName instruction
+ std::map<uint32_t, std::string> operand_names_;
+
+ /// The section of the code being processed
+ ModuleLayoutSection current_layout_section_;
+
+ /// A list of functions in the module
+ std::list<Function> module_functions_;
+
+ /// Mask of the capabilities available in the module
+ spv_capability_mask_t
+ module_capabilities_; /// Module's declared capabilities.
+
+ /// Definitions and uses of all the IDs in the module.
+ UseDefTracker usedefs_;
+
+ /// IDs that are entry points, ie, arguments to OpEntryPoint.
+ std::vector<uint32_t> entry_points_;
+
+ AssemblyGrammar grammar_;
+
+ SpvAddressingModel addressing_model_;
+ SpvMemoryModel memory_model_;
+
+ /// NOTE: See correspoding getter functions
+ bool in_function_;
+};
+
+} /// namespace libspirv
+
+#endif /// LIBSPIRV_VAL_VALIDATIONSTATE_H_
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+#include "validate.h"
+
#include <cassert>
#include <cstdio>
#include <string>
#include <vector>
-#include "validate.h"
-#include "validate_passes.h"
-
#include "binary.h"
#include "diagnostic.h"
#include "instruction.h"
#include "spirv-tools/libspirv.h"
#include "spirv_constant.h"
#include "spirv_endian.h"
+#include "val/Construct.h"
+#include "val/Function.h"
+#include "val/ValidationState.h"
using std::function;
using std::ostream_iterator;
default:
break;
}
+
}
// Collects use-def info about an instruction's IDs.
#include "spirv-tools/libspirv.h"
#include "spirv_definition.h"
#include "table.h"
-
-#define MSG(msg) \
- do { \
- libspirv::message(__FILE__, size_t(__LINE__), msg); \
- } while (0)
-
-#define SHOW(exp) \
- do { \
- libspirv::message(__FILE__, size_t(__LINE__), #exp, (exp)); \
- } while (0)
+#include "val/BasicBlock.h"
// Structures
-// Info about a result ID.
-typedef struct spv_id_info_t {
- // Id value.
- uint32_t id;
- // Type id, or 0 if no type.
- uint32_t type_id;
- // Opcode of the instruction defining the id.
- SpvOp opcode;
- // Binary words of the instruction defining the id.
- std::vector<uint32_t> words;
-} spv_id_info_t;
-
namespace libspirv {
-void message(std::string file, size_t line, std::string name);
-
-template <typename T>
-void message(std::string file, size_t line, std::string name, T val) {
- std::cout << file << ":" << line << ": " << name << " " << val << std::endl;
-}
-
-/// This enum represents the sections of a SPIRV module. See section 2.4
-/// of the SPIRV spec for additional details of the order. The enumerant values
-/// are in the same order as the vector returned by GetModuleOrder
-enum ModuleLayoutSection {
- kLayoutCapabilities, // < Section 2.4 #1
- kLayoutExtensions, // < Section 2.4 #2
- kLayoutExtInstImport, // < Section 2.4 #3
- kLayoutMemoryModel, // < Section 2.4 #4
- kLayoutEntryPoint, // < Section 2.4 #5
- kLayoutExecutionMode, // < Section 2.4 #6
- kLayoutDebug1, // < Section 2.4 #7 > 1
- kLayoutDebug2, // < Section 2.4 #7 > 2
- kLayoutAnnotations, // < Section 2.4 #8
- kLayoutTypes, // < Section 2.4 #9
- kLayoutFunctionDeclarations, // < Section 2.4 #10
- kLayoutFunctionDefinitions // < Section 2.4 #11
-};
-
-enum class FunctionDecl {
- kFunctionDeclUnknown, // < Unknown function declaration
- kFunctionDeclDeclaration, // < Function declaration
- kFunctionDeclDefinition // < Function definition
-};
-
class ValidationState_t;
-class Function;
-
-// This class represents a basic block in a SPIR-V module
-class BasicBlock {
- public:
- /// Constructor for a BasicBlock
- ///
- /// @param[in] id The ID of the basic block
- explicit BasicBlock(uint32_t id);
-
- /// Returns the id of the BasicBlock
- uint32_t get_id() const { return id_; }
-
- /// Returns the predecessors of the BasicBlock
- const std::vector<BasicBlock*>& get_predecessors() const {
- return predecessors_;
- }
-
- /// Returns the predecessors of the BasicBlock
- std::vector<BasicBlock*>& get_predecessors() { return predecessors_; }
-
- /// Returns the successors of the BasicBlock
- const std::vector<BasicBlock*>& get_successors() const { return successors_; }
-
- /// Returns the successors of the BasicBlock
- std::vector<BasicBlock*>& get_successors() { return successors_; }
-
- /// Returns true if the block should be reachable in the CFG
- bool is_reachable() const { return reachable_; }
-
- void set_reachability(bool reachability) { reachable_ = reachability; }
-
- /// Sets the immedate dominator of this basic block
- ///
- /// @param[in] dom_block The dominator block
- void SetImmediateDominator(BasicBlock* dom_block);
-
- /// Returns the immedate dominator of this basic block
- BasicBlock* GetImmediateDominator();
-
- /// Returns the immedate dominator of this basic block
- const BasicBlock* GetImmediateDominator() const;
-
- /// Ends the block without a successor
- void RegisterBranchInstruction(SpvOp branch_instruction);
-
- /// Adds @p next BasicBlocks as successors of this BasicBlock
- void RegisterSuccessors(std::vector<BasicBlock*> next = {});
-
- /// Returns true if the id of the BasicBlock matches
- bool operator==(const BasicBlock& other) const { return other.id_ == id_; }
-
- /// Returns true if the id of the BasicBlock matches
- bool operator==(const uint32_t& id) const { return id == id_; }
-
- /// @brief A BasicBlock dominator iterator class
- ///
- /// This iterator will iterate over the dominators of the block
- class DominatorIterator
- : public std::iterator<std::forward_iterator_tag, BasicBlock*> {
- public:
- /// @brief Constructs the end of dominator iterator
- ///
- /// This will create an iterator which will represent the element
- /// before the root node of the dominator tree
- DominatorIterator();
-
- /// @brief Constructs an iterator for the given block which points to
- /// @p block
- ///
- /// @param block The block which is referenced by the iterator
- explicit DominatorIterator(const BasicBlock* block);
-
- /// @brief Advances the iterator
- DominatorIterator& operator++();
-
- /// @brief Returns the current element
- const BasicBlock*& operator*();
-
- friend bool operator==(const DominatorIterator& lhs,
- const DominatorIterator& rhs);
-
- private:
- const BasicBlock* current_;
- };
-
- /// Returns an iterator which points to the current block
- const DominatorIterator dom_begin() const;
- DominatorIterator dom_begin();
-
- /// Returns an iterator which points to one element past the first block
- const DominatorIterator dom_end() const;
- DominatorIterator dom_end();
-
- private:
- /// Id of the BasicBlock
- const uint32_t id_;
-
- /// Pointer to the immediate dominator of the BasicBlock
- BasicBlock* immediate_dominator_;
-
- /// The set of predecessors of the BasicBlock
- std::vector<BasicBlock*> predecessors_;
-
- /// The set of successors of the BasicBlock
- std::vector<BasicBlock*> successors_;
-
- SpvOp branch_instruction_;
-
- bool reachable_;
-};
-
-/// @brief Returns true if the iterators point to the same element or if both
-/// iterators point to the @p dom_end block
-bool operator==(const BasicBlock::DominatorIterator& lhs,
- const BasicBlock::DominatorIterator& rhs);
-
-/// @brief Returns true if the iterators point to different elements and they
-/// do not both point to the @p dom_end block
-bool operator!=(const BasicBlock::DominatorIterator& lhs,
- const BasicBlock::DominatorIterator& rhs);
-
-/// @brief This class tracks the CFG constructs as defined in the SPIR-V spec
-class CFConstruct {
- // Universal Limit of ResultID + 1
- static const uint32_t kInitialValue = 0x400000;
-
- public:
- CFConstruct(BasicBlock* header_block, BasicBlock* merge_block,
- BasicBlock* continue_block = nullptr)
- : header_block_(header_block),
- merge_block_(merge_block),
- continue_block_(continue_block) {}
-
- const BasicBlock* get_header() const { return header_block_; }
- const BasicBlock* get_merge() const { return merge_block_; }
- const BasicBlock* get_continue() const { return continue_block_; }
-
- BasicBlock* get_header() { return header_block_; }
- BasicBlock* get_merge() { return merge_block_; }
- BasicBlock* get_continue() { return continue_block_; }
-
- private:
- BasicBlock* header_block_; ///< The header block of a loop or selection
- BasicBlock* merge_block_; ///< The merge block of a loop or selection
- BasicBlock* continue_block_; ///< The continue block of a loop block
-};
-
-// This class manages all function declaration and definitions in a module. It
-// handles the state and id information while parsing a function in the SPIR-V
-// binary.
-class Function {
- public:
- Function(uint32_t id, uint32_t result_type_id,
- SpvFunctionControlMask function_control, uint32_t function_type_id,
- ValidationState_t& module);
-
- /// Registers a function parameter in the current function
- /// @return Returns SPV_SUCCESS if the call was successful
- spv_result_t RegisterFunctionParameter(uint32_t id, uint32_t type_id);
-
- /// Sets the declaration type of the current function
- /// @return Returns SPV_SUCCESS if the call was successful
- spv_result_t RegisterSetFunctionDeclType(FunctionDecl type);
-
- // Registers a block in the current function. Subsequent block instructions
- // will target this block
- // @param id The ID of the label of the block
- /// @return Returns SPV_SUCCESS if the call was successful
- spv_result_t RegisterBlock(uint32_t id, bool is_definition = true);
-
- /// Registers a variable in the current block
- ///
- /// @param[in] type_id The type ID of the varaible
- /// @param[in] id The ID of the varaible
- /// @param[in] storage The storage of the variable
- /// @param[in] init_id The initializer ID of the variable
- ///
- /// @return Returns SPV_SUCCESS if the call was successful
- spv_result_t RegisterBlockVariable(uint32_t type_id, uint32_t id,
- SpvStorageClass storage, uint32_t init_id);
-
- /// Registers a loop merge construct in the function
- ///
- /// @param[in] merge_id The merge block ID of the loop
- /// @param[in] continue_id The continue block ID of the loop
- ///
- /// @return Returns SPV_SUCCESS if the call was successful
- spv_result_t RegisterLoopMerge(uint32_t merge_id, uint32_t continue_id);
-
- /// Registers a selection merge construct in the function
- /// @return Returns SPV_SUCCESS if the call was successful
- spv_result_t RegisterSelectionMerge(uint32_t merge_id);
-
- /// Registers the end of the block
- ///
- /// @param[in] successors_list A list of ids to the blocks successors
- /// @param[in] branch_instruction the branch instruction that ended the block
- void RegisterBlockEnd(std::vector<uint32_t> successors_list,
- SpvOp branch_instruction);
-
- /// Returns true if the \p merge_block_id is a merge block
- bool IsMergeBlock(uint32_t merge_block_id) const;
-
- /// Returns true if the \p id is the first block of this function
- bool IsFirstBlock(uint32_t id) const;
-
- /// Returns the first block of the current function
- const BasicBlock* get_first_block() const;
-
- /// Returns the first block of the current function
- BasicBlock* get_first_block();
-
- /// Returns a vector of all the blocks in the function
- const std::vector<BasicBlock*>& get_blocks() const;
-
- /// Returns a vector of all the blocks in the function
- std::vector<BasicBlock*>& get_blocks();
-
- /// Returns a list of all the cfg constructs in the function
- const std::list<CFConstruct>& get_constructs() const;
-
- /// Returns a list of all the cfg constructs in the function
- std::list<CFConstruct>& get_constructs();
-
- // Returns the number of blocks in the current function being parsed
- size_t get_block_count() const;
-
- /// Returns the id of the funciton
- uint32_t get_id() const { return id_; }
-
- // Returns the number of blocks in the current function being parsed
- size_t get_undefined_block_count() const;
- const std::unordered_set<uint32_t>& get_undefined_blocks() const {
- return undefined_blocks_;
- }
-
- /// Returns the block that is currently being parsed in the binary
- BasicBlock* get_current_block();
-
- /// Returns the block that is currently being parsed in the binary
- const BasicBlock* get_current_block() const;
-
- /// Prints a GraphViz digraph of the CFG of the current funciton
- void printDotGraph() const;
-
- /// Prints a directed graph of the CFG of the current funciton
- void printBlocks() const;
-
- private:
- /// Parent module
- ValidationState_t& module_;
-
- /// The result id of the OpLabel that defined this block
- uint32_t id_;
-
- /// The type of the function
- uint32_t function_type_id_;
-
- /// The type of the return value
- uint32_t result_type_id_;
-
- /// The control fo the funciton
- SpvFunctionControlMask function_control_;
-
- /// The type of declaration of each function
- FunctionDecl declaration_type_;
-
- /// The blocks in the function mapped by block ID
- std::unordered_map<uint32_t, BasicBlock> blocks_;
-
- /// A list of blocks in the order they appeared in the binary
- std::vector<BasicBlock*> ordered_blocks_;
-
- /// Blocks which are forward referenced by blocks but not defined
- std::unordered_set<uint32_t> undefined_blocks_;
-
- /// The block that is currently being parsed
- BasicBlock* current_block_;
-
- /// The constructs that are available in this function
- std::list<CFConstruct> cfg_constructs_;
-
- /// The variable IDs of the functions
- std::vector<uint32_t> variable_ids_;
-
- /// The function parameter ids of the functions
- std::vector<uint32_t> parameter_ids_;
-};
-
-class ValidationState_t {
- public:
- ValidationState_t(spv_diagnostic* diagnostic,
- const spv_const_context context);
-
- // Forward declares the id in the module
- spv_result_t forwardDeclareId(uint32_t id);
-
- // Removes a forward declared ID if it has been defined
- spv_result_t removeIfForwardDeclared(uint32_t id);
-
- // Assigns a name to an ID
- void assignNameToId(uint32_t id, std::string name);
-
- // Returns a string representation of the ID in the format <id>[Name] where
- // the <id> is the numeric valid of the id and the Name is a name assigned by
- // the OpName instruction
- std::string getIdName(uint32_t id) const;
-
- /// Like getIdName but does not display the id if the \p id has a name
- std::string getIdOrName(uint32_t id) const;
-
- // Returns the number of ID which have been forward referenced but not defined
- size_t unresolvedForwardIdCount() const;
-
- // Returns a list of unresolved forward ids.
- std::vector<uint32_t> unresolvedForwardIds() const;
-
- // Returns true if the id has been defined
- bool isDefinedId(uint32_t id) const;
-
- // Increments the instruction count. Used for diagnostic
- int incrementInstructionCount();
-
- // Returns the current layout section which is being processed
- ModuleLayoutSection getLayoutSection() const;
-
- // Increments the module_layout_order_section_
- void progressToNextLayoutSectionOrder();
-
- // Determines if the op instruction is part of the current section
- bool isOpcodeInCurrentLayoutSection(SpvOp op);
-
- libspirv::DiagnosticStream diag(spv_result_t error_code) const;
-
- // Returns the function states
- std::list<Function>& get_functions();
-
- // Returns the function states
- Function& get_current_function();
-
- // Returns true if the called after a function instruction but before the
- // function end instruction
- bool in_function_body() const;
-
- // Returns true if called after a label instruction but before a branch
- // instruction
- bool in_block() const;
-
- // Keeps track of ID definitions and uses.
- class UseDefTracker {
- public:
- void AddDef(const spv_id_info_t& def) { defs_[def.id] = def; }
-
- void AddUse(uint32_t id) { uses_.insert(id); }
-
- // Finds id's def, if it exists. If found, returns <true, def>. Otherwise,
- // returns <false, something>.
- std::pair<bool, spv_id_info_t> FindDef(uint32_t id) const {
- if (defs_.count(id) == 0) {
- return std::make_pair(false, spv_id_info_t{});
- } else {
- // We are in a const function, so we cannot use defs.operator[]().
- // Luckily we know the key exists, so defs_.at() won't throw an
- // exception.
- return std::make_pair(true, defs_.at(id));
- }
- }
-
- // Returns uses of IDs lacking defs.
- std::unordered_set<uint32_t> FindUsesWithoutDefs() const {
- auto diff = uses_;
- for (const auto d : defs_) diff.erase(d.first);
- return diff;
- }
-
- private:
- std::unordered_set<uint32_t> uses_;
- std::unordered_map<uint32_t, spv_id_info_t> defs_;
- };
-
- UseDefTracker& usedefs() { return usedefs_; }
- const UseDefTracker& usedefs() const { return usedefs_; }
-
- std::vector<uint32_t>& entry_points() { return entry_points_; }
- const std::vector<uint32_t>& entry_points() const { return entry_points_; }
-
- // Registers the capability and its dependent capabilities
- void RegisterCapability(SpvCapability cap);
-
- // Registers the function in the module. Subsequent instructions will be
- // called against this function
- spv_result_t RegisterFunction(uint32_t id, uint32_t ret_type_id,
- SpvFunctionControlMask function_control,
- uint32_t function_type_id);
-
- // Register a function end instruction
- spv_result_t RegisterFunctionEnd();
-
- // Returns true if the capability is enabled in the module.
- bool hasCapability(SpvCapability cap) const;
-
- // Returns true if any of the capabilities are enabled. Always true for
- // capabilities==0.
- bool HasAnyOf(spv_capability_mask_t capabilities) const;
-
- // Sets the addressing model of this module (logical/physical).
- void setAddressingModel(SpvAddressingModel am);
-
- // Returns the addressing model of this module, or Logical if uninitialized.
- SpvAddressingModel getAddressingModel() const;
-
- // Sets the memory model of this module.
- void setMemoryModel(SpvMemoryModel mm);
-
- // Returns the memory model of this module, or Simple if uninitialized.
- SpvMemoryModel getMemoryModel() const;
-
- AssemblyGrammar& grammar() { return grammar_; }
-
- private:
- spv_diagnostic* diagnostic_;
- // Tracks the number of instructions evaluated by the validator
- int instruction_counter_;
-
- // IDs which have been forward declared but have not been defined
- std::unordered_set<uint32_t> unresolved_forward_ids_;
-
- std::map<uint32_t, std::string> operand_names_;
-
- // The section of the code being processed
- ModuleLayoutSection current_layout_section_;
-
- std::list<Function> module_functions_;
-
- spv_capability_mask_t
- module_capabilities_; // Module's declared capabilities.
-
- // Definitions and uses of all the IDs in the module.
- UseDefTracker usedefs_;
-
- // IDs that are entry points, ie, arguments to OpEntryPoint.
- std::vector<uint32_t> entry_points_;
-
- AssemblyGrammar grammar_;
-
- SpvAddressingModel addressing_model_;
- SpvMemoryModel memory_model_;
-
- // NOTE: See correspoding getter functions
- bool in_function_;
-};
/// @brief Calculates dominator edges of a root basic block
///
/// @param[in] first_block the root or entry BasicBlock of a function
///
/// @return a set of dominator edges represented as a pair of blocks
-std::vector<std::pair<BasicBlock*, BasicBlock*> > CalculateDominators(
+std::vector<std::pair<BasicBlock*, BasicBlock*>> CalculateDominators(
const BasicBlock& first_block);
/// @brief Performs the Control Flow Graph checks
/// @return SPV_SUCCESS if no errors are found. SPV_ERROR_INVALID_CFG otherwise
spv_result_t PerformCfgChecks(ValidationState_t& _);
-// @brief Updates the immediate dominator for each of the block edges
-//
-// Updates the immediate dominator of the blocks for each of the edges
-// provided by the @p dom_edges parameter
-//
-// @param[in,out] dom_edges The edges of the dominator tree
+/// @brief Updates the immediate dominator for each of the block edges
+///
+/// Updates the immediate dominator of the blocks for each of the edges
+/// provided by the @p dom_edges parameter
+///
+/// @param[in,out] dom_edges The edges of the dominator tree
void UpdateImmediateDominators(
- std::vector<std::pair<BasicBlock*, BasicBlock*> >& dom_edges);
+ std::vector<std::pair<BasicBlock*, BasicBlock*>>& dom_edges);
-// @brief Prints all of the dominators of a BasicBlock
-//
-// @param[in] block The dominators of this block will be printed
+/// @brief Prints all of the dominators of a BasicBlock
+///
+/// @param[in] block The dominators of this block will be printed
void printDominatorList(BasicBlock& block);
+/// Performs logical layout validation as described in section 2.4 of the SPIR-V
+/// spec.
+spv_result_t ModuleLayoutPass(ValidationState_t& _,
+ const spv_parsed_instruction_t* inst);
+
+/// Performs Control Flow Graph validation of a module
+spv_result_t CfgPass(ValidationState_t& _,
+ const spv_parsed_instruction_t* inst);
+
+/// Performs SSA validation of a module
+spv_result_t SsaPass(ValidationState_t& _,
+ const spv_parsed_instruction_t* inst);
+
+/// Performs instruction validation.
+spv_result_t InstructionPass(ValidationState_t& _,
+ const spv_parsed_instruction_t* inst);
+
} // namespace libspirv
/// @brief Validate the ID usage of the instruction stream
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
#include "validate.h"
-#include "validate_passes.h"
-#include <algorithm>
#include <cassert>
+
+#include <algorithm>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
+#include "val/BasicBlock.h"
+#include "val/Construct.h"
+#include "val/Function.h"
+#include "val/ValidationState.h"
+
using std::find;
using std::get;
using std::make_pair;
}
// Check all headers dominate their merge blocks
- for (CFConstruct& construct : function.get_constructs()) {
+ for (Construct& construct : function.get_constructs()) {
auto header = construct.get_header();
auto merge = construct.get_merge();
// auto cont = construct.get_continue();
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+#include "validate.h"
+
#include <cassert>
+
#include <iostream>
#include <unordered_map>
#include <vector>
#include "instruction.h"
#include "opcode.h"
#include "spirv-tools/libspirv.h"
-#include "validate.h"
+#include "val/ValidationState.h"
#define spvCheck(condition, action) \
if (condition) { \
// Performs validation on instructions that appear inside of a SPIR-V block.
+#include "validate.h"
+
#include <cassert>
+
#include <sstream>
#include <string>
#include "diagnostic.h"
#include "opcode.h"
#include "spirv_definition.h"
-#include "validate_passes.h"
+#include "val/Function.h"
+#include "val/ValidationState.h"
using libspirv::AssemblyGrammar;
using libspirv::DiagnosticStream;
// Source code for logical layout validation as described in section 2.4
-#include "spirv-tools/libspirv.h"
-#include "validate_passes.h"
+#include "validate.h"
+
+#include <cassert>
#include "diagnostic.h"
#include "opcode.h"
#include "operand.h"
-
-#include <cassert>
+#include "spirv-tools/libspirv.h"
+#include "val/Function.h"
+#include "val/ValidationState.h"
using libspirv::ValidationState_t;
using libspirv::kLayoutMemoryModel;
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.
return _.diag(SPV_ERROR_INVALID_LAYOUT)
<< "Cannot declare a function in a function body";
}
- auto control_mask = static_cast<SpvFunctionControlMask>(inst->words[inst->operands[2].offset]);
- spvCheckReturn(_.RegisterFunction(
- inst->result_id, inst->type_id,
- control_mask,
- inst->words[inst->operands[3].offset]));
+ auto control_mask = static_cast<SpvFunctionControlMask>(
+ inst->words[inst->operands[2].offset]);
+ spvCheckReturn(
+ _.RegisterFunction(inst->result_id, inst->type_id, control_mask,
+ inst->words[inst->operands[3].offset]));
if (_.getLayoutSection() == kLayoutFunctionDefinitions)
spvCheckReturn(_.get_current_function().RegisterSetFunctionDeclType(
FunctionDecl::kFunctionDeclDefinition));
}
if (_.get_current_function().get_block_count() != 0) {
return _.diag(SPV_ERROR_INVALID_LAYOUT)
- << "Function parameters must only appear immediately after the "
+ << "Function parameters must only appear immediately after "
+ "the "
"function definition";
}
spvCheckReturn(_.get_current_function().RegisterFunctionParameter(
}
if (_.getLayoutSection() == kLayoutFunctionDeclarations) {
spvCheckReturn(_.get_current_function().RegisterSetFunctionDeclType(
- FunctionDecl::kFunctionDeclDeclaration));
+ FunctionDecl::kFunctionDeclDeclaration));
}
spvCheckReturn(_.RegisterFunctionEnd());
break;
}
return SPV_SUCCESS;
}
-}
+} /// namespace
namespace libspirv {
// TODO(umar): Check linkage capabilities for function declarations
} // switch(getLayoutSection())
return SPV_SUCCESS;
}
-}
+} /// namespace libspirv
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+#include "validate.h"
+
#include <functional>
+
#include "opcode.h"
-#include "validate_passes.h"
+#include "val/ValidationState.h"
using std::function;
using libspirv::ValidationState_t;
#include <iomanip>
-#include <source/assembly_grammar.h>
-#include <source/binary.h>
-#include <source/diagnostic.h>
-#include <source/opcode.h>
-#include <source/spirv_endian.h>
-#include <source/text.h>
-#include <source/text_handler.h>
-#include <source/validate.h>
-#include <spirv-tools/libspirv.h>
+#include "source/assembly_grammar.h"
+#include "source/binary.h"
+#include "source/diagnostic.h"
+#include "source/opcode.h"
+#include "source/spirv_endian.h"
+#include "source/text.h"
+#include "source/text_handler.h"
+#include "source/validate.h"
+#include "spirv-tools/libspirv.h"
#include <gtest/gtest.h>
// Unit tests for ValidationState_t.
-#include <gtest/gtest.h>
+#include "val/ValidationState.h"
+
#include <vector>
+#include "gtest/gtest.h"
#include "spirv/spirv.h"
-
-#include "source/validate.h"
+#include "val/Construct.h"
+#include "val/Function.h"
+#include "validate.h"
namespace {
using libspirv::ValidationState_t;