void StupidAllocator::syncForBlockEnd(LBlock *block, LInstruction *ins) { // Sync any dirty registers, and update the synced state for phi nodes at // each successor of a block. We cannot conflate the storage for phis with // that of their inputs, as we cannot prove the live ranges of the phi and // its input do not overlap. The values for the two may additionally be // different, as the phi could be for the value of the input in a previous // loop iteration. for (size_t i = 0; i < registerCount; i++) syncRegister(ins, i); LMoveGroup *group = nullptr; MBasicBlock *successor = block->mir()->successorWithPhis(); if (successor) { uint32_t position = block->mir()->positionInPhiSuccessor(); LBlock *lirsuccessor = successor->lir(); for (size_t i = 0; i < lirsuccessor->numPhis(); i++) { LPhi *phi = lirsuccessor->getPhi(i); uint32_t sourcevreg = phi->getOperand(position)->toUse()->virtualRegister(); uint32_t destvreg = phi->getDef(0)->virtualRegister(); if (sourcevreg == destvreg) continue; LAllocation *source = stackLocation(sourcevreg); LAllocation *dest = stackLocation(destvreg); if (!group) { // The moves we insert here need to happen simultaneously with // each other, yet after any existing moves before the instruction. LMoveGroup *input = getInputMoveGroup(ins->id()); if (input->numMoves() == 0) { group = input; } else { group = LMoveGroup::New(alloc()); block->insertAfter(input, group); } } group->add(source, dest, phi->getDef(0)->type()); } } }
bool LiveRangeAllocator<VREG>::init() { if (!RegisterAllocator::init()) return false; liveIn = lir->mir()->allocate<BitSet*>(graph.numBlockIds()); if (!liveIn) return false; // Initialize fixed intervals. for (size_t i = 0; i < AnyRegister::Total; i++) { AnyRegister reg = AnyRegister::FromCode(i); LiveInterval *interval = new LiveInterval(0); interval->setAllocation(LAllocation(reg)); fixedIntervals[i] = interval; } fixedIntervalsUnion = new LiveInterval(0); if (!vregs.init(lir->mir(), graph.numVirtualRegisters())) return false; // Build virtual register objects for (size_t i = 0; i < graph.numBlocks(); i++) { if (mir->shouldCancel("LSRA create data structures (main loop)")) return false; LBlock *block = graph.getBlock(i); for (LInstructionIterator ins = block->begin(); ins != block->end(); ins++) { for (size_t j = 0; j < ins->numDefs(); j++) { LDefinition *def = ins->getDef(j); if (def->policy() != LDefinition::PASSTHROUGH) { uint32_t reg = def->virtualRegister(); if (!vregs[reg].init(reg, block, *ins, def, /* isTemp */ false)) return false; } } for (size_t j = 0; j < ins->numTemps(); j++) { LDefinition *def = ins->getTemp(j); if (def->isBogusTemp()) continue; if (!vregs[def].init(def->virtualRegister(), block, *ins, def, /* isTemp */ true)) return false; } } for (size_t j = 0; j < block->numPhis(); j++) { LPhi *phi = block->getPhi(j); LDefinition *def = phi->getDef(0); if (!vregs[def].init(phi->id(), block, phi, def, /* isTemp */ false)) return false; } } return true; }
bool StupidAllocator::init() { if (!RegisterAllocator::init()) return false; if (!virtualRegisters.reserve(graph.numVirtualRegisters())) return false; for (size_t i = 0; i < graph.numVirtualRegisters(); i++) virtualRegisters.infallibleAppend(NULL); for (size_t i = 0; i < graph.numBlocks(); i++) { LBlock *block = graph.getBlock(i); for (LInstructionIterator ins = block->begin(); ins != block->end(); ins++) { for (size_t j = 0; j < ins->numDefs(); j++) { LDefinition *def = ins->getDef(j); if (def->policy() != LDefinition::PASSTHROUGH) virtualRegisters[def->virtualRegister()] = def; } for (size_t j = 0; j < ins->numTemps(); j++) { LDefinition *def = ins->getTemp(j); if (def->isBogusTemp()) continue; virtualRegisters[def->virtualRegister()] = def; } } for (size_t j = 0; j < block->numPhis(); j++) { LPhi *phi = block->getPhi(j); LDefinition *def = phi->getDef(0); uint32 vreg = def->virtualRegister(); virtualRegisters[vreg] = def; } } // Assign physical registers to the tracked allocation. { registerCount = 0; RegisterSet remainingRegisters(allRegisters_); while (!remainingRegisters.empty(/* float = */ false)) registers[registerCount++].reg = AnyRegister(remainingRegisters.takeGeneral()); while (!remainingRegisters.empty(/* float = */ true)) registers[registerCount++].reg = AnyRegister(remainingRegisters.takeFloat()); JS_ASSERT(registerCount <= MAX_REGISTERS); } return true; }
bool StupidAllocator::init() { if (!RegisterAllocator::init()) return false; if (!virtualRegisters.appendN((LDefinition*)nullptr, graph.numVirtualRegisters())) return false; for (size_t i = 0; i < graph.numBlocks(); i++) { LBlock* block = graph.getBlock(i); for (LInstructionIterator ins = block->begin(); ins != block->end(); ins++) { for (size_t j = 0; j < ins->numDefs(); j++) { LDefinition* def = ins->getDef(j); virtualRegisters[def->virtualRegister()] = def; } for (size_t j = 0; j < ins->numTemps(); j++) { LDefinition* def = ins->getTemp(j); if (def->isBogusTemp()) continue; virtualRegisters[def->virtualRegister()] = def; } } for (size_t j = 0; j < block->numPhis(); j++) { LPhi* phi = block->getPhi(j); LDefinition* def = phi->getDef(0); uint32_t vreg = def->virtualRegister(); virtualRegisters[vreg] = def; } } // Assign physical registers to the tracked allocation. { registerCount = 0; LiveRegisterSet remainingRegisters(allRegisters_.asLiveSet()); while (!remainingRegisters.emptyGeneral()) registers[registerCount++].reg = AnyRegister(remainingRegisters.takeAnyGeneral()); while (!remainingRegisters.emptyFloat()) registers[registerCount++].reg = AnyRegister(remainingRegisters.takeAnyFloat()); MOZ_ASSERT(registerCount <= MAX_REGISTERS); } return true; }
bool GreedyAllocator::buildPhiMoves(LBlock *block) { IonSpew(IonSpew_RegAlloc, " Merging phi state."); phiMoves = Mover(); MBasicBlock *mblock = block->mir(); if (!mblock->successorWithPhis()) return true; // Insert moves from our state into our successor's phi. uint32 pos = mblock->positionInPhiSuccessor(); LBlock *successor = mblock->successorWithPhis()->lir(); for (size_t i = 0; i < successor->numPhis(); i++) { LPhi *phi = successor->getPhi(i); JS_ASSERT(phi->numDefs() == 1); VirtualRegister *phiReg = getVirtualRegister(phi->getDef(0)); allocateStack(phiReg); LAllocation *in = phi->getOperand(pos); VirtualRegister *inReg = getVirtualRegister(in->toUse()); allocateStack(inReg); // Try to get a register for the input. if (!inReg->hasRegister() && !allocatableRegs().empty(inReg->isDouble())) { if (!allocateReg(inReg)) return false; } // Add a move from the input to the phi. if (inReg->hasRegister()) { if (!phiMoves.move(inReg->reg(), phiReg->backingStack())) return false; } else { if (!phiMoves.move(inReg->backingStack(), phiReg->backingStack())) return false; } } return true; }
void RegisterAllocator::dumpInstructions() { #ifdef DEBUG fprintf(stderr, "Instructions:\n"); for (size_t blockIndex = 0; blockIndex < graph.numBlocks(); blockIndex++) { LBlock* block = graph.getBlock(blockIndex); MBasicBlock* mir = block->mir(); fprintf(stderr, "\nBlock %lu", static_cast<unsigned long>(blockIndex)); for (size_t i = 0; i < mir->numSuccessors(); i++) fprintf(stderr, " [successor %u]", mir->getSuccessor(i)->id()); fprintf(stderr, "\n"); for (size_t i = 0; i < block->numPhis(); i++) { LPhi* phi = block->getPhi(i); fprintf(stderr, "[%u,%u Phi] [def %s]", inputOf(phi).bits(), outputOf(phi).bits(), phi->getDef(0)->toString()); for (size_t j = 0; j < phi->numOperands(); j++) fprintf(stderr, " [use %s]", phi->getOperand(j)->toString()); fprintf(stderr, "\n"); } for (LInstructionIterator iter = block->begin(); iter != block->end(); iter++) { LInstruction* ins = *iter; fprintf(stderr, "["); if (ins->id() != 0) fprintf(stderr, "%u,%u ", inputOf(ins).bits(), outputOf(ins).bits()); fprintf(stderr, "%s]", ins->opName()); if (ins->isMoveGroup()) { LMoveGroup* group = ins->toMoveGroup(); for (int i = group->numMoves() - 1; i >= 0; i--) { // Use two printfs, as LAllocation::toString is not reentant. fprintf(stderr, " [%s", group->getMove(i).from()->toString()); fprintf(stderr, " -> %s]", group->getMove(i).to()->toString()); } fprintf(stderr, "\n"); continue; } for (size_t i = 0; i < ins->numDefs(); i++) fprintf(stderr, " [def %s]", ins->getDef(i)->toString()); for (size_t i = 0; i < ins->numTemps(); i++) { LDefinition* temp = ins->getTemp(i); if (!temp->isBogusTemp()) fprintf(stderr, " [temp %s]", temp->toString()); } for (LInstruction::InputIterator alloc(*ins); alloc.more(); alloc.next()) { if (!alloc->isBogus()) fprintf(stderr, " [use %s]", alloc->toString()); } fprintf(stderr, "\n"); } } fprintf(stderr, "\n"); #endif // DEBUG }
void AllocationIntegrityState::dump() { #ifdef DEBUG fprintf(stderr, "Register Allocation Integrity State:\n"); for (size_t blockIndex = 0; blockIndex < graph.numBlocks(); blockIndex++) { LBlock* block = graph.getBlock(blockIndex); MBasicBlock* mir = block->mir(); fprintf(stderr, "\nBlock %lu", static_cast<unsigned long>(blockIndex)); for (size_t i = 0; i < mir->numSuccessors(); i++) fprintf(stderr, " [successor %u]", mir->getSuccessor(i)->id()); fprintf(stderr, "\n"); for (size_t i = 0; i < block->numPhis(); i++) { const InstructionInfo& info = blocks[blockIndex].phis[i]; LPhi* phi = block->getPhi(i); CodePosition input(block->getPhi(0)->id(), CodePosition::INPUT); CodePosition output(block->getPhi(block->numPhis() - 1)->id(), CodePosition::OUTPUT); fprintf(stderr, "[%u,%u Phi] [def %s] ", input.bits(), output.bits(), phi->getDef(0)->toString()); for (size_t j = 0; j < phi->numOperands(); j++) fprintf(stderr, " [use %s]", info.inputs[j].toString()); fprintf(stderr, "\n"); } for (LInstructionIterator iter = block->begin(); iter != block->end(); iter++) { LInstruction* ins = *iter; const InstructionInfo& info = instructions[ins->id()]; CodePosition input(ins->id(), CodePosition::INPUT); CodePosition output(ins->id(), CodePosition::OUTPUT); fprintf(stderr, "["); if (input != CodePosition::MIN) fprintf(stderr, "%u,%u ", input.bits(), output.bits()); fprintf(stderr, "%s]", ins->opName()); if (ins->isMoveGroup()) { LMoveGroup* group = ins->toMoveGroup(); for (int i = group->numMoves() - 1; i >= 0; i--) { // Use two printfs, as LAllocation::toString is not reentrant. fprintf(stderr, " [%s", group->getMove(i).from()->toString()); fprintf(stderr, " -> %s]", group->getMove(i).to()->toString()); } fprintf(stderr, "\n"); continue; } for (size_t i = 0; i < ins->numDefs(); i++) fprintf(stderr, " [def %s]", ins->getDef(i)->toString()); for (size_t i = 0; i < ins->numTemps(); i++) { LDefinition* temp = ins->getTemp(i); if (!temp->isBogusTemp()) fprintf(stderr, " [temp v%u %s]", info.temps[i].virtualRegister(), temp->toString()); } size_t index = 0; for (LInstruction::InputIterator alloc(*ins); alloc.more(); alloc.next()) { fprintf(stderr, " [use %s", info.inputs[index++].toString()); if (!alloc->isConstant()) fprintf(stderr, " %s", alloc->toString()); fprintf(stderr, "]"); } fprintf(stderr, "\n"); } } // Print discovered allocations at the ends of blocks, in the order they // were discovered. Vector<IntegrityItem, 20, SystemAllocPolicy> seenOrdered; seenOrdered.appendN(IntegrityItem(), seen.count()); for (IntegrityItemSet::Enum iter(seen); !iter.empty(); iter.popFront()) { IntegrityItem item = iter.front(); seenOrdered[item.index] = item; } if (!seenOrdered.empty()) { fprintf(stderr, "Intermediate Allocations:\n"); for (size_t i = 0; i < seenOrdered.length(); i++) { IntegrityItem item = seenOrdered[i]; fprintf(stderr, " block %u reg v%u alloc %s\n", item.block->mir()->id(), item.vreg, item.alloc.toString()); } } fprintf(stderr, "\n"); #endif }
bool AllocationIntegrityState::record() { // Ignore repeated record() calls. if (!instructions.empty()) return true; if (!instructions.appendN(InstructionInfo(), graph.numInstructions())) return false; if (!virtualRegisters.appendN((LDefinition*)nullptr, graph.numVirtualRegisters())) return false; if (!blocks.reserve(graph.numBlocks())) return false; for (size_t i = 0; i < graph.numBlocks(); i++) { blocks.infallibleAppend(BlockInfo()); LBlock* block = graph.getBlock(i); MOZ_ASSERT(block->mir()->id() == i); BlockInfo& blockInfo = blocks[i]; if (!blockInfo.phis.reserve(block->numPhis())) return false; for (size_t j = 0; j < block->numPhis(); j++) { blockInfo.phis.infallibleAppend(InstructionInfo()); InstructionInfo& info = blockInfo.phis[j]; LPhi* phi = block->getPhi(j); MOZ_ASSERT(phi->numDefs() == 1); uint32_t vreg = phi->getDef(0)->virtualRegister(); virtualRegisters[vreg] = phi->getDef(0); if (!info.outputs.append(*phi->getDef(0))) return false; for (size_t k = 0, kend = phi->numOperands(); k < kend; k++) { if (!info.inputs.append(*phi->getOperand(k))) return false; } } for (LInstructionIterator iter = block->begin(); iter != block->end(); iter++) { LInstruction* ins = *iter; InstructionInfo& info = instructions[ins->id()]; for (size_t k = 0; k < ins->numTemps(); k++) { if (!ins->getTemp(k)->isBogusTemp()) { uint32_t vreg = ins->getTemp(k)->virtualRegister(); virtualRegisters[vreg] = ins->getTemp(k); } if (!info.temps.append(*ins->getTemp(k))) return false; } for (size_t k = 0; k < ins->numDefs(); k++) { if (!ins->getDef(k)->isBogusTemp()) { uint32_t vreg = ins->getDef(k)->virtualRegister(); virtualRegisters[vreg] = ins->getDef(k); } if (!info.outputs.append(*ins->getDef(k))) return false; } for (LInstruction::InputIterator alloc(*ins); alloc.more(); alloc.next()) { if (!info.inputs.append(**alloc)) return false; } } } return seen.init(); }
bool GreedyAllocator::allocateRegisters() { // Allocate registers bottom-up, such that we see all uses before their // definitions. for (size_t i = graph.numBlocks() - 1; i < graph.numBlocks(); i--) { LBlock *block = graph.getBlock(i); IonSpew(IonSpew_RegAlloc, "Allocating block %d", (uint32)i); // All registers should be free. JS_ASSERT(state.free == RegisterSet::All()); // Allocate stack for any phis. for (size_t j = 0; j < block->numPhis(); j++) { LPhi *phi = block->getPhi(j); VirtualRegister *vreg = getVirtualRegister(phi->getDef(0)); allocateStack(vreg); } // Allocate registers. if (!allocateRegistersInBlock(block)) return false; LMoveGroup *entrySpills = block->getEntryMoveGroup(); // We've reached the top of the block. Spill all registers by inserting // moves from their stack locations. for (AnyRegisterIterator iter(RegisterSet::All()); iter.more(); iter++) { VirtualRegister *vreg = state[*iter]; if (!vreg) { JS_ASSERT(state.free.has(*iter)); continue; } JS_ASSERT(vreg->reg() == *iter); JS_ASSERT(!state.free.has(vreg->reg())); allocateStack(vreg); LAllocation *from = LAllocation::New(vreg->backingStack()); LAllocation *to = LAllocation::New(vreg->reg()); if (!entrySpills->add(from, to)) return false; killReg(vreg); vreg->unsetRegister(); } // Before killing phis, ensure that each phi input has its own stack // allocation. This ensures we won't allocate the same slot for any phi // as its input, which technically may be legal (since the phi becomes // the last use of the slot), but we avoid for sanity. for (size_t i = 0; i < block->numPhis(); i++) { LPhi *phi = block->getPhi(i); for (size_t j = 0; j < phi->numOperands(); j++) { VirtualRegister *in = getVirtualRegister(phi->getOperand(j)->toUse()); allocateStack(in); } } // Kill phis. for (size_t i = 0; i < block->numPhis(); i++) { LPhi *phi = block->getPhi(i); VirtualRegister *vr = getVirtualRegister(phi->getDef(0)); JS_ASSERT(!vr->hasRegister()); killStack(vr); } } return true; }