#define DEBUG_TYPE "spiller"
#include "Spiller.h"
#include "VirtRegMap.h"
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include <set>
using namespace llvm;
namespace {
enum SpillerName { trivial, standard, splitting };
}
static cl::opt<SpillerName>
spillerOpt("spiller",
cl::desc("Spiller to use: (default: standard)"),
cl::Prefix,
cl::values(clEnumVal(trivial, "trivial spiller"),
clEnumVal(standard, "default spiller"),
clEnumVal(splitting, "splitting spiller"),
clEnumValEnd),
cl::init(standard));
Spiller::~Spiller() {}
namespace {
class SpillerBase : public Spiller {
protected:
MachineFunction *mf;
LiveIntervals *lis;
MachineFrameInfo *mfi;
MachineRegisterInfo *mri;
const TargetInstrInfo *tii;
VirtRegMap *vrm;
SpillerBase(MachineFunction *mf, LiveIntervals *lis, VirtRegMap *vrm)
: mf(mf), lis(lis), vrm(vrm)
{
mfi = mf->getFrameInfo();
mri = &mf->getRegInfo();
tii = mf->getTarget().getInstrInfo();
}
std::vector<LiveInterval*> trivialSpillEverywhere(LiveInterval *li) {
DEBUG(dbgs() << "Spilling everywhere " << *li << "\n");
assert(li->weight != HUGE_VALF &&
"Attempting to spill already spilled value.");
assert(!li->isStackSlot() &&
"Trying to spill a stack slot.");
DEBUG(dbgs() << "Trivial spill everywhere of reg" << li->reg << "\n");
std::vector<LiveInterval*> added;
const TargetRegisterClass *trc = mri->getRegClass(li->reg);
unsigned ss = vrm->assignVirt2StackSlot(li->reg);
for (MachineRegisterInfo::reg_iterator
regItr = mri->reg_begin(li->reg); regItr != mri->reg_end();) {
MachineInstr *mi = &*regItr;
DEBUG(dbgs() << " Processing " << *mi);
do {
++regItr;
} while (regItr != mri->reg_end() && (&*regItr == mi));
SmallVector<unsigned, 2> indices;
bool hasUse = false;
bool hasDef = false;
for (unsigned i = 0; i != mi->getNumOperands(); ++i) {
MachineOperand &op = mi->getOperand(i);
if (!op.isReg() || op.getReg() != li->reg)
continue;
hasUse |= mi->getOperand(i).isUse();
hasDef |= mi->getOperand(i).isDef();
indices.push_back(i);
}
unsigned newVReg = mri->createVirtualRegister(trc);
vrm->grow();
vrm->assignVirt2StackSlot(newVReg, ss);
LiveInterval *newLI = &lis->getOrCreateInterval(newVReg);
newLI->weight = HUGE_VALF;
for (unsigned i = 0; i < indices.size(); ++i) {
unsigned mopIdx = indices[i];
MachineOperand &mop = mi->getOperand(mopIdx);
mop.setReg(newVReg);
if (mop.isUse() && !mi->isRegTiedToDefOperand(mopIdx)) {
mop.setIsKill(true);
}
}
assert(hasUse || hasDef);
MachineBasicBlock::iterator miItr(mi);
if (hasUse) {
tii->loadRegFromStackSlot(*mi->getParent(), miItr, newVReg, ss, trc);
MachineInstr *loadInstr(prior(miItr));
SlotIndex loadIndex =
lis->InsertMachineInstrInMaps(loadInstr).getDefIndex();
SlotIndex endIndex = loadIndex.getNextIndex();
VNInfo *loadVNI =
newLI->getNextValue(loadIndex, 0, true, lis->getVNInfoAllocator());
loadVNI->addKill(endIndex);
newLI->addRange(LiveRange(loadIndex, endIndex, loadVNI));
}
if (hasDef) {
tii->storeRegToStackSlot(*mi->getParent(), llvm::next(miItr), newVReg, true,
ss, trc);
MachineInstr *storeInstr(llvm::next(miItr));
SlotIndex storeIndex =
lis->InsertMachineInstrInMaps(storeInstr).getDefIndex();
SlotIndex beginIndex = storeIndex.getPrevIndex();
VNInfo *storeVNI =
newLI->getNextValue(beginIndex, 0, true, lis->getVNInfoAllocator());
storeVNI->addKill(storeIndex);
newLI->addRange(LiveRange(beginIndex, storeIndex, storeVNI));
}
added.push_back(newLI);
}
return added;
}
};
class TrivialSpiller : public SpillerBase {
public:
TrivialSpiller(MachineFunction *mf, LiveIntervals *lis, VirtRegMap *vrm)
: SpillerBase(mf, lis, vrm) {}
std::vector<LiveInterval*> spill(LiveInterval *li,
SmallVectorImpl<LiveInterval*> &spillIs,
SlotIndex*) {
return trivialSpillEverywhere(li);
}
};
class StandardSpiller : public Spiller {
protected:
LiveIntervals *lis;
const MachineLoopInfo *loopInfo;
VirtRegMap *vrm;
public:
StandardSpiller(LiveIntervals *lis, const MachineLoopInfo *loopInfo,
VirtRegMap *vrm)
: lis(lis), loopInfo(loopInfo), vrm(vrm) {}
std::vector<LiveInterval*> spill(LiveInterval *li,
SmallVectorImpl<LiveInterval*> &spillIs,
SlotIndex*) {
return lis->addIntervalsForSpills(*li, spillIs, loopInfo, *vrm);
}
};
class SplittingSpiller : public StandardSpiller {
public:
SplittingSpiller(MachineFunction *mf, LiveIntervals *lis,
const MachineLoopInfo *loopInfo, VirtRegMap *vrm)
: StandardSpiller(lis, loopInfo, vrm) {
mri = &mf->getRegInfo();
tii = mf->getTarget().getInstrInfo();
tri = mf->getTarget().getRegisterInfo();
}
std::vector<LiveInterval*> spill(LiveInterval *li,
SmallVectorImpl<LiveInterval*> &spillIs,
SlotIndex *earliestStart) {
if (worthTryingToSplit(li)) {
return tryVNISplit(li, earliestStart);
}
return StandardSpiller::spill(li, spillIs, earliestStart);
}
private:
MachineRegisterInfo *mri;
const TargetInstrInfo *tii;
const TargetRegisterInfo *tri;
DenseSet<LiveInterval*> alreadySplit;
bool worthTryingToSplit(LiveInterval *li) const {
return (!alreadySplit.count(li) && li->getNumValNums() > 1);
}
std::vector<LiveInterval*> tryVNISplit(LiveInterval *li,
SlotIndex *earliestStart) {
DEBUG(dbgs() << "Trying VNI split of %reg" << *li << "\n");
std::vector<LiveInterval*> added;
SmallVector<VNInfo*, 4> vnis;
std::copy(li->vni_begin(), li->vni_end(), std::back_inserter(vnis));
for (SmallVectorImpl<VNInfo*>::iterator vniItr = vnis.begin(),
vniEnd = vnis.end(); vniItr != vniEnd; ++vniItr) {
VNInfo *vni = *vniItr;
if (vni->isUnused() || vni->kills.empty())
continue;
DEBUG(dbgs() << " Extracted Val #" << vni->id << " as ");
LiveInterval *splitInterval = extractVNI(li, vni);
if (splitInterval != 0) {
DEBUG(dbgs() << *splitInterval << "\n");
added.push_back(splitInterval);
alreadySplit.insert(splitInterval);
if (earliestStart != 0) {
if (splitInterval->beginIndex() < *earliestStart)
*earliestStart = splitInterval->beginIndex();
}
} else {
DEBUG(dbgs() << "0\n");
}
}
DEBUG(dbgs() << "Original LI: " << *li << "\n");
if (!li->empty()) {
added.push_back(li);
alreadySplit.insert(li);
if (earliestStart != 0) {
if (li->beginIndex() < *earliestStart)
*earliestStart = li->beginIndex();
}
}
return added;
}
LiveInterval* extractVNI(LiveInterval *li, VNInfo *vni) const {
assert(vni->isDefAccurate() || vni->isPHIDef());
assert(!vni->kills.empty());
const TargetRegisterClass *trc = mri->getRegClass(li->reg);
unsigned newVReg = mri->createVirtualRegister(trc);
vrm->grow();
LiveInterval *newLI = &lis->getOrCreateInterval(newVReg);
VNInfo *newVNI = newLI->createValueCopy(vni, lis->getVNInfoAllocator());
for (LiveInterval::iterator rItr = li->begin(), rEnd = li->end();
rItr != rEnd; ++rItr) {
if (rItr->valno == vni) {
newLI->addRange(LiveRange(rItr->start, rItr->end, newVNI));
}
}
li->removeValNo(vni);
std::set<MachineInstr*> uses;
for (MachineRegisterInfo::use_iterator
useItr = mri->use_begin(li->reg), useEnd = mri->use_end();
useItr != useEnd; ++useItr) {
uses.insert(&*useItr);
}
if (newVNI->isPHIDef()) {
MachineBasicBlock *defMBB = lis->getMBBFromIndex(newVNI->def);
tii->copyRegToReg(*defMBB, defMBB->begin(), newVReg, li->reg, trc, trc);
MachineInstr *copyMI = defMBB->begin();
copyMI->addRegisterKilled(li->reg, tri);
SlotIndex copyIdx = lis->InsertMachineInstrInMaps(copyMI);
VNInfo *phiDefVNI = li->getNextValue(lis->getMBBStartIdx(defMBB),
0, false, lis->getVNInfoAllocator());
phiDefVNI->setIsPHIDef(true);
phiDefVNI->addKill(copyIdx.getDefIndex());
li->addRange(LiveRange(phiDefVNI->def, copyIdx.getDefIndex(), phiDefVNI));
LiveRange *oldPHIDefRange =
newLI->getLiveRangeContaining(lis->getMBBStartIdx(defMBB));
if (oldPHIDefRange->start < lis->getMBBStartIdx(defMBB)) {
LiveRange oldPHIDefRange2(copyIdx.getDefIndex(), oldPHIDefRange->end,
oldPHIDefRange->valno);
oldPHIDefRange->end = lis->getMBBStartIdx(defMBB);
newLI->addRange(oldPHIDefRange2);
} else if (oldPHIDefRange->start == lis->getMBBStartIdx(defMBB)) {
oldPHIDefRange->start = copyIdx.getDefIndex();
} else {
assert(false && "PHI def range doesn't cover PHI def?");
}
newVNI->def = copyIdx.getDefIndex();
newVNI->setCopy(copyMI);
newVNI->setIsPHIDef(false); newVNI->setIsDefAccurate(true);
} else {
MachineInstr *defInst = lis->getInstructionFromIndex(newVNI->def);
uses.erase(defInst);
unsigned defOpIdx = defInst->findRegisterDefOperandIdx(li->reg);
bool isTwoAddr = defInst->isRegTiedToUseOperand(defOpIdx),
twoAddrUseIsUndef = false;
for (unsigned i = 0; i < defInst->getNumOperands(); ++i) {
MachineOperand &mo = defInst->getOperand(i);
if (mo.isReg() && (mo.isDef() || isTwoAddr) && (mo.getReg()==li->reg)) {
mo.setReg(newVReg);
if (isTwoAddr && mo.isUse() && mo.isUndef())
twoAddrUseIsUndef = true;
}
}
SlotIndex defIdx = lis->getInstructionIndex(defInst);
newVNI->def = defIdx.getDefIndex();
if (isTwoAddr && !twoAddrUseIsUndef) {
MachineBasicBlock *defMBB = defInst->getParent();
tii->copyRegToReg(*defMBB, defInst, newVReg, li->reg, trc, trc);
MachineInstr *copyMI = prior(MachineBasicBlock::iterator(defInst));
SlotIndex copyIdx = lis->InsertMachineInstrInMaps(copyMI);
copyMI->addRegisterKilled(li->reg, tri);
LiveRange *origUseRange =
li->getLiveRangeContaining(newVNI->def.getUseIndex());
VNInfo *origUseVNI = origUseRange->valno;
origUseRange->end = copyIdx.getDefIndex();
bool updatedKills = false;
for (unsigned k = 0; k < origUseVNI->kills.size(); ++k) {
if (origUseVNI->kills[k] == defIdx.getDefIndex()) {
origUseVNI->kills[k] = copyIdx.getDefIndex();
updatedKills = true;
break;
}
}
assert(updatedKills && "Failed to update VNI kill list.");
VNInfo *copyVNI = newLI->getNextValue(copyIdx.getDefIndex(), copyMI,
true, lis->getVNInfoAllocator());
copyVNI->addKill(defIdx.getDefIndex());
LiveRange copyRange(copyIdx.getDefIndex(),defIdx.getDefIndex(),copyVNI);
newLI->addRange(copyRange);
}
}
for (std::set<MachineInstr*>::iterator
usesItr = uses.begin(), usesEnd = uses.end();
usesItr != usesEnd; ++usesItr) {
MachineInstr *useInst = *usesItr;
SlotIndex useIdx = lis->getInstructionIndex(useInst);
LiveRange *useRange =
newLI->getLiveRangeContaining(useIdx.getUseIndex());
if (useRange == 0)
continue;
if (useRange->valno != newVNI)
continue;
unsigned useOpIdx = useInst->findRegisterUseOperandIdx(li->reg);
bool isTwoAddress = useInst->isRegTiedToDefOperand(useOpIdx);
for (unsigned i = 0; i < useInst->getNumOperands(); ++i) {
MachineOperand &mo = useInst->getOperand(i);
if (mo.isReg() && (mo.isUse() || isTwoAddress) &&
(mo.getReg() == li->reg)) {
mo.setReg(newVReg);
}
}
if (isTwoAddress) {
MachineBasicBlock *useMBB = useInst->getParent();
MachineBasicBlock::iterator useItr(useInst);
tii->copyRegToReg(*useMBB, next(useItr), li->reg, newVReg, trc, trc);
MachineInstr *copyMI = next(useItr);
copyMI->addRegisterKilled(newVReg, tri);
SlotIndex copyIdx = lis->InsertMachineInstrInMaps(copyMI);
LiveRange *origDefRange =
li->getLiveRangeContaining(useIdx.getDefIndex());
origDefRange->start = copyIdx.getDefIndex();
origDefRange->valno->def = copyIdx.getDefIndex();
origDefRange->valno->setCopy(copyMI);
VNInfo *copyVNI =
newLI->getNextValue(useIdx.getDefIndex(), 0, true,
lis->getVNInfoAllocator());
copyVNI->addKill(copyIdx.getDefIndex());
LiveRange copyRange(useIdx.getDefIndex(),copyIdx.getDefIndex(),copyVNI);
newLI->addRange(copyRange);
}
}
for (VNInfo::KillSet::iterator
killItr = newVNI->kills.begin(), killEnd = newVNI->kills.end();
killItr != killEnd; ++killItr) {
SlotIndex killIdx(*killItr);
if (killItr->isPHI()) {
MachineBasicBlock *killMBB = lis->getMBBFromIndex(killIdx);
LiveRange *oldKillRange =
newLI->getLiveRangeContaining(killIdx);
assert(oldKillRange != 0 && "No kill range?");
tii->copyRegToReg(*killMBB, killMBB->getFirstTerminator(),
li->reg, newVReg, trc, trc);
MachineInstr *copyMI = prior(killMBB->getFirstTerminator());
copyMI->addRegisterKilled(newVReg, tri);
SlotIndex copyIdx = lis->InsertMachineInstrInMaps(copyMI);
SlotIndex newKillRangeEnd = oldKillRange->end;
oldKillRange->end = copyIdx.getDefIndex();
if (newKillRangeEnd != lis->getMBBEndIdx(killMBB)) {
assert(newKillRangeEnd > lis->getMBBEndIdx(killMBB) &&
"PHI kill range doesn't reach kill-block end. Not sane.");
newLI->addRange(LiveRange(lis->getMBBEndIdx(killMBB),
newKillRangeEnd, newVNI));
}
*killItr = oldKillRange->end;
VNInfo *newKillVNI = li->getNextValue(copyIdx.getDefIndex(),
copyMI, true,
lis->getVNInfoAllocator());
newKillVNI->addKill(lis->getMBBTerminatorGap(killMBB));
newKillVNI->setHasPHIKill(true);
li->addRange(LiveRange(copyIdx.getDefIndex(),
lis->getMBBEndIdx(killMBB),
newKillVNI));
}
}
newVNI->setHasPHIKill(false);
return newLI;
}
};
}
llvm::Spiller* llvm::createSpiller(MachineFunction *mf, LiveIntervals *lis,
const MachineLoopInfo *loopInfo,
VirtRegMap *vrm) {
switch (spillerOpt) {
case trivial: return new TrivialSpiller(mf, lis, vrm); break;
case standard: return new StandardSpiller(lis, loopInfo, vrm); break;
case splitting: return new SplittingSpiller(mf, lis, loopInfo, vrm); break;
default: llvm_unreachable("Unreachable!"); break;
}
}