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

Side by Side Diff: runtime/vm/flow_graph_allocator.h

Issue 10696151: Skeleton of a linear scan register allocator. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 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 | Annotate | Revision Log
OLDNEW
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 #ifndef VM_FLOW_GRAPH_ALLOCATOR_H_ 5 #ifndef VM_FLOW_GRAPH_ALLOCATOR_H_
6 #define VM_FLOW_GRAPH_ALLOCATOR_H_ 6 #define VM_FLOW_GRAPH_ALLOCATOR_H_
7 7
8 #include "vm/growable_array.h" 8 #include "vm/growable_array.h"
9 #include "vm/intermediate_language.h" 9 #include "vm/intermediate_language.h"
10 10
11 namespace dart { 11 namespace dart {
12 12
13 class FlowGraphBuilder;
14 class LiveRange;
15 class UseInterval;
16
13 class FlowGraphAllocator : public ValueObject { 17 class FlowGraphAllocator : public ValueObject {
14 public: 18 public:
15 FlowGraphAllocator(const GrowableArray<BlockEntryInstr*>& postorder, 19 FlowGraphAllocator(const GrowableArray<BlockEntryInstr*>& block_order,
16 intptr_t max_ssa_temp_index); 20 FlowGraphBuilder* builder);
17 21
18 void ResolveConstraints(); 22 void AllocateRegisters();
19 23
20 // Build live-in and live-out sets for each block. 24 // Build live-in and live-out sets for each block.
21 void AnalyzeLiveness(); 25 void AnalyzeLiveness();
22 26
23 private: 27 private:
24 // Compute initial values for live-out, kill and live-in sets. 28 // Compute initial values for live-out, kill and live-in sets.
25 void ComputeInitialSets(); 29 void ComputeInitialSets();
26 30
27 // Update live-out set for the given block: live-out should contain 31 // Update live-out set for the given block: live-out should contain
28 // all values that are live-in for block's successors. 32 // all values that are live-in for block's successors.
29 // Returns true if live-out set was changed. 33 // Returns true if live-out set was changed.
30 bool UpdateLiveOut(BlockEntryInstr* instr); 34 bool UpdateLiveOut(BlockEntryInstr* instr);
31 35
32 // Update live-in set for the given block: live-in should contain 36 // Update live-in set for the given block: live-in should contain
33 // all values taht are live-out from the block and are not defined 37 // all values taht are live-out from the block and are not defined
34 // by this block. 38 // by this block.
35 // Returns true if live-in set was changed. 39 // Returns true if live-in set was changed.
36 bool UpdateLiveIn(BlockEntryInstr* instr); 40 bool UpdateLiveIn(BlockEntryInstr* instr);
37 41
38 // Perform fix-point iteration updating live-out and live-in sets 42 // Perform fix-point iteration updating live-out and live-in sets
39 // for blocks until they stop changing. 43 // for blocks until they stop changing.
40 void ComputeLiveInAndLiveOutSets(); 44 void ComputeLiveInAndLiveOutSets();
41 45
42 // Print results of liveness analysis. 46 // Print results of liveness analysis.
43 void DumpLiveness(); 47 void DumpLiveness();
44 48
49 FlowGraphBuilder* builder_;
srdjan 2012/07/10 23:27:54 Move all instance fields together, to the end. The
Vyacheslav Egorov (Google) 2012/07/11 13:27:58 Done. Moved fields down. Added comments to each ne
50
45 // Live-out sets for each block. They contain indices of SSA values 51 // Live-out sets for each block. They contain indices of SSA values
46 // that are live out from this block: that is values that were either 52 // that are live out from this block: that is values that were either
47 // defined in this block or live into it and that are used in some 53 // defined in this block or live into it and that are used in some
48 // successor block. 54 // successor block.
49 GrowableArray<BitVector*> live_out_; 55 GrowableArray<BitVector*> live_out_;
50 56
51 // Kill sets for each block. They contain indices of SSA values that 57 // Kill sets for each block. They contain indices of SSA values that
52 // are defined by this block. 58 // are defined by this block.
53 GrowableArray<BitVector*> kill_; 59 GrowableArray<BitVector*> kill_;
54 60
55 // Live-in sets for each block. They contain indices of SSA values 61 // Live-in sets for each block. They contain indices of SSA values
56 // that are used by this block or its successors. 62 // that are used by this block or its successors.
57 GrowableArray<BitVector*> live_in_; 63 GrowableArray<BitVector*> live_in_;
58 64
65 const GrowableArray<BlockEntryInstr*>& block_order_;
59 const GrowableArray<BlockEntryInstr*>& postorder_; 66 const GrowableArray<BlockEntryInstr*>& postorder_;
60 67
61 // Number of virtual registers. Currently equal to the number of 68 // Number of virtual registers. Currently equal to the number of
62 // SSA values. 69 // SSA values.
63 const intptr_t vreg_count_; 70 const intptr_t vreg_count_;
64 71
72 void NumberInstructions();
73
74 LiveRange* GetLiveRange(intptr_t vreg);
75 void BuildLiveRanges();
76 void PrintLiveRanges();
77
78
79 void UseValue(Instruction* instr,
80 intptr_t def,
81 intptr_t use,
82 intptr_t vreg,
83 Location* loc,
84 bool use_at_end);
85 void Define(Instruction* instr, intptr_t def, intptr_t vreg, Location* loc);
86
87 void AddToUnallocated(UseInterval* chain);
88 void BlockLocation(Location loc, intptr_t pos);
89
90 bool AllocateFreeRegister(UseInterval* unallocated);
91 void AssignFreeRegister(UseInterval* unallocated, Register reg);
92
93 void FinalizeInterval(UseInterval* interval, Location loc);
94 void AdvanceActiveIntervals(const intptr_t start);
95
96 bool UnallocatedIsSorted();
97 void AllocateCPURegisters();
98
99 GrowableArray<LiveRange*> live_ranges_;
100
101 GrowableArray<UseInterval*> unallocated_;
102
103 UseInterval* cpu_regs_[kNumberOfCpuRegisters];
104
65 DISALLOW_COPY_AND_ASSIGN(FlowGraphAllocator); 105 DISALLOW_COPY_AND_ASSIGN(FlowGraphAllocator);
66 }; 106 };
67 107
108
109 // UsePosition represents a single use of an SSA value by some instruction.
110 // It points to a location slot which either tells register allocator
111 // where instruction expects the value (if slot contains a fixed location) or
112 // asks register allocator to allocate storage (register or spill slot) for
113 // this use with certain properties (if slot contain an unallocated location).
114 class UsePosition : public ZoneAllocated {
115 public:
116 static const intptr_t kFixedUse = 0x1;
117 static const intptr_t kSameAsFirstUse = 0x2;
118 static const intptr_t kInstructionTagMask = 0x3;
srdjan 2012/07/10 23:27:54 If you make the upper three enum, you could use ty
Vyacheslav Egorov (Google) 2012/07/11 13:27:58 Switched to enum. This is a pretty ugly place. I
119 static const intptr_t kPositionShift = 2;
120
121 static intptr_t FlagForUse(Location* loc) {
srdjan 2012/07/10 23:27:54 const Location&
Vyacheslav Egorov (Google) 2012/07/11 13:27:58 Done.
122 ASSERT(loc != NULL);
123 if (loc->IsRegister()) return kFixedUse;
124 if (loc->IsUnallocated() &&
125 loc->policy() == Location::kSameAsFirstInput) {
srdjan 2012/07/10 23:27:54 Add parenthesis
Vyacheslav Egorov (Google) 2012/07/11 13:27:58 Done.
126 return kSameAsFirstUse;
127 }
128 return kInstructionTagMask;
129 }
130
131 // TODO(vegorov): we encode either position or instruction pointer
132 // into the pos_ field to generate moves when needed to resolve
133 // fixed or same-as-first constraints, but this looks ugly.
134 UsePosition(Instruction* instr,
135 intptr_t pos,
136 UsePosition* next,
137 Location* location_slot)
138 : pos_(pos << kPositionShift),
srdjan 2012/07/10 23:27:54 This shift is wasted if instr != NULL. Maybe set i
Vyacheslav Egorov (Google) 2012/07/11 13:27:58 instr != NULL is considered an unlikely occasion t
srdjan 2012/07/11 17:22:31 Add comment, otherwise 'somebody' may clean it up
139 location_slot_(location_slot),
140 next_(next) {
141 if (instr != NULL) {
142 pos_ = reinterpret_cast<intptr_t>(instr) | FlagForUse(location_slot_);
143 }
144 ASSERT(this->pos() == pos);
145 }
146
147 // Tell the use that it should load the value from the given location.
148 // If location slot for the use is flexible (unallocated) it will be updated
149 // with the given location. Otherwise a move will be scheduled from the given
150 // location to the location already stored in the slot.
151 void AssignLocation(Location loc);
152
153 Location* location_slot() const { return location_slot_; }
154 void set_location_slot(Location* location_slot) {
155 location_slot_ = location_slot;
156 }
157
158 void set_next(UsePosition* next) { next_ = next; }
159 UsePosition* next() const { return next_; }
160
161 intptr_t pos() const {
162 if ((pos_ & kInstructionTagMask) != 0) {
163 return instr()->pos();
164 }
165 return pos_ >> kPositionShift;
166 }
167
168 Instruction* instr() const {
169 ASSERT((pos_ & kInstructionTagMask) != 0);
170 return reinterpret_cast<Instruction*>(pos_ & ~kInstructionTagMask);
171 }
172
173 bool HasHint() const {
174 return (pos_ & kInstructionTagMask) == kFixedUse;
175 }
176
177 Location hint() const {
178 ASSERT(HasHint());
179 ASSERT(location_slot()->IsRegister());
180 return *location_slot_;
181 }
182
183 private:
184 intptr_t pos_;
185 Location* location_slot_;
186 UsePosition* next_;
187 };
188
189
190 // UseInterval represents a holeless half open interval of liveness for a given
191 // SSA value: [start, end). The interval can cover zero or more uses.
192 // During the register allocation UseIntervals from different live ranges
193 // allocated to the same register will be chained together through
194 // next_allocated_ field.
195 // Note: currently all uses of the same SSA value are linked together into a
196 // single list (and not split between UseIntervals).
srdjan 2012/07/10 23:27:54 Please describe what are start and end values (wha
Vyacheslav Egorov (Google) 2012/07/11 13:27:58 Expanded comment. Added comment to NumberInstructi
197 class UseInterval : public ZoneAllocated {
198 public:
199 UseInterval(intptr_t vreg, intptr_t start, intptr_t end, UseInterval* next)
200 : vreg_(vreg),
201 start_(start),
202 end_(end),
203 uses_((next == NULL) ? NULL : next->uses_),
204 next_(next),
205 next_allocated_(next) { }
206
207
208 void AddUse(Instruction* instr, intptr_t pos, Location* loc);
209 void Print();
210
211 intptr_t vreg() const { return vreg_; }
212 intptr_t start() const { return start_; }
213 intptr_t end() const { return end_; }
214 UsePosition* first_use() const { return uses_; }
215 UseInterval* next() const { return next_; }
216
217 bool Contains(intptr_t pos) {
srdjan 2012/07/10 23:27:54 const
Vyacheslav Egorov (Google) 2012/07/11 13:27:58 Done.
218 return (start() <= pos) && (pos < end());
219 }
220
221 intptr_t Intersect(UseInterval* other);
222
223 UseInterval* Split(intptr_t pos);
224
225 void set_next_allocated(UseInterval* next_allocated) {
226 next_allocated_ = next_allocated;
227 }
228 UseInterval* next_allocated() const { return next_allocated_; }
229
230 private:
231 friend class LiveRange;
232 const intptr_t vreg_;
233
234 intptr_t start_;
235 intptr_t end_;
236
237 UsePosition* uses_;
238
239 UseInterval* next_;
240 UseInterval* next_allocated_;
241 };
242
243
244 // LiveRange represents a sequence of UseIntervals for a given SSA value.
245 // TODO(vegorov): this class is actually redundant currently.
246 class LiveRange : public ZoneAllocated {
247 public:
248 explicit LiveRange(intptr_t vreg) : vreg_(vreg), head_(NULL) { }
249
250 void DefineAt(Instruction* instr, intptr_t pos, Location* loc);
251
252 void UseAt(Instruction* instr,
253 intptr_t def_pos,
254 intptr_t use_pos,
255 bool use_at_end,
256 Location* loc);
257
258 void AddUseInterval(intptr_t start, intptr_t end);
259
260 void Print();
261
262 UseInterval* head() const { return head_; }
263
264 private:
265 const intptr_t vreg_;
266 UseInterval* head_;
267 };
268
269
68 } // namespace dart 270 } // namespace dart
69 271
70 #endif // VM_FLOW_GRAPH_ALLOCATOR_H_ 272 #endif // VM_FLOW_GRAPH_ALLOCATOR_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698