| 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 333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 344 LiveRange* FlowGraphAllocator::MakeLiveRangeForTemporary() { | 344 LiveRange* FlowGraphAllocator::MakeLiveRangeForTemporary() { |
| 345 LiveRange* range = new LiveRange(kTempVirtualRegister); | 345 LiveRange* range = new LiveRange(kTempVirtualRegister); |
| 346 #if defined(DEBUG) | 346 #if defined(DEBUG) |
| 347 temporaries_.Add(range); | 347 temporaries_.Add(range); |
| 348 #endif | 348 #endif |
| 349 return range; | 349 return range; |
| 350 } | 350 } |
| 351 | 351 |
| 352 | 352 |
| 353 // Block location from the start of the instruction to its end. | 353 // Block location from the start of the instruction to its end. |
| 354 void FlowGraphAllocator::BlockLocation(Location loc, intptr_t pos) { | 354 void FlowGraphAllocator::BlockLocation(Location loc, |
| 355 intptr_t from, |
| 356 intptr_t to) { |
| 355 ASSERT(loc.IsRegister()); | 357 ASSERT(loc.IsRegister()); |
| 356 ASSERT(IsInstructionStartPosition(pos)); | |
| 357 const Register reg = loc.reg(); | 358 const Register reg = loc.reg(); |
| 358 if (blocked_cpu_regs_[reg]) return; | 359 if (blocked_cpu_regs_[reg]) return; |
| 359 if (cpu_regs_[reg].length() == 0) { | 360 if (cpu_regs_[reg].length() == 0) { |
| 360 LiveRange* range = new LiveRange(kNoVirtualRegister); | 361 LiveRange* range = new LiveRange(kNoVirtualRegister); |
| 361 cpu_regs_[reg].Add(range); | 362 cpu_regs_[reg].Add(range); |
| 362 range->set_assigned_location(loc); | 363 range->set_assigned_location(loc); |
| 363 #if defined(DEBUG) | 364 #if defined(DEBUG) |
| 364 temporaries_.Add(range); | 365 temporaries_.Add(range); |
| 365 #endif | 366 #endif |
| 366 } | 367 } |
| 367 cpu_regs_[reg][0]->AddUseInterval(pos, pos + 1); | 368 cpu_regs_[reg][0]->AddUseInterval(from, to); |
| 368 } | 369 } |
| 369 | 370 |
| 370 | 371 |
| 371 void LiveRange::Print() { | 372 void LiveRange::Print() { |
| 372 if (first_use_interval() == NULL) { | 373 if (first_use_interval() == NULL) { |
| 373 return; | 374 return; |
| 374 } | 375 } |
| 375 | 376 |
| 376 OS::Print(" live range v%d [%d, %d) in ", vreg(), Start(), End()); | 377 OS::Print(" live range v%d [%d, %d) in ", vreg(), Start(), End()); |
| 377 assigned_location().Print(); | 378 assigned_location().Print(); |
| (...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 676 ASSERT(input->IsUse()); // Can not be a constant currently. | 677 ASSERT(input->IsUse()); // Can not be a constant currently. |
| 677 const intptr_t vreg = input->AsUse()->definition()->ssa_temp_index(); | 678 const intptr_t vreg = input->AsUse()->definition()->ssa_temp_index(); |
| 678 LiveRange* range = GetLiveRange(vreg); | 679 LiveRange* range = GetLiveRange(vreg); |
| 679 | 680 |
| 680 Location* in_ref = locs->in_slot(j); | 681 Location* in_ref = locs->in_slot(j); |
| 681 | 682 |
| 682 if (in_ref->IsRegister()) { | 683 if (in_ref->IsRegister()) { |
| 683 // Input is expected in a fixed register. Expected shape of | 684 // Input is expected in a fixed register. Expected shape of |
| 684 // live ranges: | 685 // live ranges: |
| 685 // | 686 // |
| 686 // i i' | 687 // j' i i' |
| 687 // value --* | 688 // value --* |
| 688 // register [--) | 689 // register [-----) |
| 689 // | 690 // |
| 690 MoveOperands* move = | 691 MoveOperands* move = |
| 691 AddMoveAt(pos, *in_ref, Location::PrefersRegister()); | 692 AddMoveAt(pos - 1, *in_ref, Location::PrefersRegister()); |
| 692 BlockLocation(*in_ref, pos); | 693 BlockLocation(*in_ref, pos - 1, pos + 1); |
| 693 range->AddUseInterval(block->start_pos(), pos); | 694 range->AddUseInterval(block->start_pos(), pos - 1); |
| 694 range->AddUse(pos, move->src_slot()); | 695 range->AddUse(pos - 1, move->src_slot()); |
| 695 } else { | 696 } else { |
| 696 // Normal unallocated input. Expected shape of | 697 // Normal unallocated input. Expected shape of |
| 697 // live ranges: | 698 // live ranges: |
| 698 // | 699 // |
| 699 // i i' | 700 // i i' |
| 700 // value -----* | 701 // value -----* |
| 701 // | 702 // |
| 702 ASSERT(in_ref->IsUnallocated()); | 703 ASSERT(in_ref->IsUnallocated()); |
| 703 range->AddUseInterval(block->start_pos(), pos + 1); | 704 range->AddUseInterval(block->start_pos(), pos + 1); |
| 704 range->AddUse(pos + 1, in_ref); | 705 range->AddUse(pos + 1, in_ref); |
| 705 } | 706 } |
| 706 } | 707 } |
| 707 | 708 |
| 708 // Process temps. | 709 // Process temps. |
| 709 for (intptr_t j = 0; j < locs->temp_count(); j++) { | 710 for (intptr_t j = 0; j < locs->temp_count(); j++) { |
| 710 // Expected shape of live range: | 711 // Expected shape of live range: |
| 711 // | 712 // |
| 712 // i i' | 713 // i i' |
| 713 // [--) | 714 // [--) |
| 714 // | 715 // |
| 715 | 716 |
| 716 Location temp = locs->temp(j); | 717 Location temp = locs->temp(j); |
| 717 if (temp.IsRegister()) { | 718 if (temp.IsRegister()) { |
| 718 BlockLocation(temp, pos); | 719 BlockLocation(temp, pos, pos + 1); |
| 719 } else if (temp.IsUnallocated()) { | 720 } else if (temp.IsUnallocated()) { |
| 720 LiveRange* range = MakeLiveRangeForTemporary(); | 721 LiveRange* range = MakeLiveRangeForTemporary(); |
| 721 range->AddUseInterval(pos, pos + 1); | 722 range->AddUseInterval(pos, pos + 1); |
| 722 range->AddUse(pos, locs->temp_slot(j)); | 723 range->AddUse(pos, locs->temp_slot(j)); |
| 723 AddToUnallocated(range); | 724 AddToUnallocated(range); |
| 724 } else { | 725 } else { |
| 725 UNREACHABLE(); | 726 UNREACHABLE(); |
| 726 } | 727 } |
| 727 } | 728 } |
| 728 | 729 |
| 729 // Block all allocatable registers for calls. | 730 // Block all allocatable registers for calls. |
| 730 if (locs->is_call()) { | 731 if (locs->is_call()) { |
| 731 // Expected shape of live range: | 732 // Expected shape of live range: |
| 732 // | 733 // |
| 733 // i i' | 734 // i i' |
| 734 // [--) | 735 // [--) |
| 735 // | 736 // |
| 736 | 737 |
| 737 for (intptr_t reg = 0; reg < kNumberOfCpuRegisters; reg++) { | 738 for (intptr_t reg = 0; reg < kNumberOfCpuRegisters; reg++) { |
| 738 BlockLocation(Location::RegisterLocation(static_cast<Register>(reg)), | 739 BlockLocation(Location::RegisterLocation(static_cast<Register>(reg)), |
| 739 pos); | 740 pos, |
| 741 pos + 1); |
| 740 } | 742 } |
| 741 | 743 |
| 742 #if defined(DEBUG) | 744 #if defined(DEBUG) |
| 743 // Verify that temps, inputs and output were specified as fixed | 745 // Verify that temps, inputs and output were specified as fixed |
| 744 // locations. Every register is blocked now so attempt to | 746 // locations. Every register is blocked now so attempt to |
| 745 // allocate will not succeed. | 747 // allocate will not succeed. |
| 746 for (intptr_t j = 0; j < locs->temp_count(); j++) { | 748 for (intptr_t j = 0; j < locs->temp_count(); j++) { |
| 747 ASSERT(!locs->temp(j).IsUnallocated()); | 749 ASSERT(!locs->temp(j).IsUnallocated()); |
| 748 } | 750 } |
| 749 | 751 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 774 Location* out = locs->out_slot(); | 776 Location* out = locs->out_slot(); |
| 775 | 777 |
| 776 // Process output and finalize its liverange. | 778 // Process output and finalize its liverange. |
| 777 if (out->IsRegister()) { | 779 if (out->IsRegister()) { |
| 778 // Fixed output location. Expected shape of live range: | 780 // Fixed output location. Expected shape of live range: |
| 779 // | 781 // |
| 780 // i i' j j' | 782 // i i' j j' |
| 781 // register [--) | 783 // register [--) |
| 782 // output [------- | 784 // output [------- |
| 783 // | 785 // |
| 784 BlockLocation(*out, pos); | 786 BlockLocation(*out, pos, pos + 1); |
| 785 | 787 |
| 786 if (range->vreg() == kTempVirtualRegister) return; | 788 if (range->vreg() == kTempVirtualRegister) return; |
| 787 | 789 |
| 788 // We need to emit move connecting fixed register with another location | 790 // We need to emit move connecting fixed register with another location |
| 789 // that will be allocated for this output's live range. | 791 // that will be allocated for this output's live range. |
| 790 // Special case: fixed output followed by a fixed input last use. | 792 // Special case: fixed output followed by a fixed input last use. |
| 791 UsePosition* use = range->first_use(); | 793 UsePosition* use = range->first_use(); |
| 792 | 794 |
| 793 // If the value has no uses we don't need to allocate it. | 795 // If the value has no uses we don't need to allocate it. |
| 794 if (use == NULL) return; | 796 if (use == NULL) return; |
| (...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1070 (loc->IsRegister() || | 1072 (loc->IsRegister() || |
| 1071 (loc->IsUnallocated() && loc->IsRegisterBeneficial()))) { | 1073 (loc->IsUnallocated() && loc->IsRegisterBeneficial()))) { |
| 1072 first_register_beneficial_use_ = use; | 1074 first_register_beneficial_use_ = use; |
| 1073 return use; | 1075 return use; |
| 1074 } | 1076 } |
| 1075 } | 1077 } |
| 1076 return NULL; | 1078 return NULL; |
| 1077 } | 1079 } |
| 1078 | 1080 |
| 1079 | 1081 |
| 1082 void AllocationFinger::UpdateAfterSplit(intptr_t first_use_after_split_pos) { |
| 1083 if ((first_register_use_ != NULL) && |
| 1084 (first_register_use_->pos() >= first_use_after_split_pos)) { |
| 1085 first_register_use_ = NULL; |
| 1086 } |
| 1087 |
| 1088 if ((first_register_beneficial_use_ != NULL) && |
| 1089 (first_register_beneficial_use_->pos() >= first_use_after_split_pos)) { |
| 1090 first_register_beneficial_use_ = NULL; |
| 1091 } |
| 1092 } |
| 1093 |
| 1094 |
| 1080 intptr_t UseInterval::Intersect(UseInterval* other) { | 1095 intptr_t UseInterval::Intersect(UseInterval* other) { |
| 1081 if (this->start() <= other->start()) { | 1096 if (this->start() <= other->start()) { |
| 1082 if (other->start() < this->end()) return other->start(); | 1097 if (other->start() < this->end()) return other->start(); |
| 1083 } else if (this->start() < other->end()) { | 1098 } else if (this->start() < other->end()) { |
| 1084 return this->start(); | 1099 return this->start(); |
| 1085 } | 1100 } |
| 1086 return kIllegalPosition; | 1101 return kIllegalPosition; |
| 1087 } | 1102 } |
| 1088 | 1103 |
| 1089 | 1104 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1111 | 1126 |
| 1112 LiveRange* LiveRange::SplitAt(intptr_t split_pos) { | 1127 LiveRange* LiveRange::SplitAt(intptr_t split_pos) { |
| 1113 if (Start() == split_pos) return this; | 1128 if (Start() == split_pos) return this; |
| 1114 | 1129 |
| 1115 UseInterval* interval = finger_.first_pending_use_interval(); | 1130 UseInterval* interval = finger_.first_pending_use_interval(); |
| 1116 if (interval == NULL) { | 1131 if (interval == NULL) { |
| 1117 finger_.Initialize(this); | 1132 finger_.Initialize(this); |
| 1118 interval = finger_.first_pending_use_interval(); | 1133 interval = finger_.first_pending_use_interval(); |
| 1119 } | 1134 } |
| 1120 | 1135 |
| 1121 ASSERT(interval->start() < split_pos); | |
| 1122 ASSERT(split_pos < End()); | 1136 ASSERT(split_pos < End()); |
| 1123 | 1137 |
| 1124 // Corner case. We need to start over to find previous interval. | 1138 // Corner case. We need to start over to find previous interval. |
| 1125 if (interval->start() == split_pos) interval = first_use_interval_; | 1139 if (interval->start() == split_pos) interval = first_use_interval_; |
| 1126 | 1140 |
| 1127 UseInterval* last_before_split = NULL; | 1141 UseInterval* last_before_split = NULL; |
| 1128 while (interval->end() <= split_pos) { | 1142 while (interval->end() <= split_pos) { |
| 1129 last_before_split = interval; | 1143 last_before_split = interval; |
| 1130 interval = interval->next(); | 1144 interval = interval->next(); |
| 1131 } | 1145 } |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1173 first_use_after_split, | 1187 first_use_after_split, |
| 1174 first_after_split, | 1188 first_after_split, |
| 1175 last_use_interval, | 1189 last_use_interval, |
| 1176 next_sibling_); | 1190 next_sibling_); |
| 1177 | 1191 |
| 1178 TRACE_ALLOC((" split sibling [%d, %d)\n", | 1192 TRACE_ALLOC((" split sibling [%d, %d)\n", |
| 1179 next_sibling_->Start(), next_sibling_->End())); | 1193 next_sibling_->Start(), next_sibling_->End())); |
| 1180 | 1194 |
| 1181 last_use_interval_ = last_before_split; | 1195 last_use_interval_ = last_before_split; |
| 1182 last_use_interval_->next_ = NULL; | 1196 last_use_interval_->next_ = NULL; |
| 1197 |
| 1198 if (first_use_after_split != NULL) { |
| 1199 finger_.UpdateAfterSplit(first_use_after_split->pos()); |
| 1200 } |
| 1201 |
| 1183 return next_sibling_; | 1202 return next_sibling_; |
| 1184 } | 1203 } |
| 1185 | 1204 |
| 1186 | 1205 |
| 1187 LiveRange* FlowGraphAllocator::SplitBetween(LiveRange* range, | 1206 LiveRange* FlowGraphAllocator::SplitBetween(LiveRange* range, |
| 1188 intptr_t from, | 1207 intptr_t from, |
| 1189 intptr_t to) { | 1208 intptr_t to) { |
| 1190 TRACE_ALLOC(("split %d [%d, %d) between [%d, %d)\n", | 1209 TRACE_ALLOC(("split %d [%d, %d) between [%d, %d)\n", |
| 1191 range->vreg(), range->Start(), range->End(), from, to)); | 1210 range->vreg(), range->Start(), range->End(), from, to)); |
| 1192 | 1211 |
| (...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1422 intptr_t blocked_at = kMaxPosition; | 1441 intptr_t blocked_at = kMaxPosition; |
| 1423 const intptr_t start = unallocated->Start(); | 1442 const intptr_t start = unallocated->Start(); |
| 1424 | 1443 |
| 1425 for (intptr_t i = 0; i < cpu_regs_[reg].length(); i++) { | 1444 for (intptr_t i = 0; i < cpu_regs_[reg].length(); i++) { |
| 1426 LiveRange* allocated = cpu_regs_[reg][i]; | 1445 LiveRange* allocated = cpu_regs_[reg][i]; |
| 1427 | 1446 |
| 1428 UseInterval* first_pending_use_interval = | 1447 UseInterval* first_pending_use_interval = |
| 1429 allocated->finger()->first_pending_use_interval(); | 1448 allocated->finger()->first_pending_use_interval(); |
| 1430 if (first_pending_use_interval->Contains(start)) { | 1449 if (first_pending_use_interval->Contains(start)) { |
| 1431 // This is an active interval. | 1450 // This is an active interval. |
| 1432 if (allocated->vreg() <= 0) { | 1451 if (allocated->vreg() < 0) { |
| 1433 // This register blocked by an interval that | 1452 // This register blocked by an interval that |
| 1434 // can't be spilled. | 1453 // can't be spilled. |
| 1435 return false; | 1454 return false; |
| 1436 } | 1455 } |
| 1437 | 1456 |
| 1438 const UsePosition* use = | 1457 const UsePosition* use = |
| 1439 allocated->finger()->FirstRegisterBeneficialUse(unallocated->Start()); | 1458 allocated->finger()->FirstRegisterBeneficialUse(unallocated->Start()); |
| 1440 | 1459 |
| 1441 if ((use != NULL) && ((use->pos() - start) <= 1)) { | 1460 if ((use != NULL) && ((use->pos() - start) <= 1)) { |
| 1442 // This register is blocked by interval that is used | 1461 // This register is blocked by interval that is used |
| (...skipping 358 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1801 NumberInstructions(); | 1820 NumberInstructions(); |
| 1802 | 1821 |
| 1803 DiscoverLoops(); | 1822 DiscoverLoops(); |
| 1804 | 1823 |
| 1805 BuildLiveRanges(); | 1824 BuildLiveRanges(); |
| 1806 | 1825 |
| 1807 if (FLAG_print_ssa_liveness) { | 1826 if (FLAG_print_ssa_liveness) { |
| 1808 DumpLiveness(); | 1827 DumpLiveness(); |
| 1809 } | 1828 } |
| 1810 | 1829 |
| 1830 if (FLAG_print_ssa_liveranges) { |
| 1831 const Function& function = builder_->parsed_function().function(); |
| 1832 |
| 1833 OS::Print("-- [before ssa allocator] ranges [%s] ---------\n", |
| 1834 function.ToFullyQualifiedCString()); |
| 1835 PrintLiveRanges(); |
| 1836 OS::Print("----------------------------------------------\n"); |
| 1837 |
| 1838 OS::Print("-- [before ssa allocator] ir [%s] -------------\n", |
| 1839 function.ToFullyQualifiedCString()); |
| 1840 FlowGraphPrinter printer(Function::Handle(), block_order_, true); |
| 1841 printer.PrintBlocks(); |
| 1842 OS::Print("----------------------------------------------\n"); |
| 1843 } |
| 1844 |
| 1811 AllocateCPURegisters(); | 1845 AllocateCPURegisters(); |
| 1812 | 1846 |
| 1813 ResolveControlFlow(); | 1847 ResolveControlFlow(); |
| 1814 | 1848 |
| 1815 GraphEntryInstr* entry = block_order_[0]->AsGraphEntry(); | 1849 GraphEntryInstr* entry = block_order_[0]->AsGraphEntry(); |
| 1816 ASSERT(entry != NULL); | 1850 ASSERT(entry != NULL); |
| 1817 entry->set_spill_slot_count(spill_slots_.length()); | 1851 entry->set_spill_slot_count(spill_slots_.length()); |
| 1818 | 1852 |
| 1819 if (FLAG_print_ssa_liveranges) { | 1853 if (FLAG_print_ssa_liveranges) { |
| 1820 const Function& function = builder_->parsed_function().function(); | 1854 const Function& function = builder_->parsed_function().function(); |
| 1821 | 1855 |
| 1822 OS::Print("-- [after ssa allocator] ranges [%s] ---------\n", | 1856 OS::Print("-- [after ssa allocator] ranges [%s] ---------\n", |
| 1823 function.ToFullyQualifiedCString()); | 1857 function.ToFullyQualifiedCString()); |
| 1824 PrintLiveRanges(); | 1858 PrintLiveRanges(); |
| 1825 OS::Print("----------------------------------------------\n"); | 1859 OS::Print("----------------------------------------------\n"); |
| 1826 | 1860 |
| 1827 OS::Print("-- [after ssa allocator] ir [%s] -------------\n", | 1861 OS::Print("-- [after ssa allocator] ir [%s] -------------\n", |
| 1828 function.ToFullyQualifiedCString()); | 1862 function.ToFullyQualifiedCString()); |
| 1829 FlowGraphPrinter printer(Function::Handle(), block_order_, true); | 1863 FlowGraphPrinter printer(Function::Handle(), block_order_, true); |
| 1830 printer.PrintBlocks(); | 1864 printer.PrintBlocks(); |
| 1831 OS::Print("----------------------------------------------\n"); | 1865 OS::Print("----------------------------------------------\n"); |
| 1832 } | 1866 } |
| 1833 } | 1867 } |
| 1834 | 1868 |
| 1835 | 1869 |
| 1836 } // namespace dart | 1870 } // namespace dart |
| OLD | NEW |