//
//===----------------------------------------------------------------------===//
//
-// This file implements the virtual register map.
+// This file implements the virtual register map. It also implements
+// the eliminateVirtRegs() function that given a virtual register map
+// and a machine function it eliminates all virtual references by
+// replacing them with physical register references and adds spill
+// code as necessary.
//
//===----------------------------------------------------------------------===//
+#define DEBUG_TYPE "regalloc"
#include "VirtRegMap.h"
+#include "llvm/Function.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetInstrInfo.h"
#include "Support/Statistic.h"
+#include "Support/Debug.h"
+#include "Support/STLExtras.h"
#include <iostream>
using namespace llvm;
namespace {
- Statistic<> numSpills("ra-linearscan", "Number of register spills");
+ Statistic<> numSpills("spiller", "Number of register spills");
+ Statistic<> numStores("spiller", "Number of stores added");
+ Statistic<> numLoads ("spiller", "Number of loads added");
+
}
int VirtRegMap::assignVirt2StackSlot(unsigned virtReg)
{
assert(MRegisterInfo::isVirtualRegister(virtReg));
- assert(v2ssMap_[toIndex(virtReg)] == NO_STACK_SLOT &&
+ assert(v2ssMap_[virtReg] == NO_STACK_SLOT &&
"attempt to assign stack slot to already spilled register");
const TargetRegisterClass* rc =
mf_->getSSARegMap()->getRegClass(virtReg);
int frameIndex = mf_->getFrameInfo()->CreateStackObject(rc);
- v2ssMap_[toIndex(virtReg)] = frameIndex;
+ v2ssMap_[virtReg] = frameIndex;
++numSpills;
return frameIndex;
}
const MRegisterInfo* mri = vrm.mf_->getTarget().getRegisterInfo();
std::cerr << "********** REGISTER MAP **********\n";
- for (unsigned i = 0, e = vrm.v2pMap_.size(); i != e; ++i) {
+ for (unsigned i = MRegisterInfo::FirstVirtualRegister,
+ e = vrm.mf_->getSSARegMap()->getLastVirtReg(); i <= e; ++i) {
if (vrm.v2pMap_[i] != VirtRegMap::NO_PHYS_REG)
- std::cerr << "[reg" << VirtRegMap::fromIndex(i) << " -> "
+ std::cerr << "[reg" << i << " -> "
<< mri->getName(vrm.v2pMap_[i]) << "]\n";
}
- for (unsigned i = 0, e = vrm.v2ssMap_.size(); i != e; ++i) {
+ for (unsigned i = MRegisterInfo::FirstVirtualRegister,
+ e = vrm.mf_->getSSARegMap()->getLastVirtReg(); i <= e; ++i) {
if (vrm.v2ssMap_[i] != VirtRegMap::NO_STACK_SLOT)
- std::cerr << "[reg" << VirtRegMap::fromIndex(i) << " -> fi#"
+ std::cerr << "[reg" << i << " -> fi#"
<< vrm.v2ssMap_[i] << "]\n";
}
return std::cerr << '\n';
}
+
+namespace {
+
+ class Spiller {
+ typedef std::vector<unsigned> Phys2VirtMap;
+ typedef std::vector<bool> PhysFlag;
+
+ MachineFunction& mf_;
+ const TargetMachine& tm_;
+ const TargetInstrInfo& tii_;
+ const MRegisterInfo& mri_;
+ const VirtRegMap& vrm_;
+ Phys2VirtMap p2vMap_;
+ PhysFlag dirty_;
+
+ public:
+ Spiller(MachineFunction& mf, const VirtRegMap& vrm)
+ : mf_(mf),
+ tm_(mf_.getTarget()),
+ tii_(tm_.getInstrInfo()),
+ mri_(*tm_.getRegisterInfo()),
+ vrm_(vrm),
+ p2vMap_(mri_.getNumRegs()),
+ dirty_(mri_.getNumRegs()) {
+ DEBUG(std::cerr << "********** REWRITE MACHINE CODE **********\n");
+ DEBUG(std::cerr << "********** Function: "
+ << mf_.getFunction()->getName() << '\n');
+ }
+
+ void eliminateVirtRegs() {
+ for (MachineFunction::iterator mbbi = mf_.begin(),
+ mbbe = mf_.end(); mbbi != mbbe; ++mbbi) {
+ // clear map and dirty flag
+ p2vMap_.assign(p2vMap_.size(), 0);
+ dirty_.assign(dirty_.size(), false);
+ DEBUG(std::cerr << mbbi->getBasicBlock()->getName() << ":\n");
+ eliminateVirtRegsInMbb(*mbbi);
+ }
+ }
+
+ private:
+ void vacateJustPhysReg(MachineBasicBlock& mbb,
+ MachineBasicBlock::iterator mii,
+ unsigned physReg) {
+ unsigned virtReg = p2vMap_[physReg];
+ if (dirty_[physReg] && vrm_.hasStackSlot(virtReg)) {
+ mri_.storeRegToStackSlot(mbb, mii, physReg,
+ vrm_.getStackSlot(virtReg),
+ mri_.getRegClass(physReg));
+ ++numStores;
+ DEBUG(std::cerr << "*\t"; prior(mii)->print(std::cerr, tm_));
+ }
+ p2vMap_[physReg] = 0;
+ dirty_[physReg] = false;
+ }
+
+ void vacatePhysReg(MachineBasicBlock& mbb,
+ MachineBasicBlock::iterator mii,
+ unsigned physReg) {
+ vacateJustPhysReg(mbb, mii, physReg);
+ for (const unsigned* as = mri_.getAliasSet(physReg); *as; ++as)
+ vacateJustPhysReg(mbb, mii, *as);
+ }
+
+ void handleUse(MachineBasicBlock& mbb,
+ MachineBasicBlock::iterator mii,
+ unsigned virtReg,
+ unsigned physReg) {
+ // check if we are replacing a previous mapping
+ if (p2vMap_[physReg] != virtReg) {
+ vacatePhysReg(mbb, mii, physReg);
+ p2vMap_[physReg] = virtReg;
+ // load if necessary
+ if (vrm_.hasStackSlot(virtReg)) {
+ mri_.loadRegFromStackSlot(mbb, mii, physReg,
+ vrm_.getStackSlot(virtReg),
+ mri_.getRegClass(physReg));
+ ++numLoads;
+ DEBUG(std::cerr << "*\t"; prior(mii)->print(std::cerr,tm_));
+ }
+ }
+ }
+
+ void handleDef(MachineBasicBlock& mbb,
+ MachineBasicBlock::iterator mii,
+ unsigned virtReg,
+ unsigned physReg) {
+ // check if we are replacing a previous mapping
+ if (p2vMap_[physReg] != virtReg)
+ vacatePhysReg(mbb, mii, physReg);
+
+ p2vMap_[physReg] = virtReg;
+ dirty_[physReg] = true;
+ }
+
+ void eliminateVirtRegsInMbb(MachineBasicBlock& mbb) {
+ for (MachineBasicBlock::iterator mii = mbb.begin(),
+ mie = mbb.end(); mii != mie; ++mii) {
+ // rewrite all used operands
+ for (unsigned i = 0, e = mii->getNumOperands(); i != e; ++i) {
+ MachineOperand& op = mii->getOperand(i);
+ if (op.isRegister() && op.getReg() && op.isUse() &&
+ MRegisterInfo::isVirtualRegister(op.getReg())) {
+ unsigned physReg = vrm_.getPhys(op.getReg());
+ handleUse(mbb, mii, op.getReg(), physReg);
+ mii->SetMachineOperandReg(i, physReg);
+ // mark as dirty if this is def&use
+ if (op.isDef()) dirty_[physReg] = true;
+ }
+ }
+
+ // spill implicit defs
+ const TargetInstrDescriptor& tid =tii_.get(mii->getOpcode());
+ for (const unsigned* id = tid.ImplicitDefs; *id; ++id)
+ vacatePhysReg(mbb, mii, *id);
+
+ // rewrite def operands (def&use was handled with the
+ // uses so don't check for those here)
+ for (unsigned i = 0, e = mii->getNumOperands(); i != e; ++i) {
+ MachineOperand& op = mii->getOperand(i);
+ if (op.isRegister() && op.getReg() && !op.isUse())
+ if (MRegisterInfo::isPhysicalRegister(op.getReg()))
+ vacatePhysReg(mbb, mii, op.getReg());
+ else {
+ unsigned physReg = vrm_.getPhys(op.getReg());
+ handleDef(mbb, mii, op.getReg(), physReg);
+ mii->SetMachineOperandReg(i, physReg);
+ }
+ }
+
+ DEBUG(std::cerr << '\t'; mii->print(std::cerr, tm_));
+ }
+
+ for (unsigned i = 1, e = p2vMap_.size(); i != e; ++i)
+ vacateJustPhysReg(mbb, mbb.getFirstTerminator(), i);
+
+ }
+ };
+}
+
+
+void llvm::eliminateVirtRegs(MachineFunction& mf, const VirtRegMap& vrm)
+{
+ Spiller(mf, vrm).eliminateVirtRegs();
+}