| 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 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 322 | 317 |
| 323 | 318 |
| 324 LiveRange* FlowGraphAllocator::GetLiveRange(intptr_t vreg) { | 319 LiveRange* FlowGraphAllocator::GetLiveRange(intptr_t vreg) { |
| 325 if (live_ranges_[vreg] == NULL) { | 320 if (live_ranges_[vreg] == NULL) { |
| 326 live_ranges_[vreg] = new LiveRange(vreg); | 321 live_ranges_[vreg] = new LiveRange(vreg); |
| 327 } | 322 } |
| 328 return live_ranges_[vreg]; | 323 return live_ranges_[vreg]; |
| 329 } | 324 } |
| 330 | 325 |
| 331 | 326 |
| 327 // Block location from the start of the instruction to its end. |
| 332 void FlowGraphAllocator::BlockLocation(Location loc, intptr_t pos) { | 328 void FlowGraphAllocator::BlockLocation(Location loc, intptr_t pos) { |
| 333 ASSERT(loc.IsRegister()); | 329 ASSERT(loc.IsRegister()); |
| 330 ASSERT(IsInstructionStartPosition(pos)); |
| 334 const Register reg = loc.reg(); | 331 const Register reg = loc.reg(); |
| 335 if (blocked_cpu_regs_[reg]) return; | 332 if (blocked_cpu_regs_[reg]) return; |
| 336 if (cpu_regs_[reg].length() == 0) { | 333 if (cpu_regs_[reg].length() == 0) { |
| 337 cpu_regs_[reg].Add(new LiveRange(kNoVirtualRegister)); | 334 cpu_regs_[reg].Add(new LiveRange(kNoVirtualRegister)); |
| 338 } | 335 } |
| 339 cpu_regs_[reg][0]->AddUseInterval(pos, pos + 2); | 336 cpu_regs_[reg][0]->AddUseInterval(pos, pos + 1); |
| 340 } | 337 } |
| 341 | 338 |
| 342 | 339 |
| 343 void LiveRange::Print() { | 340 void LiveRange::Print() { |
| 344 OS::Print(" live range v%d [%d, %d)\n", vreg(), Start(), End()); | 341 OS::Print(" live range v%d [%d, %d)\n", vreg(), Start(), End()); |
| 345 UsePosition* use_pos = uses_; | 342 UsePosition* use_pos = uses_; |
| 346 for (UseInterval* interval = first_use_interval_; | 343 for (UseInterval* interval = first_use_interval_; |
| 347 interval != NULL; | 344 interval != NULL; |
| 348 interval = interval->next()) { | 345 interval = interval->next()) { |
| 349 OS::Print(" use interval [%d, %d)\n", | 346 OS::Print(" use interval [%d, %d)\n", |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 473 BlockEntryInstr* block) { | 470 BlockEntryInstr* block) { |
| 474 Instruction* last = block->last_instruction(); | 471 Instruction* last = block->last_instruction(); |
| 475 | 472 |
| 476 GotoInstr* goto_instr = last->AsGoto(); | 473 GotoInstr* goto_instr = last->AsGoto(); |
| 477 if (goto_instr == NULL) return last; | 474 if (goto_instr == NULL) return last; |
| 478 | 475 |
| 479 // If we have a parallel move here then the successor block must be a | 476 // 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 | 477 // join with phis. The phi inputs contribute uses to each predecessor |
| 481 // block (and the phi outputs contribute definitions in the successor | 478 // block (and the phi outputs contribute definitions in the successor |
| 482 // block). | 479 // block). |
| 483 ParallelMoveInstr* parallel_move = goto_instr->previous()->AsParallelMove(); | 480 if (!goto_instr->HasParallelMove()) return goto_instr->previous(); |
| 484 if (parallel_move == NULL) return goto_instr->previous(); | 481 ParallelMoveInstr* parallel_move = goto_instr->parallel_move(); |
| 485 | 482 |
| 486 // All uses are recorded at the position of parallel move preceding goto. | 483 // All uses are recorded at the position of parallel move preceding goto. |
| 487 const intptr_t pos = goto_instr->lifetime_position(); | 484 const intptr_t pos = goto_instr->lifetime_position(); |
| 488 ASSERT(parallel_move->lifetime_position() == pos); | |
| 489 | 485 |
| 490 JoinEntryInstr* join = goto_instr->successor(); | 486 JoinEntryInstr* join = goto_instr->successor(); |
| 491 ASSERT(join != NULL); | 487 ASSERT(join != NULL); |
| 492 | 488 |
| 493 // Search for the index of the current block in the predecessors of | 489 // Search for the index of the current block in the predecessors of |
| 494 // the join. | 490 // the join. |
| 495 const intptr_t pred_idx = join->IndexOfPredecessor(block); | 491 const intptr_t pred_idx = join->IndexOfPredecessor(block); |
| 496 | 492 |
| 497 // Record the corresponding phi input use for each phi. | 493 // Record the corresponding phi input use for each phi. |
| 498 ZoneGrowableArray<PhiInstr*>* phis = join->phis(); | 494 ZoneGrowableArray<PhiInstr*>* phis = join->phis(); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 519 move->set_src(Location::PrefersRegister()); | 515 move->set_src(Location::PrefersRegister()); |
| 520 } else { | 516 } else { |
| 521 ASSERT(val->IsConstant()); | 517 ASSERT(val->IsConstant()); |
| 522 move->set_src(Location::Constant(val->AsConstant()->value())); | 518 move->set_src(Location::Constant(val->AsConstant()->value())); |
| 523 } | 519 } |
| 524 move_idx++; | 520 move_idx++; |
| 525 } | 521 } |
| 526 | 522 |
| 527 // Begin backward iteration with the instruction before the parallel | 523 // Begin backward iteration with the instruction before the parallel |
| 528 // move. | 524 // move. |
| 529 return parallel_move->previous(); | 525 return goto_instr->previous(); |
| 530 } | 526 } |
| 531 | 527 |
| 532 | 528 |
| 533 void FlowGraphAllocator::ConnectIncomingPhiMoves(BlockEntryInstr* block) { | 529 void FlowGraphAllocator::ConnectIncomingPhiMoves(BlockEntryInstr* block) { |
| 534 // If this block is a join we need to add destinations of phi | 530 // 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 | 531 // resolution moves to phi's live range so that register allocator will |
| 536 // fill them with moves. | 532 // fill them with moves. |
| 537 JoinEntryInstr* join = block->AsJoinEntry(); | 533 JoinEntryInstr* join = block->AsJoinEntry(); |
| 538 if (join == NULL) return; | 534 if (join == NULL) return; |
| 539 | 535 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 553 // Expected shape of live range: | 549 // Expected shape of live range: |
| 554 // | 550 // |
| 555 // B | 551 // B |
| 556 // phi [-------- | 552 // phi [-------- |
| 557 // | 553 // |
| 558 LiveRange* range = GetLiveRange(vreg); | 554 LiveRange* range = GetLiveRange(vreg); |
| 559 range->DefineAt(pos); // Shorten live range. | 555 range->DefineAt(pos); // Shorten live range. |
| 560 | 556 |
| 561 for (intptr_t pred_idx = 0; pred_idx < phi->InputCount(); pred_idx++) { | 557 for (intptr_t pred_idx = 0; pred_idx < phi->InputCount(); pred_idx++) { |
| 562 BlockEntryInstr* pred = block->PredecessorAt(pred_idx); | 558 BlockEntryInstr* pred = block->PredecessorAt(pred_idx); |
| 563 ASSERT(pred->last_instruction()->IsGoto()); | 559 GotoInstr* goto_instr = pred->last_instruction()->AsGoto(); |
| 564 Instruction* move_instr = pred->last_instruction()->previous(); | 560 ASSERT((goto_instr != NULL) && (goto_instr->HasParallelMove())); |
| 565 ASSERT(move_instr->IsParallelMove()); | |
| 566 | |
| 567 MoveOperands* move = | 561 MoveOperands* move = |
| 568 move_instr->AsParallelMove()->MoveOperandsAt(move_idx); | 562 goto_instr->parallel_move()->MoveOperandsAt(move_idx); |
| 569 move->set_dest(Location::PrefersRegister()); | 563 move->set_dest(Location::PrefersRegister()); |
| 570 range->AddUse(pos, move->dest_slot()); | 564 range->AddUse(pos, move->dest_slot()); |
| 571 } | 565 } |
| 572 | 566 |
| 573 // All phi resolution moves are connected. Phi's live range is | 567 // All phi resolution moves are connected. Phi's live range is |
| 574 // complete. | 568 // complete. |
| 575 AddToUnallocated(range); | 569 AddToUnallocated(range); |
| 576 | 570 |
| 577 move_idx++; | 571 move_idx++; |
| 578 } | 572 } |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 672 range->AddUseInterval(block->start_pos(), pos + 1); | 666 range->AddUseInterval(block->start_pos(), pos + 1); |
| 673 range->AddUse(pos + 1, in_ref); | 667 range->AddUse(pos + 1, in_ref); |
| 674 } | 668 } |
| 675 } | 669 } |
| 676 | 670 |
| 677 // Process temps. | 671 // Process temps. |
| 678 for (intptr_t j = 0; j < locs->temp_count(); j++) { | 672 for (intptr_t j = 0; j < locs->temp_count(); j++) { |
| 679 // Expected shape of live range: | 673 // Expected shape of live range: |
| 680 // | 674 // |
| 681 // i i' | 675 // i i' |
| 682 // [-----) | 676 // [--) |
| 683 // | 677 // |
| 684 | 678 |
| 685 Location temp = locs->temp(j); | 679 Location temp = locs->temp(j); |
| 686 if (temp.IsRegister()) { | 680 if (temp.IsRegister()) { |
| 687 BlockLocation(temp, pos); | 681 BlockLocation(temp, pos); |
| 688 } else if (temp.IsUnallocated()) { | 682 } else if (temp.IsUnallocated()) { |
| 689 LiveRange* range = new LiveRange(kTempVirtualRegister); | 683 LiveRange* range = new LiveRange(kTempVirtualRegister); |
| 690 range->AddUseInterval(pos, pos + 1); | 684 range->AddUseInterval(pos, pos + 1); |
| 691 range->AddUse(pos, locs->temp_slot(j)); | 685 range->AddUse(pos, locs->temp_slot(j)); |
| 692 AddToUnallocated(range); | 686 AddToUnallocated(range); |
| 693 } else { | 687 } else { |
| 694 UNREACHABLE(); | 688 UNREACHABLE(); |
| 695 } | 689 } |
| 696 } | 690 } |
| 697 | 691 |
| 698 // Block all allocatable registers for calls. | 692 // Block all allocatable registers for calls. |
| 699 if (locs->is_call()) { | 693 if (locs->is_call()) { |
| 700 // Expected shape of live range: | 694 // Expected shape of live range: |
| 701 // | 695 // |
| 702 // i i' | 696 // i i' |
| 703 // [-----) | 697 // [--) |
| 704 // | 698 // |
| 705 | 699 |
| 706 for (intptr_t reg = 0; reg < kNumberOfCpuRegisters; reg++) { | 700 for (intptr_t reg = 0; reg < kNumberOfCpuRegisters; reg++) { |
| 707 BlockLocation(Location::RegisterLocation(static_cast<Register>(reg)), | 701 BlockLocation(Location::RegisterLocation(static_cast<Register>(reg)), |
| 708 pos); | 702 pos); |
| 709 } | 703 } |
| 710 | 704 |
| 711 #ifdef DEBUG | 705 #ifdef DEBUG |
| 712 // Verify that temps, inputs and output were specified as fixed | 706 // Verify that temps, inputs and output were specified as fixed |
| 713 // locations. Every register is blocked now so attempt to | 707 // locations. Every register is blocked now so attempt to |
| (...skipping 26 matching lines...) Expand all Loading... |
| 740 LiveRange* range = (def->ssa_temp_index() >= 0) ? | 734 LiveRange* range = (def->ssa_temp_index() >= 0) ? |
| 741 GetLiveRange(def->ssa_temp_index()) : | 735 GetLiveRange(def->ssa_temp_index()) : |
| 742 new LiveRange(kTempVirtualRegister); | 736 new LiveRange(kTempVirtualRegister); |
| 743 Location* out = locs->out_slot(); | 737 Location* out = locs->out_slot(); |
| 744 | 738 |
| 745 // Process output and finalize its liverange. | 739 // Process output and finalize its liverange. |
| 746 if (out->IsRegister()) { | 740 if (out->IsRegister()) { |
| 747 // Fixed output location. Expected shape of live range: | 741 // Fixed output location. Expected shape of live range: |
| 748 // | 742 // |
| 749 // i i' j j' | 743 // i i' j j' |
| 750 // register [-----) | 744 // register [--) |
| 751 // output [------- | 745 // output [------- |
| 752 // | 746 // |
| 753 BlockLocation(*out, pos); | 747 BlockLocation(*out, pos); |
| 754 | 748 |
| 755 if (range->vreg() == kTempVirtualRegister) return; | 749 if (range->vreg() == kTempVirtualRegister) return; |
| 756 | 750 |
| 757 // We need to emit move connecting fixed register with another location | 751 // We need to emit move connecting fixed register with another location |
| 758 // that will be allocated for this output's live range. | 752 // that will be allocated for this output's live range. |
| 759 // Special case: fixed output followed by a fixed input last use. | 753 // Special case: fixed output followed by a fixed input last use. |
| 760 UsePosition* use = range->first_use(); | 754 UsePosition* use = range->first_use(); |
| 761 if (use->pos() == (pos + 2)) { | 755 if (use->pos() == (pos + 1)) { |
| 762 ASSERT(use->location_slot()->IsUnallocated()); | 756 ASSERT(use->location_slot()->IsUnallocated()); |
| 763 *(use->location_slot()) = *out; | 757 *(use->location_slot()) = *out; |
| 764 | 758 |
| 765 // Remove first use. It was allocated. | 759 // Remove first use. It was allocated. |
| 766 range->set_first_use(range->first_use()->next()); | 760 range->set_first_use(range->first_use()->next()); |
| 767 } | 761 } |
| 768 | 762 |
| 769 // Shorten live range to the point of definition, this might make the range | 763 // 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 | 764 // empty (if the only use immediately follows). If range is not empty add |
| 771 // move from a fixed register to an unallocated location. | 765 // move from a fixed register to an unallocated location. |
| 772 range->DefineAt(pos + 2); | 766 range->DefineAt(pos + 1); |
| 773 if (range->Start() == range->End()) return; | 767 if (range->Start() == range->End()) return; |
| 774 | 768 |
| 775 MoveOperands* move = AddMoveAt(pos + 2, Location::PrefersRegister(), *out); | 769 MoveOperands* move = AddMoveAt(pos + 1, Location::PrefersRegister(), *out); |
| 776 range->AddUse(pos + 2, move->dest_slot()); | 770 range->AddUse(pos + 1, move->dest_slot()); |
| 777 } else if (output_same_as_first_input) { | 771 } else if (output_same_as_first_input) { |
| 778 // Output register will contain a value of the first input at instruction's | 772 // Output register will contain a value of the first input at instruction's |
| 779 // start. Expected shape of live ranges: | 773 // start. Expected shape of live ranges: |
| 780 // | 774 // |
| 781 // i i' | 775 // i i' |
| 782 // input #0 --* | 776 // input #0 --* |
| 783 // output [---- | 777 // output [---- |
| 784 // | 778 // |
| 785 ASSERT(locs->in_slot(0)->Equals(Location::RequiresRegister())); | 779 ASSERT(locs->in_slot(0)->Equals(Location::RequiresRegister())); |
| 786 | 780 |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 891 JoinEntryInstr* join = block->AsJoinEntry(); | 885 JoinEntryInstr* join = block->AsJoinEntry(); |
| 892 if ((join != NULL) && (join->phi_count() > 0)) { | 886 if ((join != NULL) && (join->phi_count() > 0)) { |
| 893 const intptr_t phi_count = join->phi_count(); | 887 const intptr_t phi_count = join->phi_count(); |
| 894 for (intptr_t i = 0; i < block->PredecessorCount(); i++) { | 888 for (intptr_t i = 0; i < block->PredecessorCount(); i++) { |
| 895 // Insert the move between the last two instructions of the | 889 // Insert the move between the last two instructions of the |
| 896 // predecessor block (all such blocks have at least two instructions: | 890 // predecessor block (all such blocks have at least two instructions: |
| 897 // the block entry and goto instructions.) | 891 // the block entry and goto instructions.) |
| 898 Instruction* last = block->PredecessorAt(i)->last_instruction(); | 892 Instruction* last = block->PredecessorAt(i)->last_instruction(); |
| 899 ASSERT(last->IsGoto()); | 893 ASSERT(last->IsGoto()); |
| 900 | 894 |
| 901 ParallelMoveInstr* move = | 895 ParallelMoveInstr* move = last->AsGoto()->GetParallelMove(); |
| 902 CreateParallelMoveBefore(last, last->lifetime_position()); | |
| 903 | 896 |
| 904 // Populate the ParallelMove with empty moves. | 897 // Populate the ParallelMove with empty moves. |
| 905 for (intptr_t j = 0; j < phi_count; j++) { | 898 for (intptr_t j = 0; j < phi_count; j++) { |
| 906 move->AddMove(Location::NoLocation(), Location::NoLocation()); | 899 move->AddMove(Location::NoLocation(), Location::NoLocation()); |
| 907 } | 900 } |
| 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 } | 901 } |
| 922 } | 902 } |
| 923 } | 903 } |
| 924 } | 904 } |
| 925 | 905 |
| 926 | 906 |
| 927 Instruction* FlowGraphAllocator::InstructionAt(intptr_t pos) const { | 907 Instruction* FlowGraphAllocator::InstructionAt(intptr_t pos) const { |
| 928 return instructions_[pos / 2]; | 908 return instructions_[pos / 2]; |
| 929 } | 909 } |
| 930 | 910 |
| 931 | 911 |
| 932 bool FlowGraphAllocator::IsBlockEntry(intptr_t pos) const { | 912 bool FlowGraphAllocator::IsBlockEntry(intptr_t pos) const { |
| 933 return InstructionAt(pos)->IsBlockEntry(); | 913 return IsInstructionStartPosition(pos) && InstructionAt(pos)->IsBlockEntry(); |
| 934 } | 914 } |
| 935 | 915 |
| 936 | 916 |
| 937 void AllocationFinger::Initialize(LiveRange* range) { | 917 void AllocationFinger::Initialize(LiveRange* range) { |
| 938 first_pending_use_interval_ = range->first_use_interval(); | 918 first_pending_use_interval_ = range->first_use_interval(); |
| 939 first_register_use_ = range->first_use(); | 919 first_register_use_ = range->first_use(); |
| 940 first_register_beneficial_use_ = range->first_use(); | 920 first_register_beneficial_use_ = range->first_use(); |
| 941 first_hinted_use_ = range->first_use(); | 921 first_hinted_use_ = range->first_use(); |
| 942 } | 922 } |
| 943 | 923 |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1035 UNREACHABLE(); | 1015 UNREACHABLE(); |
| 1036 return NULL; | 1016 return NULL; |
| 1037 } | 1017 } |
| 1038 | 1018 |
| 1039 | 1019 |
| 1040 LiveRange* LiveRange::SplitAt(intptr_t split_pos) { | 1020 LiveRange* LiveRange::SplitAt(intptr_t split_pos) { |
| 1041 if (Start() == split_pos) return this; | 1021 if (Start() == split_pos) return this; |
| 1042 | 1022 |
| 1043 UseInterval* interval = finger_.first_pending_use_interval(); | 1023 UseInterval* interval = finger_.first_pending_use_interval(); |
| 1044 ASSERT(interval->start() < split_pos); | 1024 ASSERT(interval->start() < split_pos); |
| 1025 ASSERT(split_pos < End()); |
| 1045 | 1026 |
| 1046 // Corner case. We need to start over to find previous interval. | 1027 // Corner case. We need to start over to find previous interval. |
| 1047 if (interval->start() == split_pos) interval = first_use_interval_; | 1028 if (interval->start() == split_pos) interval = first_use_interval_; |
| 1048 | 1029 |
| 1049 UseInterval* last_before_split = NULL; | 1030 UseInterval* last_before_split = NULL; |
| 1050 while (interval->end() <= split_pos) { | 1031 while (interval->end() <= split_pos) { |
| 1051 last_before_split = interval; | 1032 last_before_split = interval; |
| 1052 interval = interval->next(); | 1033 interval = interval->next(); |
| 1053 } | 1034 } |
| 1054 | 1035 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1093 first_after_split : last_use_interval_; | 1074 first_after_split : last_use_interval_; |
| 1094 next_sibling_ = new LiveRange(vreg(), | 1075 next_sibling_ = new LiveRange(vreg(), |
| 1095 first_use_after_split, | 1076 first_use_after_split, |
| 1096 first_after_split, | 1077 first_after_split, |
| 1097 last_use_interval, | 1078 last_use_interval, |
| 1098 next_sibling_); | 1079 next_sibling_); |
| 1099 | 1080 |
| 1100 TRACE_ALLOC((" split sibling [%d, %d)\n", | 1081 TRACE_ALLOC((" split sibling [%d, %d)\n", |
| 1101 next_sibling_->Start(), next_sibling_->End())); | 1082 next_sibling_->Start(), next_sibling_->End())); |
| 1102 | 1083 |
| 1103 // Split sibling can only start at a parallel move. | |
| 1104 ASSERT(IsParallelMovePosition(next_sibling_->Start())); | |
| 1105 | |
| 1106 last_use_interval_ = last_before_split; | 1084 last_use_interval_ = last_before_split; |
| 1107 last_use_interval_->next_ = NULL; | 1085 last_use_interval_->next_ = NULL; |
| 1108 return next_sibling_; | 1086 return next_sibling_; |
| 1109 } | 1087 } |
| 1110 | 1088 |
| 1111 | 1089 |
| 1112 LiveRange* FlowGraphAllocator::SplitBetween(LiveRange* range, | 1090 LiveRange* FlowGraphAllocator::SplitBetween(LiveRange* range, |
| 1113 intptr_t from, | 1091 intptr_t from, |
| 1114 intptr_t to) { | 1092 intptr_t to) { |
| 1115 // TODO(vegorov): select optimal split position based on loop structure. | 1093 // TODO(vegorov): select optimal split position based on loop structure. |
| 1116 TRACE_ALLOC(("split %d [%d, %d) between [%d, %d)\n", | 1094 TRACE_ALLOC(("split %d [%d, %d) between [%d, %d)\n", |
| 1117 range->vreg(), range->Start(), range->End(), from, to)); | 1095 range->vreg(), range->Start(), range->End(), from, to)); |
| 1118 | 1096 |
| 1119 // Prefer spliting at instruction starts if possible. | 1097 // Prefer spliting at instruction starts if possible. |
| 1120 if (from < ToInstructionStart(to)) { | 1098 if (from < ToInstructionStart(to)) { |
| 1121 to = ToInstructionStart(to); | 1099 to = ToInstructionStart(to); |
| 1122 } | 1100 } |
| 1123 | 1101 |
| 1102 // Splitting at the end is not allowed as it produces an empty |
| 1103 // live range. |
| 1104 if (to == range->End()) to -= 1; |
| 1105 ASSERT(from <= to); |
| 1106 |
| 1124 return range->SplitAt(to); | 1107 return range->SplitAt(to); |
| 1125 } | 1108 } |
| 1126 | 1109 |
| 1127 | 1110 |
| 1128 void FlowGraphAllocator::SpillBetween(LiveRange* range, | 1111 void FlowGraphAllocator::SpillBetween(LiveRange* range, |
| 1129 intptr_t from, | 1112 intptr_t from, |
| 1130 intptr_t to) { | 1113 intptr_t to) { |
| 1131 ASSERT(from < to); | 1114 ASSERT(from < to); |
| 1132 TRACE_ALLOC(("spill %d [%d, %d) between [%d, %d)\n", | 1115 TRACE_ALLOC(("spill %d [%d, %d) between [%d, %d)\n", |
| 1133 range->vreg(), range->Start(), range->End(), from, to)); | 1116 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); | 1399 SpillBetween(allocated, spill_position, restore_position); |
| 1417 } | 1400 } |
| 1418 | 1401 |
| 1419 return true; | 1402 return true; |
| 1420 } | 1403 } |
| 1421 | 1404 |
| 1422 | 1405 |
| 1423 MoveOperands* FlowGraphAllocator::AddMoveAt(intptr_t pos, | 1406 MoveOperands* FlowGraphAllocator::AddMoveAt(intptr_t pos, |
| 1424 Location to, | 1407 Location to, |
| 1425 Location from) { | 1408 Location from) { |
| 1409 ASSERT(!IsBlockEntry(pos)); |
| 1410 |
| 1426 Instruction* instr = InstructionAt(pos); | 1411 Instruction* instr = InstructionAt(pos); |
| 1427 ASSERT(!instr->IsBlockEntry()); | |
| 1428 | 1412 |
| 1429 ParallelMoveInstr* parallel_move = NULL; | 1413 ParallelMoveInstr* parallel_move = NULL; |
| 1430 if (IsInstructionStartPosition(pos)) { | 1414 if (IsInstructionStartPosition(pos)) { |
| 1431 parallel_move = CreateParallelMoveBefore(instr, pos); | 1415 parallel_move = CreateParallelMoveBefore(instr, pos); |
| 1432 } else { | 1416 } else { |
| 1433 parallel_move = CreateParallelMoveAfter(instr, pos); | 1417 parallel_move = CreateParallelMoveAfter(instr, pos); |
| 1434 } | 1418 } |
| 1435 | 1419 |
| 1436 return parallel_move->AddMove(to, from); | 1420 return parallel_move->AddMove(to, from); |
| 1437 } | 1421 } |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1603 | 1587 |
| 1604 TRACE_ALLOC(("connecting [%d, %d) [%s] to [%d, %d) [%s]\n", | 1588 TRACE_ALLOC(("connecting [%d, %d) [%s] to [%d, %d) [%s]\n", |
| 1605 source_cover->Start(), source_cover->End(), source.Name(), | 1589 source_cover->Start(), source_cover->End(), source.Name(), |
| 1606 target_cover->Start(), target_cover->End(), target.Name())); | 1590 target_cover->Start(), target_cover->End(), target.Name())); |
| 1607 | 1591 |
| 1608 // Siblings were allocated to the same register. | 1592 // Siblings were allocated to the same register. |
| 1609 if (source.Equals(target)) return; | 1593 if (source.Equals(target)) return; |
| 1610 | 1594 |
| 1611 Instruction* last = source_block->last_instruction(); | 1595 Instruction* last = source_block->last_instruction(); |
| 1612 if (last->SuccessorCount() == 1) { | 1596 if (last->SuccessorCount() == 1) { |
| 1613 CreateParallelMoveBefore(last, last->lifetime_position())-> | 1597 ASSERT(last->IsGoto()); |
| 1614 AddMove(target, source); | 1598 last->AsGoto()->GetParallelMove()->AddMove(target, source); |
| 1615 } else { | 1599 } else { |
| 1616 CreateParallelMoveAfter(target_block, target_block->start_pos())-> | 1600 target_block->GetParallelMove()->AddMove(target, source); |
| 1617 AddMove(target, source); | |
| 1618 } | 1601 } |
| 1619 } | 1602 } |
| 1620 | 1603 |
| 1621 | 1604 |
| 1622 void FlowGraphAllocator::ResolveControlFlow() { | 1605 void FlowGraphAllocator::ResolveControlFlow() { |
| 1623 // Resolve linear control flow between touching split siblings | 1606 // Resolve linear control flow between touching split siblings |
| 1624 // inside basic blocks. | 1607 // inside basic blocks. |
| 1625 for (intptr_t vreg = 0; vreg < live_ranges_.length(); vreg++) { | 1608 for (intptr_t vreg = 0; vreg < live_ranges_.length(); vreg++) { |
| 1626 LiveRange* range = live_ranges_[vreg]; | 1609 LiveRange* range = live_ranges_[vreg]; |
| 1627 if (range == NULL) continue; | 1610 if (range == NULL) continue; |
| 1628 | 1611 |
| 1629 while (range->next_sibling() != NULL) { | 1612 while (range->next_sibling() != NULL) { |
| 1630 LiveRange* sibling = range->next_sibling(); | 1613 LiveRange* sibling = range->next_sibling(); |
| 1614 TRACE_ALLOC(("connecting [%d, %d) [%s] to [%d, %d) [%s]\n", |
| 1615 range->Start(), range->End(), |
| 1616 range->assigned_location().Name(), |
| 1617 sibling->Start(), sibling->End(), |
| 1618 sibling->assigned_location().Name())); |
| 1631 if ((range->End() == sibling->Start()) && | 1619 if ((range->End() == sibling->Start()) && |
| 1632 !range->assigned_location().Equals(sibling->assigned_location()) && | 1620 !range->assigned_location().Equals(sibling->assigned_location()) && |
| 1633 !IsBlockEntry(range->End())) { | 1621 !IsBlockEntry(range->End())) { |
| 1634 AddMoveAt(sibling->Start(), | 1622 AddMoveAt(sibling->Start(), |
| 1635 sibling->assigned_location(), | 1623 sibling->assigned_location(), |
| 1636 range->assigned_location()); | 1624 range->assigned_location()); |
| 1637 } | 1625 } |
| 1638 range = sibling; | 1626 range = sibling; |
| 1639 } | 1627 } |
| 1640 } | 1628 } |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1676 | 1664 |
| 1677 if (FLAG_trace_ssa_allocator) { | 1665 if (FLAG_trace_ssa_allocator) { |
| 1678 OS::Print("-- ir after allocation -------------------------\n"); | 1666 OS::Print("-- ir after allocation -------------------------\n"); |
| 1679 FlowGraphPrinter printer(Function::Handle(), block_order_, true); | 1667 FlowGraphPrinter printer(Function::Handle(), block_order_, true); |
| 1680 printer.PrintBlocks(); | 1668 printer.PrintBlocks(); |
| 1681 } | 1669 } |
| 1682 } | 1670 } |
| 1683 | 1671 |
| 1684 | 1672 |
| 1685 } // namespace dart | 1673 } // namespace dart |
| OLD | NEW |