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.
SignatureNode(unsigned int register_no,unsigned int signature_position)54   explicit SignatureNode(unsigned int register_no, unsigned int signature_position):
55     InstructionNode(NULL), register_no_(register_no), position_(signature_position) { }
56 
GetResultRegister()57   int GetResultRegister() const {
58     return register_no_;
59   }
60 
GetPositionInSignature()61   unsigned int GetPositionInSignature() const {
62     return position_;
63   }
64 
GetUses()65   std::vector<int> GetUses() const {
66     return std::vector<int>();
67   }
68 
Accept(IRVisitor * v)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:
PhiInstructionNode(int register_no)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.
GetRegisterNumber()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.
RenameToSSA(int reg_no,InstructionNode * definition,unsigned int predecessor_id)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().
GetSSAProducers()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.
GetSSAUses(int predecessor_pos)122   std::vector<InstructionNode*>* GetSSAUses(int predecessor_pos) {
123     return definition_edges_.at(predecessor_pos);
124   }
125 
Accept(IRVisitor * v)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:
Region()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.
GetInstructions()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 
SetRPO(int rpo)168   void SetRPO(int rpo) {
169     rpo_number_ = rpo;
170   }
171 
GetRPO()172   int GetRPO() {
173     return rpo_number_;
174   }
175 
SetIDominator(Region * dom)176   void SetIDominator(Region* dom) {
177     idom_ = dom;
178   }
179 
GetIDominator()180   Region* GetIDominator() const {
181     return idom_;
182   }
183 
AddToIDominatedSet(Region * dominated)184   void AddToIDominatedSet(Region* dominated) {
185     idominated_set_.insert(dominated);
186   }
187 
GetIDominatedSet()188   const std::set<Region*>* GetIDominatedSet() {
189     return &idominated_set_;
190   }
191   // Adds @df_reg to the dominance frontier of the current region.
AddToDominanceFrontier(Region * df_reg)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()
GetDominanceFrontier()197   std::set<Region*>* GetDominanceFrontier() {
198     return &df_;
199   }
200   // Returns true if the region contains a phi function for @reg_no.
ContainsPhiFor(int 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.
GetPhiNodes()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 
Accept(IRVisitor * v)216   void Accept(IRVisitor* v) {
217     v->Visit(this);
218     v->Traverse(this);
219   }
220 
AddSuccessor(Region * successor)221   void AddSuccessor(Region* successor) {
222     DCHECK(successor) << "Tried to add NULL successor to SEA node.";
223     successors_.push_back(successor);
224     return;
225   }
AddPredecessor(Region * predecessor)226   void AddPredecessor(Region* predecessor) {
227     DCHECK(predecessor) << "Tried to add NULL predecessor to SEA node.";
228     predecessors_.push_back(predecessor);
229   }
230 
GetSuccessors()231   std::vector<sea_ir::Region*>* GetSuccessors() {
232     return &successors_;
233   }
GetPredecessors()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.
GetRegions()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.
GetParameterNodes()276   std::vector<SignatureNode*>* GetParameterNodes() {
277     return &parameters_;
278   }
279 
GetDexFile()280   const art::DexFile* GetDexFile() const {
281     return &dex_file_;
282   }
283 
Accept(IRVisitor * visitor)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);
~SeaGraph()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.
AddParameterNode(SignatureNode * parameterNode)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