Home | History | Annotate | Download | only in ir
      1 /*
      2  * Copyright (C) 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 
     18 #ifndef ART_COMPILER_SEA_IR_IR_SEA_H_
     19 #define ART_COMPILER_SEA_IR_IR_SEA_H_
     20 
     21 #include <set>
     22 #include <map>
     23 
     24 #include "utils/scoped_hashtable.h"
     25 #include "gtest/gtest_prod.h"
     26 #include "dex_file.h"
     27 #include "dex_instruction.h"
     28 #include "sea_ir/ir/instruction_tools.h"
     29 #include "sea_ir/ir/instruction_nodes.h"
     30 
     31 namespace sea_ir {
     32 
     33 // Reverse post-order numbering constants
     34 enum RegionNumbering {
     35   NOT_VISITED = -1,
     36   VISITING = -2
     37 };
     38 
     39 class TypeInference;
     40 class CodeGenData;
     41 
     42 class Region;
     43 class InstructionNode;
     44 class PhiInstructionNode;
     45 class SignatureNode;
     46 
     47 // A SignatureNode is a declaration of one parameter in the function signature.
     48 // This class is used to provide place-holder definitions to which instructions
     49 // can return from the GetSSAUses() calls, instead of having missing SSA edges.
     50 class SignatureNode: public InstructionNode {
     51  public:
     52   // Creates a new signature node representing the initial definition of the
     53   // register @register_no which is the @signature_position-th argument to the method.
     54   explicit SignatureNode(unsigned int register_no, unsigned int signature_position):
     55     InstructionNode(NULL), register_no_(register_no), position_(signature_position) { }
     56 
     57   int GetResultRegister() const {
     58     return register_no_;
     59   }
     60 
     61   unsigned int GetPositionInSignature() const {
     62     return position_;
     63   }
     64 
     65   std::vector<int> GetUses() const {
     66     return std::vector<int>();
     67   }
     68 
     69   void Accept(IRVisitor* v) {
     70     v->Visit(this);
     71     v->Traverse(this);
     72   }
     73 
     74  private:
     75   const unsigned int register_no_;
     76   const unsigned int position_;     // The position of this parameter node is
     77                                     // in the function parameter list.
     78 };
     79 
     80 class PhiInstructionNode: public InstructionNode {
     81  public:
     82   explicit PhiInstructionNode(int register_no):
     83     InstructionNode(NULL), register_no_(register_no), definition_edges_() {}
     84   // Returns the register on which this phi-function is used.
     85   int GetRegisterNumber() const {
     86     return register_no_;
     87   }
     88 
     89   // Renames the use of @reg_no to refer to the instruction @definition.
     90   // Phi-functions are different than normal instructions in that they
     91   // have multiple predecessor regions; this is why RenameToSSA has
     92   // the additional parameter specifying that @parameter_id is the incoming
     93   // edge for @definition, essentially creating SSA form.
     94   void RenameToSSA(int reg_no, InstructionNode* definition, unsigned int predecessor_id) {
     95     DCHECK(NULL != definition) << "Tried to rename to SSA using a NULL definition for "
     96         << StringId() << " register " << reg_no;
     97     if (definition_edges_.size() < predecessor_id+1) {
     98       definition_edges_.resize(predecessor_id+1, NULL);
     99     }
    100     if (NULL == definition_edges_.at(predecessor_id)) {
    101       definition_edges_[predecessor_id] = new std::vector<InstructionNode*>();
    102     }
    103     definition_edges_[predecessor_id]->push_back(definition);
    104     definition->AddSSAUse(this);
    105   }
    106 
    107   // Returns the ordered set of Instructions that define the input operands of this instruction.
    108   // Precondition: SeaGraph.ConvertToSSA().
    109   std::vector<InstructionNode*> GetSSAProducers() {
    110     std::vector<InstructionNode*> producers;
    111     for (std::vector<std::vector<InstructionNode*>*>::const_iterator
    112         cit = definition_edges_.begin(); cit != definition_edges_.end(); cit++) {
    113       producers.insert(producers.end(), (*cit)->begin(), (*cit)->end());
    114     }
    115     return producers;
    116   }
    117 
    118   // Returns the instruction that defines the phi register from predecessor
    119   // on position @predecessor_pos. Note that the return value is vector<> just
    120   // for consistency with the return value of GetSSAUses() on regular instructions,
    121   // The returned vector should always have a single element because the IR is SSA.
    122   std::vector<InstructionNode*>* GetSSAUses(int predecessor_pos) {
    123     return definition_edges_.at(predecessor_pos);
    124   }
    125 
    126   void Accept(IRVisitor* v) {
    127     v->Visit(this);
    128     v->Traverse(this);
    129   }
    130 
    131  private:
    132   int register_no_;
    133   // This vector has one entry for each predecessors, each with a single
    134   // element, storing the id of the instruction that defines the register
    135   // corresponding to this phi function.
    136   std::vector<std::vector<InstructionNode*>*> definition_edges_;
    137 };
    138 
    139 // This class corresponds to a basic block in traditional compiler IRs.
    140 // The dataflow analysis relies on this class both during execution and
    141 // for storing its results.
    142 class Region : public SeaNode {
    143  public:
    144   explicit Region():
    145     SeaNode(), successors_(), predecessors_(), reaching_defs_size_(0),
    146     rpo_number_(NOT_VISITED), idom_(NULL), idominated_set_(), df_(), phi_set_() {
    147     string_id_ = "cluster_" + string_id_;
    148   }
    149   // Adds @instruction as an instruction node child in the current region.
    150   void AddChild(sea_ir::InstructionNode* instruction);
    151   // Returns the last instruction node child of the current region.
    152   // This child has the CFG successors pointing to the new regions.
    153   SeaNode* GetLastChild() const;
    154   // Returns all the child instructions of this region, in program order.
    155   std::vector<InstructionNode*>* GetInstructions() {
    156     return &instructions_;
    157   }
    158 
    159   // Computes Downward Exposed Definitions for the current node.
    160   void ComputeDownExposedDefs();
    161   const std::map<int, sea_ir::InstructionNode*>* GetDownExposedDefs() const;
    162   // Performs one iteration of the reaching definitions algorithm
    163   // and returns true if the reaching definitions set changed.
    164   bool UpdateReachingDefs();
    165   // Returns the set of reaching definitions for the current region.
    166   std::map<int, std::set<sea_ir::InstructionNode*>* >* GetReachingDefs();
    167 
    168   void SetRPO(int rpo) {
    169     rpo_number_ = rpo;
    170   }
    171 
    172   int GetRPO() {
    173     return rpo_number_;
    174   }
    175 
    176   void SetIDominator(Region* dom) {
    177     idom_ = dom;
    178   }
    179 
    180   Region* GetIDominator() const {
    181     return idom_;
    182   }
    183 
    184   void AddToIDominatedSet(Region* dominated) {
    185     idominated_set_.insert(dominated);
    186   }
    187 
    188   const std::set<Region*>* GetIDominatedSet() {
    189     return &idominated_set_;
    190   }
    191   // Adds @df_reg to the dominance frontier of the current region.
    192   void AddToDominanceFrontier(Region* df_reg) {
    193     df_.insert(df_reg);
    194   }
    195   // Returns the dominance frontier of the current region.
    196   // Preconditions: SeaGraph.ComputeDominanceFrontier()
    197   std::set<Region*>* GetDominanceFrontier() {
    198     return &df_;
    199   }
    200   // Returns true if the region contains a phi function for @reg_no.
    201   bool ContainsPhiFor(int reg_no) {
    202     return (phi_set_.end() != phi_set_.find(reg_no));
    203   }
    204   // Returns the phi-functions from the region.
    205   std::vector<PhiInstructionNode*>* GetPhiNodes() {
    206     return &phi_instructions_;
    207   }
    208   // Adds a phi-function for @reg_no to this region.
    209   // Note: The insertion order does not matter, as phi-functions
    210   //       are conceptually executed at the same time.
    211   bool InsertPhiFor(int reg_no);
    212   // Sets the phi-function uses to be as defined in @scoped_table for predecessor @@predecessor.
    213   void SetPhiDefinitionsForUses(const utils::ScopedHashtable<int, InstructionNode*>* scoped_table,
    214       Region* predecessor);
    215 
    216   void Accept(IRVisitor* v) {
    217     v->Visit(this);
    218     v->Traverse(this);
    219   }
    220 
    221   void AddSuccessor(Region* successor) {
    222     DCHECK(successor) << "Tried to add NULL successor to SEA node.";
    223     successors_.push_back(successor);
    224     return;
    225   }
    226   void AddPredecessor(Region* predecessor) {
    227     DCHECK(predecessor) << "Tried to add NULL predecessor to SEA node.";
    228     predecessors_.push_back(predecessor);
    229   }
    230 
    231   std::vector<sea_ir::Region*>* GetSuccessors() {
    232     return &successors_;
    233   }
    234   std::vector<sea_ir::Region*>* GetPredecessors() {
    235     return &predecessors_;
    236   }
    237 
    238  private:
    239   std::vector<sea_ir::Region*> successors_;    // CFG successor nodes (regions)
    240   std::vector<sea_ir::Region*> predecessors_;  // CFG predecessor nodes (instructions/regions)
    241   std::vector<sea_ir::InstructionNode*> instructions_;
    242   std::map<int, sea_ir::InstructionNode*> de_defs_;
    243   std::map<int, std::set<sea_ir::InstructionNode*>* > reaching_defs_;
    244   int reaching_defs_size_;
    245   int rpo_number_;                              // reverse postorder number of the region
    246   // Immediate dominator node.
    247   Region* idom_;
    248   // The set of nodes immediately dominated by the region.
    249   std::set<Region*> idominated_set_;
    250   // Records the dominance frontier.
    251   std::set<Region*> df_;
    252   // Records the set of register numbers that have phi nodes in this region.
    253   std::set<int> phi_set_;
    254   std::vector<PhiInstructionNode*> phi_instructions_;
    255 };
    256 
    257 // A SeaGraph instance corresponds to a source code function.
    258 // Its main point is to encapsulate the SEA IR representation of it
    259 // and acts as starting point for visitors (ex: during code generation).
    260 class SeaGraph: IVisitable {
    261  public:
    262   static SeaGraph* GetGraph(const art::DexFile&);
    263 
    264   CodeGenData* CompileMethod(const std::string& function_name,
    265       const art::DexFile::CodeItem* code_item, uint16_t class_def_idx,
    266       uint32_t method_idx, uint32_t method_access_flags, const art::DexFile& dex_file);
    267   // Returns all regions corresponding to this SeaGraph.
    268   std::vector<Region*>* GetRegions() {
    269     return &regions_;
    270   }
    271   // Recursively computes the reverse postorder value for @crt_bb and successors.
    272   static void ComputeRPO(Region* crt_bb, int& crt_rpo);
    273   // Returns the "lowest common ancestor" of @i and @j in the dominator tree.
    274   static Region* Intersect(Region* i, Region* j);
    275   // Returns the vector of parameters of the function.
    276   std::vector<SignatureNode*>* GetParameterNodes() {
    277     return &parameters_;
    278   }
    279 
    280   const art::DexFile* GetDexFile() const {
    281     return &dex_file_;
    282   }
    283 
    284   virtual void Accept(IRVisitor* visitor) {
    285     visitor->Initialize(this);
    286     visitor->Visit(this);
    287     visitor->Traverse(this);
    288   }
    289 
    290   TypeInference* ti_;
    291   uint16_t class_def_idx_;
    292   uint32_t method_idx_;
    293   uint32_t method_access_flags_;
    294 
    295  protected:
    296   explicit SeaGraph(const art::DexFile& df);
    297   virtual ~SeaGraph() { }
    298 
    299  private:
    300   FRIEND_TEST(RegionsTest, Basics);
    301   // Registers @childReg as a region belonging to the SeaGraph instance.
    302   void AddRegion(Region* childReg);
    303   // Returns new region and registers it with the  SeaGraph instance.
    304   Region* GetNewRegion();
    305   // Adds a (formal) parameter node to the vector of parameters of the function.
    306   void AddParameterNode(SignatureNode* parameterNode) {
    307     parameters_.push_back(parameterNode);
    308   }
    309   // Adds a CFG edge from @src node to @dst node.
    310   void AddEdge(Region* src, Region* dst) const;
    311   // Builds the non-SSA sea-ir representation of the function @code_item from @dex_file
    312   // with class id @class_def_idx and method id @method_idx.
    313   void BuildMethodSeaGraph(const art::DexFile::CodeItem* code_item,
    314       const art::DexFile& dex_file, uint16_t class_def_idx,
    315       uint32_t method_idx, uint32_t method_access_flags);
    316   // Computes immediate dominators for each region.
    317   // Precondition: ComputeMethodSeaGraph()
    318   void ComputeIDominators();
    319   // Computes Downward Exposed Definitions for all regions in the graph.
    320   void ComputeDownExposedDefs();
    321   // Computes the reaching definitions set following the equations from
    322   // Cooper & Torczon, "Engineering a Compiler", second edition, page 491.
    323   // Precondition: ComputeDEDefs()
    324   void ComputeReachingDefs();
    325   // Computes the reverse-postorder numbering for the region nodes.
    326   // Precondition: ComputeDEDefs()
    327   void ComputeRPO();
    328   // Computes the dominance frontier for all regions in the graph,
    329   // following the algorithm from
    330   // Cooper & Torczon, "Engineering a Compiler", second edition, page 499.
    331   // Precondition: ComputeIDominators()
    332   void ComputeDominanceFrontier();
    333   // Converts the IR to semi-pruned SSA form.
    334   void ConvertToSSA();
    335   // Performs the renaming phase of the SSA transformation during ConvertToSSA() execution.
    336   void RenameAsSSA();
    337   // Identifies the definitions corresponding to uses for region @node
    338   // by using the scoped hashtable of names @ scoped_table.
    339   void RenameAsSSA(Region* node, utils::ScopedHashtable<int, InstructionNode*>* scoped_table);
    340   // Generate LLVM IR for the method.
    341   // Precondition: ConvertToSSA().
    342   CodeGenData* GenerateLLVM(const std::string& function_name, const art::DexFile& dex_file);
    343   // Inserts one SignatureNode for each argument of the function in
    344   void InsertSignatureNodes(const art::DexFile::CodeItem* code_item, Region* r);
    345 
    346   static SeaGraph graph_;
    347   std::vector<Region*> regions_;
    348   std::vector<SignatureNode*> parameters_;
    349   const art::DexFile& dex_file_;
    350   const art::DexFile::CodeItem* code_item_;
    351 };
    352 }  // namespace sea_ir
    353 #endif  // ART_COMPILER_SEA_IR_IR_SEA_H_
    354