Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(175)

Side by Side Diff: runtime/vm/flow_graph_allocator.cc

Issue 10850023: When selecting an optimal position for SplitBetween(from, to) ensure: (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: address Srdjan's comments Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/flow_graph_allocator.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_allocator.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698