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

Side by Side Diff: src/compiler/greedy-allocator.h

Issue 2060673002: [turbofan] Retiring Greedy Allocator (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 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/coalesced-live-ranges.cc ('k') | src/compiler/greedy-allocator.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #ifndef V8_GREEDY_ALLOCATOR_H_
6 #define V8_GREEDY_ALLOCATOR_H_
7
8 #include "src/compiler/coalesced-live-ranges.h"
9 #include "src/compiler/register-allocator.h"
10 #include "src/zone-containers.h"
11
12 namespace v8 {
13 namespace internal {
14 namespace compiler {
15
16
17 // The object of allocation scheduling. At minimum, this is a LiveRange, but
18 // we may extend this to groups of LiveRanges. It has to be comparable.
19 class AllocationCandidate {
20 public:
21 explicit AllocationCandidate(LiveRange* range)
22 : is_group_(false), size_(range->GetSize()) {
23 candidate_.range_ = range;
24 }
25
26 explicit AllocationCandidate(LiveRangeGroup* ranges)
27 : is_group_(true), size_(CalculateGroupSize(ranges)) {
28 candidate_.group_ = ranges;
29 }
30
31 // Strict ordering operators
32 bool operator<(const AllocationCandidate& other) const {
33 return size() < other.size();
34 }
35
36 bool operator>(const AllocationCandidate& other) const {
37 return size() > other.size();
38 }
39
40 bool is_group() const { return is_group_; }
41 LiveRange* live_range() const { return candidate_.range_; }
42 LiveRangeGroup* group() const { return candidate_.group_; }
43
44 private:
45 unsigned CalculateGroupSize(LiveRangeGroup* group) {
46 unsigned ret = 0;
47 for (LiveRange* range : group->ranges()) {
48 ret += range->GetSize();
49 }
50 return ret;
51 }
52
53 unsigned size() const { return size_; }
54 bool is_group_;
55 unsigned size_;
56 union {
57 LiveRange* range_;
58 LiveRangeGroup* group_;
59 } candidate_;
60 };
61
62
63 // Schedule processing (allocating) of AllocationCandidates.
64 class AllocationScheduler final : ZoneObject {
65 public:
66 explicit AllocationScheduler(Zone* zone) : queue_(zone) {}
67 void Schedule(LiveRange* range);
68 void Schedule(LiveRangeGroup* group);
69 AllocationCandidate GetNext();
70 bool empty() const { return queue_.empty(); }
71
72 private:
73 typedef ZonePriorityQueue<AllocationCandidate> ScheduleQueue;
74 ScheduleQueue queue_;
75
76 DISALLOW_COPY_AND_ASSIGN(AllocationScheduler);
77 };
78
79
80 // A variant of the LLVM Greedy Register Allocator. See
81 // http://blog.llvm.org/2011/09/greedy-register-allocation-in-llvm-30.html
82 class GreedyAllocator final : public RegisterAllocator {
83 public:
84 explicit GreedyAllocator(RegisterAllocationData* data, RegisterKind kind,
85 Zone* local_zone);
86
87 void AllocateRegisters();
88
89 private:
90 static const float kAllocatedRangeMultiplier;
91
92 static void UpdateWeightAtAllocation(LiveRange* range) {
93 DCHECK_NE(range->weight(), LiveRange::kInvalidWeight);
94 range->set_weight(range->weight() * kAllocatedRangeMultiplier);
95 }
96
97
98 static void UpdateWeightAtEviction(LiveRange* range) {
99 DCHECK_NE(range->weight(), LiveRange::kInvalidWeight);
100 range->set_weight(range->weight() / kAllocatedRangeMultiplier);
101 }
102
103 AllocationScheduler& scheduler() { return scheduler_; }
104 CoalescedLiveRanges* current_allocations(unsigned i) {
105 return allocations_[i];
106 }
107
108 CoalescedLiveRanges* current_allocations(unsigned i) const {
109 return allocations_[i];
110 }
111
112 Zone* local_zone() const { return local_zone_; }
113 ZoneVector<LiveRangeGroup*>& groups() { return groups_; }
114 const ZoneVector<LiveRangeGroup*>& groups() const { return groups_; }
115
116 // Insert fixed ranges.
117 void PreallocateFixedRanges();
118
119 void GroupLiveRanges();
120
121 // Schedule unassigned live ranges for allocation.
122 void ScheduleAllocationCandidates();
123
124 void AllocateRegisterToRange(unsigned reg_id, LiveRange* range) {
125 UpdateWeightAtAllocation(range);
126 current_allocations(reg_id)->AllocateRange(range);
127 }
128 // Evict and reschedule conflicts of a given range, at a given register.
129 void EvictAndRescheduleConflicts(unsigned reg_id, const LiveRange* range);
130
131 void TryAllocateCandidate(const AllocationCandidate& candidate);
132 void TryAllocateLiveRange(LiveRange* range);
133 void TryAllocateGroup(LiveRangeGroup* group);
134
135 // Calculate the weight of a candidate for allocation.
136 void EnsureValidRangeWeight(LiveRange* range);
137
138 // Calculate the new weight of a range that is about to be allocated.
139 float GetAllocatedRangeWeight(float candidate_weight);
140
141 // Returns kInvalidWeight if there are no conflicts, or the largest weight of
142 // a range conflicting with the given range, at the given register.
143 float GetMaximumConflictingWeight(unsigned reg_id, const LiveRange* range,
144 float competing_weight) const;
145
146 // Returns kInvalidWeight if there are no conflicts, or the largest weight of
147 // a range conflicting with the given range, at the given register.
148 float GetMaximumConflictingWeight(unsigned reg_id,
149 const LiveRangeGroup* group,
150 float group_weight) const;
151
152 // This is the extension point for splitting heuristics.
153 void SplitOrSpillBlockedRange(LiveRange* range);
154
155 // Find a good position where to fill, after a range was spilled after a call.
156 LifetimePosition FindSplitPositionAfterCall(const LiveRange* range,
157 int call_index);
158 // Split a range around all calls it passes over. Returns true if any changes
159 // were made, or false if no calls were found.
160 bool TrySplitAroundCalls(LiveRange* range);
161
162 // Find a split position at the outmost loop.
163 LifetimePosition FindSplitPositionBeforeLoops(LiveRange* range);
164
165 // Finds the first call instruction in the path of this range. Splits before
166 // and requeues that segment (if any), spills the section over the call, and
167 // returns the section after the call. The return is:
168 // - same range, if no call was found
169 // - nullptr, if the range finished at the call and there's no "after the
170 // call" portion.
171 // - the portion after the call.
172 LiveRange* GetRemainderAfterSplittingAroundFirstCall(LiveRange* range);
173
174 // While we attempt to merge spill ranges later on in the allocation pipeline,
175 // we want to ensure group elements get merged. Waiting until later may hinder
176 // merge-ability, since the pipeline merger (being naive) may create conflicts
177 // between spill ranges of group members.
178 void TryReuseSpillRangesForGroups();
179
180 LifetimePosition GetLastResortSplitPosition(const LiveRange* range);
181
182 bool IsProgressPossible(const LiveRange* range);
183
184 // Necessary heuristic: spill when all else failed.
185 void SpillRangeAsLastResort(LiveRange* range);
186
187 void AssignRangeToRegister(int reg_id, LiveRange* range);
188
189 Zone* local_zone_;
190 ZoneVector<CoalescedLiveRanges*> allocations_;
191 AllocationScheduler scheduler_;
192 ZoneVector<LiveRangeGroup*> groups_;
193
194 DISALLOW_COPY_AND_ASSIGN(GreedyAllocator);
195 };
196 } // namespace compiler
197 } // namespace internal
198 } // namespace v8
199 #endif // V8_GREEDY_ALLOCATOR_H_
OLDNEW
« no previous file with comments | « src/compiler/coalesced-live-ranges.cc ('k') | src/compiler/greedy-allocator.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698