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_builder.h" | 10 #include "vm/flow_graph_builder.h" |
11 #include "vm/flow_graph_compiler.h" | 11 #include "vm/flow_graph_compiler.h" |
12 #include "vm/parser.h" | 12 #include "vm/parser.h" |
13 | 13 |
14 namespace dart { | 14 namespace dart { |
15 | 15 |
16 DEFINE_FLAG(bool, print_ssa_liveness, false, | 16 DEFINE_FLAG(bool, print_ssa_liveness, false, |
17 "Print liveness for ssa variables."); | 17 "Print liveness for ssa variables."); |
18 DEFINE_FLAG(bool, trace_ssa_allocator, false, | 18 DEFINE_FLAG(bool, trace_ssa_allocator, false, |
19 "Trace register allocation over SSA."); | 19 "Trace register allocation over SSA."); |
| 20 DEFINE_FLAG(bool, print_ssa_liveranges, false, |
| 21 "Print live ranges after allocation."); |
20 | 22 |
21 #ifdef DEBUG | 23 #if defined(DEBUG) |
22 #define TRACE_ALLOC(m) do { \ | 24 #define TRACE_ALLOC(m) do { \ |
23 if (FLAG_trace_ssa_allocator) OS::Print m ; \ | 25 if (FLAG_trace_ssa_allocator) OS::Print m ; \ |
24 } while (0) | 26 } while (0) |
25 #else | 27 #else |
26 #define TRACE_ALLOC(m) | 28 #define TRACE_ALLOC(m) |
27 #endif | 29 #endif |
28 | 30 |
29 | 31 |
30 static const intptr_t kNoVirtualRegister = -1; | 32 static const intptr_t kNoVirtualRegister = -1; |
31 static const intptr_t kTempVirtualRegister = -2; | 33 static const intptr_t kTempVirtualRegister = -2; |
(...skipping 300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
332 | 334 |
333 | 335 |
334 LiveRange* FlowGraphAllocator::GetLiveRange(intptr_t vreg) { | 336 LiveRange* FlowGraphAllocator::GetLiveRange(intptr_t vreg) { |
335 if (live_ranges_[vreg] == NULL) { | 337 if (live_ranges_[vreg] == NULL) { |
336 live_ranges_[vreg] = new LiveRange(vreg); | 338 live_ranges_[vreg] = new LiveRange(vreg); |
337 } | 339 } |
338 return live_ranges_[vreg]; | 340 return live_ranges_[vreg]; |
339 } | 341 } |
340 | 342 |
341 | 343 |
| 344 LiveRange* FlowGraphAllocator::MakeLiveRangeForTemporary() { |
| 345 LiveRange* range = new LiveRange(kTempVirtualRegister); |
| 346 #if defined(DEBUG) |
| 347 temporaries_.Add(range); |
| 348 #endif |
| 349 return range; |
| 350 } |
| 351 |
| 352 |
342 // Block location from the start of the instruction to its end. | 353 // Block location from the start of the instruction to its end. |
343 void FlowGraphAllocator::BlockLocation(Location loc, intptr_t pos) { | 354 void FlowGraphAllocator::BlockLocation(Location loc, intptr_t pos) { |
344 ASSERT(loc.IsRegister()); | 355 ASSERT(loc.IsRegister()); |
345 ASSERT(IsInstructionStartPosition(pos)); | 356 ASSERT(IsInstructionStartPosition(pos)); |
346 const Register reg = loc.reg(); | 357 const Register reg = loc.reg(); |
347 if (blocked_cpu_regs_[reg]) return; | 358 if (blocked_cpu_regs_[reg]) return; |
348 if (cpu_regs_[reg].length() == 0) { | 359 if (cpu_regs_[reg].length() == 0) { |
349 cpu_regs_[reg].Add(new LiveRange(kNoVirtualRegister)); | 360 LiveRange* range = new LiveRange(kNoVirtualRegister); |
| 361 cpu_regs_[reg].Add(range); |
| 362 range->set_assigned_location(loc); |
| 363 #if defined(DEBUG) |
| 364 temporaries_.Add(range); |
| 365 #endif |
350 } | 366 } |
351 cpu_regs_[reg][0]->AddUseInterval(pos, pos + 1); | 367 cpu_regs_[reg][0]->AddUseInterval(pos, pos + 1); |
352 } | 368 } |
353 | 369 |
354 | 370 |
355 void LiveRange::Print() { | 371 void LiveRange::Print() { |
356 OS::Print(" live range v%d [%d, %d)\n", vreg(), Start(), End()); | 372 if (first_use_interval() == NULL) { |
| 373 return; |
| 374 } |
| 375 |
| 376 OS::Print(" live range v%d [%d, %d) in ", vreg(), Start(), End()); |
| 377 assigned_location().Print(); |
| 378 OS::Print("\n"); |
| 379 |
357 UsePosition* use_pos = uses_; | 380 UsePosition* use_pos = uses_; |
358 for (UseInterval* interval = first_use_interval_; | 381 for (UseInterval* interval = first_use_interval_; |
359 interval != NULL; | 382 interval != NULL; |
360 interval = interval->next()) { | 383 interval = interval->next()) { |
361 OS::Print(" use interval [%d, %d)\n", | 384 OS::Print(" use interval [%d, %d)\n", |
362 interval->start(), | 385 interval->start(), |
363 interval->end()); | 386 interval->end()); |
364 while ((use_pos != NULL) && (use_pos->pos() <= interval->end())) { | 387 while ((use_pos != NULL) && (use_pos->pos() <= interval->end())) { |
365 OS::Print(" use at %d as %s\n", | 388 OS::Print(" use at %d", use_pos->pos()); |
366 use_pos->pos(), | 389 if (use_pos->location_slot() != NULL) { |
367 (use_pos->location_slot() == NULL) | 390 OS::Print(" as "); |
368 ? "-" : use_pos->location_slot()->Name()); | 391 use_pos->location_slot()->Print(); |
| 392 } |
| 393 OS::Print("\n"); |
369 use_pos = use_pos->next(); | 394 use_pos = use_pos->next(); |
370 } | 395 } |
371 } | 396 } |
372 | 397 |
373 if (next_sibling() != NULL) { | 398 if (next_sibling() != NULL) { |
374 next_sibling()->Print(); | 399 next_sibling()->Print(); |
375 } | 400 } |
376 } | 401 } |
377 | 402 |
378 | 403 |
379 void FlowGraphAllocator::PrintLiveRanges() { | 404 void FlowGraphAllocator::PrintLiveRanges() { |
380 for (intptr_t i = 0; i < unallocated_.length(); i++) { | 405 #if defined(DEBUG) |
381 unallocated_[i]->Print(); | 406 for (intptr_t i = 0; i < temporaries_.length(); i++) { |
| 407 temporaries_[i]->Print(); |
382 } | 408 } |
| 409 #endif |
383 | 410 |
384 for (intptr_t reg = 0; reg < kNumberOfCpuRegisters; reg++) { | 411 for (intptr_t i = 0; i < live_ranges_.length(); i++) { |
385 if (blocked_cpu_regs_[reg]) continue; | 412 if (live_ranges_[i] != NULL) { |
386 if (cpu_regs_[reg].length() == 0) continue; | 413 live_ranges_[i]->Print(); |
387 | 414 } |
388 ASSERT(cpu_regs_[reg].length() == 1); | |
389 OS::Print("blocking live range for %s\n", | |
390 Location::RegisterLocation(static_cast<Register>(reg)).Name()); | |
391 cpu_regs_[reg][0]->Print(); | |
392 } | 415 } |
393 } | 416 } |
394 | 417 |
395 | 418 |
396 void FlowGraphAllocator::BuildLiveRanges() { | 419 void FlowGraphAllocator::BuildLiveRanges() { |
397 NumberInstructions(); | 420 NumberInstructions(); |
398 | 421 |
399 const intptr_t block_count = postorder_.length(); | 422 const intptr_t block_count = postorder_.length(); |
400 ASSERT(postorder_[block_count - 1]->IsGraphEntry()); | 423 ASSERT(postorder_[block_count - 1]->IsGraphEntry()); |
401 for (intptr_t i = 0; i < (block_count - 1); i++) { | 424 for (intptr_t i = 0; i < (block_count - 1); i++) { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
435 if (val->IsUse()) { | 458 if (val->IsUse()) { |
436 ParameterInstr* param = val->AsUse()->definition()->AsParameter(); | 459 ParameterInstr* param = val->AsUse()->definition()->AsParameter(); |
437 | 460 |
438 LiveRange* range = GetLiveRange(param->ssa_temp_index()); | 461 LiveRange* range = GetLiveRange(param->ssa_temp_index()); |
439 range->AddUseInterval(graph_entry->start_pos(), graph_entry->end_pos()); | 462 range->AddUseInterval(graph_entry->start_pos(), graph_entry->end_pos()); |
440 range->DefineAt(graph_entry->start_pos()); | 463 range->DefineAt(graph_entry->start_pos()); |
441 | 464 |
442 // Slot index for the rightmost parameter is -1. | 465 // Slot index for the rightmost parameter is -1. |
443 const intptr_t slot_index = param->index() - fixed_parameters_count; | 466 const intptr_t slot_index = param->index() - fixed_parameters_count; |
444 range->set_assigned_location(Location::StackSlot(slot_index)); | 467 range->set_assigned_location(Location::StackSlot(slot_index)); |
| 468 range->set_spill_slot(Location::StackSlot(slot_index)); |
445 | 469 |
446 range->finger()->Initialize(range); | 470 range->finger()->Initialize(range); |
447 UsePosition* use = range->finger()->FirstRegisterBeneficialUse( | 471 UsePosition* use = range->finger()->FirstRegisterBeneficialUse( |
448 graph_entry->start_pos()); | 472 graph_entry->start_pos()); |
449 if (use != NULL) { | 473 if (use != NULL) { |
450 LiveRange* tail = SplitBetween(range, | 474 LiveRange* tail = SplitBetween(range, |
451 graph_entry->start_pos(), | 475 graph_entry->start_pos(), |
452 use->pos()); | 476 use->pos()); |
453 AddToUnallocated(tail); | 477 AddToUnallocated(tail); |
454 } | 478 } |
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
688 // Expected shape of live range: | 712 // Expected shape of live range: |
689 // | 713 // |
690 // i i' | 714 // i i' |
691 // [--) | 715 // [--) |
692 // | 716 // |
693 | 717 |
694 Location temp = locs->temp(j); | 718 Location temp = locs->temp(j); |
695 if (temp.IsRegister()) { | 719 if (temp.IsRegister()) { |
696 BlockLocation(temp, pos); | 720 BlockLocation(temp, pos); |
697 } else if (temp.IsUnallocated()) { | 721 } else if (temp.IsUnallocated()) { |
698 LiveRange* range = new LiveRange(kTempVirtualRegister); | 722 LiveRange* range = MakeLiveRangeForTemporary(); |
699 range->AddUseInterval(pos, pos + 1); | 723 range->AddUseInterval(pos, pos + 1); |
700 range->AddUse(pos, locs->temp_slot(j)); | 724 range->AddUse(pos, locs->temp_slot(j)); |
701 AddToUnallocated(range); | 725 AddToUnallocated(range); |
702 } else { | 726 } else { |
703 UNREACHABLE(); | 727 UNREACHABLE(); |
704 } | 728 } |
705 } | 729 } |
706 | 730 |
707 // Block all allocatable registers for calls. | 731 // Block all allocatable registers for calls. |
708 if (locs->is_call()) { | 732 if (locs->is_call()) { |
709 // Expected shape of live range: | 733 // Expected shape of live range: |
710 // | 734 // |
711 // i i' | 735 // i i' |
712 // [--) | 736 // [--) |
713 // | 737 // |
714 | 738 |
715 for (intptr_t reg = 0; reg < kNumberOfCpuRegisters; reg++) { | 739 for (intptr_t reg = 0; reg < kNumberOfCpuRegisters; reg++) { |
716 BlockLocation(Location::RegisterLocation(static_cast<Register>(reg)), | 740 BlockLocation(Location::RegisterLocation(static_cast<Register>(reg)), |
717 pos); | 741 pos); |
718 } | 742 } |
719 | 743 |
720 #ifdef DEBUG | 744 #if defined(DEBUG) |
721 // Verify that temps, inputs and output were specified as fixed | 745 // Verify that temps, inputs and output were specified as fixed |
722 // locations. Every register is blocked now so attempt to | 746 // locations. Every register is blocked now so attempt to |
723 // allocate will not succeed. | 747 // allocate will not succeed. |
724 for (intptr_t j = 0; j < locs->temp_count(); j++) { | 748 for (intptr_t j = 0; j < locs->temp_count(); j++) { |
725 ASSERT(!locs->temp(j).IsUnallocated()); | 749 ASSERT(!locs->temp(j).IsUnallocated()); |
726 } | 750 } |
727 | 751 |
728 for (intptr_t j = 0; j < locs->input_count(); j++) { | 752 for (intptr_t j = 0; j < locs->input_count(); j++) { |
729 ASSERT(!locs->in(j).IsUnallocated()); | 753 ASSERT(!locs->in(j).IsUnallocated()); |
730 } | 754 } |
(...skipping 10 matching lines...) Expand all Loading... |
741 | 765 |
742 if (locs->out().IsInvalid()) { | 766 if (locs->out().IsInvalid()) { |
743 ASSERT(def->ssa_temp_index() < 0); | 767 ASSERT(def->ssa_temp_index() < 0); |
744 return; | 768 return; |
745 } | 769 } |
746 | 770 |
747 // We might have a definition without use. We do not assign SSA index to | 771 // We might have a definition without use. We do not assign SSA index to |
748 // such definitions. | 772 // such definitions. |
749 LiveRange* range = (def->ssa_temp_index() >= 0) ? | 773 LiveRange* range = (def->ssa_temp_index() >= 0) ? |
750 GetLiveRange(def->ssa_temp_index()) : | 774 GetLiveRange(def->ssa_temp_index()) : |
751 new LiveRange(kTempVirtualRegister); | 775 MakeLiveRangeForTemporary(); |
752 Location* out = locs->out_slot(); | 776 Location* out = locs->out_slot(); |
753 | 777 |
754 // Process output and finalize its liverange. | 778 // Process output and finalize its liverange. |
755 if (out->IsRegister()) { | 779 if (out->IsRegister()) { |
756 // Fixed output location. Expected shape of live range: | 780 // Fixed output location. Expected shape of live range: |
757 // | 781 // |
758 // i i' j j' | 782 // i i' j j' |
759 // register [--) | 783 // register [--) |
760 // output [------- | 784 // output [------- |
761 // | 785 // |
(...skipping 386 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1148 | 1172 |
1149 | 1173 |
1150 void FlowGraphAllocator::SpillAfter(LiveRange* range, intptr_t from) { | 1174 void FlowGraphAllocator::SpillAfter(LiveRange* range, intptr_t from) { |
1151 TRACE_ALLOC(("spill %d [%d, %d) after %d\n", | 1175 TRACE_ALLOC(("spill %d [%d, %d) after %d\n", |
1152 range->vreg(), range->Start(), range->End(), from)); | 1176 range->vreg(), range->Start(), range->End(), from)); |
1153 LiveRange* tail = range->SplitAt(from); | 1177 LiveRange* tail = range->SplitAt(from); |
1154 Spill(tail); | 1178 Spill(tail); |
1155 } | 1179 } |
1156 | 1180 |
1157 | 1181 |
1158 intptr_t FlowGraphAllocator::AllocateSpillSlotFor(LiveRange* range) { | 1182 void FlowGraphAllocator::AllocateSpillSlotFor(LiveRange* range) { |
1159 for (intptr_t i = 0; i < spill_slots_.length(); i++) { | 1183 ASSERT(range->spill_slot().IsInvalid()); |
1160 if (spill_slots_[i] <= range->Start()) { | 1184 |
1161 return i; | 1185 intptr_t idx = 0; |
1162 } | 1186 for (; idx < spill_slots_.length(); idx++) { |
| 1187 if (spill_slots_[idx] <= range->Start()) break; |
1163 } | 1188 } |
1164 spill_slots_.Add(0); | 1189 |
1165 return spill_slots_.length() - 1; | 1190 if (idx == spill_slots_.length()) spill_slots_.Add(0); |
| 1191 |
| 1192 LiveRange* last_sibling = range; |
| 1193 while (last_sibling->next_sibling() != NULL) { |
| 1194 last_sibling = last_sibling->next_sibling(); |
| 1195 } |
| 1196 |
| 1197 spill_slots_[idx] = last_sibling->End(); |
| 1198 |
| 1199 range->set_spill_slot(Location::StackSlot(idx)); |
| 1200 |
| 1201 spilled_.Add(range); |
1166 } | 1202 } |
1167 | 1203 |
1168 | 1204 |
1169 void FlowGraphAllocator::Spill(LiveRange* range) { | 1205 void FlowGraphAllocator::Spill(LiveRange* range) { |
1170 const intptr_t spill_index = AllocateSpillSlotFor(range); | 1206 LiveRange* parent = GetLiveRange(range->vreg()); |
1171 ASSERT(spill_slots_[spill_index] <= range->Start()); | 1207 |
1172 spill_slots_[spill_index] = range->End(); | 1208 if (parent->spill_slot().IsInvalid()) AllocateSpillSlotFor(parent); |
1173 range->set_assigned_location(Location::StackSlot(spill_index)); | 1209 |
| 1210 range->set_assigned_location(parent->spill_slot()); |
1174 ConvertAllUses(range); | 1211 ConvertAllUses(range); |
1175 } | 1212 } |
1176 | 1213 |
1177 | 1214 |
1178 intptr_t FlowGraphAllocator::FirstIntersectionWithAllocated( | 1215 intptr_t FlowGraphAllocator::FirstIntersectionWithAllocated( |
1179 Register reg, LiveRange* unallocated) { | 1216 Register reg, LiveRange* unallocated) { |
1180 intptr_t intersection = kMaxPosition; | 1217 intptr_t intersection = kMaxPosition; |
1181 for (intptr_t i = 0; i < cpu_regs_[reg].length(); i++) { | 1218 for (intptr_t i = 0; i < cpu_regs_[reg].length(); i++) { |
1182 LiveRange* allocated = cpu_regs_[reg][i]; | 1219 LiveRange* allocated = cpu_regs_[reg][i]; |
1183 if (allocated == NULL) continue; | 1220 if (allocated == NULL) continue; |
(...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1504 for (intptr_t i = unallocated_.length() - 1; i >= 0; i--) { | 1541 for (intptr_t i = unallocated_.length() - 1; i >= 0; i--) { |
1505 if (ShouldBeAllocatedBefore(range, unallocated_[i])) { | 1542 if (ShouldBeAllocatedBefore(range, unallocated_[i])) { |
1506 unallocated_.InsertAt(i + 1, range); | 1543 unallocated_.InsertAt(i + 1, range); |
1507 return; | 1544 return; |
1508 } | 1545 } |
1509 } | 1546 } |
1510 unallocated_.InsertAt(0, range); | 1547 unallocated_.InsertAt(0, range); |
1511 } | 1548 } |
1512 | 1549 |
1513 | 1550 |
1514 #ifdef DEBUG | 1551 #if defined(DEBUG) |
1515 bool FlowGraphAllocator::UnallocatedIsSorted() { | 1552 bool FlowGraphAllocator::UnallocatedIsSorted() { |
1516 for (intptr_t i = unallocated_.length() - 1; i >= 1; i--) { | 1553 for (intptr_t i = unallocated_.length() - 1; i >= 1; i--) { |
1517 LiveRange* a = unallocated_[i]; | 1554 LiveRange* a = unallocated_[i]; |
1518 LiveRange* b = unallocated_[i - 1]; | 1555 LiveRange* b = unallocated_[i - 1]; |
1519 if (!ShouldBeAllocatedBefore(a, b)) return false; | 1556 if (!ShouldBeAllocatedBefore(a, b)) return false; |
1520 } | 1557 } |
1521 return true; | 1558 return true; |
1522 } | 1559 } |
1523 #endif | 1560 #endif |
1524 | 1561 |
1525 | 1562 |
1526 void FlowGraphAllocator::AllocateCPURegisters() { | 1563 void FlowGraphAllocator::AllocateCPURegisters() { |
1527 #ifdef DEBUG | 1564 #if defined(DEBUG) |
1528 ASSERT(UnallocatedIsSorted()); | 1565 ASSERT(UnallocatedIsSorted()); |
1529 #endif | 1566 #endif |
1530 | 1567 |
1531 for (intptr_t i = 0; i < kNumberOfCpuRegisters; i++) { | 1568 for (intptr_t i = 0; i < kNumberOfCpuRegisters; i++) { |
1532 if (cpu_regs_[i].length() == 1) { | 1569 if (cpu_regs_[i].length() == 1) { |
1533 LiveRange* range = cpu_regs_[i][0]; | 1570 LiveRange* range = cpu_regs_[i][0]; |
1534 range->finger()->Initialize(range); | 1571 range->finger()->Initialize(range); |
1535 } | 1572 } |
1536 } | 1573 } |
1537 | 1574 |
(...skipping 15 matching lines...) Expand all Loading... |
1553 | 1590 |
1554 // All allocation decisions were done. | 1591 // All allocation decisions were done. |
1555 ASSERT(unallocated_.is_empty()); | 1592 ASSERT(unallocated_.is_empty()); |
1556 | 1593 |
1557 // Finish allocation. | 1594 // Finish allocation. |
1558 AdvanceActiveIntervals(kMaxPosition); | 1595 AdvanceActiveIntervals(kMaxPosition); |
1559 TRACE_ALLOC(("Allocation completed\n")); | 1596 TRACE_ALLOC(("Allocation completed\n")); |
1560 } | 1597 } |
1561 | 1598 |
1562 | 1599 |
1563 void FlowGraphAllocator::ConnectSplitSiblings(LiveRange* range, | 1600 void FlowGraphAllocator::ConnectSplitSiblings(LiveRange* parent, |
1564 BlockEntryInstr* source_block, | 1601 BlockEntryInstr* source_block, |
1565 BlockEntryInstr* target_block) { | 1602 BlockEntryInstr* target_block) { |
1566 TRACE_ALLOC(("Connect source_block=%d, target_block=%d\n", | 1603 TRACE_ALLOC(("Connect source_block=%d, target_block=%d\n", |
1567 source_block->block_id(), | 1604 source_block->block_id(), |
1568 target_block->block_id())); | 1605 target_block->block_id())); |
1569 if (range->next_sibling() == NULL) { | 1606 if (parent->next_sibling() == NULL) { |
1570 // Nothing to connect. The whole range was allocated to the same location. | 1607 // Nothing to connect. The whole range was allocated to the same location. |
1571 TRACE_ALLOC(("range %d has no siblings\n", range->vreg())); | 1608 TRACE_ALLOC(("range %d has no siblings\n", parent->vreg())); |
1572 return; | 1609 return; |
1573 } | 1610 } |
1574 | 1611 |
1575 const intptr_t source_pos = source_block->end_pos() - 1; | 1612 const intptr_t source_pos = source_block->end_pos() - 1; |
1576 ASSERT(IsInstructionEndPosition(source_pos)); | 1613 ASSERT(IsInstructionEndPosition(source_pos)); |
1577 | 1614 |
1578 const intptr_t target_pos = target_block->start_pos(); | 1615 const intptr_t target_pos = target_block->start_pos(); |
1579 | 1616 |
1580 Location target; | 1617 Location target; |
1581 Location source; | 1618 Location source; |
1582 | 1619 |
1583 #ifdef DEBUG | 1620 #if defined(DEBUG) |
1584 LiveRange* source_cover = NULL; | 1621 LiveRange* source_cover = NULL; |
1585 LiveRange* target_cover = NULL; | 1622 LiveRange* target_cover = NULL; |
1586 #endif | 1623 #endif |
1587 | 1624 |
| 1625 LiveRange* range = parent; |
1588 while ((range != NULL) && (source.IsInvalid() || target.IsInvalid())) { | 1626 while ((range != NULL) && (source.IsInvalid() || target.IsInvalid())) { |
1589 if (range->CanCover(source_pos)) { | 1627 if (range->CanCover(source_pos)) { |
1590 ASSERT(source.IsInvalid()); | 1628 ASSERT(source.IsInvalid()); |
1591 source = range->assigned_location(); | 1629 source = range->assigned_location(); |
1592 #ifdef DEBUG | 1630 #if defined(DEBUG) |
1593 source_cover = range; | 1631 source_cover = range; |
1594 #endif | 1632 #endif |
1595 } | 1633 } |
1596 if (range->CanCover(target_pos)) { | 1634 if (range->CanCover(target_pos)) { |
1597 ASSERT(target.IsInvalid()); | 1635 ASSERT(target.IsInvalid()); |
1598 target = range->assigned_location(); | 1636 target = range->assigned_location(); |
1599 #ifdef DEBUG | 1637 #if defined(DEBUG) |
1600 target_cover = range; | 1638 target_cover = range; |
1601 #endif | 1639 #endif |
1602 } | 1640 } |
1603 | 1641 |
1604 range = range->next_sibling(); | 1642 range = range->next_sibling(); |
1605 } | 1643 } |
1606 | 1644 |
1607 TRACE_ALLOC(("connecting [%d, %d) [%s] to [%d, %d) [%s]\n", | 1645 TRACE_ALLOC(("connecting [%d, %d) [%s] to [%d, %d) [%s]\n", |
1608 source_cover->Start(), source_cover->End(), source.Name(), | 1646 source_cover->Start(), source_cover->End(), source.Name(), |
1609 target_cover->Start(), target_cover->End(), target.Name())); | 1647 target_cover->Start(), target_cover->End(), target.Name())); |
1610 | 1648 |
1611 // Siblings were allocated to the same register. | 1649 // Siblings were allocated to the same register. |
1612 if (source.Equals(target)) return; | 1650 if (source.Equals(target)) return; |
1613 | 1651 |
| 1652 // Values are eagerly spilled. Spill slot already contains appropriate value. |
| 1653 if (target.IsStackSlot()) { |
| 1654 ASSERT(parent->spill_slot().Equals(target)); |
| 1655 return; |
| 1656 } |
| 1657 |
1614 Instruction* last = source_block->last_instruction(); | 1658 Instruction* last = source_block->last_instruction(); |
1615 if (last->SuccessorCount() == 1) { | 1659 if (last->SuccessorCount() == 1) { |
1616 ASSERT(last->IsGoto()); | 1660 ASSERT(last->IsGoto()); |
1617 last->AsGoto()->GetParallelMove()->AddMove(target, source); | 1661 last->AsGoto()->GetParallelMove()->AddMove(target, source); |
1618 } else { | 1662 } else { |
1619 target_block->GetParallelMove()->AddMove(target, source); | 1663 target_block->GetParallelMove()->AddMove(target, source); |
1620 } | 1664 } |
1621 } | 1665 } |
1622 | 1666 |
1623 | 1667 |
1624 void FlowGraphAllocator::ResolveControlFlow() { | 1668 void FlowGraphAllocator::ResolveControlFlow() { |
1625 // Resolve linear control flow between touching split siblings | 1669 // Resolve linear control flow between touching split siblings |
1626 // inside basic blocks. | 1670 // inside basic blocks. |
1627 for (intptr_t vreg = 0; vreg < live_ranges_.length(); vreg++) { | 1671 for (intptr_t vreg = 0; vreg < live_ranges_.length(); vreg++) { |
1628 LiveRange* range = live_ranges_[vreg]; | 1672 LiveRange* range = live_ranges_[vreg]; |
1629 if (range == NULL) continue; | 1673 if (range == NULL) continue; |
1630 | 1674 |
1631 while (range->next_sibling() != NULL) { | 1675 while (range->next_sibling() != NULL) { |
1632 LiveRange* sibling = range->next_sibling(); | 1676 LiveRange* sibling = range->next_sibling(); |
1633 TRACE_ALLOC(("connecting [%d, %d) [%s] to [%d, %d) [%s]\n", | 1677 TRACE_ALLOC(("connecting [%d, %d) [%s] to [%d, %d) [%s]\n", |
1634 range->Start(), range->End(), | 1678 range->Start(), range->End(), |
1635 range->assigned_location().Name(), | 1679 range->assigned_location().Name(), |
1636 sibling->Start(), sibling->End(), | 1680 sibling->Start(), sibling->End(), |
1637 sibling->assigned_location().Name())); | 1681 sibling->assigned_location().Name())); |
1638 if ((range->End() == sibling->Start()) && | 1682 if ((range->End() == sibling->Start()) && |
| 1683 !sibling->assigned_location().IsStackSlot() && |
1639 !range->assigned_location().Equals(sibling->assigned_location()) && | 1684 !range->assigned_location().Equals(sibling->assigned_location()) && |
1640 !IsBlockEntry(range->End())) { | 1685 !IsBlockEntry(range->End())) { |
1641 AddMoveAt(sibling->Start(), | 1686 AddMoveAt(sibling->Start(), |
1642 sibling->assigned_location(), | 1687 sibling->assigned_location(), |
1643 range->assigned_location()); | 1688 range->assigned_location()); |
1644 } | 1689 } |
1645 range = sibling; | 1690 range = sibling; |
1646 } | 1691 } |
1647 } | 1692 } |
1648 | 1693 |
1649 // Resolve non-linear control flow across branches. | 1694 // Resolve non-linear control flow across branches. |
1650 for (intptr_t i = 1; i < block_order_.length(); i++) { | 1695 for (intptr_t i = 1; i < block_order_.length(); i++) { |
1651 BlockEntryInstr* block = block_order_[i]; | 1696 BlockEntryInstr* block = block_order_[i]; |
1652 BitVector* live = live_in_[block->postorder_number()]; | 1697 BitVector* live = live_in_[block->postorder_number()]; |
1653 for (BitVector::Iterator it(live); !it.Done(); it.Advance()) { | 1698 for (BitVector::Iterator it(live); !it.Done(); it.Advance()) { |
1654 LiveRange* range = GetLiveRange(it.Current()); | 1699 LiveRange* range = GetLiveRange(it.Current()); |
1655 for (intptr_t j = 0; j < block->PredecessorCount(); j++) { | 1700 for (intptr_t j = 0; j < block->PredecessorCount(); j++) { |
1656 ConnectSplitSiblings(range, block->PredecessorAt(j), block); | 1701 ConnectSplitSiblings(range, block->PredecessorAt(j), block); |
1657 } | 1702 } |
1658 } | 1703 } |
1659 } | 1704 } |
| 1705 |
| 1706 // Eagerly spill values. |
| 1707 // TODO(vegorov): if value is spilled on the cold path (e.g. by the call) |
| 1708 // this will cause spilling to occur on the fast path (at the definition). |
| 1709 for (intptr_t i = 0; i < spilled_.length(); i++) { |
| 1710 LiveRange* range = spilled_[i]; |
| 1711 if (range->assigned_location().IsStackSlot()) { |
| 1712 ASSERT(range->assigned_location().Equals(range->spill_slot())); |
| 1713 } else { |
| 1714 AddMoveAt(range->Start() + 1, |
| 1715 range->spill_slot(), |
| 1716 range->assigned_location()); |
| 1717 } |
| 1718 } |
1660 } | 1719 } |
1661 | 1720 |
1662 | 1721 |
1663 void FlowGraphAllocator::AllocateRegisters() { | 1722 void FlowGraphAllocator::AllocateRegisters() { |
1664 EliminateEnvironmentUses(); | 1723 EliminateEnvironmentUses(); |
1665 | 1724 |
1666 AnalyzeLiveness(); | 1725 AnalyzeLiveness(); |
1667 | 1726 |
1668 BuildLiveRanges(); | 1727 BuildLiveRanges(); |
1669 | 1728 |
1670 if (FLAG_print_ssa_liveness) { | 1729 if (FLAG_print_ssa_liveness) { |
1671 DumpLiveness(); | 1730 DumpLiveness(); |
1672 } | 1731 } |
1673 | 1732 |
1674 if (FLAG_trace_ssa_allocator) { | |
1675 PrintLiveRanges(); | |
1676 } | |
1677 | |
1678 AllocateCPURegisters(); | 1733 AllocateCPURegisters(); |
1679 | 1734 |
1680 ResolveControlFlow(); | 1735 ResolveControlFlow(); |
1681 | 1736 |
1682 GraphEntryInstr* entry = block_order_[0]->AsGraphEntry(); | 1737 GraphEntryInstr* entry = block_order_[0]->AsGraphEntry(); |
1683 ASSERT(entry != NULL); | 1738 ASSERT(entry != NULL); |
1684 entry->set_spill_slot_count(spill_slots_.length()); | 1739 entry->set_spill_slot_count(spill_slots_.length()); |
1685 | 1740 |
1686 if (FLAG_trace_ssa_allocator) { | 1741 if (FLAG_print_ssa_liveranges) { |
1687 OS::Print("-- ir after allocation -------------------------\n"); | 1742 const Function& function = builder_->parsed_function().function(); |
| 1743 |
| 1744 OS::Print("-- [after ssa allocator] ranges [%s] ---------\n", |
| 1745 function.ToFullyQualifiedCString()); |
| 1746 PrintLiveRanges(); |
| 1747 OS::Print("----------------------------------------------\n"); |
| 1748 |
| 1749 OS::Print("-- [after ssa allocator] ir [%s] -------------\n", |
| 1750 function.ToFullyQualifiedCString()); |
1688 FlowGraphPrinter printer(Function::Handle(), block_order_, true); | 1751 FlowGraphPrinter printer(Function::Handle(), block_order_, true); |
1689 printer.PrintBlocks(); | 1752 printer.PrintBlocks(); |
| 1753 OS::Print("----------------------------------------------\n"); |
1690 } | 1754 } |
1691 } | 1755 } |
1692 | 1756 |
1693 | 1757 |
1694 } // namespace dart | 1758 } // namespace dart |
OLD | NEW |