| 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 399 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 410 | 410 |
| 411 for (intptr_t i = 0; i < live_ranges_.length(); i++) { | 411 for (intptr_t i = 0; i < live_ranges_.length(); i++) { |
| 412 if (live_ranges_[i] != NULL) { | 412 if (live_ranges_[i] != NULL) { |
| 413 live_ranges_[i]->Print(); | 413 live_ranges_[i]->Print(); |
| 414 } | 414 } |
| 415 } | 415 } |
| 416 } | 416 } |
| 417 | 417 |
| 418 | 418 |
| 419 void FlowGraphAllocator::BuildLiveRanges() { | 419 void FlowGraphAllocator::BuildLiveRanges() { |
| 420 NumberInstructions(); | |
| 421 | |
| 422 const intptr_t block_count = postorder_.length(); | 420 const intptr_t block_count = postorder_.length(); |
| 423 ASSERT(postorder_[block_count - 1]->IsGraphEntry()); | 421 ASSERT(postorder_[block_count - 1]->IsGraphEntry()); |
| 424 for (intptr_t i = 0; i < (block_count - 1); i++) { | 422 for (intptr_t i = 0; i < (block_count - 1); i++) { |
| 425 BlockEntryInstr* block = postorder_[i]; | 423 BlockEntryInstr* block = postorder_[i]; |
| 426 | 424 |
| 427 // For every SSA value that is live out of this block, create an interval | 425 // For every SSA value that is live out of this block, create an interval |
| 428 // that covers the whole block. It will be shortened if we encounter a | 426 // that covers the whole block. It will be shortened if we encounter a |
| 429 // definition of this value in this block. | 427 // definition of this value in this block. |
| 430 for (BitVector::Iterator it(live_out_[i]); !it.Done(); it.Advance()) { | 428 for (BitVector::Iterator it(live_out_[i]); !it.Done(); it.Advance()) { |
| 431 LiveRange* range = GetLiveRange(it.Current()); | 429 LiveRange* range = GetLiveRange(it.Current()); |
| (...skipping 461 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 893 // numbers representing lifetime positions. Introduce explicit parallel | 891 // numbers representing lifetime positions. Introduce explicit parallel |
| 894 // move instructions in the predecessors of join nodes. The moves are used | 892 // move instructions in the predecessors of join nodes. The moves are used |
| 895 // for phi resolution. | 893 // for phi resolution. |
| 896 void FlowGraphAllocator::NumberInstructions() { | 894 void FlowGraphAllocator::NumberInstructions() { |
| 897 intptr_t pos = 0; | 895 intptr_t pos = 0; |
| 898 | 896 |
| 899 // The basic block order is reverse postorder. | 897 // The basic block order is reverse postorder. |
| 900 const intptr_t block_count = postorder_.length(); | 898 const intptr_t block_count = postorder_.length(); |
| 901 for (intptr_t i = block_count - 1; i >= 0; i--) { | 899 for (intptr_t i = block_count - 1; i >= 0; i--) { |
| 902 BlockEntryInstr* block = postorder_[i]; | 900 BlockEntryInstr* block = postorder_[i]; |
| 901 BlockInfo* info = new BlockInfo(block); |
| 903 | 902 |
| 904 instructions_.Add(block); | 903 instructions_.Add(block); |
| 904 block_info_.Add(info); |
| 905 block->set_start_pos(pos); | 905 block->set_start_pos(pos); |
| 906 block->set_lifetime_position(pos); | 906 block->set_lifetime_position(pos); |
| 907 pos += 2; | 907 pos += 2; |
| 908 | 908 |
| 909 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 909 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
| 910 Instruction* current = it.Current(); | 910 Instruction* current = it.Current(); |
| 911 // Do not assign numbers to parallel move instructions. | 911 // Do not assign numbers to parallel move instructions. |
| 912 if (!current->IsParallelMove()) { | 912 if (!current->IsParallelMove()) { |
| 913 instructions_.Add(current); | 913 instructions_.Add(current); |
| 914 block_info_.Add(info); |
| 914 current->set_lifetime_position(pos); | 915 current->set_lifetime_position(pos); |
| 915 pos += 2; | 916 pos += 2; |
| 916 } | 917 } |
| 917 } | 918 } |
| 918 block->set_end_pos(pos); | 919 block->set_end_pos(pos); |
| 919 } | 920 } |
| 920 | 921 |
| 921 // Create parallel moves in join predecessors. This must be done after | 922 // Create parallel moves in join predecessors. This must be done after |
| 922 // all instructions are numbered. | 923 // all instructions are numbered. |
| 923 for (intptr_t i = block_count - 1; i >= 0; i--) { | 924 for (intptr_t i = block_count - 1; i >= 0; i--) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 940 // Populate the ParallelMove with empty moves. | 941 // Populate the ParallelMove with empty moves. |
| 941 for (intptr_t j = 0; j < phi_count; j++) { | 942 for (intptr_t j = 0; j < phi_count; j++) { |
| 942 move->AddMove(Location::NoLocation(), Location::NoLocation()); | 943 move->AddMove(Location::NoLocation(), Location::NoLocation()); |
| 943 } | 944 } |
| 944 } | 945 } |
| 945 } | 946 } |
| 946 } | 947 } |
| 947 } | 948 } |
| 948 | 949 |
| 949 | 950 |
| 951 // Discover structural (reducible) loops nesting structure. |
| 952 void FlowGraphAllocator::DiscoverLoops() { |
| 953 // TODO(vegorov): consider using a generic algorithm to correctly discover |
| 954 // both headers of reducible and irreducible loops. |
| 955 BlockInfo* current_loop = NULL; |
| 956 |
| 957 const intptr_t block_count = postorder_.length(); |
| 958 for (intptr_t i = 0; i < block_count; i++) { |
| 959 BlockEntryInstr* block = postorder_[i]; |
| 960 GotoInstr* goto_instr = block->last_instruction()->AsGoto(); |
| 961 if (goto_instr != NULL) { |
| 962 JoinEntryInstr* successor = goto_instr->successor(); |
| 963 if (successor->postorder_number() > i) { |
| 964 // This is back-edge. |
| 965 BlockInfo* successor_info = BlockInfoAt(successor->lifetime_position()); |
| 966 ASSERT(successor_info->entry() == successor); |
| 967 if (!successor_info->is_loop_header() && |
| 968 ((current_loop == NULL) || |
| 969 (current_loop->entry()->block_id() < |
| 970 successor_info->entry()->block_id()))) { |
| 971 ASSERT(successor_info != current_loop); |
| 972 |
| 973 successor_info->mark_loop_header(); |
| 974 // For loop header loop information points to the outer loop. |
| 975 successor_info->set_loop(current_loop); |
| 976 current_loop = successor_info; |
| 977 } |
| 978 } |
| 979 } |
| 980 |
| 981 if (current_loop != NULL) { |
| 982 BlockInfo* current_info = BlockInfoAt(block->lifetime_position()); |
| 983 if (current_info == current_loop) { |
| 984 ASSERT(current_loop->is_loop_header()); |
| 985 current_loop = current_info->loop(); |
| 986 } else { |
| 987 current_info->set_loop(current_loop); |
| 988 } |
| 989 } |
| 990 } |
| 991 } |
| 992 |
| 993 |
| 950 Instruction* FlowGraphAllocator::InstructionAt(intptr_t pos) const { | 994 Instruction* FlowGraphAllocator::InstructionAt(intptr_t pos) const { |
| 951 return instructions_[pos / 2]; | 995 return instructions_[pos / 2]; |
| 952 } | 996 } |
| 953 | 997 |
| 954 | 998 |
| 999 BlockInfo* FlowGraphAllocator::BlockInfoAt(intptr_t pos) const { |
| 1000 return block_info_[pos / 2]; |
| 1001 } |
| 1002 |
| 1003 |
| 955 bool FlowGraphAllocator::IsBlockEntry(intptr_t pos) const { | 1004 bool FlowGraphAllocator::IsBlockEntry(intptr_t pos) const { |
| 956 return IsInstructionStartPosition(pos) && InstructionAt(pos)->IsBlockEntry(); | 1005 return IsInstructionStartPosition(pos) && InstructionAt(pos)->IsBlockEntry(); |
| 957 } | 1006 } |
| 958 | 1007 |
| 959 | 1008 |
| 960 void AllocationFinger::Initialize(LiveRange* range) { | 1009 void AllocationFinger::Initialize(LiveRange* range) { |
| 961 first_pending_use_interval_ = range->first_use_interval(); | 1010 first_pending_use_interval_ = range->first_use_interval(); |
| 962 first_register_use_ = range->first_use(); | 1011 first_register_use_ = range->first_use(); |
| 963 first_register_beneficial_use_ = range->first_use(); | 1012 first_register_beneficial_use_ = range->first_use(); |
| 964 first_hinted_use_ = range->first_use(); | 1013 first_hinted_use_ = range->first_use(); |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1131 | 1180 |
| 1132 last_use_interval_ = last_before_split; | 1181 last_use_interval_ = last_before_split; |
| 1133 last_use_interval_->next_ = NULL; | 1182 last_use_interval_->next_ = NULL; |
| 1134 return next_sibling_; | 1183 return next_sibling_; |
| 1135 } | 1184 } |
| 1136 | 1185 |
| 1137 | 1186 |
| 1138 LiveRange* FlowGraphAllocator::SplitBetween(LiveRange* range, | 1187 LiveRange* FlowGraphAllocator::SplitBetween(LiveRange* range, |
| 1139 intptr_t from, | 1188 intptr_t from, |
| 1140 intptr_t to) { | 1189 intptr_t to) { |
| 1141 // TODO(vegorov): select optimal split position based on loop structure. | |
| 1142 TRACE_ALLOC(("split %d [%d, %d) between [%d, %d)\n", | 1190 TRACE_ALLOC(("split %d [%d, %d) between [%d, %d)\n", |
| 1143 range->vreg(), range->Start(), range->End(), from, to)); | 1191 range->vreg(), range->Start(), range->End(), from, to)); |
| 1144 | 1192 |
| 1145 // Prefer spliting at instruction starts if possible. | 1193 intptr_t split_pos = kIllegalPosition; |
| 1146 if (from < ToInstructionStart(to)) { | 1194 |
| 1147 to = ToInstructionStart(to); | 1195 BlockInfo* split_block = BlockInfoAt(to); |
| 1196 if (from < split_block->entry()->lifetime_position()) { |
| 1197 // Interval [from, to) spans multiple blocks. |
| 1198 |
| 1199 // If last block is inside a loop prefer splitting at outermost loop's |
| 1200 // header. |
| 1201 BlockInfo* loop_header = split_block->loop(); |
| 1202 while ((loop_header != NULL) && |
| 1203 (from < loop_header->entry()->lifetime_position())) { |
| 1204 split_block = loop_header; |
| 1205 loop_header = loop_header->loop(); |
| 1206 } |
| 1207 |
| 1208 // Split at block's start. |
| 1209 split_pos = split_block->entry()->lifetime_position(); |
| 1210 } else { |
| 1211 // Interval [from, to) is contained inside a single block. |
| 1212 |
| 1213 // Split at position corresponding to the end of the previous |
| 1214 // instruction. |
| 1215 split_pos = ToInstructionStart(to) - 1; |
| 1148 } | 1216 } |
| 1149 | 1217 |
| 1150 // Splitting at the end is not allowed as it produces an empty | 1218 ASSERT((split_pos != kIllegalPosition) && (from < split_pos)); |
| 1151 // live range. | |
| 1152 if (to == range->End()) to -= 1; | |
| 1153 ASSERT(from <= to); | |
| 1154 | 1219 |
| 1155 return range->SplitAt(to); | 1220 return range->SplitAt(split_pos); |
| 1156 } | 1221 } |
| 1157 | 1222 |
| 1158 | 1223 |
| 1159 void FlowGraphAllocator::SpillBetween(LiveRange* range, | 1224 void FlowGraphAllocator::SpillBetween(LiveRange* range, |
| 1160 intptr_t from, | 1225 intptr_t from, |
| 1161 intptr_t to) { | 1226 intptr_t to) { |
| 1162 ASSERT(from < to); | 1227 ASSERT(from < to); |
| 1163 TRACE_ALLOC(("spill %d [%d, %d) between [%d, %d)\n", | 1228 TRACE_ALLOC(("spill %d [%d, %d) between [%d, %d)\n", |
| 1164 range->vreg(), range->Start(), range->End(), from, to)); | 1229 range->vreg(), range->Start(), range->End(), from, to)); |
| 1165 LiveRange* tail = range->SplitAt(from); | 1230 LiveRange* tail = range->SplitAt(from); |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1326 } | 1391 } |
| 1327 } | 1392 } |
| 1328 | 1393 |
| 1329 if (free_until < register_use->pos()) { | 1394 if (free_until < register_use->pos()) { |
| 1330 // Can't acquire free register. Spill until we really need one. | 1395 // Can't acquire free register. Spill until we really need one. |
| 1331 ASSERT(unallocated->Start() < ToInstructionStart(register_use->pos())); | 1396 ASSERT(unallocated->Start() < ToInstructionStart(register_use->pos())); |
| 1332 SpillBetween(unallocated, unallocated->Start(), register_use->pos()); | 1397 SpillBetween(unallocated, unallocated->Start(), register_use->pos()); |
| 1333 return; | 1398 return; |
| 1334 } | 1399 } |
| 1335 | 1400 |
| 1401 TRACE_ALLOC(("assigning blocked register %s to live range %d until %d\n", |
| 1402 Location::RegisterLocation(candidate).Name(), |
| 1403 unallocated->vreg(), |
| 1404 blocked_at)); |
| 1405 |
| 1336 if (blocked_at < unallocated->End()) { | 1406 if (blocked_at < unallocated->End()) { |
| 1337 LiveRange* tail = SplitBetween(unallocated, | 1407 LiveRange* tail = SplitBetween(unallocated, |
| 1338 unallocated->Start(), | 1408 unallocated->Start(), |
| 1339 blocked_at); | 1409 blocked_at); |
| 1340 AddToUnallocated(tail); | 1410 AddToUnallocated(tail); |
| 1341 } | 1411 } |
| 1342 | 1412 |
| 1343 AssignNonFreeRegister(unallocated, candidate); | 1413 AssignNonFreeRegister(unallocated, candidate); |
| 1344 } | 1414 } |
| 1345 | 1415 |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1407 while (from < cpu_regs_[reg].length()) { | 1477 while (from < cpu_regs_[reg].length()) { |
| 1408 LiveRange* allocated = cpu_regs_[reg][from++]; | 1478 LiveRange* allocated = cpu_regs_[reg][from++]; |
| 1409 if (allocated != NULL) cpu_regs_[reg][to++] = allocated; | 1479 if (allocated != NULL) cpu_regs_[reg][to++] = allocated; |
| 1410 } | 1480 } |
| 1411 cpu_regs_[reg].TruncateTo(to); | 1481 cpu_regs_[reg].TruncateTo(to); |
| 1412 } | 1482 } |
| 1413 | 1483 |
| 1414 | 1484 |
| 1415 void FlowGraphAllocator::AssignNonFreeRegister(LiveRange* unallocated, | 1485 void FlowGraphAllocator::AssignNonFreeRegister(LiveRange* unallocated, |
| 1416 Register reg) { | 1486 Register reg) { |
| 1417 TRACE_ALLOC(("assigning blocked register %s to live range %d\n", | |
| 1418 Location::RegisterLocation(reg).Name(), | |
| 1419 unallocated->vreg())); | |
| 1420 | |
| 1421 intptr_t first_evicted = -1; | 1487 intptr_t first_evicted = -1; |
| 1422 for (intptr_t i = cpu_regs_[reg].length() - 1; i >= 0; i--) { | 1488 for (intptr_t i = cpu_regs_[reg].length() - 1; i >= 0; i--) { |
| 1423 LiveRange* allocated = cpu_regs_[reg][i]; | 1489 LiveRange* allocated = cpu_regs_[reg][i]; |
| 1424 if (allocated->vreg() < 0) continue; // Can't be evicted. | 1490 if (allocated->vreg() < 0) continue; // Can't be evicted. |
| 1425 if (EvictIntersection(allocated, unallocated)) { | 1491 if (EvictIntersection(allocated, unallocated)) { |
| 1426 ASSERT(allocated->End() <= unallocated->Start()); | 1492 // If allocated was not spilled convert all pending uses. |
| 1427 ConvertAllUses(allocated); | 1493 if (allocated->assigned_location().IsRegister()) { |
| 1494 ASSERT(allocated->End() <= unallocated->Start()); |
| 1495 ConvertAllUses(allocated); |
| 1496 } |
| 1428 cpu_regs_[reg][i] = NULL; | 1497 cpu_regs_[reg][i] = NULL; |
| 1429 first_evicted = i; | 1498 first_evicted = i; |
| 1430 } | 1499 } |
| 1431 } | 1500 } |
| 1432 | 1501 |
| 1433 // Remove evicted ranges from the array. | 1502 // Remove evicted ranges from the array. |
| 1434 if (first_evicted != -1) RemoveEvicted(reg, first_evicted); | 1503 if (first_evicted != -1) RemoveEvicted(reg, first_evicted); |
| 1435 | 1504 |
| 1436 cpu_regs_[reg].Add(unallocated); | 1505 cpu_regs_[reg].Add(unallocated); |
| 1437 unallocated->set_assigned_location(Location::RegisterLocation(reg)); | 1506 unallocated->set_assigned_location(Location::RegisterLocation(reg)); |
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1654 // Siblings were allocated to the same register. | 1723 // Siblings were allocated to the same register. |
| 1655 if (source.Equals(target)) return; | 1724 if (source.Equals(target)) return; |
| 1656 | 1725 |
| 1657 // Values are eagerly spilled. Spill slot already contains appropriate value. | 1726 // Values are eagerly spilled. Spill slot already contains appropriate value. |
| 1658 if (target.IsStackSlot()) { | 1727 if (target.IsStackSlot()) { |
| 1659 ASSERT(parent->spill_slot().Equals(target)); | 1728 ASSERT(parent->spill_slot().Equals(target)); |
| 1660 return; | 1729 return; |
| 1661 } | 1730 } |
| 1662 | 1731 |
| 1663 Instruction* last = source_block->last_instruction(); | 1732 Instruction* last = source_block->last_instruction(); |
| 1664 if (last->SuccessorCount() == 1) { | 1733 if ((last->SuccessorCount() == 1) && !source_block->IsGraphEntry()) { |
| 1665 ASSERT(last->IsGoto()); | 1734 ASSERT(last->IsGoto()); |
| 1666 last->AsGoto()->GetParallelMove()->AddMove(target, source); | 1735 last->AsGoto()->GetParallelMove()->AddMove(target, source); |
| 1667 } else { | 1736 } else { |
| 1668 target_block->GetParallelMove()->AddMove(target, source); | 1737 target_block->GetParallelMove()->AddMove(target, source); |
| 1669 } | 1738 } |
| 1670 } | 1739 } |
| 1671 | 1740 |
| 1672 | 1741 |
| 1673 void FlowGraphAllocator::ResolveControlFlow() { | 1742 void FlowGraphAllocator::ResolveControlFlow() { |
| 1674 // Resolve linear control flow between touching split siblings | 1743 // Resolve linear control flow between touching split siblings |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1722 } | 1791 } |
| 1723 } | 1792 } |
| 1724 } | 1793 } |
| 1725 | 1794 |
| 1726 | 1795 |
| 1727 void FlowGraphAllocator::AllocateRegisters() { | 1796 void FlowGraphAllocator::AllocateRegisters() { |
| 1728 EliminateEnvironmentUses(); | 1797 EliminateEnvironmentUses(); |
| 1729 | 1798 |
| 1730 AnalyzeLiveness(); | 1799 AnalyzeLiveness(); |
| 1731 | 1800 |
| 1801 NumberInstructions(); |
| 1802 |
| 1803 DiscoverLoops(); |
| 1804 |
| 1732 BuildLiveRanges(); | 1805 BuildLiveRanges(); |
| 1733 | 1806 |
| 1734 if (FLAG_print_ssa_liveness) { | 1807 if (FLAG_print_ssa_liveness) { |
| 1735 DumpLiveness(); | 1808 DumpLiveness(); |
| 1736 } | 1809 } |
| 1737 | 1810 |
| 1738 AllocateCPURegisters(); | 1811 AllocateCPURegisters(); |
| 1739 | 1812 |
| 1740 ResolveControlFlow(); | 1813 ResolveControlFlow(); |
| 1741 | 1814 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1754 OS::Print("-- [after ssa allocator] ir [%s] -------------\n", | 1827 OS::Print("-- [after ssa allocator] ir [%s] -------------\n", |
| 1755 function.ToFullyQualifiedCString()); | 1828 function.ToFullyQualifiedCString()); |
| 1756 FlowGraphPrinter printer(Function::Handle(), block_order_, true); | 1829 FlowGraphPrinter printer(Function::Handle(), block_order_, true); |
| 1757 printer.PrintBlocks(); | 1830 printer.PrintBlocks(); |
| 1758 OS::Print("----------------------------------------------\n"); | 1831 OS::Print("----------------------------------------------\n"); |
| 1759 } | 1832 } |
| 1760 } | 1833 } |
| 1761 | 1834 |
| 1762 | 1835 |
| 1763 } // namespace dart | 1836 } // namespace dart |
| OLD | NEW |