mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-17 03:30:28 +00:00
Factor out LiveIntervalAnalysis' code to determine whether an instruction
is trivially rematerializable and integrate it into TargetInstrInfo::isTriviallyReMaterializable. This way, all places that need to know whether an instruction is rematerializable will get the same answer. This enables the useful parts of the aggressive-remat option by default -- using AliasAnalysis to determine whether a memory location is invariant, and removes the questionable parts -- rematting operations with virtual register inputs that may not be live everywhere. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@83687 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
ac1ceb3dd3
commit
a70dca156f
@ -275,11 +275,13 @@ public:
|
||||
/// isSafeToMove - Return true if it is safe to move this instruction. If
|
||||
/// SawStore is set to true, it means that there is a store (or call) between
|
||||
/// the instruction's location and its intended destination.
|
||||
bool isSafeToMove(const TargetInstrInfo *TII, bool &SawStore) const;
|
||||
bool isSafeToMove(const TargetInstrInfo *TII, bool &SawStore,
|
||||
AliasAnalysis *AA) const;
|
||||
|
||||
/// isSafeToReMat - Return true if it's safe to rematerialize the specified
|
||||
/// instruction which defined the specified register instead of copying it.
|
||||
bool isSafeToReMat(const TargetInstrInfo *TII, unsigned DstReg) const;
|
||||
bool isSafeToReMat(const TargetInstrInfo *TII, unsigned DstReg,
|
||||
AliasAnalysis *AA) const;
|
||||
|
||||
/// hasVolatileMemoryRef - Return true if this instruction may have a
|
||||
/// volatile memory reference, or if the information describing the
|
||||
@ -292,7 +294,7 @@ public:
|
||||
/// loading a value from the constant pool or from from the argument area of
|
||||
/// a function if it does not change. This should only return true of *all*
|
||||
/// loads the instruction does are invariant (if it does multiple loads).
|
||||
bool isInvariantLoad(AliasAnalysis *AA = 0) const;
|
||||
bool isInvariantLoad(AliasAnalysis *AA) const;
|
||||
|
||||
//
|
||||
// Debugging support
|
||||
|
@ -103,24 +103,34 @@ public:
|
||||
/// isTriviallyReMaterializable - Return true if the instruction is trivially
|
||||
/// rematerializable, meaning it has no side effects and requires no operands
|
||||
/// that aren't always available.
|
||||
bool isTriviallyReMaterializable(const MachineInstr *MI) const {
|
||||
return MI->getDesc().isRematerializable() &&
|
||||
isReallyTriviallyReMaterializable(MI);
|
||||
bool isTriviallyReMaterializable(const MachineInstr *MI,
|
||||
AliasAnalysis *AA = 0) const {
|
||||
return MI->getOpcode() == IMPLICIT_DEF ||
|
||||
(MI->getDesc().isRematerializable() &&
|
||||
(isReallyTriviallyReMaterializable(MI) ||
|
||||
isReallyTriviallyReMaterializableGeneric(MI, AA)));
|
||||
}
|
||||
|
||||
protected:
|
||||
/// isReallyTriviallyReMaterializable - For instructions with opcodes for
|
||||
/// which the M_REMATERIALIZABLE flag is set, this function tests whether the
|
||||
/// instruction itself is actually trivially rematerializable, considering
|
||||
/// its operands. This is used for targets that have instructions that are
|
||||
/// only trivially rematerializable for specific uses. This predicate must
|
||||
/// return false if the instruction has any side effects other than
|
||||
/// producing a value, or if it requres any address registers that are not
|
||||
/// always available.
|
||||
/// which the M_REMATERIALIZABLE flag is set, this hook lets the target
|
||||
/// specify whether the instruction is actually trivially rematerializable,
|
||||
/// taking into consideration its operands. This predicate must return false
|
||||
/// if the instruction has any side effects other than producing a value, or
|
||||
/// if it requres any address registers that are not always available.
|
||||
virtual bool isReallyTriviallyReMaterializable(const MachineInstr *MI) const {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
/// isReallyTriviallyReMaterializableGeneric - For instructions with opcodes
|
||||
/// for which the M_REMATERIALIZABLE flag is set and the target hook
|
||||
/// isReallyTriviallyReMaterializable returns false, this function does
|
||||
/// target-independent tests to determine if the instruction is really
|
||||
/// trivially rematerializable.
|
||||
bool isReallyTriviallyReMaterializableGeneric(const MachineInstr *MI,
|
||||
AliasAnalysis *AA) const;
|
||||
|
||||
public:
|
||||
/// Return true if the instruction is a register to register move and return
|
||||
/// the source and dest operands and their sub-register indices by reference.
|
||||
|
@ -53,7 +53,7 @@ FunctionPass *llvm::createDeadMachineInstructionElimPass() {
|
||||
bool DeadMachineInstructionElim::isDead(const MachineInstr *MI) const {
|
||||
// Don't delete instructions with side effects.
|
||||
bool SawStore = false;
|
||||
if (!MI->isSafeToMove(TII, SawStore))
|
||||
if (!MI->isSafeToMove(TII, SawStore, 0))
|
||||
return false;
|
||||
|
||||
// Examine each operand.
|
||||
|
@ -50,8 +50,6 @@ using namespace llvm;
|
||||
static cl::opt<bool> DisableReMat("disable-rematerialization",
|
||||
cl::init(false), cl::Hidden);
|
||||
|
||||
static cl::opt<bool> EnableAggressiveRemat("aggressive-remat", cl::Hidden);
|
||||
|
||||
static cl::opt<bool> EnableFastSpilling("fast-spill",
|
||||
cl::init(false), cl::Hidden);
|
||||
|
||||
@ -1408,99 +1406,12 @@ bool LiveIntervals::isReMaterializable(const LiveInterval &li,
|
||||
if (DisableReMat)
|
||||
return false;
|
||||
|
||||
if (MI->getOpcode() == TargetInstrInfo::IMPLICIT_DEF)
|
||||
return true;
|
||||
|
||||
int FrameIdx = 0;
|
||||
if (tii_->isLoadFromStackSlot(MI, FrameIdx) &&
|
||||
mf_->getFrameInfo()->isImmutableObjectIndex(FrameIdx))
|
||||
// FIXME: Let target specific isReallyTriviallyReMaterializable determines
|
||||
// this but remember this is not safe to fold into a two-address
|
||||
// instruction.
|
||||
// This is a load from fixed stack slot. It can be rematerialized.
|
||||
return true;
|
||||
|
||||
// If the target-specific rules don't identify an instruction as
|
||||
// being trivially rematerializable, use some target-independent
|
||||
// rules.
|
||||
if (!tii_->isTriviallyReMaterializable(MI)) {
|
||||
if (!EnableAggressiveRemat)
|
||||
return false;
|
||||
|
||||
const TargetInstrDesc &TID = MI->getDesc();
|
||||
|
||||
// Avoid instructions obviously unsafe for remat.
|
||||
if (TID.hasUnmodeledSideEffects() || TID.isNotDuplicable() ||
|
||||
TID.mayStore())
|
||||
return false;
|
||||
|
||||
// Avoid instructions which load from potentially varying memory.
|
||||
if (TID.mayLoad() && !MI->isInvariantLoad(aa_))
|
||||
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)) {
|
||||
if (MO.isUse()) {
|
||||
// If the physreg has no defs anywhere, it's just an ambient register
|
||||
// and we can freely move its uses. Alternatively, if it's allocatable,
|
||||
// it could get allocated to something with a def during allocation.
|
||||
if (!mri_->def_empty(Reg))
|
||||
return false;
|
||||
if (allocatableRegs_.test(Reg))
|
||||
return false;
|
||||
// Check for a def among the register's aliases too.
|
||||
for (const unsigned *Alias = tri_->getAliasSet(Reg); *Alias; ++Alias) {
|
||||
unsigned AliasReg = *Alias;
|
||||
if (!mri_->def_empty(AliasReg))
|
||||
return false;
|
||||
if (allocatableRegs_.test(AliasReg))
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// A physreg def. We can't remat it.
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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 of that register.
|
||||
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 the use, there should be only one associated def.
|
||||
if (I != E && (next(I) != E || IsLiveIn))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!tii_->isTriviallyReMaterializable(MI, aa_))
|
||||
return false;
|
||||
|
||||
// Target-specific code can mark an instruction as being rematerializable
|
||||
// if it has one virtual reg use, though it had better be something like
|
||||
// a PIC base register which is likely to be live everywhere.
|
||||
unsigned ImpUse = getReMatImplicitUse(li, MI);
|
||||
if (ImpUse) {
|
||||
const LiveInterval &ImpLi = getInterval(ImpUse);
|
||||
|
@ -933,7 +933,8 @@ void MachineInstr::copyPredicates(const MachineInstr *MI) {
|
||||
/// SawStore is set to true, it means that there is a store (or call) between
|
||||
/// the instruction's location and its intended destination.
|
||||
bool MachineInstr::isSafeToMove(const TargetInstrInfo *TII,
|
||||
bool &SawStore) const {
|
||||
bool &SawStore,
|
||||
AliasAnalysis *AA) const {
|
||||
// Ignore stuff that we obviously can't move.
|
||||
if (TID->mayStore() || TID->isCall()) {
|
||||
SawStore = true;
|
||||
@ -947,7 +948,7 @@ bool MachineInstr::isSafeToMove(const TargetInstrInfo *TII,
|
||||
// destination. The check for isInvariantLoad gives the targe the chance to
|
||||
// classify the load as always returning a constant, e.g. a constant pool
|
||||
// load.
|
||||
if (TID->mayLoad() && !isInvariantLoad())
|
||||
if (TID->mayLoad() && !isInvariantLoad(AA))
|
||||
// Otherwise, this is a real load. If there is a store between the load and
|
||||
// end of block, or if the load is volatile, we can't move it.
|
||||
return !SawStore && !hasVolatileMemoryRef();
|
||||
@ -958,10 +959,11 @@ bool MachineInstr::isSafeToMove(const TargetInstrInfo *TII,
|
||||
/// isSafeToReMat - Return true if it's safe to rematerialize the specified
|
||||
/// instruction which defined the specified register instead of copying it.
|
||||
bool MachineInstr::isSafeToReMat(const TargetInstrInfo *TII,
|
||||
unsigned DstReg) const {
|
||||
unsigned DstReg,
|
||||
AliasAnalysis *AA) const {
|
||||
bool SawStore = false;
|
||||
if (!TII->isTriviallyReMaterializable(this) ||
|
||||
!isSafeToMove(TII, SawStore))
|
||||
if (!TII->isTriviallyReMaterializable(this, AA) ||
|
||||
!isSafeToMove(TII, SawStore, AA))
|
||||
return false;
|
||||
for (unsigned i = 0, e = getNumOperands(); i != e; ++i) {
|
||||
const MachineOperand &MO = getOperand(i);
|
||||
|
@ -317,12 +317,10 @@ bool MachineLICM::IsProfitableToHoist(MachineInstr &MI) {
|
||||
if (MI.getOpcode() == TargetInstrInfo::IMPLICIT_DEF)
|
||||
return false;
|
||||
|
||||
const TargetInstrDesc &TID = MI.getDesc();
|
||||
|
||||
// FIXME: For now, only hoist re-materilizable instructions. LICM will
|
||||
// increase register pressure. We want to make sure it doesn't increase
|
||||
// spilling.
|
||||
if (!TII->isTriviallyReMaterializable(&MI))
|
||||
if (!TII->isTriviallyReMaterializable(&MI, AA))
|
||||
return false;
|
||||
|
||||
// If result(s) of this instruction is used by PHIs, then don't hoist it.
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "llvm/CodeGen/Passes.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/CodeGen/MachineDominators.h"
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/Target/TargetRegisterInfo.h"
|
||||
#include "llvm/Target/TargetInstrInfo.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
@ -39,6 +40,7 @@ namespace {
|
||||
MachineFunction *CurMF; // Current MachineFunction
|
||||
MachineRegisterInfo *RegInfo; // Machine register information
|
||||
MachineDominatorTree *DT; // Machine dominator tree
|
||||
AliasAnalysis *AA;
|
||||
BitVector AllocatableSet; // Which physregs are allocatable?
|
||||
|
||||
public:
|
||||
@ -50,6 +52,7 @@ namespace {
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.setPreservesCFG();
|
||||
MachineFunctionPass::getAnalysisUsage(AU);
|
||||
AU.addRequired<AliasAnalysis>();
|
||||
AU.addRequired<MachineDominatorTree>();
|
||||
AU.addPreserved<MachineDominatorTree>();
|
||||
}
|
||||
@ -100,6 +103,7 @@ bool MachineSinking::runOnMachineFunction(MachineFunction &MF) {
|
||||
TRI = TM->getRegisterInfo();
|
||||
RegInfo = &CurMF->getRegInfo();
|
||||
DT = &getAnalysis<MachineDominatorTree>();
|
||||
AA = &getAnalysis<AliasAnalysis>();
|
||||
AllocatableSet = TRI->getAllocatableSet(*CurMF);
|
||||
|
||||
bool EverMadeChange = false;
|
||||
@ -151,7 +155,7 @@ bool MachineSinking::ProcessBlock(MachineBasicBlock &MBB) {
|
||||
/// instruction out of its current block into a successor.
|
||||
bool MachineSinking::SinkInstruction(MachineInstr *MI, bool &SawStore) {
|
||||
// Check if it's safe to move the instruction.
|
||||
if (!MI->isSafeToMove(TII, SawStore))
|
||||
if (!MI->isSafeToMove(TII, SawStore, AA))
|
||||
return false;
|
||||
|
||||
// FIXME: This should include support for sinking instructions within the
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "llvm/CodeGen/MachineLoopInfo.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/CodeGen/ScheduleHazardRecognizer.h"
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/Target/TargetLowering.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Target/TargetInstrInfo.h"
|
||||
@ -76,12 +77,15 @@ DebugMod("postra-sched-debugmod",
|
||||
|
||||
namespace {
|
||||
class VISIBILITY_HIDDEN PostRAScheduler : public MachineFunctionPass {
|
||||
AliasAnalysis *AA;
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
PostRAScheduler() : MachineFunctionPass(&ID) {}
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.setPreservesCFG();
|
||||
AU.addRequired<AliasAnalysis>();
|
||||
AU.addRequired<MachineDominatorTree>();
|
||||
AU.addPreserved<MachineDominatorTree>();
|
||||
AU.addRequired<MachineLoopInfo>();
|
||||
@ -119,6 +123,9 @@ namespace {
|
||||
/// HazardRec - The hazard recognizer to use.
|
||||
ScheduleHazardRecognizer *HazardRec;
|
||||
|
||||
/// AA - AliasAnalysis for making memory reference queries.
|
||||
AliasAnalysis *AA;
|
||||
|
||||
/// Classes - For live regs that are only used in one register class in a
|
||||
/// live range, the register class. If the register is not live, the
|
||||
/// corresponding value is null. If the register is live but used in
|
||||
@ -146,10 +153,11 @@ namespace {
|
||||
SchedulePostRATDList(MachineFunction &MF,
|
||||
const MachineLoopInfo &MLI,
|
||||
const MachineDominatorTree &MDT,
|
||||
ScheduleHazardRecognizer *HR)
|
||||
ScheduleHazardRecognizer *HR,
|
||||
AliasAnalysis *aa)
|
||||
: ScheduleDAGInstrs(MF, MLI, MDT), Topo(SUnits),
|
||||
AllocatableSet(TRI->getAllocatableSet(MF)),
|
||||
HazardRec(HR) {}
|
||||
HazardRec(HR), AA(aa) {}
|
||||
|
||||
~SchedulePostRATDList() {
|
||||
delete HazardRec;
|
||||
@ -241,7 +249,7 @@ bool PostRAScheduler::runOnMachineFunction(MachineFunction &Fn) {
|
||||
(ScheduleHazardRecognizer *)new ExactHazardRecognizer(InstrItins) :
|
||||
(ScheduleHazardRecognizer *)new SimpleHazardRecognizer();
|
||||
|
||||
SchedulePostRATDList Scheduler(Fn, MLI, MDT, HR);
|
||||
SchedulePostRATDList Scheduler(Fn, MLI, MDT, HR, AA);
|
||||
|
||||
// Loop over all of the basic blocks
|
||||
for (MachineFunction::iterator MBB = Fn.begin(), MBBe = Fn.end();
|
||||
@ -379,7 +387,7 @@ void SchedulePostRATDList::Schedule() {
|
||||
DEBUG(errs() << "********** List Scheduling **********\n");
|
||||
|
||||
// Build the scheduling graph.
|
||||
BuildSchedGraph();
|
||||
BuildSchedGraph(AA);
|
||||
|
||||
if (EnableAntiDepBreaking) {
|
||||
if (BreakAntiDependencies()) {
|
||||
@ -392,7 +400,7 @@ void SchedulePostRATDList::Schedule() {
|
||||
SUnits.clear();
|
||||
EntrySU = SUnit();
|
||||
ExitSU = SUnit();
|
||||
BuildSchedGraph();
|
||||
BuildSchedGraph(AA);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,7 +123,7 @@ void ScheduleDAGInstrs::StartBlock(MachineBasicBlock *BB) {
|
||||
}
|
||||
}
|
||||
|
||||
void ScheduleDAGInstrs::BuildSchedGraph() {
|
||||
void ScheduleDAGInstrs::BuildSchedGraph(AliasAnalysis *AA) {
|
||||
// We'll be allocating one SUnit for each instruction, plus one for
|
||||
// the region exit node.
|
||||
SUnits.reserve(BB->size());
|
||||
@ -375,7 +375,7 @@ void ScheduleDAGInstrs::BuildSchedGraph() {
|
||||
// Treat all other stores conservatively.
|
||||
goto new_chain;
|
||||
} else if (TID.mayLoad()) {
|
||||
if (MI->isInvariantLoad()) {
|
||||
if (MI->isInvariantLoad(AA)) {
|
||||
// Invariant load, no chain dependencies needed!
|
||||
} else if (const Value *V = getUnderlyingObjectForInstr(MI)) {
|
||||
// A load from a specific PseudoSourceValue. Add precise dependencies.
|
||||
|
@ -155,7 +155,7 @@ namespace llvm {
|
||||
|
||||
/// BuildSchedGraph - Build SUnits from the MachineBasicBlock that we are
|
||||
/// input.
|
||||
virtual void BuildSchedGraph();
|
||||
virtual void BuildSchedGraph(AliasAnalysis *AA);
|
||||
|
||||
/// ComputeLatency - Compute node latency.
|
||||
///
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "VirtRegMap.h"
|
||||
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
|
||||
#include "llvm/Value.h"
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
#include "llvm/CodeGen/MachineInstr.h"
|
||||
#include "llvm/CodeGen/MachineLoopInfo.h"
|
||||
@ -72,6 +73,7 @@ const PassInfo *const llvm::SimpleRegisterCoalescingID = &X;
|
||||
|
||||
void SimpleRegisterCoalescing::getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.setPreservesCFG();
|
||||
AU.addRequired<AliasAnalysis>();
|
||||
AU.addRequired<LiveIntervals>();
|
||||
AU.addPreserved<LiveIntervals>();
|
||||
AU.addRequired<MachineLoopInfo>();
|
||||
@ -646,10 +648,10 @@ bool SimpleRegisterCoalescing::ReMaterializeTrivialDef(LiveInterval &SrcInt,
|
||||
const TargetInstrDesc &TID = DefMI->getDesc();
|
||||
if (!TID.isAsCheapAsAMove())
|
||||
return false;
|
||||
if (!tii_->isTriviallyReMaterializable(DefMI))
|
||||
if (!tii_->isTriviallyReMaterializable(DefMI, AA))
|
||||
return false;
|
||||
bool SawStore = false;
|
||||
if (!DefMI->isSafeToMove(tii_, SawStore))
|
||||
if (!DefMI->isSafeToMove(tii_, SawStore, AA))
|
||||
return false;
|
||||
if (TID.getNumDefs() != 1)
|
||||
return false;
|
||||
@ -2655,6 +2657,7 @@ bool SimpleRegisterCoalescing::runOnMachineFunction(MachineFunction &fn) {
|
||||
tri_ = tm_->getRegisterInfo();
|
||||
tii_ = tm_->getInstrInfo();
|
||||
li_ = &getAnalysis<LiveIntervals>();
|
||||
AA = &getAnalysis<AliasAnalysis>();
|
||||
loopInfo = &getAnalysis<MachineLoopInfo>();
|
||||
|
||||
DEBUG(errs() << "********** SIMPLE REGISTER COALESCING **********\n"
|
||||
|
@ -45,6 +45,7 @@ namespace llvm {
|
||||
const TargetInstrInfo* tii_;
|
||||
LiveIntervals *li_;
|
||||
const MachineLoopInfo* loopInfo;
|
||||
AliasAnalysis *AA;
|
||||
|
||||
BitVector allocatableRegs_;
|
||||
DenseMap<const TargetRegisterClass*, BitVector> allocatableRCRegs_;
|
||||
|
@ -13,11 +13,14 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Target/TargetInstrInfo.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Target/TargetRegisterInfo.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
#include "llvm/CodeGen/MachineInstr.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/CodeGen/MachineMemOperand.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/CodeGen/PseudoSourceValue.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
@ -238,3 +241,88 @@ TargetInstrInfo::foldMemoryOperand(MachineFunction &MF,
|
||||
|
||||
return NewMI;
|
||||
}
|
||||
|
||||
bool
|
||||
TargetInstrInfo::isReallyTriviallyReMaterializableGeneric(const MachineInstr *
|
||||
MI,
|
||||
AliasAnalysis *
|
||||
AA) const {
|
||||
const MachineFunction &MF = *MI->getParent()->getParent();
|
||||
const MachineRegisterInfo &MRI = MF.getRegInfo();
|
||||
const TargetMachine &TM = MF.getTarget();
|
||||
const TargetInstrInfo &TII = *TM.getInstrInfo();
|
||||
const TargetRegisterInfo &TRI = *TM.getRegisterInfo();
|
||||
|
||||
// A load from a fixed stack slot can be rematerialized. This may be
|
||||
// redundant with subsequent checks, but it's target-independent,
|
||||
// simple, and a common case.
|
||||
int FrameIdx = 0;
|
||||
if (TII.isLoadFromStackSlot(MI, FrameIdx) &&
|
||||
MF.getFrameInfo()->isImmutableObjectIndex(FrameIdx))
|
||||
return true;
|
||||
|
||||
const TargetInstrDesc &TID = MI->getDesc();
|
||||
|
||||
// Avoid instructions obviously unsafe for remat.
|
||||
if (TID.hasUnmodeledSideEffects() || TID.isNotDuplicable() ||
|
||||
TID.mayStore())
|
||||
return false;
|
||||
|
||||
// Avoid instructions which load from potentially varying memory.
|
||||
if (TID.mayLoad() && !MI->isInvariantLoad(AA))
|
||||
return false;
|
||||
|
||||
// If any of the registers accessed are non-constant, conservatively assume
|
||||
// the instruction is not rematerializable.
|
||||
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
|
||||
const MachineOperand &MO = MI->getOperand(i);
|
||||
if (!MO.isReg()) continue;
|
||||
unsigned Reg = MO.getReg();
|
||||
if (Reg == 0)
|
||||
continue;
|
||||
|
||||
// Check for a well-behaved physical register.
|
||||
if (TargetRegisterInfo::isPhysicalRegister(Reg)) {
|
||||
if (MO.isUse()) {
|
||||
// If the physreg has no defs anywhere, it's just an ambient register
|
||||
// and we can freely move its uses. Alternatively, if it's allocatable,
|
||||
// it could get allocated to something with a def during allocation.
|
||||
if (!MRI.def_empty(Reg))
|
||||
return false;
|
||||
BitVector AllocatableRegs = TRI.getAllocatableSet(MF, 0);
|
||||
if (AllocatableRegs.test(Reg))
|
||||
return false;
|
||||
// Check for a def among the register's aliases too.
|
||||
for (const unsigned *Alias = TRI.getAliasSet(Reg); *Alias; ++Alias) {
|
||||
unsigned AliasReg = *Alias;
|
||||
if (!MRI.def_empty(AliasReg))
|
||||
return false;
|
||||
if (AllocatableRegs.test(AliasReg))
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// A physreg def. We can't remat it.
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only allow one virtual-register def, and that in the first operand.
|
||||
if (MO.isDef() != (i == 0))
|
||||
return false;
|
||||
|
||||
// For the def, it should be the only def of that register.
|
||||
if (MO.isDef() && (next(MRI.def_begin(Reg)) != MRI.def_end() ||
|
||||
MRI.isLiveIn(Reg)))
|
||||
return false;
|
||||
|
||||
// Don't allow any virtual-register uses. Rematting an instruction with
|
||||
// virtual register uses would length the live ranges of the uses, which
|
||||
// is not necessarily a good idea, certainly not "trivial".
|
||||
if (MO.isUse())
|
||||
return false;
|
||||
}
|
||||
|
||||
// Everything checked out.
|
||||
return true;
|
||||
}
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineInstr.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/Target/TargetRegisterInfo.h"
|
||||
#include "llvm/Target/TargetInstrInfo.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
@ -62,6 +63,7 @@ namespace {
|
||||
const TargetRegisterInfo *TRI;
|
||||
MachineRegisterInfo *MRI;
|
||||
LiveVariables *LV;
|
||||
AliasAnalysis *AA;
|
||||
|
||||
// DistanceMap - Keep track the distance of a MI from the start of the
|
||||
// current basic block.
|
||||
@ -130,6 +132,7 @@ namespace {
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.setPreservesCFG();
|
||||
AU.addRequired<AliasAnalysis>();
|
||||
AU.addPreserved<LiveVariables>();
|
||||
AU.addPreservedID(MachineLoopInfoID);
|
||||
AU.addPreservedID(MachineDominatorsID);
|
||||
@ -160,7 +163,7 @@ bool TwoAddressInstructionPass::Sink3AddrInstruction(MachineBasicBlock *MBB,
|
||||
MachineBasicBlock::iterator OldPos) {
|
||||
// Check if it's safe to move this instruction.
|
||||
bool SeenStore = true; // Be conservative.
|
||||
if (!MI->isSafeToMove(TII, SeenStore))
|
||||
if (!MI->isSafeToMove(TII, SeenStore, AA))
|
||||
return false;
|
||||
|
||||
unsigned DefReg = 0;
|
||||
@ -903,6 +906,7 @@ bool TwoAddressInstructionPass::runOnMachineFunction(MachineFunction &MF) {
|
||||
TII = TM.getInstrInfo();
|
||||
TRI = TM.getRegisterInfo();
|
||||
LV = getAnalysisIfAvailable<LiveVariables>();
|
||||
AA = &getAnalysis<AliasAnalysis>();
|
||||
|
||||
bool MadeChange = false;
|
||||
|
||||
@ -1027,7 +1031,7 @@ bool TwoAddressInstructionPass::runOnMachineFunction(MachineFunction &MF) {
|
||||
// copying it.
|
||||
if (DefMI &&
|
||||
DefMI->getDesc().isAsCheapAsAMove() &&
|
||||
DefMI->isSafeToReMat(TII, regB) &&
|
||||
DefMI->isSafeToReMat(TII, regB, AA) &&
|
||||
isProfitableToReMat(regB, rc, mi, DefMI, mbbi, Dist)){
|
||||
DEBUG(errs() << "2addr: REMATTING : " << *DefMI << "\n");
|
||||
unsigned regASubIdx = mi->getOperand(DstIdx).getSubReg();
|
||||
|
Loading…
Reference in New Issue
Block a user