| 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 |