OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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.h" | 10 #include "vm/flow_graph.h" |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
56 | 56 |
57 | 57 |
58 static intptr_t ToInstructionEnd(intptr_t pos) { | 58 static intptr_t ToInstructionEnd(intptr_t pos) { |
59 return (pos | 1); | 59 return (pos | 1); |
60 } | 60 } |
61 | 61 |
62 | 62 |
63 FlowGraphAllocator::FlowGraphAllocator(const FlowGraph& flow_graph) | 63 FlowGraphAllocator::FlowGraphAllocator(const FlowGraph& flow_graph) |
64 : flow_graph_(flow_graph), | 64 : flow_graph_(flow_graph), |
65 reaching_defs_(flow_graph), | 65 reaching_defs_(flow_graph), |
66 mint_values_(NULL), | 66 value_representations_(flow_graph.max_virtual_register_number()), |
67 block_order_(flow_graph.reverse_postorder()), | 67 block_order_(flow_graph.reverse_postorder()), |
68 postorder_(flow_graph.postorder()), | 68 postorder_(flow_graph.postorder()), |
69 live_out_(block_order_.length()), | 69 live_out_(block_order_.length()), |
70 kill_(block_order_.length()), | 70 kill_(block_order_.length()), |
71 live_in_(block_order_.length()), | 71 live_in_(block_order_.length()), |
72 vreg_count_(flow_graph.max_virtual_register_number()), | 72 vreg_count_(flow_graph.max_virtual_register_number()), |
73 live_ranges_(flow_graph.max_virtual_register_number()), | 73 live_ranges_(flow_graph.max_virtual_register_number()), |
74 cpu_regs_(), | 74 cpu_regs_(), |
75 fpu_regs_(), | 75 fpu_regs_(), |
76 blocked_cpu_registers_(), | 76 blocked_cpu_registers_(), |
77 blocked_fpu_registers_(), | 77 blocked_fpu_registers_(), |
78 cpu_spill_slot_count_(0) { | 78 cpu_spill_slot_count_(0) { |
79 for (intptr_t i = 0; i < vreg_count_; i++) live_ranges_.Add(NULL); | 79 for (intptr_t i = 0; i < vreg_count_; i++) live_ranges_.Add(NULL); |
| 80 for (intptr_t i = 0; i < vreg_count_; i++) { |
| 81 value_representations_.Add(kNoRepresentation); |
| 82 } |
80 | 83 |
81 // All registers are marked as "not blocked" (array initialized to false). | 84 // All registers are marked as "not blocked" (array initialized to false). |
82 // Mark the unavailable ones as "blocked" (true). | 85 // Mark the unavailable ones as "blocked" (true). |
83 for (intptr_t i = 0; i < kFirstFreeCpuRegister; i++) { | 86 for (intptr_t i = 0; i < kFirstFreeCpuRegister; i++) { |
84 blocked_cpu_registers_[i] = true; | 87 blocked_cpu_registers_[i] = true; |
85 } | 88 } |
86 for (intptr_t i = kLastFreeCpuRegister + 1; i < kNumberOfCpuRegisters; i++) { | 89 for (intptr_t i = kLastFreeCpuRegister + 1; i < kNumberOfCpuRegisters; i++) { |
87 blocked_cpu_registers_[i] = true; | 90 blocked_cpu_registers_[i] = true; |
88 } | 91 } |
89 blocked_cpu_registers_[CTX] = true; | 92 blocked_cpu_registers_[CTX] = true; |
(...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
378 // Shrink the first use interval. It was optimistically expanded to | 381 // Shrink the first use interval. It was optimistically expanded to |
379 // cover the the block from the start to the last use in the block. | 382 // cover the the block from the start to the last use in the block. |
380 ASSERT(first_use_interval_->start_ <= pos); | 383 ASSERT(first_use_interval_->start_ <= pos); |
381 first_use_interval_->start_ = pos; | 384 first_use_interval_->start_ = pos; |
382 } | 385 } |
383 } | 386 } |
384 | 387 |
385 | 388 |
386 LiveRange* FlowGraphAllocator::GetLiveRange(intptr_t vreg) { | 389 LiveRange* FlowGraphAllocator::GetLiveRange(intptr_t vreg) { |
387 if (live_ranges_[vreg] == NULL) { | 390 if (live_ranges_[vreg] == NULL) { |
388 Location::Representation rep = | 391 Representation rep = value_representations_[vreg]; |
389 mint_values_->Contains(vreg) ? Location::kMint : Location::kDouble; | 392 ASSERT(rep != kNoRepresentation); |
390 live_ranges_[vreg] = new LiveRange(vreg, rep); | 393 live_ranges_[vreg] = new LiveRange(vreg, rep); |
391 } | 394 } |
392 return live_ranges_[vreg]; | 395 return live_ranges_[vreg]; |
393 } | 396 } |
394 | 397 |
395 | 398 |
396 LiveRange* FlowGraphAllocator::MakeLiveRangeForTemporary() { | 399 LiveRange* FlowGraphAllocator::MakeLiveRangeForTemporary() { |
397 Location::Representation ignored = Location::kDouble; | 400 // Representation does not matter for temps. |
| 401 Representation ignored = kNoRepresentation; |
398 LiveRange* range = new LiveRange(kTempVirtualRegister, ignored); | 402 LiveRange* range = new LiveRange(kTempVirtualRegister, ignored); |
399 #if defined(DEBUG) | 403 #if defined(DEBUG) |
400 temporaries_.Add(range); | 404 temporaries_.Add(range); |
401 #endif | 405 #endif |
402 return range; | 406 return range; |
403 } | 407 } |
404 | 408 |
405 | 409 |
406 void FlowGraphAllocator::BlockRegisterLocation(Location loc, | 410 void FlowGraphAllocator::BlockRegisterLocation(Location loc, |
407 intptr_t from, | 411 intptr_t from, |
408 intptr_t to, | 412 intptr_t to, |
409 bool* blocked_registers, | 413 bool* blocked_registers, |
410 LiveRange** blocking_ranges) { | 414 LiveRange** blocking_ranges) { |
411 if (blocked_registers[loc.register_code()]) { | 415 if (blocked_registers[loc.register_code()]) { |
412 return; | 416 return; |
413 } | 417 } |
414 | 418 |
415 if (blocking_ranges[loc.register_code()] == NULL) { | 419 if (blocking_ranges[loc.register_code()] == NULL) { |
416 Location::Representation ignored = Location::kDouble; | 420 Representation ignored = kNoRepresentation; |
417 LiveRange* range = new LiveRange(kNoVirtualRegister, ignored); | 421 LiveRange* range = new LiveRange(kNoVirtualRegister, ignored); |
418 blocking_ranges[loc.register_code()] = range; | 422 blocking_ranges[loc.register_code()] = range; |
419 range->set_assigned_location(loc); | 423 range->set_assigned_location(loc); |
420 #if defined(DEBUG) | 424 #if defined(DEBUG) |
421 temporaries_.Add(range); | 425 temporaries_.Add(range); |
422 #endif | 426 #endif |
423 } | 427 } |
424 | 428 |
425 blocking_ranges[loc.register_code()]->AddUseInterval(from, to); | 429 blocking_ranges[loc.register_code()]->AddUseInterval(from, to); |
426 } | 430 } |
(...skipping 519 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
946 // [--) | 950 // [--) |
947 // | 951 // |
948 // The stack bitmap describes the position i. | 952 // The stack bitmap describes the position i. |
949 for (intptr_t reg = 0; reg < kNumberOfCpuRegisters; reg++) { | 953 for (intptr_t reg = 0; reg < kNumberOfCpuRegisters; reg++) { |
950 BlockLocation(Location::RegisterLocation(static_cast<Register>(reg)), | 954 BlockLocation(Location::RegisterLocation(static_cast<Register>(reg)), |
951 pos, | 955 pos, |
952 pos + 1); | 956 pos + 1); |
953 } | 957 } |
954 | 958 |
955 for (intptr_t reg = 0; reg < kNumberOfFpuRegisters; reg++) { | 959 for (intptr_t reg = 0; reg < kNumberOfFpuRegisters; reg++) { |
956 Location::Representation ignored = Location::kDouble; | 960 Representation ignored = kNoRepresentation; |
957 BlockLocation( | 961 BlockLocation( |
958 Location::FpuRegisterLocation(static_cast<FpuRegister>(reg), ignored), | 962 Location::FpuRegisterLocation(static_cast<FpuRegister>(reg), ignored), |
959 pos, | 963 pos, |
960 pos + 1); | 964 pos + 1); |
961 } | 965 } |
962 | 966 |
963 | 967 |
964 #if defined(DEBUG) | 968 #if defined(DEBUG) |
965 // Verify that temps, inputs and output were specified as fixed | 969 // Verify that temps, inputs and output were specified as fixed |
966 // locations. Every register is blocked now so attempt to | 970 // locations. Every register is blocked now so attempt to |
(...skipping 618 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1585 } | 1589 } |
1586 range = range->next_sibling(); | 1590 range = range->next_sibling(); |
1587 } | 1591 } |
1588 } | 1592 } |
1589 | 1593 |
1590 | 1594 |
1591 void FlowGraphAllocator::Spill(LiveRange* range) { | 1595 void FlowGraphAllocator::Spill(LiveRange* range) { |
1592 LiveRange* parent = GetLiveRange(range->vreg()); | 1596 LiveRange* parent = GetLiveRange(range->vreg()); |
1593 if (parent->spill_slot().IsInvalid()) { | 1597 if (parent->spill_slot().IsInvalid()) { |
1594 AllocateSpillSlotFor(parent); | 1598 AllocateSpillSlotFor(parent); |
1595 if (register_kind_ == Location::kRegister) { | 1599 if (range->representation() == kTagged) { |
1596 MarkAsObjectAtSafepoints(parent); | 1600 MarkAsObjectAtSafepoints(parent); |
1597 } | 1601 } |
1598 } | 1602 } |
1599 range->set_assigned_location(parent->spill_slot()); | 1603 range->set_assigned_location(parent->spill_slot()); |
1600 ConvertAllUses(range); | 1604 ConvertAllUses(range); |
1601 } | 1605 } |
1602 | 1606 |
1603 | 1607 |
1604 intptr_t FlowGraphAllocator::FirstIntersectionWithAllocated( | 1608 intptr_t FlowGraphAllocator::FirstIntersectionWithAllocated( |
1605 intptr_t reg, LiveRange* unallocated) { | 1609 intptr_t reg, LiveRange* unallocated) { |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1741 if (!reaching_defs_.Get(phi)->Contains(unallocated->vreg())) { | 1745 if (!reaching_defs_.Get(phi)->Contains(unallocated->vreg())) { |
1742 used_on_backedge[reg] = true; | 1746 used_on_backedge[reg] = true; |
1743 } | 1747 } |
1744 } | 1748 } |
1745 } | 1749 } |
1746 | 1750 |
1747 if (used_on_backedge[candidate]) { | 1751 if (used_on_backedge[candidate]) { |
1748 TRACE_ALLOC(OS::Print( | 1752 TRACE_ALLOC(OS::Print( |
1749 "considering %s for v%"Pd": has interference on the back edge" | 1753 "considering %s for v%"Pd": has interference on the back edge" |
1750 " {loop [%"Pd", %"Pd")}\n", | 1754 " {loop [%"Pd", %"Pd")}\n", |
1751 MakeRegisterLocation(candidate, Location::kDouble).Name(), | 1755 MakeRegisterLocation(candidate, kUnboxedDouble).Name(), |
1752 unallocated->vreg(), | 1756 unallocated->vreg(), |
1753 loop_header->entry()->start_pos(), | 1757 loop_header->entry()->start_pos(), |
1754 loop_header->last_block()->end_pos())); | 1758 loop_header->last_block()->end_pos())); |
1755 for (intptr_t reg = 0; reg < NumberOfRegisters(); ++reg) { | 1759 for (intptr_t reg = 0; reg < NumberOfRegisters(); ++reg) { |
1756 if (blocked_registers_[reg] || | 1760 if (blocked_registers_[reg] || |
1757 (reg == candidate) || | 1761 (reg == candidate) || |
1758 used_on_backedge[reg]) { | 1762 used_on_backedge[reg]) { |
1759 continue; | 1763 continue; |
1760 } | 1764 } |
1761 | 1765 |
1762 const intptr_t intersection = | 1766 const intptr_t intersection = |
1763 FirstIntersectionWithAllocated(reg, unallocated); | 1767 FirstIntersectionWithAllocated(reg, unallocated); |
1764 if (intersection >= free_until) { | 1768 if (intersection >= free_until) { |
1765 candidate = reg; | 1769 candidate = reg; |
1766 free_until = intersection; | 1770 free_until = intersection; |
1767 TRACE_ALLOC(OS::Print( | 1771 TRACE_ALLOC(OS::Print( |
1768 "found %s for v%"Pd" with no interference on the back edge\n", | 1772 "found %s for v%"Pd" with no interference on the back edge\n", |
1769 MakeRegisterLocation(candidate, Location::kDouble).Name(), | 1773 MakeRegisterLocation(candidate, kUnboxedDouble).Name(), |
1770 candidate)); | 1774 candidate)); |
1771 break; | 1775 break; |
1772 } | 1776 } |
1773 } | 1777 } |
1774 } | 1778 } |
1775 } | 1779 } |
1776 | 1780 |
1777 ASSERT(0 <= kMaxPosition); | 1781 ASSERT(0 <= kMaxPosition); |
1778 if (free_until != kMaxPosition) { | 1782 if (free_until != kMaxPosition) { |
1779 for (intptr_t reg = 0; reg < NumberOfRegisters(); ++reg) { | 1783 for (intptr_t reg = 0; reg < NumberOfRegisters(); ++reg) { |
1780 if (blocked_registers_[reg] || (reg == candidate)) continue; | 1784 if (blocked_registers_[reg] || (reg == candidate)) continue; |
1781 const intptr_t intersection = | 1785 const intptr_t intersection = |
1782 FirstIntersectionWithAllocated(reg, unallocated); | 1786 FirstIntersectionWithAllocated(reg, unallocated); |
1783 if (intersection > free_until) { | 1787 if (intersection > free_until) { |
1784 candidate = reg; | 1788 candidate = reg; |
1785 free_until = intersection; | 1789 free_until = intersection; |
1786 if (free_until == kMaxPosition) break; | 1790 if (free_until == kMaxPosition) break; |
1787 } | 1791 } |
1788 } | 1792 } |
1789 } | 1793 } |
1790 | 1794 |
1791 // All registers are blocked by active ranges. | 1795 // All registers are blocked by active ranges. |
1792 if (free_until <= unallocated->Start()) return false; | 1796 if (free_until <= unallocated->Start()) return false; |
1793 | 1797 |
1794 TRACE_ALLOC(OS::Print("assigning free register ")); | 1798 TRACE_ALLOC(OS::Print("assigning free register ")); |
1795 TRACE_ALLOC(MakeRegisterLocation(candidate, Location::kDouble).Print()); | 1799 TRACE_ALLOC(MakeRegisterLocation(candidate, kUnboxedDouble).Print()); |
1796 TRACE_ALLOC(OS::Print(" to v%"Pd"\n", unallocated->vreg())); | 1800 TRACE_ALLOC(OS::Print(" to v%"Pd"\n", unallocated->vreg())); |
1797 | 1801 |
1798 if (free_until != kMaxPosition) { | 1802 if (free_until != kMaxPosition) { |
1799 // There was an intersection. Split unallocated. | 1803 // There was an intersection. Split unallocated. |
1800 TRACE_ALLOC(OS::Print(" splitting at %"Pd"\n", free_until)); | 1804 TRACE_ALLOC(OS::Print(" splitting at %"Pd"\n", free_until)); |
1801 LiveRange* tail = unallocated->SplitAt(free_until); | 1805 LiveRange* tail = unallocated->SplitAt(free_until); |
1802 AddToUnallocated(tail); | 1806 AddToUnallocated(tail); |
1803 } | 1807 } |
1804 | 1808 |
1805 registers_[candidate].Add(unallocated); | 1809 registers_[candidate].Add(unallocated); |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1888 (register_use != NULL) ? register_use->pos() | 1892 (register_use != NULL) ? register_use->pos() |
1889 : unallocated->Start(); | 1893 : unallocated->Start(); |
1890 if (free_until < register_use_pos) { | 1894 if (free_until < register_use_pos) { |
1891 // Can't acquire free register. Spill until we really need one. | 1895 // Can't acquire free register. Spill until we really need one. |
1892 ASSERT(unallocated->Start() < ToInstructionStart(register_use_pos)); | 1896 ASSERT(unallocated->Start() < ToInstructionStart(register_use_pos)); |
1893 SpillBetween(unallocated, unallocated->Start(), register_use->pos()); | 1897 SpillBetween(unallocated, unallocated->Start(), register_use->pos()); |
1894 return; | 1898 return; |
1895 } | 1899 } |
1896 | 1900 |
1897 TRACE_ALLOC(OS::Print("assigning blocked register ")); | 1901 TRACE_ALLOC(OS::Print("assigning blocked register ")); |
1898 TRACE_ALLOC(MakeRegisterLocation(candidate, Location::kDouble).Print()); | 1902 TRACE_ALLOC(MakeRegisterLocation(candidate, kUnboxedDouble).Print()); |
1899 TRACE_ALLOC(OS::Print(" to live range v%"Pd" until %"Pd"\n", | 1903 TRACE_ALLOC(OS::Print(" to live range v%"Pd" until %"Pd"\n", |
1900 unallocated->vreg(), blocked_at)); | 1904 unallocated->vreg(), blocked_at)); |
1901 | 1905 |
1902 if (blocked_at < unallocated->End()) { | 1906 if (blocked_at < unallocated->End()) { |
1903 // Register is blocked before the end of the live range. Split the range | 1907 // Register is blocked before the end of the live range. Split the range |
1904 // at latest at blocked_at position. | 1908 // at latest at blocked_at position. |
1905 LiveRange* tail = SplitBetween(unallocated, | 1909 LiveRange* tail = SplitBetween(unallocated, |
1906 unallocated->Start(), | 1910 unallocated->Start(), |
1907 blocked_at + 1); | 1911 blocked_at + 1); |
1908 AddToUnallocated(tail); | 1912 AddToUnallocated(tail); |
(...skipping 481 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2390 } else { | 2394 } else { |
2391 AddMoveAt(range->Start() + 1, | 2395 AddMoveAt(range->Start() + 1, |
2392 range->spill_slot(), | 2396 range->spill_slot(), |
2393 range->assigned_location()); | 2397 range->assigned_location()); |
2394 } | 2398 } |
2395 } | 2399 } |
2396 } | 2400 } |
2397 | 2401 |
2398 | 2402 |
2399 void FlowGraphAllocator::CollectRepresentations() { | 2403 void FlowGraphAllocator::CollectRepresentations() { |
2400 mint_values_ = new BitVector(flow_graph_.max_virtual_register_number()); | 2404 // Parameters. |
| 2405 GraphEntryInstr* graph_entry = flow_graph_.graph_entry(); |
| 2406 for (intptr_t i = 0; i < graph_entry->initial_definitions()->length(); ++i) { |
| 2407 Definition* def = (*graph_entry->initial_definitions())[i]; |
| 2408 value_representations_[def->ssa_temp_index()] = def->representation(); |
| 2409 } |
2401 | 2410 |
2402 for (BlockIterator it = flow_graph_.reverse_postorder_iterator(); | 2411 for (BlockIterator it = flow_graph_.reverse_postorder_iterator(); |
2403 !it.Done(); | 2412 !it.Done(); |
2404 it.Advance()) { | 2413 it.Advance()) { |
2405 BlockEntryInstr* block = it.Current(); | 2414 BlockEntryInstr* block = it.Current(); |
2406 // TODO(fschneider): Support unboxed mint representation for phis. | 2415 // Phis. |
| 2416 if (block->IsJoinEntry()) { |
| 2417 JoinEntryInstr* join = block->AsJoinEntry(); |
| 2418 for (PhiIterator it(join); !it.Done(); it.Advance()) { |
| 2419 PhiInstr* phi = it.Current(); |
| 2420 if ((phi != NULL) && (phi->ssa_temp_index() >= 0)) { |
| 2421 value_representations_[phi->ssa_temp_index()] = phi->representation(); |
| 2422 } |
| 2423 } |
| 2424 } |
| 2425 // Normal instructions. |
2407 for (ForwardInstructionIterator instr_it(block); | 2426 for (ForwardInstructionIterator instr_it(block); |
2408 !instr_it.Done(); | 2427 !instr_it.Done(); |
2409 instr_it.Advance()) { | 2428 instr_it.Advance()) { |
2410 Definition* defn = instr_it.Current()->AsDefinition(); | 2429 Definition* def = instr_it.Current()->AsDefinition(); |
2411 if ((defn != NULL) && | 2430 if ((def != NULL) && (def->ssa_temp_index() >= 0)) { |
2412 (defn->ssa_temp_index() >= 0) && | 2431 value_representations_[def->ssa_temp_index()] = def->representation(); |
2413 (defn->representation() == kUnboxedMint)) { | |
2414 mint_values_->Add(defn->ssa_temp_index()); | |
2415 } | 2432 } |
2416 } | 2433 } |
2417 } | 2434 } |
2418 } | 2435 } |
2419 | 2436 |
2420 | 2437 |
2421 void FlowGraphAllocator::AllocateRegisters() { | 2438 void FlowGraphAllocator::AllocateRegisters() { |
2422 CollectRepresentations(); | 2439 CollectRepresentations(); |
2423 | 2440 |
2424 EliminateEnvironments(); | 2441 EliminateEnvironments(); |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2486 OS::Print("-- [after ssa allocator] ir [%s] -------------\n", | 2503 OS::Print("-- [after ssa allocator] ir [%s] -------------\n", |
2487 function.ToFullyQualifiedCString()); | 2504 function.ToFullyQualifiedCString()); |
2488 FlowGraphPrinter printer(flow_graph_, true); | 2505 FlowGraphPrinter printer(flow_graph_, true); |
2489 printer.PrintBlocks(); | 2506 printer.PrintBlocks(); |
2490 OS::Print("----------------------------------------------\n"); | 2507 OS::Print("----------------------------------------------\n"); |
2491 } | 2508 } |
2492 } | 2509 } |
2493 | 2510 |
2494 | 2511 |
2495 } // namespace dart | 2512 } // namespace dart |
OLD | NEW |