blob: 36ada129b3d6611fedc44e55ad01ee1cb54e16ca [file] [log] [blame]
Jim Stichnothd97c7df2014-06-04 11:57:08 -07001//===- 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
22namespace Ice {
23
Jim Stichnothad403532014-09-25 12:44:17 -070024namespace {
25
26// Returns true if Var has any definitions within Item's live range.
27bool overlapsDefs(const Cfg *Func, const LiveRangeWrapper &Item,
28 const Variable *Var) {
29 const InstDefList &Defs = Func->getVMetadata()->getDefinitions(Var);
30 for (size_t i = 0; i < Defs.size(); ++i) {
31 if (Item.range().overlaps(Defs[i]->getNumber()))
32 return true;
33 }
34 return false;
35}
36
37void dumpDisableOverlap(const Cfg *Func, const Variable *Var,
38 const char *Reason) {
39 if (Func->getContext()->isVerbose(IceV_LinearScan)) {
40 Ostream &Str = Func->getContext()->getStrDump();
41 Str << "Disabling Overlap due to " << Reason << " " << *Var
42 << " LIVE=" << Var->getLiveRange() << " Defs=";
43 const InstDefList &Defs = Func->getVMetadata()->getDefinitions(Var);
44 for (size_t i = 0; i < Defs.size(); ++i) {
45 if (i > 0)
46 Str << ",";
47 Str << Defs[i]->getNumber();
48 }
49 Str << "\n";
50 }
51}
52
53} // end of anonymous namespace
54
Jim Stichnothd97c7df2014-06-04 11:57:08 -070055// Implements the linear-scan algorithm. Based on "Linear Scan
56// Register Allocation in the Context of SSA Form and Register
57// Constraints" by Hanspeter Mössenböck and Michael Pfeiffer,
58// ftp://ftp.ssw.uni-linz.ac.at/pub/Papers/Moe02.PDF . This
59// implementation is modified to take affinity into account and allow
60// two interfering variables to share the same register in certain
61// cases.
62//
Jim Stichnoth800dab22014-09-20 12:25:02 -070063// Requires running Cfg::liveness(Liveness_Intervals) in
Jim Stichnothd97c7df2014-06-04 11:57:08 -070064// preparation. Results are assigned to Variable::RegNum for each
65// Variable.
66void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) {
67 assert(RegMaskFull.any()); // Sanity check
68 Unhandled.clear();
69 Handled.clear();
70 Inactive.clear();
71 Active.clear();
72 Ostream &Str = Func->getContext()->getStrDump();
Jim Stichnoth800dab22014-09-20 12:25:02 -070073 Func->resetCurrentNode();
Jim Stichnothad403532014-09-25 12:44:17 -070074 VariablesMetadata *VMetadata = Func->getVMetadata();
Jim Stichnothd97c7df2014-06-04 11:57:08 -070075
76 // Gather the live ranges of all variables and add them to the
77 // Unhandled set. TODO: Unhandled is a set<> which is based on a
78 // balanced binary tree, so inserting live ranges for N variables is
79 // O(N log N) complexity. N may be proportional to the number of
80 // instructions, thanks to temporary generation during lowering. As
81 // a result, it may be useful to design a better data structure for
82 // storing Func->getVariables().
83 const VarList &Vars = Func->getVariables();
84 for (VarList::const_iterator I = Vars.begin(), E = Vars.end(); I != E; ++I) {
85 Variable *Var = *I;
86 // Explicitly don't consider zero-weight variables, which are
87 // meant to be spill slots.
88 if (Var->getWeight() == RegWeight::Zero)
89 continue;
90 // Don't bother if the variable has a null live range, which means
91 // it was never referenced.
92 if (Var->getLiveRange().isEmpty())
93 continue;
94 Unhandled.insert(LiveRangeWrapper(Var));
95 if (Var->hasReg()) {
96 Var->setRegNumTmp(Var->getRegNum());
97 Var->setLiveRangeInfiniteWeight();
98 }
99 }
100
101 // RegUses[I] is the number of live ranges (variables) that register
102 // I is currently assigned to. It can be greater than 1 as a result
103 // of Variable::AllowRegisterOverlap.
104 std::vector<int> RegUses(RegMaskFull.size());
105 // Unhandled is already set to all ranges in increasing order of
106 // start points.
107 assert(Active.empty());
108 assert(Inactive.empty());
109 assert(Handled.empty());
110 UnorderedRanges::iterator Next;
111
112 while (!Unhandled.empty()) {
113 LiveRangeWrapper Cur = *Unhandled.begin();
114 Unhandled.erase(Unhandled.begin());
115 if (Func->getContext()->isVerbose(IceV_LinearScan)) {
116 Str << "\nConsidering ";
117 Cur.dump(Func);
118 Str << "\n";
119 }
120 const llvm::SmallBitVector RegMask =
121 RegMaskFull &
122 Func->getTarget()->getRegisterSetForType(Cur.Var->getType());
123
124 // Check for precolored ranges. If Cur is precolored, it
125 // definitely gets that register. Previously processed live
126 // ranges would have avoided that register due to it being
127 // precolored. Future processed live ranges won't evict that
128 // register because the live range has infinite weight.
129 if (Cur.Var->hasReg()) {
130 int32_t RegNum = Cur.Var->getRegNum();
131 // RegNumTmp should have already been set above.
132 assert(Cur.Var->getRegNumTmp() == RegNum);
133 if (Func->getContext()->isVerbose(IceV_LinearScan)) {
134 Str << "Precoloring ";
135 Cur.dump(Func);
136 Str << "\n";
137 }
138 Active.push_back(Cur);
139 assert(RegUses[RegNum] >= 0);
140 ++RegUses[RegNum];
141 continue;
142 }
143
144 // Check for active ranges that have expired or become inactive.
145 for (UnorderedRanges::iterator I = Active.begin(), E = Active.end(); I != E;
146 I = Next) {
147 Next = I;
148 ++Next;
149 LiveRangeWrapper Item = *I;
150 bool Moved = false;
151 if (Item.endsBefore(Cur)) {
152 // Move Item from Active to Handled list.
153 if (Func->getContext()->isVerbose(IceV_LinearScan)) {
154 Str << "Expiring ";
155 Item.dump(Func);
156 Str << "\n";
157 }
158 Active.erase(I);
159 Handled.push_back(Item);
160 Moved = true;
161 } else if (!Item.overlapsStart(Cur)) {
162 // Move Item from Active to Inactive list.
163 if (Func->getContext()->isVerbose(IceV_LinearScan)) {
164 Str << "Inactivating ";
165 Item.dump(Func);
166 Str << "\n";
167 }
168 Active.erase(I);
169 Inactive.push_back(Item);
170 Moved = true;
171 }
172 if (Moved) {
173 // Decrement Item from RegUses[].
174 assert(Item.Var->hasRegTmp());
175 int32_t RegNum = Item.Var->getRegNumTmp();
176 --RegUses[RegNum];
177 assert(RegUses[RegNum] >= 0);
178 }
179 }
180
181 // Check for inactive ranges that have expired or reactivated.
182 for (UnorderedRanges::iterator I = Inactive.begin(), E = Inactive.end();
183 I != E; I = Next) {
184 Next = I;
185 ++Next;
186 LiveRangeWrapper Item = *I;
187 if (Item.endsBefore(Cur)) {
188 // Move Item from Inactive to Handled list.
189 if (Func->getContext()->isVerbose(IceV_LinearScan)) {
190 Str << "Expiring ";
191 Item.dump(Func);
192 Str << "\n";
193 }
194 Inactive.erase(I);
195 Handled.push_back(Item);
196 } else if (Item.overlapsStart(Cur)) {
197 // Move Item from Inactive to Active list.
198 if (Func->getContext()->isVerbose(IceV_LinearScan)) {
199 Str << "Reactivating ";
200 Item.dump(Func);
201 Str << "\n";
202 }
203 Inactive.erase(I);
204 Active.push_back(Item);
205 // Increment Item in RegUses[].
206 assert(Item.Var->hasRegTmp());
207 int32_t RegNum = Item.Var->getRegNumTmp();
208 assert(RegUses[RegNum] >= 0);
209 ++RegUses[RegNum];
210 }
211 }
212
213 // Calculate available registers into Free[].
214 llvm::SmallBitVector Free = RegMask;
215 for (SizeT i = 0; i < RegMask.size(); ++i) {
216 if (RegUses[i] > 0)
217 Free[i] = false;
218 }
219
Jim Stichnothad403532014-09-25 12:44:17 -0700220 // Infer register preference and allowable overlap. Only form a
221 // preference when the current Variable has an unambiguous "first"
222 // definition. The preference is some source Variable of the
223 // defining instruction that either is assigned a register that is
224 // currently free, or that is assigned a register that is not free
225 // but overlap is allowed. Overlap is allowed when the Variable
226 // under consideration is single-definition, and its definition is
227 // a simple assignment - i.e., the register gets copied/aliased
228 // but is never modified. Furthermore, overlap is only allowed
229 // when preferred Variable definition instructions do not appear
230 // within the current Variable's live range.
231 Variable *Prefer = NULL;
232 int32_t PreferReg = Variable::NoRegister;
233 bool AllowOverlap = false;
234 if (const Inst *DefInst = VMetadata->getFirstDefinition(Cur.Var)) {
235 assert(DefInst->getDest() == Cur.Var);
236 bool IsAssign = DefInst->isSimpleAssign();
237 bool IsSingleDef = !VMetadata->isMultiDef(Cur.Var);
238 for (SizeT i = 0; i < DefInst->getSrcSize(); ++i) {
239 // TODO(stichnot): Iterate through the actual Variables of the
240 // instruction, not just the source operands. This could
241 // capture Load instructions, including address mode
242 // optimization, for Prefer (but not for AllowOverlap).
243 if (Variable *SrcVar = llvm::dyn_cast<Variable>(DefInst->getSrc(i))) {
244 int32_t SrcReg = SrcVar->getRegNumTmp();
245 // Only consider source variables that have (so far) been
246 // assigned a register. That register must be one in the
247 // RegMask set, e.g. don't try to prefer the stack pointer
248 // as a result of the stacksave intrinsic.
249 if (SrcVar->hasRegTmp() && RegMask[SrcReg]) {
250 if (!Free[SrcReg]) {
251 // Don't bother trying to enable AllowOverlap if the
252 // register is already free.
253 AllowOverlap =
254 IsSingleDef && IsAssign && !overlapsDefs(Func, Cur, SrcVar);
255 }
256 if (AllowOverlap || Free[SrcReg]) {
257 Prefer = SrcVar;
258 PreferReg = SrcReg;
259 }
260 }
261 }
262 }
263 }
264 if (Func->getContext()->isVerbose(IceV_LinearScan)) {
265 if (Prefer) {
266 Str << "Initial Prefer=" << *Prefer << " R=" << PreferReg
267 << " LIVE=" << Prefer->getLiveRange() << " Overlap=" << AllowOverlap
268 << "\n";
269 }
270 }
271
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700272 // Remove registers from the Free[] list where an Inactive range
273 // overlaps with the current range.
274 for (UnorderedRanges::const_iterator I = Inactive.begin(),
275 E = Inactive.end();
276 I != E; ++I) {
277 LiveRangeWrapper Item = *I;
278 if (Item.overlaps(Cur)) {
279 int32_t RegNum = Item.Var->getRegNumTmp();
280 // Don't assert(Free[RegNum]) because in theory (though
281 // probably never in practice) there could be two inactive
282 // variables that were allowed marked with
283 // AllowRegisterOverlap.
284 Free[RegNum] = false;
Jim Stichnothad403532014-09-25 12:44:17 -0700285 // Disable AllowOverlap if an Inactive variable, which is not
286 // Prefer, shares Prefer's register, and has a definition
287 // within Cur's live range.
288 if (AllowOverlap && Item.Var != Prefer && RegNum == PreferReg &&
289 overlapsDefs(Func, Cur, Item.Var)) {
290 AllowOverlap = false;
291 dumpDisableOverlap(Func, Item.Var, "Inactive");
292 }
293 }
294 }
295
296 // Disable AllowOverlap if an Active variable, which is not
297 // Prefer, shares Prefer's register, and has a definition within
298 // Cur's live range.
299 for (UnorderedRanges::iterator I = Active.begin(), E = Active.end();
300 AllowOverlap && I != E; ++I) {
301 LiveRangeWrapper Item = *I;
302 int32_t RegNum = Item.Var->getRegNumTmp();
303 if (Item.Var != Prefer && RegNum == PreferReg &&
304 overlapsDefs(Func, Cur, Item.Var)) {
305 AllowOverlap = false;
306 dumpDisableOverlap(Func, Item.Var, "Active");
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700307 }
308 }
309
310 // Remove registers from the Free[] list where an Unhandled range
311 // overlaps with the current range and is precolored.
312 // Cur.endsBefore(*I) is an early exit check that turns a
313 // guaranteed O(N^2) algorithm into expected linear complexity.
Jim Stichnothca662e92014-07-10 15:32:36 -0700314 llvm::SmallBitVector PrecoloredUnhandled(RegMask.size());
Jim Stichnothad403532014-09-25 12:44:17 -0700315 // Note: PrecoloredUnhandled is only used for dumping.
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700316 for (OrderedRanges::const_iterator I = Unhandled.begin(),
317 E = Unhandled.end();
318 I != E && !Cur.endsBefore(*I); ++I) {
319 LiveRangeWrapper Item = *I;
320 if (Item.Var->hasReg() && Item.overlaps(Cur)) {
Jim Stichnothad403532014-09-25 12:44:17 -0700321 int32_t ItemReg = Item.Var->getRegNum(); // Note: not getRegNumTmp()
322 Free[ItemReg] = false;
323 PrecoloredUnhandled[ItemReg] = true;
324 // Disable AllowOverlap if the preferred register is one of
325 // these precolored unhandled overlapping ranges.
326 if (AllowOverlap && ItemReg == PreferReg) {
327 AllowOverlap = false;
328 dumpDisableOverlap(Func, Item.Var, "PrecoloredUnhandled");
329 }
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700330 }
331 }
332
333 // Print info about physical register availability.
334 if (Func->getContext()->isVerbose(IceV_LinearScan)) {
335 for (SizeT i = 0; i < RegMask.size(); ++i) {
336 if (RegMask[i]) {
337 Str << Func->getTarget()->getRegName(i, IceType_i32)
Jim Stichnothca662e92014-07-10 15:32:36 -0700338 << "(U=" << RegUses[i] << ",F=" << Free[i]
339 << ",P=" << PrecoloredUnhandled[i] << ") ";
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700340 }
341 }
342 Str << "\n";
343 }
344
Jim Stichnothad403532014-09-25 12:44:17 -0700345 if (Prefer && (AllowOverlap || Free[PreferReg])) {
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700346 // First choice: a preferred register that is either free or is
347 // allowed to overlap with its linked variable.
348 Cur.Var->setRegNumTmp(PreferReg);
349 if (Func->getContext()->isVerbose(IceV_LinearScan)) {
350 Str << "Preferring ";
351 Cur.dump(Func);
352 Str << "\n";
353 }
354 assert(RegUses[PreferReg] >= 0);
355 ++RegUses[PreferReg];
356 Active.push_back(Cur);
357 } else if (Free.any()) {
358 // Second choice: any free register. TODO: After explicit
359 // affinity is considered, is there a strategy better than just
360 // picking the lowest-numbered available register?
361 int32_t RegNum = Free.find_first();
362 Cur.Var->setRegNumTmp(RegNum);
363 if (Func->getContext()->isVerbose(IceV_LinearScan)) {
364 Str << "Allocating ";
365 Cur.dump(Func);
366 Str << "\n";
367 }
368 assert(RegUses[RegNum] >= 0);
369 ++RegUses[RegNum];
370 Active.push_back(Cur);
371 } else {
372 // Fallback: there are no free registers, so we look for the
373 // lowest-weight register and see if Cur has higher weight.
374 std::vector<RegWeight> Weights(RegMask.size());
375 // Check Active ranges.
376 for (UnorderedRanges::const_iterator I = Active.begin(), E = Active.end();
377 I != E; ++I) {
378 LiveRangeWrapper Item = *I;
379 assert(Item.overlaps(Cur));
380 int32_t RegNum = Item.Var->getRegNumTmp();
381 assert(Item.Var->hasRegTmp());
382 Weights[RegNum].addWeight(Item.range().getWeight());
383 }
384 // Same as above, but check Inactive ranges instead of Active.
385 for (UnorderedRanges::const_iterator I = Inactive.begin(),
386 E = Inactive.end();
387 I != E; ++I) {
388 LiveRangeWrapper Item = *I;
389 int32_t RegNum = Item.Var->getRegNumTmp();
390 assert(Item.Var->hasRegTmp());
391 if (Item.overlaps(Cur))
392 Weights[RegNum].addWeight(Item.range().getWeight());
393 }
394 // Check Unhandled ranges that overlap Cur and are precolored.
395 // Cur.endsBefore(*I) is an early exit check that turns a
396 // guaranteed O(N^2) algorithm into expected linear complexity.
397 for (OrderedRanges::const_iterator I = Unhandled.begin(),
398 E = Unhandled.end();
399 I != E && !Cur.endsBefore(*I); ++I) {
400 LiveRangeWrapper Item = *I;
401 int32_t RegNum = Item.Var->getRegNumTmp();
402 if (RegNum < 0)
403 continue;
404 if (Item.overlaps(Cur))
405 Weights[RegNum].setWeight(RegWeight::Inf);
406 }
407
408 // All the weights are now calculated. Find the register with
409 // smallest weight.
410 int32_t MinWeightIndex = RegMask.find_first();
411 // MinWeightIndex must be valid because of the initial
412 // RegMask.any() test.
413 assert(MinWeightIndex >= 0);
414 for (SizeT i = MinWeightIndex + 1; i < Weights.size(); ++i) {
415 if (RegMask[i] && Weights[i] < Weights[MinWeightIndex])
416 MinWeightIndex = i;
417 }
418
419 if (Cur.range().getWeight() <= Weights[MinWeightIndex]) {
420 // Cur doesn't have priority over any other live ranges, so
421 // don't allocate any register to it, and move it to the
422 // Handled state.
423 Handled.push_back(Cur);
424 if (Cur.range().getWeight().isInf()) {
425 Func->setError("Unable to find a physical register for an "
426 "infinite-weight live range");
427 }
428 } else {
429 // Evict all live ranges in Active that register number
430 // MinWeightIndex is assigned to.
431 for (UnorderedRanges::iterator I = Active.begin(), E = Active.end();
432 I != E; I = Next) {
433 Next = I;
434 ++Next;
435 LiveRangeWrapper Item = *I;
436 if (Item.Var->getRegNumTmp() == MinWeightIndex) {
437 if (Func->getContext()->isVerbose(IceV_LinearScan)) {
438 Str << "Evicting ";
439 Item.dump(Func);
440 Str << "\n";
441 }
442 --RegUses[MinWeightIndex];
443 assert(RegUses[MinWeightIndex] >= 0);
444 Item.Var->setRegNumTmp(Variable::NoRegister);
445 Active.erase(I);
446 Handled.push_back(Item);
447 }
448 }
449 // Do the same for Inactive.
450 for (UnorderedRanges::iterator I = Inactive.begin(), E = Inactive.end();
451 I != E; I = Next) {
452 Next = I;
453 ++Next;
454 LiveRangeWrapper Item = *I;
Jim Stichnoth68e28192014-07-24 08:48:15 -0700455 // Note: The Item.overlaps(Cur) clause is not part of the
456 // description of AssignMemLoc() in the original paper. But
457 // there doesn't seem to be any need to evict an inactive
458 // live range that doesn't overlap with the live range
459 // currently being considered. It's especially bad if we
460 // would end up evicting an infinite-weight but
461 // currently-inactive live range. The most common situation
462 // for this would be a scratch register kill set for call
463 // instructions.
464 if (Item.Var->getRegNumTmp() == MinWeightIndex &&
465 Item.overlaps(Cur)) {
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700466 if (Func->getContext()->isVerbose(IceV_LinearScan)) {
467 Str << "Evicting ";
468 Item.dump(Func);
469 Str << "\n";
470 }
471 Item.Var->setRegNumTmp(Variable::NoRegister);
472 Inactive.erase(I);
473 Handled.push_back(Item);
474 }
475 }
476 // Assign the register to Cur.
477 Cur.Var->setRegNumTmp(MinWeightIndex);
478 assert(RegUses[MinWeightIndex] >= 0);
479 ++RegUses[MinWeightIndex];
480 Active.push_back(Cur);
481 if (Func->getContext()->isVerbose(IceV_LinearScan)) {
482 Str << "Allocating ";
483 Cur.dump(Func);
484 Str << "\n";
485 }
486 }
487 }
488 dump(Func);
489 }
490 // Move anything Active or Inactive to Handled for easier handling.
491 for (UnorderedRanges::iterator I = Active.begin(), E = Active.end(); I != E;
492 I = Next) {
493 Next = I;
494 ++Next;
495 Handled.push_back(*I);
496 Active.erase(I);
497 }
498 for (UnorderedRanges::iterator I = Inactive.begin(), E = Inactive.end();
499 I != E; I = Next) {
500 Next = I;
501 ++Next;
502 Handled.push_back(*I);
503 Inactive.erase(I);
504 }
505 dump(Func);
506
507 // Finish up by assigning RegNumTmp->RegNum for each Variable.
508 for (UnorderedRanges::const_iterator I = Handled.begin(), E = Handled.end();
509 I != E; ++I) {
510 LiveRangeWrapper Item = *I;
511 int32_t RegNum = Item.Var->getRegNumTmp();
512 if (Func->getContext()->isVerbose(IceV_LinearScan)) {
513 if (!Item.Var->hasRegTmp()) {
514 Str << "Not assigning ";
515 Item.Var->dump(Func);
516 Str << "\n";
517 } else {
518 Str << (RegNum == Item.Var->getRegNum() ? "Reassigning " : "Assigning ")
519 << Func->getTarget()->getRegName(RegNum, IceType_i32) << "(r"
520 << RegNum << ") to ";
521 Item.Var->dump(Func);
522 Str << "\n";
523 }
524 }
525 Item.Var->setRegNum(Item.Var->getRegNumTmp());
526 }
527
528 // TODO: Consider running register allocation one more time, with
529 // infinite registers, for two reasons. First, evicted live ranges
530 // get a second chance for a register. Second, it allows coalescing
531 // of stack slots. If there is no time budget for the second
532 // register allocation run, each unallocated variable just gets its
533 // own slot.
534 //
535 // Another idea for coalescing stack slots is to initialize the
536 // Unhandled list with just the unallocated variables, saving time
537 // but not offering second-chance opportunities.
538}
539
540// ======================== Dump routines ======================== //
541
542void LiveRangeWrapper::dump(const Cfg *Func) const {
543 Ostream &Str = Func->getContext()->getStrDump();
544 const static size_t BufLen = 30;
545 char buf[BufLen];
546 snprintf(buf, BufLen, "%2d", Var->getRegNumTmp());
547 Str << "R=" << buf << " V=";
548 Var->dump(Func);
549 Str << " Range=" << range();
550}
551
552void LinearScan::dump(Cfg *Func) const {
553 Ostream &Str = Func->getContext()->getStrDump();
554 if (!Func->getContext()->isVerbose(IceV_LinearScan))
555 return;
Jim Stichnoth800dab22014-09-20 12:25:02 -0700556 Func->resetCurrentNode();
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700557 Str << "**** Current regalloc state:\n";
558 Str << "++++++ Handled:\n";
559 for (UnorderedRanges::const_iterator I = Handled.begin(), E = Handled.end();
560 I != E; ++I) {
561 I->dump(Func);
562 Str << "\n";
563 }
564 Str << "++++++ Unhandled:\n";
565 for (OrderedRanges::const_iterator I = Unhandled.begin(), E = Unhandled.end();
566 I != E; ++I) {
567 I->dump(Func);
568 Str << "\n";
569 }
570 Str << "++++++ Active:\n";
571 for (UnorderedRanges::const_iterator I = Active.begin(), E = Active.end();
572 I != E; ++I) {
573 I->dump(Func);
574 Str << "\n";
575 }
576 Str << "++++++ Inactive:\n";
577 for (UnorderedRanges::const_iterator I = Inactive.begin(), E = Inactive.end();
578 I != E; ++I) {
579 I->dump(Func);
580 Str << "\n";
581 }
582}
583
584} // end of namespace Ice