| 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 liveness_(flow_graph), | 69 live_out_(block_order_.length()), |
| 70 kill_(block_order_.length()), |
| 71 live_in_(block_order_.length()), |
| 70 vreg_count_(flow_graph.max_virtual_register_number()), | 72 vreg_count_(flow_graph.max_virtual_register_number()), |
| 71 live_ranges_(flow_graph.max_virtual_register_number()), | 73 live_ranges_(flow_graph.max_virtual_register_number()), |
| 72 cpu_regs_(), | 74 cpu_regs_(), |
| 73 fpu_regs_(), | 75 fpu_regs_(), |
| 74 blocked_cpu_registers_(), | 76 blocked_cpu_registers_(), |
| 75 blocked_fpu_registers_(), | 77 blocked_fpu_registers_(), |
| 76 cpu_spill_slot_count_(0) { | 78 cpu_spill_slot_count_(0) { |
| 77 for (intptr_t i = 0; i < vreg_count_; i++) live_ranges_.Add(NULL); | 79 for (intptr_t i = 0; i < vreg_count_; i++) live_ranges_.Add(NULL); |
| 78 for (intptr_t i = 0; i < vreg_count_; i++) { | 80 for (intptr_t i = 0; i < vreg_count_; i++) { |
| 79 value_representations_.Add(kNoRepresentation); | 81 value_representations_.Add(kNoRepresentation); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 107 for (intptr_t i = 0; i < block_order_.length(); ++i) { | 109 for (intptr_t i = 0; i < block_order_.length(); ++i) { |
| 108 BlockEntryInstr* block = block_order_[i]; | 110 BlockEntryInstr* block = block_order_[i]; |
| 109 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 111 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
| 110 Instruction* current = it.Current(); | 112 Instruction* current = it.Current(); |
| 111 if (!current->CanDeoptimize()) current->RemoveEnvironment(); | 113 if (!current->CanDeoptimize()) current->RemoveEnvironment(); |
| 112 } | 114 } |
| 113 } | 115 } |
| 114 } | 116 } |
| 115 | 117 |
| 116 | 118 |
| 117 void SSALivenessAnalysis::ComputeInitialSets() { | 119 void FlowGraphAllocator::ComputeInitialSets() { |
| 118 const intptr_t block_count = postorder_.length(); | 120 const intptr_t block_count = postorder_.length(); |
| 119 for (intptr_t i = 0; i < block_count; i++) { | 121 for (intptr_t i = 0; i < block_count; i++) { |
| 120 BlockEntryInstr* block = postorder_[i]; | 122 BlockEntryInstr* block = postorder_[i]; |
| 121 | 123 |
| 122 BitVector* kill = kill_[i]; | 124 BitVector* kill = kill_[i]; |
| 123 BitVector* live_in = live_in_[i]; | 125 BitVector* live_in = live_in_[i]; |
| 124 | 126 |
| 125 // Iterate backwards starting at the last instruction. | 127 // Iterate backwards starting at the last instruction. |
| 126 for (BackwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 128 for (BackwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
| 127 Instruction* current = it.Current(); | 129 Instruction* current = it.Current(); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 180 const intptr_t use = val->definition()->ssa_temp_index(); | 182 const intptr_t use = val->definition()->ssa_temp_index(); |
| 181 if (!kill_[pred->postorder_number()]->Contains(use)) { | 183 if (!kill_[pred->postorder_number()]->Contains(use)) { |
| 182 live_in_[pred->postorder_number()]->Add(use); | 184 live_in_[pred->postorder_number()]->Add(use); |
| 183 } | 185 } |
| 184 } | 186 } |
| 185 } | 187 } |
| 186 } | 188 } |
| 187 } | 189 } |
| 188 | 190 |
| 189 // Process initial definitions, ie, constants and incoming parameters. | 191 // Process initial definitions, ie, constants and incoming parameters. |
| 190 for (intptr_t i = 0; i < graph_entry_->initial_definitions()->length(); i++) { | 192 GraphEntryInstr* graph_entry = flow_graph_.graph_entry(); |
| 191 intptr_t vreg = (*graph_entry_->initial_definitions())[i]->ssa_temp_index(); | 193 for (intptr_t i = 0; i < graph_entry->initial_definitions()->length(); i++) { |
| 192 kill_[graph_entry_->postorder_number()]->Add(vreg); | 194 intptr_t vreg = (*graph_entry->initial_definitions())[i]->ssa_temp_index(); |
| 193 live_in_[graph_entry_->postorder_number()]->Remove(vreg); | 195 kill_[graph_entry->postorder_number()]->Add(vreg); |
| 196 live_in_[graph_entry->postorder_number()]->Remove(vreg); |
| 194 } | 197 } |
| 195 | 198 |
| 196 // Update initial live_in sets to match live_out sets. Has to be | 199 // Update initial live_in sets to match live_out sets. Has to be |
| 197 // done in a separate path because of backwards branches. | 200 // done in a separate path because of backwards branches. |
| 198 for (intptr_t i = 0; i < block_count; i++) { | 201 for (intptr_t i = 0; i < block_count; i++) { |
| 199 UpdateLiveIn(*postorder_[i]); | 202 UpdateLiveIn(*postorder_[i]); |
| 200 } | 203 } |
| 201 } | 204 } |
| 202 | 205 |
| 203 | 206 |
| 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 |
| 204 void LiveRange::AddUse(intptr_t pos, Location* location_slot) { | 294 void LiveRange::AddUse(intptr_t pos, Location* location_slot) { |
| 205 ASSERT(location_slot != NULL); | 295 ASSERT(location_slot != NULL); |
| 206 ASSERT((first_use_interval_->start_ <= pos) && | 296 ASSERT((first_use_interval_->start_ <= pos) && |
| 207 (pos <= first_use_interval_->end_)); | 297 (pos <= first_use_interval_->end_)); |
| 208 if ((uses_ != NULL) && | 298 if ((uses_ != NULL) && |
| 209 (uses_->pos() == pos) && | 299 (uses_->pos() == pos) && |
| 210 (uses_->location_slot() == location_slot)) { | 300 (uses_->location_slot() == location_slot)) { |
| 211 return; | 301 return; |
| 212 } | 302 } |
| 213 uses_ = new UsePosition(pos, uses_, location_slot); | 303 uses_ = new UsePosition(pos, uses_, location_slot); |
| (...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 438 ASSERT(postorder_.Last()->IsGraphEntry()); | 528 ASSERT(postorder_.Last()->IsGraphEntry()); |
| 439 BitVector* current_interference_set = NULL; | 529 BitVector* current_interference_set = NULL; |
| 440 for (intptr_t i = 0; i < (block_count - 1); i++) { | 530 for (intptr_t i = 0; i < (block_count - 1); i++) { |
| 441 BlockEntryInstr* block = postorder_[i]; | 531 BlockEntryInstr* block = postorder_[i]; |
| 442 | 532 |
| 443 BlockInfo* block_info = BlockInfoAt(block->start_pos()); | 533 BlockInfo* block_info = BlockInfoAt(block->start_pos()); |
| 444 | 534 |
| 445 // For every SSA value that is live out of this block, create an interval | 535 // For every SSA value that is live out of this block, create an interval |
| 446 // that covers the whole block. It will be shortened if we encounter a | 536 // that covers the whole block. It will be shortened if we encounter a |
| 447 // definition of this value in this block. | 537 // definition of this value in this block. |
| 448 for (BitVector::Iterator it(liveness_.GetLiveOutSetAt(i)); | 538 for (BitVector::Iterator it(live_out_[i]); !it.Done(); it.Advance()) { |
| 449 !it.Done(); | |
| 450 it.Advance()) { | |
| 451 LiveRange* range = GetLiveRange(it.Current()); | 539 LiveRange* range = GetLiveRange(it.Current()); |
| 452 range->AddUseInterval(block->start_pos(), block->end_pos()); | 540 range->AddUseInterval(block->start_pos(), block->end_pos()); |
| 453 } | 541 } |
| 454 | 542 |
| 455 BlockInfo* loop_header = block_info->loop_header(); | 543 BlockInfo* loop_header = block_info->loop_header(); |
| 456 if ((loop_header != NULL) && (loop_header->last_block() == block)) { | 544 if ((loop_header != NULL) && (loop_header->last_block() == block)) { |
| 457 current_interference_set = | 545 current_interference_set = |
| 458 new BitVector(flow_graph_.max_virtual_register_number()); | 546 new BitVector(flow_graph_.max_virtual_register_number()); |
| 459 ASSERT(loop_header->backedge_interference() == NULL); | 547 ASSERT(loop_header->backedge_interference() == NULL); |
| 460 // All values flowing into the loop header are live at the back-edge and | 548 // All values flowing into the loop header are live at the back-edge and |
| 461 // can interfere with phi moves. | 549 // can interfere with phi moves. |
| 462 current_interference_set->AddAll( | 550 current_interference_set->AddAll( |
| 463 liveness_.GetLiveInSet(loop_header->entry())); | 551 live_in_[loop_header->entry()->postorder_number()]); |
| 464 loop_header->set_backedge_interference( | 552 loop_header->set_backedge_interference( |
| 465 current_interference_set); | 553 current_interference_set); |
| 466 } | 554 } |
| 467 | 555 |
| 468 // Connect outgoing phi-moves that were created in NumberInstructions | 556 // Connect outgoing phi-moves that were created in NumberInstructions |
| 469 // and find last instruction that contributes to liveness. | 557 // and find last instruction that contributes to liveness. |
| 470 Instruction* current = ConnectOutgoingPhiMoves(block, | 558 Instruction* current = ConnectOutgoingPhiMoves(block, |
| 471 current_interference_set); | 559 current_interference_set); |
| 472 | 560 |
| 473 // Now process all instructions in reverse order. | 561 // Now process all instructions in reverse order. |
| 474 while (current != block) { | 562 while (current != block) { |
| 475 // Skip parallel moves that we insert while processing instructions. | 563 // Skip parallel moves that we insert while processing instructions. |
| 476 if (!current->IsParallelMove()) { | 564 if (!current->IsParallelMove()) { |
| 477 ProcessOneInstruction(block, current, current_interference_set); | 565 ProcessOneInstruction(block, current, current_interference_set); |
| 478 } | 566 } |
| 479 current = current->previous(); | 567 current = current->previous(); |
| 480 } | 568 } |
| 481 | 569 |
| 482 | 570 |
| 483 // Check if any values live into the loop can be spilled for free. | 571 // Check if any values live into the loop can be spilled for free. |
| 484 if (block_info->is_loop_header()) { | 572 if (block_info->is_loop_header()) { |
| 485 current_interference_set = NULL; | 573 current_interference_set = NULL; |
| 486 for (BitVector::Iterator it(liveness_.GetLiveInSetAt(i)); | 574 for (BitVector::Iterator it(live_in_[i]); !it.Done(); it.Advance()) { |
| 487 !it.Done(); | |
| 488 it.Advance()) { | |
| 489 LiveRange* range = GetLiveRange(it.Current()); | 575 LiveRange* range = GetLiveRange(it.Current()); |
| 490 if (HasOnlyUnconstrainedUsesInLoop(range, block_info)) { | 576 if (HasOnlyUnconstrainedUsesInLoop(range, block_info)) { |
| 491 range->MarkHasOnlyUnconstrainedUsesInLoop(block_info->loop_id()); | 577 range->MarkHasOnlyUnconstrainedUsesInLoop(block_info->loop_id()); |
| 492 } | 578 } |
| 493 } | 579 } |
| 494 } | 580 } |
| 495 | 581 |
| 496 ConnectIncomingPhiMoves(block); | 582 ConnectIncomingPhiMoves(block); |
| 497 } | 583 } |
| 498 | 584 |
| (...skipping 1815 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2314 sibling->assigned_location(), | 2400 sibling->assigned_location(), |
| 2315 range->assigned_location()); | 2401 range->assigned_location()); |
| 2316 } | 2402 } |
| 2317 range = sibling; | 2403 range = sibling; |
| 2318 } | 2404 } |
| 2319 } | 2405 } |
| 2320 | 2406 |
| 2321 // Resolve non-linear control flow across branches. | 2407 // Resolve non-linear control flow across branches. |
| 2322 for (intptr_t i = 1; i < block_order_.length(); i++) { | 2408 for (intptr_t i = 1; i < block_order_.length(); i++) { |
| 2323 BlockEntryInstr* block = block_order_[i]; | 2409 BlockEntryInstr* block = block_order_[i]; |
| 2324 BitVector* live = liveness_.GetLiveInSet(block); | 2410 BitVector* live = live_in_[block->postorder_number()]; |
| 2325 for (BitVector::Iterator it(live); !it.Done(); it.Advance()) { | 2411 for (BitVector::Iterator it(live); !it.Done(); it.Advance()) { |
| 2326 LiveRange* range = GetLiveRange(it.Current()); | 2412 LiveRange* range = GetLiveRange(it.Current()); |
| 2327 for (intptr_t j = 0; j < block->PredecessorCount(); j++) { | 2413 for (intptr_t j = 0; j < block->PredecessorCount(); j++) { |
| 2328 ConnectSplitSiblings(range, block->PredecessorAt(j), block); | 2414 ConnectSplitSiblings(range, block->PredecessorAt(j), block); |
| 2329 } | 2415 } |
| 2330 } | 2416 } |
| 2331 } | 2417 } |
| 2332 | 2418 |
| 2333 // Eagerly spill values. | 2419 // Eagerly spill values. |
| 2334 // TODO(vegorov): if value is spilled on the cold path (e.g. by the call) | 2420 // 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... |
| 2381 } | 2467 } |
| 2382 } | 2468 } |
| 2383 } | 2469 } |
| 2384 | 2470 |
| 2385 | 2471 |
| 2386 void FlowGraphAllocator::AllocateRegisters() { | 2472 void FlowGraphAllocator::AllocateRegisters() { |
| 2387 CollectRepresentations(); | 2473 CollectRepresentations(); |
| 2388 | 2474 |
| 2389 EliminateEnvironments(); | 2475 EliminateEnvironments(); |
| 2390 | 2476 |
| 2391 liveness_.Analyze(); | 2477 AnalyzeLiveness(); |
| 2392 | 2478 |
| 2393 NumberInstructions(); | 2479 NumberInstructions(); |
| 2394 | 2480 |
| 2395 DiscoverLoops(); | 2481 DiscoverLoops(); |
| 2396 | 2482 |
| 2397 BuildLiveRanges(); | 2483 BuildLiveRanges(); |
| 2398 | 2484 |
| 2399 if (FLAG_print_ssa_liveness) { | 2485 if (FLAG_print_ssa_liveness) { |
| 2400 liveness_.Dump(); | 2486 DumpLiveness(); |
| 2401 } | 2487 } |
| 2402 | 2488 |
| 2403 if (FLAG_print_ssa_liveranges) { | 2489 if (FLAG_print_ssa_liveranges) { |
| 2404 const Function& function = flow_graph_.parsed_function().function(); | 2490 const Function& function = flow_graph_.parsed_function().function(); |
| 2405 | 2491 |
| 2406 OS::Print("-- [before ssa allocator] ranges [%s] ---------\n", | 2492 OS::Print("-- [before ssa allocator] ranges [%s] ---------\n", |
| 2407 function.ToFullyQualifiedCString()); | 2493 function.ToFullyQualifiedCString()); |
| 2408 PrintLiveRanges(); | 2494 PrintLiveRanges(); |
| 2409 OS::Print("----------------------------------------------\n"); | 2495 OS::Print("----------------------------------------------\n"); |
| 2410 | 2496 |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2451 OS::Print("-- [after ssa allocator] ir [%s] -------------\n", | 2537 OS::Print("-- [after ssa allocator] ir [%s] -------------\n", |
| 2452 function.ToFullyQualifiedCString()); | 2538 function.ToFullyQualifiedCString()); |
| 2453 FlowGraphPrinter printer(flow_graph_, true); | 2539 FlowGraphPrinter printer(flow_graph_, true); |
| 2454 printer.PrintBlocks(); | 2540 printer.PrintBlocks(); |
| 2455 OS::Print("----------------------------------------------\n"); | 2541 OS::Print("----------------------------------------------\n"); |
| 2456 } | 2542 } |
| 2457 } | 2543 } |
| 2458 | 2544 |
| 2459 | 2545 |
| 2460 } // namespace dart | 2546 } // namespace dart |
| OLD | NEW |