forked from OSchip/llvm-project
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:
parent
5eb536b74c
commit
09b0448dbc
|
@ -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#).
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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:
|
||||
///
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
Loading…
Reference in New Issue