| 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.h" | 10 #include "vm/flow_graph.h" |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 55 } | 55 } |
| 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 reps_(NULL), |
| 65 block_order_(flow_graph.reverse_postorder()), | 66 block_order_(flow_graph.reverse_postorder()), |
| 66 postorder_(flow_graph.postorder()), | 67 postorder_(flow_graph.postorder()), |
| 67 live_out_(block_order_.length()), | 68 live_out_(block_order_.length()), |
| 68 kill_(block_order_.length()), | 69 kill_(block_order_.length()), |
| 69 live_in_(block_order_.length()), | 70 live_in_(block_order_.length()), |
| 70 vreg_count_(flow_graph.max_virtual_register_number()), | 71 vreg_count_(flow_graph.max_virtual_register_number()), |
| 71 live_ranges_(flow_graph.max_virtual_register_number()), | 72 live_ranges_(flow_graph.max_virtual_register_number()), |
| 72 cpu_regs_(), | 73 cpu_regs_(), |
| 73 xmm_regs_(), | 74 xmm_regs_(), |
| 74 blocked_cpu_registers_(), | 75 blocked_cpu_registers_(), |
| (...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 385 // Shrink the first use interval. It was optimistically expanded to | 386 // Shrink the first use interval. It was optimistically expanded to |
| 386 // cover the the block from the start to the last use in the block. | 387 // cover the the block from the start to the last use in the block. |
| 387 ASSERT(first_use_interval_->start_ <= pos); | 388 ASSERT(first_use_interval_->start_ <= pos); |
| 388 first_use_interval_->start_ = pos; | 389 first_use_interval_->start_ = pos; |
| 389 } | 390 } |
| 390 } | 391 } |
| 391 | 392 |
| 392 | 393 |
| 393 LiveRange* FlowGraphAllocator::GetLiveRange(intptr_t vreg) { | 394 LiveRange* FlowGraphAllocator::GetLiveRange(intptr_t vreg) { |
| 394 if (live_ranges_[vreg] == NULL) { | 395 if (live_ranges_[vreg] == NULL) { |
| 395 live_ranges_[vreg] = new LiveRange(vreg); | 396 Location::Representation rep = |
| 397 reps_->Contains(vreg) ? Location::kMint : Location::kDouble; |
| 398 live_ranges_[vreg] = new LiveRange(vreg, rep); |
| 396 } | 399 } |
| 397 return live_ranges_[vreg]; | 400 return live_ranges_[vreg]; |
| 398 } | 401 } |
| 399 | 402 |
| 400 | 403 |
| 401 LiveRange* FlowGraphAllocator::MakeLiveRangeForTemporary() { | 404 LiveRange* FlowGraphAllocator::MakeLiveRangeForTemporary() { |
| 402 LiveRange* range = new LiveRange(kTempVirtualRegister); | 405 Location::Representation ignored = Location::kDouble; |
| 406 LiveRange* range = new LiveRange(kTempVirtualRegister, ignored); |
| 403 #if defined(DEBUG) | 407 #if defined(DEBUG) |
| 404 temporaries_.Add(range); | 408 temporaries_.Add(range); |
| 405 #endif | 409 #endif |
| 406 return range; | 410 return range; |
| 407 } | 411 } |
| 408 | 412 |
| 409 | 413 |
| 410 void FlowGraphAllocator::BlockRegisterLocation(Location loc, | 414 void FlowGraphAllocator::BlockRegisterLocation(Location loc, |
| 411 intptr_t from, | 415 intptr_t from, |
| 412 intptr_t to, | 416 intptr_t to, |
| 413 bool* blocked_registers, | 417 bool* blocked_registers, |
| 414 LiveRange** blocking_ranges) { | 418 LiveRange** blocking_ranges) { |
| 415 if (blocked_registers[loc.register_code()]) { | 419 if (blocked_registers[loc.register_code()]) { |
| 416 return; | 420 return; |
| 417 } | 421 } |
| 418 | 422 |
| 419 if (blocking_ranges[loc.register_code()] == NULL) { | 423 if (blocking_ranges[loc.register_code()] == NULL) { |
| 420 LiveRange* range = new LiveRange(kNoVirtualRegister); | 424 Location::Representation ignored = Location::kDouble; |
| 425 LiveRange* range = new LiveRange(kNoVirtualRegister, ignored); |
| 421 blocking_ranges[loc.register_code()] = range; | 426 blocking_ranges[loc.register_code()] = range; |
| 422 range->set_assigned_location(loc); | 427 range->set_assigned_location(loc); |
| 423 #if defined(DEBUG) | 428 #if defined(DEBUG) |
| 424 temporaries_.Add(range); | 429 temporaries_.Add(range); |
| 425 #endif | 430 #endif |
| 426 } | 431 } |
| 427 | 432 |
| 428 blocking_ranges[loc.register_code()]->AddUseInterval(from, to); | 433 blocking_ranges[loc.register_code()]->AddUseInterval(from, to); |
| 429 } | 434 } |
| 430 | 435 |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 574 static Location::Kind RegisterKindFromPolicy(Location loc) { | 579 static Location::Kind RegisterKindFromPolicy(Location loc) { |
| 575 if (loc.policy() == Location::kRequiresXmmRegister) { | 580 if (loc.policy() == Location::kRequiresXmmRegister) { |
| 576 return Location::kXmmRegister; | 581 return Location::kXmmRegister; |
| 577 } else { | 582 } else { |
| 578 return Location::kRegister; | 583 return Location::kRegister; |
| 579 } | 584 } |
| 580 } | 585 } |
| 581 | 586 |
| 582 | 587 |
| 583 static Location::Kind RegisterKindForResult(Instruction* instr) { | 588 static Location::Kind RegisterKindForResult(Instruction* instr) { |
| 584 if (instr->representation() == kUnboxedDouble) { | 589 if (instr->representation() == kUnboxedDouble || |
| 590 instr->representation() == kUnboxedInteger) { |
| 585 return Location::kXmmRegister; | 591 return Location::kXmmRegister; |
| 586 } else { | 592 } else { |
| 587 return Location::kRegister; | 593 return Location::kRegister; |
| 588 } | 594 } |
| 589 } | 595 } |
| 590 | 596 |
| 591 | 597 |
| 592 // | 598 // |
| 593 // When describing shape of live ranges in comments below we are going to use | 599 // When describing shape of live ranges in comments below we are going to use |
| 594 // the following notation: | 600 // the following notation: |
| (...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 906 // [--) | 912 // [--) |
| 907 // | 913 // |
| 908 // The stack bitmap describes the position i. | 914 // The stack bitmap describes the position i. |
| 909 for (intptr_t reg = 0; reg < kNumberOfCpuRegisters; reg++) { | 915 for (intptr_t reg = 0; reg < kNumberOfCpuRegisters; reg++) { |
| 910 BlockLocation(Location::RegisterLocation(static_cast<Register>(reg)), | 916 BlockLocation(Location::RegisterLocation(static_cast<Register>(reg)), |
| 911 pos, | 917 pos, |
| 912 pos + 1); | 918 pos + 1); |
| 913 } | 919 } |
| 914 | 920 |
| 915 for (intptr_t reg = 0; reg < kNumberOfXmmRegisters; reg++) { | 921 for (intptr_t reg = 0; reg < kNumberOfXmmRegisters; reg++) { |
| 922 Location::Representation ignored = Location::kDouble; |
| 916 BlockLocation( | 923 BlockLocation( |
| 917 Location::XmmRegisterLocation(static_cast<XmmRegister>(reg)), | 924 Location::XmmRegisterLocation(static_cast<XmmRegister>(reg), ignored), |
| 918 pos, | 925 pos, |
| 919 pos + 1); | 926 pos + 1); |
| 920 } | 927 } |
| 921 | 928 |
| 922 | 929 |
| 923 #if defined(DEBUG) | 930 #if defined(DEBUG) |
| 924 // Verify that temps, inputs and output were specified as fixed | 931 // Verify that temps, inputs and output were specified as fixed |
| 925 // locations. Every register is blocked now so attempt to | 932 // locations. Every register is blocked now so attempt to |
| 926 // allocate will not succeed. | 933 // allocate will not succeed. |
| 927 for (intptr_t j = 0; j < locs->temp_count(); j++) { | 934 for (intptr_t j = 0; j < locs->temp_count(); j++) { |
| (...skipping 447 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1375 | 1382 |
| 1376 UsePosition* first_use_after_split = | 1383 UsePosition* first_use_after_split = |
| 1377 SplitListOfPositions(&uses_, split_pos, split_at_start); | 1384 SplitListOfPositions(&uses_, split_pos, split_at_start); |
| 1378 | 1385 |
| 1379 SafepointPosition* first_safepoint_after_split = | 1386 SafepointPosition* first_safepoint_after_split = |
| 1380 SplitListOfPositions(&first_safepoint_, split_pos, split_at_start); | 1387 SplitListOfPositions(&first_safepoint_, split_pos, split_at_start); |
| 1381 | 1388 |
| 1382 UseInterval* last_use_interval = (last_before_split == last_use_interval_) ? | 1389 UseInterval* last_use_interval = (last_before_split == last_use_interval_) ? |
| 1383 first_after_split : last_use_interval_; | 1390 first_after_split : last_use_interval_; |
| 1384 next_sibling_ = new LiveRange(vreg(), | 1391 next_sibling_ = new LiveRange(vreg(), |
| 1392 representation(), |
| 1385 first_use_after_split, | 1393 first_use_after_split, |
| 1386 first_after_split, | 1394 first_after_split, |
| 1387 last_use_interval, | 1395 last_use_interval, |
| 1388 first_safepoint_after_split, | 1396 first_safepoint_after_split, |
| 1389 next_sibling_); | 1397 next_sibling_); |
| 1390 | 1398 |
| 1391 TRACE_ALLOC(OS::Print(" split sibling [%"Pd", %"Pd")\n", | 1399 TRACE_ALLOC(OS::Print(" split sibling [%"Pd", %"Pd")\n", |
| 1392 next_sibling_->Start(), next_sibling_->End())); | 1400 next_sibling_->Start(), next_sibling_->End())); |
| 1393 | 1401 |
| 1394 last_use_interval_ = last_before_split; | 1402 last_use_interval_ = last_before_split; |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1489 range->set_spill_slot(Location::StackSlot(idx)); | 1497 range->set_spill_slot(Location::StackSlot(idx)); |
| 1490 } else { | 1498 } else { |
| 1491 // Double spill slots are essentially one (x64) or two (ia32) normal | 1499 // Double spill slots are essentially one (x64) or two (ia32) normal |
| 1492 // word size spill slots. We use the index of the slot with the lowest | 1500 // word size spill slots. We use the index of the slot with the lowest |
| 1493 // address as an index for the double spill slot. In terms of indexes | 1501 // address as an index for the double spill slot. In terms of indexes |
| 1494 // this relation is inverted: so we have to take the highest index. | 1502 // this relation is inverted: so we have to take the highest index. |
| 1495 const intptr_t slot_idx = | 1503 const intptr_t slot_idx = |
| 1496 idx * kDoubleSpillSlotFactor + (kDoubleSpillSlotFactor - 1); | 1504 idx * kDoubleSpillSlotFactor + (kDoubleSpillSlotFactor - 1); |
| 1497 range->set_spill_slot( | 1505 range->set_spill_slot( |
| 1498 Location::DoubleStackSlot( | 1506 Location::DoubleStackSlot( |
| 1499 cpu_spill_slot_count_ + slot_idx)); | 1507 cpu_spill_slot_count_ + slot_idx, range->representation())); |
| 1500 } | 1508 } |
| 1501 | 1509 |
| 1502 spilled_.Add(range); | 1510 spilled_.Add(range); |
| 1503 } | 1511 } |
| 1504 | 1512 |
| 1505 | 1513 |
| 1506 void FlowGraphAllocator::MarkAsObjectAtSafepoints(LiveRange* range) { | 1514 void FlowGraphAllocator::MarkAsObjectAtSafepoints(LiveRange* range) { |
| 1507 intptr_t stack_index = range->spill_slot().stack_index(); | 1515 intptr_t stack_index = range->spill_slot().stack_index(); |
| 1508 ASSERT(stack_index >= 0); | 1516 ASSERT(stack_index >= 0); |
| 1509 | 1517 |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1590 free_until = intersection; | 1598 free_until = intersection; |
| 1591 if (free_until == kMaxPosition) break; | 1599 if (free_until == kMaxPosition) break; |
| 1592 } | 1600 } |
| 1593 } | 1601 } |
| 1594 } | 1602 } |
| 1595 | 1603 |
| 1596 // All registers are blocked by active ranges. | 1604 // All registers are blocked by active ranges. |
| 1597 if (free_until <= unallocated->Start()) return false; | 1605 if (free_until <= unallocated->Start()) return false; |
| 1598 | 1606 |
| 1599 TRACE_ALLOC(OS::Print("assigning free register ")); | 1607 TRACE_ALLOC(OS::Print("assigning free register ")); |
| 1600 TRACE_ALLOC(MakeRegisterLocation(candidate).Print()); | 1608 TRACE_ALLOC(MakeRegisterLocation(candidate, Location::kDouble).Print()); |
| 1601 TRACE_ALLOC(OS::Print(" to %"Pd"\n", unallocated->vreg())); | 1609 TRACE_ALLOC(OS::Print(" to %"Pd"\n", unallocated->vreg())); |
| 1602 | 1610 |
| 1603 if (free_until != kMaxPosition) { | 1611 if (free_until != kMaxPosition) { |
| 1604 // There was an intersection. Split unallocated. | 1612 // There was an intersection. Split unallocated. |
| 1605 TRACE_ALLOC(OS::Print(" splitting at %"Pd"\n", free_until)); | 1613 TRACE_ALLOC(OS::Print(" splitting at %"Pd"\n", free_until)); |
| 1606 LiveRange* tail = unallocated->SplitAt(free_until); | 1614 LiveRange* tail = unallocated->SplitAt(free_until); |
| 1607 AddToUnallocated(tail); | 1615 AddToUnallocated(tail); |
| 1608 } | 1616 } |
| 1609 | 1617 |
| 1610 registers_[candidate].Add(unallocated); | 1618 registers_[candidate].Add(unallocated); |
| 1611 unallocated->set_assigned_location(MakeRegisterLocation(candidate)); | 1619 unallocated->set_assigned_location( |
| 1620 MakeRegisterLocation(candidate, unallocated->representation())); |
| 1612 | 1621 |
| 1613 return true; | 1622 return true; |
| 1614 } | 1623 } |
| 1615 | 1624 |
| 1616 | 1625 |
| 1617 void FlowGraphAllocator::AllocateAnyRegister(LiveRange* unallocated) { | 1626 void FlowGraphAllocator::AllocateAnyRegister(LiveRange* unallocated) { |
| 1618 UsePosition* register_use = | 1627 UsePosition* register_use = |
| 1619 unallocated->finger()->FirstRegisterUse(unallocated->Start()); | 1628 unallocated->finger()->FirstRegisterUse(unallocated->Start()); |
| 1620 if (register_use == NULL) { | 1629 if (register_use == NULL) { |
| 1621 Spill(unallocated); | 1630 Spill(unallocated); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1634 } | 1643 } |
| 1635 | 1644 |
| 1636 if (free_until < register_use->pos()) { | 1645 if (free_until < register_use->pos()) { |
| 1637 // Can't acquire free register. Spill until we really need one. | 1646 // Can't acquire free register. Spill until we really need one. |
| 1638 ASSERT(unallocated->Start() < ToInstructionStart(register_use->pos())); | 1647 ASSERT(unallocated->Start() < ToInstructionStart(register_use->pos())); |
| 1639 SpillBetween(unallocated, unallocated->Start(), register_use->pos()); | 1648 SpillBetween(unallocated, unallocated->Start(), register_use->pos()); |
| 1640 return; | 1649 return; |
| 1641 } | 1650 } |
| 1642 | 1651 |
| 1643 TRACE_ALLOC(OS::Print("assigning blocked register ")); | 1652 TRACE_ALLOC(OS::Print("assigning blocked register ")); |
| 1644 TRACE_ALLOC(MakeRegisterLocation(candidate).Print()); | 1653 TRACE_ALLOC(MakeRegisterLocation(candidate, Location::kDouble).Print()); |
| 1645 TRACE_ALLOC(OS::Print(" to live range %"Pd" until %"Pd"\n", | 1654 TRACE_ALLOC(OS::Print(" to live range %"Pd" until %"Pd"\n", |
| 1646 unallocated->vreg(), blocked_at)); | 1655 unallocated->vreg(), blocked_at)); |
| 1647 | 1656 |
| 1648 if (blocked_at < unallocated->End()) { | 1657 if (blocked_at < unallocated->End()) { |
| 1649 // Register is blocked before the end of the live range. Split the range | 1658 // Register is blocked before the end of the live range. Split the range |
| 1650 // at latest at blocked_at position. | 1659 // at latest at blocked_at position. |
| 1651 LiveRange* tail = SplitBetween(unallocated, | 1660 LiveRange* tail = SplitBetween(unallocated, |
| 1652 unallocated->Start(), | 1661 unallocated->Start(), |
| 1653 blocked_at + 1); | 1662 blocked_at + 1); |
| 1654 AddToUnallocated(tail); | 1663 AddToUnallocated(tail); |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1740 } | 1749 } |
| 1741 registers_[reg][i] = NULL; | 1750 registers_[reg][i] = NULL; |
| 1742 first_evicted = i; | 1751 first_evicted = i; |
| 1743 } | 1752 } |
| 1744 } | 1753 } |
| 1745 | 1754 |
| 1746 // Remove evicted ranges from the array. | 1755 // Remove evicted ranges from the array. |
| 1747 if (first_evicted != -1) RemoveEvicted(reg, first_evicted); | 1756 if (first_evicted != -1) RemoveEvicted(reg, first_evicted); |
| 1748 | 1757 |
| 1749 registers_[reg].Add(unallocated); | 1758 registers_[reg].Add(unallocated); |
| 1750 unallocated->set_assigned_location(MakeRegisterLocation(reg)); | 1759 unallocated->set_assigned_location( |
| 1760 MakeRegisterLocation(reg, unallocated->representation())); |
| 1751 } | 1761 } |
| 1752 | 1762 |
| 1753 | 1763 |
| 1754 bool FlowGraphAllocator::EvictIntersection(LiveRange* allocated, | 1764 bool FlowGraphAllocator::EvictIntersection(LiveRange* allocated, |
| 1755 LiveRange* unallocated) { | 1765 LiveRange* unallocated) { |
| 1756 UseInterval* first_unallocated = | 1766 UseInterval* first_unallocated = |
| 1757 unallocated->finger()->first_pending_use_interval(); | 1767 unallocated->finger()->first_pending_use_interval(); |
| 1758 const intptr_t intersection = FirstIntersection( | 1768 const intptr_t intersection = FirstIntersection( |
| 1759 allocated->finger()->first_pending_use_interval(), | 1769 allocated->finger()->first_pending_use_interval(), |
| 1760 first_unallocated); | 1770 first_unallocated); |
| (...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2131 ASSERT(range->assigned_location().Equals(range->spill_slot())); | 2141 ASSERT(range->assigned_location().Equals(range->spill_slot())); |
| 2132 } else { | 2142 } else { |
| 2133 AddMoveAt(range->Start() + 1, | 2143 AddMoveAt(range->Start() + 1, |
| 2134 range->spill_slot(), | 2144 range->spill_slot(), |
| 2135 range->assigned_location()); | 2145 range->assigned_location()); |
| 2136 } | 2146 } |
| 2137 } | 2147 } |
| 2138 } | 2148 } |
| 2139 | 2149 |
| 2140 | 2150 |
| 2151 void FlowGraphAllocator::CollectRepresentations() { |
| 2152 reps_ = new BitVector(flow_graph_.max_virtual_register_number()); |
| 2153 |
| 2154 for (BlockIterator it = flow_graph_.reverse_postorder_iterator(); |
| 2155 !it.Done(); |
| 2156 it.Advance()) { |
| 2157 BlockEntryInstr* block = it.Current(); |
| 2158 // TODO(fschneider): Support unboxed mint representation for phis. |
| 2159 for (ForwardInstructionIterator instr_it(block); |
| 2160 !instr_it.Done(); |
| 2161 instr_it.Advance()) { |
| 2162 Instruction* instr = instr_it.Current(); |
| 2163 if (instr->IsDefinition() && instr->representation() == kUnboxedInteger) { |
| 2164 reps_->Add(instr->AsDefinition()->ssa_temp_index()); |
| 2165 } |
| 2166 } |
| 2167 } |
| 2168 } |
| 2169 |
| 2170 |
| 2171 |
| 2141 void FlowGraphAllocator::AllocateRegisters() { | 2172 void FlowGraphAllocator::AllocateRegisters() { |
| 2173 CollectRepresentations(); |
| 2174 |
| 2142 EliminateEnvironmentUses(); | 2175 EliminateEnvironmentUses(); |
| 2143 | 2176 |
| 2144 AnalyzeLiveness(); | 2177 AnalyzeLiveness(); |
| 2145 | 2178 |
| 2146 NumberInstructions(); | 2179 NumberInstructions(); |
| 2147 | 2180 |
| 2148 DiscoverLoops(); | 2181 DiscoverLoops(); |
| 2149 | 2182 |
| 2150 BuildLiveRanges(); | 2183 BuildLiveRanges(); |
| 2151 | 2184 |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2204 OS::Print("-- [after ssa allocator] ir [%s] -------------\n", | 2237 OS::Print("-- [after ssa allocator] ir [%s] -------------\n", |
| 2205 function.ToFullyQualifiedCString()); | 2238 function.ToFullyQualifiedCString()); |
| 2206 FlowGraphPrinter printer(flow_graph_, true); | 2239 FlowGraphPrinter printer(flow_graph_, true); |
| 2207 printer.PrintBlocks(); | 2240 printer.PrintBlocks(); |
| 2208 OS::Print("----------------------------------------------\n"); | 2241 OS::Print("----------------------------------------------\n"); |
| 2209 } | 2242 } |
| 2210 } | 2243 } |
| 2211 | 2244 |
| 2212 | 2245 |
| 2213 } // namespace dart | 2246 } // namespace dart |
| OLD | NEW |