forked from OSchip/llvm-project
Add option -licm-const-load to hoist all loads from constant memory.
llvm-svn: 89477
This commit is contained in:
parent
51c538bee4
commit
b39a9fd3ed
|
@ -34,11 +34,16 @@
|
||||||
#include "llvm/Analysis/AliasAnalysis.h"
|
#include "llvm/Analysis/AliasAnalysis.h"
|
||||||
#include "llvm/ADT/DenseMap.h"
|
#include "llvm/ADT/DenseMap.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"
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
|
static cl::opt<bool> HoistLdConst("licm-const-load",
|
||||||
|
cl::desc("LICM load from constant memory"),
|
||||||
|
cl::init(false), cl::Hidden);
|
||||||
|
|
||||||
STATISTIC(NumHoisted, "Number of machine instructions hoisted out of loops");
|
STATISTIC(NumHoisted, "Number of machine instructions hoisted out of loops");
|
||||||
STATISTIC(NumCSEed, "Number of hoisted machine instructions CSEed");
|
STATISTIC(NumCSEed, "Number of hoisted machine instructions CSEed");
|
||||||
|
|
||||||
|
@ -97,7 +102,7 @@ namespace {
|
||||||
|
|
||||||
/// 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, bool &isConstLd);
|
||||||
|
|
||||||
/// HoistRegion - Walk the specified region of the CFG (defined by all
|
/// HoistRegion - Walk the specified region of the CFG (defined by all
|
||||||
/// blocks dominated by the specified block, and that are in the current
|
/// blocks dominated by the specified block, and that are in the current
|
||||||
|
@ -107,6 +112,10 @@ namespace {
|
||||||
///
|
///
|
||||||
void HoistRegion(MachineDomTreeNode *N);
|
void HoistRegion(MachineDomTreeNode *N);
|
||||||
|
|
||||||
|
/// isLoadFromConstantMemory - Return true if the given instruction is a
|
||||||
|
/// load from constant memory.
|
||||||
|
bool isLoadFromConstantMemory(MachineInstr *MI);
|
||||||
|
|
||||||
/// ExtractHoistableLoad - Unfold a load from the given machineinstr if
|
/// ExtractHoistableLoad - Unfold a load from the given machineinstr if
|
||||||
/// the load itself could be hoisted. Return the unfolded and hoistable
|
/// the load itself could be hoisted. Return the unfolded and hoistable
|
||||||
/// load, or null if the load couldn't be unfolded or if it wouldn't
|
/// load, or null if the load couldn't be unfolded or if it wouldn't
|
||||||
|
@ -338,17 +347,45 @@ static bool HasPHIUses(unsigned Reg, MachineRegisterInfo *RegInfo) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// isLoadFromConstantMemory - Return true if the given instruction is a
|
||||||
|
/// load from constant memory. Machine LICM will hoist these even if they are
|
||||||
|
/// not re-materializable.
|
||||||
|
bool MachineLICM::isLoadFromConstantMemory(MachineInstr *MI) {
|
||||||
|
if (!MI->getDesc().mayLoad()) return false;
|
||||||
|
if (!MI->hasOneMemOperand()) return false;
|
||||||
|
MachineMemOperand *MMO = *MI->memoperands_begin();
|
||||||
|
if (MMO->isVolatile()) return false;
|
||||||
|
if (!MMO->getValue()) return false;
|
||||||
|
const PseudoSourceValue *PSV = dyn_cast<PseudoSourceValue>(MMO->getValue());
|
||||||
|
if (PSV) {
|
||||||
|
MachineFunction &MF = *MI->getParent()->getParent();
|
||||||
|
return PSV->isConstant(MF.getFrameInfo());
|
||||||
|
} else {
|
||||||
|
return AA->pointsToConstantMemory(MMO->getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 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, bool &isConstLd) {
|
||||||
|
isConstLd = false;
|
||||||
|
|
||||||
if (MI.getOpcode() == TargetInstrInfo::IMPLICIT_DEF)
|
if (MI.getOpcode() == TargetInstrInfo::IMPLICIT_DEF)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// FIXME: For now, only hoist re-materilizable instructions. LICM will
|
// FIXME: For now, only hoist re-materilizable instructions. LICM will
|
||||||
// increase register pressure. We want to make sure it doesn't increase
|
// increase register pressure. We want to make sure it doesn't increase
|
||||||
// spilling.
|
// spilling.
|
||||||
if (!TII->isTriviallyReMaterializable(&MI, AA))
|
// Also hoist loads from constant memory, e.g. load from stubs, GOT. Hoisting
|
||||||
return false;
|
// these tend to help performance in low register pressure situation. The
|
||||||
|
// trade off is it may cause spill in high pressure situation. It will end up
|
||||||
|
// adding a store in the loop preheader. But the reload is no more expensive.
|
||||||
|
// The side benefit is these loads are frequently CSE'ed.
|
||||||
|
if (!TII->isTriviallyReMaterializable(&MI, AA)) {
|
||||||
|
if (!HoistLdConst || !isLoadFromConstantMemory(&MI))
|
||||||
|
return false;
|
||||||
|
isConstLd = true;
|
||||||
|
}
|
||||||
|
|
||||||
// If result(s) of this instruction is used by PHIs, then don't hoist it.
|
// If result(s) of this instruction is used by PHIs, then don't hoist it.
|
||||||
// The presence of joins makes it difficult for current register allocator
|
// The presence of joins makes it difficult for current register allocator
|
||||||
|
@ -368,18 +405,9 @@ MachineInstr *MachineLICM::ExtractHoistableLoad(MachineInstr *MI) {
|
||||||
// If not, we may be able to unfold a load and hoist that.
|
// If not, we may be able to unfold a load and hoist that.
|
||||||
// First test whether the instruction is loading from an amenable
|
// First test whether the instruction is loading from an amenable
|
||||||
// memory location.
|
// memory location.
|
||||||
if (!MI->getDesc().mayLoad()) return 0;
|
if (!isLoadFromConstantMemory(MI))
|
||||||
if (!MI->hasOneMemOperand()) return 0;
|
return 0;
|
||||||
MachineMemOperand *MMO = *MI->memoperands_begin();
|
|
||||||
if (MMO->isVolatile()) return 0;
|
|
||||||
MachineFunction &MF = *MI->getParent()->getParent();
|
|
||||||
if (!MMO->getValue()) return 0;
|
|
||||||
if (const PseudoSourceValue *PSV =
|
|
||||||
dyn_cast<PseudoSourceValue>(MMO->getValue())) {
|
|
||||||
if (!PSV->isConstant(MF.getFrameInfo())) return 0;
|
|
||||||
} else {
|
|
||||||
if (!AA->pointsToConstantMemory(MMO->getValue())) return 0;
|
|
||||||
}
|
|
||||||
// Next determine the register class for a temporary register.
|
// Next determine the register class for a temporary register.
|
||||||
unsigned LoadRegIndex;
|
unsigned LoadRegIndex;
|
||||||
unsigned NewOpc =
|
unsigned NewOpc =
|
||||||
|
@ -393,6 +421,8 @@ MachineInstr *MachineLICM::ExtractHoistableLoad(MachineInstr *MI) {
|
||||||
const TargetRegisterClass *RC = TID.OpInfo[LoadRegIndex].getRegClass(TRI);
|
const TargetRegisterClass *RC = TID.OpInfo[LoadRegIndex].getRegClass(TRI);
|
||||||
// Ok, we're unfolding. Create a temporary register and do the unfold.
|
// Ok, we're unfolding. Create a temporary register and do the unfold.
|
||||||
unsigned Reg = RegInfo->createVirtualRegister(RC);
|
unsigned Reg = RegInfo->createVirtualRegister(RC);
|
||||||
|
|
||||||
|
MachineFunction &MF = *MI->getParent()->getParent();
|
||||||
SmallVector<MachineInstr *, 2> NewMIs;
|
SmallVector<MachineInstr *, 2> NewMIs;
|
||||||
bool Success =
|
bool Success =
|
||||||
TII->unfoldMemoryOperand(MF, MI, Reg,
|
TII->unfoldMemoryOperand(MF, MI, Reg,
|
||||||
|
@ -409,7 +439,9 @@ MachineInstr *MachineLICM::ExtractHoistableLoad(MachineInstr *MI) {
|
||||||
MBB->insert(MI, NewMIs[1]);
|
MBB->insert(MI, NewMIs[1]);
|
||||||
// If unfolding produced a load that wasn't loop-invariant or profitable to
|
// If unfolding produced a load that wasn't loop-invariant or profitable to
|
||||||
// hoist, discard the new instructions and bail.
|
// hoist, discard the new instructions and bail.
|
||||||
if (!IsLoopInvariantInst(*NewMIs[0]) || !IsProfitableToHoist(*NewMIs[0])) {
|
bool isConstLd;
|
||||||
|
if (!IsLoopInvariantInst(*NewMIs[0]) ||
|
||||||
|
!IsProfitableToHoist(*NewMIs[0], isConstLd)) {
|
||||||
NewMIs[0]->eraseFromParent();
|
NewMIs[0]->eraseFromParent();
|
||||||
NewMIs[1]->eraseFromParent();
|
NewMIs[1]->eraseFromParent();
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -475,7 +507,9 @@ bool MachineLICM::EliminateCSE(MachineInstr *MI,
|
||||||
///
|
///
|
||||||
void MachineLICM::Hoist(MachineInstr *MI) {
|
void MachineLICM::Hoist(MachineInstr *MI) {
|
||||||
// First check whether we should hoist this instruction.
|
// First check whether we should hoist this instruction.
|
||||||
if (!IsLoopInvariantInst(*MI) || !IsProfitableToHoist(*MI)) {
|
bool isConstLd;
|
||||||
|
if (!IsLoopInvariantInst(*MI) ||
|
||||||
|
!IsProfitableToHoist(*MI, isConstLd)) {
|
||||||
// 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;
|
||||||
|
@ -484,7 +518,10 @@ void MachineLICM::Hoist(MachineInstr *MI) {
|
||||||
// Now move the instructions to the predecessor, inserting it before any
|
// Now move the instructions to the predecessor, inserting it before any
|
||||||
// terminator instructions.
|
// terminator instructions.
|
||||||
DEBUG({
|
DEBUG({
|
||||||
errs() << "Hoisting " << *MI;
|
errs() << "Hoisting ";
|
||||||
|
if (isConstLd)
|
||||||
|
errs() << "load from constant mem ";
|
||||||
|
errs() << *MI;
|
||||||
if (CurPreheader->getBasicBlock())
|
if (CurPreheader->getBasicBlock())
|
||||||
errs() << " to MachineBasicBlock "
|
errs() << " to MachineBasicBlock "
|
||||||
<< CurPreheader->getName();
|
<< CurPreheader->getName();
|
||||||
|
|
Loading…
Reference in New Issue