OLD | NEW |
1 //===- subzero/src/IceRegAlloc.cpp - Linear-scan implementation -----------===// | 1 //===- subzero/src/IceRegAlloc.cpp - Linear-scan implementation -----------===// |
2 // | 2 // |
3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
4 // | 4 // |
5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
7 // | 7 // |
8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
9 // | 9 // |
10 // This file implements the LinearScan class, which performs the | 10 // This file implements the LinearScan class, which performs the |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
78 } // end of anonymous namespace | 78 } // end of anonymous namespace |
79 | 79 |
80 // Prepare for full register allocation of all variables. We depend | 80 // Prepare for full register allocation of all variables. We depend |
81 // on liveness analysis to have calculated live ranges. | 81 // on liveness analysis to have calculated live ranges. |
82 void LinearScan::initForGlobal() { | 82 void LinearScan::initForGlobal() { |
83 TimerMarker T(TimerStack::TT_initUnhandled, Func); | 83 TimerMarker T(TimerStack::TT_initUnhandled, Func); |
84 FindPreference = true; | 84 FindPreference = true; |
85 FindOverlap = true; | 85 FindOverlap = true; |
86 const VarList &Vars = Func->getVariables(); | 86 const VarList &Vars = Func->getVariables(); |
87 Unhandled.reserve(Vars.size()); | 87 Unhandled.reserve(Vars.size()); |
| 88 UnhandledPrecolored.reserve(Vars.size()); |
88 // Gather the live ranges of all variables and add them to the | 89 // Gather the live ranges of all variables and add them to the |
89 // Unhandled set. | 90 // Unhandled set. |
90 for (Variable *Var : Vars) { | 91 for (Variable *Var : Vars) { |
91 // Explicitly don't consider zero-weight variables, which are | 92 // Explicitly don't consider zero-weight variables, which are |
92 // meant to be spill slots. | 93 // meant to be spill slots. |
93 if (Var->getWeight() == RegWeight::Zero) | 94 if (Var->getWeight() == RegWeight::Zero) |
94 continue; | 95 continue; |
95 // Don't bother if the variable has a null live range, which means | 96 // Don't bother if the variable has a null live range, which means |
96 // it was never referenced. | 97 // it was never referenced. |
97 if (Var->getLiveRange().isEmpty()) | 98 if (Var->getLiveRange().isEmpty()) |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
177 for (SizeT J = 0; J < NumVars; ++J) { | 178 for (SizeT J = 0; J < NumVars; ++J) { |
178 const Variable *Var = Src->getVar(J); | 179 const Variable *Var = Src->getVar(J); |
179 if (Var->hasReg() || Var->getWeight() == RegWeight::Inf) | 180 if (Var->hasReg() || Var->getWeight() == RegWeight::Inf) |
180 LREnd[Var->getIndex()] = Inst->getNumber(); | 181 LREnd[Var->getIndex()] = Inst->getNumber(); |
181 } | 182 } |
182 } | 183 } |
183 } | 184 } |
184 } | 185 } |
185 | 186 |
186 Unhandled.reserve(NumVars); | 187 Unhandled.reserve(NumVars); |
| 188 UnhandledPrecolored.reserve(NumVars); |
187 for (SizeT i = 0; i < Vars.size(); ++i) { | 189 for (SizeT i = 0; i < Vars.size(); ++i) { |
188 Variable *Var = Vars[i]; | 190 Variable *Var = Vars[i]; |
189 if (LRBegin[i] != Inst::NumberSentinel) { | 191 if (LRBegin[i] != Inst::NumberSentinel) { |
190 assert(LREnd[i] != Inst::NumberSentinel); | 192 assert(LREnd[i] != Inst::NumberSentinel); |
191 Unhandled.push_back(Var); | 193 Unhandled.push_back(Var); |
192 Var->resetLiveRange(); | 194 Var->resetLiveRange(); |
193 const uint32_t WeightDelta = 1; | 195 const uint32_t WeightDelta = 1; |
194 Var->addLiveRange(LRBegin[i], LREnd[i], WeightDelta); | 196 Var->addLiveRange(LRBegin[i], LREnd[i], WeightDelta); |
195 Var->untrimLiveRange(); | 197 Var->untrimLiveRange(); |
196 if (Var->hasReg()) { | 198 if (Var->hasReg()) { |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
232 InstNumberT Rstart = R->getLiveRange().getStart(); | 234 InstNumberT Rstart = R->getLiveRange().getStart(); |
233 if (Lstart == Rstart) | 235 if (Lstart == Rstart) |
234 return L->getIndex() < R->getIndex(); | 236 return L->getIndex() < R->getIndex(); |
235 return Lstart < Rstart; | 237 return Lstart < Rstart; |
236 } | 238 } |
237 }; | 239 }; |
238 // Do a reverse sort so that erasing elements (from the end) is fast. | 240 // Do a reverse sort so that erasing elements (from the end) is fast. |
239 std::sort(Unhandled.rbegin(), Unhandled.rend(), CompareRanges()); | 241 std::sort(Unhandled.rbegin(), Unhandled.rend(), CompareRanges()); |
240 std::sort(UnhandledPrecolored.rbegin(), UnhandledPrecolored.rend(), | 242 std::sort(UnhandledPrecolored.rbegin(), UnhandledPrecolored.rend(), |
241 CompareRanges()); | 243 CompareRanges()); |
| 244 |
| 245 Handled.reserve(Unhandled.size()); |
| 246 Inactive.reserve(Unhandled.size()); |
| 247 Active.reserve(Unhandled.size()); |
242 } | 248 } |
243 | 249 |
244 // Implements the linear-scan algorithm. Based on "Linear Scan | 250 // Implements the linear-scan algorithm. Based on "Linear Scan |
245 // Register Allocation in the Context of SSA Form and Register | 251 // Register Allocation in the Context of SSA Form and Register |
246 // Constraints" by Hanspeter Mössenböck and Michael Pfeiffer, | 252 // Constraints" by Hanspeter Mössenböck and Michael Pfeiffer, |
247 // ftp://ftp.ssw.uni-linz.ac.at/pub/Papers/Moe02.PDF . This | 253 // ftp://ftp.ssw.uni-linz.ac.at/pub/Papers/Moe02.PDF . This |
248 // implementation is modified to take affinity into account and allow | 254 // implementation is modified to take affinity into account and allow |
249 // two interfering variables to share the same register in certain | 255 // two interfering variables to share the same register in certain |
250 // cases. | 256 // cases. |
251 // | 257 // |
(...skipping 17 matching lines...) Expand all Loading... |
269 | 275 |
270 // RegUses[I] is the number of live ranges (variables) that register | 276 // RegUses[I] is the number of live ranges (variables) that register |
271 // I is currently assigned to. It can be greater than 1 as a result | 277 // I is currently assigned to. It can be greater than 1 as a result |
272 // of AllowOverlap inference below. | 278 // of AllowOverlap inference below. |
273 std::vector<int> RegUses(RegMaskFull.size()); | 279 std::vector<int> RegUses(RegMaskFull.size()); |
274 // Unhandled is already set to all ranges in increasing order of | 280 // Unhandled is already set to all ranges in increasing order of |
275 // start points. | 281 // start points. |
276 assert(Active.empty()); | 282 assert(Active.empty()); |
277 assert(Inactive.empty()); | 283 assert(Inactive.empty()); |
278 assert(Handled.empty()); | 284 assert(Handled.empty()); |
279 UnorderedRanges::iterator Next; | |
280 const TargetLowering::RegSetMask RegsInclude = | 285 const TargetLowering::RegSetMask RegsInclude = |
281 TargetLowering::RegSet_CallerSave; | 286 TargetLowering::RegSet_CallerSave; |
282 const TargetLowering::RegSetMask RegsExclude = TargetLowering::RegSet_None; | 287 const TargetLowering::RegSetMask RegsExclude = TargetLowering::RegSet_None; |
283 const llvm::SmallBitVector KillsMask = | 288 const llvm::SmallBitVector KillsMask = |
284 Func->getTarget()->getRegisterSet(RegsInclude, RegsExclude); | 289 Func->getTarget()->getRegisterSet(RegsInclude, RegsExclude); |
285 | 290 |
286 while (!Unhandled.empty()) { | 291 while (!Unhandled.empty()) { |
287 Variable *Cur = Unhandled.back(); | 292 Variable *Cur = Unhandled.back(); |
288 Unhandled.pop_back(); | 293 Unhandled.pop_back(); |
289 if (Verbose) { | 294 if (Verbose) { |
(...skipping 22 matching lines...) Expand all Loading... |
312 Active.push_back(Cur); | 317 Active.push_back(Cur); |
313 assert(RegUses[RegNum] >= 0); | 318 assert(RegUses[RegNum] >= 0); |
314 ++RegUses[RegNum]; | 319 ++RegUses[RegNum]; |
315 assert(!UnhandledPrecolored.empty()); | 320 assert(!UnhandledPrecolored.empty()); |
316 assert(UnhandledPrecolored.back() == Cur); | 321 assert(UnhandledPrecolored.back() == Cur); |
317 UnhandledPrecolored.pop_back(); | 322 UnhandledPrecolored.pop_back(); |
318 continue; | 323 continue; |
319 } | 324 } |
320 | 325 |
321 // Check for active ranges that have expired or become inactive. | 326 // Check for active ranges that have expired or become inactive. |
322 for (auto I = Active.begin(), E = Active.end(); I != E; I = Next) { | 327 for (SizeT I = Active.size(); I > 0; --I) { |
323 Next = I; | 328 const SizeT Index = I - 1; |
324 ++Next; | 329 Variable *Item = Active[Index]; |
325 Variable *Item = *I; | |
326 Item->trimLiveRange(Cur->getLiveRange().getStart()); | 330 Item->trimLiveRange(Cur->getLiveRange().getStart()); |
327 bool Moved = false; | 331 bool Moved = false; |
328 if (Item->rangeEndsBefore(Cur)) { | 332 if (Item->rangeEndsBefore(Cur)) { |
329 // Move Item from Active to Handled list. | 333 // Move Item from Active to Handled list. |
330 if (Verbose) { | 334 if (Verbose) { |
331 Str << "Expiring "; | 335 Str << "Expiring "; |
332 dumpLiveRange(Item, Func); | 336 dumpLiveRange(Item, Func); |
333 Str << "\n"; | 337 Str << "\n"; |
334 } | 338 } |
335 Handled.splice(Handled.end(), Active, I); | 339 moveItem(Active, Index, Handled); |
336 Moved = true; | 340 Moved = true; |
337 } else if (!Item->rangeOverlapsStart(Cur)) { | 341 } else if (!Item->rangeOverlapsStart(Cur)) { |
338 // Move Item from Active to Inactive list. | 342 // Move Item from Active to Inactive list. |
339 if (Verbose) { | 343 if (Verbose) { |
340 Str << "Inactivating "; | 344 Str << "Inactivating "; |
341 dumpLiveRange(Item, Func); | 345 dumpLiveRange(Item, Func); |
342 Str << "\n"; | 346 Str << "\n"; |
343 } | 347 } |
344 Inactive.splice(Inactive.end(), Active, I); | 348 moveItem(Active, Index, Inactive); |
345 Moved = true; | 349 Moved = true; |
346 } | 350 } |
347 if (Moved) { | 351 if (Moved) { |
348 // Decrement Item from RegUses[]. | 352 // Decrement Item from RegUses[]. |
349 assert(Item->hasRegTmp()); | 353 assert(Item->hasRegTmp()); |
350 int32_t RegNum = Item->getRegNumTmp(); | 354 int32_t RegNum = Item->getRegNumTmp(); |
351 --RegUses[RegNum]; | 355 --RegUses[RegNum]; |
352 assert(RegUses[RegNum] >= 0); | 356 assert(RegUses[RegNum] >= 0); |
353 } | 357 } |
354 } | 358 } |
355 | 359 |
356 // Check for inactive ranges that have expired or reactivated. | 360 // Check for inactive ranges that have expired or reactivated. |
357 for (auto I = Inactive.begin(), E = Inactive.end(); I != E; I = Next) { | 361 for (SizeT I = Inactive.size(); I > 0; --I) { |
358 Next = I; | 362 const SizeT Index = I - 1; |
359 ++Next; | 363 Variable *Item = Inactive[Index]; |
360 Variable *Item = *I; | |
361 Item->trimLiveRange(Cur->getLiveRange().getStart()); | 364 Item->trimLiveRange(Cur->getLiveRange().getStart()); |
362 if (Item->rangeEndsBefore(Cur)) { | 365 if (Item->rangeEndsBefore(Cur)) { |
363 // Move Item from Inactive to Handled list. | 366 // Move Item from Inactive to Handled list. |
364 if (Verbose) { | 367 if (Verbose) { |
365 Str << "Expiring "; | 368 Str << "Expiring "; |
366 dumpLiveRange(Item, Func); | 369 dumpLiveRange(Item, Func); |
367 Str << "\n"; | 370 Str << "\n"; |
368 } | 371 } |
369 Handled.splice(Handled.end(), Inactive, I); | 372 moveItem(Inactive, Index, Handled); |
370 } else if (Item->rangeOverlapsStart(Cur)) { | 373 } else if (Item->rangeOverlapsStart(Cur)) { |
371 // Move Item from Inactive to Active list. | 374 // Move Item from Inactive to Active list. |
372 if (Verbose) { | 375 if (Verbose) { |
373 Str << "Reactivating "; | 376 Str << "Reactivating "; |
374 dumpLiveRange(Item, Func); | 377 dumpLiveRange(Item, Func); |
375 Str << "\n"; | 378 Str << "\n"; |
376 } | 379 } |
377 Active.splice(Active.end(), Inactive, I); | 380 moveItem(Inactive, Index, Active); |
378 // Increment Item in RegUses[]. | 381 // Increment Item in RegUses[]. |
379 assert(Item->hasRegTmp()); | 382 assert(Item->hasRegTmp()); |
380 int32_t RegNum = Item->getRegNumTmp(); | 383 int32_t RegNum = Item->getRegNumTmp(); |
381 assert(RegUses[RegNum] >= 0); | 384 assert(RegUses[RegNum] >= 0); |
382 ++RegUses[RegNum]; | 385 ++RegUses[RegNum]; |
383 } | 386 } |
384 } | 387 } |
385 | 388 |
386 // Calculate available registers into Free[]. | 389 // Calculate available registers into Free[]. |
387 llvm::SmallBitVector Free = RegMask; | 390 llvm::SmallBitVector Free = RegMask; |
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
591 // don't allocate any register to it, and move it to the | 594 // don't allocate any register to it, and move it to the |
592 // Handled state. | 595 // Handled state. |
593 Handled.push_back(Cur); | 596 Handled.push_back(Cur); |
594 if (Cur->getLiveRange().getWeight().isInf()) { | 597 if (Cur->getLiveRange().getWeight().isInf()) { |
595 Func->setError("Unable to find a physical register for an " | 598 Func->setError("Unable to find a physical register for an " |
596 "infinite-weight live range"); | 599 "infinite-weight live range"); |
597 } | 600 } |
598 } else { | 601 } else { |
599 // Evict all live ranges in Active that register number | 602 // Evict all live ranges in Active that register number |
600 // MinWeightIndex is assigned to. | 603 // MinWeightIndex is assigned to. |
601 for (auto I = Active.begin(), E = Active.end(); I != E; I = Next) { | 604 for (SizeT I = Active.size(); I > 0; --I) { |
602 Next = I; | 605 const SizeT Index = I - 1; |
603 ++Next; | 606 Variable *Item = Active[Index]; |
604 Variable *Item = *I; | |
605 if (Item->getRegNumTmp() == MinWeightIndex) { | 607 if (Item->getRegNumTmp() == MinWeightIndex) { |
606 if (Verbose) { | 608 if (Verbose) { |
607 Str << "Evicting "; | 609 Str << "Evicting "; |
608 dumpLiveRange(Item, Func); | 610 dumpLiveRange(Item, Func); |
609 Str << "\n"; | 611 Str << "\n"; |
610 } | 612 } |
611 --RegUses[MinWeightIndex]; | 613 --RegUses[MinWeightIndex]; |
612 assert(RegUses[MinWeightIndex] >= 0); | 614 assert(RegUses[MinWeightIndex] >= 0); |
613 Item->setRegNumTmp(Variable::NoRegister); | 615 Item->setRegNumTmp(Variable::NoRegister); |
614 Handled.splice(Handled.end(), Active, I); | 616 moveItem(Active, Index, Handled); |
615 } | 617 } |
616 } | 618 } |
617 // Do the same for Inactive. | 619 // Do the same for Inactive. |
618 for (auto I = Inactive.begin(), E = Inactive.end(); I != E; I = Next) { | 620 for (SizeT I = Inactive.size(); I > 0; --I) { |
619 Next = I; | 621 const SizeT Index = I - 1; |
620 ++Next; | 622 Variable *Item = Inactive[Index]; |
621 Variable *Item = *I; | |
622 // Note: The Item->rangeOverlaps(Cur) clause is not part of the | 623 // Note: The Item->rangeOverlaps(Cur) clause is not part of the |
623 // description of AssignMemLoc() in the original paper. But | 624 // description of AssignMemLoc() in the original paper. But |
624 // there doesn't seem to be any need to evict an inactive | 625 // there doesn't seem to be any need to evict an inactive |
625 // live range that doesn't overlap with the live range | 626 // live range that doesn't overlap with the live range |
626 // currently being considered. It's especially bad if we | 627 // currently being considered. It's especially bad if we |
627 // would end up evicting an infinite-weight but | 628 // would end up evicting an infinite-weight but |
628 // currently-inactive live range. The most common situation | 629 // currently-inactive live range. The most common situation |
629 // for this would be a scratch register kill set for call | 630 // for this would be a scratch register kill set for call |
630 // instructions. | 631 // instructions. |
631 if (Item->getRegNumTmp() == MinWeightIndex && | 632 if (Item->getRegNumTmp() == MinWeightIndex && |
632 Item->rangeOverlaps(Cur)) { | 633 Item->rangeOverlaps(Cur)) { |
633 if (Verbose) { | 634 if (Verbose) { |
634 Str << "Evicting "; | 635 Str << "Evicting "; |
635 dumpLiveRange(Item, Func); | 636 dumpLiveRange(Item, Func); |
636 Str << "\n"; | 637 Str << "\n"; |
637 } | 638 } |
638 Item->setRegNumTmp(Variable::NoRegister); | 639 Item->setRegNumTmp(Variable::NoRegister); |
639 Handled.splice(Handled.end(), Inactive, I); | 640 moveItem(Inactive, Index, Handled); |
640 } | 641 } |
641 } | 642 } |
642 // Assign the register to Cur. | 643 // Assign the register to Cur. |
643 Cur->setRegNumTmp(MinWeightIndex); | 644 Cur->setRegNumTmp(MinWeightIndex); |
644 assert(RegUses[MinWeightIndex] >= 0); | 645 assert(RegUses[MinWeightIndex] >= 0); |
645 ++RegUses[MinWeightIndex]; | 646 ++RegUses[MinWeightIndex]; |
646 Active.push_back(Cur); | 647 Active.push_back(Cur); |
647 if (Verbose) { | 648 if (Verbose) { |
648 Str << "Allocating "; | 649 Str << "Allocating "; |
649 dumpLiveRange(Cur, Func); | 650 dumpLiveRange(Cur, Func); |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
719 Str << "\n"; | 720 Str << "\n"; |
720 } | 721 } |
721 Str << "++++++ Inactive:\n"; | 722 Str << "++++++ Inactive:\n"; |
722 for (const Variable *Item : Inactive) { | 723 for (const Variable *Item : Inactive) { |
723 dumpLiveRange(Item, Func); | 724 dumpLiveRange(Item, Func); |
724 Str << "\n"; | 725 Str << "\n"; |
725 } | 726 } |
726 } | 727 } |
727 | 728 |
728 } // end of namespace Ice | 729 } // end of namespace Ice |
OLD | NEW |