More machine LICM work. It now tracks register pressure for path from preheader to current BB and use the information determine whether hoisting is worthwhile.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@116654 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Evan Cheng 2010-10-16 02:20:26 +00:00
parent 47650ece37
commit 03a9fdf2e7

View File

@ -48,8 +48,14 @@ TrackRegPressure("rp-aware-machine-licm",
cl::desc("Register pressure aware machine LICM"), cl::desc("Register pressure aware machine LICM"),
cl::init(false), cl::Hidden); cl::init(false), cl::Hidden);
STATISTIC(NumHoisted, "Number of machine instructions hoisted out of loops"); STATISTIC(NumHoisted,
STATISTIC(NumCSEed, "Number of hoisted machine instructions CSEed"); "Number of machine instructions hoisted out of loops");
STATISTIC(NumLowRP,
"Number of instructions hoisted in low reg pressure situation");
STATISTIC(NumHighLatency,
"Number of high latency instructions hoisted");
STATISTIC(NumCSEed,
"Number of hoisted machine instructions CSEed");
STATISTIC(NumPostRAHoisted, STATISTIC(NumPostRAHoisted,
"Number of machine instructions hoisted out of loops post regalloc"); "Number of machine instructions hoisted out of loops post regalloc");
@ -79,9 +85,16 @@ namespace {
BitVector AllocatableSet; BitVector AllocatableSet;
// Track 'estimated' register pressure. // Track 'estimated' register pressure.
SmallSet<unsigned, 32> RegSeen;
SmallVector<unsigned, 8> RegPressure; SmallVector<unsigned, 8> RegPressure;
// Register pressure "limit" per register class. If the pressure
// is higher than the limit, then it's considered high.
SmallVector<unsigned, 8> RegLimit; SmallVector<unsigned, 8> RegLimit;
// Register pressure on path leading from loop preheader to current BB.
SmallVector<SmallVector<unsigned, 8>, 16> BackTrace;
// For each opcode, keep a list of potential CSE instructions. // For each opcode, keep a list of potential CSE instructions.
DenseMap<unsigned, std::vector<const MachineInstr*> > CSEMap; DenseMap<unsigned, std::vector<const MachineInstr*> > CSEMap;
@ -108,8 +121,12 @@ namespace {
} }
virtual void releaseMemory() { virtual void releaseMemory() {
RegSeen.clear();
RegPressure.clear(); RegPressure.clear();
RegLimit.clear(); RegLimit.clear();
for (DenseMap<unsigned,std::vector<const MachineInstr*> >::iterator
CI = CSEMap.begin(), CE = CSEMap.end(); CI != CE; ++CI)
CI->second.clear();
CSEMap.clear(); CSEMap.clear();
} }
@ -158,6 +175,11 @@ namespace {
/// and an use in the current loop. /// and an use in the current loop.
int ComputeOperandLatency(MachineInstr &MI, unsigned DefIdx, unsigned Reg); int ComputeOperandLatency(MachineInstr &MI, unsigned DefIdx, unsigned Reg);
/// IncreaseHighRegPressure - Visit BBs from preheader to current BB, check
/// if hoisting an instruction of the given cost matrix can cause high
/// register pressure.
bool IncreaseHighRegPressure(DenseMap<unsigned, int> &Cost);
/// IsProfitableToHoist - Return true if it is potentially profitable to /// IsProfitableToHoist - Return true if it is potentially profitable to
/// hoist the given loop invariant. /// hoist the given loop invariant.
bool IsProfitableToHoist(MachineInstr &MI); bool IsProfitableToHoist(MachineInstr &MI);
@ -168,11 +190,11 @@ namespace {
/// visit definitions before uses, allowing us to hoist a loop body in one /// visit definitions before uses, allowing us to hoist a loop body in one
/// pass without iteration. /// pass without iteration.
/// ///
void HoistRegion(MachineDomTreeNode *N); void HoistRegion(MachineDomTreeNode *N, bool IsHeader = false);
/// InitRegPressure - Find all virtual register references that are livein /// InitRegPressure - Find all virtual register references that are liveout
/// to the block to initialize the starting "register pressure". Note this /// of the preheader to initialize the starting "register pressure". Note
/// does not count live through (livein but not used) registers. /// this does not count live through (livein but not used) registers.
void InitRegPressure(MachineBasicBlock *BB); void InitRegPressure(MachineBasicBlock *BB);
/// UpdateRegPressureBefore / UpdateRegPressureAfter - Update estimate of /// UpdateRegPressureBefore / UpdateRegPressureAfter - Update estimate of
@ -247,9 +269,10 @@ static bool LoopIsOuterMostWithPredecessor(MachineLoop *CurLoop) {
bool MachineLICM::runOnMachineFunction(MachineFunction &MF) { bool MachineLICM::runOnMachineFunction(MachineFunction &MF) {
if (PreRegAlloc) if (PreRegAlloc)
DEBUG(dbgs() << "******** Pre-regalloc Machine LICM ********\n"); DEBUG(dbgs() << "******** Pre-regalloc Machine LICM: ");
else else
DEBUG(dbgs() << "******** Post-regalloc Machine LICM ********\n"); DEBUG(dbgs() << "******** Post-regalloc Machine LICM: ");
DEBUG(dbgs() << MF.getFunction()->getName() << " ********\n");
Changed = FirstInLoop = false; Changed = FirstInLoop = false;
TM = &MF.getTarget(); TM = &MF.getTarget();
@ -265,8 +288,8 @@ bool MachineLICM::runOnMachineFunction(MachineFunction &MF) {
// Estimate register pressure during pre-regalloc pass. // Estimate register pressure during pre-regalloc pass.
unsigned NumRC = TRI->getNumRegClasses(); unsigned NumRC = TRI->getNumRegClasses();
RegPressure.resize(NumRC); RegPressure.resize(NumRC);
RegLimit.resize(NumRC);
std::fill(RegPressure.begin(), RegPressure.end(), 0); std::fill(RegPressure.begin(), RegPressure.end(), 0);
RegLimit.resize(NumRC);
for (TargetRegisterInfo::regclass_iterator I = TRI->regclass_begin(), for (TargetRegisterInfo::regclass_iterator I = TRI->regclass_begin(),
E = TRI->regclass_end(); I != E; ++I) E = TRI->regclass_end(); I != E; ++I)
RegLimit[(*I)->getID()] = TLI->getRegPressureLimit(*I, MF); RegLimit[(*I)->getID()] = TLI->getRegPressureLimit(*I, MF);
@ -296,7 +319,7 @@ bool MachineLICM::runOnMachineFunction(MachineFunction &MF) {
// being hoisted. // being hoisted.
MachineDomTreeNode *N = DT->getNode(CurLoop->getHeader()); MachineDomTreeNode *N = DT->getNode(CurLoop->getHeader());
FirstInLoop = true; FirstInLoop = true;
HoistRegion(N); HoistRegion(N, true);
CSEMap.clear(); CSEMap.clear();
} }
} }
@ -522,7 +545,7 @@ void MachineLICM::HoistPostRA(MachineInstr *MI, unsigned Def) {
/// first order w.r.t the DominatorTree. This allows us to visit definitions /// first order w.r.t the DominatorTree. This allows us to visit definitions
/// before uses, allowing us to hoist a loop body in one pass without iteration. /// before uses, allowing us to hoist a loop body in one pass without iteration.
/// ///
void MachineLICM::HoistRegion(MachineDomTreeNode *N) { void MachineLICM::HoistRegion(MachineDomTreeNode *N, bool IsHeader) {
assert(N != 0 && "Null dominator tree node?"); assert(N != 0 && "Null dominator tree node?");
MachineBasicBlock *BB = N->getBlock(); MachineBasicBlock *BB = N->getBlock();
@ -530,9 +553,20 @@ void MachineLICM::HoistRegion(MachineDomTreeNode *N) {
if (!CurLoop->contains(BB)) return; if (!CurLoop->contains(BB)) return;
MachineBasicBlock *Preheader = getCurPreheader(); MachineBasicBlock *Preheader = getCurPreheader();
if (Preheader) { if (!Preheader)
if (TrackRegPressure) return;
InitRegPressure(BB);
if (TrackRegPressure) {
if (IsHeader) {
// Compute registers which are liveout of preheader.
RegSeen.clear();
BackTrace.clear();
InitRegPressure(Preheader);
}
// Remember livein register pressure.
BackTrace.push_back(RegPressure);
}
for (MachineBasicBlock::iterator for (MachineBasicBlock::iterator
MII = BB->begin(), E = BB->end(); MII != E; ) { MII = BB->begin(), E = BB->end(); MII != E; ) {
@ -547,7 +581,6 @@ void MachineLICM::HoistRegion(MachineDomTreeNode *N) {
MII = NextMII; MII = NextMII;
} }
}
// Don't hoist things out of a large switch statement. This often causes // Don't hoist things out of a large switch statement. This often causes
// code to be hoisted that wasn't going to be executed, and increases // code to be hoisted that wasn't going to be executed, and increases
@ -557,15 +590,17 @@ void MachineLICM::HoistRegion(MachineDomTreeNode *N) {
for (unsigned I = 0, E = Children.size(); I != E; ++I) for (unsigned I = 0, E = Children.size(); I != E; ++I)
HoistRegion(Children[I]); HoistRegion(Children[I]);
} }
if (TrackRegPressure)
BackTrace.pop_back();
} }
/// InitRegPressure - Find all virtual register references that are livein to /// InitRegPressure - Find all virtual register references that are liveout of
/// the block to initialize the starting "register pressure". Note this does /// the preheader to initialize the starting "register pressure". Note this
/// not count live through (livein but not used) registers. /// does not count live through (livein but not used) registers.
void MachineLICM::InitRegPressure(MachineBasicBlock *BB) { void MachineLICM::InitRegPressure(MachineBasicBlock *BB) {
SmallSet<unsigned, 16> Seen;
std::fill(RegPressure.begin(), RegPressure.end(), 0); std::fill(RegPressure.begin(), RegPressure.end(), 0);
for (MachineBasicBlock::iterator MII = BB->begin(), E = BB->end(); for (MachineBasicBlock::iterator MII = BB->begin(), E = BB->end();
MII != E; ++MII) { MII != E; ++MII) {
MachineInstr *MI = &*MII; MachineInstr *MI = &*MII;
@ -576,14 +611,20 @@ void MachineLICM::InitRegPressure(MachineBasicBlock *BB) {
unsigned Reg = MO.getReg(); unsigned Reg = MO.getReg();
if (!Reg || TargetRegisterInfo::isPhysicalRegister(Reg)) if (!Reg || TargetRegisterInfo::isPhysicalRegister(Reg))
continue; continue;
if (!Seen.insert(Reg))
continue;
// Must be a livein. bool isNew = !RegSeen.insert(Reg);
const TargetRegisterClass *RC = MRI->getRegClass(Reg); const TargetRegisterClass *RC = MRI->getRegClass(Reg);
EVT VT = *RC->vt_begin(); EVT VT = *RC->vt_begin();
unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); unsigned RCId = TLI->getRepRegClassFor(VT)->getID();
if (MO.isDef())
RegPressure[RCId] += TLI->getRepRegClassCostFor(VT); RegPressure[RCId] += TLI->getRepRegClassCostFor(VT);
else {
if (isNew && !MO.isKill())
// Haven't seen this, it must be a livein.
RegPressure[RCId] += TLI->getRepRegClassCostFor(VT);
else if (!isNew && MO.isKill())
RegPressure[RCId] -= TLI->getRepRegClassCostFor(VT);
}
} }
} }
} }
@ -591,17 +632,21 @@ void MachineLICM::InitRegPressure(MachineBasicBlock *BB) {
/// UpdateRegPressureBefore / UpdateRegPressureAfter - Update estimate of /// UpdateRegPressureBefore / UpdateRegPressureAfter - Update estimate of
/// register pressure before and after executing a specifi instruction. /// register pressure before and after executing a specifi instruction.
void MachineLICM::UpdateRegPressureBefore(const MachineInstr *MI) { void MachineLICM::UpdateRegPressureBefore(const MachineInstr *MI) {
if (MI->isImplicitDef() || MI->isPHI()) bool NoImpact = MI->isImplicitDef() || MI->isPHI();
return;
for (unsigned i = 0, e = MI->getDesc().getNumOperands(); i != e; ++i) { for (unsigned i = 0, e = MI->getDesc().getNumOperands(); i != e; ++i) {
const MachineOperand &MO = MI->getOperand(i); const MachineOperand &MO = MI->getOperand(i);
if (!MO.isReg() || MO.isImplicit() || !MO.isUse() || !MO.isKill()) if (!MO.isReg() || MO.isImplicit() || !MO.isUse())
continue; continue;
unsigned Reg = MO.getReg(); unsigned Reg = MO.getReg();
if (!Reg || TargetRegisterInfo::isPhysicalRegister(Reg)) if (!Reg || TargetRegisterInfo::isPhysicalRegister(Reg))
continue; continue;
bool isNew = !RegSeen.insert(Reg);
if (NoImpact)
continue;
if (!isNew && MO.isKill()) {
const TargetRegisterClass *RC = MRI->getRegClass(Reg); const TargetRegisterClass *RC = MRI->getRegClass(Reg);
EVT VT = *RC->vt_begin(); EVT VT = *RC->vt_begin();
unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); unsigned RCId = TLI->getRepRegClassFor(VT)->getID();
@ -611,10 +656,10 @@ void MachineLICM::UpdateRegPressureBefore(const MachineInstr *MI) {
RegPressure[RCId] -= RCCost; RegPressure[RCId] -= RCCost;
} }
} }
}
void MachineLICM::UpdateRegPressureAfter(const MachineInstr *MI) { void MachineLICM::UpdateRegPressureAfter(const MachineInstr *MI) {
if (MI->isImplicitDef() || MI->isPHI()) bool NoImpact = MI->isImplicitDef() || MI->isPHI();
return;
for (unsigned i = 0, e = MI->getDesc().getNumOperands(); i != e; ++i) { for (unsigned i = 0, e = MI->getDesc().getNumOperands(); i != e; ++i) {
const MachineOperand &MO = MI->getOperand(i); const MachineOperand &MO = MI->getOperand(i);
@ -624,6 +669,10 @@ void MachineLICM::UpdateRegPressureAfter(const MachineInstr *MI) {
if (!Reg || TargetRegisterInfo::isPhysicalRegister(Reg)) if (!Reg || TargetRegisterInfo::isPhysicalRegister(Reg))
continue; continue;
RegSeen.insert(Reg);
if (NoImpact)
continue;
const TargetRegisterClass *RC = MRI->getRegClass(Reg); const TargetRegisterClass *RC = MRI->getRegClass(Reg);
EVT VT = *RC->vt_begin(); EVT VT = *RC->vt_begin();
unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); unsigned RCId = TLI->getRepRegClassFor(VT)->getID();
@ -775,6 +824,31 @@ int MachineLICM::ComputeOperandLatency(MachineInstr &MI,
return Latency; return Latency;
} }
/// IncreaseHighRegPressure - Visit BBs from preheader to current BB, check
/// if hoisting an instruction of the given cost matrix can cause high
/// register pressure.
bool MachineLICM::IncreaseHighRegPressure(DenseMap<unsigned, int> &Cost) {
for (unsigned i = BackTrace.size(); i != 0; --i) {
bool AnyIncrease = false;
SmallVector<unsigned, 8> &RP = BackTrace[i-1];
for (DenseMap<unsigned, int>::iterator CI = Cost.begin(), CE = Cost.end();
CI != CE; ++CI) {
if (CI->second <= 0)
continue;
AnyIncrease = true;
unsigned RCId = CI->first;
if (RP[RCId] + CI->second >= RegLimit[RCId])
return true;
}
if (!AnyIncrease)
// Hoisting the instruction doesn't increase register pressure.
return false;
}
return false;
}
/// IsProfitableToHoist - Return true if it is potentially profitable to hoist /// IsProfitableToHoist - Return true if it is potentially profitable to hoist
/// the given loop invariant. /// the given loop invariant.
bool MachineLICM::IsProfitableToHoist(MachineInstr &MI) { bool MachineLICM::IsProfitableToHoist(MachineInstr &MI) {
@ -797,7 +871,7 @@ bool MachineLICM::IsProfitableToHoist(MachineInstr &MI) {
// In low register pressure situation, we can be more aggressive about // In low register pressure situation, we can be more aggressive about
// hoisting. Also, favors hoisting long latency instructions even in // hoisting. Also, favors hoisting long latency instructions even in
// moderately high pressure situation. // moderately high pressure situation.
int Delta = 0; DenseMap<unsigned, int> Cost;
for (unsigned i = 0, e = MI.getDesc().getNumOperands(); i != e; ++i) { for (unsigned i = 0, e = MI.getDesc().getNumOperands(); i != e; ++i) {
const MachineOperand &MO = MI.getOperand(i); const MachineOperand &MO = MI.getOperand(i);
if (!MO.isReg() || MO.isImplicit()) if (!MO.isReg() || MO.isImplicit())
@ -805,38 +879,50 @@ bool MachineLICM::IsProfitableToHoist(MachineInstr &MI) {
unsigned Reg = MO.getReg(); unsigned Reg = MO.getReg();
if (!Reg || TargetRegisterInfo::isPhysicalRegister(Reg)) if (!Reg || TargetRegisterInfo::isPhysicalRegister(Reg))
continue; continue;
if (MO.isDef()) {
if (InstrItins && !InstrItins->isEmpty()) {
int Cycle = ComputeOperandLatency(MI, i, Reg);
if (Cycle > 3) {
// FIXME: Target specific high latency limit?
++NumHighLatency;
return true;
}
}
const TargetRegisterClass *RC = MRI->getRegClass(Reg); const TargetRegisterClass *RC = MRI->getRegClass(Reg);
EVT VT = *RC->vt_begin(); EVT VT = *RC->vt_begin();
unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); unsigned RCId = TLI->getRepRegClassFor(VT)->getID();
unsigned RCCost = TLI->getRepRegClassCostFor(VT); unsigned RCCost = TLI->getRepRegClassCostFor(VT);
DenseMap<unsigned, int>::iterator CI = Cost.find(RCId);
if (MO.isUse()) { // If the instruction is not register pressure neutrail (or better),
if (RegPressure[RCId] >= RegLimit[RCId]) { // check if hoisting it will cause high register pressure in BB's
// Hoisting this instruction may actually reduce register pressure // leading up to this point.
// in the loop. if (CI != Cost.end())
int Pressure = RegPressure[RCId] - RCCost; CI->second += RCCost;
assert(Pressure >= 0); else
Delta -= (int)RegLimit[RCId] - Pressure; Cost.insert(std::make_pair(RCId, RCCost));
} } else if (MO.isKill()) {
} else { // Is a virtual register use is a kill, hoisting it out of the loop
if (InstrItins && !InstrItins->isEmpty()) { // may actually reduce register pressure or be register pressure
int Cycle = ComputeOperandLatency(MI, i, Reg); // neutral
if (Cycle > 3) const TargetRegisterClass *RC = MRI->getRegClass(Reg);
// FIXME: Target specific high latency limit? EVT VT = *RC->vt_begin();
return true; unsigned RCId = TLI->getRepRegClassFor(VT)->getID();
} unsigned RCCost = TLI->getRepRegClassCostFor(VT);
if (RegPressure[RCId] >= RegLimit[RCId]) DenseMap<unsigned, int>::iterator CI = Cost.find(RCId);
Delta += RCCost; if (CI != Cost.end())
else { CI->second -= RCCost;
int Pressure = RegPressure[RCId] + RCCost; else
if (Pressure > (int)RegLimit[RCId]) Cost.insert(std::make_pair(RCId, -RCCost));
Delta += Pressure - RegLimit[RCId];
}
} }
} }
if (Delta >= 0) // Visit BBs from preheader to current BB, if hoisting this doesn't cause
// high register pressure, then it's safe to proceed.
if (!IncreaseHighRegPressure(Cost)) {
++NumLowRP;
return true; return true;
}
// High register pressure situation, only hoist if the instruction is going to // High register pressure situation, only hoist if the instruction is going to
// be remat'ed. // be remat'ed.