| 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 478 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 489 #endif | 489 #endif |
| 490 | 490 |
| 491 for (intptr_t i = 0; i < live_ranges_.length(); i++) { | 491 for (intptr_t i = 0; i < live_ranges_.length(); i++) { |
| 492 if (live_ranges_[i] != NULL) { | 492 if (live_ranges_[i] != NULL) { |
| 493 live_ranges_[i]->Print(); | 493 live_ranges_[i]->Print(); |
| 494 } | 494 } |
| 495 } | 495 } |
| 496 } | 496 } |
| 497 | 497 |
| 498 | 498 |
| 499 // Returns true if all uses of the given range inside the given loop |
| 500 // have Any allocation policy. |
| 501 static bool HasOnlyUnconstrainedUsesInLoop(LiveRange* range, |
| 502 BlockInfo* loop_header) { |
| 503 const intptr_t boundary = loop_header->last_block()->end_pos(); |
| 504 |
| 505 UsePosition* use = range->first_use(); |
| 506 while ((use != NULL) && (use->pos() < boundary)) { |
| 507 if (!use->location_slot()->Equals(Location::Any())) { |
| 508 return false; |
| 509 } |
| 510 use = use->next(); |
| 511 } |
| 512 |
| 513 return true; |
| 514 } |
| 515 |
| 516 |
| 499 void FlowGraphAllocator::BuildLiveRanges() { | 517 void FlowGraphAllocator::BuildLiveRanges() { |
| 500 const intptr_t block_count = postorder_.length(); | 518 const intptr_t block_count = postorder_.length(); |
| 501 ASSERT(postorder_.Last()->IsGraphEntry()); | 519 ASSERT(postorder_.Last()->IsGraphEntry()); |
| 502 for (intptr_t i = 0; i < (block_count - 1); i++) { | 520 for (intptr_t i = 0; i < (block_count - 1); i++) { |
| 503 BlockEntryInstr* block = postorder_[i]; | 521 BlockEntryInstr* block = postorder_[i]; |
| 504 | 522 |
| 505 // For every SSA value that is live out of this block, create an interval | 523 // For every SSA value that is live out of this block, create an interval |
| 506 // that covers the whole block. It will be shortened if we encounter a | 524 // that covers the whole block. It will be shortened if we encounter a |
| 507 // definition of this value in this block. | 525 // definition of this value in this block. |
| 508 for (BitVector::Iterator it(live_out_[i]); !it.Done(); it.Advance()) { | 526 for (BitVector::Iterator it(live_out_[i]); !it.Done(); it.Advance()) { |
| 509 LiveRange* range = GetLiveRange(it.Current()); | 527 LiveRange* range = GetLiveRange(it.Current()); |
| 510 range->AddUseInterval(block->start_pos(), block->end_pos()); | 528 range->AddUseInterval(block->start_pos(), block->end_pos()); |
| 511 } | 529 } |
| 512 | 530 |
| 513 // Connect outgoing phi-moves that were created in NumberInstructions | 531 // Connect outgoing phi-moves that were created in NumberInstructions |
| 514 // and find last instruction that contributes to liveness. | 532 // and find last instruction that contributes to liveness. |
| 515 Instruction* current = ConnectOutgoingPhiMoves(block); | 533 Instruction* current = ConnectOutgoingPhiMoves(block); |
| 516 | 534 |
| 517 // Now process all instructions in reverse order. | 535 // Now process all instructions in reverse order. |
| 518 while (current != block) { | 536 while (current != block) { |
| 519 // Skip parallel moves that we insert while processing instructions. | 537 // Skip parallel moves that we insert while processing instructions. |
| 520 if (!current->IsParallelMove()) { | 538 if (!current->IsParallelMove()) { |
| 521 ProcessOneInstruction(block, current); | 539 ProcessOneInstruction(block, current); |
| 522 } | 540 } |
| 523 current = current->previous(); | 541 current = current->previous(); |
| 524 } | 542 } |
| 525 | 543 |
| 544 |
| 545 // Check if any values live into the loop can be spilled for free. |
| 546 BlockInfo* block_info = BlockInfoAt(block->start_pos()); |
| 547 if (block_info->is_loop_header()) { |
| 548 for (BitVector::Iterator it(live_in_[i]); !it.Done(); it.Advance()) { |
| 549 LiveRange* range = GetLiveRange(it.Current()); |
| 550 if (HasOnlyUnconstrainedUsesInLoop(range, block_info)) { |
| 551 range->MarkHasOnlyUnconstrainedUsesInLoop(block_info->loop_id()); |
| 552 } |
| 553 } |
| 554 } |
| 555 |
| 526 ConnectIncomingPhiMoves(block); | 556 ConnectIncomingPhiMoves(block); |
| 527 } | 557 } |
| 528 | 558 |
| 529 // Process incoming parameters and constants. Do this after all other | 559 // Process incoming parameters and constants. Do this after all other |
| 530 // instructions so that safepoints for all calls have already been found. | 560 // instructions so that safepoints for all calls have already been found. |
| 531 GraphEntryInstr* graph_entry = flow_graph_.graph_entry(); | 561 GraphEntryInstr* graph_entry = flow_graph_.graph_entry(); |
| 532 for (intptr_t i = 0; i < graph_entry->initial_definitions()->length(); i++) { | 562 for (intptr_t i = 0; i < graph_entry->initial_definitions()->length(); i++) { |
| 533 Definition* defn = (*graph_entry->initial_definitions())[i]; | 563 Definition* defn = (*graph_entry->initial_definitions())[i]; |
| 534 LiveRange* range = GetLiveRange(defn->ssa_temp_index()); | 564 LiveRange* range = GetLiveRange(defn->ssa_temp_index()); |
| 535 range->AddUseInterval(graph_entry->start_pos(), graph_entry->end_pos()); | 565 range->AddUseInterval(graph_entry->start_pos(), graph_entry->end_pos()); |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 702 ASSERT(vreg != -1); | 732 ASSERT(vreg != -1); |
| 703 | 733 |
| 704 // Expected shape of live range: | 734 // Expected shape of live range: |
| 705 // | 735 // |
| 706 // B | 736 // B |
| 707 // phi [-------- | 737 // phi [-------- |
| 708 // | 738 // |
| 709 LiveRange* range = GetLiveRange(vreg); | 739 LiveRange* range = GetLiveRange(vreg); |
| 710 range->DefineAt(pos); // Shorten live range. | 740 range->DefineAt(pos); // Shorten live range. |
| 711 | 741 |
| 742 if (join->loop_info() != NULL) range->mark_loop_phi(); |
| 743 |
| 712 for (intptr_t pred_idx = 0; pred_idx < phi->InputCount(); pred_idx++) { | 744 for (intptr_t pred_idx = 0; pred_idx < phi->InputCount(); pred_idx++) { |
| 713 BlockEntryInstr* pred = block->PredecessorAt(pred_idx); | 745 BlockEntryInstr* pred = block->PredecessorAt(pred_idx); |
| 714 GotoInstr* goto_instr = pred->last_instruction()->AsGoto(); | 746 GotoInstr* goto_instr = pred->last_instruction()->AsGoto(); |
| 715 ASSERT((goto_instr != NULL) && (goto_instr->HasParallelMove())); | 747 ASSERT((goto_instr != NULL) && (goto_instr->HasParallelMove())); |
| 716 MoveOperands* move = | 748 MoveOperands* move = |
| 717 goto_instr->parallel_move()->MoveOperandsAt(move_idx); | 749 goto_instr->parallel_move()->MoveOperandsAt(move_idx); |
| 718 move->set_dest(Location::PrefersRegister()); | 750 move->set_dest(Location::PrefersRegister()); |
| 719 range->AddUse(pos, move->dest_slot()); | 751 range->AddUse(pos, move->dest_slot()); |
| 720 } | 752 } |
| 721 | 753 |
| (...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1012 ASSERT(locs->in(0).Equals(Location::RequiresRegister()) || | 1044 ASSERT(locs->in(0).Equals(Location::RequiresRegister()) || |
| 1013 locs->in(0).Equals(Location::RequiresXmmRegister())); | 1045 locs->in(0).Equals(Location::RequiresXmmRegister())); |
| 1014 | 1046 |
| 1015 // Create move that will copy value between input and output. | 1047 // Create move that will copy value between input and output. |
| 1016 locs->set_out(Location::RequiresRegister()); | 1048 locs->set_out(Location::RequiresRegister()); |
| 1017 MoveOperands* move = AddMoveAt(pos, | 1049 MoveOperands* move = AddMoveAt(pos, |
| 1018 Location::RequiresRegister(), | 1050 Location::RequiresRegister(), |
| 1019 Location::Any()); | 1051 Location::Any()); |
| 1020 | 1052 |
| 1021 // Add uses to the live range of the input. | 1053 // Add uses to the live range of the input. |
| 1022 Value* input = current->InputAt(0); | 1054 Definition* input = current->InputAt(0)->definition(); |
| 1023 LiveRange* input_range = | 1055 LiveRange* input_range = |
| 1024 GetLiveRange(input->definition()->ssa_temp_index()); | 1056 GetLiveRange(input->ssa_temp_index()); |
| 1025 input_range->AddUseInterval(block->start_pos(), pos); | 1057 input_range->AddUseInterval(block->start_pos(), pos); |
| 1026 input_range->AddUse(pos, move->src_slot()); | 1058 input_range->AddUse(pos, move->src_slot()); |
| 1027 | 1059 |
| 1028 // Shorten output live range to the point of definition and add both input | 1060 // Shorten output live range to the point of definition and add both input |
| 1029 // and output uses slots to be filled by allocator. | 1061 // and output uses slots to be filled by allocator. |
| 1030 range->DefineAt(pos); | 1062 range->DefineAt(pos); |
| 1031 range->AddHintedUse(pos, out, move->src_slot()); | 1063 range->AddHintedUse(pos, out, move->src_slot()); |
| 1032 range->AddUse(pos, move->dest_slot()); | 1064 range->AddUse(pos, move->dest_slot()); |
| 1033 range->AddUse(pos, locs->in_slot(0)); | 1065 range->AddUse(pos, locs->in_slot(0)); |
| 1034 } else { | 1066 } else { |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1141 | 1173 |
| 1142 // Discover structural (reducible) loops nesting structure. | 1174 // Discover structural (reducible) loops nesting structure. |
| 1143 void FlowGraphAllocator::DiscoverLoops() { | 1175 void FlowGraphAllocator::DiscoverLoops() { |
| 1144 // This algorithm relies on the assumption that we emit blocks in reverse | 1176 // This algorithm relies on the assumption that we emit blocks in reverse |
| 1145 // postorder, so postorder number can be used to identify loop nesting. | 1177 // postorder, so postorder number can be used to identify loop nesting. |
| 1146 // | 1178 // |
| 1147 // TODO(vegorov): consider using a generic algorithm to correctly discover | 1179 // TODO(vegorov): consider using a generic algorithm to correctly discover |
| 1148 // both headers of reducible and irreducible loops. | 1180 // both headers of reducible and irreducible loops. |
| 1149 BlockInfo* current_loop = NULL; | 1181 BlockInfo* current_loop = NULL; |
| 1150 | 1182 |
| 1183 intptr_t loop_id = 0; // All loop headers have a unique id. |
| 1184 |
| 1151 const intptr_t block_count = postorder_.length(); | 1185 const intptr_t block_count = postorder_.length(); |
| 1152 for (intptr_t i = 0; i < block_count; i++) { | 1186 for (intptr_t i = 0; i < block_count; i++) { |
| 1153 BlockEntryInstr* block = postorder_[i]; | 1187 BlockEntryInstr* block = postorder_[i]; |
| 1154 GotoInstr* goto_instr = block->last_instruction()->AsGoto(); | 1188 GotoInstr* goto_instr = block->last_instruction()->AsGoto(); |
| 1155 if (goto_instr != NULL) { | 1189 if (goto_instr != NULL) { |
| 1156 JoinEntryInstr* successor = goto_instr->successor(); | 1190 JoinEntryInstr* successor = goto_instr->successor(); |
| 1157 if (successor->postorder_number() > i) { | 1191 if (successor->postorder_number() > i) { |
| 1158 // This is back-edge. | 1192 // This is back-edge. |
| 1159 BlockInfo* successor_info = BlockInfoAt(successor->lifetime_position()); | 1193 BlockInfo* successor_info = BlockInfoAt(successor->lifetime_position()); |
| 1160 ASSERT(successor_info->entry() == successor); | 1194 ASSERT(successor_info->entry() == successor); |
| 1161 if (!successor_info->is_loop_header() && | 1195 if (!successor_info->is_loop_header() && |
| 1162 ((current_loop == NULL) || | 1196 ((current_loop == NULL) || |
| 1163 (current_loop->entry()->postorder_number() > | 1197 (current_loop->entry()->postorder_number() > |
| 1164 successor_info->entry()->postorder_number()))) { | 1198 successor_info->entry()->postorder_number()))) { |
| 1165 ASSERT(successor_info != current_loop); | 1199 ASSERT(successor_info != current_loop); |
| 1166 | 1200 |
| 1167 successor_info->mark_loop_header(); | 1201 successor_info->mark_loop_header(); |
| 1202 successor_info->set_loop_id(loop_id++); |
| 1203 successor_info->set_last_block(block); |
| 1168 // For loop header loop information points to the outer loop. | 1204 // For loop header loop information points to the outer loop. |
| 1169 successor_info->set_loop(current_loop); | 1205 successor_info->set_loop(current_loop); |
| 1170 current_loop = successor_info; | 1206 current_loop = successor_info; |
| 1171 } | 1207 } |
| 1172 } | 1208 } |
| 1173 } | 1209 } |
| 1174 | 1210 |
| 1175 if (current_loop != NULL) { | 1211 if (current_loop != NULL) { |
| 1176 BlockInfo* current_info = BlockInfoAt(block->lifetime_position()); | 1212 BlockInfo* current_info = BlockInfoAt(block->lifetime_position()); |
| 1177 if (current_info == current_loop) { | 1213 if (current_info == current_loop) { |
| (...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1464 } else { | 1500 } else { |
| 1465 // No intersection between tail and [from, to). | 1501 // No intersection between tail and [from, to). |
| 1466 AddToUnallocated(tail); | 1502 AddToUnallocated(tail); |
| 1467 } | 1503 } |
| 1468 } | 1504 } |
| 1469 | 1505 |
| 1470 | 1506 |
| 1471 void FlowGraphAllocator::SpillAfter(LiveRange* range, intptr_t from) { | 1507 void FlowGraphAllocator::SpillAfter(LiveRange* range, intptr_t from) { |
| 1472 TRACE_ALLOC(OS::Print("spill %"Pd" [%"Pd", %"Pd") after %"Pd"\n", | 1508 TRACE_ALLOC(OS::Print("spill %"Pd" [%"Pd", %"Pd") after %"Pd"\n", |
| 1473 range->vreg(), range->Start(), range->End(), from)); | 1509 range->vreg(), range->Start(), range->End(), from)); |
| 1510 |
| 1511 // When spilling the value inside the loop check if this spill can |
| 1512 // be moved outside. |
| 1513 BlockInfo* block_info = BlockInfoAt(from); |
| 1514 if (block_info->is_loop_header() || (block_info->loop() != NULL)) { |
| 1515 BlockInfo* loop_header = |
| 1516 block_info->is_loop_header() ? block_info : block_info->loop(); |
| 1517 |
| 1518 if ((range->Start() <= loop_header->entry()->start_pos()) && |
| 1519 RangeHasOnlyUnconstrainedUsesInLoop(range, loop_header->loop_id())) { |
| 1520 ASSERT(loop_header->entry()->start_pos() <= from); |
| 1521 from = loop_header->entry()->start_pos(); |
| 1522 TRACE_ALLOC(OS::Print(" moved spill position to loop header %"Pd"\n", |
| 1523 from)); |
| 1524 } |
| 1525 } |
| 1526 |
| 1474 LiveRange* tail = range->SplitAt(from); | 1527 LiveRange* tail = range->SplitAt(from); |
| 1475 Spill(tail); | 1528 Spill(tail); |
| 1476 } | 1529 } |
| 1477 | 1530 |
| 1478 | 1531 |
| 1479 void FlowGraphAllocator::AllocateSpillSlotFor(LiveRange* range) { | 1532 void FlowGraphAllocator::AllocateSpillSlotFor(LiveRange* range) { |
| 1480 ASSERT(range->spill_slot().IsInvalid()); | 1533 ASSERT(range->spill_slot().IsInvalid()); |
| 1481 | 1534 |
| 1482 intptr_t idx = 0; | 1535 intptr_t idx = 0; |
| 1483 for (; idx < spill_slots_.length(); idx++) { | 1536 for (; idx < spill_slots_.length(); idx++) { |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1616 } | 1669 } |
| 1617 | 1670 |
| 1618 registers_[candidate].Add(unallocated); | 1671 registers_[candidate].Add(unallocated); |
| 1619 unallocated->set_assigned_location( | 1672 unallocated->set_assigned_location( |
| 1620 MakeRegisterLocation(candidate, unallocated->representation())); | 1673 MakeRegisterLocation(candidate, unallocated->representation())); |
| 1621 | 1674 |
| 1622 return true; | 1675 return true; |
| 1623 } | 1676 } |
| 1624 | 1677 |
| 1625 | 1678 |
| 1679 bool FlowGraphAllocator::RangeHasOnlyUnconstrainedUsesInLoop(LiveRange* range, |
| 1680 intptr_t loop_id) { |
| 1681 if (range->vreg() >= 0) { |
| 1682 return GetLiveRange(range->vreg())->HasOnlyUnconstrainedUsesInLoop(loop_id); |
| 1683 } |
| 1684 return false; |
| 1685 } |
| 1686 |
| 1687 |
| 1688 bool FlowGraphAllocator::IsCheapToEvictRegisterInLoop(BlockInfo* loop, |
| 1689 intptr_t reg) { |
| 1690 const intptr_t loop_start = loop->entry()->start_pos(); |
| 1691 const intptr_t loop_end = loop->last_block()->end_pos(); |
| 1692 |
| 1693 for (intptr_t i = 0; i < registers_[reg].length(); i++) { |
| 1694 LiveRange* allocated = registers_[reg][i]; |
| 1695 |
| 1696 UseInterval* interval = allocated->finger()->first_pending_use_interval(); |
| 1697 if (interval->Contains(loop_start)) { |
| 1698 if (!RangeHasOnlyUnconstrainedUsesInLoop(allocated, loop->loop_id())) { |
| 1699 return false; |
| 1700 } |
| 1701 } else if (interval->start() < loop_end) { |
| 1702 return false; |
| 1703 } |
| 1704 } |
| 1705 |
| 1706 return true; |
| 1707 } |
| 1708 |
| 1709 |
| 1710 bool FlowGraphAllocator::HasCheapEvictionCandidate(LiveRange* phi_range) { |
| 1711 ASSERT(phi_range->is_loop_phi()); |
| 1712 |
| 1713 BlockInfo* loop_header = BlockInfoAt(phi_range->Start()); |
| 1714 ASSERT(loop_header->is_loop_header()); |
| 1715 ASSERT(phi_range->Start() == loop_header->entry()->start_pos()); |
| 1716 |
| 1717 for (intptr_t reg = 0; reg < NumberOfRegisters(); ++reg) { |
| 1718 if (blocked_registers_[reg]) continue; |
| 1719 if (IsCheapToEvictRegisterInLoop(loop_header, reg)) { |
| 1720 return true; |
| 1721 } |
| 1722 } |
| 1723 |
| 1724 return false; |
| 1725 } |
| 1726 |
| 1727 |
| 1626 void FlowGraphAllocator::AllocateAnyRegister(LiveRange* unallocated) { | 1728 void FlowGraphAllocator::AllocateAnyRegister(LiveRange* unallocated) { |
| 1729 // If a loop phi has no register uses we might still want to allocate it |
| 1730 // to the register to reduce amount of memory moves on the back edge. |
| 1731 // This is possible if there is a register blocked by a range that can be |
| 1732 // cheaply evicted i.e. it has no register beneficial uses inside the |
| 1733 // loop. |
| 1627 UsePosition* register_use = | 1734 UsePosition* register_use = |
| 1628 unallocated->finger()->FirstRegisterUse(unallocated->Start()); | 1735 unallocated->finger()->FirstRegisterUse(unallocated->Start()); |
| 1629 if (register_use == NULL) { | 1736 if ((register_use == NULL) && |
| 1737 !(unallocated->is_loop_phi() && HasCheapEvictionCandidate(unallocated))) { |
| 1630 Spill(unallocated); | 1738 Spill(unallocated); |
| 1631 return; | 1739 return; |
| 1632 } | 1740 } |
| 1633 | 1741 |
| 1634 intptr_t candidate = kNoRegister; | 1742 intptr_t candidate = kNoRegister; |
| 1635 intptr_t free_until = 0; | 1743 intptr_t free_until = 0; |
| 1636 intptr_t blocked_at = kMaxPosition; | 1744 intptr_t blocked_at = kMaxPosition; |
| 1637 | 1745 |
| 1638 for (int reg = 0; reg < NumberOfRegisters(); ++reg) { | 1746 for (int reg = 0; reg < NumberOfRegisters(); ++reg) { |
| 1639 if (blocked_registers_[reg]) continue; | 1747 if (blocked_registers_[reg]) continue; |
| 1640 if (UpdateFreeUntil(reg, unallocated, &free_until, &blocked_at)) { | 1748 if (UpdateFreeUntil(reg, unallocated, &free_until, &blocked_at)) { |
| 1641 candidate = reg; | 1749 candidate = reg; |
| 1642 } | 1750 } |
| 1643 } | 1751 } |
| 1644 | 1752 |
| 1645 if (free_until < register_use->pos()) { | 1753 const intptr_t register_use_pos = |
| 1754 (register_use != NULL) ? register_use->pos() |
| 1755 : unallocated->Start(); |
| 1756 if (free_until < register_use_pos) { |
| 1646 // Can't acquire free register. Spill until we really need one. | 1757 // Can't acquire free register. Spill until we really need one. |
| 1647 ASSERT(unallocated->Start() < ToInstructionStart(register_use->pos())); | 1758 ASSERT(unallocated->Start() < ToInstructionStart(register_use_pos)); |
| 1648 SpillBetween(unallocated, unallocated->Start(), register_use->pos()); | 1759 SpillBetween(unallocated, unallocated->Start(), register_use->pos()); |
| 1649 return; | 1760 return; |
| 1650 } | 1761 } |
| 1651 | 1762 |
| 1652 TRACE_ALLOC(OS::Print("assigning blocked register ")); | 1763 TRACE_ALLOC(OS::Print("assigning blocked register ")); |
| 1653 TRACE_ALLOC(MakeRegisterLocation(candidate, Location::kDouble).Print()); | 1764 TRACE_ALLOC(MakeRegisterLocation(candidate, Location::kDouble).Print()); |
| 1654 TRACE_ALLOC(OS::Print(" to live range %"Pd" until %"Pd"\n", | 1765 TRACE_ALLOC(OS::Print(" to live range %"Pd" until %"Pd"\n", |
| 1655 unallocated->vreg(), blocked_at)); | 1766 unallocated->vreg(), blocked_at)); |
| 1656 | 1767 |
| 1657 if (blocked_at < unallocated->End()) { | 1768 if (blocked_at < unallocated->End()) { |
| (...skipping 577 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2235 OS::Print("-- [after ssa allocator] ir [%s] -------------\n", | 2346 OS::Print("-- [after ssa allocator] ir [%s] -------------\n", |
| 2236 function.ToFullyQualifiedCString()); | 2347 function.ToFullyQualifiedCString()); |
| 2237 FlowGraphPrinter printer(flow_graph_, true); | 2348 FlowGraphPrinter printer(flow_graph_, true); |
| 2238 printer.PrintBlocks(); | 2349 printer.PrintBlocks(); |
| 2239 OS::Print("----------------------------------------------\n"); | 2350 OS::Print("----------------------------------------------\n"); |
| 2240 } | 2351 } |
| 2241 } | 2352 } |
| 2242 | 2353 |
| 2243 | 2354 |
| 2244 } // namespace dart | 2355 } // namespace dart |
| OLD | NEW |