Chromium Code Reviews| 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 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 176 Value* val = phi->InputAt(k); | 176 Value* val = phi->InputAt(k); |
| 177 if (val->BindsToConstant()) continue; | 177 if (val->BindsToConstant()) continue; |
| 178 | 178 |
| 179 BlockEntryInstr* pred = block->PredecessorAt(k); | 179 BlockEntryInstr* pred = block->PredecessorAt(k); |
| 180 const intptr_t use = val->definition()->ssa_temp_index(); | 180 const intptr_t use = val->definition()->ssa_temp_index(); |
| 181 if (!kill_[pred->postorder_number()]->Contains(use)) { | 181 if (!kill_[pred->postorder_number()]->Contains(use)) { |
| 182 live_in_[pred->postorder_number()]->Add(use); | 182 live_in_[pred->postorder_number()]->Add(use); |
| 183 } | 183 } |
| 184 } | 184 } |
| 185 } | 185 } |
| 186 } else if (block->IsCatchBlockEntry()) { | |
| 187 // Process initial definitions. | |
|
Kevin Millikin (Google)
2013/05/08 11:42:00
It's disconcerting that locals are treated so diff
Florian Schneider
2013/05/08 17:10:55
This deals with SSA values, similar to the initial
| |
| 188 CatchBlockEntryInstr* catch_entry = block->AsCatchBlockEntry(); | |
| 189 for (intptr_t i = 0; | |
| 190 i < catch_entry->initial_definitions()->length(); | |
| 191 i++) { | |
| 192 intptr_t vreg = | |
| 193 (*catch_entry->initial_definitions())[i]->ssa_temp_index(); | |
| 194 kill_[catch_entry->postorder_number()]->Add(vreg); | |
| 195 live_in_[catch_entry->postorder_number()]->Remove(vreg); | |
| 196 } | |
| 186 } | 197 } |
| 187 } | 198 } |
| 188 | 199 |
| 189 // Process initial definitions, ie, constants and incoming parameters. | 200 // Process initial definitions, ie, constants and incoming parameters. |
| 190 for (intptr_t i = 0; i < graph_entry_->initial_definitions()->length(); i++) { | 201 for (intptr_t i = 0; i < graph_entry_->initial_definitions()->length(); i++) { |
| 191 intptr_t vreg = (*graph_entry_->initial_definitions())[i]->ssa_temp_index(); | 202 intptr_t vreg = (*graph_entry_->initial_definitions())[i]->ssa_temp_index(); |
| 192 kill_[graph_entry_->postorder_number()]->Add(vreg); | 203 kill_[graph_entry_->postorder_number()]->Add(vreg); |
| 193 live_in_[graph_entry_->postorder_number()]->Remove(vreg); | 204 live_in_[graph_entry_->postorder_number()]->Remove(vreg); |
| 194 } | 205 } |
| 195 | 206 |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 239 ASSERT(hint != NULL); | 250 ASSERT(hint != NULL); |
| 240 AddUse(pos, location_slot); | 251 AddUse(pos, location_slot); |
| 241 uses_->set_hint(hint); | 252 uses_->set_hint(hint); |
| 242 } | 253 } |
| 243 | 254 |
| 244 | 255 |
| 245 void LiveRange::AddUseInterval(intptr_t start, intptr_t end) { | 256 void LiveRange::AddUseInterval(intptr_t start, intptr_t end) { |
| 246 ASSERT(start < end); | 257 ASSERT(start < end); |
| 247 | 258 |
| 248 // Live ranges are being build by visiting instructions in post-order. | 259 // Live ranges are being build by visiting instructions in post-order. |
| 249 // This implies that use intervals will be perpended in a monotonically | 260 // This implies that use intervals will be prepended in a monotonically |
| 250 // decreasing order. | 261 // decreasing order. |
| 251 if (first_use_interval() != NULL) { | 262 if (first_use_interval() != NULL) { |
| 252 // If the first use interval and the use interval we are adding | 263 // If the first use interval and the use interval we are adding |
| 253 // touch then we can just extend the first interval to cover their | 264 // touch then we can just extend the first interval to cover their |
| 254 // union. | 265 // union. |
| 255 if (start >= first_use_interval()->start()) { | 266 if (start >= first_use_interval()->start()) { |
| 256 // The only case when we can add intervals with start greater than | 267 // The only case when we can add intervals with start greater than |
| 257 // start of an already created interval is BlockLocation. | 268 // start of an already created interval is BlockLocation. |
| 258 ASSERT((start == first_use_interval()->start()) || | 269 ASSERT((start == first_use_interval()->start()) || |
| 259 (vreg() == kNoVirtualRegister)); | 270 (vreg() == kNoVirtualRegister)); |
| (...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 486 for (BitVector::Iterator it(liveness_.GetLiveInSetAt(i)); | 497 for (BitVector::Iterator it(liveness_.GetLiveInSetAt(i)); |
| 487 !it.Done(); | 498 !it.Done(); |
| 488 it.Advance()) { | 499 it.Advance()) { |
| 489 LiveRange* range = GetLiveRange(it.Current()); | 500 LiveRange* range = GetLiveRange(it.Current()); |
| 490 if (HasOnlyUnconstrainedUsesInLoop(range, block_info)) { | 501 if (HasOnlyUnconstrainedUsesInLoop(range, block_info)) { |
| 491 range->MarkHasOnlyUnconstrainedUsesInLoop(block_info->loop_id()); | 502 range->MarkHasOnlyUnconstrainedUsesInLoop(block_info->loop_id()); |
| 492 } | 503 } |
| 493 } | 504 } |
| 494 } | 505 } |
| 495 | 506 |
| 496 ConnectIncomingPhiMoves(block); | 507 if (block->IsJoinEntry()) { |
| 508 ConnectIncomingPhiMoves(block->AsJoinEntry()); | |
| 509 } else if (block->IsCatchBlockEntry()) { | |
| 510 // Process initial definitions. | |
| 511 CatchBlockEntryInstr* catch_entry = block->AsCatchBlockEntry(); | |
| 512 for (intptr_t i = 0; | |
| 513 i < catch_entry->initial_definitions()->length(); | |
| 514 i++) { | |
| 515 Definition* defn = (*catch_entry->initial_definitions())[i]; | |
|
Kevin Millikin (Google)
2013/05/08 11:42:00
All this code that is duplicated below should be m
Florian Schneider
2013/05/08 17:10:55
Done.
| |
| 516 LiveRange* range = GetLiveRange(defn->ssa_temp_index()); | |
| 517 range->DefineAt(catch_entry->start_pos()); // Defined at block entry. | |
| 518 if (defn->IsParameter()) { | |
| 519 ParameterInstr* param = defn->AsParameter(); | |
| 520 // Assert that copied and non-copied parameters are mutually | |
| 521 // exclusive. This might change in the future and, if so, the | |
| 522 // index will be wrong. | |
| 523 ASSERT((flow_graph_.num_copied_params() == 0) || | |
| 524 (flow_graph_.num_non_copied_params() == 0)); | |
| 525 // Slot index for the leftmost copied parameter is 0. | |
| 526 intptr_t slot_index = param->index(); | |
| 527 // Slot index for the rightmost fixed parameter is -1. | |
| 528 slot_index -= flow_graph_.num_non_copied_params(); | |
| 529 range->set_assigned_location(Location::StackSlot(slot_index)); | |
| 530 range->set_spill_slot(Location::StackSlot(slot_index)); | |
| 531 } else { | |
| 532 ConstantInstr* constant = defn->AsConstant(); | |
| 533 ASSERT(constant != NULL); | |
| 534 range->set_assigned_location(Location::Constant(constant->value())); | |
| 535 range->set_spill_slot(Location::Constant(constant->value())); | |
| 536 } | |
| 537 spill_slots_.Add(range->End()); | |
| 538 quad_spill_slots_.Add(false); | |
| 539 AssignSafepoints(range); | |
| 540 range->finger()->Initialize(range); | |
| 541 UsePosition* use = range->finger()->FirstRegisterBeneficialUse( | |
| 542 catch_entry->start_pos()); | |
| 543 if (use != NULL) { | |
| 544 LiveRange* tail = | |
| 545 SplitBetween(range, catch_entry->start_pos(), use->pos()); | |
| 546 // Parameters and constants are tagged, so allocated to CPU registers. | |
| 547 CompleteRange(tail, Location::kRegister); | |
| 548 } | |
| 549 ConvertAllUses(range); | |
| 550 if (defn->IsParameter() && range->spill_slot().stack_index() >= 0) { | |
| 551 MarkAsObjectAtSafepoints(range); | |
| 552 } | |
| 553 } | |
| 554 } | |
| 497 } | 555 } |
| 498 | 556 |
| 499 // Process incoming parameters and constants. Do this after all other | 557 // Process incoming parameters and constants. Do this after all other |
| 500 // instructions so that safepoints for all calls have already been found. | 558 // instructions so that safepoints for all calls have already been found. |
| 501 GraphEntryInstr* graph_entry = flow_graph_.graph_entry(); | 559 GraphEntryInstr* graph_entry = flow_graph_.graph_entry(); |
| 502 for (intptr_t i = 0; i < graph_entry->initial_definitions()->length(); i++) { | 560 for (intptr_t i = 0; i < graph_entry->initial_definitions()->length(); i++) { |
| 503 Definition* defn = (*graph_entry->initial_definitions())[i]; | 561 Definition* defn = (*graph_entry->initial_definitions())[i]; |
| 504 LiveRange* range = GetLiveRange(defn->ssa_temp_index()); | 562 LiveRange* range = GetLiveRange(defn->ssa_temp_index()); |
| 505 range->AddUseInterval(graph_entry->start_pos(), graph_entry->end_pos()); | 563 range->AddUseInterval(graph_entry->start_pos(), graph_entry->end_pos()); |
| 506 range->DefineAt(graph_entry->start_pos()); | 564 range->DefineAt(graph_entry->start_pos()); |
| 507 if (defn->IsParameter()) { | 565 if (defn->IsParameter()) { |
| 508 ParameterInstr* param = defn->AsParameter(); | 566 ParameterInstr* param = defn->AsParameter(); |
| 509 // Assert that copied and non-copied parameters are mutually exclusive. | 567 // Assert that copied and non-copied parameters are mutually exclusive. |
| 510 // This might change in the future and, if so, the index will be wrong. | 568 // This might change in the future and, if so, the index will be wrong. |
| 511 ASSERT((flow_graph_.num_copied_params() == 0) || | 569 ASSERT((flow_graph_.num_copied_params() == 0) || |
| 512 (flow_graph_.num_non_copied_params() == 0)); | 570 (flow_graph_.num_non_copied_params() == 0)); |
| 513 // Slot index for the leftmost copied parameter is 0. | 571 // Slot index for the leftmost copied parameter is 0. |
| 514 intptr_t slot_index = param->index(); | 572 intptr_t slot_index = param->index(); |
| 515 // Slot index for the rightmost fixed parameter is -1. | 573 // Slot index for the rightmost fixed parameter is -1. |
| 516 slot_index -= flow_graph_.num_non_copied_params(); | 574 slot_index -= flow_graph_.num_non_copied_params(); |
| 517 | 575 |
| 518 range->set_assigned_location(Location::StackSlot(slot_index)); | 576 range->set_assigned_location(Location::StackSlot(slot_index)); |
| 519 range->set_spill_slot(Location::StackSlot(slot_index)); | 577 range->set_spill_slot(Location::StackSlot(slot_index)); |
| 520 if (flow_graph_.num_copied_params() > 0) { | 578 if (flow_graph_.num_copied_params() > 0) { |
| 521 ASSERT(spill_slots_.length() == slot_index); | |
| 522 spill_slots_.Add(range->End()); | 579 spill_slots_.Add(range->End()); |
| 523 quad_spill_slots_.Add(false); | 580 quad_spill_slots_.Add(false); |
| 524 } | 581 } |
| 525 } else { | 582 } else { |
| 526 ConstantInstr* constant = defn->AsConstant(); | 583 ConstantInstr* constant = defn->AsConstant(); |
| 527 ASSERT(constant != NULL); | 584 ASSERT(constant != NULL); |
| 528 range->set_assigned_location(Location::Constant(constant->value())); | 585 range->set_assigned_location(Location::Constant(constant->value())); |
| 529 range->set_spill_slot(Location::Constant(constant->value())); | 586 range->set_spill_slot(Location::Constant(constant->value())); |
| 530 } | 587 } |
| 531 AssignSafepoints(range); | 588 AssignSafepoints(range); |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 646 move->set_src(Location::PrefersRegister()); | 703 move->set_src(Location::PrefersRegister()); |
| 647 move_idx++; | 704 move_idx++; |
| 648 } | 705 } |
| 649 | 706 |
| 650 // Begin backward iteration with the instruction before the parallel | 707 // Begin backward iteration with the instruction before the parallel |
| 651 // move. | 708 // move. |
| 652 return goto_instr->previous(); | 709 return goto_instr->previous(); |
| 653 } | 710 } |
| 654 | 711 |
| 655 | 712 |
| 656 void FlowGraphAllocator::ConnectIncomingPhiMoves(BlockEntryInstr* block) { | 713 void FlowGraphAllocator::ConnectIncomingPhiMoves(JoinEntryInstr* join) { |
| 657 // If this block is a join we need to add destinations of phi | 714 // For join blocks we need to add destinations of phi resolution moves |
| 658 // resolution moves to phi's live range so that register allocator will | 715 // to phi's live range so that register allocator will fill them with moves. |
| 659 // fill them with moves. | |
| 660 JoinEntryInstr* join = block->AsJoinEntry(); | |
| 661 if (join == NULL) return; | |
| 662 | 716 |
| 663 // All uses are recorded at the start position in the block. | 717 // All uses are recorded at the start position in the block. |
| 664 const intptr_t pos = join->start_pos(); | 718 const intptr_t pos = join->start_pos(); |
| 665 const bool is_loop_header = BlockInfoAt(join->start_pos())->is_loop_header(); | 719 const bool is_loop_header = BlockInfoAt(join->start_pos())->is_loop_header(); |
| 666 intptr_t move_idx = 0; | 720 intptr_t move_idx = 0; |
| 667 for (PhiIterator it(join); !it.Done(); it.Advance()) { | 721 for (PhiIterator it(join); !it.Done(); it.Advance()) { |
| 668 PhiInstr* phi = it.Current(); | 722 PhiInstr* phi = it.Current(); |
| 669 ASSERT(phi != NULL); | 723 ASSERT(phi != NULL); |
| 670 const intptr_t vreg = phi->ssa_temp_index(); | 724 const intptr_t vreg = phi->ssa_temp_index(); |
| 671 ASSERT(vreg >= 0); | 725 ASSERT(vreg >= 0); |
| 672 | 726 |
| 673 // Expected shape of live range: | 727 // Expected shape of live range: |
| 674 // | 728 // |
| 675 // B | 729 // B |
| 676 // phi [-------- | 730 // phi [-------- |
| 677 // | 731 // |
| 678 LiveRange* range = GetLiveRange(vreg); | 732 LiveRange* range = GetLiveRange(vreg); |
| 679 range->DefineAt(pos); // Shorten live range. | 733 range->DefineAt(pos); // Shorten live range. |
| 680 | 734 |
| 681 if (is_loop_header) range->mark_loop_phi(); | 735 if (is_loop_header) range->mark_loop_phi(); |
| 682 | 736 |
| 683 for (intptr_t pred_idx = 0; pred_idx < phi->InputCount(); pred_idx++) { | 737 for (intptr_t pred_idx = 0; pred_idx < phi->InputCount(); pred_idx++) { |
| 684 BlockEntryInstr* pred = block->PredecessorAt(pred_idx); | 738 BlockEntryInstr* pred = join->PredecessorAt(pred_idx); |
| 685 GotoInstr* goto_instr = pred->last_instruction()->AsGoto(); | 739 GotoInstr* goto_instr = pred->last_instruction()->AsGoto(); |
| 686 ASSERT((goto_instr != NULL) && (goto_instr->HasParallelMove())); | 740 ASSERT((goto_instr != NULL) && (goto_instr->HasParallelMove())); |
| 687 MoveOperands* move = | 741 MoveOperands* move = |
| 688 goto_instr->parallel_move()->MoveOperandsAt(move_idx); | 742 goto_instr->parallel_move()->MoveOperandsAt(move_idx); |
| 689 move->set_dest(Location::PrefersRegister()); | 743 move->set_dest(Location::PrefersRegister()); |
| 690 range->AddUse(pos, move->dest_slot()); | 744 range->AddUse(pos, move->dest_slot()); |
| 691 } | 745 } |
| 692 | 746 |
| 693 // All phi resolution moves are connected. Phi's live range is | 747 // All phi resolution moves are connected. Phi's live range is |
| 694 // complete. | 748 // complete. |
| (...skipping 815 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1510 // Special care is taken to never allocate the same index to both | 1564 // Special care is taken to never allocate the same index to both |
| 1511 // double and quad spill slots as it complicates disambiguation during | 1565 // double and quad spill slots as it complicates disambiguation during |
| 1512 // parallel move resolution. | 1566 // parallel move resolution. |
| 1513 const bool need_quad = (register_kind_ == Location::kFpuRegister) && | 1567 const bool need_quad = (register_kind_ == Location::kFpuRegister) && |
| 1514 ((range->representation() == kUnboxedFloat32x4) || | 1568 ((range->representation() == kUnboxedFloat32x4) || |
| 1515 (range->representation() == kUnboxedUint32x4)); | 1569 (range->representation() == kUnboxedUint32x4)); |
| 1516 | 1570 |
| 1517 // Search for a free spill slot among allocated: the value in it should be | 1571 // Search for a free spill slot among allocated: the value in it should be |
| 1518 // dead and its type should match (e.g. it should not be a part of the quad if | 1572 // dead and its type should match (e.g. it should not be a part of the quad if |
| 1519 // we are allocating normal double slot). | 1573 // we are allocating normal double slot). |
| 1520 intptr_t idx = 0; | 1574 // For CPU registers we need to take reserved slots for try-catch into |
| 1575 // account. | |
| 1576 intptr_t idx = register_kind_ == Location::kRegister | |
| 1577 ? flow_graph_.graph_entry()->fixed_slot_count() | |
| 1578 : 0; | |
| 1521 for (; idx < spill_slots_.length(); idx++) { | 1579 for (; idx < spill_slots_.length(); idx++) { |
| 1522 if ((need_quad == quad_spill_slots_[idx]) && | 1580 if ((need_quad == quad_spill_slots_[idx]) && |
| 1523 (spill_slots_[idx] <= start)) { | 1581 (spill_slots_[idx] <= start)) { |
| 1524 break; | 1582 break; |
| 1525 } | 1583 } |
| 1526 } | 1584 } |
| 1527 | 1585 |
| 1528 if (idx == spill_slots_.length()) { | 1586 if (idx == spill_slots_.length()) { |
| 1529 // No free spill slot found. Allocate a new one. | 1587 // No free spill slot found. Allocate a new one. |
| 1530 spill_slots_.Add(0); | 1588 spill_slots_.Add(0); |
| (...skipping 871 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2402 GraphEntryInstr* graph_entry = flow_graph_.graph_entry(); | 2460 GraphEntryInstr* graph_entry = flow_graph_.graph_entry(); |
| 2403 for (intptr_t i = 0; i < graph_entry->initial_definitions()->length(); ++i) { | 2461 for (intptr_t i = 0; i < graph_entry->initial_definitions()->length(); ++i) { |
| 2404 Definition* def = (*graph_entry->initial_definitions())[i]; | 2462 Definition* def = (*graph_entry->initial_definitions())[i]; |
| 2405 value_representations_[def->ssa_temp_index()] = def->representation(); | 2463 value_representations_[def->ssa_temp_index()] = def->representation(); |
| 2406 } | 2464 } |
| 2407 | 2465 |
| 2408 for (BlockIterator it = flow_graph_.reverse_postorder_iterator(); | 2466 for (BlockIterator it = flow_graph_.reverse_postorder_iterator(); |
| 2409 !it.Done(); | 2467 !it.Done(); |
| 2410 it.Advance()) { | 2468 it.Advance()) { |
| 2411 BlockEntryInstr* block = it.Current(); | 2469 BlockEntryInstr* block = it.Current(); |
| 2470 | |
| 2471 // Catch entry. | |
| 2472 if (block->IsCatchBlockEntry()) { | |
| 2473 CatchBlockEntryInstr* catch_entry = block->AsCatchBlockEntry(); | |
| 2474 for (intptr_t i = 0; | |
| 2475 i < catch_entry->initial_definitions()->length(); | |
| 2476 ++i) { | |
| 2477 Definition* def = (*catch_entry->initial_definitions())[i]; | |
| 2478 value_representations_[def->ssa_temp_index()] = def->representation(); | |
| 2479 } | |
| 2480 } | |
| 2412 // Phis. | 2481 // Phis. |
| 2413 if (block->IsJoinEntry()) { | 2482 if (block->IsJoinEntry()) { |
| 2414 JoinEntryInstr* join = block->AsJoinEntry(); | 2483 JoinEntryInstr* join = block->AsJoinEntry(); |
| 2415 for (PhiIterator it(join); !it.Done(); it.Advance()) { | 2484 for (PhiIterator it(join); !it.Done(); it.Advance()) { |
| 2416 PhiInstr* phi = it.Current(); | 2485 PhiInstr* phi = it.Current(); |
| 2417 if ((phi != NULL) && (phi->ssa_temp_index() >= 0)) { | 2486 if ((phi != NULL) && (phi->ssa_temp_index() >= 0)) { |
| 2418 value_representations_[phi->ssa_temp_index()] = phi->representation(); | 2487 value_representations_[phi->ssa_temp_index()] = phi->representation(); |
| 2419 } | 2488 } |
| 2420 } | 2489 } |
| 2421 } | 2490 } |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2500 OS::Print("-- [after ssa allocator] ir [%s] -------------\n", | 2569 OS::Print("-- [after ssa allocator] ir [%s] -------------\n", |
| 2501 function.ToFullyQualifiedCString()); | 2570 function.ToFullyQualifiedCString()); |
| 2502 FlowGraphPrinter printer(flow_graph_, true); | 2571 FlowGraphPrinter printer(flow_graph_, true); |
| 2503 printer.PrintBlocks(); | 2572 printer.PrintBlocks(); |
| 2504 OS::Print("----------------------------------------------\n"); | 2573 OS::Print("----------------------------------------------\n"); |
| 2505 } | 2574 } |
| 2506 } | 2575 } |
| 2507 | 2576 |
| 2508 | 2577 |
| 2509 } // namespace dart | 2578 } // namespace dart |
| OLD | NEW |