| 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 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 171 Value* val = phi->InputAt(k); | 171 Value* val = phi->InputAt(k); |
| 172 if (val->BindsToConstant()) continue; | 172 if (val->BindsToConstant()) continue; |
| 173 | 173 |
| 174 BlockEntryInstr* pred = block->PredecessorAt(k); | 174 BlockEntryInstr* pred = block->PredecessorAt(k); |
| 175 const intptr_t use = val->definition()->ssa_temp_index(); | 175 const intptr_t use = val->definition()->ssa_temp_index(); |
| 176 if (!kill_[pred->postorder_number()]->Contains(use)) { | 176 if (!kill_[pred->postorder_number()]->Contains(use)) { |
| 177 live_in_[pred->postorder_number()]->Add(use); | 177 live_in_[pred->postorder_number()]->Add(use); |
| 178 } | 178 } |
| 179 } | 179 } |
| 180 } | 180 } |
| 181 } else if (block->IsCatchBlockEntry()) { |
| 182 // Process initial definitions. |
| 183 CatchBlockEntryInstr* catch_entry = block->AsCatchBlockEntry(); |
| 184 for (intptr_t i = 0; |
| 185 i < catch_entry->initial_definitions()->length(); |
| 186 i++) { |
| 187 intptr_t vreg = |
| 188 (*catch_entry->initial_definitions())[i]->ssa_temp_index(); |
| 189 kill_[catch_entry->postorder_number()]->Add(vreg); |
| 190 live_in_[catch_entry->postorder_number()]->Remove(vreg); |
| 191 } |
| 181 } | 192 } |
| 182 } | 193 } |
| 183 | 194 |
| 184 // Process initial definitions, ie, constants and incoming parameters. | 195 // Process initial definitions, ie, constants and incoming parameters. |
| 185 for (intptr_t i = 0; i < graph_entry_->initial_definitions()->length(); i++) { | 196 for (intptr_t i = 0; i < graph_entry_->initial_definitions()->length(); i++) { |
| 186 intptr_t vreg = (*graph_entry_->initial_definitions())[i]->ssa_temp_index(); | 197 intptr_t vreg = (*graph_entry_->initial_definitions())[i]->ssa_temp_index(); |
| 187 kill_[graph_entry_->postorder_number()]->Add(vreg); | 198 kill_[graph_entry_->postorder_number()]->Add(vreg); |
| 188 live_in_[graph_entry_->postorder_number()]->Remove(vreg); | 199 live_in_[graph_entry_->postorder_number()]->Remove(vreg); |
| 189 } | 200 } |
| 190 | 201 |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 234 ASSERT(hint != NULL); | 245 ASSERT(hint != NULL); |
| 235 AddUse(pos, location_slot); | 246 AddUse(pos, location_slot); |
| 236 uses_->set_hint(hint); | 247 uses_->set_hint(hint); |
| 237 } | 248 } |
| 238 | 249 |
| 239 | 250 |
| 240 void LiveRange::AddUseInterval(intptr_t start, intptr_t end) { | 251 void LiveRange::AddUseInterval(intptr_t start, intptr_t end) { |
| 241 ASSERT(start < end); | 252 ASSERT(start < end); |
| 242 | 253 |
| 243 // Live ranges are being build by visiting instructions in post-order. | 254 // Live ranges are being build by visiting instructions in post-order. |
| 244 // This implies that use intervals will be perpended in a monotonically | 255 // This implies that use intervals will be prepended in a monotonically |
| 245 // decreasing order. | 256 // decreasing order. |
| 246 if (first_use_interval() != NULL) { | 257 if (first_use_interval() != NULL) { |
| 247 // If the first use interval and the use interval we are adding | 258 // If the first use interval and the use interval we are adding |
| 248 // touch then we can just extend the first interval to cover their | 259 // touch then we can just extend the first interval to cover their |
| 249 // union. | 260 // union. |
| 250 if (start >= first_use_interval()->start()) { | 261 if (start >= first_use_interval()->start()) { |
| 251 // The only case when we can add intervals with start greater than | 262 // The only case when we can add intervals with start greater than |
| 252 // start of an already created interval is BlockLocation. | 263 // start of an already created interval is BlockLocation. |
| 253 ASSERT((start == first_use_interval()->start()) || | 264 ASSERT((start == first_use_interval()->start()) || |
| 254 (vreg() == kNoVirtualRegister)); | 265 (vreg() == kNoVirtualRegister)); |
| (...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 481 for (BitVector::Iterator it(liveness_.GetLiveInSetAt(i)); | 492 for (BitVector::Iterator it(liveness_.GetLiveInSetAt(i)); |
| 482 !it.Done(); | 493 !it.Done(); |
| 483 it.Advance()) { | 494 it.Advance()) { |
| 484 LiveRange* range = GetLiveRange(it.Current()); | 495 LiveRange* range = GetLiveRange(it.Current()); |
| 485 if (HasOnlyUnconstrainedUsesInLoop(range, block_info)) { | 496 if (HasOnlyUnconstrainedUsesInLoop(range, block_info)) { |
| 486 range->MarkHasOnlyUnconstrainedUsesInLoop(block_info->loop_id()); | 497 range->MarkHasOnlyUnconstrainedUsesInLoop(block_info->loop_id()); |
| 487 } | 498 } |
| 488 } | 499 } |
| 489 } | 500 } |
| 490 | 501 |
| 491 ConnectIncomingPhiMoves(block); | 502 if (block->IsJoinEntry()) { |
| 503 ConnectIncomingPhiMoves(block->AsJoinEntry()); |
| 504 } else if (block->IsCatchBlockEntry()) { |
| 505 // Process initial definitions. |
| 506 CatchBlockEntryInstr* catch_entry = block->AsCatchBlockEntry(); |
| 507 for (intptr_t i = 0; |
| 508 i < catch_entry->initial_definitions()->length(); |
| 509 i++) { |
| 510 Definition* defn = (*catch_entry->initial_definitions())[i]; |
| 511 LiveRange* range = GetLiveRange(defn->ssa_temp_index()); |
| 512 range->DefineAt(catch_entry->start_pos()); // Defined at block entry. |
| 513 |
| 514 // Save range->End() because it may change in ProcessInitialDefinition. |
| 515 intptr_t range_end = range->End(); |
| 516 ProcessInitialDefinition(defn, range, catch_entry); |
| 517 spill_slots_.Add(range_end); |
| 518 quad_spill_slots_.Add(false); |
| 519 |
| 520 if (defn->IsParameter() && range->spill_slot().stack_index() >= 0) { |
| 521 MarkAsObjectAtSafepoints(range); |
| 522 } |
| 523 } |
| 524 } |
| 492 } | 525 } |
| 493 | 526 |
| 494 // Process incoming parameters and constants. Do this after all other | 527 // Process incoming parameters and constants. Do this after all other |
| 495 // instructions so that safepoints for all calls have already been found. | 528 // instructions so that safepoints for all calls have already been found. |
| 496 GraphEntryInstr* graph_entry = flow_graph_.graph_entry(); | 529 GraphEntryInstr* graph_entry = flow_graph_.graph_entry(); |
| 497 for (intptr_t i = 0; i < graph_entry->initial_definitions()->length(); i++) { | 530 for (intptr_t i = 0; i < graph_entry->initial_definitions()->length(); i++) { |
| 498 Definition* defn = (*graph_entry->initial_definitions())[i]; | 531 Definition* defn = (*graph_entry->initial_definitions())[i]; |
| 499 LiveRange* range = GetLiveRange(defn->ssa_temp_index()); | 532 LiveRange* range = GetLiveRange(defn->ssa_temp_index()); |
| 500 range->AddUseInterval(graph_entry->start_pos(), graph_entry->end_pos()); | 533 range->AddUseInterval(graph_entry->start_pos(), graph_entry->end_pos()); |
| 501 range->DefineAt(graph_entry->start_pos()); | 534 range->DefineAt(graph_entry->start_pos()); |
| 502 if (defn->IsParameter()) { | |
| 503 ParameterInstr* param = defn->AsParameter(); | |
| 504 // Assert that copied and non-copied parameters are mutually exclusive. | |
| 505 // This might change in the future and, if so, the index will be wrong. | |
| 506 ASSERT((flow_graph_.num_copied_params() == 0) || | |
| 507 (flow_graph_.num_non_copied_params() == 0)); | |
| 508 // Slot index for the leftmost copied parameter is 0. | |
| 509 intptr_t slot_index = param->index(); | |
| 510 // Slot index for the rightmost fixed parameter is -1. | |
| 511 slot_index -= flow_graph_.num_non_copied_params(); | |
| 512 | 535 |
| 513 range->set_assigned_location(Location::StackSlot(slot_index)); | 536 // Save range->End() because it may change in ProcessInitialDefinition. |
| 514 range->set_spill_slot(Location::StackSlot(slot_index)); | 537 intptr_t range_end = range->End(); |
| 515 if (flow_graph_.num_copied_params() > 0) { | 538 ProcessInitialDefinition(defn, range, graph_entry); |
| 516 ASSERT(spill_slots_.length() == slot_index); | 539 if (defn->IsParameter() && flow_graph_.num_copied_params() > 0) { |
| 517 spill_slots_.Add(range->End()); | 540 spill_slots_.Add(range_end); |
| 518 quad_spill_slots_.Add(false); | 541 quad_spill_slots_.Add(false); |
| 519 } | |
| 520 } else { | |
| 521 ConstantInstr* constant = defn->AsConstant(); | |
| 522 ASSERT(constant != NULL); | |
| 523 range->set_assigned_location(Location::Constant(constant->value())); | |
| 524 range->set_spill_slot(Location::Constant(constant->value())); | |
| 525 } | |
| 526 AssignSafepoints(range); | |
| 527 range->finger()->Initialize(range); | |
| 528 UsePosition* use = | |
| 529 range->finger()->FirstRegisterBeneficialUse(graph_entry->start_pos()); | |
| 530 if (use != NULL) { | |
| 531 LiveRange* tail = | |
| 532 SplitBetween(range, graph_entry->start_pos(), use->pos()); | |
| 533 // Parameters and constants are tagged, so allocated to CPU registers. | |
| 534 CompleteRange(tail, Location::kRegister); | |
| 535 } | |
| 536 ConvertAllUses(range); | |
| 537 | 542 |
| 538 if (defn->IsParameter() && flow_graph_.num_copied_params() > 0) { | |
| 539 MarkAsObjectAtSafepoints(range); | 543 MarkAsObjectAtSafepoints(range); |
| 540 } | 544 } |
| 541 } | 545 } |
| 542 } | 546 } |
| 543 | 547 |
| 544 | 548 |
| 549 void FlowGraphAllocator::ProcessInitialDefinition(Definition* defn, |
| 550 LiveRange* range, |
| 551 BlockEntryInstr* block) { |
| 552 if (defn->IsParameter()) { |
| 553 ParameterInstr* param = defn->AsParameter(); |
| 554 // Assert that copied and non-copied parameters are mutually exclusive. |
| 555 // This might change in the future and, if so, the index will be wrong. |
| 556 ASSERT((flow_graph_.num_copied_params() == 0) || |
| 557 (flow_graph_.num_non_copied_params() == 0)); |
| 558 // Slot index for the leftmost copied parameter is 0. |
| 559 intptr_t slot_index = param->index(); |
| 560 // Slot index for the rightmost fixed parameter is -1. |
| 561 slot_index -= flow_graph_.num_non_copied_params(); |
| 562 |
| 563 range->set_assigned_location(Location::StackSlot(slot_index)); |
| 564 range->set_spill_slot(Location::StackSlot(slot_index)); |
| 565 } else { |
| 566 ConstantInstr* constant = defn->AsConstant(); |
| 567 ASSERT(constant != NULL); |
| 568 range->set_assigned_location(Location::Constant(constant->value())); |
| 569 range->set_spill_slot(Location::Constant(constant->value())); |
| 570 } |
| 571 AssignSafepoints(range); |
| 572 range->finger()->Initialize(range); |
| 573 UsePosition* use = |
| 574 range->finger()->FirstRegisterBeneficialUse(block->start_pos()); |
| 575 if (use != NULL) { |
| 576 LiveRange* tail = |
| 577 SplitBetween(range, block->start_pos(), use->pos()); |
| 578 // Parameters and constants are tagged, so allocated to CPU registers. |
| 579 CompleteRange(tail, Location::kRegister); |
| 580 } |
| 581 ConvertAllUses(range); |
| 582 } |
| 583 |
| 584 |
| 545 static Location::Kind RegisterKindFromPolicy(Location loc) { | 585 static Location::Kind RegisterKindFromPolicy(Location loc) { |
| 546 if (loc.policy() == Location::kRequiresFpuRegister) { | 586 if (loc.policy() == Location::kRequiresFpuRegister) { |
| 547 return Location::kFpuRegister; | 587 return Location::kFpuRegister; |
| 548 } else { | 588 } else { |
| 549 return Location::kRegister; | 589 return Location::kRegister; |
| 550 } | 590 } |
| 551 } | 591 } |
| 552 | 592 |
| 553 | 593 |
| 554 static Location::Kind RegisterKindForResult(Instruction* instr) { | 594 static Location::Kind RegisterKindForResult(Instruction* instr) { |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 641 move->set_src(Location::PrefersRegister()); | 681 move->set_src(Location::PrefersRegister()); |
| 642 move_idx++; | 682 move_idx++; |
| 643 } | 683 } |
| 644 | 684 |
| 645 // Begin backward iteration with the instruction before the parallel | 685 // Begin backward iteration with the instruction before the parallel |
| 646 // move. | 686 // move. |
| 647 return goto_instr->previous(); | 687 return goto_instr->previous(); |
| 648 } | 688 } |
| 649 | 689 |
| 650 | 690 |
| 651 void FlowGraphAllocator::ConnectIncomingPhiMoves(BlockEntryInstr* block) { | 691 void FlowGraphAllocator::ConnectIncomingPhiMoves(JoinEntryInstr* join) { |
| 652 // If this block is a join we need to add destinations of phi | 692 // For join blocks we need to add destinations of phi resolution moves |
| 653 // resolution moves to phi's live range so that register allocator will | 693 // to phi's live range so that register allocator will fill them with moves. |
| 654 // fill them with moves. | |
| 655 JoinEntryInstr* join = block->AsJoinEntry(); | |
| 656 if (join == NULL) return; | |
| 657 | 694 |
| 658 // All uses are recorded at the start position in the block. | 695 // All uses are recorded at the start position in the block. |
| 659 const intptr_t pos = join->start_pos(); | 696 const intptr_t pos = join->start_pos(); |
| 660 const bool is_loop_header = BlockInfoAt(join->start_pos())->is_loop_header(); | 697 const bool is_loop_header = BlockInfoAt(join->start_pos())->is_loop_header(); |
| 661 intptr_t move_idx = 0; | 698 intptr_t move_idx = 0; |
| 662 for (PhiIterator it(join); !it.Done(); it.Advance()) { | 699 for (PhiIterator it(join); !it.Done(); it.Advance()) { |
| 663 PhiInstr* phi = it.Current(); | 700 PhiInstr* phi = it.Current(); |
| 664 ASSERT(phi != NULL); | 701 ASSERT(phi != NULL); |
| 665 const intptr_t vreg = phi->ssa_temp_index(); | 702 const intptr_t vreg = phi->ssa_temp_index(); |
| 666 ASSERT(vreg >= 0); | 703 ASSERT(vreg >= 0); |
| 667 | 704 |
| 668 // Expected shape of live range: | 705 // Expected shape of live range: |
| 669 // | 706 // |
| 670 // B | 707 // B |
| 671 // phi [-------- | 708 // phi [-------- |
| 672 // | 709 // |
| 673 LiveRange* range = GetLiveRange(vreg); | 710 LiveRange* range = GetLiveRange(vreg); |
| 674 range->DefineAt(pos); // Shorten live range. | 711 range->DefineAt(pos); // Shorten live range. |
| 675 | 712 |
| 676 if (is_loop_header) range->mark_loop_phi(); | 713 if (is_loop_header) range->mark_loop_phi(); |
| 677 | 714 |
| 678 for (intptr_t pred_idx = 0; pred_idx < phi->InputCount(); pred_idx++) { | 715 for (intptr_t pred_idx = 0; pred_idx < phi->InputCount(); pred_idx++) { |
| 679 BlockEntryInstr* pred = block->PredecessorAt(pred_idx); | 716 BlockEntryInstr* pred = join->PredecessorAt(pred_idx); |
| 680 GotoInstr* goto_instr = pred->last_instruction()->AsGoto(); | 717 GotoInstr* goto_instr = pred->last_instruction()->AsGoto(); |
| 681 ASSERT((goto_instr != NULL) && (goto_instr->HasParallelMove())); | 718 ASSERT((goto_instr != NULL) && (goto_instr->HasParallelMove())); |
| 682 MoveOperands* move = | 719 MoveOperands* move = |
| 683 goto_instr->parallel_move()->MoveOperandsAt(move_idx); | 720 goto_instr->parallel_move()->MoveOperandsAt(move_idx); |
| 684 move->set_dest(Location::PrefersRegister()); | 721 move->set_dest(Location::PrefersRegister()); |
| 685 range->AddUse(pos, move->dest_slot()); | 722 range->AddUse(pos, move->dest_slot()); |
| 686 } | 723 } |
| 687 | 724 |
| 688 // All phi resolution moves are connected. Phi's live range is | 725 // All phi resolution moves are connected. Phi's live range is |
| 689 // complete. | 726 // complete. |
| (...skipping 861 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1551 // Special care is taken to never allocate the same index to both | 1588 // Special care is taken to never allocate the same index to both |
| 1552 // double and quad spill slots as it complicates disambiguation during | 1589 // double and quad spill slots as it complicates disambiguation during |
| 1553 // parallel move resolution. | 1590 // parallel move resolution. |
| 1554 const bool need_quad = (register_kind_ == Location::kFpuRegister) && | 1591 const bool need_quad = (register_kind_ == Location::kFpuRegister) && |
| 1555 ((range->representation() == kUnboxedFloat32x4) || | 1592 ((range->representation() == kUnboxedFloat32x4) || |
| 1556 (range->representation() == kUnboxedUint32x4)); | 1593 (range->representation() == kUnboxedUint32x4)); |
| 1557 | 1594 |
| 1558 // Search for a free spill slot among allocated: the value in it should be | 1595 // Search for a free spill slot among allocated: the value in it should be |
| 1559 // dead and its type should match (e.g. it should not be a part of the quad if | 1596 // dead and its type should match (e.g. it should not be a part of the quad if |
| 1560 // we are allocating normal double slot). | 1597 // we are allocating normal double slot). |
| 1561 intptr_t idx = 0; | 1598 // For CPU registers we need to take reserved slots for try-catch into |
| 1599 // account. |
| 1600 intptr_t idx = register_kind_ == Location::kRegister |
| 1601 ? flow_graph_.graph_entry()->fixed_slot_count() |
| 1602 : 0; |
| 1562 for (; idx < spill_slots_.length(); idx++) { | 1603 for (; idx < spill_slots_.length(); idx++) { |
| 1563 if ((need_quad == quad_spill_slots_[idx]) && | 1604 if ((need_quad == quad_spill_slots_[idx]) && |
| 1564 (spill_slots_[idx] <= start)) { | 1605 (spill_slots_[idx] <= start)) { |
| 1565 break; | 1606 break; |
| 1566 } | 1607 } |
| 1567 } | 1608 } |
| 1568 | 1609 |
| 1569 if (idx == spill_slots_.length()) { | 1610 if (idx == spill_slots_.length()) { |
| 1570 // No free spill slot found. Allocate a new one. | 1611 // No free spill slot found. Allocate a new one. |
| 1571 spill_slots_.Add(0); | 1612 spill_slots_.Add(0); |
| (...skipping 871 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2443 GraphEntryInstr* graph_entry = flow_graph_.graph_entry(); | 2484 GraphEntryInstr* graph_entry = flow_graph_.graph_entry(); |
| 2444 for (intptr_t i = 0; i < graph_entry->initial_definitions()->length(); ++i) { | 2485 for (intptr_t i = 0; i < graph_entry->initial_definitions()->length(); ++i) { |
| 2445 Definition* def = (*graph_entry->initial_definitions())[i]; | 2486 Definition* def = (*graph_entry->initial_definitions())[i]; |
| 2446 value_representations_[def->ssa_temp_index()] = def->representation(); | 2487 value_representations_[def->ssa_temp_index()] = def->representation(); |
| 2447 } | 2488 } |
| 2448 | 2489 |
| 2449 for (BlockIterator it = flow_graph_.reverse_postorder_iterator(); | 2490 for (BlockIterator it = flow_graph_.reverse_postorder_iterator(); |
| 2450 !it.Done(); | 2491 !it.Done(); |
| 2451 it.Advance()) { | 2492 it.Advance()) { |
| 2452 BlockEntryInstr* block = it.Current(); | 2493 BlockEntryInstr* block = it.Current(); |
| 2494 |
| 2495 // Catch entry. |
| 2496 if (block->IsCatchBlockEntry()) { |
| 2497 CatchBlockEntryInstr* catch_entry = block->AsCatchBlockEntry(); |
| 2498 for (intptr_t i = 0; |
| 2499 i < catch_entry->initial_definitions()->length(); |
| 2500 ++i) { |
| 2501 Definition* def = (*catch_entry->initial_definitions())[i]; |
| 2502 value_representations_[def->ssa_temp_index()] = def->representation(); |
| 2503 } |
| 2504 } |
| 2453 // Phis. | 2505 // Phis. |
| 2454 if (block->IsJoinEntry()) { | 2506 if (block->IsJoinEntry()) { |
| 2455 JoinEntryInstr* join = block->AsJoinEntry(); | 2507 JoinEntryInstr* join = block->AsJoinEntry(); |
| 2456 for (PhiIterator it(join); !it.Done(); it.Advance()) { | 2508 for (PhiIterator it(join); !it.Done(); it.Advance()) { |
| 2457 PhiInstr* phi = it.Current(); | 2509 PhiInstr* phi = it.Current(); |
| 2458 if ((phi != NULL) && (phi->ssa_temp_index() >= 0)) { | 2510 if ((phi != NULL) && (phi->ssa_temp_index() >= 0)) { |
| 2459 value_representations_[phi->ssa_temp_index()] = phi->representation(); | 2511 value_representations_[phi->ssa_temp_index()] = phi->representation(); |
| 2460 } | 2512 } |
| 2461 } | 2513 } |
| 2462 } | 2514 } |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2539 OS::Print("-- [after ssa allocator] ir [%s] -------------\n", | 2591 OS::Print("-- [after ssa allocator] ir [%s] -------------\n", |
| 2540 function.ToFullyQualifiedCString()); | 2592 function.ToFullyQualifiedCString()); |
| 2541 FlowGraphPrinter printer(flow_graph_, true); | 2593 FlowGraphPrinter printer(flow_graph_, true); |
| 2542 printer.PrintBlocks(); | 2594 printer.PrintBlocks(); |
| 2543 OS::Print("----------------------------------------------\n"); | 2595 OS::Print("----------------------------------------------\n"); |
| 2544 } | 2596 } |
| 2545 } | 2597 } |
| 2546 | 2598 |
| 2547 | 2599 |
| 2548 } // namespace dart | 2600 } // namespace dart |
| OLD | NEW |