| 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 mint_values_(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 mint_values_->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() == kUnboxedMint)) { |
| 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 312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 907 // [--) | 913 // [--) |
| 908 // | 914 // |
| 909 // The stack bitmap describes the position i. | 915 // The stack bitmap describes the position i. |
| 910 for (intptr_t reg = 0; reg < kNumberOfCpuRegisters; reg++) { | 916 for (intptr_t reg = 0; reg < kNumberOfCpuRegisters; reg++) { |
| 911 BlockLocation(Location::RegisterLocation(static_cast<Register>(reg)), | 917 BlockLocation(Location::RegisterLocation(static_cast<Register>(reg)), |
| 912 pos, | 918 pos, |
| 913 pos + 1); | 919 pos + 1); |
| 914 } | 920 } |
| 915 | 921 |
| 916 for (intptr_t reg = 0; reg < kNumberOfXmmRegisters; reg++) { | 922 for (intptr_t reg = 0; reg < kNumberOfXmmRegisters; reg++) { |
| 923 Location::Representation ignored = Location::kDouble; |
| 917 BlockLocation( | 924 BlockLocation( |
| 918 Location::XmmRegisterLocation(static_cast<XmmRegister>(reg)), | 925 Location::XmmRegisterLocation(static_cast<XmmRegister>(reg), ignored), |
| 919 pos, | 926 pos, |
| 920 pos + 1); | 927 pos + 1); |
| 921 } | 928 } |
| 922 | 929 |
| 923 | 930 |
| 924 #if defined(DEBUG) | 931 #if defined(DEBUG) |
| 925 // Verify that temps, inputs and output were specified as fixed | 932 // Verify that temps, inputs and output were specified as fixed |
| 926 // locations. Every register is blocked now so attempt to | 933 // locations. Every register is blocked now so attempt to |
| 927 // allocate will not succeed. | 934 // allocate will not succeed. |
| 928 for (intptr_t j = 0; j < locs->temp_count(); j++) { | 935 for (intptr_t j = 0; j < locs->temp_count(); j++) { |
| (...skipping 447 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1376 | 1383 |
| 1377 UsePosition* first_use_after_split = | 1384 UsePosition* first_use_after_split = |
| 1378 SplitListOfPositions(&uses_, split_pos, split_at_start); | 1385 SplitListOfPositions(&uses_, split_pos, split_at_start); |
| 1379 | 1386 |
| 1380 SafepointPosition* first_safepoint_after_split = | 1387 SafepointPosition* first_safepoint_after_split = |
| 1381 SplitListOfPositions(&first_safepoint_, split_pos, split_at_start); | 1388 SplitListOfPositions(&first_safepoint_, split_pos, split_at_start); |
| 1382 | 1389 |
| 1383 UseInterval* last_use_interval = (last_before_split == last_use_interval_) ? | 1390 UseInterval* last_use_interval = (last_before_split == last_use_interval_) ? |
| 1384 first_after_split : last_use_interval_; | 1391 first_after_split : last_use_interval_; |
| 1385 next_sibling_ = new LiveRange(vreg(), | 1392 next_sibling_ = new LiveRange(vreg(), |
| 1393 representation(), |
| 1386 first_use_after_split, | 1394 first_use_after_split, |
| 1387 first_after_split, | 1395 first_after_split, |
| 1388 last_use_interval, | 1396 last_use_interval, |
| 1389 first_safepoint_after_split, | 1397 first_safepoint_after_split, |
| 1390 next_sibling_); | 1398 next_sibling_); |
| 1391 | 1399 |
| 1392 TRACE_ALLOC(OS::Print(" split sibling [%"Pd", %"Pd")\n", | 1400 TRACE_ALLOC(OS::Print(" split sibling [%"Pd", %"Pd")\n", |
| 1393 next_sibling_->Start(), next_sibling_->End())); | 1401 next_sibling_->Start(), next_sibling_->End())); |
| 1394 | 1402 |
| 1395 last_use_interval_ = last_before_split; | 1403 last_use_interval_ = last_before_split; |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1490 range->set_spill_slot(Location::StackSlot(idx)); | 1498 range->set_spill_slot(Location::StackSlot(idx)); |
| 1491 } else { | 1499 } else { |
| 1492 // Double spill slots are essentially one (x64) or two (ia32) normal | 1500 // Double spill slots are essentially one (x64) or two (ia32) normal |
| 1493 // word size spill slots. We use the index of the slot with the lowest | 1501 // word size spill slots. We use the index of the slot with the lowest |
| 1494 // address as an index for the double spill slot. In terms of indexes | 1502 // address as an index for the double spill slot. In terms of indexes |
| 1495 // this relation is inverted: so we have to take the highest index. | 1503 // this relation is inverted: so we have to take the highest index. |
| 1496 const intptr_t slot_idx = | 1504 const intptr_t slot_idx = |
| 1497 idx * kDoubleSpillSlotFactor + (kDoubleSpillSlotFactor - 1); | 1505 idx * kDoubleSpillSlotFactor + (kDoubleSpillSlotFactor - 1); |
| 1498 range->set_spill_slot( | 1506 range->set_spill_slot( |
| 1499 Location::DoubleStackSlot( | 1507 Location::DoubleStackSlot( |
| 1500 cpu_spill_slot_count_ + slot_idx)); | 1508 cpu_spill_slot_count_ + slot_idx, range->representation())); |
| 1501 } | 1509 } |
| 1502 | 1510 |
| 1503 spilled_.Add(range); | 1511 spilled_.Add(range); |
| 1504 } | 1512 } |
| 1505 | 1513 |
| 1506 | 1514 |
| 1507 void FlowGraphAllocator::MarkAsObjectAtSafepoints(LiveRange* range) { | 1515 void FlowGraphAllocator::MarkAsObjectAtSafepoints(LiveRange* range) { |
| 1508 intptr_t stack_index = range->spill_slot().stack_index(); | 1516 intptr_t stack_index = range->spill_slot().stack_index(); |
| 1509 ASSERT(stack_index >= 0); | 1517 ASSERT(stack_index >= 0); |
| 1510 | 1518 |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1591 free_until = intersection; | 1599 free_until = intersection; |
| 1592 if (free_until == kMaxPosition) break; | 1600 if (free_until == kMaxPosition) break; |
| 1593 } | 1601 } |
| 1594 } | 1602 } |
| 1595 } | 1603 } |
| 1596 | 1604 |
| 1597 // All registers are blocked by active ranges. | 1605 // All registers are blocked by active ranges. |
| 1598 if (free_until <= unallocated->Start()) return false; | 1606 if (free_until <= unallocated->Start()) return false; |
| 1599 | 1607 |
| 1600 TRACE_ALLOC(OS::Print("assigning free register ")); | 1608 TRACE_ALLOC(OS::Print("assigning free register ")); |
| 1601 TRACE_ALLOC(MakeRegisterLocation(candidate).Print()); | 1609 TRACE_ALLOC(MakeRegisterLocation(candidate, Location::kDouble).Print()); |
| 1602 TRACE_ALLOC(OS::Print(" to %"Pd"\n", unallocated->vreg())); | 1610 TRACE_ALLOC(OS::Print(" to %"Pd"\n", unallocated->vreg())); |
| 1603 | 1611 |
| 1604 if (free_until != kMaxPosition) { | 1612 if (free_until != kMaxPosition) { |
| 1605 // There was an intersection. Split unallocated. | 1613 // There was an intersection. Split unallocated. |
| 1606 TRACE_ALLOC(OS::Print(" splitting at %"Pd"\n", free_until)); | 1614 TRACE_ALLOC(OS::Print(" splitting at %"Pd"\n", free_until)); |
| 1607 LiveRange* tail = unallocated->SplitAt(free_until); | 1615 LiveRange* tail = unallocated->SplitAt(free_until); |
| 1608 AddToUnallocated(tail); | 1616 AddToUnallocated(tail); |
| 1609 } | 1617 } |
| 1610 | 1618 |
| 1611 registers_[candidate].Add(unallocated); | 1619 registers_[candidate].Add(unallocated); |
| 1612 unallocated->set_assigned_location(MakeRegisterLocation(candidate)); | 1620 unallocated->set_assigned_location( |
| 1621 MakeRegisterLocation(candidate, unallocated->representation())); |
| 1613 | 1622 |
| 1614 return true; | 1623 return true; |
| 1615 } | 1624 } |
| 1616 | 1625 |
| 1617 | 1626 |
| 1618 void FlowGraphAllocator::AllocateAnyRegister(LiveRange* unallocated) { | 1627 void FlowGraphAllocator::AllocateAnyRegister(LiveRange* unallocated) { |
| 1619 UsePosition* register_use = | 1628 UsePosition* register_use = |
| 1620 unallocated->finger()->FirstRegisterUse(unallocated->Start()); | 1629 unallocated->finger()->FirstRegisterUse(unallocated->Start()); |
| 1621 if (register_use == NULL) { | 1630 if (register_use == NULL) { |
| 1622 Spill(unallocated); | 1631 Spill(unallocated); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1635 } | 1644 } |
| 1636 | 1645 |
| 1637 if (free_until < register_use->pos()) { | 1646 if (free_until < register_use->pos()) { |
| 1638 // Can't acquire free register. Spill until we really need one. | 1647 // Can't acquire free register. Spill until we really need one. |
| 1639 ASSERT(unallocated->Start() < ToInstructionStart(register_use->pos())); | 1648 ASSERT(unallocated->Start() < ToInstructionStart(register_use->pos())); |
| 1640 SpillBetween(unallocated, unallocated->Start(), register_use->pos()); | 1649 SpillBetween(unallocated, unallocated->Start(), register_use->pos()); |
| 1641 return; | 1650 return; |
| 1642 } | 1651 } |
| 1643 | 1652 |
| 1644 TRACE_ALLOC(OS::Print("assigning blocked register ")); | 1653 TRACE_ALLOC(OS::Print("assigning blocked register ")); |
| 1645 TRACE_ALLOC(MakeRegisterLocation(candidate).Print()); | 1654 TRACE_ALLOC(MakeRegisterLocation(candidate, Location::kDouble).Print()); |
| 1646 TRACE_ALLOC(OS::Print(" to live range %"Pd" until %"Pd"\n", | 1655 TRACE_ALLOC(OS::Print(" to live range %"Pd" until %"Pd"\n", |
| 1647 unallocated->vreg(), blocked_at)); | 1656 unallocated->vreg(), blocked_at)); |
| 1648 | 1657 |
| 1649 if (blocked_at < unallocated->End()) { | 1658 if (blocked_at < unallocated->End()) { |
| 1650 // Register is blocked before the end of the live range. Split the range | 1659 // Register is blocked before the end of the live range. Split the range |
| 1651 // at latest at blocked_at position. | 1660 // at latest at blocked_at position. |
| 1652 LiveRange* tail = SplitBetween(unallocated, | 1661 LiveRange* tail = SplitBetween(unallocated, |
| 1653 unallocated->Start(), | 1662 unallocated->Start(), |
| 1654 blocked_at + 1); | 1663 blocked_at + 1); |
| 1655 AddToUnallocated(tail); | 1664 AddToUnallocated(tail); |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1741 } | 1750 } |
| 1742 registers_[reg][i] = NULL; | 1751 registers_[reg][i] = NULL; |
| 1743 first_evicted = i; | 1752 first_evicted = i; |
| 1744 } | 1753 } |
| 1745 } | 1754 } |
| 1746 | 1755 |
| 1747 // Remove evicted ranges from the array. | 1756 // Remove evicted ranges from the array. |
| 1748 if (first_evicted != -1) RemoveEvicted(reg, first_evicted); | 1757 if (first_evicted != -1) RemoveEvicted(reg, first_evicted); |
| 1749 | 1758 |
| 1750 registers_[reg].Add(unallocated); | 1759 registers_[reg].Add(unallocated); |
| 1751 unallocated->set_assigned_location(MakeRegisterLocation(reg)); | 1760 unallocated->set_assigned_location( |
| 1761 MakeRegisterLocation(reg, unallocated->representation())); |
| 1752 } | 1762 } |
| 1753 | 1763 |
| 1754 | 1764 |
| 1755 bool FlowGraphAllocator::EvictIntersection(LiveRange* allocated, | 1765 bool FlowGraphAllocator::EvictIntersection(LiveRange* allocated, |
| 1756 LiveRange* unallocated) { | 1766 LiveRange* unallocated) { |
| 1757 UseInterval* first_unallocated = | 1767 UseInterval* first_unallocated = |
| 1758 unallocated->finger()->first_pending_use_interval(); | 1768 unallocated->finger()->first_pending_use_interval(); |
| 1759 const intptr_t intersection = FirstIntersection( | 1769 const intptr_t intersection = FirstIntersection( |
| 1760 allocated->finger()->first_pending_use_interval(), | 1770 allocated->finger()->first_pending_use_interval(), |
| 1761 first_unallocated); | 1771 first_unallocated); |
| (...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2132 ASSERT(range->assigned_location().Equals(range->spill_slot())); | 2142 ASSERT(range->assigned_location().Equals(range->spill_slot())); |
| 2133 } else { | 2143 } else { |
| 2134 AddMoveAt(range->Start() + 1, | 2144 AddMoveAt(range->Start() + 1, |
| 2135 range->spill_slot(), | 2145 range->spill_slot(), |
| 2136 range->assigned_location()); | 2146 range->assigned_location()); |
| 2137 } | 2147 } |
| 2138 } | 2148 } |
| 2139 } | 2149 } |
| 2140 | 2150 |
| 2141 | 2151 |
| 2152 void FlowGraphAllocator::CollectRepresentations() { |
| 2153 mint_values_ = new BitVector(flow_graph_.max_virtual_register_number()); |
| 2154 |
| 2155 for (BlockIterator it = flow_graph_.reverse_postorder_iterator(); |
| 2156 !it.Done(); |
| 2157 it.Advance()) { |
| 2158 BlockEntryInstr* block = it.Current(); |
| 2159 // TODO(fschneider): Support unboxed mint representation for phis. |
| 2160 for (ForwardInstructionIterator instr_it(block); |
| 2161 !instr_it.Done(); |
| 2162 instr_it.Advance()) { |
| 2163 Instruction* instr = instr_it.Current(); |
| 2164 if (instr->IsDefinition() && instr->representation() == kUnboxedMint) { |
| 2165 mint_values_->Add(instr->AsDefinition()->ssa_temp_index()); |
| 2166 } |
| 2167 } |
| 2168 } |
| 2169 } |
| 2170 |
| 2171 |
| 2172 |
| 2142 void FlowGraphAllocator::AllocateRegisters() { | 2173 void FlowGraphAllocator::AllocateRegisters() { |
| 2174 CollectRepresentations(); |
| 2175 |
| 2143 EliminateEnvironmentUses(); | 2176 EliminateEnvironmentUses(); |
| 2144 | 2177 |
| 2145 AnalyzeLiveness(); | 2178 AnalyzeLiveness(); |
| 2146 | 2179 |
| 2147 NumberInstructions(); | 2180 NumberInstructions(); |
| 2148 | 2181 |
| 2149 DiscoverLoops(); | 2182 DiscoverLoops(); |
| 2150 | 2183 |
| 2151 BuildLiveRanges(); | 2184 BuildLiveRanges(); |
| 2152 | 2185 |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2205 OS::Print("-- [after ssa allocator] ir [%s] -------------\n", | 2238 OS::Print("-- [after ssa allocator] ir [%s] -------------\n", |
| 2206 function.ToFullyQualifiedCString()); | 2239 function.ToFullyQualifiedCString()); |
| 2207 FlowGraphPrinter printer(flow_graph_, true); | 2240 FlowGraphPrinter printer(flow_graph_, true); |
| 2208 printer.PrintBlocks(); | 2241 printer.PrintBlocks(); |
| 2209 OS::Print("----------------------------------------------\n"); | 2242 OS::Print("----------------------------------------------\n"); |
| 2210 } | 2243 } |
| 2211 } | 2244 } |
| 2212 | 2245 |
| 2213 | 2246 |
| 2214 } // namespace dart | 2247 } // namespace dart |
| OLD | NEW |