SimpleAllocator.cpp (46040B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "jit/SimpleAllocator.h" 8 9 #include "mozilla/Maybe.h" 10 11 #include <algorithm> 12 13 #include "jit/BitSet.h" 14 #include "jit/CompileInfo.h" 15 #include "js/Printf.h" 16 17 using namespace js; 18 using namespace js::jit; 19 20 using mozilla::DebugOnly; 21 using mozilla::Maybe; 22 23 // [SMDOC] Simple Register Allocator 24 // 25 // This is an alternative register allocator for Ion that's simpler than the 26 // backtracking allocator. It attempts to perform register allocation quickly 27 // while still producing fairly decent code within basic blocks. 28 // 29 // The Backtracking allocator is usually the slowest part of the Ion compiler 30 // backend, whereas this Simple allocator is often faster than codegen and/or 31 // GVN. 32 // 33 // This allocator lets us experiment with different compilation strategies and 34 // it provides a useful baseline for measuring and optimizing the performance of 35 // the backtracking allocator. 36 // 37 // This allocator also helps document our LIR => Register Allocator interface 38 // and will make it easier to experiment with alternative register allocators in 39 // the future. 40 // 41 // Phases 42 // ====== 43 // This allocator has 3 phases with the following main goals: 44 // 45 // (1) init: initializes a VirtualRegister instance for each virtual register. 46 // 47 // (2) analyzeLiveness: iterates over all LIR instructions in reverse order to 48 // collect the following information: 49 // 50 // * For each virtual register we record where it's last used (its 51 // lastUseInsId_). Register allocation uses this information to free 52 // dead registers and stack slots in freeDeadVregsAfterInstruction. 53 // 54 // * For each basic block it records the set of live GC things (liveGCIn_) 55 // at the start of the block. This is used by the register allocation pass 56 // to populate safepoints (used for GC tracing). 57 // 58 // * For virtual registers with fixed register uses, it assigns a register 59 // hint to help avoid moves (fixedUseHint_). 60 // 61 // This function is based on BacktrackingAllocator::buildLivenessInfo. 62 // 63 // (3) allocateRegisters: this iterates over all LIR instructions (from first to 64 // last) to allocate registers and to populate safepoints. 65 // 66 // Register allocation 67 // =================== 68 // Producing the fastest possible code is not a goal for this allocator, so it 69 // makes the following trade-offs: 70 // 71 // * It tries to keep values in registers within a basic block, but values that 72 // are used across blocks are spilled in the block where they're defined. 73 // We try to spill these values as early as possible (instead of all at the 74 // end of the block) to help avoid CPU store buffer stalls. 75 // 76 // * Blocks with a single predecessor can reuse the register state at the end of 77 // that predecessor block. Values in these registers must have a stack 78 // location too so reusing this state is optional. This is based on a small 79 // array with state for just four recent blocks in it, but in practice this is 80 // good enough to eliminate a lot of memory loads. 81 // 82 // * Phis are always assigned a stack slot and phi operands are stored to this 83 // location at the end of the predecessor blocks (in allocateForBlockEnd). 84 // 85 // * Stack slots are freed when virtual registers die and can then be reused. 86 // 87 // In practice this results in fairly decent code within basic blocks. This 88 // allocator generates relatively poor code for tight loops or for code with 89 // many short blocks. 90 91 static AnyRegister MaybeGetRegisterFromSet(AllocatableRegisterSet regs, 92 LDefinition::Type type) { 93 // Get an available register from `regs`, or return an invalid register if no 94 // register is available. 95 switch (type) { 96 case LDefinition::Type::FLOAT32: 97 if (regs.hasAny<RegTypeName::Float32>()) { 98 return AnyRegister(regs.getAnyFloat<RegTypeName::Float32>()); 99 } 100 break; 101 case LDefinition::Type::DOUBLE: 102 if (regs.hasAny<RegTypeName::Float64>()) { 103 return AnyRegister(regs.getAnyFloat<RegTypeName::Float64>()); 104 } 105 break; 106 case LDefinition::Type::SIMD128: 107 if (regs.hasAny<RegTypeName::Vector128>()) { 108 return AnyRegister(regs.getAnyFloat<RegTypeName::Vector128>()); 109 } 110 break; 111 default: 112 MOZ_ASSERT(!LDefinition::isFloatReg(type)); 113 if (regs.hasAny<RegTypeName::GPR>()) { 114 return AnyRegister(regs.getAnyGeneral()); 115 } 116 break; 117 } 118 return AnyRegister(); 119 } 120 121 bool SimpleAllocator::init() { 122 size_t numBlocks = graph.numBlocks(); 123 if (!liveGCIn_.growBy(numBlocks)) { 124 return false; 125 } 126 127 size_t numVregs = graph.numVirtualRegisters(); 128 if (!vregs_.initCapacity(numVregs)) { 129 return false; 130 } 131 for (size_t i = 0; i < numVregs; i++) { 132 vregs_.infallibleEmplaceBack(); 133 } 134 135 // Initialize virtual registers. 136 for (size_t blockIndex = 0; blockIndex < numBlocks; blockIndex++) { 137 if (mir->shouldCancel("init (block loop)")) { 138 return false; 139 } 140 141 LBlock* block = graph.getBlock(blockIndex); 142 143 for (uint32_t i = 0, numPhis = block->numPhis(); i < numPhis; i++) { 144 LPhi* phi = block->getPhi(i); 145 LDefinition* def = phi->getDef(0); 146 vregs_[def->virtualRegister()].init(phi, def, /* isTemp = */ false); 147 } 148 149 for (LInstructionIterator iter = block->begin(); iter != block->end(); 150 iter++) { 151 LInstruction* ins = *iter; 152 for (LInstruction::OutputIter output(ins); !output.done(); output++) { 153 LDefinition* def = *output; 154 vregs_[def->virtualRegister()].init(ins, def, /* isTemp = */ false); 155 } 156 for (LInstruction::TempIter temp(ins); !temp.done(); temp++) { 157 LDefinition* def = *temp; 158 vregs_[def->virtualRegister()].init(ins, def, /* isTemp = */ true); 159 } 160 } 161 } 162 163 return true; 164 } 165 166 bool SimpleAllocator::analyzeLiveness() { 167 JitSpew(JitSpew_RegAlloc, "Beginning liveness analysis"); 168 169 // Stack of active loops. 170 struct LoopState { 171 // The first instruction of the loop header. 172 uint32_t firstId; 173 // The last instruction of the backedge. 174 uint32_t lastId; 175 explicit LoopState(LBlock* header, uint32_t lastId) 176 : firstId(header->firstId()), lastId(lastId) {} 177 }; 178 Vector<LoopState, 4, BackgroundSystemAllocPolicy> loopStack; 179 180 #ifdef DEBUG 181 // In debug builds, assert that each instruction has a smaller ID than the 182 // previous instructions we saw (since we're iterating over instructions in 183 // reverse order). Our simple liveness analysis relies on this for the vreg's 184 // lastUseInsId_. 185 uint32_t lastInsId = UINT32_MAX; 186 #endif 187 188 for (size_t i = graph.numBlocks(); i > 0; i--) { 189 if (mir->shouldCancel("analyzeLiveness (block loop)")) { 190 return false; 191 } 192 193 LBlock* block = graph.getBlock(i - 1); 194 MBasicBlock* mblock = block->mir(); 195 VirtualRegBitSet& liveGC = liveGCIn_[mblock->id()]; 196 197 if (mblock->isLoopBackedge()) { 198 if (!loopStack.emplaceBack(mblock->loopHeaderOfBackedge()->lir(), 199 block->lastId())) { 200 return false; 201 } 202 } 203 204 // Propagate liveGCIn from our successors to us. Skip backedges, as we fix 205 // them up at the loop header. 206 for (size_t i = 0; i < mblock->lastIns()->numSuccessors(); i++) { 207 MBasicBlock* successor = mblock->lastIns()->getSuccessor(i); 208 if (mblock->id() < successor->id()) { 209 if (!liveGC.insertAll(liveGCIn_[successor->id()])) { 210 return false; 211 } 212 } 213 } 214 215 uint32_t blockFirstId = block->firstId(); 216 217 auto handleUseOfVreg = [&](uint32_t insId, uint32_t vregId) { 218 uint32_t defId = vregs_[vregId].insId(); 219 const LoopState* outerLoop = nullptr; 220 if (defId < blockFirstId) { 221 // This vreg is defined before the current block. We need to add it to 222 // the block's liveGC set if it's a GC type. 223 if (vregs_[vregId].isGCType() && !liveGC.insert(vregId)) { 224 return false; 225 } 226 // If we're inside a loop, search for the outermost loop that has this 227 // vreg live across the entire loop. We need to extend the vreg's range 228 // to cover this loop. 229 for (size_t i = loopStack.length(); i > 0; i--) { 230 const LoopState& loop = loopStack[i - 1]; 231 if (defId >= loop.firstId) { 232 break; 233 } 234 outerLoop = &loop; 235 } 236 } 237 vregs_[vregId].updateLastUseId(outerLoop ? outerLoop->lastId : insId); 238 return true; 239 }; 240 241 // If this block has a successor with phis, the phi operands will be used at 242 // the end of the current block. 243 if (MBasicBlock* successor = mblock->successorWithPhis()) { 244 LBlock* phiSuccessor = successor->lir(); 245 uint32_t blockLastInsId = block->lastId(); 246 for (size_t j = 0; j < phiSuccessor->numPhis(); j++) { 247 LPhi* phi = phiSuccessor->getPhi(j); 248 LAllocation* use = phi->getOperand(mblock->positionInPhiSuccessor()); 249 if (!handleUseOfVreg(blockLastInsId, use->toUse()->virtualRegister())) { 250 return false; 251 } 252 } 253 } 254 255 // Handle instruction uses and outputs. 256 for (LInstructionReverseIterator ins = block->rbegin(); 257 ins != block->rend(); ins++) { 258 if (mir->shouldCancel("analyzeLiveness (instruction loop)")) { 259 return false; 260 } 261 262 #ifdef DEBUG 263 MOZ_ASSERT(ins->id() < lastInsId); 264 lastInsId = ins->id(); 265 #endif 266 267 for (LInstruction::OutputIter output(*ins); !output.done(); output++) { 268 uint32_t vregId = output->virtualRegister(); 269 if (vregs_[vregId].isGCType()) { 270 liveGC.remove(vregId); 271 } 272 } 273 for (LInstruction::InputIter inputAlloc(**ins); inputAlloc.more(); 274 inputAlloc.next()) { 275 if (!inputAlloc->isUse()) { 276 continue; 277 } 278 LUse* use = inputAlloc->toUse(); 279 uint32_t vregId = use->virtualRegister(); 280 if (!handleUseOfVreg(ins->id(), vregId)) { 281 return false; 282 } 283 if (use->policy() == LUse::FIXED) { 284 // Assign a register hint to the vreg. We'll prefer allocating this 285 // register later to avoid unnecessary moves. 286 VirtualRegister& vreg = vregs_[vregId]; 287 AnyRegister fixedReg = GetFixedRegister(vreg.def(), use); 288 if (vreg.fixedUseHint().isNothing()) { 289 vreg.setFixedUseHint(fixedReg); 290 } else if (*vreg.fixedUseHint() != fixedReg) { 291 // Conflicting fixed register uses. Clear the hint. 292 vreg.setFixedUseHint(AnyRegister()); 293 } 294 } 295 } 296 } 297 298 // Handle phi definitions. 299 for (size_t i = 0; i < block->numPhis(); i++) { 300 LPhi* phi = block->getPhi(i); 301 LDefinition* def = phi->getDef(0); 302 uint32_t vregId = def->virtualRegister(); 303 if (vregs_[vregId].isGCType()) { 304 liveGC.remove(vregId); 305 } 306 // Loop header phis must not be freed before the end of the backedge 307 // because the backedge might store to the phi's stack slot. 308 if (mblock->isLoopHeader()) { 309 vregs_[vregId].updateLastUseId(loopStack.back().lastId); 310 } 311 } 312 313 if (mblock->isLoopHeader()) { 314 MBasicBlock* backedge = mblock->backedge(); 315 MOZ_ASSERT(loopStack.back().firstId == block->firstId()); 316 loopStack.popBack(); 317 318 // Propagate the loop header's liveGCIn set to all blocks within the loop. 319 if (mblock != backedge && !liveGC.empty()) { 320 // Start at the block after |mblock|. 321 MOZ_ASSERT(graph.getBlock(i - 1) == mblock->lir()); 322 size_t j = i; 323 while (true) { 324 MBasicBlock* loopBlock = graph.getBlock(j)->mir(); 325 if (!liveGCIn_[loopBlock->id()].insertAll(liveGC)) { 326 return false; 327 } 328 if (loopBlock == backedge) { 329 break; 330 } 331 j++; 332 } 333 } 334 } 335 336 MOZ_ASSERT_IF(!mblock->numPredecessors(), liveGC.empty()); 337 } 338 339 MOZ_ASSERT(loopStack.empty()); 340 341 // Initialize vregLastUses_ vector and sort it by instructionId in descending 342 // order. This will be used in freeDeadVregsAfterInstruction. 343 uint32_t numVregs = vregs_.length(); 344 if (!vregLastUses_.reserve(numVregs)) { 345 return false; 346 } 347 for (uint32_t vregId = 1; vregId < numVregs; vregId++) { 348 vregLastUses_.infallibleEmplaceBack(vregs_[vregId].lastUseInsId(), vregId); 349 } 350 auto compareEntries = [](VregLastUse a, VregLastUse b) { 351 return a.instructionId > b.instructionId; 352 }; 353 std::sort(vregLastUses_.begin(), vregLastUses_.end(), compareEntries); 354 return true; 355 } 356 357 void SimpleAllocator::removeAllocatedRegisterAtIndex(size_t index) { 358 // Release the register for this entry. 359 AllocatedRegister allocated = allocatedRegs_[index]; 360 uint32_t vregId = allocated.vregId(); 361 availableRegs_.add(allocated.reg()); 362 363 // Use the swap-and-pop idiom to remove the entry so that we don't change the 364 // register index of other entries. 365 size_t lastIndex = allocatedRegs_.length() - 1; 366 if (index != lastIndex) { 367 uint32_t lastVregId = allocatedRegs_.back().vregId(); 368 allocatedRegs_[index] = allocatedRegs_.back(); 369 if (vregs_[lastVregId].registerIndex() == lastIndex) { 370 vregs_[lastVregId].setRegisterIndex(index); 371 } 372 } 373 allocatedRegs_.popBack(); 374 vregs_[vregId].clearRegisterIndex(); 375 376 // In the uncommon case where the vreg might have another allocated register, 377 // assign the other register to this vreg if needed. 378 if (MOZ_UNLIKELY(hasMultipleRegsForVreg_)) { 379 for (size_t j = 0; j < allocatedRegs_.length(); j++) { 380 if (allocatedRegs_[j].vregId() == vregId) { 381 vregs_[vregId].setRegisterIndex(j); 382 break; 383 } 384 } 385 } 386 } 387 388 LAllocation SimpleAllocator::ensureStackLocation(uint32_t vregId) { 389 // Allocate a stack slot for this virtual register if needed. 390 VirtualRegister& vreg = vregs_[vregId]; 391 if (vreg.hasStackLocation()) { 392 return vreg.stackLocation(); 393 } 394 LStackSlot::Width width = LStackSlot::width(vreg.def()->type()); 395 LStackSlot::SlotAndWidth slot(stackSlotAllocator_.allocateSlot(width), width); 396 vreg.setAllocatedStackSlot(slot); 397 return LStackSlot(slot); 398 } 399 400 LAllocation SimpleAllocator::registerOrStackLocation(LInstruction* ins, 401 uint32_t vregId, 402 bool trackRegUse) { 403 const VirtualRegister& vreg = vregs_[vregId]; 404 if (vreg.hasRegister()) { 405 AllocatedRegister& allocated = allocatedRegs_[vreg.registerIndex()]; 406 if (trackRegUse) { 407 allocated.setLastUsedAtInsId(ins->id()); 408 } 409 return LAllocation(allocated.reg()); 410 } 411 return vreg.stackLocation(); 412 } 413 414 bool SimpleAllocator::spillRegister(LInstruction* ins, 415 AllocatedRegister allocated) { 416 VirtualRegister& vreg = vregs_[allocated.vregId()]; 417 MOZ_ASSERT(vreg.insId() < ins->id()); 418 if (vreg.hasStackLocation()) { 419 return true; 420 } 421 // Allocate a new stack slot and insert a register => stack move. 422 LMoveGroup* input = getInputMoveGroup(ins); 423 LAllocation dest = ensureStackLocation(allocated.vregId()); 424 return input->addAfter(LAllocation(allocated.reg()), dest, 425 vreg.def()->type()); 426 } 427 428 bool SimpleAllocator::allocateForBlockEnd(LBlock* block, LInstruction* ins) { 429 #ifdef DEBUG 430 // All vregs that are live after this block must have a stack location at this 431 // point. 432 for (const AllocatedRegister& allocated : allocatedRegs_) { 433 MOZ_ASSERT_IF(vregs_[allocated.vregId()].lastUseInsId() > ins->id(), 434 vregs_[allocated.vregId()].hasStackLocation()); 435 } 436 #endif 437 438 MBasicBlock* successor = block->mir()->successorWithPhis(); 439 if (!successor) { 440 return true; 441 } 442 443 // The current block has a successor with phis. For each successor phi, insert 444 // a move at the end of the current block to store the phi's operand into the 445 // phi's stack slot. 446 447 uint32_t position = block->mir()->positionInPhiSuccessor(); 448 LBlock* lirSuccessor = successor->lir(); 449 LMoveGroup* group = nullptr; 450 451 for (size_t i = 0, numPhis = lirSuccessor->numPhis(); i < numPhis; i++) { 452 LPhi* phi = lirSuccessor->getPhi(i); 453 454 uint32_t sourceVreg = phi->getOperand(position)->toUse()->virtualRegister(); 455 uint32_t destVreg = phi->getDef(0)->virtualRegister(); 456 if (sourceVreg == destVreg) { 457 continue; 458 } 459 460 if (!group) { 461 // The moves we insert here need to happen simultaneously with each other, 462 // yet after any existing moves before the instruction. 463 LMoveGroup* input = getInputMoveGroup(ins); 464 if (input->numMoves() == 0) { 465 group = input; 466 } else { 467 group = LMoveGroup::New(alloc()); 468 block->insertAfter(input, group); 469 } 470 } 471 472 LAllocation source = 473 registerOrStackLocation(ins, sourceVreg, /* trackRegUse = */ true); 474 LAllocation dest = ensureStackLocation(destVreg); 475 if (!group->add(source, dest, phi->getDef(0)->type())) { 476 return false; 477 } 478 } 479 480 return true; 481 } 482 483 void SimpleAllocator::scanDefinition(LInstruction* ins, LDefinition* def, 484 bool isTemp) { 485 // Record fixed registers to make sure we don't assign these registers to 486 // uses. 487 if (def->policy() == LDefinition::FIXED && def->output()->isAnyRegister()) { 488 AnyRegister reg = def->output()->toAnyRegister(); 489 if (isTemp) { 490 fixedTempRegs_.add(reg); 491 } 492 // Note: addUnchecked because some instructions use the same fixed register 493 // for a Temp and an Output (eg LCallNative). See bug 1962671. 494 fixedOutputAndTempRegs_.addUnchecked(reg); 495 return; 496 } 497 if (def->policy() == LDefinition::MUST_REUSE_INPUT) { 498 ins->changePolicyOfReusedInputToAny(def); 499 } 500 } 501 502 bool SimpleAllocator::allocateForNonFixedDefOrUse(LInstruction* ins, 503 uint32_t vregId, 504 AllocationKind kind, 505 AnyRegister* reg) { 506 // This function is responsible for finding a new register for a (non-fixed) 507 // register def or use. If no register is available, it will evict something. 508 509 // This should only be called if the vreg doesn't have a register yet, unless 510 // the caller set hasMultipleRegsForVreg_ to true. 511 const VirtualRegister& vreg = vregs_[vregId]; 512 MOZ_ASSERT_IF(!hasMultipleRegsForVreg_, !vreg.hasRegister()); 513 514 // Determine the set of available registers. We can pick any register in 515 // availableRegs_ except for fixed output/temp registers that we need to 516 // allocate later. Note that UseAtStart inputs may use the same register as 517 // outputs (but not temps). 518 bool isUseAtStart = (kind == AllocationKind::UseAtStart); 519 RegisterSet fixedDefs = 520 isUseAtStart ? fixedTempRegs_.set() : fixedOutputAndTempRegs_.set(); 521 AllocatableRegisterSet available( 522 RegisterSet::Subtract(availableRegs_.set(), fixedDefs)); 523 524 // If the virtual register has a register hint, pick that register if it's 525 // available. 526 if (vreg.fixedUseHint().isSome() && vreg.fixedUseHint()->isValid()) { 527 AnyRegister regHint = *vreg.fixedUseHint(); 528 if (available.has(regHint)) { 529 *reg = regHint; 530 return addAllocatedReg(ins, vregId, isUseAtStart, *reg); 531 } 532 } 533 534 // Try to get an arbitrary register from the set. 535 *reg = MaybeGetRegisterFromSet(available, vreg.def()->type()); 536 if (reg->isValid()) { 537 return addAllocatedReg(ins, vregId, isUseAtStart, *reg); 538 } 539 540 // No register is available. We need to evict something. 541 542 // Determine which registers we must not evict. These are the registers in 543 // fixedDefs (same as above) + registers we've already allocated for this 544 // instruction. Note again that outputs can be assigned the same register as 545 // UseAtStart inputs and we rely on this to not run out of registers on 32-bit 546 // x86. 547 AllocatableRegisterSet notEvictable; 548 if (kind == AllocationKind::Output) { 549 notEvictable.set() = 550 RegisterSet::Union(fixedDefs, currentInsRegsNotAtStart_.set()); 551 } else { 552 notEvictable.set() = RegisterSet::Union(fixedDefs, currentInsRegs_.set()); 553 } 554 555 // Search for the best register to evict. 556 LDefinition* def = vreg.def(); 557 const AllocatedRegister* bestToEvict = nullptr; 558 for (size_t i = 0, len = allocatedRegs_.length(); i < len; i++) { 559 AllocatedRegister& allocated = allocatedRegs_[i]; 560 if (!def->isCompatibleReg(allocated.reg()) || 561 notEvictable.has(allocated.reg())) { 562 continue; 563 } 564 // Heuristics: prefer evicting registers where the vreg is also in another 565 // register (uncommon), registers that already have a stack location, or 566 // registers that haven't been used recently. 567 if (!bestToEvict || vregs_[allocated.vregId()].registerIndex() != i || 568 (vregs_[allocated.vregId()].hasStackLocation() && 569 !vregs_[bestToEvict->vregId()].hasStackLocation()) || 570 allocated.lastUsedAtInsId() < bestToEvict->lastUsedAtInsId()) { 571 bestToEvict = &allocated; 572 } 573 } 574 575 if (bestToEvict) { 576 *reg = bestToEvict->reg(); 577 } else { 578 // We didn't find a compatible register to evict. This can happen for 579 // aliased registers, for example if we allocated all Float32 registers and 580 // now need a Double register. Pick an arbitrary register that's evictable 581 // and evict all of its aliases. 582 AllocatableRegisterSet evictable; 583 evictable.set() = 584 RegisterSet::Subtract(allRegisters_.set(), notEvictable.set()); 585 *reg = MaybeGetRegisterFromSet(evictable, def->type()); 586 MOZ_ASSERT(reg->numAliased() > 1); 587 } 588 if (!evictRegister(ins, *reg)) { 589 return false; 590 } 591 return addAllocatedReg(ins, vregId, isUseAtStart, *reg); 592 } 593 594 bool SimpleAllocator::allocateForFixedUse(LInstruction* ins, const LUse* use, 595 AnyRegister* reg) { 596 uint32_t vregId = use->virtualRegister(); 597 VirtualRegister& vreg = vregs_[vregId]; 598 *reg = GetFixedRegister(vreg.def(), use); 599 600 // Determine the vreg's current location. 601 LAllocation alloc; 602 if (vreg.hasRegister()) { 603 // Check if the vreg is already using the fixed register. 604 AllocatedRegister& allocated = allocatedRegs_[vreg.registerIndex()]; 605 if (allocated.reg() == *reg) { 606 markUseOfAllocatedReg(ins, allocated, use->usedAtStart()); 607 return true; 608 } 609 610 // Try to avoid having multiple registers for the same vreg by replacing the 611 // current register with the new one. If this is not possible (this is 612 // uncommon) we set hasMultipleRegsForVreg_ and fix this up at the end of 613 // allocateForInstruction. 614 alloc = LAllocation(allocated.reg()); 615 if (currentInsRegs_.has(allocated.reg())) { 616 hasMultipleRegsForVreg_ = true; 617 } else { 618 removeAllocatedRegisterAtIndex(vreg.registerIndex()); 619 } 620 } else { 621 alloc = vreg.stackLocation(); 622 } 623 624 // If the fixed register is not available we have to evict it. 625 if (!availableRegs_.has(*reg) && !evictRegister(ins, *reg)) { 626 return false; 627 } 628 629 // Mark register as allocated and load the value in it. 630 if (!addAllocatedReg(ins, vregId, use->usedAtStart(), *reg)) { 631 return false; 632 } 633 LMoveGroup* input = getInputMoveGroup(ins); 634 return input->addAfter(alloc, LAllocation(*reg), vreg.def()->type()); 635 } 636 637 bool SimpleAllocator::allocateForRegisterUse(LInstruction* ins, const LUse* use, 638 AnyRegister* reg) { 639 uint32_t vregId = use->virtualRegister(); 640 VirtualRegister& vreg = vregs_[vregId]; 641 bool useAtStart = use->usedAtStart(); 642 643 // Determine the vreg's current location. 644 LAllocation alloc; 645 if (vreg.hasRegister()) { 646 // The vreg already has a register. We can use it if we won't need this 647 // register later for a fixed output or temp. 648 AllocatedRegister& allocated = allocatedRegs_[vreg.registerIndex()]; 649 bool isReserved = useAtStart ? fixedTempRegs_.has(allocated.reg()) 650 : fixedOutputAndTempRegs_.has(allocated.reg()); 651 if (!isReserved) { 652 markUseOfAllocatedReg(ins, allocated, useAtStart); 653 *reg = allocated.reg(); 654 return true; 655 } 656 657 // Try to avoid having multiple registers for the same vreg by replacing the 658 // current register with the new one. If this is not possible (this is 659 // uncommon) we set hasMultipleRegsForVreg_ and fix this up at the end of 660 // allocateForInstruction. 661 alloc = LAllocation(allocated.reg()); 662 if (currentInsRegs_.has(allocated.reg())) { 663 hasMultipleRegsForVreg_ = true; 664 } else { 665 removeAllocatedRegisterAtIndex(vreg.registerIndex()); 666 } 667 } else { 668 alloc = vreg.stackLocation(); 669 } 670 671 // This vreg is not in a register or it's in a reserved register. Allocate a 672 // new register. 673 AllocationKind kind = 674 useAtStart ? AllocationKind::UseAtStart : AllocationKind::UseOrTemp; 675 if (!allocateForNonFixedDefOrUse(ins, vregId, kind, reg)) { 676 return false; 677 } 678 LMoveGroup* input = getInputMoveGroup(ins); 679 return input->addAfter(alloc, LAllocation(*reg), vreg.def()->type()); 680 } 681 682 bool SimpleAllocator::evictRegister(LInstruction* ins, AnyRegister reg) { 683 // The caller wants to use `reg` but it's not available. Spill this register 684 // (and its aliases) to make it available. 685 686 MOZ_ASSERT(reg.isValid()); 687 MOZ_ASSERT(!availableRegs_.has(reg)); 688 689 for (size_t i = 0; i < allocatedRegs_.length();) { 690 AllocatedRegister allocated = allocatedRegs_[i]; 691 if (!allocated.reg().aliases(reg)) { 692 i++; 693 continue; 694 } 695 696 // Registers are added to the safepoint in `populateSafepoint`, but if we're 697 // evicting a register that's being used at-start we lose information about 698 // this so we have to add it to the safepoint now. 699 if (ins->safepoint() && !ins->isCall() && 700 currentInsRegs_.has(allocated.reg())) { 701 MOZ_ASSERT(!currentInsRegsNotAtStart_.has(allocated.reg())); 702 if (!addLiveRegisterToSafepoint(ins->safepoint(), allocated)) { 703 return false; 704 } 705 } 706 707 // Spill this register unless we know this vreg also lives in a different 708 // register (this is uncommon). 709 uint32_t vregId = allocated.vregId(); 710 if (vregs_[vregId].registerIndex() == i) { 711 if (!spillRegister(ins, allocated)) { 712 return false; 713 } 714 } else { 715 MOZ_ASSERT(hasMultipleRegsForVreg_); 716 } 717 removeAllocatedRegisterAtIndex(i); 718 719 if (availableRegs_.has(reg)) { 720 return true; 721 } 722 } 723 724 MOZ_CRASH("failed to evict register"); 725 } 726 727 bool SimpleAllocator::allocateForDefinition(uint32_t blockLastId, 728 LInstruction* ins, LDefinition* def, 729 bool isTemp) { 730 uint32_t vregId = def->virtualRegister(); 731 732 // Allocate a register for this definition. Return early for definitions that 733 // don't need a register. 734 AnyRegister reg; 735 switch (def->policy()) { 736 case LDefinition::FIXED: { 737 if (!def->output()->isAnyRegister()) { 738 MOZ_ASSERT(!isTemp); 739 vregs_[vregId].setHasStackLocation(); 740 return true; 741 } 742 743 // We need a fixed register. Evict it if it's not available. 744 reg = def->output()->toAnyRegister(); 745 if (!availableRegs_.has(reg)) { 746 // For call instructions we allow Temps and Outputs to use the same 747 // fixed register. That should probably be changed at some point, but 748 // for now we can handle this edge case by removing the temp's register. 749 // See bug 1962671. 750 if (!isTemp && fixedTempRegs_.has(reg)) { 751 MOZ_ASSERT(ins->isCall()); 752 for (size_t i = 0; i < allocatedRegs_.length(); i++) { 753 if (allocatedRegs_[i].reg() == reg) { 754 removeAllocatedRegisterAtIndex(i); 755 break; 756 } 757 } 758 MOZ_ASSERT(availableRegs_.has(reg)); 759 } else { 760 if (!evictRegister(ins, reg)) { 761 return false; 762 } 763 } 764 } 765 if (!addAllocatedReg(ins, vregId, /* usedAtStart = */ false, reg)) { 766 return false; 767 } 768 break; 769 } 770 case LDefinition::REGISTER: { 771 AllocationKind kind = 772 isTemp ? AllocationKind::UseOrTemp : AllocationKind::Output; 773 if (!allocateForNonFixedDefOrUse(ins, vregId, kind, ®)) { 774 return false; 775 } 776 break; 777 } 778 case LDefinition::MUST_REUSE_INPUT: { 779 // Allocate a new register and add an entry to reusedInputs_ to move the 780 // input into this register when we're done allocating registers. 781 AllocationKind kind = 782 isTemp ? AllocationKind::UseOrTemp : AllocationKind::Output; 783 if (!allocateForNonFixedDefOrUse(ins, vregId, kind, ®)) { 784 return false; 785 } 786 LAllocation* useAlloc = ins->getOperand(def->getReusedInput()); 787 uint32_t useVregId = useAlloc->toUse()->virtualRegister(); 788 LDefinition::Type type = vregs_[useVregId].def()->type(); 789 if (!reusedInputs_.emplaceBack(useAlloc, reg, type)) { 790 return false; 791 } 792 break; 793 } 794 case LDefinition::STACK: { 795 // This is a Wasm stack area or stack result. This is used when calling 796 // functions with multiple return values. 797 MOZ_ASSERT(!isTemp); 798 if (def->type() == LDefinition::STACKRESULTS) { 799 LStackArea alloc(ins->toInstruction()); 800 stackSlotAllocator_.allocateStackArea(&alloc); 801 def->setOutput(alloc); 802 } else { 803 // Because the definitions are visited in order, the area has been 804 // allocated before we reach this result, so we know the operand is an 805 // LStackArea. 806 const LUse* use = ins->getOperand(0)->toUse(); 807 VirtualRegister& area = vregs_[use->virtualRegister()]; 808 const LStackArea* areaAlloc = area.def()->output()->toStackArea(); 809 def->setOutput(areaAlloc->resultAlloc(ins, def)); 810 } 811 vregs_[vregId].setHasStackLocation(); 812 return true; 813 } 814 } 815 816 def->setOutput(LAllocation(reg)); 817 818 // If this is an output register for a vreg that's used in a different block, 819 // we have to spill it to the stack at some point and we want to do that as 820 // early as possible. We can't do it here though because we're not allowed to 821 // insert moves right before LOsiPoint instructions. Add the outputs to a 822 // vector that we check at the start of allocateForInstruction. 823 if (!isTemp && vregs_[vregId].lastUseInsId() > blockLastId) { 824 if (!eagerSpillOutputs_.append(def)) { 825 return false; 826 } 827 } 828 829 return true; 830 } 831 832 bool SimpleAllocator::allocateForInstruction(VirtualRegBitSet& liveGC, 833 uint32_t blockLastId, 834 LInstruction* ins) { 835 if (!alloc().ensureBallast()) { 836 return false; 837 } 838 839 assertValidRegisterStateBeforeInstruction(); 840 MOZ_ASSERT(reusedInputs_.empty()); 841 842 // If we have to spill output registers of a previous instruction, do that now 843 // if the instruction is not an LOsiPoint instruction. See the comment at the 844 // end of allocateForDefinition. 845 if (!eagerSpillOutputs_.empty() && !ins->isOsiPoint()) { 846 LMoveGroup* moves = getInputMoveGroup(ins); 847 for (LDefinition* def : eagerSpillOutputs_) { 848 MOZ_ASSERT(!vregs_[def->virtualRegister()].hasStackLocation()); 849 LAllocation dest = ensureStackLocation(def->virtualRegister()); 850 if (!moves->add(*def->output(), dest, def->type())) { 851 return false; 852 } 853 } 854 eagerSpillOutputs_.clear(); 855 } 856 857 // Clear per-instruction register sets. 858 currentInsRegs_ = AllocatableRegisterSet(); 859 currentInsRegsNotAtStart_ = AllocatableRegisterSet(); 860 fixedTempRegs_ = AllocatableRegisterSet(); 861 fixedOutputAndTempRegs_ = AllocatableRegisterSet(); 862 863 // Allocate all fixed inputs first. 864 for (LInstruction::NonSnapshotInputIter alloc(*ins); alloc.more(); 865 alloc.next()) { 866 if (!alloc->isUse() || alloc->toUse()->policy() != LUse::FIXED) { 867 continue; 868 } 869 AnyRegister reg; 870 if (!allocateForFixedUse(ins, alloc->toUse(), ®)) { 871 return false; 872 } 873 alloc.replace(LAllocation(reg)); 874 } 875 876 // Scan all definitions. If any of these require fixed registers, it will 877 // affect which registers are available for the inputs. 878 for (LInstruction::TempIter temp(ins); !temp.done(); temp++) { 879 scanDefinition(ins, *temp, /* isTemp = */ true); 880 } 881 for (LInstruction::OutputIter output(ins); !output.done(); output++) { 882 scanDefinition(ins, *output, /* isTemp = */ false); 883 } 884 885 // Allocate inputs which are required to be in non-fixed registers. 886 for (LInstruction::NonSnapshotInputIter alloc(*ins); alloc.more(); 887 alloc.next()) { 888 if (!alloc->isUse() || alloc->toUse()->policy() != LUse::REGISTER) { 889 continue; 890 } 891 AnyRegister reg; 892 if (!allocateForRegisterUse(ins, alloc->toUse(), ®)) { 893 return false; 894 } 895 alloc.replace(LAllocation(reg)); 896 } 897 898 // Allocate all definitions. 899 for (LInstruction::TempIter temp(ins); !temp.done(); temp++) { 900 if (!allocateForDefinition(blockLastId, ins, *temp, /* isTemp = */ true)) { 901 return false; 902 } 903 } 904 for (LInstruction::OutputIter output(ins); !output.done(); output++) { 905 LDefinition* def = *output; 906 if (!allocateForDefinition(blockLastId, ins, def, /* isTemp = */ false)) { 907 return false; 908 } 909 if (vregs_[def->virtualRegister()].isGCType()) { 910 if (!liveGC.insert(def->virtualRegister())) { 911 return false; 912 } 913 } 914 } 915 916 // If this instruction is a call, we need to evict all registers except for 917 // preserved registers or the instruction's definitions. We have to do this 918 // before the next step because call instructions are allowed to clobber 919 // their input registers so we shouldn't use the same register for snapshot 920 // inputs. 921 if (ins->isCall()) { 922 for (size_t i = 0; i < allocatedRegs_.length();) { 923 AllocatedRegister allocated = allocatedRegs_[i]; 924 if (ins->isCallPreserved(allocated.reg()) || 925 vregs_[allocated.vregId()].insId() == ins->id()) { 926 i++; 927 continue; 928 } 929 if (!spillRegister(ins, allocated)) { 930 return false; 931 } 932 removeAllocatedRegisterAtIndex(i); 933 } 934 } 935 936 // Allocate for remaining inputs which do not need to be in registers. 937 for (LInstruction::InputIter alloc(*ins); alloc.more(); alloc.next()) { 938 if (!alloc->isUse()) { 939 continue; 940 } 941 LUse* use = alloc->toUse(); 942 MOZ_ASSERT(use->policy() != LUse::REGISTER && use->policy() != LUse::FIXED); 943 uint32_t vreg = use->virtualRegister(); 944 // KEEPALIVE uses are very common in JS code for snapshots and these uses 945 // don't prefer a register. Don't update the register's last-use (used for 946 // eviction heuristics) for them. 947 bool trackRegUse = (use->policy() != LUse::KEEPALIVE); 948 LAllocation allocated = registerOrStackLocation(ins, vreg, trackRegUse); 949 alloc.replace(allocated); 950 } 951 952 // If this instruction had MUST_REUSE_INPUT definitions, we've now assigned a 953 // register or stack slot for the input and we allocated a register for the 954 // output. We can now insert a move and then rewrite the input LAllocation to 955 // match the LDefinition (code generation relies on this). 956 while (!reusedInputs_.empty()) { 957 auto entry = reusedInputs_.popCopy(); 958 LMoveGroup* input = getInputMoveGroup(ins); 959 if (!input->addAfter(*entry.source, LAllocation(entry.dest), entry.type)) { 960 return false; 961 } 962 *entry.source = LAllocation(entry.dest); 963 } 964 965 // Add registers and stack locations to the instruction's safepoint if needed. 966 if (LSafepoint* safepoint = ins->safepoint()) { 967 if (!populateSafepoint(liveGC, ins, safepoint)) { 968 return false; 969 } 970 } 971 972 // In the uncommon case where a vreg might have multiple allocated registers, 973 // discard the registers not linked from the vreg. This simplifies other parts 974 // of the allocator. 975 if (hasMultipleRegsForVreg_) { 976 for (size_t i = 0; i < allocatedRegs_.length();) { 977 VirtualRegister& vreg = vregs_[allocatedRegs_[i].vregId()]; 978 if (vreg.registerIndex() != i) { 979 removeAllocatedRegisterAtIndex(i); 980 continue; 981 } 982 i++; 983 } 984 hasMultipleRegsForVreg_ = false; 985 } 986 987 return true; 988 } 989 990 bool SimpleAllocator::addLiveRegisterToSafepoint(LSafepoint* safepoint, 991 AllocatedRegister allocated) { 992 safepoint->addLiveRegister(allocated.reg()); 993 const VirtualRegister& vreg = vregs_[allocated.vregId()]; 994 if (vreg.isGCType()) { 995 if (!safepoint->addGCAllocation(allocated.vregId(), vreg.def(), 996 LAllocation(allocated.reg()))) { 997 return false; 998 } 999 } 1000 return true; 1001 } 1002 1003 bool SimpleAllocator::populateSafepoint(VirtualRegBitSet& liveGC, 1004 LInstruction* ins, 1005 LSafepoint* safepoint) { 1006 // Add allocated registers to the safepoint. Safepoints for call instructions 1007 // never include any registers. 1008 if (!ins->isCall()) { 1009 for (AllocatedRegister allocated : allocatedRegs_) { 1010 // Outputs (but not temps) of the current instruction are ignored, except 1011 // for the clobberedRegs set that's used for debug assertions. 1012 const VirtualRegister& vreg = vregs_[allocated.vregId()]; 1013 if (vreg.insId() == ins->id()) { 1014 #ifdef CHECK_OSIPOINT_REGISTERS 1015 safepoint->addClobberedRegister(allocated.reg()); 1016 #endif 1017 if (!vreg.isTemp()) { 1018 continue; 1019 } 1020 } 1021 if (!addLiveRegisterToSafepoint(safepoint, allocated)) { 1022 return false; 1023 } 1024 } 1025 } 1026 1027 // Also add stack locations that store GC things. 1028 for (VirtualRegBitSet::Iterator liveRegId(liveGC); liveRegId; ++liveRegId) { 1029 uint32_t vregId = *liveRegId; 1030 const VirtualRegister& vreg = vregs_[vregId]; 1031 MOZ_ASSERT(vreg.isGCType()); 1032 if (!vreg.hasStackLocation() || vreg.insId() == ins->id()) { 1033 continue; 1034 } 1035 if (!safepoint->addGCAllocation(vregId, vreg.def(), vreg.stackLocation())) { 1036 return false; 1037 } 1038 } 1039 1040 return true; 1041 } 1042 1043 void SimpleAllocator::freeDeadVregsAfterInstruction(VirtualRegBitSet& liveGC, 1044 LNode* ins) { 1045 // Mark virtual registers that won't be used after `ins` as dead. This also 1046 // frees their stack slots and registers. 1047 while (!vregLastUses_.empty() && 1048 vregLastUses_.back().instructionId <= ins->id()) { 1049 VregLastUse entry = vregLastUses_.popCopy(); 1050 VirtualRegister& vreg = vregs_[entry.vregId]; 1051 if (vreg.hasRegister()) { 1052 removeAllocatedRegisterAtIndex(vreg.registerIndex()); 1053 } 1054 if (vreg.hasAllocatedStackSlot()) { 1055 LStackSlot::SlotAndWidth stackSlot = vreg.stackSlot(); 1056 stackSlotAllocator_.freeSlot(stackSlot.width(), stackSlot.slot()); 1057 } 1058 if (vreg.isGCType()) { 1059 liveGC.remove(entry.vregId); 1060 } 1061 vreg.markDead(); 1062 } 1063 } 1064 1065 bool SimpleAllocator::tryReuseRegistersFromPredecessor(MBasicBlock* block) { 1066 // Try to reuse the register state from our predecessor block if we have a 1067 // single predecessor. Note that this is completely optional because all live 1068 // vregs must have a stack location at this point. 1069 1070 if (block->numPredecessors() != 1) { 1071 return true; 1072 } 1073 1074 auto findBlockState = [this](uint32_t predId) -> const BlockState* { 1075 for (const BlockState& state : blockStates_) { 1076 if (state.blockIndex == predId) { 1077 return &state; 1078 } 1079 } 1080 return nullptr; 1081 }; 1082 const BlockState* state = findBlockState(block->getPredecessor(0)->id()); 1083 if (!state) { 1084 return true; 1085 } 1086 1087 MOZ_ASSERT(allocatedRegs_.empty()); 1088 availableRegs_ = state->availableRegs; 1089 for (AllocatedRegister allocated : state->allocatedRegs) { 1090 // Ignore registers for vregs that were marked dead between the 1091 // predecessor block and the current block. 1092 if (vregs_[allocated.vregId()].isDead()) { 1093 availableRegs_.add(allocated.reg()); 1094 } else { 1095 VirtualRegister& vreg = vregs_[allocated.vregId()]; 1096 MOZ_ASSERT(!vreg.hasRegister()); 1097 vreg.setRegisterIndex(allocatedRegs_.length()); 1098 if (!allocatedRegs_.append(allocated)) { 1099 return false; 1100 } 1101 } 1102 } 1103 return true; 1104 } 1105 1106 void SimpleAllocator::saveAndClearAllocatedRegisters(MBasicBlock* block) { 1107 if (allocatedRegs_.empty()) { 1108 return; 1109 } 1110 1111 for (AllocatedRegister allocated : allocatedRegs_) { 1112 vregs_[allocated.vregId()].clearRegisterIndex(); 1113 } 1114 1115 // Ensure at least one successor has a single predecessor block that could use 1116 // our register state later in tryReuseRegistersFromPredecessor. 1117 bool shouldSave = false; 1118 for (size_t i = 0; i < block->numSuccessors(); i++) { 1119 if (block->getSuccessor(i)->numPredecessors() == 1 && 1120 block->getSuccessor(i)->id() > block->id()) { 1121 shouldSave = true; 1122 break; 1123 } 1124 } 1125 if (shouldSave) { 1126 // Save current register state in the circular buffer. We use std::swap for 1127 // the vectors to try to reuse malloc buffers. 1128 BlockState& state = blockStates_[nextBlockStateIndex_]; 1129 std::swap(allocatedRegs_, state.allocatedRegs); 1130 state.availableRegs = availableRegs_; 1131 state.blockIndex = block->id(); 1132 nextBlockStateIndex_ = (nextBlockStateIndex_ + 1) % BlockStateLength; 1133 } 1134 allocatedRegs_.clear(); 1135 availableRegs_ = allRegisters_; 1136 } 1137 1138 bool SimpleAllocator::allocateRegisters() { 1139 // Initialize register state. 1140 MOZ_ASSERT(allocatedRegs_.empty()); 1141 availableRegs_ = allRegisters_; 1142 1143 size_t numBlocks = graph.numBlocks(); 1144 1145 // It's very common for JS code to have a basic block that jumps to the next 1146 // block and the next block doesn't have any other predecessors. We treat 1147 // such blocks as a single block. 1148 bool fuseWithNextBlock = false; 1149 1150 for (size_t blockIndex = 0; blockIndex < numBlocks; blockIndex++) { 1151 if (mir->shouldCancel("allocateRegisters (block loop)")) { 1152 return false; 1153 } 1154 1155 LBlock* block = graph.getBlock(blockIndex); 1156 MBasicBlock* mblock = block->mir(); 1157 MOZ_ASSERT(mblock->id() == blockIndex); 1158 1159 VirtualRegBitSet& liveGC = liveGCIn_[blockIndex]; 1160 1161 // Try to reuse the register state from our predecessor. If we fused this 1162 // block with the previous block we're already using its register state. 1163 if (!fuseWithNextBlock) { 1164 MOZ_ASSERT(allocatedRegs_.empty()); 1165 if (!tryReuseRegistersFromPredecessor(mblock)) { 1166 return false; 1167 } 1168 } 1169 1170 // Note: sometimes two blocks appear fusable but the successor block still 1171 // has an (unnecessary) phi. Don't fuse in this edge case. 1172 fuseWithNextBlock = mblock->numSuccessors() == 1 && 1173 mblock->getSuccessor(0)->id() == blockIndex + 1 && 1174 mblock->getSuccessor(0)->numPredecessors() == 1 && 1175 graph.getBlock(blockIndex + 1)->numPhis() == 0; 1176 1177 uint32_t blockLastId = fuseWithNextBlock 1178 ? graph.getBlock(blockIndex + 1)->lastId() 1179 : block->lastId(); 1180 1181 // Allocate stack slots for phis. 1182 for (uint32_t i = 0, numPhis = block->numPhis(); i < numPhis; i++) { 1183 LPhi* phi = block->getPhi(i); 1184 LDefinition* def = phi->getDef(0); 1185 uint32_t vregId = def->virtualRegister(); 1186 bool isGCType = vregs_[vregId].isGCType(); 1187 def->setOutput(ensureStackLocation(vregId)); 1188 if (isGCType && !liveGC.insert(vregId)) { 1189 return false; 1190 } 1191 if (i == numPhis - 1) { 1192 freeDeadVregsAfterInstruction(liveGC, phi); 1193 } 1194 } 1195 1196 // Allocate registers for each instruction. 1197 for (LInstructionIterator iter = block->begin(); iter != block->end(); 1198 iter++) { 1199 if (mir->shouldCancel("allocateRegisters (instruction loop)")) { 1200 return false; 1201 } 1202 1203 LInstruction* ins = *iter; 1204 if (!allocateForInstruction(liveGC, blockLastId, ins)) { 1205 return false; 1206 } 1207 if (ins == *block->rbegin() && !fuseWithNextBlock) { 1208 if (!allocateForBlockEnd(block, ins)) { 1209 return false; 1210 } 1211 } 1212 freeDeadVregsAfterInstruction(liveGC, ins); 1213 } 1214 1215 if (!fuseWithNextBlock) { 1216 saveAndClearAllocatedRegisters(mblock); 1217 } 1218 } 1219 1220 // All vregs must now be dead. 1221 MOZ_ASSERT(vregLastUses_.empty()); 1222 #ifdef DEBUG 1223 for (size_t i = 1; i < vregs_.length(); i++) { 1224 MOZ_ASSERT(vregs_[i].isDead()); 1225 } 1226 #endif 1227 1228 graph.setLocalSlotsSize(stackSlotAllocator_.stackHeight()); 1229 return true; 1230 } 1231 1232 void SimpleAllocator::assertValidRegisterStateBeforeInstruction() const { 1233 #ifdef DEBUG 1234 MOZ_ASSERT(!hasMultipleRegsForVreg_); 1235 1236 // Assert allocatedRegs_ does not contain duplicate registers and matches the 1237 // availableRegs_ set. 1238 AllocatableRegisterSet available = allRegisters_; 1239 for (size_t i = 0; i < allocatedRegs_.length(); i++) { 1240 AllocatedRegister allocated = allocatedRegs_[i]; 1241 available.take(allocated.reg()); 1242 const VirtualRegister& vreg = vregs_[allocated.vregId()]; 1243 MOZ_ASSERT(vreg.registerIndex() == i); 1244 MOZ_ASSERT(!vreg.isTemp()); 1245 } 1246 MOZ_ASSERT(availableRegs_.set() == available.set()); 1247 1248 // Assert vregs have a valid register index. Limit this to the first 20 vregs 1249 // to not slow down debug builds too much. 1250 size_t numVregsToCheck = std::min<size_t>(20, vregs_.length()); 1251 for (size_t i = 1; i < numVregsToCheck; i++) { 1252 if (!vregs_[i].isDead() && vregs_[i].hasRegister()) { 1253 size_t index = vregs_[i].registerIndex(); 1254 MOZ_ASSERT(allocatedRegs_[index].vregId() == i); 1255 } 1256 } 1257 #endif 1258 } 1259 1260 bool SimpleAllocator::go() { 1261 JitSpewCont(JitSpew_RegAlloc, "\n"); 1262 JitSpew(JitSpew_RegAlloc, "Beginning register allocation"); 1263 1264 JitSpewCont(JitSpew_RegAlloc, "\n"); 1265 if (JitSpewEnabled(JitSpew_RegAlloc)) { 1266 dumpInstructions("(Pre-allocation LIR)"); 1267 } 1268 1269 if (!init()) { 1270 return false; 1271 } 1272 if (!analyzeLiveness()) { 1273 return false; 1274 } 1275 if (!allocateRegisters()) { 1276 return false; 1277 } 1278 return true; 1279 }