| 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 |