Split validate_types file into multiple classes
authorUmar Arshad <umar@arrayfire.com>
Thu, 2 Jun 2016 22:51:05 +0000 (18:51 -0400)
committerDavid Neto <dneto@google.com>
Wed, 8 Jun 2016 18:40:33 +0000 (14:40 -0400)
Creates separate files for the ValidationState, Function and
BasicBlock classes.

21 files changed:
CMakeLists.txt
source/CMakeLists.txt
source/diagnostic.cpp
source/diagnostic.h
source/val/BasicBlock.cpp [new file with mode: 0644]
source/val/BasicBlock.h [new file with mode: 0644]
source/val/Construct.cpp [moved from source/validate_passes.h with 62% similarity]
source/val/Construct.h [new file with mode: 0644]
source/val/Function.cpp [new file with mode: 0644]
source/val/Function.h [new file with mode: 0644]
source/val/ValidationState.cpp [moved from source/validate_types.cpp with 54% similarity]
source/val/ValidationState.h [new file with mode: 0644]
source/validate.cpp
source/validate.h
source/validate_cfg.cpp
source/validate_id.cpp
source/validate_instruction.cpp
source/validate_layout.cpp
source/validate_ssa.cpp
test/UnitSPIRV.h
test/ValidationState.cpp

index ba61667..bdb9f3b 100644 (file)
@@ -79,6 +79,8 @@ elseif(MSVC)
   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)
index c598846..ca06f28 100644 (file)
@@ -167,7 +167,10 @@ set(SPIRV_SOURCES
   ${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
@@ -184,7 +187,6 @@ set_source_files_properties(
   ${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}
index 9da7e38..61dd325 100644 (file)
@@ -148,4 +148,8 @@ spvResultToString(spv_result_t res) {
   return out;
 }
 
+void message(std::string file, size_t line, std::string name) {
+  std::cout << file << ":" << line << ": " << name << std::endl;
+}
+
 }  // namespace libspirv
index 38a35ea..8dd079b 100644 (file)
 
 #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)
@@ -104,6 +117,14 @@ class DiagnosticStream {
 
 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_
diff --git a/source/val/BasicBlock.cpp b/source/val/BasicBlock.cpp
new file mode 100644 (file)
index 0000000..55be3b8
--- /dev/null
@@ -0,0 +1,107 @@
+// 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
diff --git a/source/val/BasicBlock.h b/source/val/BasicBlock.h
new file mode 100644 (file)
index 0000000..0612db1
--- /dev/null
@@ -0,0 +1,157 @@
+// 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_
similarity index 62%
rename from source/validate_passes.h
rename to source/val/Construct.cpp
index de1d44a..91140bf 100644 (file)
 // 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
diff --git a/source/val/Construct.h b/source/val/Construct.h
new file mode 100644 (file)
index 0000000..ef5fae4
--- /dev/null
@@ -0,0 +1,58 @@
+// 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_
diff --git a/source/val/Function.cpp b/source/val/Function.cpp
new file mode 100644 (file)
index 0000000..dd8b386
--- /dev/null
@@ -0,0 +1,232 @@
+// 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
diff --git a/source/val/Function.h b/source/val/Function.h
new file mode 100644 (file)
index 0000000..a6a4304
--- /dev/null
@@ -0,0 +1,195 @@
+// 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_
similarity index 54%
rename from source/validate_types.cpp
rename to source/val/ValidationState.cpp
index bba979d..f937e2f 100644 (file)
 // 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) {
@@ -211,12 +190,6 @@ 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),
@@ -357,25 +330,6 @@ SpvMemoryModel ValidationState_t::getMemoryModel() const {
   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) {
@@ -402,244 +356,4 @@ spv_result_t ValidationState_t::RegisterFunctionEnd() {
   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
diff --git a/source/val/ValidationState.h b/source/val/ValidationState.h
new file mode 100644 (file)
index 0000000..41ccd99
--- /dev/null
@@ -0,0 +1,248 @@
+// 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_
index 800cc51..63f7fe0 100644 (file)
@@ -24,6 +24,8 @@
 // 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>
 
@@ -34,9 +36,6 @@
 #include <string>
 #include <vector>
 
-#include "validate.h"
-#include "validate_passes.h"
-
 #include "binary.h"
 #include "diagnostic.h"
 #include "instruction.h"
@@ -45,6 +44,9 @@
 #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;
@@ -123,6 +125,7 @@ void DebugInstructionPass(ValidationState_t& _,
     default:
       break;
   }
+
 }
 
 // Collects use-def info about an instruction's IDs.
index 35050cd..6f2b89e 100644 (file)
 #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
 ///
@@ -564,7 +60,7 @@ class ValidationState_t {
 /// @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
@@ -574,20 +70,37 @@ std::vector<std::pair<BasicBlock*, BasicBlock*> > CalculateDominators(
 /// @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
index 187d820..d6d1389 100644 (file)
 // 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;
@@ -242,7 +247,7 @@ spv_result_t PerformCfgChecks(ValidationState_t& _) {
     }
 
     // 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();
index ac68bc9..edb559b 100644 (file)
 // 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>
@@ -33,7 +36,7 @@
 #include "instruction.h"
 #include "opcode.h"
 #include "spirv-tools/libspirv.h"
-#include "validate.h"
+#include "val/ValidationState.h"
 
 #define spvCheck(condition, action) \
   if (condition) {                  \
index b86028d..6098fb6 100644 (file)
 
 // 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;
index 0b0b609..943fb59 100644 (file)
 
 // 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;
@@ -42,7 +44,6 @@ 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.
@@ -86,11 +87,11 @@ spv_result_t FunctionScopedInstructions(ValidationState_t& _,
           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));
@@ -104,7 +105,8 @@ spv_result_t FunctionScopedInstructions(ValidationState_t& _,
         }
         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(
@@ -128,7 +130,7 @@ spv_result_t FunctionScopedInstructions(ValidationState_t& _,
         }
         if (_.getLayoutSection() == kLayoutFunctionDeclarations) {
           spvCheckReturn(_.get_current_function().RegisterSetFunctionDeclType(
-                                                    FunctionDecl::kFunctionDeclDeclaration));
+              FunctionDecl::kFunctionDeclDeclaration));
         }
         spvCheckReturn(_.RegisterFunctionEnd());
         break;
@@ -174,7 +176,7 @@ spv_result_t FunctionScopedInstructions(ValidationState_t& _,
   }
   return SPV_SUCCESS;
 }
-}
+}  /// namespace
 
 namespace libspirv {
 // TODO(umar): Check linkage capabilities for function declarations
@@ -205,4 +207,4 @@ spv_result_t ModuleLayoutPass(ValidationState_t& _,
   }  // switch(getLayoutSection())
   return SPV_SUCCESS;
 }
-}
+}  /// namespace libspirv
index 38250bf..423221d 100644 (file)
 // 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;
index 967d998..93bf791 100644 (file)
 
 #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>
 
index 58d15b6..0ab90c7 100644 (file)
 
 // 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;