More accurate estimate / tracking of register pressure.

- Initial register pressure in the loop should be all the live defs into the
  loop. Not just those from loop preheader which is often empty.
- When an instruction is hoisted, update register pressure from loop preheader
  to the original BB.
- Treat only use of a virtual register as kill since the code is still SSA.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@116956 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Evan Cheng 2010-10-20 22:03:58 +00:00
parent e4d31593c5
commit 134982daa9
3 changed files with 136 additions and 66 deletions

View File

@ -37,7 +37,6 @@
#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/Statistic.h" #include "llvm/ADT/Statistic.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h" #include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h" #include "llvm/Support/raw_ostream.h"
@ -176,10 +175,15 @@ namespace {
/// it 'high'. /// it 'high'.
bool HasHighOperandLatency(MachineInstr &MI, unsigned DefIdx, unsigned Reg); bool HasHighOperandLatency(MachineInstr &MI, unsigned DefIdx, unsigned Reg);
/// IncreaseHighRegPressure - Visit BBs from preheader to current BB, check /// CanCauseHighRegPressure - Visit BBs from header to current BB,
/// if hoisting an instruction of the given cost matrix can cause high /// check if hoisting an instruction of the given cost matrix can cause high
/// register pressure. /// register pressure.
bool IncreaseHighRegPressure(DenseMap<unsigned, int> &Cost); bool CanCauseHighRegPressure(DenseMap<unsigned, int> &Cost);
/// UpdateBackTraceRegPressure - Traverse the back trace from header to
/// the current block and update their register pressures to reflect the
/// effect of hoisting MI from the current block to the preheader.
void UpdateBackTraceRegPressure(const MachineInstr *MI);
/// 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.
@ -198,11 +202,9 @@ namespace {
/// this 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 /// UpdateRegPressure - Update estimate of register pressure after the
/// register pressure before and after executing a specifi instruction. /// specified instruction.
void UpdateRegPressureBefore(const MachineInstr *MI, void UpdateRegPressure(const MachineInstr *MI);
SmallVector<unsigned, 4> &Defs);
void UpdateRegPressureAfter(SmallVector<unsigned, 4> &Defs);
/// isLoadFromConstantMemory - Return true if the given instruction is a /// isLoadFromConstantMemory - Return true if the given instruction is a
/// load from constant memory. /// load from constant memory.
@ -228,8 +230,8 @@ namespace {
/// Hoist - When an instruction is found to only use loop invariant operands /// Hoist - When an instruction is found to only use loop invariant operands
/// that is safe to hoist, this instruction is called to do the dirty work. /// that is safe to hoist, this instruction is called to do the dirty work.
/// /// It returns true if the instruction is hoisted.
void Hoist(MachineInstr *MI, MachineBasicBlock *Preheader); bool Hoist(MachineInstr *MI, MachineBasicBlock *Preheader);
/// InitCSEMap - Initialize the CSE map with instructions that are in the /// InitCSEMap - Initialize the CSE map with instructions that are in the
/// current loop preheader that may become duplicates of instructions that /// current loop preheader that may become duplicates of instructions that
@ -559,7 +561,7 @@ void MachineLICM::HoistRegion(MachineDomTreeNode *N, bool IsHeader) {
return; return;
if (IsHeader) { if (IsHeader) {
// Compute registers which are liveout of preheader. // Compute registers which are livein into the loop headers.
RegSeen.clear(); RegSeen.clear();
BackTrace.clear(); BackTrace.clear();
InitRegPressure(Preheader); InitRegPressure(Preheader);
@ -568,17 +570,12 @@ void MachineLICM::HoistRegion(MachineDomTreeNode *N, bool IsHeader) {
// Remember livein register pressure. // Remember livein register pressure.
BackTrace.push_back(RegPressure); BackTrace.push_back(RegPressure);
SmallVector<unsigned, 4> Defs;
for (MachineBasicBlock::iterator for (MachineBasicBlock::iterator
MII = BB->begin(), E = BB->end(); MII != E; ) { MII = BB->begin(), E = BB->end(); MII != E; ) {
MachineBasicBlock::iterator NextMII = MII; ++NextMII; MachineBasicBlock::iterator NextMII = MII; ++NextMII;
MachineInstr *MI = &*MII; MachineInstr *MI = &*MII;
if (!Hoist(MI, Preheader))
assert(Defs.empty()); UpdateRegPressure(MI);
UpdateRegPressureBefore(MI, Defs);
Hoist(MI, Preheader);
UpdateRegPressureAfter(Defs);
MII = NextMII; MII = NextMII;
} }
@ -594,12 +591,27 @@ void MachineLICM::HoistRegion(MachineDomTreeNode *N, bool IsHeader) {
BackTrace.pop_back(); BackTrace.pop_back();
} }
static bool isOperandKill(const MachineOperand &MO, MachineRegisterInfo *MRI) {
return MO.isKill() || MRI->hasOneNonDBGUse(MO.getReg());
}
/// InitRegPressure - Find all virtual register references that are liveout of /// InitRegPressure - Find all virtual register references that are liveout of
/// the preheader to initialize the starting "register pressure". Note this /// the preheader to initialize the starting "register pressure". Note this
/// does 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) {
std::fill(RegPressure.begin(), RegPressure.end(), 0); std::fill(RegPressure.begin(), RegPressure.end(), 0);
// If the preheader has only a single predecessor and it ends with a
// fallthrough or an unconditional branch, then scan its predecessor for live
// defs as well. This happens whenever the preheader is created by splitting
// the critical edge from the loop predecessor to the loop header.
if (BB->pred_size() == 1) {
MachineBasicBlock *TBB = 0, *FBB = 0;
SmallVector<MachineOperand, 4> Cond;
if (!TII->AnalyzeBranch(*BB, TBB, FBB, Cond, false) && Cond.empty())
InitRegPressure(*BB->pred_begin());
}
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;
@ -618,22 +630,24 @@ void MachineLICM::InitRegPressure(MachineBasicBlock *BB) {
if (MO.isDef()) if (MO.isDef())
RegPressure[RCId] += TLI->getRepRegClassCostFor(VT); RegPressure[RCId] += TLI->getRepRegClassCostFor(VT);
else { else {
if (isNew && !MO.isKill()) bool isKill = isOperandKill(MO, MRI);
if (isNew && !isKill)
// Haven't seen this, it must be a livein. // Haven't seen this, it must be a livein.
RegPressure[RCId] += TLI->getRepRegClassCostFor(VT); RegPressure[RCId] += TLI->getRepRegClassCostFor(VT);
else if (!isNew && MO.isKill()) else if (!isNew && isKill)
RegPressure[RCId] -= TLI->getRepRegClassCostFor(VT); RegPressure[RCId] -= TLI->getRepRegClassCostFor(VT);
} }
} }
} }
} }
/// UpdateRegPressureBefore / UpdateRegPressureAfter - Update estimate of /// UpdateRegPressure - Update estimate of register pressure after the
/// register pressure before and after executing a specifi instruction. /// specified instruction.
void MachineLICM::UpdateRegPressureBefore(const MachineInstr *MI, void MachineLICM::UpdateRegPressure(const MachineInstr *MI) {
SmallVector<unsigned, 4> &Defs) { if (MI->isImplicitDef())
bool NoImpact = MI->isImplicitDef() || MI->isPHI(); return;
SmallVector<unsigned, 4> Defs;
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())
@ -643,29 +657,23 @@ void MachineLICM::UpdateRegPressureBefore(const MachineInstr *MI,
continue; continue;
bool isNew = RegSeen.insert(Reg); bool isNew = RegSeen.insert(Reg);
if (NoImpact)
continue;
if (MO.isDef()) if (MO.isDef())
Defs.push_back(Reg); Defs.push_back(Reg);
else { else if (!isNew && isOperandKill(MO, MRI)) {
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(); unsigned RCCost = TLI->getRepRegClassCostFor(VT);
unsigned RCCost = TLI->getRepRegClassCostFor(VT);
assert(RCCost <= RegPressure[RCId]); if (RCCost > RegPressure[RCId])
RegPressure[RCId] = 0;
else
RegPressure[RCId] -= RCCost; RegPressure[RCId] -= RCCost;
}
} }
} }
}
void MachineLICM::UpdateRegPressureAfter(SmallVector<unsigned, 4> &Defs) {
while (!Defs.empty()) { while (!Defs.empty()) {
unsigned Reg = Defs.pop_back_val(); unsigned Reg = Defs.pop_back_val();
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();
@ -815,31 +823,74 @@ bool MachineLICM::HasHighOperandLatency(MachineInstr &MI,
return false; return false;
} }
/// IncreaseHighRegPressure - Visit BBs from preheader to current BB, check /// CanCauseHighRegPressure - Visit BBs from header to current BB, check
/// if hoisting an instruction of the given cost matrix can cause high /// if hoisting an instruction of the given cost matrix can cause high
/// register pressure. /// register pressure.
bool MachineLICM::IncreaseHighRegPressure(DenseMap<unsigned, int> &Cost) { bool MachineLICM::CanCauseHighRegPressure(DenseMap<unsigned, int> &Cost) {
for (unsigned i = BackTrace.size(); i != 0; --i) { for (DenseMap<unsigned, int>::iterator CI = Cost.begin(), CE = Cost.end();
bool AnyIncrease = false; CI != CE; ++CI) {
SmallVector<unsigned, 8> &RP = BackTrace[i-1]; if (CI->second <= 0)
for (DenseMap<unsigned, int>::iterator CI = Cost.begin(), CE = Cost.end(); continue;
CI != CE; ++CI) {
if (CI->second <= 0) unsigned RCId = CI->first;
continue; for (unsigned i = BackTrace.size(); i != 0; --i) {
AnyIncrease = true; SmallVector<unsigned, 8> &RP = BackTrace[i-1];
unsigned RCId = CI->first;
if (RP[RCId] + CI->second >= RegLimit[RCId]) if (RP[RCId] + CI->second >= RegLimit[RCId])
return true; return true;
} }
if (!AnyIncrease)
// Hoisting the instruction doesn't increase register pressure.
return false;
} }
return false; return false;
} }
/// UpdateBackTraceRegPressure - Traverse the back trace from header to the
/// current block and update their register pressures to reflect the effect
/// of hoisting MI from the current block to the preheader.
void MachineLICM::UpdateBackTraceRegPressure(const MachineInstr *MI) {
if (MI->isImplicitDef())
return;
// First compute the 'cost' of the instruction, i.e. its contribution
// to register pressure.
DenseMap<unsigned, int> Cost;
for (unsigned i = 0, e = MI->getDesc().getNumOperands(); i != e; ++i) {
const MachineOperand &MO = MI->getOperand(i);
if (!MO.isReg() || MO.isImplicit())
continue;
unsigned Reg = MO.getReg();
if (!Reg || TargetRegisterInfo::isPhysicalRegister(Reg))
continue;
const TargetRegisterClass *RC = MRI->getRegClass(Reg);
EVT VT = *RC->vt_begin();
unsigned RCId = TLI->getRepRegClassFor(VT)->getID();
unsigned RCCost = TLI->getRepRegClassCostFor(VT);
if (MO.isDef()) {
DenseMap<unsigned, int>::iterator CI = Cost.find(RCId);
if (CI != Cost.end())
CI->second += RCCost;
else
Cost.insert(std::make_pair(RCId, RCCost));
} else if (isOperandKill(MO, MRI)) {
DenseMap<unsigned, int>::iterator CI = Cost.find(RCId);
if (CI != Cost.end())
CI->second -= RCCost;
else
Cost.insert(std::make_pair(RCId, -RCCost));
}
}
// Update register pressure of blocks from loop header to current block.
for (unsigned i = 0, e = BackTrace.size(); i != e; ++i) {
SmallVector<unsigned, 8> &RP = BackTrace[i];
for (DenseMap<unsigned, int>::iterator CI = Cost.begin(), CE = Cost.end();
CI != CE; ++CI) {
unsigned RCId = CI->first;
RP[RCId] += CI->second;
}
}
}
/// 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) {
@ -881,17 +932,14 @@ bool MachineLICM::IsProfitableToHoist(MachineInstr &MI) {
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); DenseMap<unsigned, int>::iterator CI = Cost.find(RCId);
// If the instruction is not register pressure neutrail (or better),
// check if hoisting it will cause high register pressure in BB's
// leading up to this point.
if (CI != Cost.end()) if (CI != Cost.end())
CI->second += RCCost; CI->second += RCCost;
else else
Cost.insert(std::make_pair(RCId, RCCost)); Cost.insert(std::make_pair(RCId, RCCost));
} else if (MO.isKill()) { } else if (isOperandKill(MO, MRI)) {
// Is a virtual register use is a kill, hoisting it out of the loop // Is a virtual register use is a kill, hoisting it out of the loop
// may actually reduce register pressure or be register pressure // may actually reduce register pressure or be register pressure
// neutral // neutral.
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();
@ -904,9 +952,9 @@ bool MachineLICM::IsProfitableToHoist(MachineInstr &MI) {
} }
} }
// Visit BBs from preheader to current BB, if hoisting this doesn't cause // Visit BBs from header to current BB, if hoisting this doesn't cause
// high register pressure, then it's safe to proceed. // high register pressure, then it's safe to proceed.
if (!IncreaseHighRegPressure(Cost)) { if (!CanCauseHighRegPressure(Cost)) {
++NumLowRP; ++NumLowRP;
return true; return true;
} }
@ -979,6 +1027,10 @@ MachineInstr *MachineLICM::ExtractHoistableLoad(MachineInstr *MI) {
NewMIs[1]->eraseFromParent(); NewMIs[1]->eraseFromParent();
return 0; return 0;
} }
// Update register pressure for the unfolded instruction.
UpdateRegPressure(NewMIs[1]);
// Otherwise we successfully unfolded a load that we can hoist. // Otherwise we successfully unfolded a load that we can hoist.
MI->eraseFromParent(); MI->eraseFromParent();
return NewMIs[0]; return NewMIs[0];
@ -1053,12 +1105,12 @@ bool MachineLICM::EliminateCSE(MachineInstr *MI,
/// Hoist - When an instruction is found to use only loop invariant operands /// Hoist - When an instruction is found to use only loop invariant operands
/// that are safe to hoist, this instruction is called to do the dirty work. /// that are safe to hoist, this instruction is called to do the dirty work.
/// ///
void MachineLICM::Hoist(MachineInstr *MI, MachineBasicBlock *Preheader) { bool MachineLICM::Hoist(MachineInstr *MI, MachineBasicBlock *Preheader) {
// First check whether we should hoist this instruction. // First check whether we should hoist this instruction.
if (!IsLoopInvariantInst(*MI) || !IsProfitableToHoist(*MI)) { if (!IsLoopInvariantInst(*MI) || !IsProfitableToHoist(*MI)) {
// If not, try unfolding a hoistable load. // If not, try unfolding a hoistable load.
MI = ExtractHoistableLoad(MI); MI = ExtractHoistableLoad(MI);
if (!MI) return; if (!MI) return false;
} }
// Now move the instructions to the predecessor, inserting it before any // Now move the instructions to the predecessor, inserting it before any
@ -1089,6 +1141,9 @@ void MachineLICM::Hoist(MachineInstr *MI, MachineBasicBlock *Preheader) {
// Otherwise, splice the instruction to the preheader. // Otherwise, splice the instruction to the preheader.
Preheader->splice(Preheader->getFirstTerminator(),MI->getParent(),MI); Preheader->splice(Preheader->getFirstTerminator(),MI->getParent(),MI);
// Update register pressure for BBs from header to this block.
UpdateBackTraceRegPressure(MI);
// Clear the kill flags of any register this instruction defines, // Clear the kill flags of any register this instruction defines,
// since they may need to be live throughout the entire loop // since they may need to be live throughout the entire loop
// rather than just live for part of it. // rather than just live for part of it.
@ -1110,6 +1165,8 @@ void MachineLICM::Hoist(MachineInstr *MI, MachineBasicBlock *Preheader) {
++NumHoisted; ++NumHoisted;
Changed = true; Changed = true;
return true;
} }
MachineBasicBlock *MachineLICM::getCurPreheader() { MachineBasicBlock *MachineLICM::getCurPreheader() {

View File

@ -1,15 +1,23 @@
; RUN: llc < %s -mtriple=thumbv7-apple-darwin9 -mcpu=cortex-a8 | grep vmov.f32 | count 1 ; RUN: llc < %s -mtriple=thumbv7-apple-darwin9 -mcpu=cortex-a8 | FileCheck %s
define void @fht(float* nocapture %fz, i16 signext %n) nounwind { define void @fht(float* nocapture %fz, i16 signext %n) nounwind {
; CHECK: fht:
entry: entry:
br label %bb5 br label %bb5
bb5: ; preds = %bb5, %entry bb5: ; preds = %bb5, %entry
; CHECK: %bb5
; CHECK: bne
br i1 undef, label %bb5, label %bb.nph br i1 undef, label %bb5, label %bb.nph
bb.nph: ; preds = %bb5 bb.nph: ; preds = %bb5
br label %bb7 br label %bb7
; Loop preheader
; CHECK: vmov.f32
; CHECK: vmul.f32
; CHECK: vsub.f32
; CHECK: vadd.f32
bb7: ; preds = %bb9, %bb.nph bb7: ; preds = %bb9, %bb.nph
%s1.02 = phi float [ undef, %bb.nph ], [ %35, %bb9 ] ; <float> [#uses=3] %s1.02 = phi float [ undef, %bb.nph ], [ %35, %bb9 ] ; <float> [#uses=3]
%tmp79 = add i32 undef, undef ; <i32> [#uses=1] %tmp79 = add i32 undef, undef ; <i32> [#uses=1]
@ -19,6 +27,9 @@ bb7: ; preds = %bb9, %bb.nph
br label %bb8 br label %bb8
bb8: ; preds = %bb8, %bb7 bb8: ; preds = %bb8, %bb7
; CHECK: %bb8
; CHECK-NOT: vmov.f32
; CHECK: blt
%tmp54 = add i32 0, %tmp53 ; <i32> [#uses=0] %tmp54 = add i32 0, %tmp53 ; <i32> [#uses=0]
%fi.1 = getelementptr float* %fz, i32 undef ; <float*> [#uses=2] %fi.1 = getelementptr float* %fz, i32 undef ; <float*> [#uses=2]
%tmp80 = add i32 0, %tmp79 ; <i32> [#uses=1] %tmp80 = add i32 0, %tmp79 ; <i32> [#uses=1]
@ -62,6 +73,8 @@ bb8: ; preds = %bb8, %bb7
br i1 %34, label %bb8, label %bb9 br i1 %34, label %bb8, label %bb9
bb9: ; preds = %bb8 bb9: ; preds = %bb8
; CHECK: %bb9
; CHECK: vmov.f32
%35 = fadd float 0.000000e+00, undef ; <float> [#uses=1] %35 = fadd float 0.000000e+00, undef ; <float> [#uses=1]
br label %bb7 br label %bb7
} }

View File

@ -1,4 +1,4 @@
; RUN: llc < %s -march=x86-64 -mattr=+sse3,+sse41 -stats |& grep {7 machine-licm} ; RUN: llc < %s -march=x86-64 -mattr=+sse3,+sse41 -stats |& grep {8 machine-licm}
; RUN: llc < %s -march=x86-64 -mattr=+sse3,+sse41 | FileCheck %s ; RUN: llc < %s -march=x86-64 -mattr=+sse3,+sse41 | FileCheck %s
; rdar://6627786 ; rdar://6627786
; rdar://7792037 ; rdar://7792037