blob: efdbb3b135b632336e799acdb34e435d4e97eeca [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 Sbirleab40eddf2013-07-31 13:37:31 -070060 // Creates a new signature node representing the initial definition of the
61 // register @parameter_register which is the @position-th argument to the method.
62 explicit SignatureNode(unsigned int parameter_register, unsigned int position):
63 InstructionNode(NULL), parameter_register_(parameter_register), position_(position) { }
Brian Carlstrom7940e442013-07-12 13:46:57 -070064
Dragos Sbirlea6bee4452013-07-26 12:05:03 -070065 void ToDot(std::string& result, const art::DexFile& dex_file) const {
Dragos Sbirlea0e260a32013-06-21 09:20:34 -070066 result += StringId() +" [label=\"signature:";
Dragos Sbirleadb063062013-07-23 16:29:09 -070067 result += art::StringPrintf("r%d", GetResultRegister());
Brian Carlstrom1db91132013-07-12 18:05:20 -070068 result += "\"] // signature node\n";
Dragos Sbirleae2245322013-07-29 14:16:14 -070069 ToDotSSAEdges(result);
Brian Carlstrom1db91132013-07-12 18:05:20 -070070 }
71
Brian Carlstrom1db91132013-07-12 18:05:20 -070072 int GetResultRegister() const {
Dragos Sbirleadb063062013-07-23 16:29:09 -070073 return parameter_register_;
Brian Carlstrom1db91132013-07-12 18:05:20 -070074 }
75
Dragos Sbirleab40eddf2013-07-31 13:37:31 -070076 unsigned int GetPositionInSignature() {
77 return position_;
78 }
79
Brian Carlstrom1db91132013-07-12 18:05:20 -070080 std::vector<int> GetUses() {
81 return std::vector<int>();
82 }
83
Dragos Sbirlea0e260a32013-06-21 09:20:34 -070084 void Accept(IRVisitor* v) {
85 v->Visit(this);
86 v->Traverse(this);
87 }
88
Brian Carlstrom1db91132013-07-12 18:05:20 -070089 private:
Dragos Sbirleadb063062013-07-23 16:29:09 -070090 unsigned int parameter_register_;
Dragos Sbirleab40eddf2013-07-31 13:37:31 -070091 unsigned int position_; // The position of this parameter node is in the function parameter list.
Brian Carlstrom1db91132013-07-12 18:05:20 -070092};
93
Brian Carlstrom1db91132013-07-12 18:05:20 -070094class PhiInstructionNode: public InstructionNode {
95 public:
96 explicit PhiInstructionNode(int register_no):
97 InstructionNode(NULL), register_no_(register_no), definition_edges_() {}
98 // Appends to @result the .dot string representation of the instruction.
Dragos Sbirlea6bee4452013-07-26 12:05:03 -070099 void ToDot(std::string& result, const art::DexFile& dex_file) const;
Brian Carlstrom1db91132013-07-12 18:05:20 -0700100 // Returns the register on which this phi-function is used.
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700101 int GetRegisterNumber() const {
Brian Carlstrom1db91132013-07-12 18:05:20 -0700102 return register_no_;
103 }
104
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700105 // Renames the use of @reg_no to refer to the instruction @definition.
Brian Carlstrom1db91132013-07-12 18:05:20 -0700106 // Phi-functions are different than normal instructions in that they
107 // have multiple predecessor regions; this is why RenameToSSA has
108 // the additional parameter specifying that @parameter_id is the incoming
109 // edge for @definition, essentially creating SSA form.
110 void RenameToSSA(int reg_no, InstructionNode* definition, unsigned int predecessor_id) {
111 DCHECK(NULL != definition) << "Tried to rename to SSA using a NULL definition for "
112 << StringId() << " register " << reg_no;
113 if (definition_edges_.size() < predecessor_id+1) {
114 definition_edges_.resize(predecessor_id+1, NULL);
115 }
Brian Carlstrom1db91132013-07-12 18:05:20 -0700116 if (NULL == definition_edges_.at(predecessor_id)) {
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700117 definition_edges_[predecessor_id] = new std::vector<InstructionNode*>();
Brian Carlstrom1db91132013-07-12 18:05:20 -0700118 }
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700119 definition_edges_[predecessor_id]->push_back(definition);
Dragos Sbirleae2245322013-07-29 14:16:14 -0700120 definition->AddSSAUse(this);
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700121 }
122
123 // Returns the instruction that defines the phi register from predecessor
124 // on position @predecessor_pos. Note that the return value is vector<> just
125 // for consistency with the return value of GetSSAUses() on regular instructions,
126 // The returned vector should always have a single element because the IR is SSA.
127 std::vector<InstructionNode*>* GetSSAUses(int predecessor_pos) {
128 return definition_edges_.at(predecessor_pos);
129 }
130
131 void Accept(IRVisitor* v) {
132 v->Visit(this);
133 v->Traverse(this);
Brian Carlstrom1db91132013-07-12 18:05:20 -0700134 }
135
136 private:
137 int register_no_;
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700138 std::vector<std::vector<InstructionNode*>*> definition_edges_;
Brian Carlstrom1db91132013-07-12 18:05:20 -0700139};
Brian Carlstrom7940e442013-07-12 13:46:57 -0700140
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700141// This class corresponds to a basic block in traditional compiler IRs.
142// The dataflow analysis relies on this class both during execution and
143// for storing its results.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700144class Region : public SeaNode {
145 public:
Brian Carlstrom1db91132013-07-12 18:05:20 -0700146 explicit Region():
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700147 SeaNode(), successors_(), predecessors_(), reaching_defs_size_(0),
Dragos Sbirlea6bee4452013-07-26 12:05:03 -0700148 rpo_number_(NOT_VISITED), idom_(NULL), idominated_set_(), df_(), phi_set_() {
149 string_id_ = "cluster_" + string_id_;
150 }
Brian Carlstrom1db91132013-07-12 18:05:20 -0700151 // Adds @instruction as an instruction node child in the current region.
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700152 void AddChild(sea_ir::InstructionNode* instruction);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700153 // Returns the last instruction node child of the current region.
154 // This child has the CFG successors pointing to the new regions.
155 SeaNode* GetLastChild() const;
Brian Carlstrom1db91132013-07-12 18:05:20 -0700156 // Returns all the child instructions of this region, in program order.
157 std::vector<InstructionNode*>* GetInstructions() {
158 return &instructions_;
159 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700160 // Appends to @result a dot language formatted string representing the node and
161 // (by convention) outgoing edges, so that the composition of theToDot() of all nodes
162 // builds a complete dot graph (without prolog and epilog though).
Dragos Sbirlea6bee4452013-07-26 12:05:03 -0700163 virtual void ToDot(std::string& result, const art::DexFile& dex_file) const;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700164 // Computes Downward Exposed Definitions for the current node.
165 void ComputeDownExposedDefs();
166 const std::map<int, sea_ir::InstructionNode*>* GetDownExposedDefs() const;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700167 // Performs one iteration of the reaching definitions algorithm
168 // and returns true if the reaching definitions set changed.
169 bool UpdateReachingDefs();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700170 // Returns the set of reaching definitions for the current region.
171 std::map<int, std::set<sea_ir::InstructionNode*>* >* GetReachingDefs();
172
Brian Carlstrom1db91132013-07-12 18:05:20 -0700173 void SetRPO(int rpo) {
Dragos Sbirlea81f79a62013-07-23 14:31:47 -0700174 rpo_number_ = rpo;
Brian Carlstrom1db91132013-07-12 18:05:20 -0700175 }
176
177 int GetRPO() {
Dragos Sbirlea81f79a62013-07-23 14:31:47 -0700178 return rpo_number_;
Brian Carlstrom1db91132013-07-12 18:05:20 -0700179 }
180
181 void SetIDominator(Region* dom) {
182 idom_ = dom;
183 }
184
185 Region* GetIDominator() const {
186 return idom_;
187 }
188
189 void AddToIDominatedSet(Region* dominated) {
190 idominated_set_.insert(dominated);
191 }
192
193 const std::set<Region*>* GetIDominatedSet() {
194 return &idominated_set_;
195 }
Brian Carlstrom1db91132013-07-12 18:05:20 -0700196 // Adds @df_reg to the dominance frontier of the current region.
197 void AddToDominanceFrontier(Region* df_reg) {
198 df_.insert(df_reg);
199 }
200 // Returns the dominance frontier of the current region.
201 // Preconditions: SeaGraph.ComputeDominanceFrontier()
202 std::set<Region*>* GetDominanceFrontier() {
203 return &df_;
204 }
205 // Returns true if the region contains a phi function for @reg_no.
206 bool ContainsPhiFor(int reg_no) {
207 return (phi_set_.end() != phi_set_.find(reg_no));
208 }
209 // Returns the phi-functions from the region.
210 std::vector<PhiInstructionNode*>* GetPhiNodes() {
211 return &phi_instructions_;
212 }
213 // Adds a phi-function for @reg_no to this region.
214 // Note: The insertion order does not matter, as phi-functions
215 // are conceptually executed at the same time.
216 bool InsertPhiFor(int reg_no);
217 // Sets the phi-function uses to be as defined in @scoped_table for predecessor @@predecessor.
218 void SetPhiDefinitionsForUses(const utils::ScopedHashtable<int, InstructionNode*>* scoped_table,
219 Region* predecessor);
220
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700221 void Accept(IRVisitor* v) {
222 v->Visit(this);
223 v->Traverse(this);
224 }
225
226 void AddSuccessor(Region* successor) {
227 DCHECK(successor) << "Tried to add NULL successor to SEA node.";
228 successors_.push_back(successor);
229 return;
230 }
231 void AddPredecessor(Region* predecessor) {
232 DCHECK(predecessor) << "Tried to add NULL predecessor to SEA node.";
233 predecessors_.push_back(predecessor);
234 }
235
236 std::vector<sea_ir::Region*>* GetSuccessors() {
237 return &successors_;
238 }
239 std::vector<sea_ir::Region*>* GetPredecessors() {
240 return &predecessors_;
241 }
242
Brian Carlstrom7940e442013-07-12 13:46:57 -0700243 private:
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700244 std::vector<sea_ir::Region*> successors_; // CFG successor nodes (regions)
245 std::vector<sea_ir::Region*> predecessors_; // CFG predecessor nodes (instructions/regions)
Brian Carlstrom7940e442013-07-12 13:46:57 -0700246 std::vector<sea_ir::InstructionNode*> instructions_;
247 std::map<int, sea_ir::InstructionNode*> de_defs_;
248 std::map<int, std::set<sea_ir::InstructionNode*>* > reaching_defs_;
249 int reaching_defs_size_;
Dragos Sbirlea81f79a62013-07-23 14:31:47 -0700250 int rpo_number_; // reverse postorder number of the region
Brian Carlstrom1db91132013-07-12 18:05:20 -0700251 // Immediate dominator node.
252 Region* idom_;
253 // The set of nodes immediately dominated by the region.
254 std::set<Region*> idominated_set_;
255 // Records the dominance frontier.
256 std::set<Region*> df_;
257 // Records the set of register numbers that have phi nodes in this region.
258 std::set<int> phi_set_;
259 std::vector<PhiInstructionNode*> phi_instructions_;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700260};
261
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700262// A SeaGraph instance corresponds to a source code function.
263// Its main point is to encapsulate the SEA IR representation of it
264// and acts as starting point for visitors (ex: during code generation).
265class SeaGraph: IVisitable {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700266 public:
Dragos Sbirlea6bee4452013-07-26 12:05:03 -0700267 static SeaGraph* GetCurrentGraph(const art::DexFile&);
Brian Carlstrom1db91132013-07-12 18:05:20 -0700268
Dragos Sbirleab40eddf2013-07-31 13:37:31 -0700269 void CompileMethod(const art::DexFile::CodeItem* code_item, uint32_t class_def_idx,
270 uint32_t method_idx, uint32_t method_access_flags, const art::DexFile& dex_file);
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700271 // Returns all regions corresponding to this SeaGraph.
272 std::vector<Region*>* GetRegions() {
273 return &regions_;
274 }
Brian Carlstrom1db91132013-07-12 18:05:20 -0700275 // Returns a string representation of the region and its Instruction children.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700276 void DumpSea(std::string filename) const;
Brian Carlstrom1db91132013-07-12 18:05:20 -0700277 // Recursively computes the reverse postorder value for @crt_bb and successors.
278 static void ComputeRPO(Region* crt_bb, int& crt_rpo);
279 // Returns the "lowest common ancestor" of @i and @j in the dominator tree.
280 static Region* Intersect(Region* i, Region* j);
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700281 // Returns the vector of parameters of the function.
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700282 std::vector<SignatureNode*>* GetParameterNodes() {
283 return &parameters_;
284 }
Dragos Sbirleab40eddf2013-07-31 13:37:31 -0700285
286 const art::DexFile* GetDexFile() const {
287 return &dex_file_;
288 }
289
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700290 uint32_t class_def_idx_;
291 uint32_t method_idx_;
Dragos Sbirleab40eddf2013-07-31 13:37:31 -0700292 uint32_t method_access_flags_;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700293
294 private:
Dragos Sbirlea6bee4452013-07-26 12:05:03 -0700295 explicit SeaGraph(const art::DexFile& df):
Dragos Sbirleab40eddf2013-07-31 13:37:31 -0700296 class_def_idx_(0), method_idx_(0), method_access_flags_(), regions_(),
297 parameters_(), dex_file_(df), code_item_(NULL) {
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700298 }
Brian Carlstrom1db91132013-07-12 18:05:20 -0700299 // Registers @childReg as a region belonging to the SeaGraph instance.
300 void AddRegion(Region* childReg);
301 // Returns new region and registers it with the SeaGraph instance.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700302 Region* GetNewRegion();
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700303 // Adds a (formal) parameter node to the vector of parameters of the function.
304 void AddParameterNode(SignatureNode* parameterNode) {
305 parameters_.push_back(parameterNode);
306 }
Brian Carlstrom1db91132013-07-12 18:05:20 -0700307 // Adds a CFG edge from @src node to @dst node.
308 void AddEdge(Region* src, Region* dst) const;
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700309 // Builds the non-SSA sea-ir representation of the function @code_item from @dex_file
310 // with class id @class_def_idx and method id @method_idx.
311 void BuildMethodSeaGraph(const art::DexFile::CodeItem* code_item,
Dragos Sbirleab40eddf2013-07-31 13:37:31 -0700312 const art::DexFile& dex_file, uint32_t class_def_idx,
313 uint32_t method_idx, uint32_t method_access_flags);
Brian Carlstrom1db91132013-07-12 18:05:20 -0700314 // Computes immediate dominators for each region.
315 // Precondition: ComputeMethodSeaGraph()
316 void ComputeIDominators();
317 // Computes Downward Exposed Definitions for all regions in the graph.
318 void ComputeDownExposedDefs();
319 // Computes the reaching definitions set following the equations from
320 // Cooper & Torczon, "Engineering a Compiler", second edition, page 491.
321 // Precondition: ComputeDEDefs()
322 void ComputeReachingDefs();
323 // Computes the reverse-postorder numbering for the region nodes.
324 // Precondition: ComputeDEDefs()
325 void ComputeRPO();
326 // Computes the dominance frontier for all regions in the graph,
327 // following the algorithm from
328 // Cooper & Torczon, "Engineering a Compiler", second edition, page 499.
329 // Precondition: ComputeIDominators()
330 void ComputeDominanceFrontier();
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700331 // Converts the IR to semi-pruned SSA form.
Brian Carlstrom1db91132013-07-12 18:05:20 -0700332 void ConvertToSSA();
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700333 // Performs the renaming phase of the SSA transformation during ConvertToSSA() execution.
334 void RenameAsSSA();
Brian Carlstrom1db91132013-07-12 18:05:20 -0700335 // Identifies the definitions corresponding to uses for region @node
336 // by using the scoped hashtable of names @ scoped_table.
337 void RenameAsSSA(Region* node, utils::ScopedHashtable<int, InstructionNode*>* scoped_table);
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700338
339 virtual void Accept(IRVisitor* visitor) {
340 visitor->Initialize(this);
341 visitor->Visit(this);
342 visitor->Traverse(this);
343 }
344
345 virtual ~SeaGraph() {}
346 // Generate LLVM IR for the method.
347 // Precondition: ConvertToSSA().
348 void GenerateLLVM();
Brian Carlstrom1db91132013-07-12 18:05:20 -0700349
Brian Carlstrom7940e442013-07-12 13:46:57 -0700350 static SeaGraph graph_;
351 std::vector<Region*> regions_;
Dragos Sbirlea0e260a32013-06-21 09:20:34 -0700352 std::vector<SignatureNode*> parameters_;
Dragos Sbirlea6bee4452013-07-26 12:05:03 -0700353 const art::DexFile& dex_file_;
Dragos Sbirleab40eddf2013-07-31 13:37:31 -0700354 const art::DexFile::CodeItem* code_item_;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700355};
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700356} // namespace sea_ir
Brian Carlstromfc0e3212013-07-17 14:40:12 -0700357#endif // ART_COMPILER_SEA_IR_SEA_H_