blob: 5cb84240ae789900a44e30da023c221c07d8526a [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
Brian Carlstromfc0e3212013-07-17 14:40:12 -070018#ifndef ART_COMPILER_SEA_IR_SEA_H_
19#define ART_COMPILER_SEA_IR_SEA_H_
Brian Carlstrom7940e442013-07-12 13:46:57 -070020
21#include <set>
22#include <map>
23
24#include "dex_file.h"
25#include "dex_instruction.h"
Dragos Sbirlea0e260a32013-06-21 09:20:34 -070026#include "instruction_tools.h"
27#include "instruction_nodes.h"
Brian Carlstrom1db91132013-07-12 18:05:20 -070028#include "utils/scoped_hashtable.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070029
Brian Carlstrom7940e442013-07-12 13:46:57 -070030namespace sea_ir {
Brian Carlstrom1db91132013-07-12 18:05:20 -070031
Brian Carlstrom1db91132013-07-12 18:05:20 -070032// Reverse post-order numbering constants
33enum RegionNumbering {
34 NOT_VISITED = -1,
35 VISITING = -2
36};
37
Dragos Sbirleae2245322013-07-29 14:16:14 -070038// Stores options for turning a SEA IR graph to a .dot file.
39class DotConversion {
40 public:
41 static bool SaveUseEdges() {
42 return save_use_edges_;
43 }
44
45 private:
Dragos Sbirleab4dcf652013-07-29 16:49:56 -070046 static const bool save_use_edges_ = false; // TODO: Enable per-sea graph configuration.
Dragos Sbirleae2245322013-07-29 14:16:14 -070047};
48
Brian Carlstrom7940e442013-07-12 13:46:57 -070049class Region;
Dragos Sbirlea0e260a32013-06-21 09:20:34 -070050
Brian Carlstrom1db91132013-07-12 18:05:20 -070051class InstructionNode;
52class PhiInstructionNode;
Dragos Sbirlea0e260a32013-06-21 09:20:34 -070053class SignatureNode;
Brian Carlstrom7940e442013-07-12 13:46:57 -070054
Dragos Sbirlea0e260a32013-06-21 09:20:34 -070055// A SignatureNode is a declaration of one parameter in the function signature.
56// This class is used to provide place-holder definitions to which instructions
57// can return from the GetSSAUses() calls, instead of having missing SSA edges.
Brian Carlstrom1db91132013-07-12 18:05:20 -070058class SignatureNode: public InstructionNode {
59 public:
Dragos Sbirleadb063062013-07-23 16:29:09 -070060 explicit SignatureNode(unsigned int parameter_register):InstructionNode(NULL),
61 parameter_register_(parameter_register) { }
Brian Carlstrom7940e442013-07-12 13:46:57 -070062
Dragos Sbirlea6bee4452013-07-26 12:05:03 -070063 void ToDot(std::string& result, const art::DexFile& dex_file) const {
Dragos Sbirlea0e260a32013-06-21 09:20:34 -070064 result += StringId() +" [label=\"signature:";
Dragos Sbirleadb063062013-07-23 16:29:09 -070065 result += art::StringPrintf("r%d", GetResultRegister());
Brian Carlstrom1db91132013-07-12 18:05:20 -070066 result += "\"] // signature node\n";
Dragos Sbirleae2245322013-07-29 14:16:14 -070067 ToDotSSAEdges(result);
Brian Carlstrom1db91132013-07-12 18:05:20 -070068 }
69
Brian Carlstrom1db91132013-07-12 18:05:20 -070070 int GetResultRegister() const {
Dragos Sbirleadb063062013-07-23 16:29:09 -070071 return parameter_register_;
Brian Carlstrom1db91132013-07-12 18:05:20 -070072 }
73
74 std::vector<int> GetUses() {
75 return std::vector<int>();
76 }
77
Dragos Sbirlea0e260a32013-06-21 09:20:34 -070078 void Accept(IRVisitor* v) {
79 v->Visit(this);
80 v->Traverse(this);
81 }
82
Brian Carlstrom1db91132013-07-12 18:05:20 -070083 private:
Dragos Sbirleadb063062013-07-23 16:29:09 -070084 unsigned int parameter_register_;
Brian Carlstrom1db91132013-07-12 18:05:20 -070085};
86
Brian Carlstrom1db91132013-07-12 18:05:20 -070087class PhiInstructionNode: public InstructionNode {
88 public:
89 explicit PhiInstructionNode(int register_no):
90 InstructionNode(NULL), register_no_(register_no), definition_edges_() {}
91 // Appends to @result the .dot string representation of the instruction.
Dragos Sbirlea6bee4452013-07-26 12:05:03 -070092 void ToDot(std::string& result, const art::DexFile& dex_file) const;
Brian Carlstrom1db91132013-07-12 18:05:20 -070093 // Returns the register on which this phi-function is used.
Dragos Sbirlea0e260a32013-06-21 09:20:34 -070094 int GetRegisterNumber() const {
Brian Carlstrom1db91132013-07-12 18:05:20 -070095 return register_no_;
96 }
97
Dragos Sbirlea0e260a32013-06-21 09:20:34 -070098 // Renames the use of @reg_no to refer to the instruction @definition.
Brian Carlstrom1db91132013-07-12 18:05:20 -070099 // Phi-functions are different than normal instructions in that they
100 // have multiple predecessor regions; this is why RenameToSSA has
101 // the additional parameter specifying that @parameter_id is the incoming
102 // edge for @definition, essentially creating SSA form.
103 void RenameToSSA(int reg_no, InstructionNode* definition, unsigned int predecessor_id) {
104 DCHECK(NULL != definition) << "Tried to rename to SSA using a NULL definition for "
105 << StringId() << " register " << reg_no;
106 if (definition_edges_.size() < predecessor_id+1) {
107 definition_edges_.resize(predecessor_id+1, NULL);
108 }
Brian Carlstrom1db91132013-07-12 18:05:20 -0700109 if (NULL == definition_edges_.at(predecessor_id)) {
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700110 definition_edges_[predecessor_id] = new std::vector<InstructionNode*>();
Brian Carlstrom1db91132013-07-12 18:05:20 -0700111 }
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700112 definition_edges_[predecessor_id]->push_back(definition);
Dragos Sbirleae2245322013-07-29 14:16:14 -0700113 definition->AddSSAUse(this);
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700114 }
115
116 // Returns the instruction that defines the phi register from predecessor
117 // on position @predecessor_pos. Note that the return value is vector<> just
118 // for consistency with the return value of GetSSAUses() on regular instructions,
119 // The returned vector should always have a single element because the IR is SSA.
120 std::vector<InstructionNode*>* GetSSAUses(int predecessor_pos) {
121 return definition_edges_.at(predecessor_pos);
122 }
123
124 void Accept(IRVisitor* v) {
125 v->Visit(this);
126 v->Traverse(this);
Brian Carlstrom1db91132013-07-12 18:05:20 -0700127 }
128
129 private:
130 int register_no_;
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700131 std::vector<std::vector<InstructionNode*>*> definition_edges_;
Brian Carlstrom1db91132013-07-12 18:05:20 -0700132};
Brian Carlstrom7940e442013-07-12 13:46:57 -0700133
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700134// This class corresponds to a basic block in traditional compiler IRs.
135// The dataflow analysis relies on this class both during execution and
136// for storing its results.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700137class Region : public SeaNode {
138 public:
Brian Carlstrom1db91132013-07-12 18:05:20 -0700139 explicit Region():
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700140 SeaNode(), successors_(), predecessors_(), reaching_defs_size_(0),
Dragos Sbirlea6bee4452013-07-26 12:05:03 -0700141 rpo_number_(NOT_VISITED), idom_(NULL), idominated_set_(), df_(), phi_set_() {
142 string_id_ = "cluster_" + string_id_;
143 }
Brian Carlstrom1db91132013-07-12 18:05:20 -0700144 // Adds @instruction as an instruction node child in the current region.
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700145 void AddChild(sea_ir::InstructionNode* instruction);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700146 // Returns the last instruction node child of the current region.
147 // This child has the CFG successors pointing to the new regions.
148 SeaNode* GetLastChild() const;
Brian Carlstrom1db91132013-07-12 18:05:20 -0700149 // Returns all the child instructions of this region, in program order.
150 std::vector<InstructionNode*>* GetInstructions() {
151 return &instructions_;
152 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700153 // Appends to @result a dot language formatted string representing the node and
154 // (by convention) outgoing edges, so that the composition of theToDot() of all nodes
155 // builds a complete dot graph (without prolog and epilog though).
Dragos Sbirlea6bee4452013-07-26 12:05:03 -0700156 virtual void ToDot(std::string& result, const art::DexFile& dex_file) const;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700157 // Computes Downward Exposed Definitions for the current node.
158 void ComputeDownExposedDefs();
159 const std::map<int, sea_ir::InstructionNode*>* GetDownExposedDefs() const;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700160 // Performs one iteration of the reaching definitions algorithm
161 // and returns true if the reaching definitions set changed.
162 bool UpdateReachingDefs();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700163 // Returns the set of reaching definitions for the current region.
164 std::map<int, std::set<sea_ir::InstructionNode*>* >* GetReachingDefs();
165
Brian Carlstrom1db91132013-07-12 18:05:20 -0700166 void SetRPO(int rpo) {
Dragos Sbirlea81f79a62013-07-23 14:31:47 -0700167 rpo_number_ = rpo;
Brian Carlstrom1db91132013-07-12 18:05:20 -0700168 }
169
170 int GetRPO() {
Dragos Sbirlea81f79a62013-07-23 14:31:47 -0700171 return rpo_number_;
Brian Carlstrom1db91132013-07-12 18:05:20 -0700172 }
173
174 void SetIDominator(Region* dom) {
175 idom_ = dom;
176 }
177
178 Region* GetIDominator() const {
179 return idom_;
180 }
181
182 void AddToIDominatedSet(Region* dominated) {
183 idominated_set_.insert(dominated);
184 }
185
186 const std::set<Region*>* GetIDominatedSet() {
187 return &idominated_set_;
188 }
Brian Carlstrom1db91132013-07-12 18:05:20 -0700189 // Adds @df_reg to the dominance frontier of the current region.
190 void AddToDominanceFrontier(Region* df_reg) {
191 df_.insert(df_reg);
192 }
193 // Returns the dominance frontier of the current region.
194 // Preconditions: SeaGraph.ComputeDominanceFrontier()
195 std::set<Region*>* GetDominanceFrontier() {
196 return &df_;
197 }
198 // Returns true if the region contains a phi function for @reg_no.
199 bool ContainsPhiFor(int reg_no) {
200 return (phi_set_.end() != phi_set_.find(reg_no));
201 }
202 // Returns the phi-functions from the region.
203 std::vector<PhiInstructionNode*>* GetPhiNodes() {
204 return &phi_instructions_;
205 }
206 // Adds a phi-function for @reg_no to this region.
207 // Note: The insertion order does not matter, as phi-functions
208 // are conceptually executed at the same time.
209 bool InsertPhiFor(int reg_no);
210 // Sets the phi-function uses to be as defined in @scoped_table for predecessor @@predecessor.
211 void SetPhiDefinitionsForUses(const utils::ScopedHashtable<int, InstructionNode*>* scoped_table,
212 Region* predecessor);
213
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700214 void Accept(IRVisitor* v) {
215 v->Visit(this);
216 v->Traverse(this);
217 }
218
219 void AddSuccessor(Region* successor) {
220 DCHECK(successor) << "Tried to add NULL successor to SEA node.";
221 successors_.push_back(successor);
222 return;
223 }
224 void AddPredecessor(Region* predecessor) {
225 DCHECK(predecessor) << "Tried to add NULL predecessor to SEA node.";
226 predecessors_.push_back(predecessor);
227 }
228
229 std::vector<sea_ir::Region*>* GetSuccessors() {
230 return &successors_;
231 }
232 std::vector<sea_ir::Region*>* GetPredecessors() {
233 return &predecessors_;
234 }
235
Brian Carlstrom7940e442013-07-12 13:46:57 -0700236 private:
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700237 std::vector<sea_ir::Region*> successors_; // CFG successor nodes (regions)
238 std::vector<sea_ir::Region*> predecessors_; // CFG predecessor nodes (instructions/regions)
Brian Carlstrom7940e442013-07-12 13:46:57 -0700239 std::vector<sea_ir::InstructionNode*> instructions_;
240 std::map<int, sea_ir::InstructionNode*> de_defs_;
241 std::map<int, std::set<sea_ir::InstructionNode*>* > reaching_defs_;
242 int reaching_defs_size_;
Dragos Sbirlea81f79a62013-07-23 14:31:47 -0700243 int rpo_number_; // reverse postorder number of the region
Brian Carlstrom1db91132013-07-12 18:05:20 -0700244 // Immediate dominator node.
245 Region* idom_;
246 // The set of nodes immediately dominated by the region.
247 std::set<Region*> idominated_set_;
248 // Records the dominance frontier.
249 std::set<Region*> df_;
250 // Records the set of register numbers that have phi nodes in this region.
251 std::set<int> phi_set_;
252 std::vector<PhiInstructionNode*> phi_instructions_;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700253};
254
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700255// A SeaGraph instance corresponds to a source code function.
256// Its main point is to encapsulate the SEA IR representation of it
257// and acts as starting point for visitors (ex: during code generation).
258class SeaGraph: IVisitable {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700259 public:
Dragos Sbirlea6bee4452013-07-26 12:05:03 -0700260 static SeaGraph* GetCurrentGraph(const art::DexFile&);
Brian Carlstrom1db91132013-07-12 18:05:20 -0700261
Brian Carlstrom7940e442013-07-12 13:46:57 -0700262 void CompileMethod(const art::DexFile::CodeItem* code_item,
263 uint32_t class_def_idx, uint32_t method_idx, const art::DexFile& dex_file);
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700264 // Returns all regions corresponding to this SeaGraph.
265 std::vector<Region*>* GetRegions() {
266 return &regions_;
267 }
Brian Carlstrom1db91132013-07-12 18:05:20 -0700268 // Returns a string representation of the region and its Instruction children.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700269 void DumpSea(std::string filename) const;
Brian Carlstrom1db91132013-07-12 18:05:20 -0700270 // Recursively computes the reverse postorder value for @crt_bb and successors.
271 static void ComputeRPO(Region* crt_bb, int& crt_rpo);
272 // Returns the "lowest common ancestor" of @i and @j in the dominator tree.
273 static Region* Intersect(Region* i, Region* j);
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700274 // Returns the vector of parameters of the function.
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700275 std::vector<SignatureNode*>* GetParameterNodes() {
276 return &parameters_;
277 }
278 uint32_t class_def_idx_;
279 uint32_t method_idx_;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700280
281 private:
Dragos Sbirlea6bee4452013-07-26 12:05:03 -0700282 explicit SeaGraph(const art::DexFile& df):
283 class_def_idx_(0), method_idx_(0), regions_(), parameters_(), dex_file_(df) {
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700284 }
Brian Carlstrom1db91132013-07-12 18:05:20 -0700285 // Registers @childReg as a region belonging to the SeaGraph instance.
286 void AddRegion(Region* childReg);
287 // Returns new region and registers it with the SeaGraph instance.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700288 Region* GetNewRegion();
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700289 // Adds a (formal) parameter node to the vector of parameters of the function.
290 void AddParameterNode(SignatureNode* parameterNode) {
291 parameters_.push_back(parameterNode);
292 }
Brian Carlstrom1db91132013-07-12 18:05:20 -0700293 // Adds a CFG edge from @src node to @dst node.
294 void AddEdge(Region* src, Region* dst) const;
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700295 // Builds the non-SSA sea-ir representation of the function @code_item from @dex_file
296 // with class id @class_def_idx and method id @method_idx.
297 void BuildMethodSeaGraph(const art::DexFile::CodeItem* code_item,
298 const art::DexFile& dex_file, uint32_t class_def_idx, uint32_t method_idx);
Brian Carlstrom1db91132013-07-12 18:05:20 -0700299 // Computes immediate dominators for each region.
300 // Precondition: ComputeMethodSeaGraph()
301 void ComputeIDominators();
302 // Computes Downward Exposed Definitions for all regions in the graph.
303 void ComputeDownExposedDefs();
304 // Computes the reaching definitions set following the equations from
305 // Cooper & Torczon, "Engineering a Compiler", second edition, page 491.
306 // Precondition: ComputeDEDefs()
307 void ComputeReachingDefs();
308 // Computes the reverse-postorder numbering for the region nodes.
309 // Precondition: ComputeDEDefs()
310 void ComputeRPO();
311 // Computes the dominance frontier for all regions in the graph,
312 // following the algorithm from
313 // Cooper & Torczon, "Engineering a Compiler", second edition, page 499.
314 // Precondition: ComputeIDominators()
315 void ComputeDominanceFrontier();
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700316 // Converts the IR to semi-pruned SSA form.
Brian Carlstrom1db91132013-07-12 18:05:20 -0700317 void ConvertToSSA();
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700318 // Performs the renaming phase of the SSA transformation during ConvertToSSA() execution.
319 void RenameAsSSA();
Brian Carlstrom1db91132013-07-12 18:05:20 -0700320 // Identifies the definitions corresponding to uses for region @node
321 // by using the scoped hashtable of names @ scoped_table.
322 void RenameAsSSA(Region* node, utils::ScopedHashtable<int, InstructionNode*>* scoped_table);
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700323
324 virtual void Accept(IRVisitor* visitor) {
325 visitor->Initialize(this);
326 visitor->Visit(this);
327 visitor->Traverse(this);
328 }
329
330 virtual ~SeaGraph() {}
331 // Generate LLVM IR for the method.
332 // Precondition: ConvertToSSA().
333 void GenerateLLVM();
Brian Carlstrom1db91132013-07-12 18:05:20 -0700334
Brian Carlstrom7940e442013-07-12 13:46:57 -0700335 static SeaGraph graph_;
336 std::vector<Region*> regions_;
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700337 std::vector<SignatureNode*> parameters_;
Dragos Sbirlea6bee4452013-07-26 12:05:03 -0700338 const art::DexFile& dex_file_;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700339};
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700340} // namespace sea_ir
Brian Carlstromfc0e3212013-07-17 14:40:12 -0700341#endif // ART_COMPILER_SEA_IR_SEA_H_