RegAllocBigBlock.cpp [plain text]
#define DEBUG_TYPE "regalloc"
#include "llvm/BasicBlock.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/LiveVariables.h"
#include "llvm/CodeGen/RegAllocRegistry.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Compiler.h"
#include "llvm/ADT/IndexedMap.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include <algorithm>
using namespace llvm;
STATISTIC(NumStores, "Number of stores added");
STATISTIC(NumLoads , "Number of loads added");
STATISTIC(NumFolded, "Number of loads/stores folded into instructions");
static RegisterRegAlloc
bigBlockRegAlloc("bigblock", "Big-block register allocator",
createBigBlockRegisterAllocator);
namespace {
struct VRegKeyInfo {
static inline unsigned getEmptyKey() { return -1U; }
static inline unsigned getTombstoneKey() { return -2U; }
static bool isEqual(unsigned LHS, unsigned RHS) { return LHS == RHS; }
static unsigned getHashValue(const unsigned &Key) { return Key; }
};
class VISIBILITY_HIDDEN RABigBlock : public MachineFunctionPass {
public:
static char ID;
RABigBlock() : MachineFunctionPass(&ID) {}
private:
const TargetMachine *TM;
MachineFunction *MF;
const TargetRegisterInfo *RegInfo;
typedef SmallVector<unsigned, 2> VRegTimes;
DenseMap<unsigned, VRegTimes*, VRegKeyInfo> VRegReadTable;
DenseMap<unsigned, unsigned , VRegKeyInfo> VRegReadIdx;
IndexedMap<unsigned, VirtReg2IndexFunctor> StackSlotForVirtReg;
IndexedMap<unsigned, VirtReg2IndexFunctor> Virt2PhysRegMap;
std::vector<int> PhysRegsUsed;
std::vector<int> VirtRegModified;
int MBBLastInsnTime;
int MBBCurTime;
unsigned &getVirt2PhysRegMapSlot(unsigned VirtReg) {
return Virt2PhysRegMap[VirtReg];
}
unsigned &getVirt2StackSlot(unsigned VirtReg) {
return StackSlotForVirtReg[VirtReg];
}
void markVirtRegModified(unsigned Reg, bool Val = true) {
assert(TargetRegisterInfo::isVirtualRegister(Reg) && "Illegal VirtReg!");
Reg -= TargetRegisterInfo::FirstVirtualRegister;
if (VirtRegModified.size() <= Reg)
VirtRegModified.resize(Reg+1);
VirtRegModified[Reg] = Val;
}
bool isVirtRegModified(unsigned Reg) const {
assert(TargetRegisterInfo::isVirtualRegister(Reg) && "Illegal VirtReg!");
assert(Reg - TargetRegisterInfo::FirstVirtualRegister < VirtRegModified.size()
&& "Illegal virtual register!");
return VirtRegModified[Reg - TargetRegisterInfo::FirstVirtualRegister];
}
public:
virtual const char *getPassName() const {
return "BigBlock Register Allocator";
}
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequiredID(PHIEliminationID);
AU.addRequiredID(TwoAddressInstructionPassID);
MachineFunctionPass::getAnalysisUsage(AU);
}
private:
bool runOnMachineFunction(MachineFunction &Fn);
void AllocateBasicBlock(MachineBasicBlock &MBB);
void FillVRegReadTable(MachineBasicBlock &MBB);
bool areRegsEqual(unsigned R1, unsigned R2) const {
if (R1 == R2) return true;
for (const unsigned *AliasSet = RegInfo->getAliasSet(R2);
*AliasSet; ++AliasSet) {
if (*AliasSet == R1) return true;
}
return false;
}
int getStackSpaceFor(unsigned VirtReg, const TargetRegisterClass *RC);
void removePhysReg(unsigned PhysReg);
void spillVirtReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
unsigned VirtReg, unsigned PhysReg);
void spillPhysReg(MachineBasicBlock &MBB, MachineInstr *I,
unsigned PhysReg, bool OnlyVirtRegs = false);
void assignVirtToPhysReg(unsigned VirtReg, unsigned PhysReg);
bool isPhysRegAvailable(unsigned PhysReg) const;
unsigned getFreeReg(const TargetRegisterClass *RC);
unsigned chooseReg(MachineBasicBlock &MBB, MachineInstr *MI,
unsigned VirtReg);
MachineInstr *reloadVirtReg(MachineBasicBlock &MBB, MachineInstr *MI,
unsigned OpNum);
};
char RABigBlock::ID = 0;
}
int RABigBlock::getStackSpaceFor(unsigned VirtReg, const TargetRegisterClass *RC) {
int FrameIdx = getVirt2StackSlot(VirtReg);
if (FrameIdx)
return FrameIdx - 1;
FrameIdx = MF->getFrameInfo()->CreateStackObject(RC->getSize(),
RC->getAlignment());
getVirt2StackSlot(VirtReg) = FrameIdx + 1;
return FrameIdx;
}
void RABigBlock::removePhysReg(unsigned PhysReg) {
PhysRegsUsed[PhysReg] = -1; }
void RABigBlock::spillVirtReg(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
unsigned VirtReg, unsigned PhysReg) {
assert(VirtReg && "Spilling a physical register is illegal!"
" Must not have appropriate kill for the register or use exists beyond"
" the intended one.");
DOUT << " Spilling register " << RegInfo->getName(PhysReg)
<< " containing %reg" << VirtReg;
const TargetInstrInfo* TII = MBB.getParent()->getTarget().getInstrInfo();
if (!isVirtRegModified(VirtReg))
DOUT << " which has not been modified, so no store necessary!";
if (isVirtRegModified(VirtReg)) {
const TargetRegisterClass *RC = MF->getRegInfo().getRegClass(VirtReg);
int FrameIndex = getStackSpaceFor(VirtReg, RC);
DOUT << " to stack slot #" << FrameIndex;
TII->storeRegToStackSlot(MBB, I, PhysReg, true, FrameIndex, RC);
++NumStores; }
getVirt2PhysRegMapSlot(VirtReg) = 0;
DOUT << "\n";
removePhysReg(PhysReg);
}
void RABigBlock::spillPhysReg(MachineBasicBlock &MBB, MachineInstr *I,
unsigned PhysReg, bool OnlyVirtRegs) {
if (PhysRegsUsed[PhysReg] != -1) { assert(PhysRegsUsed[PhysReg] != -2 && "Non allocable reg used!");
if (PhysRegsUsed[PhysReg] || !OnlyVirtRegs)
spillVirtReg(MBB, I, PhysRegsUsed[PhysReg], PhysReg);
} else {
for (const unsigned *AliasSet = RegInfo->getAliasSet(PhysReg);
*AliasSet; ++AliasSet)
if (PhysRegsUsed[*AliasSet] != -1 && PhysRegsUsed[*AliasSet] != -2) if (PhysRegsUsed[*AliasSet])
spillVirtReg(MBB, I, PhysRegsUsed[*AliasSet], *AliasSet);
}
}
void RABigBlock::assignVirtToPhysReg(unsigned VirtReg, unsigned PhysReg) {
assert(PhysRegsUsed[PhysReg] == -1 && "Phys reg already assigned!");
PhysRegsUsed[PhysReg] = VirtReg;
getVirt2PhysRegMapSlot(VirtReg) = PhysReg;
}
bool RABigBlock::isPhysRegAvailable(unsigned PhysReg) const {
if (PhysRegsUsed[PhysReg] != -1) return false;
for (const unsigned *AliasSet = RegInfo->getAliasSet(PhysReg);
*AliasSet; ++AliasSet)
if (PhysRegsUsed[*AliasSet] >= 0) return false; return true;
}
unsigned RABigBlock::getFreeReg(const TargetRegisterClass *RC) {
TargetRegisterClass::iterator RI = RC->allocation_order_begin(*MF);
TargetRegisterClass::iterator RE = RC->allocation_order_end(*MF);
for (; RI != RE; ++RI)
if (isPhysRegAvailable(*RI)) { assert(*RI != 0 && "Cannot use register!");
return *RI; }
return 0;
}
unsigned RABigBlock::chooseReg(MachineBasicBlock &MBB, MachineInstr *I,
unsigned VirtReg) {
const TargetRegisterClass *RC = MF->getRegInfo().getRegClass(VirtReg);
unsigned PhysReg = getFreeReg(RC);
if (PhysReg == 0) {
unsigned delay=0, longest_delay=0;
VRegTimes* ReadTimes;
unsigned curTime = MBBCurTime;
for(TargetRegisterClass::iterator pReg = RC->begin();
pReg != RC->end(); ++pReg) {
if(PhysRegsUsed[*pReg]>0) { ReadTimes = VRegReadTable[PhysRegsUsed[*pReg]];
if(ReadTimes && !ReadTimes->empty()) {
unsigned& pt = VRegReadIdx[PhysRegsUsed[*pReg]];
while(pt < ReadTimes->size() && (*ReadTimes)[pt] < curTime) {
++pt;
}
if(pt < ReadTimes->size())
delay = (*ReadTimes)[pt] - curTime;
else
delay = MBBLastInsnTime + 1 - curTime;
} else {
delay = MBBLastInsnTime + 1 - curTime;
}
if(delay > longest_delay) {
longest_delay = delay;
PhysReg = *pReg;
}
}
}
if(PhysReg == 0) {
for(TargetRegisterClass::iterator pReg = RC->begin();
pReg != RC->end(); ++pReg) {
if(PhysRegsUsed[*pReg]>=-1)
PhysReg = *pReg; }
}
assert(PhysReg && "couldn't choose a register to spill :( ");
spillPhysReg(MBB, I, PhysReg);
}
assignVirtToPhysReg(VirtReg, PhysReg);
return PhysReg; }
MachineInstr *RABigBlock::reloadVirtReg(MachineBasicBlock &MBB, MachineInstr *MI,
unsigned OpNum) {
unsigned VirtReg = MI->getOperand(OpNum).getReg();
const TargetInstrInfo* TII = MBB.getParent()->getTarget().getInstrInfo();
if (unsigned PR = getVirt2PhysRegMapSlot(VirtReg)) {
MI->getOperand(OpNum).setReg(PR);
return MI;
}
const TargetRegisterClass *RC = MF->getRegInfo().getRegClass(VirtReg);
unsigned PhysReg = getFreeReg(RC);
int FrameIndex = getStackSpaceFor(VirtReg, RC);
if (PhysReg) { assignVirtToPhysReg(VirtReg, PhysReg);
} else { SmallVector<unsigned, 1> Ops;
Ops.push_back(OpNum);
if(MachineInstr* FMI = TII->foldMemoryOperand(*MF, MI, Ops, FrameIndex)) {
++NumFolded;
FMI->copyKillDeadInfo(MI);
return MBB.insert(MBB.erase(MI), FMI);
}
PhysReg = chooseReg(MBB, MI, VirtReg);
}
markVirtRegModified(VirtReg, false);
DOUT << " Reloading %reg" << VirtReg << " into "
<< RegInfo->getName(PhysReg) << "\n";
TII->loadRegFromStackSlot(MBB, MI, PhysReg, FrameIndex, RC);
++NumLoads;
MF->getRegInfo().setPhysRegUsed(PhysReg);
MI->getOperand(OpNum).setReg(PhysReg); return MI;
}
void RABigBlock::FillVRegReadTable(MachineBasicBlock &MBB) {
MachineBasicBlock::iterator MII;
unsigned ReadTime;
for(ReadTime=0, MII = MBB.begin(); MII != MBB.end(); ++ReadTime, ++MII) {
MachineInstr *MI = MII;
for (unsigned i = 0; i != MI->getNumOperands(); ++i) {
MachineOperand& MO = MI->getOperand(i);
if (MO.isReg() && !MO.isDef() && MO.getReg() &&
TargetRegisterInfo::isVirtualRegister(MO.getReg())) {
VRegTimes* &Times = VRegReadTable[MO.getReg()];
if(!VRegReadTable[MO.getReg()]) {
Times = new VRegTimes;
VRegReadIdx[MO.getReg()] = 0;
}
Times->push_back(ReadTime);
}
}
}
MBBLastInsnTime = ReadTime;
for(DenseMap<unsigned, VRegTimes*, VRegKeyInfo>::iterator Reads = VRegReadTable.begin();
Reads != VRegReadTable.end(); ++Reads) {
if(Reads->second) {
DOUT << "Reads[" << Reads->first << "]=" << Reads->second->size() << "\n";
}
}
}
static bool isReadModWriteImplicitKill(MachineInstr *MI, unsigned Reg) {
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
MachineOperand& MO = MI->getOperand(i);
if (MO.isReg() && MO.getReg() == Reg && MO.isImplicit() &&
MO.isDef() && !MO.isDead())
return true;
}
return false;
}
static bool isReadModWriteImplicitDef(MachineInstr *MI, unsigned Reg) {
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
MachineOperand& MO = MI->getOperand(i);
if (MO.isReg() && MO.getReg() == Reg && MO.isImplicit() &&
!MO.isDef() && MO.isKill())
return true;
}
return false;
}
void RABigBlock::AllocateBasicBlock(MachineBasicBlock &MBB) {
MachineBasicBlock::iterator MII = MBB.begin();
const TargetInstrInfo &TII = *TM->getInstrInfo();
DEBUG(const BasicBlock *LBB = MBB.getBasicBlock();
if (LBB) DOUT << "\nStarting RegAlloc of BB: " << LBB->getName());
if (&MBB == &*MF->begin()) {
for (MachineRegisterInfo::livein_iterator
I = MF->getRegInfo().livein_begin(),
E = MF->getRegInfo().livein_end(); I != E; ++I) {
unsigned Reg = I->first;
MF->getRegInfo().setPhysRegUsed(Reg);
PhysRegsUsed[Reg] = 0; for (const unsigned *AliasSet = RegInfo->getSubRegisters(Reg);
*AliasSet; ++AliasSet) {
if (PhysRegsUsed[*AliasSet] != -2) {
PhysRegsUsed[*AliasSet] = 0; MF->getRegInfo().setPhysRegUsed(*AliasSet);
}
}
}
}
MBBCurTime = -1;
while (MII != MBB.end()) {
MachineInstr *MI = MII++;
MBBCurTime++;
const TargetInstrDesc &TID = MI->getDesc();
DEBUG(DOUT << "\nTime=" << MBBCurTime << " Starting RegAlloc of: " << *MI;
DOUT << " Regs have values: ";
for (unsigned i = 0; i != RegInfo->getNumRegs(); ++i)
if (PhysRegsUsed[i] != -1 && PhysRegsUsed[i] != -2)
DOUT << "[" << RegInfo->getName(i)
<< ",%reg" << PhysRegsUsed[i] << "] ";
DOUT << "\n");
SmallVector<unsigned, 8> Kills;
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
MachineOperand& MO = MI->getOperand(i);
if (MO.isReg() && MO.isKill()) {
if (!MO.isImplicit())
Kills.push_back(MO.getReg());
else if (!isReadModWriteImplicitKill(MI, MO.getReg()))
Kills.push_back(MO.getReg());
}
}
for (unsigned i = 0; i != MI->getNumOperands(); ++i) {
MachineOperand& MO = MI->getOperand(i);
if (MO.isReg() && !MO.isDef() && MO.getReg() && !MO.isImplicit() &&
TargetRegisterInfo::isVirtualRegister(MO.getReg()))
MI = reloadVirtReg(MBB, MI, i);
}
for (unsigned i = 0, e = Kills.size(); i != e; ++i) {
unsigned VirtReg = Kills[i];
unsigned PhysReg = VirtReg;
if (TargetRegisterInfo::isVirtualRegister(VirtReg)) {
unsigned &PhysRegSlot = getVirt2PhysRegMapSlot(VirtReg);
PhysReg = PhysRegSlot;
PhysRegSlot = 0;
} else if (PhysRegsUsed[PhysReg] == -2) {
continue;
} else {
assert((!PhysRegsUsed[PhysReg] || PhysRegsUsed[PhysReg] == -1) &&
"Silently clearing a virtual register?");
}
if (PhysReg) {
DOUT << " Last use of " << RegInfo->getName(PhysReg)
<< "[%reg" << VirtReg <<"], removing it from live set\n";
removePhysReg(PhysReg);
for (const unsigned *AliasSet = RegInfo->getSubRegisters(PhysReg);
*AliasSet; ++AliasSet) {
if (PhysRegsUsed[*AliasSet] != -2) {
DOUT << " Last use of "
<< RegInfo->getName(*AliasSet)
<< "[%reg" << VirtReg <<"], removing it from live set\n";
removePhysReg(*AliasSet);
}
}
}
}
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
MachineOperand& MO = MI->getOperand(i);
if (MO.isReg() && MO.isDef() && !MO.isImplicit() && MO.getReg() &&
TargetRegisterInfo::isPhysicalRegister(MO.getReg())) {
unsigned Reg = MO.getReg();
if (PhysRegsUsed[Reg] == -2) continue; if (isReadModWriteImplicitDef(MI, MO.getReg())) continue;
MF->getRegInfo().setPhysRegUsed(Reg);
spillPhysReg(MBB, MI, Reg, true); PhysRegsUsed[Reg] = 0; for (const unsigned *AliasSet = RegInfo->getSubRegisters(Reg);
*AliasSet; ++AliasSet) {
if (PhysRegsUsed[*AliasSet] != -2) {
PhysRegsUsed[*AliasSet] = 0; MF->getRegInfo().setPhysRegUsed(*AliasSet);
}
}
}
}
if (TID.getImplicitDefs()) {
for (const unsigned *ImplicitDefs = TID.getImplicitDefs();
*ImplicitDefs; ++ImplicitDefs) {
unsigned Reg = *ImplicitDefs;
if (PhysRegsUsed[Reg] != -2) {
spillPhysReg(MBB, MI, Reg, true);
PhysRegsUsed[Reg] = 0; }
MF->getRegInfo().setPhysRegUsed(Reg);
for (const unsigned *AliasSet = RegInfo->getSubRegisters(Reg);
*AliasSet; ++AliasSet) {
if (PhysRegsUsed[*AliasSet] != -2) {
PhysRegsUsed[*AliasSet] = 0; MF->getRegInfo().setPhysRegUsed(*AliasSet);
}
}
}
}
SmallVector<unsigned, 8> DeadDefs;
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
MachineOperand& MO = MI->getOperand(i);
if (MO.isReg() && MO.isDead())
DeadDefs.push_back(MO.getReg());
}
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
MachineOperand& MO = MI->getOperand(i);
if (MO.isReg() && MO.isDef() && MO.getReg() &&
TargetRegisterInfo::isVirtualRegister(MO.getReg())) {
unsigned DestVirtReg = MO.getReg();
unsigned DestPhysReg;
if (!(DestPhysReg = getVirt2PhysRegMapSlot(DestVirtReg)))
DestPhysReg = chooseReg(MBB, MI, DestVirtReg);
MF->getRegInfo().setPhysRegUsed(DestPhysReg);
markVirtRegModified(DestVirtReg);
MI->getOperand(i).setReg(DestPhysReg); }
}
for (unsigned i = 0, e = DeadDefs.size(); i != e; ++i) {
unsigned VirtReg = DeadDefs[i];
unsigned PhysReg = VirtReg;
if (TargetRegisterInfo::isVirtualRegister(VirtReg)) {
unsigned &PhysRegSlot = getVirt2PhysRegMapSlot(VirtReg);
PhysReg = PhysRegSlot;
assert(PhysReg != 0);
PhysRegSlot = 0;
} else if (PhysRegsUsed[PhysReg] == -2) {
continue;
}
if (PhysReg) {
DOUT << " Register " << RegInfo->getName(PhysReg)
<< " [%reg" << VirtReg
<< "] is never used, removing it from live set\n";
removePhysReg(PhysReg);
for (const unsigned *AliasSet = RegInfo->getAliasSet(PhysReg);
*AliasSet; ++AliasSet) {
if (PhysRegsUsed[*AliasSet] != -2) {
DOUT << " Register " << RegInfo->getName(*AliasSet)
<< " [%reg" << *AliasSet
<< "] is never used, removing it from live set\n";
removePhysReg(*AliasSet);
}
}
}
}
unsigned SrcReg, DstReg, SrcSubReg, DstSubReg;
if (TII.isMoveInstr(*MI, SrcReg, DstReg, SrcSubReg, DstSubReg) &&
SrcReg == DstReg)
MBB.erase(MI);
}
MachineBasicBlock::iterator MI = MBB.getFirstTerminator();
for (unsigned i = 0, e = RegInfo->getNumRegs(); i != e; ++i)
if (PhysRegsUsed[i] != -1 && PhysRegsUsed[i] != -2) {
if (unsigned VirtReg = PhysRegsUsed[i])
spillVirtReg(MBB, MI, VirtReg, i);
else
removePhysReg(i);
}
}
bool RABigBlock::runOnMachineFunction(MachineFunction &Fn) {
DOUT << "Machine Function " << "\n";
MF = &Fn;
TM = &Fn.getTarget();
RegInfo = TM->getRegisterInfo();
PhysRegsUsed.assign(RegInfo->getNumRegs(), -1);
{
BitVector Allocable = RegInfo->getAllocatableSet(Fn);
for (unsigned i = 0, e = Allocable.size(); i != e; ++i)
if (!Allocable[i])
PhysRegsUsed[i] = -2; }
Virt2PhysRegMap.grow(MF->getRegInfo().getLastVirtReg());
StackSlotForVirtReg.grow(MF->getRegInfo().getLastVirtReg());
VirtRegModified.resize(MF->getRegInfo().getLastVirtReg() -
TargetRegisterInfo::FirstVirtualRegister + 1, 0);
for (MachineFunction::iterator MBB = Fn.begin(), MBBe = Fn.end();
MBB != MBBe; ++MBB) {
FillVRegReadTable(*MBB);
AllocateBasicBlock(*MBB);
VRegReadTable.clear();
}
StackSlotForVirtReg.clear();
PhysRegsUsed.clear();
VirtRegModified.clear();
Virt2PhysRegMap.clear();
return true;
}
FunctionPass *llvm::createBigBlockRegisterAllocator() {
return new RABigBlock();
}