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 ®ions_; 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 ¶meters_; 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