blob: c5ec2b9c6aa13dd40d87ac171d05c1539d7313a3 [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#include "sea.h"
18
19#include "file_output_stream.h"
Brian Carlstrom1db91132013-07-12 18:05:20 -070020#include "instruction_tools.h"
21
Brian Carlstrom7940e442013-07-12 13:46:57 -070022
23#define MAX_REACHING_DEF_ITERERATIONS (10)
24
25namespace sea_ir {
26
27SeaGraph SeaGraph::graph_;
28int SeaNode::current_max_node_id_ = 0;
29
30
31SeaGraph* SeaGraph::GetCurrentGraph() {
32 return &sea_ir::SeaGraph::graph_;
33}
34
35void SeaGraph::DumpSea(std::string filename) const {
Brian Carlstrom1db91132013-07-12 18:05:20 -070036 LOG(INFO) << "Starting to write SEA string to file.";
Brian Carlstrom7940e442013-07-12 13:46:57 -070037 std::string result;
38 result += "digraph seaOfNodes {\n";
39 for (std::vector<Region*>::const_iterator cit = regions_.begin(); cit != regions_.end(); cit++) {
40 (*cit)->ToDot(result);
41 }
42 result += "}\n";
43 art::File* file = art::OS::OpenFile(filename.c_str(), true, true);
44 art::FileOutputStream fos(file);
45 fos.WriteFully(result.c_str(), result.size());
46 LOG(INFO) << "Written SEA string to file.";
47}
48
49void SeaGraph::AddEdge(Region* src, Region* dst) const {
50 src->AddSuccessor(dst);
51 dst->AddPredecessor(src);
52}
53
Brian Carlstrom1db91132013-07-12 18:05:20 -070054void SeaGraph::ComputeRPO(Region* current_region, int& current_rpo) {
55 current_region->SetRPO(VISITING);
56 std::vector<sea_ir::Region*>* succs = current_region->GetSuccessors();
57 for (std::vector<sea_ir::Region*>::iterator succ_it = succs->begin();
58 succ_it != succs->end(); ++succ_it) {
59 if (NOT_VISITED == (*succ_it)->GetRPO()) {
60 SeaGraph::ComputeRPO(*succ_it, current_rpo);
61 }
62 }
63 current_region->SetRPO(current_rpo--);
64}
65
66void SeaGraph::ComputeIDominators() {
67 bool changed = true;
68 while (changed) {
69 changed = false;
70 // Entry node has itself as IDOM.
71 std::vector<Region*>::iterator crt_it;
72 std::set<Region*> processedNodes;
73 // Find and mark the entry node(s).
74 for (crt_it = regions_.begin(); crt_it != regions_.end(); ++crt_it) {
75 if ((*crt_it)->GetPredecessors()->size() == 0) {
76 processedNodes.insert(*crt_it);
77 (*crt_it)->SetIDominator(*crt_it);
78 }
79 }
80 for (crt_it = regions_.begin(); crt_it != regions_.end(); ++crt_it) {
81 if ((*crt_it)->GetPredecessors()->size() == 0) {
82 continue;
83 }
84 // NewIDom = first (processed) predecessor of b.
85 Region* new_dom = NULL;
86 std::vector<Region*>* preds = (*crt_it)->GetPredecessors();
87 DCHECK(NULL != preds);
88 Region* root_pred = NULL;
89 for (std::vector<Region*>::iterator pred_it = preds->begin();
90 pred_it != preds->end(); ++pred_it) {
91 if (processedNodes.end() != processedNodes.find((*pred_it))) {
92 root_pred = *pred_it;
93 new_dom = root_pred;
94 break;
95 }
96 }
97 // For all other predecessors p of b, if idom is not set,
98 // then NewIdom = Intersect(p, NewIdom)
99 for (std::vector<Region*>::const_iterator pred_it = preds->begin();
100 pred_it != preds->end(); ++pred_it) {
101 DCHECK(NULL != *pred_it);
102 // if IDOMS[p] != UNDEFINED
103 if ((*pred_it != root_pred) && (*pred_it)->GetIDominator() != NULL) {
104 DCHECK(NULL != new_dom);
105 new_dom = SeaGraph::Intersect(*pred_it, new_dom);
106 }
107 }
108 DCHECK(NULL != *crt_it);
109 if ((*crt_it)->GetIDominator() != new_dom) {
110 (*crt_it)->SetIDominator(new_dom);
111 changed = true;
112 }
113 processedNodes.insert(*crt_it);
114 }
115 }
116
117 // For easily ordering of regions we need edges dominator->dominated.
118 for (std::vector<Region*>::iterator region_it = regions_.begin();
119 region_it != regions_.end(); region_it++) {
120 Region* idom = (*region_it)->GetIDominator();
121 if (idom != *region_it) {
122 idom->AddToIDominatedSet(*region_it);
123 }
124 }
125}
126
127Region* SeaGraph::Intersect(Region* i, Region* j) {
128 Region* finger1 = i;
129 Region* finger2 = j;
130 while (finger1 != finger2) {
131 while (finger1->GetRPO() > finger2->GetRPO()) {
132 DCHECK(NULL != finger1);
133 finger1 = finger1->GetIDominator(); // should have: finger1 != NULL
134 DCHECK(NULL != finger1);
135 }
136 while (finger1->GetRPO() < finger2->GetRPO()) {
137 DCHECK(NULL != finger2);
138 finger2 = finger2->GetIDominator(); // should have: finger1 != NULL
139 DCHECK(NULL != finger2);
140 }
141 }
142 return finger1; // finger1 should be equal to finger2 at this point.
143}
144
Brian Carlstrom7940e442013-07-12 13:46:57 -0700145void SeaGraph::ComputeDownExposedDefs() {
146 for (std::vector<Region*>::iterator region_it = regions_.begin();
147 region_it != regions_.end(); region_it++) {
148 (*region_it)->ComputeDownExposedDefs();
149 }
150}
151
152void SeaGraph::ComputeReachingDefs() {
153 // Iterate until the reaching definitions set doesn't change anymore.
154 // (See Cooper & Torczon, "Engineering a Compiler", second edition, page 487)
155 bool changed = true;
156 int iteration = 0;
157 while (changed && (iteration < MAX_REACHING_DEF_ITERERATIONS)) {
158 iteration++;
159 changed = false;
160 // TODO: optimize the ordering if this becomes performance bottleneck.
161 for (std::vector<Region*>::iterator regions_it = regions_.begin();
162 regions_it != regions_.end();
163 regions_it++) {
164 changed |= (*regions_it)->UpdateReachingDefs();
165 }
166 }
167 DCHECK(!changed) << "Reaching definitions computation did not reach a fixed point.";
168}
169
170
Brian Carlstrom1db91132013-07-12 18:05:20 -0700171void SeaGraph::BuildMethodSeaGraph(const art::DexFile::CodeItem* code_item,
172 const art::DexFile& dex_file) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700173 const uint16_t* code = code_item->insns_;
174 const size_t size_in_code_units = code_item->insns_size_in_code_units_;
Brian Carlstrom1db91132013-07-12 18:05:20 -0700175 // This maps target instruction pointers to their corresponding region objects.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700176 std::map<const uint16_t*, Region*> target_regions;
177 size_t i = 0;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700178 // Pass: Find the start instruction of basic blocks
179 // by locating targets and flow-though instructions of branches.
180 while (i < size_in_code_units) {
181 const art::Instruction* inst = art::Instruction::At(&code[i]);
Brian Carlstrom1db91132013-07-12 18:05:20 -0700182 if (inst->IsBranch() || inst->IsUnconditional()) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700183 int32_t offset = inst->GetTargetOffset();
Brian Carlstrom1db91132013-07-12 18:05:20 -0700184 if (target_regions.end() == target_regions.find(&code[i + offset])) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700185 Region* region = GetNewRegion();
Brian Carlstrom1db91132013-07-12 18:05:20 -0700186 target_regions.insert(std::pair<const uint16_t*, Region*>(&code[i + offset], region));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700187 }
Brian Carlstrom1db91132013-07-12 18:05:20 -0700188 if (inst->CanFlowThrough()
189 && (target_regions.end() == target_regions.find(&code[i + inst->SizeInCodeUnits()]))) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700190 Region* region = GetNewRegion();
Brian Carlstrom1db91132013-07-12 18:05:20 -0700191 target_regions.insert(
192 std::pair<const uint16_t*, Region*>(&code[i + inst->SizeInCodeUnits()], region));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700193 }
194 }
195 i += inst->SizeInCodeUnits();
196 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700197 // Pass: Assign instructions to region nodes and
198 // assign branches their control flow successors.
199 i = 0;
Brian Carlstrom1db91132013-07-12 18:05:20 -0700200 Region* r = GetNewRegion();
201 SignatureNode* parameter_def_node = new sea_ir::SignatureNode(code_item->registers_size_-1,
202 code_item->ins_size_);
203 r->AddChild(parameter_def_node);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700204 sea_ir::InstructionNode* last_node = NULL;
205 sea_ir::InstructionNode* node = NULL;
206 while (i < size_in_code_units) {
207 const art::Instruction* inst = art::Instruction::At(&code[i]); //TODO: find workaround for this
208 last_node = node;
209 node = new sea_ir::InstructionNode(inst);
210
211 if (inst->IsBranch() || inst->IsUnconditional()) {
212 int32_t offset = inst->GetTargetOffset();
Brian Carlstrom1db91132013-07-12 18:05:20 -0700213 std::map<const uint16_t*, Region*>::iterator it = target_regions.find(&code[i + offset]);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700214 DCHECK(it != target_regions.end());
215 AddEdge(r, it->second); // Add edge to branch target.
216 }
217
218 std::map<const uint16_t*, Region*>::iterator it = target_regions.find(&code[i]);
219 if (target_regions.end() != it) {
220 // Get the already created region because this is a branch target.
221 Region* nextRegion = it->second;
Brian Carlstrom1db91132013-07-12 18:05:20 -0700222 if (last_node->GetInstruction()->IsBranch()
223 && last_node->GetInstruction()->CanFlowThrough()) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700224 AddEdge(r, it->second); // Add flow-through edge.
225 }
226 r = nextRegion;
227 }
Brian Carlstrom1db91132013-07-12 18:05:20 -0700228 bool definesRegister = (0 != InstructionTools::instruction_attributes_[inst->Opcode()]
229 && (1 << kDA));
230 LOG(INFO)<< inst->GetDexPc(code) << "*** " << inst->DumpString(&dex_file)
231 << " region:" <<r->StringId() << "Definition?" << definesRegister << std::endl;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700232 r->AddChild(node);
233 i += inst->SizeInCodeUnits();
234 }
Brian Carlstrom1db91132013-07-12 18:05:20 -0700235}
Brian Carlstrom7940e442013-07-12 13:46:57 -0700236
Brian Carlstrom1db91132013-07-12 18:05:20 -0700237void SeaGraph::ComputeRPO() {
238 int rpo_id = regions_.size() - 1;
239 for (std::vector<Region*>::const_iterator crt_it = regions_.begin(); crt_it != regions_.end();
240 ++crt_it) {
241 if ((*crt_it)->GetPredecessors()->size() == 0) {
242 ComputeRPO(*crt_it, rpo_id);
243 }
244 }
245}
246
247// Performs the renaming phase in traditional SSA transformations.
248// See: Cooper & Torczon, "Engineering a Compiler", second edition, page 505.)
249void SeaGraph::RenameAsSSA() {
250 utils::ScopedHashtable<int, InstructionNode*> scoped_table;
251 scoped_table.OpenScope();
252 for (std::vector<Region*>::iterator region_it = regions_.begin(); region_it != regions_.end();
253 region_it++) {
254 if ((*region_it)->GetIDominator() == *region_it) {
255 RenameAsSSA(*region_it, &scoped_table);
256 }
257 }
258
259 scoped_table.CloseScope();
260}
261
262void SeaGraph::ConvertToSSA() {
263 // Pass: find global names.
264 // The map @block maps registers to the blocks in which they are defined.
265 std::map<int, std::set<Region*> > blocks;
266 // The set @globals records registers whose use
267 // is in a different block than the corresponding definition.
268 std::set<int> globals;
269 for (std::vector<Region*>::iterator region_it = regions_.begin(); region_it != regions_.end();
270 region_it++) {
271 std::set<int> var_kill;
272 std::vector<InstructionNode*>* instructions = (*region_it)->GetInstructions();
273 for (std::vector<InstructionNode*>::iterator inst_it = instructions->begin();
274 inst_it != instructions->end(); inst_it++) {
275 std::vector<int> used_regs = (*inst_it)->GetUses();
276 for (std::size_t i = 0; i < used_regs.size(); i++) {
277 int used_reg = used_regs[i];
278 if (var_kill.find(used_reg) == var_kill.end()) {
279 globals.insert(used_reg);
280 }
281 }
282 const int reg_def = (*inst_it)->GetResultRegister();
283 if (reg_def != NO_REGISTER) {
284 var_kill.insert(reg_def);
285 }
286
287 blocks.insert(std::pair<int, std::set<Region*> >(reg_def, std::set<Region*>()));
288 std::set<Region*>* reg_def_blocks = &(blocks.find(reg_def)->second);
289 reg_def_blocks->insert(*region_it);
290 }
291 }
292
293 // Pass: Actually add phi-nodes to regions.
294 for (std::set<int>::const_iterator globals_it = globals.begin();
295 globals_it != globals.end(); globals_it++) {
296 int global = *globals_it;
297 // Copy the set, because we will modify the worklist as we go.
298 std::set<Region*> worklist((*(blocks.find(global))).second);
299 for (std::set<Region*>::const_iterator b_it = worklist.begin(); b_it != worklist.end(); b_it++) {
300 std::set<Region*>* df = (*b_it)->GetDominanceFrontier();
301 for (std::set<Region*>::const_iterator df_it = df->begin(); df_it != df->end(); df_it++) {
302 if ((*df_it)->InsertPhiFor(global)) {
303 // Check that the dominance frontier element is in the worklist already
304 // because we only want to break if the element is actually not there yet.
305 if (worklist.find(*df_it) == worklist.end()) {
306 worklist.insert(*df_it);
307 b_it = worklist.begin();
308 break;
309 }
310 }
311 }
312 }
313 }
314 // Pass: Build edges to the definition corresponding to each use.
315 // (This corresponds to the renaming phase in traditional SSA transformations.
316 // See: Cooper & Torczon, "Engineering a Compiler", second edition, page 505.)
317 RenameAsSSA();
318}
319
320void SeaGraph::RenameAsSSA(Region* crt_region,
321 utils::ScopedHashtable<int, InstructionNode*>* scoped_table) {
322 scoped_table->OpenScope();
323 // Rename phi nodes defined in the current region.
324 std::vector<PhiInstructionNode*>* phis = crt_region->GetPhiNodes();
325 for (std::vector<PhiInstructionNode*>::iterator phi_it = phis->begin();
326 phi_it != phis->end(); phi_it++) {
327 int reg_no = (*phi_it)->GetRegisterNumber();
328 scoped_table->Add(reg_no, (*phi_it));
329 }
330 // Rename operands of instructions from the current region.
331 std::vector<InstructionNode*>* instructions = crt_region->GetInstructions();
332 for (std::vector<InstructionNode*>::const_iterator instructions_it = instructions->begin();
333 instructions_it != instructions->end(); instructions_it++) {
334 InstructionNode* current_instruction = (*instructions_it);
335 // Rename uses.
336 std::vector<int> used_regs = current_instruction->GetUses();
337 for (std::vector<int>::const_iterator reg_it = used_regs.begin();
338 reg_it != used_regs.end(); reg_it++) {
339 int current_used_reg = (*reg_it);
340 InstructionNode* definition = scoped_table->Lookup(current_used_reg);
341 current_instruction->RenameToSSA(current_used_reg, definition);
342 }
343 // Update scope table with latest definitions.
344 std::vector<int> def_regs = current_instruction->GetDefinitions();
345 for (std::vector<int>::const_iterator reg_it = def_regs.begin();
346 reg_it != def_regs.end(); reg_it++) {
347 int current_defined_reg = (*reg_it);
348 scoped_table->Add(current_defined_reg, current_instruction);
349 }
350 }
351 // Fill in uses of phi functions in CFG successor regions.
352 const std::vector<Region*>* successors = crt_region->GetSuccessors();
353 for (std::vector<Region*>::const_iterator successors_it = successors->begin();
354 successors_it != successors->end(); successors_it++) {
355 Region* successor = (*successors_it);
356 successor->SetPhiDefinitionsForUses(scoped_table, crt_region);
357 }
358
359 // Rename all successors in the dominators tree.
360 const std::set<Region*>* dominated_nodes = crt_region->GetIDominatedSet();
361 for (std::set<Region*>::const_iterator dominated_nodes_it = dominated_nodes->begin();
362 dominated_nodes_it != dominated_nodes->end(); dominated_nodes_it++) {
363 Region* dominated_node = (*dominated_nodes_it);
364 RenameAsSSA(dominated_node, scoped_table);
365 }
366 scoped_table->CloseScope();
367}
368
369void SeaGraph::CompileMethod(const art::DexFile::CodeItem* code_item,
370 uint32_t class_def_idx, uint32_t method_idx, const art::DexFile& dex_file) {
371 // Two passes: Builds the intermediate structure (non-SSA) of the sea-ir for the function.
372 BuildMethodSeaGraph(code_item, dex_file);
373 //Pass: Compute reverse post-order of regions.
374 ComputeRPO();
375 // Multiple passes: compute immediate dominators.
376 ComputeIDominators();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700377 // Pass: compute downward-exposed definitions.
378 ComputeDownExposedDefs();
Brian Carlstrom1db91132013-07-12 18:05:20 -0700379 // Multiple Passes (iterative fixed-point algorithm): Compute reaching definitions
Brian Carlstrom7940e442013-07-12 13:46:57 -0700380 ComputeReachingDefs();
Brian Carlstrom1db91132013-07-12 18:05:20 -0700381 // Pass (O(nlogN)): Compute the dominance frontier for region nodes.
382 ComputeDominanceFrontier();
383 // Two Passes: Phi node insertion.
384 ConvertToSSA();
385}
386
387
388void SeaGraph::ComputeDominanceFrontier() {
389 for (std::vector<Region*>::iterator region_it = regions_.begin();
390 region_it != regions_.end(); region_it++) {
391 std::vector<Region*>* preds = (*region_it)->GetPredecessors();
392 if (preds->size() > 1) {
393 for (std::vector<Region*>::iterator pred_it = preds->begin();
394 pred_it != preds->end(); pred_it++) {
395 Region* runner = *pred_it;
396 while (runner != (*region_it)->GetIDominator()) {
397 runner->AddToDominanceFrontier(*region_it);
398 runner = runner->GetIDominator();
399 }
400 }
401 }
402 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700403}
404
405Region* SeaGraph::GetNewRegion() {
406 Region* new_region = new Region();
407 AddRegion(new_region);
408 return new_region;
409}
410
411void SeaGraph::AddRegion(Region* r) {
412 DCHECK(r) << "Tried to add NULL region to SEA graph.";
413 regions_.push_back(r);
414}
415
Brian Carlstrom1db91132013-07-12 18:05:20 -0700416void SeaNode::AddSuccessor(Region* successor) {
417 DCHECK(successor) << "Tried to add NULL successor to SEA node.";
418 successors_.push_back(successor);
419 return;
420}
421
422void SeaNode::AddPredecessor(Region* predecessor) {
423 DCHECK(predecessor) << "Tried to add NULL predecessor to SEA node.";
424 predecessors_.push_back(predecessor);
425}
426
Brian Carlstrom7940e442013-07-12 13:46:57 -0700427void Region::AddChild(sea_ir::InstructionNode* instruction) {
428 DCHECK(instruction) << "Tried to add NULL instruction to region node.";
429 instructions_.push_back(instruction);
430}
431
432SeaNode* Region::GetLastChild() const {
433 if (instructions_.size() > 0) {
434 return instructions_.back();
435 }
436 return NULL;
437}
438
Brian Carlstrom7940e442013-07-12 13:46:57 -0700439void Region::ToDot(std::string& result) const {
Brian Carlstrom1db91132013-07-12 18:05:20 -0700440 result += "\n// Region: \n" + StringId() + " [label=\"region " + StringId() + "(rpo=";
441 std::stringstream ss;
442 ss << rpo_;
443 result.append(ss.str());
444 if (NULL != GetIDominator()) {
445 result += " dom=" + GetIDominator()->StringId();
446 }
447 result += ")\"];\n";
448
449 // Save phi-nodes.
450 for (std::vector<PhiInstructionNode*>::const_iterator cit = phi_instructions_.begin();
451 cit != phi_instructions_.end(); cit++) {
452 (*cit)->ToDot(result);
453 result += StringId() + " -> " + (*cit)->StringId() + "; // phi-function \n";
454 }
455
456 // Save instruction nodes.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700457 for (std::vector<InstructionNode*>::const_iterator cit = instructions_.begin();
458 cit != instructions_.end(); cit++) {
459 (*cit)->ToDot(result);
Brian Carlstrom1db91132013-07-12 18:05:20 -0700460 result += StringId() + " -> " + (*cit)->StringId() + "; // region -> instruction \n";
Brian Carlstrom7940e442013-07-12 13:46:57 -0700461 }
462
463 for (std::vector<Region*>::const_iterator cit = successors_.begin(); cit != successors_.end();
464 cit++) {
465 DCHECK(NULL != *cit) << "Null successor found for SeaNode" << GetLastChild()->StringId() << ".";
466 result += GetLastChild()->StringId() + " -> " + (*cit)->StringId() + ";\n\n";
467 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700468 // Save reaching definitions.
469 for (std::map<int, std::set<sea_ir::InstructionNode*>* >::const_iterator cit =
470 reaching_defs_.begin();
471 cit != reaching_defs_.end(); cit++) {
472 for (std::set<sea_ir::InstructionNode*>::const_iterator
473 reaching_set_it = (*cit).second->begin();
474 reaching_set_it != (*cit).second->end();
475 reaching_set_it++) {
476 result += (*reaching_set_it)->StringId() +
477 " -> " + StringId() +
478 " [style=dotted]; // Reaching def.\n";
479 }
480 }
Brian Carlstrom1db91132013-07-12 18:05:20 -0700481 // Save dominance frontier.
482 for (std::set<Region*>::const_iterator cit = df_.begin(); cit != df_.end(); cit++) {
483 result += StringId() +
484 " -> " + (*cit)->StringId() +
485 " [color=gray]; // Dominance frontier.\n";
486 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700487 result += "// End Region.\n";
488}
489
Brian Carlstrom7940e442013-07-12 13:46:57 -0700490void Region::ComputeDownExposedDefs() {
491 for (std::vector<InstructionNode*>::const_iterator inst_it = instructions_.begin();
492 inst_it != instructions_.end(); inst_it++) {
493 int reg_no = (*inst_it)->GetResultRegister();
494 std::map<int, InstructionNode*>::iterator res = de_defs_.find(reg_no);
495 if ((reg_no != NO_REGISTER) && (res == de_defs_.end())) {
496 de_defs_.insert(std::pair<int, InstructionNode*>(reg_no, *inst_it));
497 } else {
498 res->second = *inst_it;
499 }
500 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700501 for (std::map<int, sea_ir::InstructionNode*>::const_iterator cit = de_defs_.begin();
502 cit != de_defs_.end(); cit++) {
503 (*cit).second->MarkAsDEDef();
504 }
505}
506
Brian Carlstrom7940e442013-07-12 13:46:57 -0700507const std::map<int, sea_ir::InstructionNode*>* Region::GetDownExposedDefs() const {
508 return &de_defs_;
509}
510
511std::map<int, std::set<sea_ir::InstructionNode*>* >* Region::GetReachingDefs() {
512 return &reaching_defs_;
513}
514
515bool Region::UpdateReachingDefs() {
516 std::map<int, std::set<sea_ir::InstructionNode*>* > new_reaching;
517 for (std::vector<Region*>::const_iterator pred_it = predecessors_.begin();
518 pred_it != predecessors_.end(); pred_it++) {
519 // The reaching_defs variable will contain reaching defs __for current predecessor only__
520 std::map<int, std::set<sea_ir::InstructionNode*>* > reaching_defs;
521 std::map<int, std::set<sea_ir::InstructionNode*>* >* pred_reaching = (*pred_it)->GetReachingDefs();
522 const std::map<int, InstructionNode*>* de_defs = (*pred_it)->GetDownExposedDefs();
523
524 // The definitions from the reaching set of the predecessor
525 // may be shadowed by downward exposed definitions from the predecessor,
526 // otherwise the defs from the reaching set are still good.
527 for (std::map<int, InstructionNode*>::const_iterator de_def = de_defs->begin();
528 de_def != de_defs->end(); de_def++) {
529 std::set<InstructionNode*>* solo_def;
530 solo_def = new std::set<InstructionNode*>();
531 solo_def->insert(de_def->second);
532 reaching_defs.insert(
533 std::pair<int const, std::set<InstructionNode*>*>(de_def->first, solo_def));
534 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700535 reaching_defs.insert(pred_reaching->begin(), pred_reaching->end());
536
537 // Now we combine the reaching map coming from the current predecessor (reaching_defs)
538 // with the accumulated set from all predecessors so far (from new_reaching).
539 std::map<int, std::set<sea_ir::InstructionNode*>*>::iterator reaching_it = reaching_defs.begin();
540 for (; reaching_it != reaching_defs.end(); reaching_it++) {
541 std::map<int, std::set<sea_ir::InstructionNode*>*>::iterator crt_entry =
542 new_reaching.find(reaching_it->first);
543 if (new_reaching.end() != crt_entry) {
544 crt_entry->second->insert(reaching_it->second->begin(), reaching_it->second->end());
545 } else {
546 new_reaching.insert(
547 std::pair<int, std::set<sea_ir::InstructionNode*>*>(
548 reaching_it->first,
549 reaching_it->second) );
550 }
551 }
552 }
553 bool changed = false;
554 // Because the sets are monotonically increasing,
555 // we can compare sizes instead of using set comparison.
556 // TODO: Find formal proof.
557 int old_size = 0;
558 if (-1 == reaching_defs_size_) {
559 std::map<int, std::set<sea_ir::InstructionNode*>*>::iterator reaching_it = reaching_defs_.begin();
560 for (; reaching_it != reaching_defs_.end(); reaching_it++) {
561 old_size += (*reaching_it).second->size();
562 }
563 } else {
564 old_size = reaching_defs_size_;
565 }
566 int new_size = 0;
567 std::map<int, std::set<sea_ir::InstructionNode*>*>::iterator reaching_it = new_reaching.begin();
568 for (; reaching_it != new_reaching.end(); reaching_it++) {
569 new_size += (*reaching_it).second->size();
570 }
571 if (old_size != new_size) {
572 changed = true;
573 }
574 if (changed) {
575 reaching_defs_ = new_reaching;
576 reaching_defs_size_ = new_size;
577 }
578 return changed;
579}
580
Brian Carlstrom1db91132013-07-12 18:05:20 -0700581bool Region::InsertPhiFor(int reg_no) {
582 if (!ContainsPhiFor(reg_no)) {
583 phi_set_.insert(reg_no);
584 PhiInstructionNode* new_phi = new PhiInstructionNode(reg_no);
585 phi_instructions_.push_back(new_phi);
586 return true;
587 }
588 return false;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700589}
590
Brian Carlstrom1db91132013-07-12 18:05:20 -0700591void Region::SetPhiDefinitionsForUses(
592 const utils::ScopedHashtable<int, InstructionNode*>* scoped_table, Region* predecessor) {
593 int predecessor_id = -1;
594 for (unsigned int crt_pred_id = 0; crt_pred_id < predecessors_.size(); crt_pred_id++) {
595 if (predecessors_.at(crt_pred_id) == predecessor) {
596 predecessor_id = crt_pred_id;
597 }
598 }
599 DCHECK_NE(-1, predecessor_id);
600 for (std::vector<PhiInstructionNode*>::iterator phi_it = phi_instructions_.begin();
601 phi_it != phi_instructions_.end(); phi_it++) {
602 PhiInstructionNode* phi = (*phi_it);
603 int reg_no = phi->GetRegisterNumber();
604 InstructionNode* definition = scoped_table->Lookup(reg_no);
605 phi->RenameToSSA(reg_no, definition, predecessor_id);
606 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700607}
608
Brian Carlstrom1db91132013-07-12 18:05:20 -0700609void InstructionNode::ToDot(std::string& result) const {
610 result += "// Instruction: \n" + StringId() +
611 " [label=\"" + instruction_->DumpString(NULL) + "\"";
612 if (de_def_) {
613 result += "style=bold";
614 }
615 result += "];\n";
616 // SSA definitions:
617 for (std::map<int, InstructionNode* >::const_iterator def_it = definition_edges_.begin();
618 def_it != definition_edges_.end(); def_it++) {
619 if (NULL != def_it->second) {
620 result += def_it->second->StringId() + " -> " + StringId() +"[color=red,label=\"";
621 std::stringstream ss;
622 ss << def_it->first;
623 result.append(ss.str());
624 result += "\"] ; // ssa edge\n";
625 }
626 }
627}
628
629void InstructionNode::MarkAsDEDef() {
630 de_def_ = true;
631}
632
633int InstructionNode::GetResultRegister() const {
634 if (instruction_->HasVRegA()) {
635 return instruction_->VRegA();
636 }
637 return NO_REGISTER;
638}
639
640std::vector<int> InstructionNode::GetDefinitions() const {
641 // TODO: Extend this to handle instructions defining more than one register (if any)
642 // The return value should be changed to pointer to field then; for now it is an object
643 // so that we avoid possible memory leaks from allocating objects dynamically.
644 std::vector<int> definitions;
645 int result = GetResultRegister();
646 if (NO_REGISTER != result) {
647 definitions.push_back(result);
648 }
649 return definitions;
650}
651
652std::vector<int> InstructionNode::GetUses() {
653 std::vector<int> uses; // Using vector<> instead of set<> because order matters.
654
655 if (!InstructionTools::IsDefinition(instruction_) && (instruction_->HasVRegA())) {
656 int vA = instruction_->VRegA();
657 uses.push_back(vA);
658 }
659 if (instruction_->HasVRegB()) {
660 int vB = instruction_->VRegB();
661 uses.push_back(vB);
662 }
663 if (instruction_->HasVRegC()) {
664 int vC = instruction_->VRegC();
665 uses.push_back(vC);
666 }
667 // TODO: Add support for function argument registers.
668 return uses;
669}
670
671void PhiInstructionNode::ToDot(std::string& result) const {
672 result += "// PhiInstruction: \n" + StringId() +
673 " [label=\"" + "PHI(";
674 std::stringstream phi_reg_stream;
675 phi_reg_stream << register_no_;
676 result.append(phi_reg_stream.str());
677 result += ")\"";
678 result += "];\n";
679
680 for (std::vector<std::map<int, InstructionNode*>*>::const_iterator pred_it = definition_edges_.begin();
681 pred_it != definition_edges_.end(); pred_it++) {
682 std::map<int, InstructionNode*>* defs_from_pred = *pred_it;
683 for (std::map<int, InstructionNode* >::const_iterator def_it = defs_from_pred->begin();
684 def_it != defs_from_pred->end(); def_it++) {
685 if (NULL != def_it->second) {
686 result += def_it->second->StringId() + " -> " + StringId() +"[color=red,label=\"vR = ";
687 std::stringstream ss;
688 ss << def_it->first;
689 result.append(ss.str());
690 result += "\"] ; // phi-ssa edge\n";
691 } else {
692 result += StringId() + " -> " + StringId() +"[color=blue,label=\"vR = ";
693 std::stringstream ss;
694 ss << def_it->first;
695 result.append(ss.str());
696 result += "\"] ; // empty phi-ssa edge\n";
697 }
698 }
699 }
700}
Brian Carlstrom7940e442013-07-12 13:46:57 -0700701} // end namespace sea_ir