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

Side by Side Diff: src/IceRegAlloc.cpp

Issue 300563003: Subzero: Initial O2 lowering (Closed) Base URL: https://gerrit.chromium.org/gerrit/p/native_client/pnacl-subzero.git@master
Patch Set: Jan's second-round comments. Created 6 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/IceRegAlloc.h ('k') | src/IceTargetLowering.h » ('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 //===- subzero/src/IceRegAlloc.cpp - Linear-scan implementation -----------===//
2 //
3 // The Subzero Code Generator
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements the LinearScan class, which performs the
11 // linear-scan register allocation after liveness analysis has been
12 // performed.
13 //
14 //===----------------------------------------------------------------------===//
15
16 #include "IceCfg.h"
17 #include "IceInst.h"
18 #include "IceOperand.h"
19 #include "IceRegAlloc.h"
20 #include "IceTargetLowering.h"
21
22 namespace Ice {
23
24 // Implements the linear-scan algorithm. Based on "Linear Scan
25 // Register Allocation in the Context of SSA Form and Register
26 // Constraints" by Hanspeter Mössenböck and Michael Pfeiffer,
27 // ftp://ftp.ssw.uni-linz.ac.at/pub/Papers/Moe02.PDF . This
28 // implementation is modified to take affinity into account and allow
29 // two interfering variables to share the same register in certain
30 // cases.
31 //
32 // Requires running Cfg::liveness(Liveness_RangesFull) in
33 // preparation. Results are assigned to Variable::RegNum for each
34 // Variable.
35 void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) {
36 assert(RegMaskFull.any()); // Sanity check
37 Unhandled.clear();
38 Handled.clear();
39 Inactive.clear();
40 Active.clear();
41 Ostream &Str = Func->getContext()->getStrDump();
42 Func->setCurrentNode(NULL);
43
44 // Gather the live ranges of all variables and add them to the
45 // Unhandled set. TODO: Unhandled is a set<> which is based on a
46 // balanced binary tree, so inserting live ranges for N variables is
47 // O(N log N) complexity. N may be proportional to the number of
48 // instructions, thanks to temporary generation during lowering. As
49 // a result, it may be useful to design a better data structure for
50 // storing Func->getVariables().
51 const VarList &Vars = Func->getVariables();
52 for (VarList::const_iterator I = Vars.begin(), E = Vars.end(); I != E; ++I) {
53 Variable *Var = *I;
54 // Explicitly don't consider zero-weight variables, which are
55 // meant to be spill slots.
56 if (Var->getWeight() == RegWeight::Zero)
57 continue;
58 // Don't bother if the variable has a null live range, which means
59 // it was never referenced.
60 if (Var->getLiveRange().isEmpty())
61 continue;
62 Unhandled.insert(LiveRangeWrapper(Var));
63 if (Var->hasReg()) {
64 Var->setRegNumTmp(Var->getRegNum());
65 Var->setLiveRangeInfiniteWeight();
66 }
67 }
68
69 // RegUses[I] is the number of live ranges (variables) that register
70 // I is currently assigned to. It can be greater than 1 as a result
71 // of Variable::AllowRegisterOverlap.
72 std::vector<int> RegUses(RegMaskFull.size());
73 // Unhandled is already set to all ranges in increasing order of
74 // start points.
75 assert(Active.empty());
76 assert(Inactive.empty());
77 assert(Handled.empty());
78 UnorderedRanges::iterator Next;
79
80 while (!Unhandled.empty()) {
81 LiveRangeWrapper Cur = *Unhandled.begin();
82 Unhandled.erase(Unhandled.begin());
83 if (Func->getContext()->isVerbose(IceV_LinearScan)) {
84 Str << "\nConsidering ";
85 Cur.dump(Func);
86 Str << "\n";
87 }
88 const llvm::SmallBitVector RegMask =
89 RegMaskFull &
90 Func->getTarget()->getRegisterSetForType(Cur.Var->getType());
91
92 // Check for precolored ranges. If Cur is precolored, it
93 // definitely gets that register. Previously processed live
94 // ranges would have avoided that register due to it being
95 // precolored. Future processed live ranges won't evict that
96 // register because the live range has infinite weight.
97 if (Cur.Var->hasReg()) {
98 int32_t RegNum = Cur.Var->getRegNum();
99 // RegNumTmp should have already been set above.
100 assert(Cur.Var->getRegNumTmp() == RegNum);
101 if (Func->getContext()->isVerbose(IceV_LinearScan)) {
102 Str << "Precoloring ";
103 Cur.dump(Func);
104 Str << "\n";
105 }
106 Active.push_back(Cur);
107 assert(RegUses[RegNum] >= 0);
108 ++RegUses[RegNum];
109 continue;
110 }
111
112 // Check for active ranges that have expired or become inactive.
113 for (UnorderedRanges::iterator I = Active.begin(), E = Active.end(); I != E;
114 I = Next) {
115 Next = I;
116 ++Next;
117 LiveRangeWrapper Item = *I;
118 bool Moved = false;
119 if (Item.endsBefore(Cur)) {
120 // Move Item from Active to Handled list.
121 if (Func->getContext()->isVerbose(IceV_LinearScan)) {
122 Str << "Expiring ";
123 Item.dump(Func);
124 Str << "\n";
125 }
126 Active.erase(I);
127 Handled.push_back(Item);
128 Moved = true;
129 } else if (!Item.overlapsStart(Cur)) {
130 // Move Item from Active to Inactive list.
131 if (Func->getContext()->isVerbose(IceV_LinearScan)) {
132 Str << "Inactivating ";
133 Item.dump(Func);
134 Str << "\n";
135 }
136 Active.erase(I);
137 Inactive.push_back(Item);
138 Moved = true;
139 }
140 if (Moved) {
141 // Decrement Item from RegUses[].
142 assert(Item.Var->hasRegTmp());
143 int32_t RegNum = Item.Var->getRegNumTmp();
144 --RegUses[RegNum];
145 assert(RegUses[RegNum] >= 0);
146 }
147 }
148
149 // Check for inactive ranges that have expired or reactivated.
150 for (UnorderedRanges::iterator I = Inactive.begin(), E = Inactive.end();
151 I != E; I = Next) {
152 Next = I;
153 ++Next;
154 LiveRangeWrapper Item = *I;
155 if (Item.endsBefore(Cur)) {
156 // Move Item from Inactive to Handled list.
157 if (Func->getContext()->isVerbose(IceV_LinearScan)) {
158 Str << "Expiring ";
159 Item.dump(Func);
160 Str << "\n";
161 }
162 Inactive.erase(I);
163 Handled.push_back(Item);
164 } else if (Item.overlapsStart(Cur)) {
165 // Move Item from Inactive to Active list.
166 if (Func->getContext()->isVerbose(IceV_LinearScan)) {
167 Str << "Reactivating ";
168 Item.dump(Func);
169 Str << "\n";
170 }
171 Inactive.erase(I);
172 Active.push_back(Item);
173 // Increment Item in RegUses[].
174 assert(Item.Var->hasRegTmp());
175 int32_t RegNum = Item.Var->getRegNumTmp();
176 assert(RegUses[RegNum] >= 0);
177 ++RegUses[RegNum];
178 }
179 }
180
181 // Calculate available registers into Free[].
182 llvm::SmallBitVector Free = RegMask;
183 for (SizeT i = 0; i < RegMask.size(); ++i) {
184 if (RegUses[i] > 0)
185 Free[i] = false;
186 }
187
188 // Remove registers from the Free[] list where an Inactive range
189 // overlaps with the current range.
190 for (UnorderedRanges::const_iterator I = Inactive.begin(),
191 E = Inactive.end();
192 I != E; ++I) {
193 LiveRangeWrapper Item = *I;
194 if (Item.overlaps(Cur)) {
195 int32_t RegNum = Item.Var->getRegNumTmp();
196 // Don't assert(Free[RegNum]) because in theory (though
197 // probably never in practice) there could be two inactive
198 // variables that were allowed marked with
199 // AllowRegisterOverlap.
200 Free[RegNum] = false;
201 }
202 }
203
204 // Remove registers from the Free[] list where an Unhandled range
205 // overlaps with the current range and is precolored.
206 // Cur.endsBefore(*I) is an early exit check that turns a
207 // guaranteed O(N^2) algorithm into expected linear complexity.
208 for (OrderedRanges::const_iterator I = Unhandled.begin(),
209 E = Unhandled.end();
210 I != E && !Cur.endsBefore(*I); ++I) {
211 LiveRangeWrapper Item = *I;
212 if (Item.Var->hasReg() && Item.overlaps(Cur)) {
jvoung (off chromium) 2014/06/02 17:07:43 because unhandled is sorted and !Cur.endsBefore(It
Jim Stichnoth 2014/06/04 14:18:03 Not necessarily. Example: int Cur = ...; if
jvoung (off chromium) 2014/06/04 18:17:57 Ah okay, makes sense.
213 Free[Item.Var->getRegNum()] = false; // Note: getRegNum not getRegNumTmp
214 }
215 }
216
217 // Print info about physical register availability.
218 if (Func->getContext()->isVerbose(IceV_LinearScan)) {
219 for (SizeT i = 0; i < RegMask.size(); ++i) {
220 if (RegMask[i]) {
221 Str << Func->getTarget()->getRegName(i, IceType_i32)
222 << "(U=" << RegUses[i] << ",F=" << Free[i] << ") ";
223 }
224 }
225 Str << "\n";
226 }
227
228 Variable *Prefer = Cur.Var->getPreferredRegister();
229 int32_t PreferReg = Prefer && Prefer->hasRegTmp() ? Prefer->getRegNumTmp()
230 : Variable::NoRegister;
231 if (PreferReg != Variable::NoRegister &&
232 (Cur.Var->getRegisterOverlap() || Free[PreferReg])) {
233 // First choice: a preferred register that is either free or is
234 // allowed to overlap with its linked variable.
235 Cur.Var->setRegNumTmp(PreferReg);
236 if (Func->getContext()->isVerbose(IceV_LinearScan)) {
237 Str << "Preferring ";
238 Cur.dump(Func);
239 Str << "\n";
240 }
241 assert(RegUses[PreferReg] >= 0);
242 ++RegUses[PreferReg];
243 Active.push_back(Cur);
244 } else if (Free.any()) {
245 // Second choice: any free register. TODO: After explicit
246 // affinity is considered, is there a strategy better than just
247 // picking the lowest-numbered available register?
248 int32_t RegNum = Free.find_first();
249 Cur.Var->setRegNumTmp(RegNum);
250 if (Func->getContext()->isVerbose(IceV_LinearScan)) {
251 Str << "Allocating ";
252 Cur.dump(Func);
253 Str << "\n";
254 }
255 assert(RegUses[RegNum] >= 0);
256 ++RegUses[RegNum];
257 Active.push_back(Cur);
258 } else {
259 // Fallback: there are no free registers, so we look for the
260 // lowest-weight register and see if Cur has higher weight.
261 std::vector<RegWeight> Weights(RegMask.size());
262 // Check Active ranges.
263 for (UnorderedRanges::const_iterator I = Active.begin(), E = Active.end();
264 I != E; ++I) {
265 LiveRangeWrapper Item = *I;
266 assert(Item.overlaps(Cur));
267 int32_t RegNum = Item.Var->getRegNumTmp();
268 assert(Item.Var->hasRegTmp());
269 Weights[RegNum].addWeight(Item.range().getWeight());
270 }
271 // Same as above, but check Inactive ranges instead of Active.
272 for (UnorderedRanges::const_iterator I = Inactive.begin(),
273 E = Inactive.end();
274 I != E; ++I) {
275 LiveRangeWrapper Item = *I;
jvoung (off chromium) 2014/06/02 17:07:43 Do you have to check for overlap first? For Active
Jim Stichnoth 2014/06/04 14:18:03 I think you're right and the lack of overlap check
276 int32_t RegNum = Item.Var->getRegNumTmp();
277 assert(Item.Var->hasRegTmp());
278 Weights[RegNum].addWeight(Item.range().getWeight());
279 }
280 // Check Unhandled ranges that overlap Cur and are precolored.
281 // Cur.endsBefore(*I) is an early exit check that turns a
282 // guaranteed O(N^2) algorithm into expected linear complexity.
283 for (OrderedRanges::const_iterator I = Unhandled.begin(),
284 E = Unhandled.end();
285 I != E && !Cur.endsBefore(*I); ++I) {
286 LiveRangeWrapper Item = *I;
287 int32_t RegNum = Item.Var->getRegNumTmp();
288 if (RegNum < 0)
289 continue;
290 if (Item.overlaps(Cur))
291 Weights[RegNum].setWeight(RegWeight::Inf);
292 }
293
294 // All the weights are now calculated. Find the register with
295 // smallest weight.
296 int32_t MinWeightIndex = RegMask.find_first();
297 // MinWeightIndex must be valid because of the initial
298 // RegMask.any() test.
299 assert(MinWeightIndex >= 0);
300 for (SizeT i = MinWeightIndex + 1; i < Weights.size(); ++i) {
301 if (RegMask[i] && Weights[i] < Weights[MinWeightIndex])
302 MinWeightIndex = i;
303 }
304
305 if (Cur.range().getWeight() <= Weights[MinWeightIndex]) {
306 // Cur doesn't have priority over any other live ranges, so
307 // don't allocate any register to it, and move it to the
308 // Handled state.
309 Handled.push_back(Cur);
310 if (Cur.range().getWeight().isInf()) {
311 Func->setError("Unable to find a physical register for an "
312 "infinite-weight live range");
313 }
314 } else {
315 // Evict all live ranges in Active that register number
316 // MinWeightIndex is assigned to.
317 for (UnorderedRanges::iterator I = Active.begin(), E = Active.end();
318 I != E; I = Next) {
319 Next = I;
320 ++Next;
321 LiveRangeWrapper Item = *I;
322 if (Item.Var->getRegNumTmp() == MinWeightIndex) {
323 if (Func->getContext()->isVerbose(IceV_LinearScan)) {
324 Str << "Evicting ";
325 Item.dump(Func);
326 Str << "\n";
327 }
328 --RegUses[MinWeightIndex];
329 assert(RegUses[MinWeightIndex] >= 0);
330 Item.Var->setRegNumTmp(Variable::NoRegister);
331 Active.erase(I);
332 Handled.push_back(Item);
333 }
334 }
335 // Do the same for Inactive.
336 for (UnorderedRanges::iterator I = Inactive.begin(), E = Inactive.end();
337 I != E; I = Next) {
338 Next = I;
339 ++Next;
340 LiveRangeWrapper Item = *I;
341 if (Item.Var->getRegNumTmp() == MinWeightIndex) {
342 if (Func->getContext()->isVerbose(IceV_LinearScan)) {
343 Str << "Evicting ";
344 Item.dump(Func);
345 Str << "\n";
346 }
347 Item.Var->setRegNumTmp(Variable::NoRegister);
348 Inactive.erase(I);
349 Handled.push_back(Item);
350 }
351 }
352 // Assign the register to Cur.
353 Cur.Var->setRegNumTmp(MinWeightIndex);
354 assert(RegUses[MinWeightIndex] >= 0);
355 ++RegUses[MinWeightIndex];
356 Active.push_back(Cur);
357 if (Func->getContext()->isVerbose(IceV_LinearScan)) {
358 Str << "Allocating ";
359 Cur.dump(Func);
360 Str << "\n";
361 }
362 }
363 }
364 dump(Func);
365 }
366 // Move anything Active or Inactive to Handled for easier handling.
367 for (UnorderedRanges::iterator I = Active.begin(), E = Active.end(); I != E;
368 I = Next) {
369 Next = I;
370 ++Next;
371 Handled.push_back(*I);
372 Active.erase(I);
373 }
374 for (UnorderedRanges::iterator I = Inactive.begin(), E = Inactive.end();
375 I != E; I = Next) {
376 Next = I;
377 ++Next;
378 Handled.push_back(*I);
379 Inactive.erase(I);
380 }
381 dump(Func);
382
383 // Finish up by assigning RegNumTmp->RegNum for each Variable.
384 for (UnorderedRanges::const_iterator I = Handled.begin(), E = Handled.end();
385 I != E; ++I) {
386 LiveRangeWrapper Item = *I;
387 int32_t RegNum = Item.Var->getRegNumTmp();
388 if (Func->getContext()->isVerbose(IceV_LinearScan)) {
389 if (!Item.Var->hasRegTmp()) {
390 Str << "Not assigning ";
391 Item.Var->dump(Func);
392 Str << "\n";
393 } else {
394 Str << (RegNum == Item.Var->getRegNum() ? "Reassigning " : "Assigning ")
395 << Func->getTarget()->getRegName(RegNum, IceType_i32) << "(r"
396 << RegNum << ") to ";
397 Item.Var->dump(Func);
398 Str << "\n";
399 }
400 }
401 Item.Var->setRegNum(Item.Var->getRegNumTmp());
402 }
403
404 // TODO: Consider running register allocation one more time, with
405 // infinite registers, for two reasons. First, evicted live ranges
406 // get a second chance for a register. Second, it allows coalescing
407 // of stack slots. If there is no time budget for the second
408 // register allocation run, each unallocated variable just gets its
409 // own slot.
410 //
411 // Another idea for coalescing stack slots is to initialize the
412 // Unhandled list with just the unallocated variables, saving time
413 // but not offering second-chance opportunities.
414 }
415
416 // ======================== Dump routines ======================== //
417
418 void LiveRangeWrapper::dump(const Cfg *Func) const {
419 Ostream &Str = Func->getContext()->getStrDump();
420 const static size_t BufLen = 30;
421 char buf[BufLen];
422 snprintf(buf, BufLen, "%2d", Var->getRegNumTmp());
423 Str << "R=" << buf << " V=";
424 Var->dump(Func);
425 Str << " Range=" << range();
426 }
427
428 void LinearScan::dump(Cfg *Func) const {
429 Ostream &Str = Func->getContext()->getStrDump();
430 if (!Func->getContext()->isVerbose(IceV_LinearScan))
431 return;
432 Func->setCurrentNode(NULL);
433 Str << "**** Current regalloc state:\n";
434 Str << "++++++ Handled:\n";
435 for (UnorderedRanges::const_iterator I = Handled.begin(), E = Handled.end();
436 I != E; ++I) {
437 I->dump(Func);
438 Str << "\n";
439 }
440 Str << "++++++ Unhandled:\n";
441 for (OrderedRanges::const_iterator I = Unhandled.begin(), E = Unhandled.end();
442 I != E; ++I) {
443 I->dump(Func);
444 Str << "\n";
445 }
446 Str << "++++++ Active:\n";
447 for (UnorderedRanges::const_iterator I = Active.begin(), E = Active.end();
448 I != E; ++I) {
449 I->dump(Func);
450 Str << "\n";
451 }
452 Str << "++++++ Inactive:\n";
453 for (UnorderedRanges::const_iterator I = Inactive.begin(), E = Inactive.end();
454 I != E; ++I) {
455 I->dump(Func);
456 Str << "\n";
457 }
458 }
459
460 } // end of namespace Ice
OLDNEW
« no previous file with comments | « src/IceRegAlloc.h ('k') | src/IceTargetLowering.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698