IteratedRegisterCoalescingAllocator(Code& code, const HashSet<Tmp>& unspillableTmp) : m_unspillableTmp(unspillableTmp) , m_numberOfRegisters(regsInPriorityOrder(type).size()) { initializeDegrees(code); unsigned tmpArraySize = this->tmpArraySize(code); m_adjacencyList.resize(tmpArraySize); m_moveList.resize(tmpArraySize); m_coalescedTmps.resize(tmpArraySize); m_isOnSelectStack.ensureSize(tmpArraySize); }
Reg allocatedReg(Tmp tmp) const { ASSERT(!tmp.isReg()); ASSERT(m_coloredTmp.size()); ASSERT(tmp.isGP() == (type == Arg::GP)); Reg reg = m_coloredTmp[AbsoluteTmpMapper<type>::absoluteIndex(tmp)]; if (!reg) { // We only care about Tmps that interfere. A Tmp that never interfere with anything // can take any register. reg = regsInPriorityOrder(type).first(); } return reg; }
void spillEverything(Code& code) { PhaseScope phaseScope(code, "spillEverything"); // We want to know the set of registers used at every point in every basic block. IndexMap<BasicBlock, Vector<RegisterSet>> usedRegisters(code.size()); GPLiveness gpLiveness(code); FPLiveness fpLiveness(code); for (BasicBlock* block : code) { GPLiveness::LocalCalc gpLocalCalc(gpLiveness, block); FPLiveness::LocalCalc fpLocalCalc(fpLiveness, block); usedRegisters[block].resize(block->size() + 1); auto setUsedRegisters = [&] (unsigned index) { RegisterSet& registerSet = usedRegisters[block][index]; for (Tmp tmp : gpLocalCalc.live()) { if (tmp.isReg()) registerSet.set(tmp.reg()); } for (Tmp tmp : fpLocalCalc.live()) { if (tmp.isReg()) registerSet.set(tmp.reg()); } // Gotta account for dead assignments to registers. These may happen because the input // code is suboptimal. Inst::forEachDefWithExtraClobberedRegs<Tmp>( block->get(index - 1), block->get(index), [&] (const Tmp& tmp, Arg::Role, Arg::Type, Arg::Width) { if (tmp.isReg()) registerSet.set(tmp.reg()); }); }; for (unsigned instIndex = block->size(); instIndex--;) { setUsedRegisters(instIndex + 1); gpLocalCalc.execute(instIndex); fpLocalCalc.execute(instIndex); } setUsedRegisters(0); } // Allocate a stack slot for each tmp. Vector<StackSlot*> allStackSlots[Arg::numTypes]; for (unsigned typeIndex = 0; typeIndex < Arg::numTypes; ++typeIndex) { Vector<StackSlot*>& stackSlots = allStackSlots[typeIndex]; Arg::Type type = static_cast<Arg::Type>(typeIndex); stackSlots.resize(code.numTmps(type)); for (unsigned tmpIndex = code.numTmps(type); tmpIndex--;) stackSlots[tmpIndex] = code.addStackSlot(8, StackSlotKind::Anonymous); } InsertionSet insertionSet(code); for (BasicBlock* block : code) { for (unsigned instIndex = 0; instIndex < block->size(); ++instIndex) { RegisterSet& setBefore = usedRegisters[block][instIndex]; RegisterSet& setAfter = usedRegisters[block][instIndex + 1]; Inst& inst = block->at(instIndex); // First try to spill directly. for (unsigned i = 0; i < inst.args.size(); ++i) { Arg& arg = inst.args[i]; if (arg.isTmp()) { if (arg.isReg()) continue; if (inst.admitsStack(i)) { StackSlot* stackSlot = allStackSlots[arg.type()][arg.tmpIndex()]; arg = Arg::stack(stackSlot); continue; } } } // Now fall back on spilling using separate Move's to load/store the tmp. inst.forEachTmp( [&] (Tmp& tmp, Arg::Role role, Arg::Type type, Arg::Width) { if (tmp.isReg()) return; StackSlot* stackSlot = allStackSlots[type][tmp.tmpIndex()]; Arg arg = Arg::stack(stackSlot); // Need to figure out a register to use. How we do that depends on the role. Reg chosenReg; switch (role) { case Arg::Use: case Arg::ColdUse: for (Reg reg : regsInPriorityOrder(type)) { if (!setBefore.get(reg)) { setBefore.set(reg); chosenReg = reg; break; } } break; case Arg::Def: case Arg::ZDef: for (Reg reg : regsInPriorityOrder(type)) { if (!setAfter.get(reg)) { setAfter.set(reg); chosenReg = reg; break; } } break; case Arg::UseDef: case Arg::UseZDef: case Arg::LateUse: case Arg::LateColdUse: case Arg::Scratch: case Arg::EarlyDef: for (Reg reg : regsInPriorityOrder(type)) { if (!setBefore.get(reg) && !setAfter.get(reg)) { setAfter.set(reg); setBefore.set(reg); chosenReg = reg; break; } } break; case Arg::UseAddr: // We will never UseAddr a Tmp, that doesn't make sense. RELEASE_ASSERT_NOT_REACHED(); break; } RELEASE_ASSERT(chosenReg); tmp = Tmp(chosenReg); Opcode move = type == Arg::GP ? Move : MoveDouble; if (Arg::isAnyUse(role) && role != Arg::Scratch) insertionSet.insert(instIndex, move, inst.origin, arg, tmp); if (Arg::isAnyDef(role)) insertionSet.insert(instIndex + 1, move, inst.origin, tmp, arg); }); } insertionSet.execute(block); } }
void spillEverything(Code& code) { PhaseScope phaseScope(code, "spillEverything"); // We want to know the set of registers used at every point in every basic block. IndexMap<BasicBlock, Vector<RegisterSet>> usedRegisters(code.size()); Liveness<Tmp> liveness(code); for (BasicBlock* block : code) { Liveness<Tmp>::LocalCalc localCalc(liveness, block); usedRegisters[block].resize(block->size() + 1); auto setUsedRegisters = [&] (unsigned index, Inst& inst) { RegisterSet& registerSet = usedRegisters[block][index]; for (Tmp tmp : localCalc.live()) { if (tmp.isReg()) registerSet.set(tmp.reg()); } // Gotta account for dead assignments to registers. These may happen because the input // code is suboptimal. inst.forEachArg( [&] (Arg& arg, Arg::Role role, Arg::Type) { if (Arg::isDef(role) && arg.isReg()) registerSet.set(arg.reg()); }); }; for (unsigned instIndex = block->size(); instIndex--;) { Inst& inst = block->at(instIndex); setUsedRegisters(instIndex + 1, inst); localCalc.execute(inst); } Inst nop; setUsedRegisters(0, nop); } // Allocate a stack slot for each tmp. Vector<StackSlot*> allStackSlots[Arg::numTypes]; for (unsigned typeIndex = 0; typeIndex < Arg::numTypes; ++typeIndex) { Vector<StackSlot*>& stackSlots = allStackSlots[typeIndex]; Arg::Type type = static_cast<Arg::Type>(typeIndex); stackSlots.resize(code.numTmps(type)); for (unsigned tmpIndex = code.numTmps(type); tmpIndex--;) stackSlots[tmpIndex] = code.addStackSlot(8, StackSlotKind::Anonymous); } InsertionSet insertionSet(code); for (BasicBlock* block : code) { for (unsigned instIndex = 0; instIndex < block->size(); ++instIndex) { RegisterSet& setBefore = usedRegisters[block][instIndex]; RegisterSet& setAfter = usedRegisters[block][instIndex + 1]; Inst& inst = block->at(instIndex); inst.forEachTmp( [&] (Tmp& tmp, Arg::Role role, Arg::Type type) { if (tmp.isReg()) return; StackSlot* stackSlot = allStackSlots[type][tmp.tmpIndex()]; Arg arg = Arg::stack(stackSlot); // Need to figure out a register to use. How we do that depends on the role. Reg chosenReg; switch (role) { case Arg::Use: for (Reg reg : regsInPriorityOrder(type)) { if (!setBefore.get(reg)) { setBefore.set(reg); chosenReg = reg; break; } } break; case Arg::Def: for (Reg reg : regsInPriorityOrder(type)) { if (!setAfter.get(reg)) { setAfter.set(reg); chosenReg = reg; break; } } break; case Arg::UseDef: for (Reg reg : regsInPriorityOrder(type)) { if (!setBefore.get(reg) && !setAfter.get(reg)) { setAfter.set(reg); setBefore.set(reg); chosenReg = reg; break; } } break; } RELEASE_ASSERT(chosenReg); tmp = Tmp(chosenReg); Opcode move = type == Arg::GP ? Move : MoveDouble; if (Arg::isUse(role)) { insertionSet.insert( instIndex, move, inst.origin, arg, tmp); } if (Arg::isDef(role)) { insertionSet.insert( instIndex + 1, move, inst.origin, tmp, arg); } }); } insertionSet.execute(block); } }