| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/flow_graph_allocator.h" | 5 #include "vm/flow_graph_allocator.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
| 9 #include "vm/il_printer.h" | 9 #include "vm/il_printer.h" |
| 10 #include "vm/flow_graph.h" | 10 #include "vm/flow_graph.h" |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 59 return (pos | 1); | 59 return (pos | 1); |
| 60 } | 60 } |
| 61 | 61 |
| 62 | 62 |
| 63 FlowGraphAllocator::FlowGraphAllocator(const FlowGraph& flow_graph) | 63 FlowGraphAllocator::FlowGraphAllocator(const FlowGraph& flow_graph) |
| 64 : flow_graph_(flow_graph), | 64 : flow_graph_(flow_graph), |
| 65 reaching_defs_(flow_graph), | 65 reaching_defs_(flow_graph), |
| 66 value_representations_(flow_graph.max_virtual_register_number()), | 66 value_representations_(flow_graph.max_virtual_register_number()), |
| 67 block_order_(flow_graph.reverse_postorder()), | 67 block_order_(flow_graph.reverse_postorder()), |
| 68 postorder_(flow_graph.postorder()), | 68 postorder_(flow_graph.postorder()), |
| 69 live_out_(block_order_.length()), | 69 liveness_(flow_graph), |
| 70 kill_(block_order_.length()), | |
| 71 live_in_(block_order_.length()), | |
| 72 vreg_count_(flow_graph.max_virtual_register_number()), | 70 vreg_count_(flow_graph.max_virtual_register_number()), |
| 73 live_ranges_(flow_graph.max_virtual_register_number()), | 71 live_ranges_(flow_graph.max_virtual_register_number()), |
| 74 cpu_regs_(), | 72 cpu_regs_(), |
| 75 fpu_regs_(), | 73 fpu_regs_(), |
| 76 blocked_cpu_registers_(), | 74 blocked_cpu_registers_(), |
| 77 blocked_fpu_registers_(), | 75 blocked_fpu_registers_(), |
| 78 cpu_spill_slot_count_(0) { | 76 cpu_spill_slot_count_(0) { |
| 79 for (intptr_t i = 0; i < vreg_count_; i++) live_ranges_.Add(NULL); | 77 for (intptr_t i = 0; i < vreg_count_; i++) live_ranges_.Add(NULL); |
| 80 for (intptr_t i = 0; i < vreg_count_; i++) { | 78 for (intptr_t i = 0; i < vreg_count_; i++) { |
| 81 value_representations_.Add(kNoRepresentation); | 79 value_representations_.Add(kNoRepresentation); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 109 for (intptr_t i = 0; i < block_order_.length(); ++i) { | 107 for (intptr_t i = 0; i < block_order_.length(); ++i) { |
| 110 BlockEntryInstr* block = block_order_[i]; | 108 BlockEntryInstr* block = block_order_[i]; |
| 111 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 109 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
| 112 Instruction* current = it.Current(); | 110 Instruction* current = it.Current(); |
| 113 if (!current->CanDeoptimize()) current->RemoveEnvironment(); | 111 if (!current->CanDeoptimize()) current->RemoveEnvironment(); |
| 114 } | 112 } |
| 115 } | 113 } |
| 116 } | 114 } |
| 117 | 115 |
| 118 | 116 |
| 119 void FlowGraphAllocator::ComputeInitialSets() { | 117 void SSALivenessAnalysis::ComputeInitialSets() { |
| 120 const intptr_t block_count = postorder_.length(); | 118 const intptr_t block_count = postorder_.length(); |
| 121 for (intptr_t i = 0; i < block_count; i++) { | 119 for (intptr_t i = 0; i < block_count; i++) { |
| 122 BlockEntryInstr* block = postorder_[i]; | 120 BlockEntryInstr* block = postorder_[i]; |
| 123 | 121 |
| 124 BitVector* kill = kill_[i]; | 122 BitVector* kill = kill_[i]; |
| 125 BitVector* live_in = live_in_[i]; | 123 BitVector* live_in = live_in_[i]; |
| 126 | 124 |
| 127 // Iterate backwards starting at the last instruction. | 125 // Iterate backwards starting at the last instruction. |
| 128 for (BackwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 126 for (BackwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
| 129 Instruction* current = it.Current(); | 127 Instruction* current = it.Current(); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 182 const intptr_t use = val->definition()->ssa_temp_index(); | 180 const intptr_t use = val->definition()->ssa_temp_index(); |
| 183 if (!kill_[pred->postorder_number()]->Contains(use)) { | 181 if (!kill_[pred->postorder_number()]->Contains(use)) { |
| 184 live_in_[pred->postorder_number()]->Add(use); | 182 live_in_[pred->postorder_number()]->Add(use); |
| 185 } | 183 } |
| 186 } | 184 } |
| 187 } | 185 } |
| 188 } | 186 } |
| 189 } | 187 } |
| 190 | 188 |
| 191 // Process initial definitions, ie, constants and incoming parameters. | 189 // Process initial definitions, ie, constants and incoming parameters. |
| 192 GraphEntryInstr* graph_entry = flow_graph_.graph_entry(); | 190 for (intptr_t i = 0; i < graph_entry_->initial_definitions()->length(); i++) { |
| 193 for (intptr_t i = 0; i < graph_entry->initial_definitions()->length(); i++) { | 191 intptr_t vreg = (*graph_entry_->initial_definitions())[i]->ssa_temp_index(); |
| 194 intptr_t vreg = (*graph_entry->initial_definitions())[i]->ssa_temp_index(); | 192 kill_[graph_entry_->postorder_number()]->Add(vreg); |
| 195 kill_[graph_entry->postorder_number()]->Add(vreg); | 193 live_in_[graph_entry_->postorder_number()]->Remove(vreg); |
| 196 live_in_[graph_entry->postorder_number()]->Remove(vreg); | |
| 197 } | 194 } |
| 198 | 195 |
| 199 // Update initial live_in sets to match live_out sets. Has to be | 196 // Update initial live_in sets to match live_out sets. Has to be |
| 200 // done in a separate path because of backwards branches. | 197 // done in a separate path because of backwards branches. |
| 201 for (intptr_t i = 0; i < block_count; i++) { | 198 for (intptr_t i = 0; i < block_count; i++) { |
| 202 UpdateLiveIn(*postorder_[i]); | 199 UpdateLiveIn(*postorder_[i]); |
| 203 } | 200 } |
| 204 } | 201 } |
| 205 | 202 |
| 206 | 203 |
| 207 bool FlowGraphAllocator::UpdateLiveOut(const BlockEntryInstr& instr) { | |
| 208 BitVector* live_out = live_out_[instr.postorder_number()]; | |
| 209 bool changed = false; | |
| 210 Instruction* last = instr.last_instruction(); | |
| 211 ASSERT(last != NULL); | |
| 212 for (intptr_t i = 0; i < last->SuccessorCount(); i++) { | |
| 213 BlockEntryInstr* succ = last->SuccessorAt(i); | |
| 214 ASSERT(succ != NULL); | |
| 215 if (live_out->AddAll(live_in_[succ->postorder_number()])) { | |
| 216 changed = true; | |
| 217 } | |
| 218 } | |
| 219 return changed; | |
| 220 } | |
| 221 | |
| 222 | |
| 223 bool FlowGraphAllocator::UpdateLiveIn(const BlockEntryInstr& instr) { | |
| 224 BitVector* live_out = live_out_[instr.postorder_number()]; | |
| 225 BitVector* kill = kill_[instr.postorder_number()]; | |
| 226 BitVector* live_in = live_in_[instr.postorder_number()]; | |
| 227 return live_in->KillAndAdd(kill, live_out); | |
| 228 } | |
| 229 | |
| 230 | |
| 231 void FlowGraphAllocator::ComputeLiveInAndLiveOutSets() { | |
| 232 const intptr_t block_count = postorder_.length(); | |
| 233 bool changed; | |
| 234 do { | |
| 235 changed = false; | |
| 236 | |
| 237 for (intptr_t i = 0; i < block_count; i++) { | |
| 238 const BlockEntryInstr& block = *postorder_[i]; | |
| 239 | |
| 240 // Live-in set depends only on kill set which does not | |
| 241 // change in this loop and live-out set. If live-out | |
| 242 // set does not change there is no need to recompute | |
| 243 // live-in set. | |
| 244 if (UpdateLiveOut(block) && UpdateLiveIn(block)) { | |
| 245 changed = true; | |
| 246 } | |
| 247 } | |
| 248 } while (changed); | |
| 249 } | |
| 250 | |
| 251 | |
| 252 void FlowGraphAllocator::AnalyzeLiveness() { | |
| 253 const intptr_t block_count = postorder_.length(); | |
| 254 for (intptr_t i = 0; i < block_count; i++) { | |
| 255 live_out_.Add(new BitVector(vreg_count_)); | |
| 256 kill_.Add(new BitVector(vreg_count_)); | |
| 257 live_in_.Add(new BitVector(vreg_count_)); | |
| 258 } | |
| 259 | |
| 260 ComputeInitialSets(); | |
| 261 ComputeLiveInAndLiveOutSets(); | |
| 262 } | |
| 263 | |
| 264 | |
| 265 static void PrintBitVector(const char* tag, BitVector* v) { | |
| 266 OS::Print("%s:", tag); | |
| 267 for (BitVector::Iterator it(v); !it.Done(); it.Advance()) { | |
| 268 OS::Print(" %"Pd"", it.Current()); | |
| 269 } | |
| 270 OS::Print("\n"); | |
| 271 } | |
| 272 | |
| 273 | |
| 274 void FlowGraphAllocator::DumpLiveness() { | |
| 275 const intptr_t block_count = postorder_.length(); | |
| 276 for (intptr_t i = 0; i < block_count; i++) { | |
| 277 BlockEntryInstr* block = postorder_[i]; | |
| 278 OS::Print("block @%"Pd" -> ", block->block_id()); | |
| 279 | |
| 280 Instruction* last = block->last_instruction(); | |
| 281 for (intptr_t j = 0; j < last->SuccessorCount(); j++) { | |
| 282 BlockEntryInstr* succ = last->SuccessorAt(j); | |
| 283 OS::Print(" @%"Pd"", succ->block_id()); | |
| 284 } | |
| 285 OS::Print("\n"); | |
| 286 | |
| 287 PrintBitVector(" live out", live_out_[i]); | |
| 288 PrintBitVector(" kill", kill_[i]); | |
| 289 PrintBitVector(" live in", live_in_[i]); | |
| 290 } | |
| 291 } | |
| 292 | |
| 293 | |
| 294 void LiveRange::AddUse(intptr_t pos, Location* location_slot) { | 204 void LiveRange::AddUse(intptr_t pos, Location* location_slot) { |
| 295 ASSERT(location_slot != NULL); | 205 ASSERT(location_slot != NULL); |
| 296 ASSERT((first_use_interval_->start_ <= pos) && | 206 ASSERT((first_use_interval_->start_ <= pos) && |
| 297 (pos <= first_use_interval_->end_)); | 207 (pos <= first_use_interval_->end_)); |
| 298 if ((uses_ != NULL) && | 208 if ((uses_ != NULL) && |
| 299 (uses_->pos() == pos) && | 209 (uses_->pos() == pos) && |
| 300 (uses_->location_slot() == location_slot)) { | 210 (uses_->location_slot() == location_slot)) { |
| 301 return; | 211 return; |
| 302 } | 212 } |
| 303 uses_ = new UsePosition(pos, uses_, location_slot); | 213 uses_ = new UsePosition(pos, uses_, location_slot); |
| (...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 528 ASSERT(postorder_.Last()->IsGraphEntry()); | 438 ASSERT(postorder_.Last()->IsGraphEntry()); |
| 529 BitVector* current_interference_set = NULL; | 439 BitVector* current_interference_set = NULL; |
| 530 for (intptr_t i = 0; i < (block_count - 1); i++) { | 440 for (intptr_t i = 0; i < (block_count - 1); i++) { |
| 531 BlockEntryInstr* block = postorder_[i]; | 441 BlockEntryInstr* block = postorder_[i]; |
| 532 | 442 |
| 533 BlockInfo* block_info = BlockInfoAt(block->start_pos()); | 443 BlockInfo* block_info = BlockInfoAt(block->start_pos()); |
| 534 | 444 |
| 535 // For every SSA value that is live out of this block, create an interval | 445 // For every SSA value that is live out of this block, create an interval |
| 536 // that covers the whole block. It will be shortened if we encounter a | 446 // that covers the whole block. It will be shortened if we encounter a |
| 537 // definition of this value in this block. | 447 // definition of this value in this block. |
| 538 for (BitVector::Iterator it(live_out_[i]); !it.Done(); it.Advance()) { | 448 for (BitVector::Iterator it(liveness_.GetLiveOutSetAt(i)); |
| 449 !it.Done(); |
| 450 it.Advance()) { |
| 539 LiveRange* range = GetLiveRange(it.Current()); | 451 LiveRange* range = GetLiveRange(it.Current()); |
| 540 range->AddUseInterval(block->start_pos(), block->end_pos()); | 452 range->AddUseInterval(block->start_pos(), block->end_pos()); |
| 541 } | 453 } |
| 542 | 454 |
| 543 BlockInfo* loop_header = block_info->loop_header(); | 455 BlockInfo* loop_header = block_info->loop_header(); |
| 544 if ((loop_header != NULL) && (loop_header->last_block() == block)) { | 456 if ((loop_header != NULL) && (loop_header->last_block() == block)) { |
| 545 current_interference_set = | 457 current_interference_set = |
| 546 new BitVector(flow_graph_.max_virtual_register_number()); | 458 new BitVector(flow_graph_.max_virtual_register_number()); |
| 547 ASSERT(loop_header->backedge_interference() == NULL); | 459 ASSERT(loop_header->backedge_interference() == NULL); |
| 548 // All values flowing into the loop header are live at the back-edge and | 460 // All values flowing into the loop header are live at the back-edge and |
| 549 // can interfere with phi moves. | 461 // can interfere with phi moves. |
| 550 current_interference_set->AddAll( | 462 current_interference_set->AddAll( |
| 551 live_in_[loop_header->entry()->postorder_number()]); | 463 liveness_.GetLiveInSet(loop_header->entry())); |
| 552 loop_header->set_backedge_interference( | 464 loop_header->set_backedge_interference( |
| 553 current_interference_set); | 465 current_interference_set); |
| 554 } | 466 } |
| 555 | 467 |
| 556 // Connect outgoing phi-moves that were created in NumberInstructions | 468 // Connect outgoing phi-moves that were created in NumberInstructions |
| 557 // and find last instruction that contributes to liveness. | 469 // and find last instruction that contributes to liveness. |
| 558 Instruction* current = ConnectOutgoingPhiMoves(block, | 470 Instruction* current = ConnectOutgoingPhiMoves(block, |
| 559 current_interference_set); | 471 current_interference_set); |
| 560 | 472 |
| 561 // Now process all instructions in reverse order. | 473 // Now process all instructions in reverse order. |
| 562 while (current != block) { | 474 while (current != block) { |
| 563 // Skip parallel moves that we insert while processing instructions. | 475 // Skip parallel moves that we insert while processing instructions. |
| 564 if (!current->IsParallelMove()) { | 476 if (!current->IsParallelMove()) { |
| 565 ProcessOneInstruction(block, current, current_interference_set); | 477 ProcessOneInstruction(block, current, current_interference_set); |
| 566 } | 478 } |
| 567 current = current->previous(); | 479 current = current->previous(); |
| 568 } | 480 } |
| 569 | 481 |
| 570 | 482 |
| 571 // Check if any values live into the loop can be spilled for free. | 483 // Check if any values live into the loop can be spilled for free. |
| 572 if (block_info->is_loop_header()) { | 484 if (block_info->is_loop_header()) { |
| 573 current_interference_set = NULL; | 485 current_interference_set = NULL; |
| 574 for (BitVector::Iterator it(live_in_[i]); !it.Done(); it.Advance()) { | 486 for (BitVector::Iterator it(liveness_.GetLiveInSetAt(i)); |
| 487 !it.Done(); |
| 488 it.Advance()) { |
| 575 LiveRange* range = GetLiveRange(it.Current()); | 489 LiveRange* range = GetLiveRange(it.Current()); |
| 576 if (HasOnlyUnconstrainedUsesInLoop(range, block_info)) { | 490 if (HasOnlyUnconstrainedUsesInLoop(range, block_info)) { |
| 577 range->MarkHasOnlyUnconstrainedUsesInLoop(block_info->loop_id()); | 491 range->MarkHasOnlyUnconstrainedUsesInLoop(block_info->loop_id()); |
| 578 } | 492 } |
| 579 } | 493 } |
| 580 } | 494 } |
| 581 | 495 |
| 582 ConnectIncomingPhiMoves(block); | 496 ConnectIncomingPhiMoves(block); |
| 583 } | 497 } |
| 584 | 498 |
| (...skipping 1861 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2446 sibling->assigned_location(), | 2360 sibling->assigned_location(), |
| 2447 range->assigned_location()); | 2361 range->assigned_location()); |
| 2448 } | 2362 } |
| 2449 range = sibling; | 2363 range = sibling; |
| 2450 } | 2364 } |
| 2451 } | 2365 } |
| 2452 | 2366 |
| 2453 // Resolve non-linear control flow across branches. | 2367 // Resolve non-linear control flow across branches. |
| 2454 for (intptr_t i = 1; i < block_order_.length(); i++) { | 2368 for (intptr_t i = 1; i < block_order_.length(); i++) { |
| 2455 BlockEntryInstr* block = block_order_[i]; | 2369 BlockEntryInstr* block = block_order_[i]; |
| 2456 BitVector* live = live_in_[block->postorder_number()]; | 2370 BitVector* live = liveness_.GetLiveInSet(block); |
| 2457 for (BitVector::Iterator it(live); !it.Done(); it.Advance()) { | 2371 for (BitVector::Iterator it(live); !it.Done(); it.Advance()) { |
| 2458 LiveRange* range = GetLiveRange(it.Current()); | 2372 LiveRange* range = GetLiveRange(it.Current()); |
| 2459 for (intptr_t j = 0; j < block->PredecessorCount(); j++) { | 2373 for (intptr_t j = 0; j < block->PredecessorCount(); j++) { |
| 2460 ConnectSplitSiblings(range, block->PredecessorAt(j), block); | 2374 ConnectSplitSiblings(range, block->PredecessorAt(j), block); |
| 2461 } | 2375 } |
| 2462 } | 2376 } |
| 2463 } | 2377 } |
| 2464 | 2378 |
| 2465 // Eagerly spill values. | 2379 // Eagerly spill values. |
| 2466 // TODO(vegorov): if value is spilled on the cold path (e.g. by the call) | 2380 // TODO(vegorov): if value is spilled on the cold path (e.g. by the call) |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2513 } | 2427 } |
| 2514 } | 2428 } |
| 2515 } | 2429 } |
| 2516 | 2430 |
| 2517 | 2431 |
| 2518 void FlowGraphAllocator::AllocateRegisters() { | 2432 void FlowGraphAllocator::AllocateRegisters() { |
| 2519 CollectRepresentations(); | 2433 CollectRepresentations(); |
| 2520 | 2434 |
| 2521 EliminateEnvironments(); | 2435 EliminateEnvironments(); |
| 2522 | 2436 |
| 2523 AnalyzeLiveness(); | 2437 liveness_.Analyze(); |
| 2524 | 2438 |
| 2525 NumberInstructions(); | 2439 NumberInstructions(); |
| 2526 | 2440 |
| 2527 DiscoverLoops(); | 2441 DiscoverLoops(); |
| 2528 | 2442 |
| 2529 BuildLiveRanges(); | 2443 BuildLiveRanges(); |
| 2530 | 2444 |
| 2531 if (FLAG_print_ssa_liveness) { | 2445 if (FLAG_print_ssa_liveness) { |
| 2532 DumpLiveness(); | 2446 liveness_.Dump(); |
| 2533 } | 2447 } |
| 2534 | 2448 |
| 2535 if (FLAG_print_ssa_liveranges) { | 2449 if (FLAG_print_ssa_liveranges) { |
| 2536 const Function& function = flow_graph_.parsed_function().function(); | 2450 const Function& function = flow_graph_.parsed_function().function(); |
| 2537 | 2451 |
| 2538 OS::Print("-- [before ssa allocator] ranges [%s] ---------\n", | 2452 OS::Print("-- [before ssa allocator] ranges [%s] ---------\n", |
| 2539 function.ToFullyQualifiedCString()); | 2453 function.ToFullyQualifiedCString()); |
| 2540 PrintLiveRanges(); | 2454 PrintLiveRanges(); |
| 2541 OS::Print("----------------------------------------------\n"); | 2455 OS::Print("----------------------------------------------\n"); |
| 2542 | 2456 |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2583 OS::Print("-- [after ssa allocator] ir [%s] -------------\n", | 2497 OS::Print("-- [after ssa allocator] ir [%s] -------------\n", |
| 2584 function.ToFullyQualifiedCString()); | 2498 function.ToFullyQualifiedCString()); |
| 2585 FlowGraphPrinter printer(flow_graph_, true); | 2499 FlowGraphPrinter printer(flow_graph_, true); |
| 2586 printer.PrintBlocks(); | 2500 printer.PrintBlocks(); |
| 2587 OS::Print("----------------------------------------------\n"); | 2501 OS::Print("----------------------------------------------\n"); |
| 2588 } | 2502 } |
| 2589 } | 2503 } |
| 2590 | 2504 |
| 2591 | 2505 |
| 2592 } // namespace dart | 2506 } // namespace dart |
| OLD | NEW |