mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-10 18:34:09 +00:00
Make the local register allocator compute (purely local) liveness information for itself
rather than depending on LiveVariables. This decreases compile time from: 0.5909s (LV + Regalloc) to 0.421s (just regalloc). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@53256 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
62b9b6e38c
commit
491fccc4b4
@ -14,7 +14,6 @@
|
|||||||
|
|
||||||
#define DEBUG_TYPE "regalloc"
|
#define DEBUG_TYPE "regalloc"
|
||||||
#include "llvm/BasicBlock.h"
|
#include "llvm/BasicBlock.h"
|
||||||
#include "llvm/CodeGen/LiveVariables.h"
|
|
||||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||||
#include "llvm/CodeGen/MachineInstr.h"
|
#include "llvm/CodeGen/MachineInstr.h"
|
||||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||||
@ -101,6 +100,10 @@ namespace {
|
|||||||
// is no reason to spill it to memory when we need the register back.
|
// is no reason to spill it to memory when we need the register back.
|
||||||
//
|
//
|
||||||
BitVector VirtRegModified;
|
BitVector VirtRegModified;
|
||||||
|
|
||||||
|
// UsedInMultipleBlocks - Tracks whether a particular register is used in
|
||||||
|
// more than one block.
|
||||||
|
BitVector UsedInMultipleBlocks;
|
||||||
|
|
||||||
void markVirtRegModified(unsigned Reg, bool Val = true) {
|
void markVirtRegModified(unsigned Reg, bool Val = true) {
|
||||||
assert(TargetRegisterInfo::isVirtualRegister(Reg) && "Illegal VirtReg!");
|
assert(TargetRegisterInfo::isVirtualRegister(Reg) && "Illegal VirtReg!");
|
||||||
@ -147,7 +150,6 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||||
AU.addRequired<LiveVariables>();
|
|
||||||
AU.addRequiredID(PHIEliminationID);
|
AU.addRequiredID(PHIEliminationID);
|
||||||
AU.addRequiredID(TwoAddressInstructionPassID);
|
AU.addRequiredID(TwoAddressInstructionPassID);
|
||||||
MachineFunctionPass::getAnalysisUsage(AU);
|
MachineFunctionPass::getAnalysisUsage(AU);
|
||||||
@ -539,6 +541,26 @@ static bool isReadModWriteImplicitDef(MachineInstr *MI, unsigned Reg) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// precedes - Helper function to determine with MachineInstr A
|
||||||
|
// precedes MachineInstr B within the same MBB.
|
||||||
|
static bool precedes(MachineBasicBlock::iterator A,
|
||||||
|
MachineBasicBlock::iterator B) {
|
||||||
|
if (A == B)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
MachineBasicBlock::iterator I = A->getParent()->begin();
|
||||||
|
while (I != A->getParent()->end()) {
|
||||||
|
if (I == A)
|
||||||
|
return true;
|
||||||
|
else if (I == B)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
++I;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void RALocal::AllocateBasicBlock(MachineBasicBlock &MBB) {
|
void RALocal::AllocateBasicBlock(MachineBasicBlock &MBB) {
|
||||||
// loop over each instruction
|
// loop over each instruction
|
||||||
MachineBasicBlock::iterator MII = MBB.begin();
|
MachineBasicBlock::iterator MII = MBB.begin();
|
||||||
@ -567,6 +589,97 @@ void RALocal::AllocateBasicBlock(MachineBasicBlock &MBB) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MachineRegisterInfo& MRI = MBB.getParent()->getRegInfo();
|
||||||
|
// Keep track of the most recently seen previous use or def of each reg,
|
||||||
|
// so that we can update them with dead/kill markers.
|
||||||
|
std::map<unsigned, std::pair<MachineInstr*, unsigned> > LastUseDef;
|
||||||
|
for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end();
|
||||||
|
I != E; ++I) {
|
||||||
|
for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i) {
|
||||||
|
MachineOperand& MO = I->getOperand(i);
|
||||||
|
// Uses don't trigger any flags, but we need to save
|
||||||
|
// them for later. Also, we have to process these
|
||||||
|
// _before_ processing the defs, since an instr
|
||||||
|
// uses regs before it defs them.
|
||||||
|
if (MO.isReg() && MO.getReg() && MO.isUse())
|
||||||
|
LastUseDef[MO.getReg()] = std::make_pair(I, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i) {
|
||||||
|
MachineOperand& MO = I->getOperand(i);
|
||||||
|
// Defs others than 2-addr redefs _do_ trigger flag changes:
|
||||||
|
// - A def followed by a def is dead
|
||||||
|
// - A use followed by a def is a kill
|
||||||
|
if (MO.isReg() && MO.getReg() && MO.isDef() &&
|
||||||
|
!I->isRegReDefinedByTwoAddr(MO.getReg())) {
|
||||||
|
std::map<unsigned, std::pair<MachineInstr*, unsigned> >::iterator
|
||||||
|
last = LastUseDef.find(MO.getReg());
|
||||||
|
if (last != LastUseDef.end()) {
|
||||||
|
MachineOperand& lastUD =
|
||||||
|
last->second.first->getOperand(last->second.second);
|
||||||
|
if (lastUD.isDef())
|
||||||
|
lastUD.setIsDead(true);
|
||||||
|
else if (lastUD.isUse())
|
||||||
|
lastUD.setIsKill(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
LastUseDef[MO.getReg()] = std::make_pair(I, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Live-out (of the function) registers contain return values of the function,
|
||||||
|
// so we need to make sure they are alive at return time.
|
||||||
|
if (!MBB.empty() && MBB.back().getDesc().isReturn()) {
|
||||||
|
MachineInstr* Ret = &MBB.back();
|
||||||
|
for (MachineRegisterInfo::liveout_iterator
|
||||||
|
I = MF->getRegInfo().liveout_begin(),
|
||||||
|
E = MF->getRegInfo().liveout_end(); I != E; ++I)
|
||||||
|
if (!Ret->readsRegister(*I)) {
|
||||||
|
Ret->addOperand(MachineOperand::CreateReg(*I, false, true));
|
||||||
|
LastUseDef[*I] = std::make_pair(Ret, Ret->getNumOperands()-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, loop over the final use/def of each reg
|
||||||
|
// in the block and determine if it is dead.
|
||||||
|
for (std::map<unsigned, std::pair<MachineInstr*, unsigned> >::iterator
|
||||||
|
I = LastUseDef.begin(), E = LastUseDef.end(); I != E; ++I) {
|
||||||
|
MachineInstr* MI = I->second.first;
|
||||||
|
unsigned idx = I->second.second;
|
||||||
|
MachineOperand& MO = MI->getOperand(idx);
|
||||||
|
|
||||||
|
bool isPhysReg = TargetRegisterInfo::isPhysicalRegister(MO.getReg());
|
||||||
|
|
||||||
|
// A crude approximation of "live-out" calculation
|
||||||
|
bool usedOutsideBlock = isPhysReg ? false :
|
||||||
|
UsedInMultipleBlocks.test(MO.getReg() -
|
||||||
|
TargetRegisterInfo::FirstVirtualRegister);
|
||||||
|
if (!isPhysReg && !usedOutsideBlock)
|
||||||
|
for (MachineRegisterInfo::reg_iterator UI = MRI.reg_begin(MO.getReg()),
|
||||||
|
UE = MRI.reg_end(); UI != UE; ++UI)
|
||||||
|
// Two cases:
|
||||||
|
// - used in another block
|
||||||
|
// - used in the same block before it is defined (loop)
|
||||||
|
if (UI->getParent() != &MBB ||
|
||||||
|
(MO.isDef() && UI.getOperand().isUse() && precedes(*UI, MI))) {
|
||||||
|
UsedInMultipleBlocks.set(MO.getReg() -
|
||||||
|
TargetRegisterInfo::FirstVirtualRegister);
|
||||||
|
usedOutsideBlock = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Physical registers and those that are not live-out of the block
|
||||||
|
// are killed/dead at their last use/def within this block.
|
||||||
|
if (isPhysReg || !usedOutsideBlock) {
|
||||||
|
if (MO.isUse())
|
||||||
|
MO.setIsKill(true);
|
||||||
|
else if (MI->getOperand(idx).isDef())
|
||||||
|
MO.setIsDead(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Otherwise, sequentially allocate each instruction in the MBB.
|
// Otherwise, sequentially allocate each instruction in the MBB.
|
||||||
while (MII != MBB.end()) {
|
while (MII != MBB.end()) {
|
||||||
MachineInstr *MI = MII++;
|
MachineInstr *MI = MII++;
|
||||||
@ -802,7 +915,6 @@ void RALocal::AllocateBasicBlock(MachineBasicBlock &MBB) {
|
|||||||
PhysRegsUseOrder.clear();
|
PhysRegsUseOrder.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// runOnMachineFunction - Register allocate the whole function
|
/// runOnMachineFunction - Register allocate the whole function
|
||||||
///
|
///
|
||||||
bool RALocal::runOnMachineFunction(MachineFunction &Fn) {
|
bool RALocal::runOnMachineFunction(MachineFunction &Fn) {
|
||||||
@ -830,7 +942,8 @@ bool RALocal::runOnMachineFunction(MachineFunction &Fn) {
|
|||||||
Virt2PhysRegMap.grow(LastVirtReg);
|
Virt2PhysRegMap.grow(LastVirtReg);
|
||||||
Virt2LastUseMap.grow(LastVirtReg);
|
Virt2LastUseMap.grow(LastVirtReg);
|
||||||
VirtRegModified.resize(LastVirtReg+1-TargetRegisterInfo::FirstVirtualRegister);
|
VirtRegModified.resize(LastVirtReg+1-TargetRegisterInfo::FirstVirtualRegister);
|
||||||
|
UsedInMultipleBlocks.resize(LastVirtReg+1-TargetRegisterInfo::FirstVirtualRegister);
|
||||||
|
|
||||||
// Loop over all of the basic blocks, eliminating virtual register references
|
// Loop over all of the basic blocks, eliminating virtual register references
|
||||||
for (MachineFunction::iterator MBB = Fn.begin(), MBBe = Fn.end();
|
for (MachineFunction::iterator MBB = Fn.begin(), MBBe = Fn.end();
|
||||||
MBB != MBBe; ++MBB)
|
MBB != MBBe; ++MBB)
|
||||||
@ -839,6 +952,7 @@ bool RALocal::runOnMachineFunction(MachineFunction &Fn) {
|
|||||||
StackSlotForVirtReg.clear();
|
StackSlotForVirtReg.clear();
|
||||||
PhysRegsUsed.clear();
|
PhysRegsUsed.clear();
|
||||||
VirtRegModified.clear();
|
VirtRegModified.clear();
|
||||||
|
UsedInMultipleBlocks.clear();
|
||||||
Virt2PhysRegMap.clear();
|
Virt2PhysRegMap.clear();
|
||||||
Virt2LastUseMap.clear();
|
Virt2LastUseMap.clear();
|
||||||
return true;
|
return true;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user