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
31namespace sea_ir {
32
33// Reverse post-order numbering constants
34enum RegionNumbering {
35  NOT_VISITED = -1,
36  VISITING = -2
37};
38
39class TypeInference;
40class CodeGenData;
41
42class Region;
43class InstructionNode;
44class PhiInstructionNode;
45class 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.
50class 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
80class 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.
142class 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).
260class 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