Home | History | Annotate | Download | only in val
      1 // Copyright (c) 2015-2016 The Khronos Group Inc.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 #ifndef LIBSPIRV_VAL_FUNCTION_H_
     16 #define LIBSPIRV_VAL_FUNCTION_H_
     17 
     18 #include <functional>
     19 #include <list>
     20 #include <unordered_map>
     21 #include <unordered_set>
     22 #include <vector>
     23 
     24 #include "spirv-tools/libspirv.h"
     25 #include "spirv/1.2/spirv.h"
     26 #include "val/basic_block.h"
     27 #include "val/construct.h"
     28 
     29 namespace libspirv {
     30 
     31 struct bb_constr_type_pair_hash {
     32   std::size_t operator()(
     33       const std::pair<const BasicBlock*, ConstructType>& p) const {
     34     auto h1 = std::hash<const BasicBlock*>{}(p.first);
     35     auto h2 = std::hash<std::underlying_type<ConstructType>::type>{}(
     36         static_cast<std::underlying_type<ConstructType>::type>(p.second));
     37     return (h1 ^ h2);
     38   }
     39 };
     40 
     41 enum class FunctionDecl {
     42   kFunctionDeclUnknown,      /// < Unknown function declaration
     43   kFunctionDeclDeclaration,  /// < Function declaration
     44   kFunctionDeclDefinition    /// < Function definition
     45 };
     46 
     47 /// This class manages all function declaration and definitions in a module. It
     48 /// handles the state and id information while parsing a function in the SPIR-V
     49 /// binary.
     50 class Function {
     51  public:
     52   Function(uint32_t id, uint32_t result_type_id,
     53            SpvFunctionControlMask function_control, uint32_t function_type_id);
     54 
     55   /// Registers a function parameter in the current function
     56   /// @return Returns SPV_SUCCESS if the call was successful
     57   spv_result_t RegisterFunctionParameter(uint32_t id, uint32_t type_id);
     58 
     59   /// Sets the declaration type of the current function
     60   /// @return Returns SPV_SUCCESS if the call was successful
     61   spv_result_t RegisterSetFunctionDeclType(FunctionDecl type);
     62 
     63   /// Registers a block in the current function. Subsequent block instructions
     64   /// will target this block
     65   /// @param id The ID of the label of the block
     66   /// @return Returns SPV_SUCCESS if the call was successful
     67   spv_result_t RegisterBlock(uint32_t id, bool is_definition = true);
     68 
     69   /// Registers a variable in the current block
     70   ///
     71   /// @param[in] type_id The type ID of the varaible
     72   /// @param[in] id      The ID of the varaible
     73   /// @param[in] storage The storage of the variable
     74   /// @param[in] init_id The initializer ID of the variable
     75   ///
     76   /// @return Returns SPV_SUCCESS if the call was successful
     77   spv_result_t RegisterBlockVariable(uint32_t type_id, uint32_t id,
     78                                      SpvStorageClass storage, uint32_t init_id);
     79 
     80   /// Registers a loop merge construct in the function
     81   ///
     82   /// @param[in] merge_id The merge block ID of the loop
     83   /// @param[in] continue_id The continue block ID of the loop
     84   ///
     85   /// @return Returns SPV_SUCCESS if the call was successful
     86   spv_result_t RegisterLoopMerge(uint32_t merge_id, uint32_t continue_id);
     87 
     88   /// Registers a selection merge construct in the function
     89   /// @return Returns SPV_SUCCESS if the call was successful
     90   spv_result_t RegisterSelectionMerge(uint32_t merge_id);
     91 
     92   /// Registers the end of the block
     93   ///
     94   /// @param[in] successors_list A list of ids to the block's successors
     95   /// @param[in] branch_instruction the branch instruction that ended the block
     96   void RegisterBlockEnd(std::vector<uint32_t> successors_list,
     97                         SpvOp branch_instruction);
     98 
     99   /// Registers the end of the function.  This is idempotent.
    100   void RegisterFunctionEnd();
    101 
    102   /// Returns true if the \p id block is the first block of this function
    103   bool IsFirstBlock(uint32_t id) const;
    104 
    105   /// Returns true if the \p merge_block_id is a BlockType of \p type
    106   bool IsBlockType(uint32_t merge_block_id, BlockType type) const;
    107 
    108   /// Returns a pair consisting of the BasicBlock with \p id and a bool
    109   /// which is true if the block has been defined, and false if it is
    110   /// declared but not defined. This function will return nullptr if the
    111   /// \p id was not declared and not defined at the current point in the binary
    112   std::pair<const BasicBlock*, bool> GetBlock(uint32_t id) const;
    113   std::pair<BasicBlock*, bool> GetBlock(uint32_t id);
    114 
    115   /// Returns the first block of the current function
    116   const BasicBlock* first_block() const;
    117 
    118   /// Returns the first block of the current function
    119   BasicBlock* first_block();
    120 
    121   /// Returns a vector of all the blocks in the function
    122   const std::vector<BasicBlock*>& ordered_blocks() const;
    123 
    124   /// Returns a vector of all the blocks in the function
    125   std::vector<BasicBlock*>& ordered_blocks();
    126 
    127   /// Returns a list of all the cfg constructs in the function
    128   const std::list<Construct>& constructs() const;
    129 
    130   /// Returns a list of all the cfg constructs in the function
    131   std::list<Construct>& constructs();
    132 
    133   /// Returns the number of blocks in the current function being parsed
    134   size_t block_count() const;
    135 
    136   /// Returns the id of the funciton
    137   uint32_t id() const { return id_; }
    138 
    139   /// Returns the number of blocks in the current function being parsed
    140   size_t undefined_block_count() const;
    141   const std::unordered_set<uint32_t>& undefined_blocks() const {
    142     return undefined_blocks_;
    143   }
    144 
    145   /// Returns the block that is currently being parsed in the binary
    146   BasicBlock* current_block();
    147 
    148   /// Returns the block that is currently being parsed in the binary
    149   const BasicBlock* current_block() const;
    150 
    151   // For dominance calculations, we want to analyze all the
    152   // blocks in the function, even in degenerate control flow cases
    153   // including unreachable blocks.  We therefore make an "augmented CFG"
    154   // which is the same as the ordinary CFG but adds:
    155   //  - A pseudo-entry node.
    156   //  - A pseudo-exit node.
    157   //  - A minimal set of edges so that a forward traversal from the
    158   //    pseudo-entry node will visit all nodes.
    159   //  - A minimal set of edges so that a backward traversal from the
    160   //    pseudo-exit node will visit all nodes.
    161   // In particular, the pseudo-entry node is the unique source of the
    162   // augmented CFG, and the psueo-exit node is the unique sink of the
    163   // augmented CFG.
    164 
    165   /// Returns the pseudo exit block
    166   BasicBlock* pseudo_entry_block() { return &pseudo_entry_block_; }
    167 
    168   /// Returns the pseudo exit block
    169   const BasicBlock* pseudo_entry_block() const { return &pseudo_entry_block_; }
    170 
    171   /// Returns the pseudo exit block
    172   BasicBlock* pseudo_exit_block() { return &pseudo_exit_block_; }
    173 
    174   /// Returns the pseudo exit block
    175   const BasicBlock* pseudo_exit_block() const { return &pseudo_exit_block_; }
    176 
    177   using GetBlocksFunction =
    178       std::function<const std::vector<BasicBlock*>*(const BasicBlock*)>;
    179   /// Returns the block successors function for the augmented CFG.
    180   GetBlocksFunction AugmentedCFGSuccessorsFunction() const;
    181   /// Like AugmentedCFGSuccessorsFunction, but also includes a forward edge from
    182   /// a loop header block to its continue target, if they are different blocks.
    183   GetBlocksFunction AugmentedCFGSuccessorsFunctionIncludingHeaderToContinueEdge() const;
    184   /// Returns the block predecessors function for the augmented CFG.
    185   GetBlocksFunction AugmentedCFGPredecessorsFunction() const;
    186 
    187   /// Returns the control flow nesting depth of the given basic block.
    188   /// This function only works when you have structured control flow.
    189   /// This function should only be called after the control flow constructs have
    190   /// been identified and dominators have been computed.
    191   int GetBlockDepth(BasicBlock* bb);
    192 
    193   /// Prints a GraphViz digraph of the CFG of the current funciton
    194   void PrintDotGraph() const;
    195 
    196   /// Prints a directed graph of the CFG of the current funciton
    197   void PrintBlocks() const;
    198 
    199  private:
    200   // Computes the representation of the augmented CFG.
    201   // Populates augmented_successors_map_ and augmented_predecessors_map_.
    202   void ComputeAugmentedCFG();
    203 
    204   // Adds a copy of the given Construct, and tracks it by its entry block.
    205   // Returns a reference to the stored construct.
    206   Construct& AddConstruct(const Construct& new_construct);
    207 
    208   // Returns a reference to the construct corresponding to the given entry
    209   // block.
    210   Construct& FindConstructForEntryBlock(const BasicBlock* entry_block,
    211                                         ConstructType t);
    212 
    213   /// The result id of the OpLabel that defined this block
    214   uint32_t id_;
    215 
    216   /// The type of the function
    217   uint32_t function_type_id_;
    218 
    219   /// The type of the return value
    220   uint32_t result_type_id_;
    221 
    222   /// The control fo the funciton
    223   SpvFunctionControlMask function_control_;
    224 
    225   /// The type of declaration of each function
    226   FunctionDecl declaration_type_;
    227 
    228   // Have we finished parsing this function?
    229   bool end_has_been_registered_;
    230 
    231   /// The blocks in the function mapped by block ID
    232   std::unordered_map<uint32_t, BasicBlock> blocks_;
    233 
    234   /// A list of blocks in the order they appeared in the binary
    235   std::vector<BasicBlock*> ordered_blocks_;
    236 
    237   /// Blocks which are forward referenced by blocks but not defined
    238   std::unordered_set<uint32_t> undefined_blocks_;
    239 
    240   /// The block that is currently being parsed
    241   BasicBlock* current_block_;
    242 
    243   /// A pseudo entry node used in dominance analysis.
    244   /// After the function end has been registered, the successor list of the
    245   /// pseudo entry node is the minimal set of nodes such that all nodes in the
    246   /// CFG can be reached by following successor lists.  That is, the successors
    247   /// will be:
    248   ///   - Any basic block without predecessors.  This includes the entry
    249   ///     block to the function.
    250   ///   - A single node from each otherwise unreachable cycle in the CFG, if
    251   ///     such cycles exist.
    252   /// The pseudo entry node does not appear in the predecessor or successor
    253   /// list of any ordinary block.
    254   /// It has no predecessors.
    255   /// It has Id 0.
    256   BasicBlock pseudo_entry_block_;
    257 
    258   /// A pseudo exit block used in dominance analysis.
    259   /// After the function end has been registered, the predecessor list of the
    260   /// pseudo exit node is the minimal set of nodes such that all nodes in the
    261   /// CFG can be reached by following predecessor lists.  That is, the
    262   /// predecessors will be:
    263   ///   - Any basic block without successors.  This includes any basic block
    264   ///     ending with an OpReturn, OpReturnValue or similar instructions.
    265   ///   - A single node from each otherwise unreachable cycle in the CFG, if
    266   ///     such cycles exist.
    267   /// The pseudo exit node does not appear in the predecessor or successor
    268   /// list of any ordinary block.
    269   /// It has no successors.
    270   BasicBlock pseudo_exit_block_;
    271 
    272   // Maps a block to its successors in the augmented CFG, if that set is
    273   // different from its successors in the ordinary CFG.
    274   std::unordered_map<const BasicBlock*, std::vector<BasicBlock*>>
    275       augmented_successors_map_;
    276   // Maps a block to its predecessors in the augmented CFG, if that set is
    277   // different from its predecessors in the ordinary CFG.
    278   std::unordered_map<const BasicBlock*, std::vector<BasicBlock*>>
    279       augmented_predecessors_map_;
    280 
    281   // Maps a structured loop header to its CFG successors and also its
    282   // continue target if that continue target is not the loop header
    283   // itself. This might have duplicates.
    284   std::unordered_map<const BasicBlock*, std::vector<BasicBlock*>>
    285       loop_header_successors_plus_continue_target_map_;
    286 
    287   /// The constructs that are available in this function
    288   std::list<Construct> cfg_constructs_;
    289 
    290   /// The variable IDs of the functions
    291   std::vector<uint32_t> variable_ids_;
    292 
    293   /// The function parameter ids of the functions
    294   std::vector<uint32_t> parameter_ids_;
    295 
    296   /// Maps a construct's entry block to the construct(s).
    297   /// Since a basic block may be the entry block of different types of
    298   /// constructs, the type of the construct should also be specified in order to
    299   /// get the unique construct.
    300   std::unordered_map<std::pair<const BasicBlock*, ConstructType>, Construct*,
    301                      libspirv::bb_constr_type_pair_hash>
    302       entry_block_to_construct_;
    303 
    304   /// This map provides the header block for a given merge block.
    305   std::unordered_map<BasicBlock*, BasicBlock*> merge_block_header_;
    306 
    307   /// Stores the control flow nesting depth of a given basic block
    308   std::unordered_map<BasicBlock*, int> block_depth_;
    309 };
    310 
    311 }  /// namespace libspirv
    312 
    313 #endif  /// LIBSPIRV_VAL_FUNCTION_H_
    314