/// Allocates a physical register for VirtReg. void RegAllocFast::allocVirtReg(MachineInstr &MI, LiveReg &LR, unsigned Hint) { const unsigned VirtReg = LR.VirtReg; assert(TargetRegisterInfo::isVirtualRegister(VirtReg) && "Can only allocate virtual registers"); const TargetRegisterClass &RC = *MRI->getRegClass(VirtReg); LLVM_DEBUG(dbgs() << "Search register for " << printReg(VirtReg) << " in class " << TRI->getRegClassName(&RC) << " with hint " << printReg(Hint, TRI) << '\n'); // Take hint when possible. if (TargetRegisterInfo::isPhysicalRegister(Hint) && MRI->isAllocatable(Hint) && RC.contains(Hint)) { // Ignore the hint if we would have to spill a dirty register. unsigned Cost = calcSpillCost(Hint); if (Cost < spillDirty) { if (Cost) definePhysReg(MI, Hint, regFree); assignVirtToPhysReg(LR, Hint); return; } } MCPhysReg BestReg = 0; unsigned BestCost = spillImpossible; ArrayRef<MCPhysReg> AllocationOrder = RegClassInfo.getOrder(&RC); for (MCPhysReg PhysReg : AllocationOrder) { LLVM_DEBUG(dbgs() << "\tRegister: " << printReg(PhysReg, TRI) << ' '); unsigned Cost = calcSpillCost(PhysReg); LLVM_DEBUG(dbgs() << "Cost: " << Cost << " BestCost: " << BestCost << '\n'); // Immediate take a register with cost 0. if (Cost == 0) { assignVirtToPhysReg(LR, PhysReg); return; } if (Cost < BestCost) { BestReg = PhysReg; BestCost = Cost; } } if (!BestReg) { // Nothing we can do: Report an error and keep going with an invalid // allocation. if (MI.isInlineAsm()) MI.emitError("inline assembly requires more registers than available"); else MI.emitError("ran out of registers during register allocation"); definePhysReg(MI, *AllocationOrder.begin(), regFree); assignVirtToPhysReg(LR, *AllocationOrder.begin()); return; } definePhysReg(MI, BestReg, regFree); assignVirtToPhysReg(LR, BestReg); }
void ARMAsmPrinter::EmitSled(const MachineInstr &MI, SledKind Kind) { if (MI.getParent()->getParent()->getInfo<ARMFunctionInfo>() ->isThumbFunction()) { MI.emitError("An attempt to perform XRay instrumentation for a" " Thumb function (not supported). Detected when emitting a sled."); return; } static const int8_t NoopsInSledCount = 6; // We want to emit the following pattern: // // .Lxray_sled_N: // ALIGN // B #20 // ; 6 NOP instructions (24 bytes) // .tmpN // // We need the 24 bytes (6 instructions) because at runtime, we'd be patching // over the full 28 bytes (7 instructions) with the following pattern: // // PUSH{ r0, lr } // MOVW r0, #<lower 16 bits of function ID> // MOVT r0, #<higher 16 bits of function ID> // MOVW ip, #<lower 16 bits of address of __xray_FunctionEntry/Exit> // MOVT ip, #<higher 16 bits of address of __xray_FunctionEntry/Exit> // BLX ip // POP{ r0, lr } // OutStreamer->EmitCodeAlignment(4); auto CurSled = OutContext.createTempSymbol("xray_sled_", true); OutStreamer->EmitLabel(CurSled); auto Target = OutContext.createTempSymbol(); // Emit "B #20" instruction, which jumps over the next 24 bytes (because // register pc is 8 bytes ahead of the jump instruction by the moment CPU // is executing it). // By analogy to ARMAsmPrinter::emitPseudoExpansionLowering() |case ARM::B|. // It is not clear why |addReg(0)| is needed (the last operand). EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::Bcc).addImm(20) .addImm(ARMCC::AL).addReg(0)); MCInst Noop; Subtarget->getInstrInfo()->getNoopForElfTarget(Noop); for (int8_t I = 0; I < NoopsInSledCount; I++) { OutStreamer->EmitInstruction(Noop, getSubtargetInfo()); } OutStreamer->EmitLabel(Target); recordSled(CurSled, MI, Kind); }
// Top-level driver to manage the queue of unassigned VirtRegs and call the // selectOrSplit implementation. void RegAllocBase::allocatePhysRegs() { seedLiveRegs(); // Continue assigning vregs one at a time to available physical registers. while (LiveInterval *VirtReg = dequeue()) { assert(!VRM->hasPhys(VirtReg->reg) && "Register already assigned"); // Unused registers can appear when the spiller coalesces snippets. if (MRI->reg_nodbg_empty(VirtReg->reg)) { DEBUG(dbgs() << "Dropping unused " << *VirtReg << '\n'); LIS->removeInterval(VirtReg->reg); continue; } // Invalidate all interference queries, live ranges could have changed. invalidateVirtRegs(); // selectOrSplit requests the allocator to return an available physical // register if possible and populate a list of new live intervals that // result from splitting. DEBUG(dbgs() << "\nselectOrSplit " << MRI->getRegClass(VirtReg->reg)->getName() << ':' << *VirtReg << '\n'); typedef SmallVector<LiveInterval*, 4> VirtRegVec; VirtRegVec SplitVRegs; unsigned AvailablePhysReg = selectOrSplit(*VirtReg, SplitVRegs); if (AvailablePhysReg == ~0u) { // selectOrSplit failed to find a register! const char *Msg = "ran out of registers during register allocation"; // Probably caused by an inline asm. MachineInstr *MI; for (MachineRegisterInfo::reg_iterator I = MRI->reg_begin(VirtReg->reg); (MI = I.skipInstruction());) if (MI->isInlineAsm()) break; if (MI) MI->emitError(Msg); else report_fatal_error(Msg); // Keep going after reporting the error. VRM->assignVirt2Phys(VirtReg->reg, RegClassInfo.getOrder(MRI->getRegClass(VirtReg->reg)).front()); continue; } if (AvailablePhysReg) assign(*VirtReg, AvailablePhysReg); for (VirtRegVec::iterator I = SplitVRegs.begin(), E = SplitVRegs.end(); I != E; ++I) { LiveInterval *SplitVirtReg = *I; assert(!VRM->hasPhys(SplitVirtReg->reg) && "Register already assigned"); if (MRI->reg_nodbg_empty(SplitVirtReg->reg)) { DEBUG(dbgs() << "not queueing unused " << *SplitVirtReg << '\n'); LIS->removeInterval(SplitVirtReg->reg); continue; } DEBUG(dbgs() << "queuing new interval: " << *SplitVirtReg << "\n"); assert(TargetRegisterInfo::isVirtualRegister(SplitVirtReg->reg) && "expect split value in virtual register"); enqueue(SplitVirtReg); ++NumNewQueued; } } }