Chromium Code Reviews| 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 reaching_defs_(flow_graph), | |
| 65 mint_values_(NULL), | 66 mint_values_(NULL), |
| 66 block_order_(flow_graph.reverse_postorder()), | 67 block_order_(flow_graph.reverse_postorder()), |
| 67 postorder_(flow_graph.postorder()), | 68 postorder_(flow_graph.postorder()), |
| 68 live_out_(block_order_.length()), | 69 live_out_(block_order_.length()), |
| 69 kill_(block_order_.length()), | 70 kill_(block_order_.length()), |
| 70 live_in_(block_order_.length()), | 71 live_in_(block_order_.length()), |
| 71 vreg_count_(flow_graph.max_virtual_register_number()), | 72 vreg_count_(flow_graph.max_virtual_register_number()), |
| 72 live_ranges_(flow_graph.max_virtual_register_number()), | 73 live_ranges_(flow_graph.max_virtual_register_number()), |
| 73 cpu_regs_(), | 74 cpu_regs_(), |
| 74 xmm_regs_(), | 75 xmm_regs_(), |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 139 Instruction* current = it.Current(); | 140 Instruction* current = it.Current(); |
| 140 | 141 |
| 141 // Handle definitions. | 142 // Handle definitions. |
| 142 Definition* current_def = current->AsDefinition(); | 143 Definition* current_def = current->AsDefinition(); |
| 143 if ((current_def != NULL) && current_def->HasSSATemp()) { | 144 if ((current_def != NULL) && current_def->HasSSATemp()) { |
| 144 kill->Add(current_def->ssa_temp_index()); | 145 kill->Add(current_def->ssa_temp_index()); |
| 145 live_in->Remove(current_def->ssa_temp_index()); | 146 live_in->Remove(current_def->ssa_temp_index()); |
| 146 } | 147 } |
| 147 | 148 |
| 148 // Handle uses. | 149 // Handle uses. |
| 150 LocationSummary* locs = current->locs(); | |
| 151 ASSERT(locs->input_count() == current->InputCount()); | |
| 149 for (intptr_t j = 0; j < current->InputCount(); j++) { | 152 for (intptr_t j = 0; j < current->InputCount(); j++) { |
| 150 Value* input = current->InputAt(j); | 153 Value* input = current->InputAt(j); |
| 151 const intptr_t use = input->definition()->ssa_temp_index(); | 154 const intptr_t use = input->definition()->ssa_temp_index(); |
| 155 | |
| 156 ASSERT(!locs->in(j).IsConstant() || input->BindsToConstant()); | |
| 157 if (locs->in(j).IsConstant()) continue; | |
| 158 | |
| 152 live_in->Add(use); | 159 live_in->Add(use); |
| 153 } | 160 } |
| 154 | 161 |
| 155 // Add non-argument uses from the deoptimization environment (pushed | 162 // Add non-argument uses from the deoptimization environment (pushed |
| 156 // arguments are not allocated by the register allocator). | 163 // arguments are not allocated by the register allocator). |
| 157 if (current->env() != NULL) { | 164 if (current->env() != NULL) { |
| 158 for (Environment::DeepIterator env_it(current->env()); | 165 for (Environment::DeepIterator env_it(current->env()); |
| 159 !env_it.Done(); | 166 !env_it.Done(); |
| 160 env_it.Advance()) { | 167 env_it.Advance()) { |
| 161 Value* value = env_it.CurrentValue(); | 168 Value* value = env_it.CurrentValue(); |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 175 PhiInstr* phi = (*join->phis())[j]; | 182 PhiInstr* phi = (*join->phis())[j]; |
| 176 if (phi == NULL) continue; | 183 if (phi == NULL) continue; |
| 177 | 184 |
| 178 kill->Add(phi->ssa_temp_index()); | 185 kill->Add(phi->ssa_temp_index()); |
| 179 live_in->Remove(phi->ssa_temp_index()); | 186 live_in->Remove(phi->ssa_temp_index()); |
| 180 | 187 |
| 181 // If phi-operand is not defined by a predecessor it must be marked | 188 // If phi-operand is not defined by a predecessor it must be marked |
| 182 // live-in for a predecessor. | 189 // live-in for a predecessor. |
| 183 for (intptr_t k = 0; k < phi->InputCount(); k++) { | 190 for (intptr_t k = 0; k < phi->InputCount(); k++) { |
| 184 Value* val = phi->InputAt(k); | 191 Value* val = phi->InputAt(k); |
| 192 if (val->BindsToConstant()) continue; | |
| 193 | |
| 185 BlockEntryInstr* pred = block->PredecessorAt(k); | 194 BlockEntryInstr* pred = block->PredecessorAt(k); |
| 186 const intptr_t use = val->definition()->ssa_temp_index(); | 195 const intptr_t use = val->definition()->ssa_temp_index(); |
| 187 if (!kill_[pred->postorder_number()]->Contains(use)) { | 196 if (!kill_[pred->postorder_number()]->Contains(use)) { |
| 188 live_in_[pred->postorder_number()]->Add(use); | 197 live_in_[pred->postorder_number()]->Add(use); |
| 189 } | 198 } |
| 190 } | 199 } |
| 191 } | 200 } |
| 192 } | 201 } |
| 193 } | 202 } |
| 194 } | 203 } |
| (...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 510 use = use->next(); | 519 use = use->next(); |
| 511 } | 520 } |
| 512 | 521 |
| 513 return true; | 522 return true; |
| 514 } | 523 } |
| 515 | 524 |
| 516 | 525 |
| 517 void FlowGraphAllocator::BuildLiveRanges() { | 526 void FlowGraphAllocator::BuildLiveRanges() { |
| 518 const intptr_t block_count = postorder_.length(); | 527 const intptr_t block_count = postorder_.length(); |
| 519 ASSERT(postorder_.Last()->IsGraphEntry()); | 528 ASSERT(postorder_.Last()->IsGraphEntry()); |
| 529 BitVector* current_interference_set = NULL; | |
| 520 for (intptr_t i = 0; i < (block_count - 1); i++) { | 530 for (intptr_t i = 0; i < (block_count - 1); i++) { |
| 521 BlockEntryInstr* block = postorder_[i]; | 531 BlockEntryInstr* block = postorder_[i]; |
| 522 | 532 |
| 533 BlockInfo* block_info = BlockInfoAt(block->start_pos()); | |
| 534 | |
| 523 // For every SSA value that is live out of this block, create an interval | 535 // For every SSA value that is live out of this block, create an interval |
| 524 // that covers the whole block. It will be shortened if we encounter a | 536 // that covers the whole block. It will be shortened if we encounter a |
| 525 // definition of this value in this block. | 537 // definition of this value in this block. |
| 526 for (BitVector::Iterator it(live_out_[i]); !it.Done(); it.Advance()) { | 538 for (BitVector::Iterator it(live_out_[i]); !it.Done(); it.Advance()) { |
| 527 LiveRange* range = GetLiveRange(it.Current()); | 539 LiveRange* range = GetLiveRange(it.Current()); |
| 528 range->AddUseInterval(block->start_pos(), block->end_pos()); | 540 range->AddUseInterval(block->start_pos(), block->end_pos()); |
| 529 } | 541 } |
| 530 | 542 |
| 543 BlockInfo* loop_header = block_info->loop_header(); | |
| 544 if ((loop_header != NULL) && (loop_header->last_block() == block)) { | |
| 545 current_interference_set = | |
| 546 new BitVector(flow_graph_.max_virtual_register_number()); | |
| 547 ASSERT(loop_header->backedge_interference() == NULL); | |
| 548 loop_header->set_backedge_interference( | |
| 549 current_interference_set); | |
| 550 } | |
| 551 | |
| 531 // Connect outgoing phi-moves that were created in NumberInstructions | 552 // Connect outgoing phi-moves that were created in NumberInstructions |
| 532 // and find last instruction that contributes to liveness. | 553 // and find last instruction that contributes to liveness. |
| 533 Instruction* current = ConnectOutgoingPhiMoves(block); | 554 Instruction* current = ConnectOutgoingPhiMoves(block, |
| 555 current_interference_set); | |
| 534 | 556 |
| 535 // Now process all instructions in reverse order. | 557 // Now process all instructions in reverse order. |
| 536 while (current != block) { | 558 while (current != block) { |
| 537 // Skip parallel moves that we insert while processing instructions. | 559 // Skip parallel moves that we insert while processing instructions. |
| 538 if (!current->IsParallelMove()) { | 560 if (!current->IsParallelMove()) { |
| 539 ProcessOneInstruction(block, current); | 561 ProcessOneInstruction(block, current, current_interference_set); |
| 540 } | 562 } |
| 541 current = current->previous(); | 563 current = current->previous(); |
| 542 } | 564 } |
| 543 | 565 |
| 544 | 566 |
| 545 // Check if any values live into the loop can be spilled for free. | 567 // 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()) { | 568 if (block_info->is_loop_header()) { |
| 569 current_interference_set = NULL; | |
| 548 for (BitVector::Iterator it(live_in_[i]); !it.Done(); it.Advance()) { | 570 for (BitVector::Iterator it(live_in_[i]); !it.Done(); it.Advance()) { |
| 549 LiveRange* range = GetLiveRange(it.Current()); | 571 LiveRange* range = GetLiveRange(it.Current()); |
| 550 if (HasOnlyUnconstrainedUsesInLoop(range, block_info)) { | 572 if (HasOnlyUnconstrainedUsesInLoop(range, block_info)) { |
| 551 range->MarkHasOnlyUnconstrainedUsesInLoop(block_info->loop_id()); | 573 range->MarkHasOnlyUnconstrainedUsesInLoop(block_info->loop_id()); |
| 552 } | 574 } |
| 553 } | 575 } |
| 554 } | 576 } |
| 555 | 577 |
| 556 ConnectIncomingPhiMoves(block); | 578 ConnectIncomingPhiMoves(block); |
| 557 } | 579 } |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 643 // | 665 // |
| 644 // i i' | 666 // i i' |
| 645 // value --*--) | 667 // value --*--) |
| 646 // | 668 // |
| 647 // can be read as: use interval for value starts somewhere before instruction | 669 // can be read as: use interval for value starts somewhere before instruction |
| 648 // and extends until currently processed instruction, there is a use of value | 670 // and extends until currently processed instruction, there is a use of value |
| 649 // at the start of the instruction. | 671 // at the start of the instruction. |
| 650 // | 672 // |
| 651 | 673 |
| 652 Instruction* FlowGraphAllocator::ConnectOutgoingPhiMoves( | 674 Instruction* FlowGraphAllocator::ConnectOutgoingPhiMoves( |
| 653 BlockEntryInstr* block) { | 675 BlockEntryInstr* block, BitVector* interfere_at_backedge) { |
| 654 Instruction* last = block->last_instruction(); | 676 Instruction* last = block->last_instruction(); |
| 655 | 677 |
| 656 GotoInstr* goto_instr = last->AsGoto(); | 678 GotoInstr* goto_instr = last->AsGoto(); |
| 657 if (goto_instr == NULL) return last; | 679 if (goto_instr == NULL) return last; |
| 658 | 680 |
| 659 // If we have a parallel move here then the successor block must be a | 681 // If we have a parallel move here then the successor block must be a |
| 660 // join with phis. The phi inputs contribute uses to each predecessor | 682 // join with phis. The phi inputs contribute uses to each predecessor |
| 661 // block (and the phi outputs contribute definitions in the successor | 683 // block (and the phi outputs contribute definitions in the successor |
| 662 // block). | 684 // block). |
| 663 if (!goto_instr->HasParallelMove()) return goto_instr->previous(); | 685 if (!goto_instr->HasParallelMove()) return goto_instr->previous(); |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 689 move_idx++; | 711 move_idx++; |
| 690 continue; | 712 continue; |
| 691 } | 713 } |
| 692 | 714 |
| 693 // Expected shape of live ranges: | 715 // Expected shape of live ranges: |
| 694 // | 716 // |
| 695 // g g' | 717 // g g' |
| 696 // value --* | 718 // value --* |
| 697 // | 719 // |
| 698 | 720 |
| 699 LiveRange* range = GetLiveRange(val->definition()->ssa_temp_index()); | 721 const intptr_t vreg = val->definition()->ssa_temp_index(); |
| 722 LiveRange* range = GetLiveRange(vreg); | |
| 723 if (interfere_at_backedge != NULL) interfere_at_backedge->Add(vreg); | |
| 700 | 724 |
| 701 range->AddUseInterval(block->start_pos(), pos); | 725 range->AddUseInterval(block->start_pos(), pos); |
| 702 range->AddHintedUse(pos, move->src_slot(), move->dest_slot()); | 726 range->AddHintedUse(pos, move->src_slot(), move->dest_slot()); |
| 703 | 727 |
| 704 move->set_src(Location::PrefersRegister()); | 728 move->set_src(Location::PrefersRegister()); |
| 705 move_idx++; | 729 move_idx++; |
| 706 } | 730 } |
| 707 | 731 |
| 708 // Begin backward iteration with the instruction before the parallel | 732 // Begin backward iteration with the instruction before the parallel |
| 709 // move. | 733 // move. |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 814 | 838 |
| 815 env->set_locations(locations); | 839 env->set_locations(locations); |
| 816 env = env->outer(); | 840 env = env->outer(); |
| 817 } | 841 } |
| 818 } | 842 } |
| 819 | 843 |
| 820 | 844 |
| 821 // Create and update live ranges corresponding to instruction's inputs, | 845 // Create and update live ranges corresponding to instruction's inputs, |
| 822 // temporaries and output. | 846 // temporaries and output. |
| 823 void FlowGraphAllocator::ProcessOneInstruction(BlockEntryInstr* block, | 847 void FlowGraphAllocator::ProcessOneInstruction(BlockEntryInstr* block, |
| 824 Instruction* current) { | 848 Instruction* current, |
| 849 BitVector* interference_set) { | |
| 825 LocationSummary* locs = current->locs(); | 850 LocationSummary* locs = current->locs(); |
| 826 | 851 |
| 827 Definition* def = current->AsDefinition(); | 852 Definition* def = current->AsDefinition(); |
| 828 if ((def != NULL) && | 853 if ((def != NULL) && |
| 829 (def->AsConstant() != NULL) && | 854 (def->AsConstant() != NULL) && |
| 830 ((def->ssa_temp_index() == -1) || | 855 ((def->ssa_temp_index() == -1) || |
| 831 (GetLiveRange(def->ssa_temp_index())->first_use() == NULL))) { | 856 (GetLiveRange(def->ssa_temp_index())->first_use() == NULL))) { |
| 832 // Drop definitions of constants that have no uses. | 857 // Drop definitions of constants that have no uses. |
| 833 locs->set_out(Location::NoLocation()); | 858 locs->set_out(Location::NoLocation()); |
| 834 return; | 859 return; |
| (...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1058 GetLiveRange(input->ssa_temp_index()); | 1083 GetLiveRange(input->ssa_temp_index()); |
| 1059 input_range->AddUseInterval(block->start_pos(), pos); | 1084 input_range->AddUseInterval(block->start_pos(), pos); |
| 1060 input_range->AddUse(pos, move->src_slot()); | 1085 input_range->AddUse(pos, move->src_slot()); |
| 1061 | 1086 |
| 1062 // Shorten output live range to the point of definition and add both input | 1087 // Shorten output live range to the point of definition and add both input |
| 1063 // and output uses slots to be filled by allocator. | 1088 // and output uses slots to be filled by allocator. |
| 1064 range->DefineAt(pos); | 1089 range->DefineAt(pos); |
| 1065 range->AddHintedUse(pos, out, move->src_slot()); | 1090 range->AddHintedUse(pos, out, move->src_slot()); |
| 1066 range->AddUse(pos, move->dest_slot()); | 1091 range->AddUse(pos, move->dest_slot()); |
| 1067 range->AddUse(pos, locs->in_slot(0)); | 1092 range->AddUse(pos, locs->in_slot(0)); |
| 1093 | |
| 1094 if ((interference_set != NULL) && | |
| 1095 (range->vreg() >= 0) && | |
| 1096 interference_set->Contains(range->vreg())) { | |
| 1097 interference_set->Add(input->ssa_temp_index()); | |
| 1098 } | |
| 1068 } else { | 1099 } else { |
| 1069 // Normal unallocated location that requires a register. Expected shape of | 1100 // Normal unallocated location that requires a register. Expected shape of |
| 1070 // live range: | 1101 // live range: |
| 1071 // | 1102 // |
| 1072 // i i' | 1103 // i i' |
| 1073 // output [------- | 1104 // output [------- |
| 1074 // | 1105 // |
| 1075 ASSERT(locs->out().Equals(Location::RequiresRegister()) || | 1106 ASSERT(locs->out().Equals(Location::RequiresRegister()) || |
| 1076 locs->out().Equals(Location::RequiresXmmRegister())); | 1107 locs->out().Equals(Location::RequiresXmmRegister())); |
| 1077 | 1108 |
| (...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1444 finger_.UpdateAfterSplit(first_use_after_split->pos()); | 1475 finger_.UpdateAfterSplit(first_use_after_split->pos()); |
| 1445 } | 1476 } |
| 1446 | 1477 |
| 1447 return next_sibling_; | 1478 return next_sibling_; |
| 1448 } | 1479 } |
| 1449 | 1480 |
| 1450 | 1481 |
| 1451 LiveRange* FlowGraphAllocator::SplitBetween(LiveRange* range, | 1482 LiveRange* FlowGraphAllocator::SplitBetween(LiveRange* range, |
| 1452 intptr_t from, | 1483 intptr_t from, |
| 1453 intptr_t to) { | 1484 intptr_t to) { |
| 1454 TRACE_ALLOC(OS::Print("split %"Pd" [%"Pd", %"Pd") between [%"Pd", %"Pd")\n", | 1485 TRACE_ALLOC(OS::Print("split v%"Pd" [%"Pd", %"Pd") between [%"Pd", %"Pd")\n", |
| 1455 range->vreg(), range->Start(), range->End(), from, to)); | 1486 range->vreg(), range->Start(), range->End(), from, to)); |
| 1456 | 1487 |
| 1457 intptr_t split_pos = kIllegalPosition; | 1488 intptr_t split_pos = kIllegalPosition; |
| 1458 | 1489 |
| 1459 BlockInfo* split_block = BlockInfoAt(to); | 1490 BlockInfo* split_block = BlockInfoAt(to); |
| 1460 if (from < split_block->entry()->lifetime_position()) { | 1491 if (from < split_block->entry()->lifetime_position()) { |
| 1461 // Interval [from, to) spans multiple blocks. | 1492 // Interval [from, to) spans multiple blocks. |
| 1462 | 1493 |
| 1463 // If last block is inside a loop prefer splitting at outermost loop's | 1494 // If last block is inside a loop prefer splitting at outermost loop's |
| 1464 // header. | 1495 // header. |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 1482 ASSERT((split_pos != kIllegalPosition) && (from < split_pos)); | 1513 ASSERT((split_pos != kIllegalPosition) && (from < split_pos)); |
| 1483 | 1514 |
| 1484 return range->SplitAt(split_pos); | 1515 return range->SplitAt(split_pos); |
| 1485 } | 1516 } |
| 1486 | 1517 |
| 1487 | 1518 |
| 1488 void FlowGraphAllocator::SpillBetween(LiveRange* range, | 1519 void FlowGraphAllocator::SpillBetween(LiveRange* range, |
| 1489 intptr_t from, | 1520 intptr_t from, |
| 1490 intptr_t to) { | 1521 intptr_t to) { |
| 1491 ASSERT(from < to); | 1522 ASSERT(from < to); |
| 1492 TRACE_ALLOC(OS::Print("spill %"Pd" [%"Pd", %"Pd") " | 1523 TRACE_ALLOC(OS::Print("spill v%"Pd" [%"Pd", %"Pd") " |
| 1493 "between [%"Pd", %"Pd")\n", | 1524 "between [%"Pd", %"Pd")\n", |
| 1494 range->vreg(), range->Start(), range->End(), from, to)); | 1525 range->vreg(), range->Start(), range->End(), from, to)); |
| 1495 LiveRange* tail = range->SplitAt(from); | 1526 LiveRange* tail = range->SplitAt(from); |
| 1496 | 1527 |
| 1497 if (tail->Start() < to) { | 1528 if (tail->Start() < to) { |
| 1498 // There is an intersection of tail and [from, to). | 1529 // There is an intersection of tail and [from, to). |
| 1499 LiveRange* tail_tail = SplitBetween(tail, tail->Start(), to); | 1530 LiveRange* tail_tail = SplitBetween(tail, tail->Start(), to); |
| 1500 Spill(tail); | 1531 Spill(tail); |
| 1501 AddToUnallocated(tail_tail); | 1532 AddToUnallocated(tail_tail); |
| 1502 } else { | 1533 } else { |
| 1503 // No intersection between tail and [from, to). | 1534 // No intersection between tail and [from, to). |
| 1504 AddToUnallocated(tail); | 1535 AddToUnallocated(tail); |
| 1505 } | 1536 } |
| 1506 } | 1537 } |
| 1507 | 1538 |
| 1508 | 1539 |
| 1509 void FlowGraphAllocator::SpillAfter(LiveRange* range, intptr_t from) { | 1540 void FlowGraphAllocator::SpillAfter(LiveRange* range, intptr_t from) { |
| 1510 TRACE_ALLOC(OS::Print("spill %"Pd" [%"Pd", %"Pd") after %"Pd"\n", | 1541 TRACE_ALLOC(OS::Print("spill v%"Pd" [%"Pd", %"Pd") after %"Pd"\n", |
| 1511 range->vreg(), range->Start(), range->End(), from)); | 1542 range->vreg(), range->Start(), range->End(), from)); |
| 1512 | 1543 |
| 1513 // When spilling the value inside the loop check if this spill can | 1544 // When spilling the value inside the loop check if this spill can |
| 1514 // be moved outside. | 1545 // be moved outside. |
| 1515 BlockInfo* block_info = BlockInfoAt(from); | 1546 BlockInfo* block_info = BlockInfoAt(from); |
| 1516 if (block_info->is_loop_header() || (block_info->loop() != NULL)) { | 1547 if (block_info->is_loop_header() || (block_info->loop() != NULL)) { |
| 1517 BlockInfo* loop_header = | 1548 BlockInfo* loop_header = |
| 1518 block_info->is_loop_header() ? block_info : block_info->loop(); | 1549 block_info->is_loop_header() ? block_info : block_info->loop(); |
| 1519 | 1550 |
| 1520 if ((range->Start() <= loop_header->entry()->start_pos()) && | 1551 if ((range->Start() <= loop_header->entry()->start_pos()) && |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1607 | 1638 |
| 1608 const intptr_t pos = FirstIntersection( | 1639 const intptr_t pos = FirstIntersection( |
| 1609 unallocated->finger()->first_pending_use_interval(), | 1640 unallocated->finger()->first_pending_use_interval(), |
| 1610 allocated_head); | 1641 allocated_head); |
| 1611 if (pos < intersection) intersection = pos; | 1642 if (pos < intersection) intersection = pos; |
| 1612 } | 1643 } |
| 1613 return intersection; | 1644 return intersection; |
| 1614 } | 1645 } |
| 1615 | 1646 |
| 1616 | 1647 |
| 1648 void ReachingDefs::AddPhi(PhiInstr* phi) { | |
| 1649 if (phi->reaching_defs() == NULL) { | |
| 1650 phi->set_reaching_defs( | |
| 1651 new BitVector(flow_graph_.max_virtual_register_number())); | |
| 1652 | |
| 1653 // Compute initial set reaching defs set. | |
| 1654 bool depends_on_phi = false; | |
| 1655 for (intptr_t i = 0; i < phi->InputCount(); i++) { | |
| 1656 Definition* input = phi->InputAt(i)->definition(); | |
| 1657 if (input->IsPhi()) { | |
| 1658 depends_on_phi = true; | |
| 1659 } | |
| 1660 phi->reaching_defs()->Add(input->ssa_temp_index()); | |
| 1661 } | |
| 1662 | |
| 1663 // If this phi depends on another phi then we need fix point iteration. | |
| 1664 if (depends_on_phi) phis_.Add(phi); | |
| 1665 } | |
| 1666 } | |
| 1667 | |
| 1668 | |
| 1669 void ReachingDefs::Compute() { | |
| 1670 // Transitively collect all phis that are used by the given phi. | |
| 1671 for (intptr_t i = 0; i < phis_.length(); i++) { | |
| 1672 PhiInstr* phi = phis_[i]; | |
| 1673 | |
| 1674 // Add all phis that affect this phi to the list. | |
| 1675 for (intptr_t i = 0; i < phi->InputCount(); i++) { | |
| 1676 Definition* input = phi->InputAt(i)->definition(); | |
| 1677 if (input->IsPhi()) { | |
| 1678 AddPhi(input->AsPhi()); | |
| 1679 } | |
| 1680 } | |
| 1681 } | |
| 1682 | |
| 1683 // Propagate values until fix point is reached. | |
| 1684 bool changed; | |
| 1685 do { | |
| 1686 changed = false; | |
| 1687 for (intptr_t i = 0; i < phis_.length(); i++) { | |
| 1688 PhiInstr* phi = phis_[i]; | |
| 1689 for (intptr_t i = 0; i < phi->InputCount(); i++) { | |
| 1690 Definition* input = phi->InputAt(i)->definition(); | |
|
Florian Schneider
2012/11/23 13:58:06
Or shorter:
input_phi = phi->InputAt(i)->definiti
Vyacheslav Egorov (Google)
2012/11/23 15:38:53
Done.
| |
| 1691 if (input->IsPhi()) { | |
| 1692 if (phi->reaching_defs()->AddAll(input->AsPhi()->reaching_defs())) { | |
| 1693 changed = true; | |
| 1694 } | |
| 1695 } | |
| 1696 } | |
| 1697 } | |
| 1698 } while (changed); | |
| 1699 | |
| 1700 phis_.Clear(); | |
| 1701 } | |
| 1702 | |
| 1703 | |
| 1704 BitVector* ReachingDefs::Get(PhiInstr* phi) { | |
| 1705 if (phi->reaching_defs() == NULL) { | |
| 1706 ASSERT(phis_.is_empty()); | |
| 1707 AddPhi(phi); | |
| 1708 Compute(); | |
| 1709 } | |
| 1710 return phi->reaching_defs(); | |
| 1711 } | |
| 1712 | |
| 1713 | |
| 1617 bool FlowGraphAllocator::AllocateFreeRegister(LiveRange* unallocated) { | 1714 bool FlowGraphAllocator::AllocateFreeRegister(LiveRange* unallocated) { |
| 1618 intptr_t candidate = kNoRegister; | 1715 intptr_t candidate = kNoRegister; |
| 1619 intptr_t free_until = 0; | 1716 intptr_t free_until = 0; |
| 1620 | 1717 |
| 1621 // If hint is available try hint first. | 1718 // If hint is available try hint first. |
| 1622 // TODO(vegorov): ensure that phis are hinted on the back edge. | 1719 // TODO(vegorov): ensure that phis are hinted on the back edge. |
| 1623 Location hint = unallocated->finger()->FirstHint(); | 1720 Location hint = unallocated->finger()->FirstHint(); |
| 1624 if (hint.IsMachineRegister()) { | 1721 if (hint.IsMachineRegister()) { |
| 1625 if (!blocked_registers_[hint.register_code()]) { | 1722 if (!blocked_registers_[hint.register_code()]) { |
| 1626 free_until = FirstIntersectionWithAllocated(hint.register_code(), | 1723 free_until = FirstIntersectionWithAllocated(hint.register_code(), |
| 1627 unallocated); | 1724 unallocated); |
| 1628 candidate = hint.register_code(); | 1725 candidate = hint.register_code(); |
| 1629 } | 1726 } |
| 1630 | 1727 |
| 1631 TRACE_ALLOC(OS::Print("found hint ")); | 1728 TRACE_ALLOC(OS::Print("found hint %s for v%"Pd": free until %"Pd"\n", |
| 1632 TRACE_ALLOC(hint.Print()); | 1729 hint.Name(), |
| 1633 TRACE_ALLOC(OS::Print(" for %"Pd": free until %"Pd"\n", | 1730 unallocated->vreg(), |
| 1634 unallocated->vreg(), free_until)); | 1731 free_until)); |
| 1635 } else if (free_until != kMaxPosition) { | 1732 } else if (free_until != kMaxPosition) { |
| 1636 for (intptr_t reg = 0; reg < NumberOfRegisters(); ++reg) { | 1733 for (intptr_t reg = 0; reg < NumberOfRegisters(); ++reg) { |
| 1637 if (!blocked_registers_[reg] && (registers_[reg].length() == 0)) { | 1734 if (!blocked_registers_[reg] && (registers_[reg].length() == 0)) { |
| 1638 candidate = reg; | 1735 candidate = reg; |
| 1639 free_until = kMaxPosition; | 1736 free_until = kMaxPosition; |
| 1640 break; | 1737 break; |
| 1641 } | 1738 } |
| 1642 } | 1739 } |
| 1643 } | 1740 } |
| 1644 | 1741 |
| 1742 // We have a very good candidate (either hinted to us or completely free). | |
| 1743 // If we are in the loop try to reduce number of moves on the back edge by | |
|
Florian Schneider
2012/11/23 13:58:06
Which loop? s/the/a/?
Vyacheslav Egorov (Google)
2012/11/23 15:38:53
Done.
| |
| 1744 // searching for a candidate that does not interfere with phis on the back | |
| 1745 // edge. | |
| 1746 BlockInfo* loop_header = BlockInfoAt(unallocated->Start())->loop_header(); | |
| 1747 if ((unallocated->vreg() >= 0) && | |
| 1748 (loop_header != NULL) && | |
| 1749 (free_until >= loop_header->last_block()->end_pos()) && | |
| 1750 loop_header->backedge_interference()->Contains(unallocated->vreg())) { | |
| 1751 ASSERT(static_cast<intptr_t>(kNumberOfXmmRegisters) <= | |
|
Florian Schneider
2012/11/23 13:58:06
COMPILE_ASSERT?
Vyacheslav Egorov (Google)
2012/11/23 15:38:53
COMPILE_ASSERT seems to be available only in debug
| |
| 1752 kNumberOfCpuRegisters); | |
| 1753 bool used_on_backedge[kNumberOfCpuRegisters] = { false }; | |
| 1754 | |
| 1755 for (PhiIterator it(loop_header->entry()->AsJoinEntry()); | |
| 1756 !it.Done(); | |
| 1757 it.Advance()) { | |
| 1758 PhiInstr* phi = it.Current(); | |
| 1759 if (phi->is_alive()) { | |
| 1760 const intptr_t phi_vreg = phi->ssa_temp_index(); | |
| 1761 LiveRange* range = GetLiveRange(phi_vreg); | |
| 1762 if (range->assigned_location().kind() == register_kind_) { | |
| 1763 const intptr_t reg = range->assigned_location().register_code(); | |
| 1764 | |
| 1765 if ((unallocated->vreg() >= 0) && | |
|
Florian Schneider
2012/11/23 13:58:06
This condition is already tested in line 1747.
Vyacheslav Egorov (Google)
2012/11/23 15:38:53
Done.
| |
| 1766 !reaching_defs_.Get(phi)->Contains(unallocated->vreg())) { | |
| 1767 used_on_backedge[reg] = true; | |
| 1768 } | |
| 1769 } | |
| 1770 } | |
| 1771 } | |
| 1772 | |
| 1773 if (used_on_backedge[candidate]) { | |
| 1774 TRACE_ALLOC(OS::Print( | |
| 1775 "considering %s for v%"Pd": has interference on the back edge" | |
| 1776 " {loop [%"Pd", %"Pd")}\n", | |
| 1777 MakeRegisterLocation(candidate, Location::kDouble).Name(), | |
| 1778 unallocated->vreg(), | |
| 1779 loop_header->entry()->start_pos(), | |
| 1780 loop_header->last_block()->end_pos())); | |
| 1781 for (intptr_t reg = 0; reg < NumberOfRegisters(); ++reg) { | |
| 1782 if (blocked_registers_[reg] || | |
| 1783 (reg == candidate) || | |
| 1784 used_on_backedge[reg]) { | |
| 1785 continue; | |
| 1786 } | |
| 1787 | |
| 1788 const intptr_t intersection = | |
| 1789 FirstIntersectionWithAllocated(reg, unallocated); | |
| 1790 if (intersection >= free_until) { | |
| 1791 candidate = reg; | |
| 1792 free_until = intersection; | |
| 1793 TRACE_ALLOC(OS::Print( | |
| 1794 "found %s for v%"Pd" with no interference on the back edge\n", | |
| 1795 MakeRegisterLocation(candidate, Location::kDouble).Name(), | |
| 1796 candidate)); | |
| 1797 break; | |
| 1798 } | |
| 1799 } | |
| 1800 } | |
| 1801 } | |
| 1802 | |
| 1645 ASSERT(0 <= kMaxPosition); | 1803 ASSERT(0 <= kMaxPosition); |
| 1646 if (free_until != kMaxPosition) { | 1804 if (free_until != kMaxPosition) { |
| 1647 for (intptr_t reg = 0; reg < NumberOfRegisters(); ++reg) { | 1805 for (intptr_t reg = 0; reg < NumberOfRegisters(); ++reg) { |
| 1648 if (blocked_registers_[reg] || (reg == candidate)) continue; | 1806 if (blocked_registers_[reg] || (reg == candidate)) continue; |
| 1649 const intptr_t intersection = | 1807 const intptr_t intersection = |
| 1650 FirstIntersectionWithAllocated(reg, unallocated); | 1808 FirstIntersectionWithAllocated(reg, unallocated); |
| 1651 if (intersection > free_until) { | 1809 if (intersection > free_until) { |
| 1652 candidate = reg; | 1810 candidate = reg; |
| 1653 free_until = intersection; | 1811 free_until = intersection; |
| 1654 if (free_until == kMaxPosition) break; | 1812 if (free_until == kMaxPosition) break; |
| 1655 } | 1813 } |
| 1656 } | 1814 } |
| 1657 } | 1815 } |
| 1658 | 1816 |
| 1659 // All registers are blocked by active ranges. | 1817 // All registers are blocked by active ranges. |
| 1660 if (free_until <= unallocated->Start()) return false; | 1818 if (free_until <= unallocated->Start()) return false; |
| 1661 | 1819 |
| 1662 TRACE_ALLOC(OS::Print("assigning free register ")); | 1820 TRACE_ALLOC(OS::Print("assigning free register ")); |
| 1663 TRACE_ALLOC(MakeRegisterLocation(candidate, Location::kDouble).Print()); | 1821 TRACE_ALLOC(MakeRegisterLocation(candidate, Location::kDouble).Print()); |
| 1664 TRACE_ALLOC(OS::Print(" to %"Pd"\n", unallocated->vreg())); | 1822 TRACE_ALLOC(OS::Print(" to v%"Pd"\n", unallocated->vreg())); |
| 1665 | 1823 |
| 1666 if (free_until != kMaxPosition) { | 1824 if (free_until != kMaxPosition) { |
| 1667 // There was an intersection. Split unallocated. | 1825 // There was an intersection. Split unallocated. |
| 1668 TRACE_ALLOC(OS::Print(" splitting at %"Pd"\n", free_until)); | 1826 TRACE_ALLOC(OS::Print(" splitting at %"Pd"\n", free_until)); |
| 1669 LiveRange* tail = unallocated->SplitAt(free_until); | 1827 LiveRange* tail = unallocated->SplitAt(free_until); |
| 1670 AddToUnallocated(tail); | 1828 AddToUnallocated(tail); |
| 1671 } | 1829 } |
| 1672 | 1830 |
| 1673 registers_[candidate].Add(unallocated); | 1831 registers_[candidate].Add(unallocated); |
| 1674 unallocated->set_assigned_location( | 1832 unallocated->set_assigned_location( |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1757 : unallocated->Start(); | 1915 : unallocated->Start(); |
| 1758 if (free_until < register_use_pos) { | 1916 if (free_until < register_use_pos) { |
| 1759 // Can't acquire free register. Spill until we really need one. | 1917 // Can't acquire free register. Spill until we really need one. |
| 1760 ASSERT(unallocated->Start() < ToInstructionStart(register_use_pos)); | 1918 ASSERT(unallocated->Start() < ToInstructionStart(register_use_pos)); |
| 1761 SpillBetween(unallocated, unallocated->Start(), register_use->pos()); | 1919 SpillBetween(unallocated, unallocated->Start(), register_use->pos()); |
| 1762 return; | 1920 return; |
| 1763 } | 1921 } |
| 1764 | 1922 |
| 1765 TRACE_ALLOC(OS::Print("assigning blocked register ")); | 1923 TRACE_ALLOC(OS::Print("assigning blocked register ")); |
| 1766 TRACE_ALLOC(MakeRegisterLocation(candidate, Location::kDouble).Print()); | 1924 TRACE_ALLOC(MakeRegisterLocation(candidate, Location::kDouble).Print()); |
| 1767 TRACE_ALLOC(OS::Print(" to live range %"Pd" until %"Pd"\n", | 1925 TRACE_ALLOC(OS::Print(" to live range v%"Pd" until %"Pd"\n", |
| 1768 unallocated->vreg(), blocked_at)); | 1926 unallocated->vreg(), blocked_at)); |
| 1769 | 1927 |
| 1770 if (blocked_at < unallocated->End()) { | 1928 if (blocked_at < unallocated->End()) { |
| 1771 // Register is blocked before the end of the live range. Split the range | 1929 // Register is blocked before the end of the live range. Split the range |
| 1772 // at latest at blocked_at position. | 1930 // at latest at blocked_at position. |
| 1773 LiveRange* tail = SplitBetween(unallocated, | 1931 LiveRange* tail = SplitBetween(unallocated, |
| 1774 unallocated->Start(), | 1932 unallocated->Start(), |
| 1775 blocked_at + 1); | 1933 blocked_at + 1); |
| 1776 AddToUnallocated(tail); | 1934 AddToUnallocated(tail); |
| 1777 } | 1935 } |
| (...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2063 } | 2221 } |
| 2064 #endif | 2222 #endif |
| 2065 | 2223 |
| 2066 | 2224 |
| 2067 void FlowGraphAllocator::PrepareForAllocation( | 2225 void FlowGraphAllocator::PrepareForAllocation( |
| 2068 Location::Kind register_kind, | 2226 Location::Kind register_kind, |
| 2069 intptr_t number_of_registers, | 2227 intptr_t number_of_registers, |
| 2070 const GrowableArray<LiveRange*>& unallocated, | 2228 const GrowableArray<LiveRange*>& unallocated, |
| 2071 LiveRange** blocking_ranges, | 2229 LiveRange** blocking_ranges, |
| 2072 bool* blocked_registers) { | 2230 bool* blocked_registers) { |
| 2231 ASSERT(number_of_registers <= kNumberOfCpuRegisters); | |
| 2073 register_kind_ = register_kind; | 2232 register_kind_ = register_kind; |
| 2074 number_of_registers_ = number_of_registers; | 2233 number_of_registers_ = number_of_registers; |
| 2075 | 2234 |
| 2076 ASSERT(unallocated_.is_empty()); | 2235 ASSERT(unallocated_.is_empty()); |
| 2077 unallocated_.AddArray(unallocated); | 2236 unallocated_.AddArray(unallocated); |
| 2078 | 2237 |
| 2079 for (intptr_t reg = 0; reg < number_of_registers; reg++) { | 2238 for (intptr_t reg = 0; reg < number_of_registers; reg++) { |
| 2080 blocked_registers_[reg] = blocked_registers[reg]; | 2239 blocked_registers_[reg] = blocked_registers[reg]; |
| 2081 ASSERT(registers_[reg].is_empty()); | 2240 ASSERT(registers_[reg].is_empty()); |
| 2082 | 2241 |
| 2083 LiveRange* range = blocking_ranges[reg]; | 2242 LiveRange* range = blocking_ranges[reg]; |
| 2084 if (range != NULL) { | 2243 if (range != NULL) { |
| 2085 range->finger()->Initialize(range); | 2244 range->finger()->Initialize(range); |
| 2086 registers_[reg].Add(range); | 2245 registers_[reg].Add(range); |
| 2087 } | 2246 } |
| 2088 } | 2247 } |
| 2089 } | 2248 } |
| 2090 | 2249 |
| 2091 | 2250 |
| 2092 void FlowGraphAllocator::AllocateUnallocatedRanges() { | 2251 void FlowGraphAllocator::AllocateUnallocatedRanges() { |
| 2093 #if defined(DEBUG) | 2252 #if defined(DEBUG) |
| 2094 ASSERT(UnallocatedIsSorted()); | 2253 ASSERT(UnallocatedIsSorted()); |
| 2095 #endif | 2254 #endif |
| 2096 | 2255 |
| 2097 while (!unallocated_.is_empty()) { | 2256 while (!unallocated_.is_empty()) { |
| 2098 LiveRange* range = unallocated_.RemoveLast(); | 2257 LiveRange* range = unallocated_.RemoveLast(); |
| 2099 const intptr_t start = range->Start(); | 2258 const intptr_t start = range->Start(); |
| 2100 TRACE_ALLOC(OS::Print("Processing live range for vreg %"Pd" " | 2259 TRACE_ALLOC(OS::Print("Processing live range for v%"Pd" " |
| 2101 "starting at %"Pd"\n", | 2260 "starting at %"Pd"\n", |
| 2102 range->vreg(), | 2261 range->vreg(), |
| 2103 start)); | 2262 start)); |
| 2104 | 2263 |
| 2105 // TODO(vegorov): eagerly spill liveranges without register uses. | 2264 // TODO(vegorov): eagerly spill liveranges without register uses. |
| 2106 AdvanceActiveIntervals(start); | 2265 AdvanceActiveIntervals(start); |
| 2107 | 2266 |
| 2108 if (!AllocateFreeRegister(range)) { | 2267 if (!AllocateFreeRegister(range)) { |
| 2109 AllocateAnyRegister(range); | 2268 AllocateAnyRegister(range); |
| 2110 } | 2269 } |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 2127 ASSERT(GetLiveRange(range->vreg())->spill_slot().Equals(target)); | 2286 ASSERT(GetLiveRange(range->vreg())->spill_slot().Equals(target)); |
| 2128 return true; | 2287 return true; |
| 2129 } | 2288 } |
| 2130 return false; | 2289 return false; |
| 2131 } | 2290 } |
| 2132 | 2291 |
| 2133 | 2292 |
| 2134 void FlowGraphAllocator::ConnectSplitSiblings(LiveRange* parent, | 2293 void FlowGraphAllocator::ConnectSplitSiblings(LiveRange* parent, |
| 2135 BlockEntryInstr* source_block, | 2294 BlockEntryInstr* source_block, |
| 2136 BlockEntryInstr* target_block) { | 2295 BlockEntryInstr* target_block) { |
| 2137 TRACE_ALLOC(OS::Print("Connect source_block=%"Pd", target_block=%"Pd"\n", | 2296 TRACE_ALLOC(OS::Print("Connect v%"Pd" on the edge B%"Pd" -> B%"Pd"\n", |
| 2297 parent->vreg(), | |
| 2138 source_block->block_id(), | 2298 source_block->block_id(), |
| 2139 target_block->block_id())); | 2299 target_block->block_id())); |
| 2140 if (parent->next_sibling() == NULL) { | 2300 if (parent->next_sibling() == NULL) { |
| 2141 // Nothing to connect. The whole range was allocated to the same location. | 2301 // Nothing to connect. The whole range was allocated to the same location. |
| 2142 TRACE_ALLOC(OS::Print("range %"Pd" has no siblings\n", parent->vreg())); | 2302 TRACE_ALLOC(OS::Print("range v%"Pd" has no siblings\n", parent->vreg())); |
| 2143 return; | 2303 return; |
| 2144 } | 2304 } |
| 2145 | 2305 |
| 2146 const intptr_t source_pos = source_block->end_pos() - 1; | 2306 const intptr_t source_pos = source_block->end_pos() - 1; |
| 2147 ASSERT(IsInstructionEndPosition(source_pos)); | 2307 ASSERT(IsInstructionEndPosition(source_pos)); |
| 2148 | 2308 |
| 2149 const intptr_t target_pos = target_block->start_pos(); | 2309 const intptr_t target_pos = target_block->start_pos(); |
| 2150 | 2310 |
| 2151 Location target; | 2311 Location target; |
| 2152 Location source; | 2312 Location source; |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 2169 ASSERT(target.IsInvalid()); | 2329 ASSERT(target.IsInvalid()); |
| 2170 target = range->assigned_location(); | 2330 target = range->assigned_location(); |
| 2171 #if defined(DEBUG) | 2331 #if defined(DEBUG) |
| 2172 target_cover = range; | 2332 target_cover = range; |
| 2173 #endif | 2333 #endif |
| 2174 } | 2334 } |
| 2175 | 2335 |
| 2176 range = range->next_sibling(); | 2336 range = range->next_sibling(); |
| 2177 } | 2337 } |
| 2178 | 2338 |
| 2179 TRACE_ALLOC(OS::Print("connecting [%"Pd", %"Pd") [", | 2339 TRACE_ALLOC(OS::Print("connecting v%"Pd" between [%"Pd", %"Pd") {%s} " |
| 2180 source_cover->Start(), source_cover->End())); | 2340 "to [%"Pd", %"Pd") {%s}\n", |
| 2181 TRACE_ALLOC(source.Print()); | 2341 parent->vreg(), |
| 2182 TRACE_ALLOC(OS::Print("] to [%"Pd", %"Pd") [", | 2342 source_cover->Start(), |
| 2183 target_cover->Start(), target_cover->End())); | 2343 source_cover->End(), |
| 2184 TRACE_ALLOC(target.Print()); | 2344 source.Name(), |
| 2185 TRACE_ALLOC(OS::Print("]\n")); | 2345 target_cover->Start(), |
| 2346 target_cover->End(), | |
| 2347 target.Name())); | |
| 2186 | 2348 |
| 2187 // Siblings were allocated to the same register. | 2349 // Siblings were allocated to the same register. |
| 2188 if (source.Equals(target)) return; | 2350 if (source.Equals(target)) return; |
| 2189 | 2351 |
| 2190 // Values are eagerly spilled. Spill slot already contains appropriate value. | 2352 // Values are eagerly spilled. Spill slot already contains appropriate value. |
| 2191 if (TargetLocationIsSpillSlot(parent, target)) { | 2353 if (TargetLocationIsSpillSlot(parent, target)) { |
| 2192 return; | 2354 return; |
| 2193 } | 2355 } |
| 2194 | 2356 |
| 2195 Instruction* last = source_block->last_instruction(); | 2357 Instruction* last = source_block->last_instruction(); |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2348 OS::Print("-- [after ssa allocator] ir [%s] -------------\n", | 2510 OS::Print("-- [after ssa allocator] ir [%s] -------------\n", |
| 2349 function.ToFullyQualifiedCString()); | 2511 function.ToFullyQualifiedCString()); |
| 2350 FlowGraphPrinter printer(flow_graph_, true); | 2512 FlowGraphPrinter printer(flow_graph_, true); |
| 2351 printer.PrintBlocks(); | 2513 printer.PrintBlocks(); |
| 2352 OS::Print("----------------------------------------------\n"); | 2514 OS::Print("----------------------------------------------\n"); |
| 2353 } | 2515 } |
| 2354 } | 2516 } |
| 2355 | 2517 |
| 2356 | 2518 |
| 2357 } // namespace dart | 2519 } // namespace dart |
| OLD | NEW |