blob: a133678225b3759ab6a05d18b2ac5e7d64d26bd3 [file] [log] [blame]
Brian Carlstrom7940e442013-07-12 13:46:57 -07001/*
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 SEA_IR_H_
19#define SEA_IR_H_
20
21#include <set>
22#include <map>
23
24#include "dex_file.h"
25#include "dex_instruction.h"
26#include "sea_ir/instruction_tools.h"
Brian Carlstrom1db91132013-07-12 18:05:20 -070027#include "utils/scoped_hashtable.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070028
Brian Carlstrom7940e442013-07-12 13:46:57 -070029
30namespace sea_ir {
Brian Carlstrom1db91132013-07-12 18:05:20 -070031
32#define NO_REGISTER (-1)
33
34// Reverse post-order numbering constants
35enum RegionNumbering {
36 NOT_VISITED = -1,
37 VISITING = -2
38};
39
Brian Carlstrom7940e442013-07-12 13:46:57 -070040class Region;
Brian Carlstrom1db91132013-07-12 18:05:20 -070041class InstructionNode;
42class PhiInstructionNode;
Brian Carlstrom7940e442013-07-12 13:46:57 -070043
44class SeaNode {
45 public:
46 explicit SeaNode():id_(GetNewId()), string_id_(), successors_(), predecessors_() {
47 std::stringstream ss;
48 ss << id_;
49 string_id_.append(ss.str());
50 }
Brian Carlstrom7940e442013-07-12 13:46:57 -070051 // Adds CFG predecessors and successors to each block.
52 void AddSuccessor(Region* successor);
53 void AddPredecessor(Region* predecesor);
54
Brian Carlstrom1db91132013-07-12 18:05:20 -070055 std::vector<sea_ir::Region*>* GetSuccessors() {
56 return &successors_;
57 }
58 std::vector<sea_ir::Region*>* GetPredecessors() {
59 return &predecessors_;
60 }
Brian Carlstrom7940e442013-07-12 13:46:57 -070061 // Returns the id of the current block as string
62 const std::string& StringId() const {
63 return string_id_;
64 }
Brian Carlstrom7940e442013-07-12 13:46:57 -070065 // Appends to @result a dot language formatted string representing the node and
66 // (by convention) outgoing edges, so that the composition of theToDot() of all nodes
67 // builds a complete dot graph, but without prolog ("digraph {") and epilog ("}").
68 virtual void ToDot(std::string& result) const = 0;
69
70 virtual ~SeaNode() {}
71
72 protected:
73 static int GetNewId() {
74 return current_max_node_id_++;
75 }
76
77 const int id_;
78 std::string string_id_;
79 std::vector<sea_ir::Region*> successors_; // CFG successor nodes (regions)
80 std::vector<sea_ir::Region*> predecessors_; // CFG predecessor nodes (instructions/regions)
81
82 private:
83 static int current_max_node_id_;
84};
85
86class InstructionNode: public SeaNode {
87 public:
Brian Carlstrom1db91132013-07-12 18:05:20 -070088 explicit InstructionNode(const art::Instruction* in):
89 SeaNode(), instruction_(in), de_def_(false) {}
90 // Returns the Dalvik instruction around which this InstructionNode is wrapped.
Brian Carlstrom7940e442013-07-12 13:46:57 -070091 const art::Instruction* GetInstruction() const {
92 DCHECK(NULL != instruction_) << "Tried to access NULL instruction in an InstructionNode.";
93 return instruction_;
94 }
95 // Returns the register that is defined by the current instruction, or NO_REGISTER otherwise.
Brian Carlstrom1db91132013-07-12 18:05:20 -070096 virtual int GetResultRegister() const;
97 // Returns the set of registers defined by the current instruction.
98 virtual std::vector<int> GetDefinitions() const;
99 // Returns the set of register numbers that are used by the instruction.
100 virtual std::vector<int> GetUses();
101 // Appends to @result the .dot string representation of the instruction.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700102 void ToDot(std::string& result) const;
Brian Carlstrom1db91132013-07-12 18:05:20 -0700103 // Mark the current instruction as a dowward exposed definition.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700104 void MarkAsDEDef();
Brian Carlstrom1db91132013-07-12 18:05:20 -0700105 // Rename the use of @reg_no to refer to the instruction @definition,
106 // essentially creating SSA form.
107 void RenameToSSA(int reg_no, InstructionNode* definition) {
108 definition_edges_.insert(std::pair<int, InstructionNode*>(reg_no, definition));
109 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700110
111 private:
112 const art::Instruction* const instruction_;
Brian Carlstrom1db91132013-07-12 18:05:20 -0700113 std::map<int, InstructionNode* > definition_edges_;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700114 bool de_def_;
115};
116
Brian Carlstrom1db91132013-07-12 18:05:20 -0700117class SignatureNode: public InstructionNode {
118 public:
119 explicit SignatureNode(unsigned int start_register, unsigned int count):
120 InstructionNode(NULL), defined_regs_() {
121 for (unsigned int crt_offset = 0; crt_offset < count; crt_offset++) {
122 defined_regs_.push_back(start_register - crt_offset);
123 }
124 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700125
Brian Carlstrom1db91132013-07-12 18:05:20 -0700126 void ToDot(std::string& result) const {
127 result += StringId() +"[label=\"signature:";
128 std::stringstream vector_printer;
129 if (!defined_regs_.empty()) {
130 for (unsigned int crt_el = 0; crt_el < defined_regs_.size()-1; crt_el++) {
131 vector_printer << defined_regs_[crt_el] <<",";
132 }
133 vector_printer << defined_regs_[defined_regs_.size()-1] <<";";
134 }
135 result += "\"] // signature node\n";
136 }
137
138 std::vector<int> GetDefinitions() const {
139 return defined_regs_;
140 }
141
142 int GetResultRegister() const {
143 return NO_REGISTER;
144 }
145
146 std::vector<int> GetUses() {
147 return std::vector<int>();
148 }
149
150 private:
151 std::vector<int> defined_regs_;
152};
153
154
155class PhiInstructionNode: public InstructionNode {
156 public:
157 explicit PhiInstructionNode(int register_no):
158 InstructionNode(NULL), register_no_(register_no), definition_edges_() {}
159 // Appends to @result the .dot string representation of the instruction.
160 void ToDot(std::string& result) const;
161 // Returns the register on which this phi-function is used.
162 int GetRegisterNumber() {
163 return register_no_;
164 }
165
166 // Rename the use of @reg_no to refer to the instruction @definition.
167 // Phi-functions are different than normal instructions in that they
168 // have multiple predecessor regions; this is why RenameToSSA has
169 // the additional parameter specifying that @parameter_id is the incoming
170 // edge for @definition, essentially creating SSA form.
171 void RenameToSSA(int reg_no, InstructionNode* definition, unsigned int predecessor_id) {
172 DCHECK(NULL != definition) << "Tried to rename to SSA using a NULL definition for "
173 << StringId() << " register " << reg_no;
174 if (definition_edges_.size() < predecessor_id+1) {
175 definition_edges_.resize(predecessor_id+1, NULL);
176 }
177
178 if (NULL == definition_edges_.at(predecessor_id)) {
179 definition_edges_[predecessor_id] = new std::map<int, InstructionNode*>();
180 }
181 definition_edges_[predecessor_id]->insert(std::pair<int, InstructionNode*>(reg_no, definition));
182 }
183
184 private:
185 int register_no_;
186 std::vector<std::map<int, InstructionNode*>*> definition_edges_;
187};
Brian Carlstrom7940e442013-07-12 13:46:57 -0700188
189class Region : public SeaNode {
190 public:
Brian Carlstrom1db91132013-07-12 18:05:20 -0700191 explicit Region():
192 SeaNode(), reaching_defs_size_(0), rpo_(NOT_VISITED), idom_(NULL),
193 idominated_set_(), df_(), phi_set_() {}
Brian Carlstrom7940e442013-07-12 13:46:57 -0700194
Brian Carlstrom1db91132013-07-12 18:05:20 -0700195 // Adds @instruction as an instruction node child in the current region.
196 void AddChild(sea_ir::InstructionNode* insttruction);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700197
198 // Returns the last instruction node child of the current region.
199 // This child has the CFG successors pointing to the new regions.
200 SeaNode* GetLastChild() const;
Brian Carlstrom1db91132013-07-12 18:05:20 -0700201 // Returns all the child instructions of this region, in program order.
202 std::vector<InstructionNode*>* GetInstructions() {
203 return &instructions_;
204 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700205 // Appends to @result a dot language formatted string representing the node and
206 // (by convention) outgoing edges, so that the composition of theToDot() of all nodes
207 // builds a complete dot graph (without prolog and epilog though).
208 virtual void ToDot(std::string& result) const;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700209 // Computes Downward Exposed Definitions for the current node.
Brian Carlstrom1db91132013-07-12 18:05:20 -0700210
Brian Carlstrom7940e442013-07-12 13:46:57 -0700211 void ComputeDownExposedDefs();
212 const std::map<int, sea_ir::InstructionNode*>* GetDownExposedDefs() const;
213
214 // Performs one iteration of the reaching definitions algorithm
215 // and returns true if the reaching definitions set changed.
216 bool UpdateReachingDefs();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700217 // Returns the set of reaching definitions for the current region.
218 std::map<int, std::set<sea_ir::InstructionNode*>* >* GetReachingDefs();
219
Brian Carlstrom1db91132013-07-12 18:05:20 -0700220 void SetRPO(int rpo) {
221 rpo_ = rpo;
222 }
223
224 int GetRPO() {
225 return rpo_;
226 }
227
228 void SetIDominator(Region* dom) {
229 idom_ = dom;
230 }
231
232 Region* GetIDominator() const {
233 return idom_;
234 }
235
236 void AddToIDominatedSet(Region* dominated) {
237 idominated_set_.insert(dominated);
238 }
239
240 const std::set<Region*>* GetIDominatedSet() {
241 return &idominated_set_;
242 }
243
244 // Adds @df_reg to the dominance frontier of the current region.
245 void AddToDominanceFrontier(Region* df_reg) {
246 df_.insert(df_reg);
247 }
248 // Returns the dominance frontier of the current region.
249 // Preconditions: SeaGraph.ComputeDominanceFrontier()
250 std::set<Region*>* GetDominanceFrontier() {
251 return &df_;
252 }
253 // Returns true if the region contains a phi function for @reg_no.
254 bool ContainsPhiFor(int reg_no) {
255 return (phi_set_.end() != phi_set_.find(reg_no));
256 }
257 // Returns the phi-functions from the region.
258 std::vector<PhiInstructionNode*>* GetPhiNodes() {
259 return &phi_instructions_;
260 }
261 // Adds a phi-function for @reg_no to this region.
262 // Note: The insertion order does not matter, as phi-functions
263 // are conceptually executed at the same time.
264 bool InsertPhiFor(int reg_no);
265 // Sets the phi-function uses to be as defined in @scoped_table for predecessor @@predecessor.
266 void SetPhiDefinitionsForUses(const utils::ScopedHashtable<int, InstructionNode*>* scoped_table,
267 Region* predecessor);
268
Brian Carlstrom7940e442013-07-12 13:46:57 -0700269 private:
270 std::vector<sea_ir::InstructionNode*> instructions_;
271 std::map<int, sea_ir::InstructionNode*> de_defs_;
272 std::map<int, std::set<sea_ir::InstructionNode*>* > reaching_defs_;
273 int reaching_defs_size_;
Brian Carlstrom1db91132013-07-12 18:05:20 -0700274 int rpo_;
275 // Immediate dominator node.
276 Region* idom_;
277 // The set of nodes immediately dominated by the region.
278 std::set<Region*> idominated_set_;
279 // Records the dominance frontier.
280 std::set<Region*> df_;
281 // Records the set of register numbers that have phi nodes in this region.
282 std::set<int> phi_set_;
283 std::vector<PhiInstructionNode*> phi_instructions_;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700284};
285
Brian Carlstrom7940e442013-07-12 13:46:57 -0700286class SeaGraph {
287 public:
288 static SeaGraph* GetCurrentGraph();
Brian Carlstrom1db91132013-07-12 18:05:20 -0700289
Brian Carlstrom7940e442013-07-12 13:46:57 -0700290 void CompileMethod(const art::DexFile::CodeItem* code_item,
291 uint32_t class_def_idx, uint32_t method_idx, const art::DexFile& dex_file);
Brian Carlstrom1db91132013-07-12 18:05:20 -0700292 // Returns a string representation of the region and its Instruction children.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700293 void DumpSea(std::string filename) const;
Brian Carlstrom1db91132013-07-12 18:05:20 -0700294 // Recursively computes the reverse postorder value for @crt_bb and successors.
295 static void ComputeRPO(Region* crt_bb, int& crt_rpo);
296 // Returns the "lowest common ancestor" of @i and @j in the dominator tree.
297 static Region* Intersect(Region* i, Region* j);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700298
299 private:
Brian Carlstrom1db91132013-07-12 18:05:20 -0700300 // Registers @childReg as a region belonging to the SeaGraph instance.
301 void AddRegion(Region* childReg);
302 // Returns new region and registers it with the SeaGraph instance.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700303 Region* GetNewRegion();
Brian Carlstrom1db91132013-07-12 18:05:20 -0700304 // Adds a CFG edge from @src node to @dst node.
305 void AddEdge(Region* src, Region* dst) const;
306 // Builds the non-SSA sea-ir representation of the function @code_item from @dex_file.
307 void BuildMethodSeaGraph(const art::DexFile::CodeItem* code_item, const art::DexFile& dex_file);
308 // Computes immediate dominators for each region.
309 // Precondition: ComputeMethodSeaGraph()
310 void ComputeIDominators();
311 // Computes Downward Exposed Definitions for all regions in the graph.
312 void ComputeDownExposedDefs();
313 // Computes the reaching definitions set following the equations from
314 // Cooper & Torczon, "Engineering a Compiler", second edition, page 491.
315 // Precondition: ComputeDEDefs()
316 void ComputeReachingDefs();
317 // Computes the reverse-postorder numbering for the region nodes.
318 // Precondition: ComputeDEDefs()
319 void ComputeRPO();
320 // Computes the dominance frontier for all regions in the graph,
321 // following the algorithm from
322 // Cooper & Torczon, "Engineering a Compiler", second edition, page 499.
323 // Precondition: ComputeIDominators()
324 void ComputeDominanceFrontier();
325
326 void ConvertToSSA();
327 // Identifies the definitions corresponding to uses for region @node
328 // by using the scoped hashtable of names @ scoped_table.
329 void RenameAsSSA(Region* node, utils::ScopedHashtable<int, InstructionNode*>* scoped_table);
330 void RenameAsSSA();
331
Brian Carlstrom7940e442013-07-12 13:46:57 -0700332 static SeaGraph graph_;
333 std::vector<Region*> regions_;
334};
Brian Carlstrom7940e442013-07-12 13:46:57 -0700335} // end namespace sea_ir
336#endif