Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(222)

Side by Side Diff: src/compiler/register-allocator.cc

Issue 1184183002: Separate greedy regalloc in its own files (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/compiler/register-allocator.h ('k') | tools/gyp/v8.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 the V8 project authors. All rights reserved. 1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/base/adapters.h" 5 #include "src/base/adapters.h"
6 #include "src/compiler/linkage.h" 6 #include "src/compiler/linkage.h"
7 #include "src/compiler/register-allocator.h" 7 #include "src/compiler/register-allocator.h"
8 #include "src/string-stream.h" 8 #include "src/string-stream.h"
9 9
10 namespace v8 { 10 namespace v8 {
(...skipping 14 matching lines...) Expand all
25 v->erase(it); 25 v->erase(it);
26 } 26 }
27 27
28 28
29 int GetRegisterCount(const RegisterConfiguration* cfg, RegisterKind kind) { 29 int GetRegisterCount(const RegisterConfiguration* cfg, RegisterKind kind) {
30 return kind == DOUBLE_REGISTERS ? cfg->num_aliased_double_registers() 30 return kind == DOUBLE_REGISTERS ? cfg->num_aliased_double_registers()
31 : cfg->num_general_registers(); 31 : cfg->num_general_registers();
32 } 32 }
33 33
34 34
35 const ZoneVector<LiveRange*>& GetFixedRegisters(
36 const RegisterAllocationData* data, RegisterKind kind) {
37 return kind == DOUBLE_REGISTERS ? data->fixed_double_live_ranges()
38 : data->fixed_live_ranges();
39 }
40
41
42 const InstructionBlock* GetContainingLoop(const InstructionSequence* sequence, 35 const InstructionBlock* GetContainingLoop(const InstructionSequence* sequence,
43 const InstructionBlock* block) { 36 const InstructionBlock* block) {
44 auto index = block->loop_header(); 37 auto index = block->loop_header();
45 if (!index.IsValid()) return nullptr; 38 if (!index.IsValid()) return nullptr;
46 return sequence->InstructionBlockAt(index); 39 return sequence->InstructionBlockAt(index);
47 } 40 }
48 41
49 42
50 const InstructionBlock* GetInstructionBlock(const InstructionSequence* code, 43 const InstructionBlock* GetInstructionBlock(const InstructionSequence* code,
51 LifetimePosition pos) { 44 LifetimePosition pos) {
52 return code->GetInstructionBlock(pos.ToInstructionIndex()); 45 return code->GetInstructionBlock(pos.ToInstructionIndex());
53 } 46 }
54 47
55 48
56 bool IsBlockBoundary(const InstructionSequence* code, LifetimePosition pos) {
57 return pos.IsFullStart() &&
58 code->GetInstructionBlock(pos.ToInstructionIndex())->code_start() ==
59 pos.ToInstructionIndex();
60 }
61
62
63 Instruction* GetLastInstruction(InstructionSequence* code, 49 Instruction* GetLastInstruction(InstructionSequence* code,
64 const InstructionBlock* block) { 50 const InstructionBlock* block) {
65 return code->InstructionAt(block->last_instruction_index()); 51 return code->InstructionAt(block->last_instruction_index());
66 } 52 }
67 53
68 54
69 bool IsOutputRegisterOf(Instruction* instr, int index) { 55 bool IsOutputRegisterOf(Instruction* instr, int index) {
70 for (size_t i = 0; i < instr->OutputCount(); i++) { 56 for (size_t i = 0; i < instr->OutputCount(); i++) {
71 auto output = instr->OutputAt(i); 57 auto output = instr->OutputAt(i);
72 if (output->IsRegister() && 58 if (output->IsRegister() &&
(...skipping 991 matching lines...) Expand 10 before | Expand all | Expand 10 after
1064 void RegisterAllocationData::MarkAllocated(RegisterKind kind, int index) { 1050 void RegisterAllocationData::MarkAllocated(RegisterKind kind, int index) {
1065 if (kind == DOUBLE_REGISTERS) { 1051 if (kind == DOUBLE_REGISTERS) {
1066 assigned_double_registers_->Add(index); 1052 assigned_double_registers_->Add(index);
1067 } else { 1053 } else {
1068 DCHECK(kind == GENERAL_REGISTERS); 1054 DCHECK(kind == GENERAL_REGISTERS);
1069 assigned_registers_->Add(index); 1055 assigned_registers_->Add(index);
1070 } 1056 }
1071 } 1057 }
1072 1058
1073 1059
1060 bool RegisterAllocationData::IsBlockBoundary(LifetimePosition pos) const {
1061 return pos.IsFullStart() &&
1062 code()->GetInstructionBlock(pos.ToInstructionIndex())->code_start() ==
1063 pos.ToInstructionIndex();
1064 }
1065
1066
1074 ConstraintBuilder::ConstraintBuilder(RegisterAllocationData* data) 1067 ConstraintBuilder::ConstraintBuilder(RegisterAllocationData* data)
1075 : data_(data) {} 1068 : data_(data) {}
1076 1069
1077 1070
1078 InstructionOperand* ConstraintBuilder::AllocateFixed( 1071 InstructionOperand* ConstraintBuilder::AllocateFixed(
1079 UnallocatedOperand* operand, int pos, bool is_tagged) { 1072 UnallocatedOperand* operand, int pos, bool is_tagged) {
1080 TRACE("Allocating fixed reg for op %d\n", operand->virtual_register()); 1073 TRACE("Allocating fixed reg for op %d\n", operand->virtual_register());
1081 DCHECK(operand->HasFixedPolicy()); 1074 DCHECK(operand->HasFixedPolicy());
1082 InstructionOperand allocated; 1075 InstructionOperand allocated;
1083 MachineType machine_type = InstructionSequence::DefaultRepresentation(); 1076 MachineType machine_type = InstructionSequence::DefaultRepresentation();
(...skipping 762 matching lines...) Expand 10 before | Expand all | Expand 10 after
1846 DCHECK(!range->spilled()); 1839 DCHECK(!range->spilled());
1847 TRACE("Spilling live range %d\n", range->id()); 1840 TRACE("Spilling live range %d\n", range->id());
1848 auto first = range->TopLevel(); 1841 auto first = range->TopLevel();
1849 if (first->HasNoSpillType()) { 1842 if (first->HasNoSpillType()) {
1850 data()->AssignSpillRangeToLiveRange(first); 1843 data()->AssignSpillRangeToLiveRange(first);
1851 } 1844 }
1852 range->Spill(); 1845 range->Spill();
1853 } 1846 }
1854 1847
1855 1848
1849 const ZoneVector<LiveRange*>& RegisterAllocator::GetFixedRegisters() const {
1850 return mode() == DOUBLE_REGISTERS ? data()->fixed_double_live_ranges()
1851 : data()->fixed_live_ranges();
1852 }
1853
1854
1856 LinearScanAllocator::LinearScanAllocator(RegisterAllocationData* data, 1855 LinearScanAllocator::LinearScanAllocator(RegisterAllocationData* data,
1857 RegisterKind kind, Zone* local_zone) 1856 RegisterKind kind, Zone* local_zone)
1858 : RegisterAllocator(data, kind), 1857 : RegisterAllocator(data, kind),
1859 unhandled_live_ranges_(local_zone), 1858 unhandled_live_ranges_(local_zone),
1860 active_live_ranges_(local_zone), 1859 active_live_ranges_(local_zone),
1861 inactive_live_ranges_(local_zone) { 1860 inactive_live_ranges_(local_zone) {
1862 unhandled_live_ranges().reserve( 1861 unhandled_live_ranges().reserve(
1863 static_cast<size_t>(code()->VirtualRegisterCount() * 2)); 1862 static_cast<size_t>(code()->VirtualRegisterCount() * 2));
1864 active_live_ranges().reserve(8); 1863 active_live_ranges().reserve(8);
1865 inactive_live_ranges().reserve(8); 1864 inactive_live_ranges().reserve(8);
(...skipping 11 matching lines...) Expand all
1877 1876
1878 for (auto range : data()->live_ranges()) { 1877 for (auto range : data()->live_ranges()) {
1879 if (range == nullptr) continue; 1878 if (range == nullptr) continue;
1880 if (range->kind() == mode()) { 1879 if (range->kind() == mode()) {
1881 AddToUnhandledUnsorted(range); 1880 AddToUnhandledUnsorted(range);
1882 } 1881 }
1883 } 1882 }
1884 SortUnhandled(); 1883 SortUnhandled();
1885 DCHECK(UnhandledIsSorted()); 1884 DCHECK(UnhandledIsSorted());
1886 1885
1887 auto& fixed_ranges = GetFixedRegisters(data(), mode()); 1886 auto& fixed_ranges = GetFixedRegisters();
1888 for (auto current : fixed_ranges) { 1887 for (auto current : fixed_ranges) {
1889 if (current != nullptr) { 1888 if (current != nullptr) {
1890 DCHECK_EQ(mode(), current->kind()); 1889 DCHECK_EQ(mode(), current->kind());
1891 AddToInactive(current); 1890 AddToInactive(current);
1892 } 1891 }
1893 } 1892 }
1894 1893
1895 while (!unhandled_live_ranges().empty()) { 1894 while (!unhandled_live_ranges().empty()) {
1896 DCHECK(UnhandledIsSorted()); 1895 DCHECK(UnhandledIsSorted());
1897 auto current = unhandled_live_ranges().back(); 1896 auto current = unhandled_live_ranges().back();
(...skipping 475 matching lines...) Expand 10 before | Expand all | Expand 10 after
2373 LifetimePosition until, 2372 LifetimePosition until,
2374 LifetimePosition end) { 2373 LifetimePosition end) {
2375 CHECK(start < end); 2374 CHECK(start < end);
2376 auto second_part = SplitRangeAt(range, start); 2375 auto second_part = SplitRangeAt(range, start);
2377 2376
2378 if (second_part->Start() < end) { 2377 if (second_part->Start() < end) {
2379 // The split result intersects with [start, end[. 2378 // The split result intersects with [start, end[.
2380 // Split it at position between ]start+1, end[, spill the middle part 2379 // Split it at position between ]start+1, end[, spill the middle part
2381 // and put the rest to unhandled. 2380 // and put the rest to unhandled.
2382 auto third_part_end = end.PrevStart().End(); 2381 auto third_part_end = end.PrevStart().End();
2383 if (IsBlockBoundary(code(), end.Start())) { 2382 if (data()->IsBlockBoundary(end.Start())) {
2384 third_part_end = end.Start(); 2383 third_part_end = end.Start();
2385 } 2384 }
2386 auto third_part = SplitBetween( 2385 auto third_part = SplitBetween(
2387 second_part, Max(second_part->Start().End(), until), third_part_end); 2386 second_part, Max(second_part->Start().End(), until), third_part_end);
2388 2387
2389 DCHECK(third_part != second_part); 2388 DCHECK(third_part != second_part);
2390 2389
2391 Spill(second_part); 2390 Spill(second_part);
2392 AddToUnhandledSorted(third_part); 2391 AddToUnhandledSorted(third_part);
2393 } else { 2392 } else {
2394 // The split result does not intersect with [start, end[. 2393 // The split result does not intersect with [start, end[.
2395 // Nothing to spill. Just put it to unhandled as whole. 2394 // Nothing to spill. Just put it to unhandled as whole.
2396 AddToUnhandledSorted(second_part); 2395 AddToUnhandledSorted(second_part);
2397 } 2396 }
2398 } 2397 }
2399 2398
2400 2399
2401 class CoalescedLiveRanges : public ZoneObject {
2402 public:
2403 explicit CoalescedLiveRanges(Zone* zone) : storage_(zone) {}
2404
2405 LiveRange* Find(UseInterval* query) {
2406 ZoneSplayTree<Config>::Locator locator;
2407
2408 if (storage_.Find(GetKey(query), &locator)) {
2409 return locator.value();
2410 }
2411 return nullptr;
2412 }
2413
2414 // TODO(mtrofin): Change to void returning if we do not care if the interval
2415 // was previously added.
2416 bool Insert(LiveRange* range) {
2417 auto* interval = range->first_interval();
2418 while (interval != nullptr) {
2419 if (!Insert(interval, range)) return false;
2420 interval = interval->next();
2421 }
2422 return true;
2423 }
2424
2425 bool Remove(LiveRange* range) {
2426 bool ret = false;
2427 auto* segment = range->first_interval();
2428 while (segment != nullptr) {
2429 ret |= Remove(segment);
2430 segment = segment->next();
2431 }
2432 return ret;
2433 }
2434
2435 bool IsEmpty() { return storage_.is_empty(); }
2436
2437 private:
2438 struct Config {
2439 typedef std::pair<int, int> Key;
2440 typedef LiveRange* Value;
2441 static const Key kNoKey;
2442 static Value NoValue() { return nullptr; }
2443 static int Compare(const Key& a, const Key& b) {
2444 if (a.second <= b.first) return -1;
2445 if (a.first >= b.second) return 1;
2446 return 0;
2447 }
2448 };
2449
2450 Config::Key GetKey(UseInterval* interval) {
2451 if (interval == nullptr) return std::make_pair(0, 0);
2452 return std::make_pair(interval->start().value(), interval->end().value());
2453 }
2454
2455 // TODO(mtrofin): Change to void returning if we do not care if the interval
2456 // was previously added.
2457 bool Insert(UseInterval* interval, LiveRange* range) {
2458 ZoneSplayTree<Config>::Locator locator;
2459 bool ret = storage_.Insert(GetKey(interval), &locator);
2460 if (ret) locator.set_value(range);
2461 return ret;
2462 }
2463
2464 bool Remove(UseInterval* key) { return storage_.Remove(GetKey(key)); }
2465
2466 ZoneSplayTree<Config> storage_;
2467 DISALLOW_COPY_AND_ASSIGN(CoalescedLiveRanges);
2468 };
2469
2470
2471 const std::pair<int, int> CoalescedLiveRanges::Config::kNoKey = {0, 0};
2472
2473 GreedyAllocator::GreedyAllocator(RegisterAllocationData* data,
2474 RegisterKind kind, Zone* local_zone)
2475 : RegisterAllocator(data, kind),
2476 local_zone_(local_zone),
2477 allocations_(local_zone),
2478 queue_(local_zone) {}
2479
2480
2481 unsigned GreedyAllocator::GetLiveRangeSize(LiveRange* range) {
2482 auto interval = range->first_interval();
2483 if (interval == nullptr) return 0;
2484
2485 unsigned size = 0;
2486 while (interval != nullptr) {
2487 size += (interval->end().value() - interval->start().value());
2488 interval = interval->next();
2489 }
2490
2491 return size;
2492 }
2493
2494
2495 void GreedyAllocator::AssignRangeToRegister(int reg_id, LiveRange* range) {
2496 allocations_[reg_id]->Insert(range);
2497 if (range->HasRegisterAssigned()) {
2498 DCHECK_EQ(reg_id, range->assigned_register());
2499 return;
2500 }
2501 range->set_assigned_register(reg_id);
2502 range->SetUseHints(reg_id);
2503 if (range->is_phi()) {
2504 data()->GetPhiMapValueFor(range->id())->set_assigned_register(reg_id);
2505 }
2506 }
2507
2508
2509 float GreedyAllocator::CalculateSpillWeight(LiveRange* range) {
2510 InstructionOperand* first_hint = nullptr;
2511 if (range->FirstHintPosition() != nullptr) {
2512 first_hint = range->FirstHintPosition()->operand();
2513 }
2514
2515 if (range->IsFixed()) return std::numeric_limits<float>::max();
2516 bool spill;
2517 if (!FindProgressingSplitPosition(range, &spill).IsValid())
2518 return std::numeric_limits<float>::max();
2519
2520 float multiplier = 1.0;
2521 if (first_hint != nullptr && first_hint->IsRegister()) {
2522 multiplier = 3.0;
2523 }
2524
2525 unsigned use_count = 0;
2526 auto* pos = range->first_pos();
2527 while (pos != nullptr) {
2528 use_count++;
2529 pos = pos->next();
2530 }
2531
2532 unsigned range_size = GetLiveRangeSize(range);
2533 DCHECK_NE(0U, range_size);
2534
2535 return multiplier * static_cast<float>(use_count) /
2536 static_cast<float>(range_size);
2537 }
2538
2539
2540 float GreedyAllocator::CalculateMaxSpillWeight(
2541 const ZoneSet<LiveRange*>& ranges) {
2542 float max = 0.0;
2543 for (auto* r : ranges) {
2544 max = std::max(max, CalculateSpillWeight(r));
2545 }
2546 return max;
2547 }
2548
2549
2550 void GreedyAllocator::Evict(LiveRange* range) {
2551 bool removed = allocations_[range->assigned_register()]->Remove(range);
2552 CHECK(removed);
2553 range->UnsetUseHints();
2554 range->UnsetAssignedRegister();
2555 if (range->is_phi()) {
2556 data()->GetPhiMapValueFor(range->id())->UnsetAssignedRegister();
2557 }
2558 }
2559
2560
2561 bool GreedyAllocator::TryAllocatePhysicalRegister(
2562 unsigned reg_id, LiveRange* range, ZoneSet<LiveRange*>* conflicting) {
2563 auto* segment = range->first_interval();
2564
2565 auto* alloc_info = allocations_[reg_id];
2566 while (segment != nullptr) {
2567 if (auto* existing = alloc_info->Find(segment)) {
2568 DCHECK(existing->HasRegisterAssigned());
2569 conflicting->insert(existing);
2570 }
2571 segment = segment->next();
2572 }
2573 if (!conflicting->empty()) return false;
2574 // No conflicts means we can safely allocate this register to this range.
2575 AssignRangeToRegister(reg_id, range);
2576 return true;
2577 }
2578
2579
2580 int GreedyAllocator::GetHintedRegister(LiveRange* range) {
2581 int reg;
2582 if (range->FirstHintPosition(&reg) != nullptr) {
2583 return reg;
2584 }
2585 return -1;
2586 }
2587
2588
2589 bool GreedyAllocator::TryAllocate(LiveRange* current,
2590 ZoneSet<LiveRange*>* conflicting) {
2591 if (current->IsFixed()) {
2592 return TryAllocatePhysicalRegister(current->assigned_register(), current,
2593 conflicting);
2594 }
2595
2596 int hinted_reg_id = GetHintedRegister(current);
2597 if (hinted_reg_id >= 0) {
2598 if (TryAllocatePhysicalRegister(hinted_reg_id, current, conflicting)) {
2599 return true;
2600 }
2601 }
2602
2603 ZoneSet<LiveRange*> local_conflicts(local_zone());
2604 for (unsigned candidate_reg = 0; candidate_reg < allocations_.size();
2605 candidate_reg++) {
2606 if (hinted_reg_id >= 0 &&
2607 candidate_reg == static_cast<size_t>(hinted_reg_id))
2608 continue;
2609 local_conflicts.clear();
2610 if (TryAllocatePhysicalRegister(candidate_reg, current, &local_conflicts)) {
2611 conflicting->clear();
2612 return true;
2613 } else {
2614 conflicting->insert(local_conflicts.begin(), local_conflicts.end());
2615 }
2616 }
2617 return false;
2618 }
2619
2620
2621 LiveRange* GreedyAllocator::SpillBetweenUntil(LiveRange* range,
2622 LifetimePosition start,
2623 LifetimePosition until,
2624 LifetimePosition end) {
2625 CHECK(start < end);
2626 auto second_part = SplitRangeAt(range, start);
2627
2628 if (second_part->Start() < end) {
2629 // The split result intersects with [start, end[.
2630 // Split it at position between ]start+1, end[, spill the middle part
2631 // and put the rest to unhandled.
2632 auto third_part_end = end.PrevStart().End();
2633 if (IsBlockBoundary(code(), end.Start())) {
2634 third_part_end = end.Start();
2635 }
2636 auto third_part = SplitBetween(
2637 second_part, Max(second_part->Start().End(), until), third_part_end);
2638
2639 DCHECK(third_part != second_part);
2640
2641 Spill(second_part);
2642 return third_part;
2643 } else {
2644 // The split result does not intersect with [start, end[.
2645 // Nothing to spill. Just return it for re-processing.
2646 return second_part;
2647 }
2648 }
2649
2650
2651 void GreedyAllocator::Enqueue(LiveRange* range) {
2652 if (range == nullptr || range->IsEmpty()) return;
2653 unsigned size = GetLiveRangeSize(range);
2654 TRACE("Enqueuing range %d\n", range->id());
2655 queue_.push(std::make_pair(size, range));
2656 }
2657
2658
2659 bool GreedyAllocator::HandleSpillOperands(LiveRange* range) {
2660 auto position = range->Start();
2661 TRACE("Processing interval %d start=%d\n", range->id(), position.value());
2662
2663 if (!range->HasNoSpillType()) {
2664 TRACE("Live range %d already has a spill operand\n", range->id());
2665 auto next_pos = position;
2666 if (next_pos.IsGapPosition()) {
2667 next_pos = next_pos.NextStart();
2668 }
2669 auto pos = range->NextUsePositionRegisterIsBeneficial(next_pos);
2670 // If the range already has a spill operand and it doesn't need a
2671 // register immediately, split it and spill the first part of the range.
2672 if (pos == nullptr) {
2673 Spill(range);
2674 return true;
2675 } else if (pos->pos() > range->Start().NextStart()) {
2676 // Do not spill live range eagerly if use position that can benefit from
2677 // the register is too close to the start of live range.
2678 auto* reminder = SpillBetweenUntil(range, position, position, pos->pos());
2679 Enqueue(reminder);
2680 return true;
2681 }
2682 }
2683 return TryReuseSpillForPhi(range);
2684 }
2685
2686
2687 void GreedyAllocator::AllocateRegisters() {
2688 for (auto range : data()->live_ranges()) {
2689 if (range == nullptr) continue;
2690 if (range->kind() == mode()) {
2691 DCHECK(!range->HasRegisterAssigned() && !range->spilled());
2692 TRACE("Enqueueing live range %d to priority queue \n", range->id());
2693 Enqueue(range);
2694 }
2695 }
2696
2697 allocations_.resize(num_registers());
2698 for (int i = 0; i < num_registers(); i++) {
2699 allocations_[i] = new (local_zone()) CoalescedLiveRanges(local_zone());
2700 }
2701
2702 for (auto* current : GetFixedRegisters(data(), mode())) {
2703 if (current != nullptr) {
2704 DCHECK_EQ(mode(), current->kind());
2705 int reg_nr = current->assigned_register();
2706 bool inserted = allocations_[reg_nr]->Insert(current);
2707 CHECK(inserted);
2708 }
2709 }
2710
2711 while (!queue_.empty()) {
2712 auto current_pair = queue_.top();
2713 queue_.pop();
2714 auto current = current_pair.second;
2715 if (HandleSpillOperands(current)) {
2716 continue;
2717 }
2718 bool spill = false;
2719 ZoneSet<LiveRange*> conflicting(local_zone());
2720 if (!TryAllocate(current, &conflicting)) {
2721 DCHECK(!conflicting.empty());
2722 float this_weight = std::numeric_limits<float>::max();
2723 LifetimePosition split_pos =
2724 FindProgressingSplitPosition(current, &spill);
2725 if (split_pos.IsValid()) {
2726 this_weight = CalculateSpillWeight(current);
2727 }
2728
2729 bool evicted = false;
2730 for (auto* conflict : conflicting) {
2731 if (CalculateSpillWeight(conflict) < this_weight) {
2732 Evict(conflict);
2733 Enqueue(conflict);
2734 evicted = true;
2735 }
2736 }
2737 if (evicted) {
2738 conflicting.clear();
2739 TryAllocate(current, &conflicting);
2740 }
2741 if (!conflicting.empty()) {
2742 DCHECK(!current->IsFixed() || current->CanBeSpilled(current->Start()));
2743 DCHECK(split_pos.IsValid());
2744 AllocateBlockedRange(current, split_pos, spill);
2745 }
2746 }
2747 }
2748
2749 for (size_t i = 0; i < allocations_.size(); ++i) {
2750 if (!allocations_[i]->IsEmpty()) {
2751 data()->MarkAllocated(mode(), static_cast<int>(i));
2752 }
2753 }
2754 }
2755
2756
2757 LifetimePosition GreedyAllocator::GetSplittablePos(LifetimePosition pos) {
2758 auto ret = pos.PrevStart().End();
2759 if (IsBlockBoundary(code(), pos.Start())) {
2760 ret = pos.Start();
2761 }
2762 DCHECK(ret <= pos);
2763 return ret;
2764 }
2765
2766 LifetimePosition GreedyAllocator::FindProgressingSplitPosition(
2767 LiveRange* range, bool* is_spill_pos) {
2768 auto start = range->Start();
2769 auto end = range->End();
2770
2771 UsePosition* next_reg_use = range->first_pos();
2772 while (next_reg_use != nullptr &&
2773 next_reg_use->type() != UsePositionType::kRequiresRegister) {
2774 next_reg_use = next_reg_use->next();
2775 }
2776
2777 if (next_reg_use == nullptr) {
2778 *is_spill_pos = true;
2779 auto ret = FindOptimalSpillingPos(range, start);
2780 DCHECK(ret.IsValid());
2781 return ret;
2782 }
2783
2784 *is_spill_pos = false;
2785 auto reg_pos = next_reg_use->pos();
2786 auto correct_pos = GetSplittablePos(reg_pos);
2787 if (start < correct_pos && correct_pos < end) {
2788 return correct_pos;
2789 }
2790
2791 if (correct_pos >= end) {
2792 return LifetimePosition::Invalid();
2793 }
2794
2795 // Correct_pos must be at or before start. Find the next use position.
2796 next_reg_use = next_reg_use->next();
2797 auto reference = reg_pos;
2798 while (next_reg_use != nullptr) {
2799 auto pos = next_reg_use->pos();
2800 // Skip over tight successive uses.
2801 if (reference.NextStart() < pos) {
2802 break;
2803 }
2804 reference = pos;
2805 next_reg_use = next_reg_use->next();
2806 }
2807
2808 if (next_reg_use == nullptr) {
2809 // While there may not be another use, we may still have space in the range
2810 // to clip off.
2811 correct_pos = reference.NextStart();
2812 if (start < correct_pos && correct_pos < end) {
2813 return correct_pos;
2814 }
2815 return LifetimePosition::Invalid();
2816 }
2817
2818 correct_pos = GetSplittablePos(next_reg_use->pos());
2819 if (start < correct_pos && correct_pos < end) {
2820 DCHECK(reference < correct_pos);
2821 return correct_pos;
2822 }
2823 return LifetimePosition::Invalid();
2824 }
2825
2826
2827 void GreedyAllocator::AllocateBlockedRange(LiveRange* current,
2828 LifetimePosition pos, bool spill) {
2829 auto tail = SplitRangeAt(current, pos);
2830 if (spill) {
2831 Spill(tail);
2832 } else {
2833 Enqueue(tail);
2834 }
2835 if (tail != current) {
2836 Enqueue(current);
2837 }
2838 }
2839
2840
2841 SpillSlotLocator::SpillSlotLocator(RegisterAllocationData* data) 2400 SpillSlotLocator::SpillSlotLocator(RegisterAllocationData* data)
2842 : data_(data) {} 2401 : data_(data) {}
2843 2402
2844 2403
2845 void SpillSlotLocator::LocateSpillSlots() { 2404 void SpillSlotLocator::LocateSpillSlots() {
2846 auto code = data()->code(); 2405 auto code = data()->code();
2847 for (auto range : data()->live_ranges()) { 2406 for (auto range : data()->live_ranges()) {
2848 if (range == nullptr || range->IsEmpty() || range->IsChild()) continue; 2407 if (range == nullptr || range->IsEmpty() || range->IsChild()) continue;
2849 // We care only about ranges which spill in the frame. 2408 // We care only about ranges which spill in the frame.
2850 if (!range->HasSpillRange()) continue; 2409 if (!range->HasSpillRange()) continue;
2851 auto spills = range->spills_at_definition(); 2410 auto spills = range->spills_at_definition();
2852 DCHECK_NOT_NULL(spills); 2411 DCHECK_NOT_NULL(spills);
2853 for (; spills != nullptr; spills = spills->next) { 2412 for (; spills != nullptr; spills = spills->next) {
2854 code->GetInstructionBlock(spills->gap_index)->mark_needs_frame(); 2413 code->GetInstructionBlock(spills->gap_index)->mark_needs_frame();
2855 } 2414 }
2856 } 2415 }
2857 } 2416 }
2858 2417
2859 2418
2860 bool GreedyAllocator::TryReuseSpillForPhi(LiveRange* range) {
2861 if (range->IsChild() || !range->is_phi()) return false;
2862 DCHECK(!range->HasSpillOperand());
2863
2864 auto phi_map_value = data()->GetPhiMapValueFor(range->id());
2865 auto phi = phi_map_value->phi();
2866 auto block = phi_map_value->block();
2867 // Count the number of spilled operands.
2868 size_t spilled_count = 0;
2869 LiveRange* first_op = nullptr;
2870 for (size_t i = 0; i < phi->operands().size(); i++) {
2871 int op = phi->operands()[i];
2872 LiveRange* op_range = LiveRangeFor(op);
2873 if (!op_range->HasSpillRange()) continue;
2874 auto pred = code()->InstructionBlockAt(block->predecessors()[i]);
2875 auto pred_end = LifetimePosition::InstructionFromInstructionIndex(
2876 pred->last_instruction_index());
2877 while (op_range != nullptr && !op_range->CanCover(pred_end)) {
2878 op_range = op_range->next();
2879 }
2880 if (op_range != nullptr && op_range->spilled()) {
2881 spilled_count++;
2882 if (first_op == nullptr) {
2883 first_op = op_range->TopLevel();
2884 }
2885 }
2886 }
2887
2888 // Only continue if more than half of the operands are spilled.
2889 if (spilled_count * 2 <= phi->operands().size()) {
2890 return false;
2891 }
2892
2893 // Try to merge the spilled operands and count the number of merged spilled
2894 // operands.
2895 DCHECK(first_op != nullptr);
2896 auto first_op_spill = first_op->GetSpillRange();
2897 size_t num_merged = 1;
2898 for (size_t i = 1; i < phi->operands().size(); i++) {
2899 int op = phi->operands()[i];
2900 auto op_range = LiveRangeFor(op);
2901 if (!op_range->HasSpillRange()) continue;
2902 auto op_spill = op_range->GetSpillRange();
2903 if (op_spill == first_op_spill || first_op_spill->TryMerge(op_spill)) {
2904 num_merged++;
2905 }
2906 }
2907
2908 // Only continue if enough operands could be merged to the
2909 // same spill slot.
2910 if (num_merged * 2 <= phi->operands().size() ||
2911 AreUseIntervalsIntersecting(first_op_spill->interval(),
2912 range->first_interval())) {
2913 return false;
2914 }
2915
2916 // If the range does not need register soon, spill it to the merged
2917 // spill range.
2918 auto next_pos = range->Start();
2919 if (next_pos.IsGapPosition()) next_pos = next_pos.NextStart();
2920 auto pos = range->NextUsePositionRegisterIsBeneficial(next_pos);
2921 if (pos == nullptr) {
2922 auto spill_range =
2923 range->TopLevel()->HasSpillRange()
2924 ? range->TopLevel()->GetSpillRange()
2925 : data()->AssignSpillRangeToLiveRange(range->TopLevel());
2926 bool merged = first_op_spill->TryMerge(spill_range);
2927 CHECK(merged);
2928 Spill(range);
2929 return true;
2930 } else if (pos->pos() > range->Start().NextStart()) {
2931 auto spill_range =
2932 range->TopLevel()->HasSpillRange()
2933 ? range->TopLevel()->GetSpillRange()
2934 : data()->AssignSpillRangeToLiveRange(range->TopLevel());
2935 bool merged = first_op_spill->TryMerge(spill_range);
2936 CHECK(merged);
2937 Enqueue(
2938 SpillBetweenUntil(range, range->Start(), range->Start(), pos->pos()));
2939 return true;
2940 }
2941 return false;
2942 }
2943
2944
2945 OperandAssigner::OperandAssigner(RegisterAllocationData* data) : data_(data) {} 2419 OperandAssigner::OperandAssigner(RegisterAllocationData* data) : data_(data) {}
2946 2420
2947 2421
2948 void OperandAssigner::AssignSpillSlots() { 2422 void OperandAssigner::AssignSpillSlots() {
2949 auto& spill_ranges = data()->spill_ranges(); 2423 auto& spill_ranges = data()->spill_ranges();
2950 // Merge disjoint spill ranges 2424 // Merge disjoint spill ranges
2951 for (size_t i = 0; i < spill_ranges.size(); i++) { 2425 for (size_t i = 0; i < spill_ranges.size(); i++) {
2952 auto range = spill_ranges[i]; 2426 auto range = spill_ranges[i];
2953 if (range->IsEmpty()) continue; 2427 if (range->IsEmpty()) continue;
2954 for (size_t j = i + 1; j < spill_ranges.size(); j++) { 2428 for (size_t j = i + 1; j < spill_ranges.size(); j++) {
(...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after
3322 DelayedInsertionMap delayed_insertion_map(local_zone); 2796 DelayedInsertionMap delayed_insertion_map(local_zone);
3323 for (auto first_range : data()->live_ranges()) { 2797 for (auto first_range : data()->live_ranges()) {
3324 if (first_range == nullptr || first_range->IsChild()) continue; 2798 if (first_range == nullptr || first_range->IsChild()) continue;
3325 for (auto second_range = first_range->next(); second_range != nullptr; 2799 for (auto second_range = first_range->next(); second_range != nullptr;
3326 first_range = second_range, second_range = second_range->next()) { 2800 first_range = second_range, second_range = second_range->next()) {
3327 auto pos = second_range->Start(); 2801 auto pos = second_range->Start();
3328 // Add gap move if the two live ranges touch and there is no block 2802 // Add gap move if the two live ranges touch and there is no block
3329 // boundary. 2803 // boundary.
3330 if (second_range->spilled()) continue; 2804 if (second_range->spilled()) continue;
3331 if (first_range->End() != pos) continue; 2805 if (first_range->End() != pos) continue;
3332 if (IsBlockBoundary(code(), pos) && 2806 if (data()->IsBlockBoundary(pos) &&
3333 !CanEagerlyResolveControlFlow(GetInstructionBlock(code(), pos))) { 2807 !CanEagerlyResolveControlFlow(GetInstructionBlock(code(), pos))) {
3334 continue; 2808 continue;
3335 } 2809 }
3336 auto prev_operand = first_range->GetAssignedOperand(); 2810 auto prev_operand = first_range->GetAssignedOperand();
3337 auto cur_operand = second_range->GetAssignedOperand(); 2811 auto cur_operand = second_range->GetAssignedOperand();
3338 if (prev_operand.Equals(cur_operand)) continue; 2812 if (prev_operand.Equals(cur_operand)) continue;
3339 bool delay_insertion = false; 2813 bool delay_insertion = false;
3340 Instruction::GapPosition gap_pos; 2814 Instruction::GapPosition gap_pos;
3341 int gap_index = pos.ToInstructionIndex(); 2815 int gap_index = pos.ToInstructionIndex();
3342 if (pos.IsGapPosition()) { 2816 if (pos.IsGapPosition()) {
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
3387 auto eliminate = moves->PrepareInsertAfter(move); 2861 auto eliminate = moves->PrepareInsertAfter(move);
3388 to_insert.push_back(move); 2862 to_insert.push_back(move);
3389 if (eliminate != nullptr) to_eliminate.push_back(eliminate); 2863 if (eliminate != nullptr) to_eliminate.push_back(eliminate);
3390 } 2864 }
3391 } 2865 }
3392 2866
3393 2867
3394 } // namespace compiler 2868 } // namespace compiler
3395 } // namespace internal 2869 } // namespace internal
3396 } // namespace v8 2870 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/register-allocator.h ('k') | tools/gyp/v8.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698