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

Side by Side Diff: src/compiler/coalesced-live-ranges.cc

Issue 1219063017: [turbofan] Unit tests for live range conflicts. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 5 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
OLDNEW
1 // Copyright 2015 the V8 project authors. All rights reserved. 1 // Copyright 2015 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/compiler/coalesced-live-ranges.h" 5 #include "src/compiler/coalesced-live-ranges.h"
6 #include "src/compiler/greedy-allocator.h" 6 #include "src/compiler/greedy-allocator.h"
7 #include "src/compiler/register-allocator.h" 7 #include "src/compiler/register-allocator.h"
8 8
9 namespace v8 { 9 namespace v8 {
10 namespace internal { 10 namespace internal {
11 namespace compiler { 11 namespace compiler {
12 12
13 #define TRACE(...) \ 13
14 do { \ 14 LiveRangeConflictIterator::LiveRangeConflictIterator(const LiveRange* range,
15 if (FLAG_trace_alloc) PrintF(__VA_ARGS__); \ 15 IntervalStore* storage)
16 } while (false) 16 : query_(range->first_interval()), pos_(storage->end()), storage_(storage) {
17 MovePosAndQueryToFirstConflict();
18 }
17 19
18 20
19 const float CoalescedLiveRanges::kAllocatedRangeMultiplier = 10.0; 21 LiveRange* LiveRangeConflictIterator::Current() const {
22 if (IsFinished()) return nullptr;
23 return pos_->range;
24 }
25
26
27 void LiveRangeConflictIterator::MovePosToFirstConflictForQuery() {
28 DCHECK(query_ != nullptr);
29 auto end = storage_->end();
30 LifetimePosition q_start = query_->start();
31 LifetimePosition q_end = query_->end();
32
33 if (storage_->empty() || storage_->rbegin()->end <= q_start ||
34 storage_->begin()->start >= q_end) {
35 pos_ = end;
36 return;
37 }
38
39 pos_ = storage_->upper_bound(AsAllocatedInterval(q_start));
40 // pos is either at the end (no start strictly greater than q_start) or
41 // at some position with the aforementioned property. In either case, the
42 // allocated interval before this one may intersect our query:
43 // either because, although it starts before this query's start, it ends
44 // after; or because it starts exactly at the query start. So unless we're
45 // right at the beginning of the storage - meaning the first allocated
46 // interval is also starting after this query's start - see what's behind.
47 if (pos_ != storage_->begin()) {
48 --pos_;
49 if (!QueryIntersectsAllocatedInterval()) {
50 // The interval behind wasn't intersecting, so move back.
51 ++pos_;
52 }
53 }
54 if (pos_ == end || !QueryIntersectsAllocatedInterval()) {
55 pos_ = end;
56 }
57 }
58
59
60 void LiveRangeConflictIterator::MovePosAndQueryToFirstConflict() {
61 auto end = storage_->end();
62 for (; query_ != nullptr; query_ = query_->next()) {
63 MovePosToFirstConflictForQuery();
64 if (pos_ == end) continue;
65 DCHECK(QueryIntersectsAllocatedInterval());
66 break;
Jarin 2015/07/21 08:51:18 This continue-break gymnastics looks awkward. How
Mircea Trofin 2015/07/21 14:51:01 Done.
67 }
68
69 if (query_ == nullptr) Invalidate();
70 }
71
72
73 void LiveRangeConflictIterator::IncrementPosAndSkipOverRepetitions() {
74 auto end = storage_->end();
75 DCHECK(pos_ != end);
76 LiveRange* current_conflict = Current();
77 while (pos_ != end && pos_->range == current_conflict) {
78 ++pos_;
79 }
80 }
81
82
83 LiveRange* LiveRangeConflictIterator::InternalGetNext(bool clean_behind) {
84 if (IsFinished()) return nullptr;
85
86 LiveRange* to_clear = Current();
87 IncrementPosAndSkipOverRepetitions();
88 // At this point, pos_ is either at the end, or on an interval that doesn't
89 // correspond to the same range as to_clear. This interval may not even be
90 // a conflict.
91 if (clean_behind) {
92 // Since we parked pos_ on an iterator that won't be affected by removal,
93 // we can safely delete to_clear's intervals.
94 for (auto interval = to_clear->first_interval(); interval != nullptr;
95 interval = interval->next()) {
96 storage_->erase({interval->start(), interval->end(), nullptr});
Jarin 2015/07/21 08:51:18 Uniform initialization is banned in Chrome, appare
Mircea Trofin 2015/07/21 14:51:01 Done.
97 }
98 }
99 // We may have parked pos_ at the end, or on a non-conflict. In that case,
100 // move to the next query and reinitialize pos and query. This may invalidate
101 // the iterator, if no more conflicts are available.
102 if (!QueryIntersectsAllocatedInterval()) {
103 query_ = query_->next();
104 MovePosAndQueryToFirstConflict();
105 }
106 return Current();
107 }
108
109
110 LiveRangeConflictIterator CoalescedLiveRanges::GetConflicts(
111 const LiveRange* range) {
112 return LiveRangeConflictIterator(range, &storage());
113 }
114
20 115
21 void CoalescedLiveRanges::AllocateRange(LiveRange* range) { 116 void CoalescedLiveRanges::AllocateRange(LiveRange* range) {
22 UpdateWeightAtAllocation(range);
23 for (auto interval = range->first_interval(); interval != nullptr; 117 for (auto interval = range->first_interval(); interval != nullptr;
24 interval = interval->next()) { 118 interval = interval->next()) {
25 storage().insert({interval->start(), interval->end(), range}); 119 storage().insert({interval->start(), interval->end(), range});
Jarin 2015/07/21 08:51:18 Same here, no uniform initialization.
Mircea Trofin 2015/07/21 14:51:01 Done.
26 } 120 }
27 } 121 }
28 122
29 123
30 void CoalescedLiveRanges::Remove(LiveRange* range) { 124 bool CoalescedLiveRanges::TestOnlyVerifyAllocationsAreValid() const {
31 for (auto interval = range->first_interval(); interval != nullptr;
32 interval = interval->next()) {
33 storage().erase({interval->start(), interval->end(), nullptr});
34 }
35 range->UnsetAssignedRegister();
36 }
37
38
39 float CoalescedLiveRanges::GetMaximumConflictingWeight(
40 const LiveRange* range) const {
41 float ret = LiveRange::kInvalidWeight;
42 auto end = storage().end();
43 for (auto query = range->first_interval(); query != nullptr;
44 query = query->next()) {
45 auto conflict = GetFirstConflict(query);
46
47 if (conflict == end) continue;
48 for (; QueryIntersectsAllocatedInterval(query, conflict); ++conflict) {
49 // It is possible we'll visit the same range multiple times, because
50 // successive (not necessarily consecutive) intervals belong to the same
51 // range, or because different intervals of the query range have the same
52 // range as conflict.
53 DCHECK_NE(conflict->range->weight(), LiveRange::kInvalidWeight);
54 ret = Max(ret, conflict->range->weight());
55 if (ret == LiveRange::kMaxWeight) break;
56 }
57 }
58 return ret;
59 }
60
61
62 void CoalescedLiveRanges::EvictAndRescheduleConflicts(
63 LiveRange* range, AllocationScheduler* scheduler) {
64 auto end = storage().end();
65
66 for (auto query = range->first_interval(); query != nullptr;
67 query = query->next()) {
68 auto conflict = GetFirstConflict(query);
69 if (conflict == end) continue;
70 while (QueryIntersectsAllocatedInterval(query, conflict)) {
71 LiveRange* range_to_evict = conflict->range;
72 // Bypass successive intervals belonging to the same range, because we're
73 // about to remove this range, and we don't want the storage iterator to
74 // become invalid.
75 while (conflict != end && conflict->range == range_to_evict) {
76 ++conflict;
77 }
78
79 DCHECK(range_to_evict->HasRegisterAssigned());
80 CHECK(!range_to_evict->IsFixed());
81 Remove(range_to_evict);
82 UpdateWeightAtEviction(range_to_evict);
83 TRACE("Evicted range %d.\n", range_to_evict->id());
84 scheduler->Schedule(range_to_evict);
85 }
86 }
87 }
88
89
90 bool CoalescedLiveRanges::VerifyAllocationsAreValid() const {
91 LifetimePosition last_end = LifetimePosition::GapFromInstructionIndex(0); 125 LifetimePosition last_end = LifetimePosition::GapFromInstructionIndex(0);
92 for (auto i : storage_) { 126 for (auto i : storage_) {
93 if (i.start < last_end) { 127 if (i.start < last_end) {
94 return false; 128 return false;
95 } 129 }
96 last_end = i.end; 130 last_end = i.end;
97 } 131 }
98 return true; 132 return true;
99 } 133 }
100 134
101 135
102 void CoalescedLiveRanges::UpdateWeightAtAllocation(LiveRange* range) {
103 DCHECK_NE(range->weight(), LiveRange::kInvalidWeight);
104 range->set_weight(range->weight() * kAllocatedRangeMultiplier);
105 }
106
107
108 void CoalescedLiveRanges::UpdateWeightAtEviction(LiveRange* range) {
109 DCHECK_NE(range->weight(), LiveRange::kInvalidWeight);
110 range->set_weight(range->weight() / kAllocatedRangeMultiplier);
111 }
112
113
114 CoalescedLiveRanges::interval_iterator CoalescedLiveRanges::GetFirstConflict(
115 const UseInterval* query) const {
116 DCHECK(query != nullptr);
117 auto end = storage().end();
118 LifetimePosition q_start = query->start();
119 LifetimePosition q_end = query->end();
120
121 if (storage().empty() || storage().rbegin()->end <= q_start ||
122 storage().begin()->start >= q_end) {
123 return end;
124 }
125
126 auto ret = storage().upper_bound(AsAllocatedInterval(q_start));
127 // ret is either at the end (no start strictly greater than q_start) or
128 // at some position with the aforementioned property. In either case, the
129 // allocated interval before this one may intersect our query:
130 // either because, although it starts before this query's start, it ends
131 // after; or because it starts exactly at the query start. So unless we're
132 // right at the beginning of the storage - meaning the first allocated
133 // interval is also starting after this query's start - see what's behind.
134 if (ret != storage().begin()) {
135 --ret;
136 if (!QueryIntersectsAllocatedInterval(query, ret)) {
137 // The interval behind wasn't intersecting, so move back.
138 ++ret;
139 }
140 }
141 if (ret != end && QueryIntersectsAllocatedInterval(query, ret)) return ret;
142 return end;
143 }
144
145
146 } // namespace compiler 136 } // namespace compiler
147 } // namespace internal 137 } // namespace internal
148 } // namespace v8 138 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698