| 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 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 66 const static size_t BufLen = 30; | 66 const static size_t BufLen = 30; |
| 67 char buf[BufLen]; | 67 char buf[BufLen]; |
| 68 snprintf(buf, BufLen, "%2d", Var->getRegNumTmp()); | 68 snprintf(buf, BufLen, "%2d", Var->getRegNumTmp()); |
| 69 Str << "R=" << buf << " V="; | 69 Str << "R=" << buf << " V="; |
| 70 Var->dump(Func); | 70 Var->dump(Func); |
| 71 Str << " Range=" << Var->getLiveRange(); | 71 Str << " Range=" << Var->getLiveRange(); |
| 72 } | 72 } |
| 73 | 73 |
| 74 } // end of anonymous namespace | 74 } // end of anonymous namespace |
| 75 | 75 |
| 76 void LinearScan::initForGlobalAlloc() { | 76 // Prepare for full register allocation of all variables. We depend |
| 77 // on liveness analysis to have calculated live ranges. |
| 78 void LinearScan::initForGlobal() { |
| 77 TimerMarker T(TimerStack::TT_initUnhandled, Func); | 79 TimerMarker T(TimerStack::TT_initUnhandled, Func); |
| 80 FindPreference = true; |
| 81 FindOverlap = true; |
| 78 Unhandled.clear(); | 82 Unhandled.clear(); |
| 79 UnhandledPrecolored.clear(); | 83 UnhandledPrecolored.clear(); |
| 80 Handled.clear(); | 84 Handled.clear(); |
| 81 Inactive.clear(); | 85 Inactive.clear(); |
| 82 Active.clear(); | 86 Active.clear(); |
| 83 // Gather the live ranges of all variables and add them to the | 87 // Gather the live ranges of all variables and add them to the |
| 84 // Unhandled set. | 88 // Unhandled set. |
| 85 const VarList &Vars = Func->getVariables(); | 89 const VarList &Vars = Func->getVariables(); |
| 86 Unhandled.reserve(Vars.size()); | 90 Unhandled.reserve(Vars.size()); |
| 87 for (Variable *Var : Vars) { | 91 for (Variable *Var : Vars) { |
| 88 // Explicitly don't consider zero-weight variables, which are | 92 // Explicitly don't consider zero-weight variables, which are |
| 89 // meant to be spill slots. | 93 // meant to be spill slots. |
| 90 if (Var->getWeight() == RegWeight::Zero) | 94 if (Var->getWeight() == RegWeight::Zero) |
| 91 continue; | 95 continue; |
| 92 // 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 |
| 93 // it was never referenced. | 97 // it was never referenced. |
| 94 if (Var->getLiveRange().isEmpty()) | 98 if (Var->getLiveRange().isEmpty()) |
| 95 continue; | 99 continue; |
| 96 Var->untrimLiveRange(); | 100 Var->untrimLiveRange(); |
| 97 Unhandled.push_back(Var); | 101 Unhandled.push_back(Var); |
| 98 if (Var->hasReg()) { | 102 if (Var->hasReg()) { |
| 99 Var->setRegNumTmp(Var->getRegNum()); | 103 Var->setRegNumTmp(Var->getRegNum()); |
| 100 Var->setLiveRangeInfiniteWeight(); | 104 Var->setLiveRangeInfiniteWeight(); |
| 101 UnhandledPrecolored.push_back(Var); | 105 UnhandledPrecolored.push_back(Var); |
| 102 } | 106 } |
| 103 } | 107 } |
| 108 |
| 109 // Build the (ordered) list of FakeKill instruction numbers. |
| 110 Kills.clear(); |
| 111 for (CfgNode *Node : Func->getNodes()) { |
| 112 for (auto I = Node->getInsts().begin(), E = Node->getInsts().end(); I != E; |
| 113 ++I) { |
| 114 if (auto Kill = llvm::dyn_cast<InstFakeKill>(I)) { |
| 115 if (!Kill->isDeleted() && !Kill->getLinked()->isDeleted()) |
| 116 Kills.push_back(I->getNumber()); |
| 117 } |
| 118 } |
| 119 } |
| 120 } |
| 121 |
| 122 // Prepare for very simple register allocation of only infinite-weight |
| 123 // Variables while respecting pre-colored Variables. Some properties |
| 124 // we take advantage of: |
| 125 // |
| 126 // * Live ranges of interest consist of a single segment. |
| 127 // |
| 128 // * Live ranges of interest never span a call instruction. |
| 129 // |
| 130 // * Phi instructions are not considered because either phis have |
| 131 // already been lowered, or they don't contain any pre-colored or |
| 132 // infinite-weight Variables. |
| 133 // |
| 134 // * We don't need to renumber instructions before computing live |
| 135 // ranges because all the high-level ICE instructions are deleted |
| 136 // prior to lowering, and the low-level instructions are added in |
| 137 // monotonically increasing order. |
| 138 // |
| 139 // * There are no opportunities for register preference or allowing |
| 140 // overlap. |
| 141 // |
| 142 // Some properties we aren't (yet) taking advantage of: |
| 143 // |
| 144 // * Because live ranges are a single segment, the Unhandled set will |
| 145 // always be empty, and the live range trimming operation is |
| 146 // unnecessary. |
| 147 // |
| 148 // * Calculating overlap of single-segment live ranges could be |
| 149 // optimized a bit. |
| 150 void LinearScan::initForInfOnly() { |
| 151 TimerMarker T(TimerStack::TT_initUnhandled, Func); |
| 152 FindPreference = false; |
| 153 FindOverlap = false; |
| 154 Unhandled.clear(); |
| 155 UnhandledPrecolored.clear(); |
| 156 Handled.clear(); |
| 157 Inactive.clear(); |
| 158 Active.clear(); |
| 159 const VarList &Vars = Func->getVariables(); |
| 160 Unhandled.reserve(Vars.size()); |
| 161 |
| 162 // Iterate across all instructions and record the begin and end of |
| 163 // the live range for each variable that is pre-colored or infinite |
| 164 // weight. |
| 165 std::vector<InstNumberT> LRBegin(Vars.size(), Inst::NumberSentinel); |
| 166 std::vector<InstNumberT> LREnd(Vars.size(), Inst::NumberSentinel); |
| 167 for (CfgNode *Node : Func->getNodes()) { |
| 168 for (auto Inst = Node->getInsts().begin(), E = Node->getInsts().end(); |
| 169 Inst != E; ++Inst) { |
| 170 if (Inst->isDeleted()) |
| 171 continue; |
| 172 if (const Variable *Var = Inst->getDest()) { |
| 173 if (Var->hasReg() || Var->getWeight() == RegWeight::Inf) { |
| 174 if (LRBegin[Var->getIndex()] == Inst::NumberSentinel) |
| 175 LRBegin[Var->getIndex()] = Inst->getNumber(); |
| 176 } |
| 177 } |
| 178 for (SizeT I = 0; I < Inst->getSrcSize(); ++I) { |
| 179 Operand *Src = Inst->getSrc(I); |
| 180 SizeT NumVars = Src->getNumVars(); |
| 181 for (SizeT J = 0; J < NumVars; ++J) { |
| 182 const Variable *Var = Src->getVar(J); |
| 183 if (Var->hasReg() || Var->getWeight() == RegWeight::Inf) |
| 184 LREnd[Var->getIndex()] = Inst->getNumber(); |
| 185 } |
| 186 } |
| 187 } |
| 188 } |
| 189 |
| 190 for (SizeT i = 0; i < Vars.size(); ++i) { |
| 191 Variable *Var = Vars[i]; |
| 192 if (LRBegin[i] != Inst::NumberSentinel) { |
| 193 assert(LREnd[i] != Inst::NumberSentinel); |
| 194 Unhandled.push_back(Var); |
| 195 Var->resetLiveRange(); |
| 196 const uint32_t WeightDelta = 1; |
| 197 Var->addLiveRange(LRBegin[i], LREnd[i], WeightDelta); |
| 198 Var->untrimLiveRange(); |
| 199 if (Var->hasReg()) { |
| 200 Var->setRegNumTmp(Var->getRegNum()); |
| 201 Var->setLiveRangeInfiniteWeight(); |
| 202 UnhandledPrecolored.push_back(Var); |
| 203 } |
| 204 } |
| 205 } |
| 206 |
| 207 // Don't build up the list of Kills because we know that no |
| 208 // infinite-weight Variable has a live range spanning a call. |
| 209 Kills.clear(); |
| 210 } |
| 211 |
| 212 void LinearScan::init(RegAllocKind Kind) { |
| 213 switch (Kind) { |
| 214 case RAK_Global: |
| 215 initForGlobal(); |
| 216 break; |
| 217 case RAK_InfOnly: |
| 218 initForInfOnly(); |
| 219 break; |
| 220 } |
| 221 |
| 104 struct CompareRanges { | 222 struct CompareRanges { |
| 105 bool operator()(const Variable *L, const Variable *R) { | 223 bool operator()(const Variable *L, const Variable *R) { |
| 106 InstNumberT Lstart = L->getLiveRange().getStart(); | 224 InstNumberT Lstart = L->getLiveRange().getStart(); |
| 107 InstNumberT Rstart = R->getLiveRange().getStart(); | 225 InstNumberT Rstart = R->getLiveRange().getStart(); |
| 108 if (Lstart == Rstart) | 226 if (Lstart == Rstart) |
| 109 return L->getIndex() < R->getIndex(); | 227 return L->getIndex() < R->getIndex(); |
| 110 return Lstart < Rstart; | 228 return Lstart < Rstart; |
| 111 } | 229 } |
| 112 }; | 230 }; |
| 113 // Do a reverse sort so that erasing elements (from the end) is fast. | 231 // Do a reverse sort so that erasing elements (from the end) is fast. |
| 114 std::sort(Unhandled.rbegin(), Unhandled.rend(), CompareRanges()); | 232 std::sort(Unhandled.rbegin(), Unhandled.rend(), CompareRanges()); |
| 115 std::sort(UnhandledPrecolored.rbegin(), UnhandledPrecolored.rend(), | 233 std::sort(UnhandledPrecolored.rbegin(), UnhandledPrecolored.rend(), |
| 116 CompareRanges()); | 234 CompareRanges()); |
| 117 | |
| 118 // Build the (ordered) list of FakeKill instruction numbers. | |
| 119 Kills.clear(); | |
| 120 for (CfgNode *Node : Func->getNodes()) { | |
| 121 for (auto I = Node->getInsts().begin(), E = Node->getInsts().end(); I != E; | |
| 122 ++I) { | |
| 123 if (I->isDeleted()) | |
| 124 continue; | |
| 125 if (auto Kill = llvm::dyn_cast<InstFakeKill>(I)) { | |
| 126 if (!Kill->getLinked()->isDeleted()) | |
| 127 Kills.push_back(I->getNumber()); | |
| 128 } | |
| 129 } | |
| 130 } | |
| 131 } | 235 } |
| 132 | 236 |
| 133 // Implements the linear-scan algorithm. Based on "Linear Scan | 237 // Implements the linear-scan algorithm. Based on "Linear Scan |
| 134 // Register Allocation in the Context of SSA Form and Register | 238 // Register Allocation in the Context of SSA Form and Register |
| 135 // Constraints" by Hanspeter Mössenböck and Michael Pfeiffer, | 239 // Constraints" by Hanspeter Mössenböck and Michael Pfeiffer, |
| 136 // ftp://ftp.ssw.uni-linz.ac.at/pub/Papers/Moe02.PDF . This | 240 // ftp://ftp.ssw.uni-linz.ac.at/pub/Papers/Moe02.PDF . This |
| 137 // implementation is modified to take affinity into account and allow | 241 // implementation is modified to take affinity into account and allow |
| 138 // two interfering variables to share the same register in certain | 242 // two interfering variables to share the same register in certain |
| 139 // cases. | 243 // cases. |
| 140 // | 244 // |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 285 // currently free, or that is assigned a register that is not free | 389 // currently free, or that is assigned a register that is not free |
| 286 // but overlap is allowed. Overlap is allowed when the Variable | 390 // but overlap is allowed. Overlap is allowed when the Variable |
| 287 // under consideration is single-definition, and its definition is | 391 // under consideration is single-definition, and its definition is |
| 288 // a simple assignment - i.e., the register gets copied/aliased | 392 // a simple assignment - i.e., the register gets copied/aliased |
| 289 // but is never modified. Furthermore, overlap is only allowed | 393 // but is never modified. Furthermore, overlap is only allowed |
| 290 // when preferred Variable definition instructions do not appear | 394 // when preferred Variable definition instructions do not appear |
| 291 // within the current Variable's live range. | 395 // within the current Variable's live range. |
| 292 Variable *Prefer = NULL; | 396 Variable *Prefer = NULL; |
| 293 int32_t PreferReg = Variable::NoRegister; | 397 int32_t PreferReg = Variable::NoRegister; |
| 294 bool AllowOverlap = false; | 398 bool AllowOverlap = false; |
| 295 if (const Inst *DefInst = VMetadata->getFirstDefinition(Cur)) { | 399 if (FindPreference) { |
| 296 assert(DefInst->getDest() == Cur); | 400 if (const Inst *DefInst = VMetadata->getFirstDefinition(Cur)) { |
| 297 bool IsAssign = DefInst->isSimpleAssign(); | 401 assert(DefInst->getDest() == Cur); |
| 298 bool IsSingleDef = !VMetadata->isMultiDef(Cur); | 402 bool IsAssign = DefInst->isSimpleAssign(); |
| 299 for (SizeT i = 0; i < DefInst->getSrcSize(); ++i) { | 403 bool IsSingleDef = !VMetadata->isMultiDef(Cur); |
| 300 // TODO(stichnot): Iterate through the actual Variables of the | 404 for (SizeT i = 0; i < DefInst->getSrcSize(); ++i) { |
| 301 // instruction, not just the source operands. This could | 405 // TODO(stichnot): Iterate through the actual Variables of the |
| 302 // capture Load instructions, including address mode | 406 // instruction, not just the source operands. This could |
| 303 // optimization, for Prefer (but not for AllowOverlap). | 407 // capture Load instructions, including address mode |
| 304 if (Variable *SrcVar = llvm::dyn_cast<Variable>(DefInst->getSrc(i))) { | 408 // optimization, for Prefer (but not for AllowOverlap). |
| 305 int32_t SrcReg = SrcVar->getRegNumTmp(); | 409 if (Variable *SrcVar = llvm::dyn_cast<Variable>(DefInst->getSrc(i))) { |
| 306 // Only consider source variables that have (so far) been | 410 int32_t SrcReg = SrcVar->getRegNumTmp(); |
| 307 // assigned a register. That register must be one in the | 411 // Only consider source variables that have (so far) been |
| 308 // RegMask set, e.g. don't try to prefer the stack pointer | 412 // assigned a register. That register must be one in the |
| 309 // as a result of the stacksave intrinsic. | 413 // RegMask set, e.g. don't try to prefer the stack pointer |
| 310 if (SrcVar->hasRegTmp() && RegMask[SrcReg]) { | 414 // as a result of the stacksave intrinsic. |
| 311 if (!Free[SrcReg]) { | 415 if (SrcVar->hasRegTmp() && RegMask[SrcReg]) { |
| 312 // Don't bother trying to enable AllowOverlap if the | 416 if (FindOverlap && !Free[SrcReg]) { |
| 313 // register is already free. | 417 // Don't bother trying to enable AllowOverlap if the |
| 314 AllowOverlap = | 418 // register is already free. |
| 315 IsSingleDef && IsAssign && !overlapsDefs(Func, Cur, SrcVar); | 419 AllowOverlap = |
| 316 } | 420 IsSingleDef && IsAssign && !overlapsDefs(Func, Cur, SrcVar); |
| 317 if (AllowOverlap || Free[SrcReg]) { | 421 } |
| 318 Prefer = SrcVar; | 422 if (AllowOverlap || Free[SrcReg]) { |
| 319 PreferReg = SrcReg; | 423 Prefer = SrcVar; |
| 424 PreferReg = SrcReg; |
| 425 } |
| 320 } | 426 } |
| 321 } | 427 } |
| 322 } | 428 } |
| 323 } | 429 if (Verbose && Prefer) { |
| 324 } | 430 Str << "Initial Prefer=" << *Prefer << " R=" << PreferReg |
| 325 if (Verbose) { | 431 << " LIVE=" << Prefer->getLiveRange() |
| 326 if (Prefer) { | 432 << " Overlap=" << AllowOverlap << "\n"; |
| 327 Str << "Initial Prefer=" << *Prefer << " R=" << PreferReg | 433 } |
| 328 << " LIVE=" << Prefer->getLiveRange() << " Overlap=" << AllowOverlap | |
| 329 << "\n"; | |
| 330 } | 434 } |
| 331 } | 435 } |
| 332 | 436 |
| 333 // Remove registers from the Free[] list where an Inactive range | 437 // Remove registers from the Free[] list where an Inactive range |
| 334 // overlaps with the current range. | 438 // overlaps with the current range. |
| 335 for (const Variable *Item : Inactive) { | 439 for (const Variable *Item : Inactive) { |
| 336 if (Item->rangeOverlaps(Cur)) { | 440 if (Item->rangeOverlaps(Cur)) { |
| 337 int32_t RegNum = Item->getRegNumTmp(); | 441 int32_t RegNum = Item->getRegNumTmp(); |
| 338 // Don't assert(Free[RegNum]) because in theory (though | 442 // Don't assert(Free[RegNum]) because in theory (though |
| 339 // probably never in practice) there could be two inactive | 443 // probably never in practice) there could be two inactive |
| 340 // variables that were marked with AllowOverlap. | 444 // variables that were marked with AllowOverlap. |
| 341 Free[RegNum] = false; | 445 Free[RegNum] = false; |
| 342 // Disable AllowOverlap if an Inactive variable, which is not | 446 // Disable AllowOverlap if an Inactive variable, which is not |
| 343 // Prefer, shares Prefer's register, and has a definition | 447 // Prefer, shares Prefer's register, and has a definition |
| 344 // within Cur's live range. | 448 // within Cur's live range. |
| 345 if (AllowOverlap && Item != Prefer && RegNum == PreferReg && | 449 if (AllowOverlap && Item != Prefer && RegNum == PreferReg && |
| 346 overlapsDefs(Func, Cur, Item)) { | 450 overlapsDefs(Func, Cur, Item)) { |
| 347 AllowOverlap = false; | 451 AllowOverlap = false; |
| 348 dumpDisableOverlap(Func, Item, "Inactive"); | 452 dumpDisableOverlap(Func, Item, "Inactive"); |
| 349 } | 453 } |
| 350 } | 454 } |
| 351 } | 455 } |
| 352 | 456 |
| 353 // Disable AllowOverlap if an Active variable, which is not | 457 // Disable AllowOverlap if an Active variable, which is not |
| 354 // Prefer, shares Prefer's register, and has a definition within | 458 // Prefer, shares Prefer's register, and has a definition within |
| 355 // Cur's live range. | 459 // Cur's live range. |
| 356 for (const Variable *Item : Active) { | 460 if (AllowOverlap) { |
| 357 int32_t RegNum = Item->getRegNumTmp(); | 461 for (const Variable *Item : Active) { |
| 358 if (Item != Prefer && RegNum == PreferReg && | 462 int32_t RegNum = Item->getRegNumTmp(); |
| 359 overlapsDefs(Func, Cur, Item)) { | 463 if (Item != Prefer && RegNum == PreferReg && |
| 360 AllowOverlap = false; | 464 overlapsDefs(Func, Cur, Item)) { |
| 361 dumpDisableOverlap(Func, Item, "Active"); | 465 AllowOverlap = false; |
| 466 dumpDisableOverlap(Func, Item, "Active"); |
| 467 } |
| 362 } | 468 } |
| 363 } | 469 } |
| 364 | 470 |
| 365 std::vector<RegWeight> Weights(RegMask.size()); | 471 std::vector<RegWeight> Weights(RegMask.size()); |
| 366 | 472 |
| 367 // Remove registers from the Free[] list where an Unhandled | 473 // Remove registers from the Free[] list where an Unhandled |
| 368 // precolored range overlaps with the current range, and set those | 474 // precolored range overlaps with the current range, and set those |
| 369 // registers to infinite weight so that they aren't candidates for | 475 // registers to infinite weight so that they aren't candidates for |
| 370 // eviction. Cur->rangeEndsBefore(Item) is an early exit check | 476 // eviction. Cur->rangeEndsBefore(Item) is an early exit check |
| 371 // that turns a guaranteed O(N^2) algorithm into expected linear | 477 // that turns a guaranteed O(N^2) algorithm into expected linear |
| (...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 603 Str << "\n"; | 709 Str << "\n"; |
| 604 } | 710 } |
| 605 Str << "++++++ Inactive:\n"; | 711 Str << "++++++ Inactive:\n"; |
| 606 for (const Variable *Item : Inactive) { | 712 for (const Variable *Item : Inactive) { |
| 607 dumpLiveRange(Item, Func); | 713 dumpLiveRange(Item, Func); |
| 608 Str << "\n"; | 714 Str << "\n"; |
| 609 } | 715 } |
| 610 } | 716 } |
| 611 | 717 |
| 612 } // end of namespace Ice | 718 } // end of namespace Ice |
| OLD | NEW |