aboutsummaryrefslogtreecommitdiff
path: root/source/val/function.h
diff options
context:
space:
mode:
Diffstat (limited to 'source/val/function.h')
-rw-r--r--source/val/function.h285
1 files changed, 285 insertions, 0 deletions
diff --git a/source/val/function.h b/source/val/function.h
new file mode 100644
index 00000000..bd993c79
--- /dev/null
+++ b/source/val/function.h
@@ -0,0 +1,285 @@
+// Copyright (c) 2015-2016 The Khronos Group Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef LIBSPIRV_VAL_FUNCTION_H_
+#define LIBSPIRV_VAL_FUNCTION_H_
+
+#include <functional>
+#include <list>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include "spirv-tools/libspirv.h"
+#include "spirv/1.1/spirv.h"
+#include "val/basic_block.h"
+#include "val/construct.h"
+
+namespace libspirv {
+
+enum class FunctionDecl {
+ kFunctionDeclUnknown, /// < Unknown function declaration
+ kFunctionDeclDeclaration, /// < Function declaration
+ kFunctionDeclDefinition /// < Function definition
+};
+
+/// 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);
+
+ /// 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 block's successors
+ /// @param[in] branch_instruction the branch instruction that ended the block
+ void RegisterBlockEnd(std::vector<uint32_t> successors_list,
+ SpvOp branch_instruction);
+
+ /// Registers the end of the function. This is idempotent.
+ void RegisterFunctionEnd();
+
+ /// Returns true if the \p id block is the first block of this function
+ bool IsFirstBlock(uint32_t id) const;
+
+ /// Returns true if the \p merge_block_id is a BlockType of \p type
+ bool IsBlockType(uint32_t merge_block_id, BlockType type) const;
+
+ /// Returns a pair consisting of the BasicBlock with \p id and a bool
+ /// which is true if the block has been defined, and false if it is
+ /// declared but not defined. This function will return nullptr if the
+ /// \p id was not declared and not defined at the current point in the binary
+ std::pair<const BasicBlock*, bool> GetBlock(uint32_t id) const;
+ std::pair<BasicBlock*, bool> GetBlock(uint32_t id);
+
+ /// Returns the first block of the current function
+ const BasicBlock* first_block() const;
+
+ /// Returns the first block of the current function
+ BasicBlock* first_block();
+
+ /// Returns a vector of all the blocks in the function
+ const std::vector<BasicBlock*>& ordered_blocks() const;
+
+ /// Returns a vector of all the blocks in the function
+ std::vector<BasicBlock*>& ordered_blocks();
+
+ /// Returns a list of all the cfg constructs in the function
+ const std::list<Construct>& constructs() const;
+
+ /// Returns a list of all the cfg constructs in the function
+ std::list<Construct>& constructs();
+
+ /// Returns the number of blocks in the current function being parsed
+ size_t block_count() const;
+
+ /// Returns the id of the funciton
+ uint32_t id() const { return id_; }
+
+ /// Returns the number of blocks in the current function being parsed
+ size_t undefined_block_count() const;
+ const std::unordered_set<uint32_t>& undefined_blocks() const {
+ return undefined_blocks_;
+ }
+
+ /// Returns the block that is currently being parsed in the binary
+ BasicBlock* current_block();
+
+ /// Returns the block that is currently being parsed in the binary
+ const BasicBlock* current_block() const;
+
+ // For dominance calculations, we want to analyze all the
+ // blocks in the function, even in degenerate control flow cases
+ // including unreachable blocks. We therefore make an "augmented CFG"
+ // which is the same as the ordinary CFG but adds:
+ // - A pseudo-entry node.
+ // - A pseudo-exit node.
+ // - A minimal set of edges so that a forward traversal from the
+ // pseudo-entry node will visit all nodes.
+ // - A minimal set of edges so that a backward traversal from the
+ // pseudo-exit node will visit all nodes.
+ // In particular, the pseudo-entry node is the unique source of the
+ // augmented CFG, and the psueo-exit node is the unique sink of the
+ // augmented CFG.
+
+ /// Returns the pseudo exit block
+ BasicBlock* pseudo_entry_block() { return &pseudo_entry_block_; }
+
+ /// Returns the pseudo exit block
+ const BasicBlock* pseudo_entry_block() const { return &pseudo_entry_block_; }
+
+ /// Returns the pseudo exit block
+ BasicBlock* pseudo_exit_block() { return &pseudo_exit_block_; }
+
+ /// Returns the pseudo exit block
+ const BasicBlock* pseudo_exit_block() const { return &pseudo_exit_block_; }
+
+ using GetBlocksFunction =
+ std::function<const std::vector<BasicBlock*>*(const BasicBlock*)>;
+ /// Returns the block successors function for the augmented CFG.
+ GetBlocksFunction AugmentedCFGSuccessorsFunction() const;
+ /// Like AugmentedCFGSuccessorsFunction, but also includes a forward edge from
+ /// a loop header block to its continue target, if they are different blocks.
+ GetBlocksFunction AugmentedCFGSuccessorsFunctionIncludingHeaderToContinueEdge() const;
+ /// Returns the block predecessors function for the augmented CFG.
+ GetBlocksFunction AugmentedCFGPredecessorsFunction() 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:
+ // Computes the representation of the augmented CFG.
+ // Populates augmented_successors_map_ and augmented_predecessors_map_.
+ void ComputeAugmentedCFG();
+
+ // Adds a copy of the given Construct, and tracks it by its entry block.
+ // Returns a reference to the stored construct.
+ Construct& AddConstruct(const Construct& new_construct);
+
+ // Returns a reference to the construct corresponding to the given entry
+ // block.
+ Construct& FindConstructForEntryBlock(const BasicBlock* entry_block);
+
+ /// 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_;
+
+ // Have we finished parsing this function?
+ bool end_has_been_registered_;
+
+ /// 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_;
+
+ /// A pseudo entry node used in dominance analysis.
+ /// After the function end has been registered, the successor list of the
+ /// pseudo entry node is the minimal set of nodes such that all nodes in the
+ /// CFG can be reached by following successor lists. That is, the successors
+ /// will be:
+ /// - Any basic block without predecessors. This includes the entry
+ /// block to the function.
+ /// - A single node from each otherwise unreachable cycle in the CFG, if
+ /// such cycles exist.
+ /// The pseudo entry node does not appear in the predecessor or successor
+ /// list of any ordinary block.
+ /// It has no predecessors.
+ /// It has Id 0.
+ BasicBlock pseudo_entry_block_;
+
+ /// A pseudo exit block used in dominance analysis.
+ /// After the function end has been registered, the predecessor list of the
+ /// pseudo exit node is the minimal set of nodes such that all nodes in the
+ /// CFG can be reached by following predecessor lists. That is, the
+ /// predecessors will be:
+ /// - Any basic block without successors. This includes any basic block
+ /// ending with an OpReturn, OpReturnValue or similar instructions.
+ /// - A single node from each otherwise unreachable cycle in the CFG, if
+ /// such cycles exist.
+ /// The pseudo exit node does not appear in the predecessor or successor
+ /// list of any ordinary block.
+ /// It has no successors.
+ BasicBlock pseudo_exit_block_;
+
+ // Maps a block to its successors in the augmented CFG, if that set is
+ // different from its successors in the ordinary CFG.
+ std::unordered_map<const BasicBlock*, std::vector<BasicBlock*>>
+ augmented_successors_map_;
+ // Maps a block to its predecessors in the augmented CFG, if that set is
+ // different from its predecessors in the ordinary CFG.
+ std::unordered_map<const BasicBlock*, std::vector<BasicBlock*>>
+ augmented_predecessors_map_;
+
+ // Maps a structured loop header to its CFG successors and also its
+ // continue target if that continue target is not the loop header
+ // itself. This might have duplicates.
+ std::unordered_map<const BasicBlock*, std::vector<BasicBlock*>>
+ loop_header_successors_plus_continue_target_map_;
+
+ /// 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_;
+
+ /// Maps a construct's entry block to the construct.
+ std::unordered_map<const BasicBlock*, Construct*> entry_block_to_construct_;
+};
+
+} /// namespace libspirv
+
+#endif /// LIBSPIRV_VAL_FUNCTION_H_