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

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: 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 static bool IsNestedLoop(BlockInfo* outer, BlockInfo* inner) {
srdjan 2012/08/02 20:04:37 Can you make checks a little bit more robust since
Vyacheslav Egorov (Google) 2012/08/03 06:29:00 Inlined function back into DiscoverLoops to avoid
952 return (outer == NULL) ||
953 (outer->entry()->block_id() < inner->entry()->block_id());
954 }
955
956
957 // Discover structural (reducible) loops nesting structure.
srdjan 2012/08/02 20:04:37 Aren't all Dart generated loops reducible?
Vyacheslav Egorov (Google) 2012/08/03 06:29:00 AFAIK you can generate an irreducible control flow
srdjan 2012/08/03 21:40:49 You cannot do this. The break goes only to outer
958 void FlowGraphAllocator::DiscoverLoops() {
959 // TODO(vegorov): consider using a generic algorithm to correctly discover
960 // both headers of reducible and irreducible loops.
961 BlockInfo* current_loop = NULL;
962
963 const intptr_t block_count = postorder_.length();
964 for (intptr_t i = 0; i < block_count; i++) {
965 BlockEntryInstr* block = postorder_[i];
966 GotoInstr* goto_instr = block->last_instruction()->AsGoto();
967 if (goto_instr != NULL) {
968 JoinEntryInstr* successor = goto_instr->successor();
969 if (successor->postorder_number() > i) {
970 // This is back-edge.
971 BlockInfo* successor_info = BlockInfoAt(successor->lifetime_position());
972 ASSERT(successor_info->entry() == successor);
973 if (!successor_info->is_loop_header() &&
974 IsNestedLoop(current_loop, successor_info)) {
975 ASSERT(successor_info != current_loop);
976
977 successor_info->mark_loop_header();
978 // For loop header loop information points to the outer loop.
979 successor_info->set_loop(current_loop);
980 current_loop = successor_info;
981 }
982 }
983 }
984
985 if (current_loop != NULL) {
986 BlockInfo* current_info = BlockInfoAt(block->lifetime_position());
987 if (current_info == current_loop) {
988 ASSERT(current_loop->is_loop_header());
989 current_loop = current_info->loop();
990 } else {
991 current_info->set_loop(current_loop);
992 }
993 }
994 }
995 }
996
997
950 Instruction* FlowGraphAllocator::InstructionAt(intptr_t pos) const { 998 Instruction* FlowGraphAllocator::InstructionAt(intptr_t pos) const {
951 return instructions_[pos / 2]; 999 return instructions_[pos / 2];
952 } 1000 }
953 1001
954 1002
1003 BlockInfo* FlowGraphAllocator::BlockInfoAt(intptr_t pos) const {
1004 return block_info_[pos / 2];
1005 }
1006
1007
955 bool FlowGraphAllocator::IsBlockEntry(intptr_t pos) const { 1008 bool FlowGraphAllocator::IsBlockEntry(intptr_t pos) const {
956 return IsInstructionStartPosition(pos) && InstructionAt(pos)->IsBlockEntry(); 1009 return IsInstructionStartPosition(pos) && InstructionAt(pos)->IsBlockEntry();
957 } 1010 }
958 1011
959 1012
960 void AllocationFinger::Initialize(LiveRange* range) { 1013 void AllocationFinger::Initialize(LiveRange* range) {
961 first_pending_use_interval_ = range->first_use_interval(); 1014 first_pending_use_interval_ = range->first_use_interval();
962 first_register_use_ = range->first_use(); 1015 first_register_use_ = range->first_use();
963 first_register_beneficial_use_ = range->first_use(); 1016 first_register_beneficial_use_ = range->first_use();
964 first_hinted_use_ = range->first_use(); 1017 first_hinted_use_ = range->first_use();
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
1131 1184
1132 last_use_interval_ = last_before_split; 1185 last_use_interval_ = last_before_split;
1133 last_use_interval_->next_ = NULL; 1186 last_use_interval_->next_ = NULL;
1134 return next_sibling_; 1187 return next_sibling_;
1135 } 1188 }
1136 1189
1137 1190
1138 LiveRange* FlowGraphAllocator::SplitBetween(LiveRange* range, 1191 LiveRange* FlowGraphAllocator::SplitBetween(LiveRange* range,
1139 intptr_t from, 1192 intptr_t from,
1140 intptr_t to) { 1193 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", 1194 TRACE_ALLOC(("split %d [%d, %d) between [%d, %d)\n",
1143 range->vreg(), range->Start(), range->End(), from, to)); 1195 range->vreg(), range->Start(), range->End(), from, to));
1144 1196
1145 // Prefer spliting at instruction starts if possible. 1197 intptr_t split_pos = kIllegalPosition;
1146 if (from < ToInstructionStart(to)) { 1198
1147 to = ToInstructionStart(to); 1199 BlockInfo* split_block = BlockInfoAt(to);
1200 if (from < split_block->entry()->lifetime_position()) {
1201 // Interval [from, to) spans multiple blocks.
1202
1203 // If it covers any last block is inside a loop prefer splitting at
1204 // loops header if possible.
srdjan 2012/08/02 20:04:37 Please make comment easier to read.
Vyacheslav Egorov (Google) 2012/08/03 06:29:00 Done.
1205 BlockInfo* loop_header = split_block->loop();
1206 while ((loop_header != NULL) &&
1207 (from < loop_header->entry()->lifetime_position())) {
1208 split_block = loop_header;
1209 loop_header = loop_header->loop();
1210 }
1211
1212 // Split at block's start.
1213 split_pos = split_block->entry()->lifetime_position();
1214 } else {
1215 // Interval [from, to) is contained inside a single block.
1216
1217 // Split at position corresponding to the end of the previous
1218 // instruction.
1219 split_pos = ToInstructionStart(to) - 1;
1148 } 1220 }
1149 1221
1150 // Splitting at the end is not allowed as it produces an empty 1222 ASSERT((split_pos != kIllegalPosition) && (from < split_pos));
1151 // live range.
1152 if (to == range->End()) to -= 1;
1153 ASSERT(from <= to);
1154 1223
1155 return range->SplitAt(to); 1224 return range->SplitAt(split_pos);
1156 } 1225 }
1157 1226
1158 1227
1159 void FlowGraphAllocator::SpillBetween(LiveRange* range, 1228 void FlowGraphAllocator::SpillBetween(LiveRange* range,
1160 intptr_t from, 1229 intptr_t from,
1161 intptr_t to) { 1230 intptr_t to) {
1162 ASSERT(from < to); 1231 ASSERT(from < to);
1163 TRACE_ALLOC(("spill %d [%d, %d) between [%d, %d)\n", 1232 TRACE_ALLOC(("spill %d [%d, %d) between [%d, %d)\n",
1164 range->vreg(), range->Start(), range->End(), from, to)); 1233 range->vreg(), range->Start(), range->End(), from, to));
1165 LiveRange* tail = range->SplitAt(from); 1234 LiveRange* tail = range->SplitAt(from);
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
1326 } 1395 }
1327 } 1396 }
1328 1397
1329 if (free_until < register_use->pos()) { 1398 if (free_until < register_use->pos()) {
1330 // Can't acquire free register. Spill until we really need one. 1399 // Can't acquire free register. Spill until we really need one.
1331 ASSERT(unallocated->Start() < ToInstructionStart(register_use->pos())); 1400 ASSERT(unallocated->Start() < ToInstructionStart(register_use->pos()));
1332 SpillBetween(unallocated, unallocated->Start(), register_use->pos()); 1401 SpillBetween(unallocated, unallocated->Start(), register_use->pos());
1333 return; 1402 return;
1334 } 1403 }
1335 1404
1405 TRACE_ALLOC(("assigning blocked register %s to live range %d until %d\n",
1406 Location::RegisterLocation(candidate).Name(),
1407 unallocated->vreg(),
1408 blocked_at));
1409
1336 if (blocked_at < unallocated->End()) { 1410 if (blocked_at < unallocated->End()) {
1337 LiveRange* tail = SplitBetween(unallocated, 1411 LiveRange* tail = SplitBetween(unallocated,
1338 unallocated->Start(), 1412 unallocated->Start(),
1339 blocked_at); 1413 blocked_at);
1340 AddToUnallocated(tail); 1414 AddToUnallocated(tail);
1341 } 1415 }
1342 1416
1343 AssignNonFreeRegister(unallocated, candidate); 1417 AssignNonFreeRegister(unallocated, candidate);
1344 } 1418 }
1345 1419
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
1407 while (from < cpu_regs_[reg].length()) { 1481 while (from < cpu_regs_[reg].length()) {
1408 LiveRange* allocated = cpu_regs_[reg][from++]; 1482 LiveRange* allocated = cpu_regs_[reg][from++];
1409 if (allocated != NULL) cpu_regs_[reg][to++] = allocated; 1483 if (allocated != NULL) cpu_regs_[reg][to++] = allocated;
1410 } 1484 }
1411 cpu_regs_[reg].TruncateTo(to); 1485 cpu_regs_[reg].TruncateTo(to);
1412 } 1486 }
1413 1487
1414 1488
1415 void FlowGraphAllocator::AssignNonFreeRegister(LiveRange* unallocated, 1489 void FlowGraphAllocator::AssignNonFreeRegister(LiveRange* unallocated,
1416 Register reg) { 1490 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; 1491 intptr_t first_evicted = -1;
1422 for (intptr_t i = cpu_regs_[reg].length() - 1; i >= 0; i--) { 1492 for (intptr_t i = cpu_regs_[reg].length() - 1; i >= 0; i--) {
1423 LiveRange* allocated = cpu_regs_[reg][i]; 1493 LiveRange* allocated = cpu_regs_[reg][i];
1424 if (allocated->vreg() < 0) continue; // Can't be evicted. 1494 if (allocated->vreg() < 0) continue; // Can't be evicted.
1425 if (EvictIntersection(allocated, unallocated)) { 1495 if (EvictIntersection(allocated, unallocated)) {
1426 ASSERT(allocated->End() <= unallocated->Start()); 1496 // If allocated was not spilled convert all pending uses.
1427 ConvertAllUses(allocated); 1497 if (allocated->assigned_location().IsRegister()) {
1498 ASSERT(allocated->End() <= unallocated->Start());
1499 ConvertAllUses(allocated);
1500 }
1428 cpu_regs_[reg][i] = NULL; 1501 cpu_regs_[reg][i] = NULL;
1429 first_evicted = i; 1502 first_evicted = i;
1430 } 1503 }
1431 } 1504 }
1432 1505
1433 // Remove evicted ranges from the array. 1506 // Remove evicted ranges from the array.
1434 if (first_evicted != -1) RemoveEvicted(reg, first_evicted); 1507 if (first_evicted != -1) RemoveEvicted(reg, first_evicted);
1435 1508
1436 cpu_regs_[reg].Add(unallocated); 1509 cpu_regs_[reg].Add(unallocated);
1437 unallocated->set_assigned_location(Location::RegisterLocation(reg)); 1510 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. 1727 // Siblings were allocated to the same register.
1655 if (source.Equals(target)) return; 1728 if (source.Equals(target)) return;
1656 1729
1657 // Values are eagerly spilled. Spill slot already contains appropriate value. 1730 // Values are eagerly spilled. Spill slot already contains appropriate value.
1658 if (target.IsStackSlot()) { 1731 if (target.IsStackSlot()) {
1659 ASSERT(parent->spill_slot().Equals(target)); 1732 ASSERT(parent->spill_slot().Equals(target));
1660 return; 1733 return;
1661 } 1734 }
1662 1735
1663 Instruction* last = source_block->last_instruction(); 1736 Instruction* last = source_block->last_instruction();
1664 if (last->SuccessorCount() == 1) { 1737 if ((last->SuccessorCount() == 1) && !source_block->IsGraphEntry()) {
1665 ASSERT(last->IsGoto()); 1738 ASSERT(last->IsGoto());
1666 last->AsGoto()->GetParallelMove()->AddMove(target, source); 1739 last->AsGoto()->GetParallelMove()->AddMove(target, source);
1667 } else { 1740 } else {
1668 target_block->GetParallelMove()->AddMove(target, source); 1741 target_block->GetParallelMove()->AddMove(target, source);
1669 } 1742 }
1670 } 1743 }
1671 1744
1672 1745
1673 void FlowGraphAllocator::ResolveControlFlow() { 1746 void FlowGraphAllocator::ResolveControlFlow() {
1674 // Resolve linear control flow between touching split siblings 1747 // Resolve linear control flow between touching split siblings
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
1722 } 1795 }
1723 } 1796 }
1724 } 1797 }
1725 1798
1726 1799
1727 void FlowGraphAllocator::AllocateRegisters() { 1800 void FlowGraphAllocator::AllocateRegisters() {
1728 EliminateEnvironmentUses(); 1801 EliminateEnvironmentUses();
1729 1802
1730 AnalyzeLiveness(); 1803 AnalyzeLiveness();
1731 1804
1805 NumberInstructions();
1806
1807 DiscoverLoops();
1808
1732 BuildLiveRanges(); 1809 BuildLiveRanges();
1733 1810
1734 if (FLAG_print_ssa_liveness) { 1811 if (FLAG_print_ssa_liveness) {
1735 DumpLiveness(); 1812 DumpLiveness();
1736 } 1813 }
1737 1814
1738 AllocateCPURegisters(); 1815 AllocateCPURegisters();
1739 1816
1740 ResolveControlFlow(); 1817 ResolveControlFlow();
1741 1818
(...skipping 12 matching lines...) Expand all
1754 OS::Print("-- [after ssa allocator] ir [%s] -------------\n", 1831 OS::Print("-- [after ssa allocator] ir [%s] -------------\n",
1755 function.ToFullyQualifiedCString()); 1832 function.ToFullyQualifiedCString());
1756 FlowGraphPrinter printer(Function::Handle(), block_order_, true); 1833 FlowGraphPrinter printer(Function::Handle(), block_order_, true);
1757 printer.PrintBlocks(); 1834 printer.PrintBlocks();
1758 OS::Print("----------------------------------------------\n"); 1835 OS::Print("----------------------------------------------\n");
1759 } 1836 }
1760 } 1837 }
1761 1838
1762 1839
1763 } // namespace dart 1840 } // 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