Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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_builder.h" | 10 #include "vm/flow_graph_builder.h" |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 31 static const intptr_t kTempVirtualRegister = -2; | 31 static const intptr_t kTempVirtualRegister = -2; |
| 32 static const intptr_t kIllegalPosition = -1; | 32 static const intptr_t kIllegalPosition = -1; |
| 33 static const intptr_t kMaxPosition = 0x7FFFFFFF; | 33 static const intptr_t kMaxPosition = 0x7FFFFFFF; |
| 34 | 34 |
| 35 | 35 |
| 36 static intptr_t MinPosition(intptr_t a, intptr_t b) { | 36 static intptr_t MinPosition(intptr_t a, intptr_t b) { |
| 37 return (a < b) ? a : b; | 37 return (a < b) ? a : b; |
| 38 } | 38 } |
| 39 | 39 |
| 40 | 40 |
| 41 static bool IsParallelMovePosition(intptr_t pos) { | |
| 42 return (pos & 1) == 0; | |
| 43 } | |
| 44 | |
| 45 | |
| 46 static bool IsInstructionStartPosition(intptr_t pos) { | 41 static bool IsInstructionStartPosition(intptr_t pos) { |
| 47 return (pos & 1) == 0; | 42 return (pos & 1) == 0; |
| 48 } | 43 } |
| 49 | 44 |
| 50 | 45 |
| 51 static bool IsInstructionEndPosition(intptr_t pos) { | 46 static bool IsInstructionEndPosition(intptr_t pos) { |
| 52 return (pos & 1) == 1; | 47 return (pos & 1) == 1; |
| 53 } | 48 } |
| 54 | 49 |
| 55 | 50 |
| (...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 329 } | 324 } |
| 330 | 325 |
| 331 | 326 |
| 332 void FlowGraphAllocator::BlockLocation(Location loc, intptr_t pos) { | 327 void FlowGraphAllocator::BlockLocation(Location loc, intptr_t pos) { |
| 333 ASSERT(loc.IsRegister()); | 328 ASSERT(loc.IsRegister()); |
| 334 const Register reg = loc.reg(); | 329 const Register reg = loc.reg(); |
| 335 if (blocked_cpu_regs_[reg]) return; | 330 if (blocked_cpu_regs_[reg]) return; |
| 336 if (cpu_regs_[reg].length() == 0) { | 331 if (cpu_regs_[reg].length() == 0) { |
| 337 cpu_regs_[reg].Add(new LiveRange(kNoVirtualRegister)); | 332 cpu_regs_[reg].Add(new LiveRange(kNoVirtualRegister)); |
| 338 } | 333 } |
| 339 cpu_regs_[reg][0]->AddUseInterval(pos, pos + 2); | 334 cpu_regs_[reg][0]->AddUseInterval(pos, pos + 1); |
|
srdjan
2012/07/31 15:58:35
Please add comment about the interval range (begin
Vyacheslav Egorov (Google)
2012/07/31 16:18:49
Done.
| |
| 340 } | 335 } |
| 341 | 336 |
| 342 | 337 |
| 343 void LiveRange::Print() { | 338 void LiveRange::Print() { |
| 344 OS::Print(" live range v%d [%d, %d)\n", vreg(), Start(), End()); | 339 OS::Print(" live range v%d [%d, %d)\n", vreg(), Start(), End()); |
| 345 UsePosition* use_pos = uses_; | 340 UsePosition* use_pos = uses_; |
| 346 for (UseInterval* interval = first_use_interval_; | 341 for (UseInterval* interval = first_use_interval_; |
| 347 interval != NULL; | 342 interval != NULL; |
| 348 interval = interval->next()) { | 343 interval = interval->next()) { |
| 349 OS::Print(" use interval [%d, %d)\n", | 344 OS::Print(" use interval [%d, %d)\n", |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 473 BlockEntryInstr* block) { | 468 BlockEntryInstr* block) { |
| 474 Instruction* last = block->last_instruction(); | 469 Instruction* last = block->last_instruction(); |
| 475 | 470 |
| 476 GotoInstr* goto_instr = last->AsGoto(); | 471 GotoInstr* goto_instr = last->AsGoto(); |
| 477 if (goto_instr == NULL) return last; | 472 if (goto_instr == NULL) return last; |
| 478 | 473 |
| 479 // If we have a parallel move here then the successor block must be a | 474 // If we have a parallel move here then the successor block must be a |
| 480 // join with phis. The phi inputs contribute uses to each predecessor | 475 // join with phis. The phi inputs contribute uses to each predecessor |
| 481 // block (and the phi outputs contribute definitions in the successor | 476 // block (and the phi outputs contribute definitions in the successor |
| 482 // block). | 477 // block). |
| 483 ParallelMoveInstr* parallel_move = goto_instr->previous()->AsParallelMove(); | 478 if (!goto_instr->HasParallelMove()) return goto_instr->previous(); |
| 484 if (parallel_move == NULL) return goto_instr->previous(); | 479 ParallelMoveInstr* parallel_move = goto_instr->parallel_move(); |
| 485 | 480 |
| 486 // All uses are recorded at the position of parallel move preceding goto. | 481 // All uses are recorded at the position of parallel move preceding goto. |
| 487 const intptr_t pos = goto_instr->lifetime_position(); | 482 const intptr_t pos = goto_instr->lifetime_position(); |
| 488 ASSERT(parallel_move->lifetime_position() == pos); | |
| 489 | 483 |
| 490 JoinEntryInstr* join = goto_instr->successor(); | 484 JoinEntryInstr* join = goto_instr->successor(); |
| 491 ASSERT(join != NULL); | 485 ASSERT(join != NULL); |
| 492 | 486 |
| 493 // Search for the index of the current block in the predecessors of | 487 // Search for the index of the current block in the predecessors of |
| 494 // the join. | 488 // the join. |
| 495 const intptr_t pred_idx = join->IndexOfPredecessor(block); | 489 const intptr_t pred_idx = join->IndexOfPredecessor(block); |
| 496 | 490 |
| 497 // Record the corresponding phi input use for each phi. | 491 // Record the corresponding phi input use for each phi. |
| 498 ZoneGrowableArray<PhiInstr*>* phis = join->phis(); | 492 ZoneGrowableArray<PhiInstr*>* phis = join->phis(); |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 519 move->set_src(Location::PrefersRegister()); | 513 move->set_src(Location::PrefersRegister()); |
| 520 } else { | 514 } else { |
| 521 ASSERT(val->IsConstant()); | 515 ASSERT(val->IsConstant()); |
| 522 move->set_src(Location::Constant(val->AsConstant()->value())); | 516 move->set_src(Location::Constant(val->AsConstant()->value())); |
| 523 } | 517 } |
| 524 move_idx++; | 518 move_idx++; |
| 525 } | 519 } |
| 526 | 520 |
| 527 // Begin backward iteration with the instruction before the parallel | 521 // Begin backward iteration with the instruction before the parallel |
| 528 // move. | 522 // move. |
| 529 return parallel_move->previous(); | 523 return goto_instr->previous(); |
| 530 } | 524 } |
| 531 | 525 |
| 532 | 526 |
| 533 void FlowGraphAllocator::ConnectIncomingPhiMoves(BlockEntryInstr* block) { | 527 void FlowGraphAllocator::ConnectIncomingPhiMoves(BlockEntryInstr* block) { |
| 534 // If this block is a join we need to add destinations of phi | 528 // If this block is a join we need to add destinations of phi |
| 535 // resolution moves to phi's live range so that register allocator will | 529 // resolution moves to phi's live range so that register allocator will |
| 536 // fill them with moves. | 530 // fill them with moves. |
| 537 JoinEntryInstr* join = block->AsJoinEntry(); | 531 JoinEntryInstr* join = block->AsJoinEntry(); |
| 538 if (join == NULL) return; | 532 if (join == NULL) return; |
| 539 | 533 |
| 540 // All uses are recorded at the start position in the block. | 534 // All uses are recorded at the start position in the block. |
| 541 const intptr_t pos = join->start_pos(); | 535 const intptr_t pos = join->start_pos(); |
| 542 | 536 |
| 543 ZoneGrowableArray<PhiInstr*>* phis = join->phis(); | 537 ZoneGrowableArray<PhiInstr*>* phis = join->phis(); |
| 544 if (phis != NULL) { | 538 if (phis != NULL) { |
| 545 intptr_t move_idx = 0; | 539 intptr_t move_idx = 0; |
| 546 for (intptr_t phi_idx = 0; phi_idx < phis->length(); phi_idx++) { | 540 for (intptr_t phi_idx = 0; phi_idx < phis->length(); phi_idx++) { |
| 547 PhiInstr* phi = (*phis)[phi_idx]; | 541 PhiInstr* phi = (*phis)[phi_idx]; |
| 548 if (phi == NULL) continue; | 542 if (phi == NULL) continue; |
| 549 | 543 |
| 550 const intptr_t vreg = phi->ssa_temp_index(); | 544 const intptr_t vreg = phi->ssa_temp_index(); |
| 551 ASSERT(vreg != -1); | 545 ASSERT(vreg != -1); |
| 552 | 546 |
| 553 // Expected shape of live range: | 547 // Expected sfhape of live range: |
|
Florian Schneider
2012/07/31 15:31:59
Accidental edit?
Vyacheslav Egorov (Google)
2012/07/31 16:18:49
Done.
| |
| 554 // | 548 // |
| 555 // B | 549 // B |
| 556 // phi [-------- | 550 // phi [-------- |
| 557 // | 551 // |
| 558 LiveRange* range = GetLiveRange(vreg); | 552 LiveRange* range = GetLiveRange(vreg); |
| 559 range->DefineAt(pos); // Shorten live range. | 553 range->DefineAt(pos); // Shorten live range. |
| 560 | 554 |
| 561 for (intptr_t pred_idx = 0; pred_idx < phi->InputCount(); pred_idx++) { | 555 for (intptr_t pred_idx = 0; pred_idx < phi->InputCount(); pred_idx++) { |
| 562 BlockEntryInstr* pred = block->PredecessorAt(pred_idx); | 556 BlockEntryInstr* pred = block->PredecessorAt(pred_idx); |
| 563 ASSERT(pred->last_instruction()->IsGoto()); | 557 GotoInstr* goto_instr = pred->last_instruction()->AsGoto(); |
| 564 Instruction* move_instr = pred->last_instruction()->previous(); | 558 ASSERT((goto_instr != NULL) && (goto_instr->HasParallelMove())); |
| 565 ASSERT(move_instr->IsParallelMove()); | |
| 566 | |
| 567 MoveOperands* move = | 559 MoveOperands* move = |
| 568 move_instr->AsParallelMove()->MoveOperandsAt(move_idx); | 560 goto_instr->parallel_move()->MoveOperandsAt(move_idx); |
| 569 move->set_dest(Location::PrefersRegister()); | 561 move->set_dest(Location::PrefersRegister()); |
| 570 range->AddUse(pos, move->dest_slot()); | 562 range->AddUse(pos, move->dest_slot()); |
| 571 } | 563 } |
| 572 | 564 |
| 573 // All phi resolution moves are connected. Phi's live range is | 565 // All phi resolution moves are connected. Phi's live range is |
| 574 // complete. | 566 // complete. |
| 575 AddToUnallocated(range); | 567 AddToUnallocated(range); |
| 576 | 568 |
| 577 move_idx++; | 569 move_idx++; |
| 578 } | 570 } |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 672 range->AddUseInterval(block->start_pos(), pos + 1); | 664 range->AddUseInterval(block->start_pos(), pos + 1); |
| 673 range->AddUse(pos + 1, in_ref); | 665 range->AddUse(pos + 1, in_ref); |
| 674 } | 666 } |
| 675 } | 667 } |
| 676 | 668 |
| 677 // Process temps. | 669 // Process temps. |
| 678 for (intptr_t j = 0; j < locs->temp_count(); j++) { | 670 for (intptr_t j = 0; j < locs->temp_count(); j++) { |
| 679 // Expected shape of live range: | 671 // Expected shape of live range: |
| 680 // | 672 // |
| 681 // i i' | 673 // i i' |
| 682 // [-----) | 674 // [--) |
| 683 // | 675 // |
| 684 | 676 |
| 685 Location temp = locs->temp(j); | 677 Location temp = locs->temp(j); |
| 686 if (temp.IsRegister()) { | 678 if (temp.IsRegister()) { |
| 687 BlockLocation(temp, pos); | 679 BlockLocation(temp, pos); |
| 688 } else if (temp.IsUnallocated()) { | 680 } else if (temp.IsUnallocated()) { |
| 689 LiveRange* range = new LiveRange(kTempVirtualRegister); | 681 LiveRange* range = new LiveRange(kTempVirtualRegister); |
| 690 range->AddUseInterval(pos, pos + 1); | 682 range->AddUseInterval(pos, pos + 1); |
| 691 range->AddUse(pos, locs->temp_slot(j)); | 683 range->AddUse(pos, locs->temp_slot(j)); |
| 692 AddToUnallocated(range); | 684 AddToUnallocated(range); |
| 693 } else { | 685 } else { |
| 694 UNREACHABLE(); | 686 UNREACHABLE(); |
| 695 } | 687 } |
| 696 } | 688 } |
| 697 | 689 |
| 698 // Block all allocatable registers for calls. | 690 // Block all allocatable registers for calls. |
| 699 if (locs->is_call()) { | 691 if (locs->is_call()) { |
| 700 // Expected shape of live range: | 692 // Expected shape of live range: |
| 701 // | 693 // |
| 702 // i i' | 694 // i i' |
| 703 // [-----) | 695 // [--) |
| 704 // | 696 // |
| 705 | 697 |
| 706 for (intptr_t reg = 0; reg < kNumberOfCpuRegisters; reg++) { | 698 for (intptr_t reg = 0; reg < kNumberOfCpuRegisters; reg++) { |
| 707 BlockLocation(Location::RegisterLocation(static_cast<Register>(reg)), | 699 BlockLocation(Location::RegisterLocation(static_cast<Register>(reg)), |
| 708 pos); | 700 pos); |
| 709 } | 701 } |
| 710 | 702 |
| 711 #ifdef DEBUG | 703 #ifdef DEBUG |
| 712 // Verify that temps, inputs and output were specified as fixed | 704 // Verify that temps, inputs and output were specified as fixed |
| 713 // locations. Every register is blocked now so attempt to | 705 // locations. Every register is blocked now so attempt to |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 740 LiveRange* range = (def->ssa_temp_index() >= 0) ? | 732 LiveRange* range = (def->ssa_temp_index() >= 0) ? |
| 741 GetLiveRange(def->ssa_temp_index()) : | 733 GetLiveRange(def->ssa_temp_index()) : |
| 742 new LiveRange(kTempVirtualRegister); | 734 new LiveRange(kTempVirtualRegister); |
| 743 Location* out = locs->out_slot(); | 735 Location* out = locs->out_slot(); |
| 744 | 736 |
| 745 // Process output and finalize its liverange. | 737 // Process output and finalize its liverange. |
| 746 if (out->IsRegister()) { | 738 if (out->IsRegister()) { |
| 747 // Fixed output location. Expected shape of live range: | 739 // Fixed output location. Expected shape of live range: |
| 748 // | 740 // |
| 749 // i i' j j' | 741 // i i' j j' |
| 750 // register [-----) | 742 // register [--) |
| 751 // output [------- | 743 // output [------- |
| 752 // | 744 // |
| 753 BlockLocation(*out, pos); | 745 BlockLocation(*out, pos); |
| 754 | 746 |
| 755 if (range->vreg() == kTempVirtualRegister) return; | 747 if (range->vreg() == kTempVirtualRegister) return; |
| 756 | 748 |
| 757 // We need to emit move connecting fixed register with another location | 749 // We need to emit move connecting fixed register with another location |
| 758 // that will be allocated for this output's live range. | 750 // that will be allocated for this output's live range. |
| 759 // Special case: fixed output followed by a fixed input last use. | 751 // Special case: fixed output followed by a fixed input last use. |
| 760 UsePosition* use = range->first_use(); | 752 UsePosition* use = range->first_use(); |
| 761 if (use->pos() == (pos + 2)) { | 753 if (use->pos() == (pos + 1)) { |
| 762 ASSERT(use->location_slot()->IsUnallocated()); | 754 ASSERT(use->location_slot()->IsUnallocated()); |
| 763 *(use->location_slot()) = *out; | 755 *(use->location_slot()) = *out; |
| 764 | 756 |
| 765 // Remove first use. It was allocated. | 757 // Remove first use. It was allocated. |
| 766 range->set_first_use(range->first_use()->next()); | 758 range->set_first_use(range->first_use()->next()); |
| 767 } | 759 } |
| 768 | 760 |
| 769 // Shorten live range to the point of definition, this might make the range | 761 // Shorten live range to the point of definition, this might make the range |
| 770 // empty (if the only use immediately follows). If range is not empty add | 762 // empty (if the only use immediately follows). If range is not empty add |
| 771 // move from a fixed register to an unallocated location. | 763 // move from a fixed register to an unallocated location. |
| 772 range->DefineAt(pos + 2); | 764 range->DefineAt(pos + 1); |
| 773 if (range->Start() == range->End()) return; | 765 if (range->Start() == range->End()) return; |
| 774 | 766 |
| 775 MoveOperands* move = AddMoveAt(pos + 2, Location::PrefersRegister(), *out); | 767 MoveOperands* move = AddMoveAt(pos + 1, Location::PrefersRegister(), *out); |
| 776 range->AddUse(pos + 2, move->dest_slot()); | 768 range->AddUse(pos + 1, move->dest_slot()); |
| 777 } else if (output_same_as_first_input) { | 769 } else if (output_same_as_first_input) { |
| 778 // Output register will contain a value of the first input at instruction's | 770 // Output register will contain a value of the first input at instruction's |
| 779 // start. Expected shape of live ranges: | 771 // start. Expected shape of live ranges: |
| 780 // | 772 // |
| 781 // i i' | 773 // i i' |
| 782 // input #0 --* | 774 // input #0 --* |
| 783 // output [---- | 775 // output [---- |
| 784 // | 776 // |
| 785 ASSERT(locs->in_slot(0)->Equals(Location::RequiresRegister())); | 777 ASSERT(locs->in_slot(0)->Equals(Location::RequiresRegister())); |
| 786 | 778 |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 891 JoinEntryInstr* join = block->AsJoinEntry(); | 883 JoinEntryInstr* join = block->AsJoinEntry(); |
| 892 if ((join != NULL) && (join->phi_count() > 0)) { | 884 if ((join != NULL) && (join->phi_count() > 0)) { |
| 893 const intptr_t phi_count = join->phi_count(); | 885 const intptr_t phi_count = join->phi_count(); |
| 894 for (intptr_t i = 0; i < block->PredecessorCount(); i++) { | 886 for (intptr_t i = 0; i < block->PredecessorCount(); i++) { |
| 895 // Insert the move between the last two instructions of the | 887 // Insert the move between the last two instructions of the |
| 896 // predecessor block (all such blocks have at least two instructions: | 888 // predecessor block (all such blocks have at least two instructions: |
| 897 // the block entry and goto instructions.) | 889 // the block entry and goto instructions.) |
| 898 Instruction* last = block->PredecessorAt(i)->last_instruction(); | 890 Instruction* last = block->PredecessorAt(i)->last_instruction(); |
| 899 ASSERT(last->IsGoto()); | 891 ASSERT(last->IsGoto()); |
| 900 | 892 |
| 901 ParallelMoveInstr* move = | 893 ParallelMoveInstr* move = last->AsGoto()->GetParallelMove(); |
| 902 CreateParallelMoveBefore(last, last->lifetime_position()); | |
| 903 | 894 |
| 904 // Populate the ParallelMove with empty moves. | 895 // Populate the ParallelMove with empty moves. |
| 905 for (intptr_t j = 0; j < phi_count; j++) { | 896 for (intptr_t j = 0; j < phi_count; j++) { |
| 906 move->AddMove(Location::NoLocation(), Location::NoLocation()); | 897 move->AddMove(Location::NoLocation(), Location::NoLocation()); |
| 907 } | 898 } |
| 908 | |
| 909 // Replace Goto instruction with the corresponding move in | |
| 910 // the array of instructions. This is done to ensure that | |
| 911 // this parallel move will be treated as a normal instruction | |
| 912 // by AddMoveAt for the purpose of live ranges connections (i.e. | |
| 913 // a separate move will be inserted by AddMoveAt) | |
| 914 // This move can't be reused by AddMoveAt to insert | |
| 915 // moves at Goto position because such range connecting moves might | |
| 916 // come into a conflict with phi connecting moves due to implicit | |
| 917 // interference: phi-value's liferange starts only at successor block | |
| 918 // but the move is actually performed at the predecessor. | |
| 919 ASSERT(instructions_[last->lifetime_position() / 2] == last); | |
| 920 instructions_[last->lifetime_position() / 2] = move; | |
| 921 } | 899 } |
| 922 } | 900 } |
| 923 } | 901 } |
| 924 } | 902 } |
| 925 | 903 |
| 926 | 904 |
| 927 Instruction* FlowGraphAllocator::InstructionAt(intptr_t pos) const { | 905 Instruction* FlowGraphAllocator::InstructionAt(intptr_t pos) const { |
| 928 return instructions_[pos / 2]; | 906 return instructions_[pos / 2]; |
| 929 } | 907 } |
| 930 | 908 |
| 931 | 909 |
| 932 bool FlowGraphAllocator::IsBlockEntry(intptr_t pos) const { | 910 bool FlowGraphAllocator::IsBlockEntry(intptr_t pos) const { |
| 933 return InstructionAt(pos)->IsBlockEntry(); | 911 return IsInstructionStartPosition(pos) && InstructionAt(pos)->IsBlockEntry(); |
| 934 } | 912 } |
| 935 | 913 |
| 936 | 914 |
| 937 void AllocationFinger::Initialize(LiveRange* range) { | 915 void AllocationFinger::Initialize(LiveRange* range) { |
| 938 first_pending_use_interval_ = range->first_use_interval(); | 916 first_pending_use_interval_ = range->first_use_interval(); |
| 939 first_register_use_ = range->first_use(); | 917 first_register_use_ = range->first_use(); |
| 940 first_register_beneficial_use_ = range->first_use(); | 918 first_register_beneficial_use_ = range->first_use(); |
| 941 first_hinted_use_ = range->first_use(); | 919 first_hinted_use_ = range->first_use(); |
| 942 } | 920 } |
| 943 | 921 |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1093 first_after_split : last_use_interval_; | 1071 first_after_split : last_use_interval_; |
| 1094 next_sibling_ = new LiveRange(vreg(), | 1072 next_sibling_ = new LiveRange(vreg(), |
| 1095 first_use_after_split, | 1073 first_use_after_split, |
| 1096 first_after_split, | 1074 first_after_split, |
| 1097 last_use_interval, | 1075 last_use_interval, |
| 1098 next_sibling_); | 1076 next_sibling_); |
| 1099 | 1077 |
| 1100 TRACE_ALLOC((" split sibling [%d, %d)\n", | 1078 TRACE_ALLOC((" split sibling [%d, %d)\n", |
| 1101 next_sibling_->Start(), next_sibling_->End())); | 1079 next_sibling_->Start(), next_sibling_->End())); |
| 1102 | 1080 |
| 1103 // Split sibling can only start at a parallel move. | |
| 1104 ASSERT(IsParallelMovePosition(next_sibling_->Start())); | |
| 1105 | |
| 1106 last_use_interval_ = last_before_split; | 1081 last_use_interval_ = last_before_split; |
| 1107 last_use_interval_->next_ = NULL; | 1082 last_use_interval_->next_ = NULL; |
| 1108 return next_sibling_; | 1083 return next_sibling_; |
| 1109 } | 1084 } |
| 1110 | 1085 |
| 1111 | 1086 |
| 1112 LiveRange* FlowGraphAllocator::SplitBetween(LiveRange* range, | 1087 LiveRange* FlowGraphAllocator::SplitBetween(LiveRange* range, |
| 1113 intptr_t from, | 1088 intptr_t from, |
| 1114 intptr_t to) { | 1089 intptr_t to) { |
| 1115 // TODO(vegorov): select optimal split position based on loop structure. | 1090 // TODO(vegorov): select optimal split position based on loop structure. |
| 1116 TRACE_ALLOC(("split %d [%d, %d) between [%d, %d)\n", | 1091 TRACE_ALLOC(("split %d [%d, %d) between [%d, %d)\n", |
| 1117 range->vreg(), range->Start(), range->End(), from, to)); | 1092 range->vreg(), range->Start(), range->End(), from, to)); |
| 1118 | 1093 |
| 1119 // Prefer spliting at instruction starts if possible. | 1094 // Prefer spliting at instruction starts if possible. |
| 1120 if (from < ToInstructionStart(to)) { | 1095 if (from < ToInstructionStart(to)) { |
| 1121 to = ToInstructionStart(to); | 1096 to = ToInstructionStart(to); |
| 1122 } | 1097 } |
| 1123 | 1098 |
| 1099 if (to == range->End()) to -= 1; | |
|
Florian Schneider
2012/07/31 15:31:59
A comment would be good here.
Vyacheslav Egorov (Google)
2012/07/31 16:18:49
Done.
| |
| 1100 | |
| 1124 return range->SplitAt(to); | 1101 return range->SplitAt(to); |
| 1125 } | 1102 } |
| 1126 | 1103 |
| 1127 | 1104 |
| 1128 void FlowGraphAllocator::SpillBetween(LiveRange* range, | 1105 void FlowGraphAllocator::SpillBetween(LiveRange* range, |
| 1129 intptr_t from, | 1106 intptr_t from, |
| 1130 intptr_t to) { | 1107 intptr_t to) { |
| 1131 ASSERT(from < to); | 1108 ASSERT(from < to); |
| 1132 TRACE_ALLOC(("spill %d [%d, %d) between [%d, %d)\n", | 1109 TRACE_ALLOC(("spill %d [%d, %d) between [%d, %d)\n", |
| 1133 range->vreg(), range->Start(), range->End(), from, to)); | 1110 range->vreg(), range->Start(), range->End(), from, to)); |
| (...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1416 SpillBetween(allocated, spill_position, restore_position); | 1393 SpillBetween(allocated, spill_position, restore_position); |
| 1417 } | 1394 } |
| 1418 | 1395 |
| 1419 return true; | 1396 return true; |
| 1420 } | 1397 } |
| 1421 | 1398 |
| 1422 | 1399 |
| 1423 MoveOperands* FlowGraphAllocator::AddMoveAt(intptr_t pos, | 1400 MoveOperands* FlowGraphAllocator::AddMoveAt(intptr_t pos, |
| 1424 Location to, | 1401 Location to, |
| 1425 Location from) { | 1402 Location from) { |
| 1403 ASSERT(!IsBlockEntry(pos)); | |
| 1404 | |
| 1426 Instruction* instr = InstructionAt(pos); | 1405 Instruction* instr = InstructionAt(pos); |
| 1427 ASSERT(!instr->IsBlockEntry()); | |
| 1428 | 1406 |
| 1429 ParallelMoveInstr* parallel_move = NULL; | 1407 ParallelMoveInstr* parallel_move = NULL; |
| 1430 if (IsInstructionStartPosition(pos)) { | 1408 if (IsInstructionStartPosition(pos)) { |
| 1431 parallel_move = CreateParallelMoveBefore(instr, pos); | 1409 parallel_move = CreateParallelMoveBefore(instr, pos); |
| 1432 } else { | 1410 } else { |
| 1433 parallel_move = CreateParallelMoveAfter(instr, pos); | 1411 parallel_move = CreateParallelMoveAfter(instr, pos); |
| 1434 } | 1412 } |
| 1435 | 1413 |
| 1436 return parallel_move->AddMove(to, from); | 1414 return parallel_move->AddMove(to, from); |
| 1437 } | 1415 } |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1603 | 1581 |
| 1604 TRACE_ALLOC(("connecting [%d, %d) [%s] to [%d, %d) [%s]\n", | 1582 TRACE_ALLOC(("connecting [%d, %d) [%s] to [%d, %d) [%s]\n", |
| 1605 source_cover->Start(), source_cover->End(), source.Name(), | 1583 source_cover->Start(), source_cover->End(), source.Name(), |
| 1606 target_cover->Start(), target_cover->End(), target.Name())); | 1584 target_cover->Start(), target_cover->End(), target.Name())); |
| 1607 | 1585 |
| 1608 // Siblings were allocated to the same register. | 1586 // Siblings were allocated to the same register. |
| 1609 if (source.Equals(target)) return; | 1587 if (source.Equals(target)) return; |
| 1610 | 1588 |
| 1611 Instruction* last = source_block->last_instruction(); | 1589 Instruction* last = source_block->last_instruction(); |
| 1612 if (last->SuccessorCount() == 1) { | 1590 if (last->SuccessorCount() == 1) { |
| 1613 CreateParallelMoveBefore(last, last->lifetime_position())-> | 1591 ASSERT(last->IsGoto()); |
| 1614 AddMove(target, source); | 1592 last->AsGoto()->GetParallelMove()->AddMove(target, source); |
| 1615 } else { | 1593 } else { |
| 1616 CreateParallelMoveAfter(target_block, target_block->start_pos())-> | 1594 target_block->GetParallelMove()->AddMove(target, source); |
| 1617 AddMove(target, source); | |
| 1618 } | 1595 } |
| 1619 } | 1596 } |
| 1620 | 1597 |
| 1621 | 1598 |
| 1622 void FlowGraphAllocator::ResolveControlFlow() { | 1599 void FlowGraphAllocator::ResolveControlFlow() { |
| 1623 // Resolve linear control flow between touching split siblings | 1600 // Resolve linear control flow between touching split siblings |
| 1624 // inside basic blocks. | 1601 // inside basic blocks. |
| 1625 for (intptr_t vreg = 0; vreg < live_ranges_.length(); vreg++) { | 1602 for (intptr_t vreg = 0; vreg < live_ranges_.length(); vreg++) { |
| 1626 LiveRange* range = live_ranges_[vreg]; | 1603 LiveRange* range = live_ranges_[vreg]; |
| 1627 if (range == NULL) continue; | 1604 if (range == NULL) continue; |
| 1628 | 1605 |
| 1629 while (range->next_sibling() != NULL) { | 1606 while (range->next_sibling() != NULL) { |
| 1630 LiveRange* sibling = range->next_sibling(); | 1607 LiveRange* sibling = range->next_sibling(); |
| 1608 TRACE_ALLOC(("connecting [%d, %d) [%s] to [%d, %d) [%s]\n", | |
| 1609 range->Start(), range->End(), | |
| 1610 range->assigned_location().Name(), | |
| 1611 sibling->Start(), sibling->End(), | |
| 1612 sibling->assigned_location().Name())); | |
| 1631 if ((range->End() == sibling->Start()) && | 1613 if ((range->End() == sibling->Start()) && |
| 1632 !range->assigned_location().Equals(sibling->assigned_location()) && | 1614 !range->assigned_location().Equals(sibling->assigned_location()) && |
| 1633 !IsBlockEntry(range->End())) { | 1615 !IsBlockEntry(range->End())) { |
| 1634 AddMoveAt(sibling->Start(), | 1616 AddMoveAt(sibling->Start(), |
| 1635 sibling->assigned_location(), | 1617 sibling->assigned_location(), |
| 1636 range->assigned_location()); | 1618 range->assigned_location()); |
| 1637 } | 1619 } |
| 1638 range = sibling; | 1620 range = sibling; |
| 1639 } | 1621 } |
| 1640 } | 1622 } |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1676 | 1658 |
| 1677 if (FLAG_trace_ssa_allocator) { | 1659 if (FLAG_trace_ssa_allocator) { |
| 1678 OS::Print("-- ir after allocation -------------------------\n"); | 1660 OS::Print("-- ir after allocation -------------------------\n"); |
| 1679 FlowGraphPrinter printer(Function::Handle(), block_order_, true); | 1661 FlowGraphPrinter printer(Function::Handle(), block_order_, true); |
| 1680 printer.PrintBlocks(); | 1662 printer.PrintBlocks(); |
| 1681 } | 1663 } |
| 1682 } | 1664 } |
| 1683 | 1665 |
| 1684 | 1666 |
| 1685 } // namespace dart | 1667 } // namespace dart |
| OLD | NEW |