Enable rematerialization of constants using AliasAnalysis::pointsToConstantMemory,

and knowledge of PseudoSourceValues. This unfortunately isn't sufficient to allow
constants to be rematerialized in PIC mode -- the extra indirection is a
complication.

llvm-svn: 54000
This commit is contained in:
Dan Gohman 2008-07-25 00:02:30 +00:00
parent 5eb536b74c
commit 09b0448dbc
6 changed files with 141 additions and 16 deletions

View File

@ -32,6 +32,7 @@
namespace llvm {
class AliasAnalysis;
class LiveVariables;
class MachineLoopInfo;
class TargetRegisterInfo;
@ -61,6 +62,7 @@ namespace llvm {
const TargetMachine* tm_;
const TargetRegisterInfo* tri_;
const TargetInstrInfo* tii_;
AliasAnalysis *aa_;
LiveVariables* lv_;
/// Special pool allocator for VNInfo's (LiveInterval val#).

View File

@ -206,6 +206,14 @@ public:
liveout_iterator liveout_begin() const { return LiveOuts.begin(); }
liveout_iterator liveout_end() const { return LiveOuts.end(); }
bool liveout_empty() const { return LiveOuts.empty(); }
bool isLiveIn(unsigned Reg) const {
for (livein_iterator I = livein_begin(), E = livein_end(); I != E; ++I)
if (I->first == Reg || I->second == Reg)
return true;
return false;
}
private:
void HandleVRegListReallocation();

View File

@ -17,6 +17,8 @@
#include "llvm/Value.h"
namespace llvm {
class MachineFrameInfo;
/// PseudoSourceValue - Special value supplied for machine level alias
/// analysis. It indicates that the a memory access references the functions
/// stack frame (e.g., a spill slot), below the stack frame (e.g., argument
@ -27,6 +29,10 @@ namespace llvm {
virtual void print(std::ostream &OS) const;
/// isConstant - Test whether this PseudoSourceValue has a constant value.
///
virtual bool isConstant(const MachineFrameInfo *) const;
/// classof - Methods for support type inquiry through isa, cast, and
/// dyn_cast:
///

View File

@ -19,12 +19,14 @@
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
#include "VirtRegMap.h"
#include "llvm/Value.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/CodeGen/LiveVariables.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineLoopInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/PseudoSourceValue.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
@ -54,6 +56,8 @@ char LiveIntervals::ID = 0;
static RegisterPass<LiveIntervals> X("liveintervals", "Live Interval Analysis");
void LiveIntervals::getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<AliasAnalysis>();
AU.addPreserved<AliasAnalysis>();
AU.addPreserved<LiveVariables>();
AU.addRequired<LiveVariables>();
AU.addPreservedID(MachineLoopInfoID);
@ -212,6 +216,7 @@ bool LiveIntervals::runOnMachineFunction(MachineFunction &fn) {
tm_ = &fn.getTarget();
tri_ = tm_->getRegisterInfo();
tii_ = tm_->getInstrInfo();
aa_ = &getAnalysis<AliasAnalysis>();
lv_ = &getAnalysis<LiveVariables>();
allocatableRegs_ = tri_->getAllocatableSet(fn);
@ -750,7 +755,9 @@ unsigned LiveIntervals::getReMatImplicitUse(const LiveInterval &li,
assert(!RegOp &&
"Can't rematerialize instruction with multiple register operand!");
RegOp = MO.getReg();
#ifndef NDEBUG
break;
#endif
}
return RegOp;
}
@ -773,7 +780,6 @@ bool LiveIntervals::isReMaterializable(const LiveInterval &li,
if (DisableReMat)
return false;
isLoad = false;
if (MI->getOpcode() == TargetInstrInfo::IMPLICIT_DEF)
return true;
@ -786,27 +792,95 @@ bool LiveIntervals::isReMaterializable(const LiveInterval &li,
// This is a load from fixed stack slot. It can be rematerialized.
return true;
if (tii_->isTriviallyReMaterializable(MI)) {
const TargetInstrDesc &TID = MI->getDesc();
isLoad = TID.isSimpleLoad();
// If the target-specific rules don't identify an instruction as
// being trivially rematerializable, use some target-independent
// rules.
if (!MI->getDesc().isRematerializable() ||
!tii_->isTriviallyReMaterializable(MI)) {
unsigned ImpUse = getReMatImplicitUse(li, MI);
if (ImpUse) {
const LiveInterval &ImpLi = getInterval(ImpUse);
for (MachineRegisterInfo::use_iterator ri = mri_->use_begin(li.reg),
re = mri_->use_end(); ri != re; ++ri) {
MachineInstr *UseMI = &*ri;
unsigned UseIdx = getInstructionIndex(UseMI);
if (li.FindLiveRangeContaining(UseIdx)->valno != ValNo)
continue;
if (!isValNoAvailableAt(ImpLi, MI, UseIdx))
// If the instruction access memory but the memoperands have been lost,
// we can't analyze it.
const TargetInstrDesc &TID = MI->getDesc();
if ((TID.mayLoad() || TID.mayStore()) && MI->memoperands_empty())
return false;
// Avoid instructions obviously unsafe for remat.
if (TID.hasUnmodeledSideEffects() || TID.isNotDuplicable())
return false;
// If the instruction accesses memory and the memory could be non-constant,
// assume the instruction is not rematerializable.
for (alist<MachineMemOperand>::const_iterator I = MI->memoperands_begin(),
E = MI->memoperands_end(); I != E; ++I) {
const MachineMemOperand &MMO = *I;
if (MMO.isVolatile() || MMO.isStore())
return false;
const Value *V = MMO.getValue();
if (!V)
return false;
if (const PseudoSourceValue *PSV = dyn_cast<PseudoSourceValue>(V)) {
if (!PSV->isConstant(mf_->getFrameInfo()))
return false;
} else if (!aa_->pointsToConstantMemory(V))
return false;
}
// If any of the registers accessed are non-constant, conservatively assume
// the instruction is not rematerializable.
unsigned ImpUse = 0;
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
const MachineOperand &MO = MI->getOperand(i);
if (MO.isReg()) {
unsigned Reg = MO.getReg();
if (Reg == 0)
continue;
if (TargetRegisterInfo::isPhysicalRegister(Reg))
return false;
// Only allow one def, and that in the first operand.
if (MO.isDef() != (i == 0))
return false;
// Only allow constant-valued registers.
bool IsLiveIn = mri_->isLiveIn(Reg);
MachineRegisterInfo::def_iterator I = mri_->def_begin(Reg),
E = mri_->def_end();
// For the def, it should be the only def.
if (MO.isDef() && (next(I) != E || IsLiveIn))
return false;
if (MO.isUse()) {
// Only allow one use other register use, as that's all the
// remat mechanisms support currently.
if (Reg != li.reg) {
if (ImpUse == 0)
ImpUse = Reg;
else if (Reg != ImpUse)
return false;
}
// For uses, there should be only one associate def.
if (I != E && (next(I) != E || IsLiveIn))
return false;
}
}
}
return true;
}
return false;
unsigned ImpUse = getReMatImplicitUse(li, MI);
if (ImpUse) {
const LiveInterval &ImpLi = getInterval(ImpUse);
for (MachineRegisterInfo::use_iterator ri = mri_->use_begin(li.reg),
re = mri_->use_end(); ri != re; ++ri) {
MachineInstr *UseMI = &*ri;
unsigned UseIdx = getInstructionIndex(UseMI);
if (li.FindLiveRangeContaining(UseIdx)->valno != ValNo)
continue;
if (!isValNoAvailableAt(ImpLi, MI, UseIdx))
return false;
}
}
return true;
}
/// isReMaterializable - Returns true if every definition of MI of every

View File

@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/PseudoSourceValue.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Support/Compiler.h"
@ -51,6 +52,9 @@ namespace llvm {
const int FI;
public:
explicit FixedStackPseudoSourceValue(int fi) : FI(fi) {}
virtual bool isConstant(const MachineFrameInfo *MFI) const;
virtual void print(std::ostream &OS) const {
OS << "FixedStack" << FI;
}
@ -64,4 +68,20 @@ namespace llvm {
V = new FixedStackPseudoSourceValue(FI);
return V;
}
bool PseudoSourceValue::isConstant(const MachineFrameInfo *) const {
if (this == getStack())
return false;
if (this == getGOT() ||
this == getConstantPool() ||
this == getJumpTable())
return true;
assert(0 && "Unknown PseudoSourceValue!");
return false;
}
bool
FixedStackPseudoSourceValue::isConstant(const MachineFrameInfo *MFI) const {
return MFI && MFI->isImmutableObjectIndex(FI);
}
}

View File

@ -0,0 +1,15 @@
; RUN: llvm-as < %s | llc -march=x86-64 -relocation-model=static | grep xmm | count 2
declare void @bar() nounwind
@a = external constant float
declare void @qux(float %f) nounwind
define void @foo() nounwind {
%f = load float* @a
call void @bar()
call void @qux(float %f)
call void @qux(float %f)
ret void
}