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 |