mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-02-27 02:31:09 +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
|
/// 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
|
/// SawStore is set to true, it means that there is a store (or call) between
|
||||||
/// the instruction's location and its intended destination.
|
/// 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
|
/// isSafeToReMat - Return true if it's safe to rematerialize the specified
|
||||||
/// instruction which defined the specified register instead of copying it.
|
/// 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
|
/// hasVolatileMemoryRef - Return true if this instruction may have a
|
||||||
/// volatile memory reference, or if the information describing the
|
/// 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
|
/// 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*
|
/// 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).
|
/// loads the instruction does are invariant (if it does multiple loads).
|
||||||
bool isInvariantLoad(AliasAnalysis *AA = 0) const;
|
bool isInvariantLoad(AliasAnalysis *AA) const;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Debugging support
|
// Debugging support
|
||||||
|
@ -103,24 +103,34 @@ public:
|
|||||||
/// isTriviallyReMaterializable - Return true if the instruction is trivially
|
/// isTriviallyReMaterializable - Return true if the instruction is trivially
|
||||||
/// rematerializable, meaning it has no side effects and requires no operands
|
/// rematerializable, meaning it has no side effects and requires no operands
|
||||||
/// that aren't always available.
|
/// that aren't always available.
|
||||||
bool isTriviallyReMaterializable(const MachineInstr *MI) const {
|
bool isTriviallyReMaterializable(const MachineInstr *MI,
|
||||||
return MI->getDesc().isRematerializable() &&
|
AliasAnalysis *AA = 0) const {
|
||||||
isReallyTriviallyReMaterializable(MI);
|
return MI->getOpcode() == IMPLICIT_DEF ||
|
||||||
|
(MI->getDesc().isRematerializable() &&
|
||||||
|
(isReallyTriviallyReMaterializable(MI) ||
|
||||||
|
isReallyTriviallyReMaterializableGeneric(MI, AA)));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// isReallyTriviallyReMaterializable - For instructions with opcodes for
|
/// isReallyTriviallyReMaterializable - For instructions with opcodes for
|
||||||
/// which the M_REMATERIALIZABLE flag is set, this function tests whether the
|
/// which the M_REMATERIALIZABLE flag is set, this hook lets the target
|
||||||
/// instruction itself is actually trivially rematerializable, considering
|
/// specify whether the instruction is actually trivially rematerializable,
|
||||||
/// its operands. This is used for targets that have instructions that are
|
/// taking into consideration its operands. This predicate must return false
|
||||||
/// only trivially rematerializable for specific uses. This predicate must
|
/// if the instruction has any side effects other than producing a value, or
|
||||||
/// return false if the instruction has any side effects other than
|
/// if it requres any address registers that are not always available.
|
||||||
/// producing a value, or if it requres any address registers that are not
|
|
||||||
/// always available.
|
|
||||||
virtual bool isReallyTriviallyReMaterializable(const MachineInstr *MI) const {
|
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:
|
public:
|
||||||
/// Return true if the instruction is a register to register move and return
|
/// 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.
|
/// 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 {
|
bool DeadMachineInstructionElim::isDead(const MachineInstr *MI) const {
|
||||||
// Don't delete instructions with side effects.
|
// Don't delete instructions with side effects.
|
||||||
bool SawStore = false;
|
bool SawStore = false;
|
||||||
if (!MI->isSafeToMove(TII, SawStore))
|
if (!MI->isSafeToMove(TII, SawStore, 0))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Examine each operand.
|
// Examine each operand.
|
||||||
|
@ -50,8 +50,6 @@ using namespace llvm;
|
|||||||
static cl::opt<bool> DisableReMat("disable-rematerialization",
|
static cl::opt<bool> DisableReMat("disable-rematerialization",
|
||||||
cl::init(false), cl::Hidden);
|
cl::init(false), cl::Hidden);
|
||||||
|
|
||||||
static cl::opt<bool> EnableAggressiveRemat("aggressive-remat", cl::Hidden);
|
|
||||||
|
|
||||||
static cl::opt<bool> EnableFastSpilling("fast-spill",
|
static cl::opt<bool> EnableFastSpilling("fast-spill",
|
||||||
cl::init(false), cl::Hidden);
|
cl::init(false), cl::Hidden);
|
||||||
|
|
||||||
@ -1408,99 +1406,12 @@ bool LiveIntervals::isReMaterializable(const LiveInterval &li,
|
|||||||
if (DisableReMat)
|
if (DisableReMat)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (MI->getOpcode() == TargetInstrInfo::IMPLICIT_DEF)
|
if (!tii_->isTriviallyReMaterializable(MI, aa_))
|
||||||
return true;
|
return false;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// 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);
|
unsigned ImpUse = getReMatImplicitUse(li, MI);
|
||||||
if (ImpUse) {
|
if (ImpUse) {
|
||||||
const LiveInterval &ImpLi = getInterval(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
|
/// SawStore is set to true, it means that there is a store (or call) between
|
||||||
/// the instruction's location and its intended destination.
|
/// the instruction's location and its intended destination.
|
||||||
bool MachineInstr::isSafeToMove(const TargetInstrInfo *TII,
|
bool MachineInstr::isSafeToMove(const TargetInstrInfo *TII,
|
||||||
bool &SawStore) const {
|
bool &SawStore,
|
||||||
|
AliasAnalysis *AA) const {
|
||||||
// Ignore stuff that we obviously can't move.
|
// Ignore stuff that we obviously can't move.
|
||||||
if (TID->mayStore() || TID->isCall()) {
|
if (TID->mayStore() || TID->isCall()) {
|
||||||
SawStore = true;
|
SawStore = true;
|
||||||
@ -947,7 +948,7 @@ bool MachineInstr::isSafeToMove(const TargetInstrInfo *TII,
|
|||||||
// destination. The check for isInvariantLoad gives the targe the chance to
|
// destination. The check for isInvariantLoad gives the targe the chance to
|
||||||
// classify the load as always returning a constant, e.g. a constant pool
|
// classify the load as always returning a constant, e.g. a constant pool
|
||||||
// load.
|
// 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
|
// 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.
|
// end of block, or if the load is volatile, we can't move it.
|
||||||
return !SawStore && !hasVolatileMemoryRef();
|
return !SawStore && !hasVolatileMemoryRef();
|
||||||
@ -958,10 +959,11 @@ bool MachineInstr::isSafeToMove(const TargetInstrInfo *TII,
|
|||||||
/// isSafeToReMat - Return true if it's safe to rematerialize the specified
|
/// isSafeToReMat - Return true if it's safe to rematerialize the specified
|
||||||
/// instruction which defined the specified register instead of copying it.
|
/// instruction which defined the specified register instead of copying it.
|
||||||
bool MachineInstr::isSafeToReMat(const TargetInstrInfo *TII,
|
bool MachineInstr::isSafeToReMat(const TargetInstrInfo *TII,
|
||||||
unsigned DstReg) const {
|
unsigned DstReg,
|
||||||
|
AliasAnalysis *AA) const {
|
||||||
bool SawStore = false;
|
bool SawStore = false;
|
||||||
if (!TII->isTriviallyReMaterializable(this) ||
|
if (!TII->isTriviallyReMaterializable(this, AA) ||
|
||||||
!isSafeToMove(TII, SawStore))
|
!isSafeToMove(TII, SawStore, AA))
|
||||||
return false;
|
return false;
|
||||||
for (unsigned i = 0, e = getNumOperands(); i != e; ++i) {
|
for (unsigned i = 0, e = getNumOperands(); i != e; ++i) {
|
||||||
const MachineOperand &MO = getOperand(i);
|
const MachineOperand &MO = getOperand(i);
|
||||||
|
@ -317,12 +317,10 @@ bool MachineLICM::IsProfitableToHoist(MachineInstr &MI) {
|
|||||||
if (MI.getOpcode() == TargetInstrInfo::IMPLICIT_DEF)
|
if (MI.getOpcode() == TargetInstrInfo::IMPLICIT_DEF)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const TargetInstrDesc &TID = MI.getDesc();
|
|
||||||
|
|
||||||
// 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))
|
if (!TII->isTriviallyReMaterializable(&MI, AA))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// 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.
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "llvm/CodeGen/Passes.h"
|
#include "llvm/CodeGen/Passes.h"
|
||||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||||
#include "llvm/CodeGen/MachineDominators.h"
|
#include "llvm/CodeGen/MachineDominators.h"
|
||||||
|
#include "llvm/Analysis/AliasAnalysis.h"
|
||||||
#include "llvm/Target/TargetRegisterInfo.h"
|
#include "llvm/Target/TargetRegisterInfo.h"
|
||||||
#include "llvm/Target/TargetInstrInfo.h"
|
#include "llvm/Target/TargetInstrInfo.h"
|
||||||
#include "llvm/Target/TargetMachine.h"
|
#include "llvm/Target/TargetMachine.h"
|
||||||
@ -39,6 +40,7 @@ namespace {
|
|||||||
MachineFunction *CurMF; // Current MachineFunction
|
MachineFunction *CurMF; // Current MachineFunction
|
||||||
MachineRegisterInfo *RegInfo; // Machine register information
|
MachineRegisterInfo *RegInfo; // Machine register information
|
||||||
MachineDominatorTree *DT; // Machine dominator tree
|
MachineDominatorTree *DT; // Machine dominator tree
|
||||||
|
AliasAnalysis *AA;
|
||||||
BitVector AllocatableSet; // Which physregs are allocatable?
|
BitVector AllocatableSet; // Which physregs are allocatable?
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -50,6 +52,7 @@ namespace {
|
|||||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||||
AU.setPreservesCFG();
|
AU.setPreservesCFG();
|
||||||
MachineFunctionPass::getAnalysisUsage(AU);
|
MachineFunctionPass::getAnalysisUsage(AU);
|
||||||
|
AU.addRequired<AliasAnalysis>();
|
||||||
AU.addRequired<MachineDominatorTree>();
|
AU.addRequired<MachineDominatorTree>();
|
||||||
AU.addPreserved<MachineDominatorTree>();
|
AU.addPreserved<MachineDominatorTree>();
|
||||||
}
|
}
|
||||||
@ -100,6 +103,7 @@ bool MachineSinking::runOnMachineFunction(MachineFunction &MF) {
|
|||||||
TRI = TM->getRegisterInfo();
|
TRI = TM->getRegisterInfo();
|
||||||
RegInfo = &CurMF->getRegInfo();
|
RegInfo = &CurMF->getRegInfo();
|
||||||
DT = &getAnalysis<MachineDominatorTree>();
|
DT = &getAnalysis<MachineDominatorTree>();
|
||||||
|
AA = &getAnalysis<AliasAnalysis>();
|
||||||
AllocatableSet = TRI->getAllocatableSet(*CurMF);
|
AllocatableSet = TRI->getAllocatableSet(*CurMF);
|
||||||
|
|
||||||
bool EverMadeChange = false;
|
bool EverMadeChange = false;
|
||||||
@ -151,7 +155,7 @@ bool MachineSinking::ProcessBlock(MachineBasicBlock &MBB) {
|
|||||||
/// instruction out of its current block into a successor.
|
/// instruction out of its current block into a successor.
|
||||||
bool MachineSinking::SinkInstruction(MachineInstr *MI, bool &SawStore) {
|
bool MachineSinking::SinkInstruction(MachineInstr *MI, bool &SawStore) {
|
||||||
// Check if it's safe to move the instruction.
|
// Check if it's safe to move the instruction.
|
||||||
if (!MI->isSafeToMove(TII, SawStore))
|
if (!MI->isSafeToMove(TII, SawStore, AA))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// FIXME: This should include support for sinking instructions within the
|
// FIXME: This should include support for sinking instructions within the
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#include "llvm/CodeGen/MachineLoopInfo.h"
|
#include "llvm/CodeGen/MachineLoopInfo.h"
|
||||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||||
#include "llvm/CodeGen/ScheduleHazardRecognizer.h"
|
#include "llvm/CodeGen/ScheduleHazardRecognizer.h"
|
||||||
|
#include "llvm/Analysis/AliasAnalysis.h"
|
||||||
#include "llvm/Target/TargetLowering.h"
|
#include "llvm/Target/TargetLowering.h"
|
||||||
#include "llvm/Target/TargetMachine.h"
|
#include "llvm/Target/TargetMachine.h"
|
||||||
#include "llvm/Target/TargetInstrInfo.h"
|
#include "llvm/Target/TargetInstrInfo.h"
|
||||||
@ -76,12 +77,15 @@ DebugMod("postra-sched-debugmod",
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
class VISIBILITY_HIDDEN PostRAScheduler : public MachineFunctionPass {
|
class VISIBILITY_HIDDEN PostRAScheduler : public MachineFunctionPass {
|
||||||
|
AliasAnalysis *AA;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static char ID;
|
static char ID;
|
||||||
PostRAScheduler() : MachineFunctionPass(&ID) {}
|
PostRAScheduler() : MachineFunctionPass(&ID) {}
|
||||||
|
|
||||||
void getAnalysisUsage(AnalysisUsage &AU) const {
|
void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||||
AU.setPreservesCFG();
|
AU.setPreservesCFG();
|
||||||
|
AU.addRequired<AliasAnalysis>();
|
||||||
AU.addRequired<MachineDominatorTree>();
|
AU.addRequired<MachineDominatorTree>();
|
||||||
AU.addPreserved<MachineDominatorTree>();
|
AU.addPreserved<MachineDominatorTree>();
|
||||||
AU.addRequired<MachineLoopInfo>();
|
AU.addRequired<MachineLoopInfo>();
|
||||||
@ -119,6 +123,9 @@ namespace {
|
|||||||
/// HazardRec - The hazard recognizer to use.
|
/// HazardRec - The hazard recognizer to use.
|
||||||
ScheduleHazardRecognizer *HazardRec;
|
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
|
/// 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
|
/// live range, the register class. If the register is not live, the
|
||||||
/// corresponding value is null. If the register is live but used in
|
/// corresponding value is null. If the register is live but used in
|
||||||
@ -146,10 +153,11 @@ namespace {
|
|||||||
SchedulePostRATDList(MachineFunction &MF,
|
SchedulePostRATDList(MachineFunction &MF,
|
||||||
const MachineLoopInfo &MLI,
|
const MachineLoopInfo &MLI,
|
||||||
const MachineDominatorTree &MDT,
|
const MachineDominatorTree &MDT,
|
||||||
ScheduleHazardRecognizer *HR)
|
ScheduleHazardRecognizer *HR,
|
||||||
|
AliasAnalysis *aa)
|
||||||
: ScheduleDAGInstrs(MF, MLI, MDT), Topo(SUnits),
|
: ScheduleDAGInstrs(MF, MLI, MDT), Topo(SUnits),
|
||||||
AllocatableSet(TRI->getAllocatableSet(MF)),
|
AllocatableSet(TRI->getAllocatableSet(MF)),
|
||||||
HazardRec(HR) {}
|
HazardRec(HR), AA(aa) {}
|
||||||
|
|
||||||
~SchedulePostRATDList() {
|
~SchedulePostRATDList() {
|
||||||
delete HazardRec;
|
delete HazardRec;
|
||||||
@ -241,7 +249,7 @@ bool PostRAScheduler::runOnMachineFunction(MachineFunction &Fn) {
|
|||||||
(ScheduleHazardRecognizer *)new ExactHazardRecognizer(InstrItins) :
|
(ScheduleHazardRecognizer *)new ExactHazardRecognizer(InstrItins) :
|
||||||
(ScheduleHazardRecognizer *)new SimpleHazardRecognizer();
|
(ScheduleHazardRecognizer *)new SimpleHazardRecognizer();
|
||||||
|
|
||||||
SchedulePostRATDList Scheduler(Fn, MLI, MDT, HR);
|
SchedulePostRATDList Scheduler(Fn, MLI, MDT, HR, AA);
|
||||||
|
|
||||||
// Loop over all of the basic blocks
|
// Loop over all of the basic blocks
|
||||||
for (MachineFunction::iterator MBB = Fn.begin(), MBBe = Fn.end();
|
for (MachineFunction::iterator MBB = Fn.begin(), MBBe = Fn.end();
|
||||||
@ -379,7 +387,7 @@ void SchedulePostRATDList::Schedule() {
|
|||||||
DEBUG(errs() << "********** List Scheduling **********\n");
|
DEBUG(errs() << "********** List Scheduling **********\n");
|
||||||
|
|
||||||
// Build the scheduling graph.
|
// Build the scheduling graph.
|
||||||
BuildSchedGraph();
|
BuildSchedGraph(AA);
|
||||||
|
|
||||||
if (EnableAntiDepBreaking) {
|
if (EnableAntiDepBreaking) {
|
||||||
if (BreakAntiDependencies()) {
|
if (BreakAntiDependencies()) {
|
||||||
@ -392,7 +400,7 @@ void SchedulePostRATDList::Schedule() {
|
|||||||
SUnits.clear();
|
SUnits.clear();
|
||||||
EntrySU = SUnit();
|
EntrySU = SUnit();
|
||||||
ExitSU = 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
|
// We'll be allocating one SUnit for each instruction, plus one for
|
||||||
// the region exit node.
|
// the region exit node.
|
||||||
SUnits.reserve(BB->size());
|
SUnits.reserve(BB->size());
|
||||||
@ -375,7 +375,7 @@ void ScheduleDAGInstrs::BuildSchedGraph() {
|
|||||||
// Treat all other stores conservatively.
|
// Treat all other stores conservatively.
|
||||||
goto new_chain;
|
goto new_chain;
|
||||||
} else if (TID.mayLoad()) {
|
} else if (TID.mayLoad()) {
|
||||||
if (MI->isInvariantLoad()) {
|
if (MI->isInvariantLoad(AA)) {
|
||||||
// Invariant load, no chain dependencies needed!
|
// Invariant load, no chain dependencies needed!
|
||||||
} else if (const Value *V = getUnderlyingObjectForInstr(MI)) {
|
} else if (const Value *V = getUnderlyingObjectForInstr(MI)) {
|
||||||
// A load from a specific PseudoSourceValue. Add precise dependencies.
|
// A load from a specific PseudoSourceValue. Add precise dependencies.
|
||||||
|
@ -155,7 +155,7 @@ namespace llvm {
|
|||||||
|
|
||||||
/// BuildSchedGraph - Build SUnits from the MachineBasicBlock that we are
|
/// BuildSchedGraph - Build SUnits from the MachineBasicBlock that we are
|
||||||
/// input.
|
/// input.
|
||||||
virtual void BuildSchedGraph();
|
virtual void BuildSchedGraph(AliasAnalysis *AA);
|
||||||
|
|
||||||
/// ComputeLatency - Compute node latency.
|
/// ComputeLatency - Compute node latency.
|
||||||
///
|
///
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "VirtRegMap.h"
|
#include "VirtRegMap.h"
|
||||||
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
|
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
|
||||||
#include "llvm/Value.h"
|
#include "llvm/Value.h"
|
||||||
|
#include "llvm/Analysis/AliasAnalysis.h"
|
||||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||||
#include "llvm/CodeGen/MachineInstr.h"
|
#include "llvm/CodeGen/MachineInstr.h"
|
||||||
#include "llvm/CodeGen/MachineLoopInfo.h"
|
#include "llvm/CodeGen/MachineLoopInfo.h"
|
||||||
@ -72,6 +73,7 @@ const PassInfo *const llvm::SimpleRegisterCoalescingID = &X;
|
|||||||
|
|
||||||
void SimpleRegisterCoalescing::getAnalysisUsage(AnalysisUsage &AU) const {
|
void SimpleRegisterCoalescing::getAnalysisUsage(AnalysisUsage &AU) const {
|
||||||
AU.setPreservesCFG();
|
AU.setPreservesCFG();
|
||||||
|
AU.addRequired<AliasAnalysis>();
|
||||||
AU.addRequired<LiveIntervals>();
|
AU.addRequired<LiveIntervals>();
|
||||||
AU.addPreserved<LiveIntervals>();
|
AU.addPreserved<LiveIntervals>();
|
||||||
AU.addRequired<MachineLoopInfo>();
|
AU.addRequired<MachineLoopInfo>();
|
||||||
@ -646,10 +648,10 @@ bool SimpleRegisterCoalescing::ReMaterializeTrivialDef(LiveInterval &SrcInt,
|
|||||||
const TargetInstrDesc &TID = DefMI->getDesc();
|
const TargetInstrDesc &TID = DefMI->getDesc();
|
||||||
if (!TID.isAsCheapAsAMove())
|
if (!TID.isAsCheapAsAMove())
|
||||||
return false;
|
return false;
|
||||||
if (!tii_->isTriviallyReMaterializable(DefMI))
|
if (!tii_->isTriviallyReMaterializable(DefMI, AA))
|
||||||
return false;
|
return false;
|
||||||
bool SawStore = false;
|
bool SawStore = false;
|
||||||
if (!DefMI->isSafeToMove(tii_, SawStore))
|
if (!DefMI->isSafeToMove(tii_, SawStore, AA))
|
||||||
return false;
|
return false;
|
||||||
if (TID.getNumDefs() != 1)
|
if (TID.getNumDefs() != 1)
|
||||||
return false;
|
return false;
|
||||||
@ -2655,6 +2657,7 @@ bool SimpleRegisterCoalescing::runOnMachineFunction(MachineFunction &fn) {
|
|||||||
tri_ = tm_->getRegisterInfo();
|
tri_ = tm_->getRegisterInfo();
|
||||||
tii_ = tm_->getInstrInfo();
|
tii_ = tm_->getInstrInfo();
|
||||||
li_ = &getAnalysis<LiveIntervals>();
|
li_ = &getAnalysis<LiveIntervals>();
|
||||||
|
AA = &getAnalysis<AliasAnalysis>();
|
||||||
loopInfo = &getAnalysis<MachineLoopInfo>();
|
loopInfo = &getAnalysis<MachineLoopInfo>();
|
||||||
|
|
||||||
DEBUG(errs() << "********** SIMPLE REGISTER COALESCING **********\n"
|
DEBUG(errs() << "********** SIMPLE REGISTER COALESCING **********\n"
|
||||||
|
@ -45,6 +45,7 @@ namespace llvm {
|
|||||||
const TargetInstrInfo* tii_;
|
const TargetInstrInfo* tii_;
|
||||||
LiveIntervals *li_;
|
LiveIntervals *li_;
|
||||||
const MachineLoopInfo* loopInfo;
|
const MachineLoopInfo* loopInfo;
|
||||||
|
AliasAnalysis *AA;
|
||||||
|
|
||||||
BitVector allocatableRegs_;
|
BitVector allocatableRegs_;
|
||||||
DenseMap<const TargetRegisterClass*, BitVector> allocatableRCRegs_;
|
DenseMap<const TargetRegisterClass*, BitVector> allocatableRCRegs_;
|
||||||
|
@ -13,11 +13,14 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "llvm/Target/TargetInstrInfo.h"
|
#include "llvm/Target/TargetInstrInfo.h"
|
||||||
|
#include "llvm/Target/TargetMachine.h"
|
||||||
|
#include "llvm/Target/TargetRegisterInfo.h"
|
||||||
#include "llvm/ADT/SmallVector.h"
|
#include "llvm/ADT/SmallVector.h"
|
||||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||||
#include "llvm/CodeGen/MachineInstr.h"
|
#include "llvm/CodeGen/MachineInstr.h"
|
||||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||||
#include "llvm/CodeGen/MachineMemOperand.h"
|
#include "llvm/CodeGen/MachineMemOperand.h"
|
||||||
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||||
#include "llvm/CodeGen/PseudoSourceValue.h"
|
#include "llvm/CodeGen/PseudoSourceValue.h"
|
||||||
#include "llvm/Support/ErrorHandling.h"
|
#include "llvm/Support/ErrorHandling.h"
|
||||||
#include "llvm/Support/raw_ostream.h"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
@ -238,3 +241,88 @@ TargetInstrInfo::foldMemoryOperand(MachineFunction &MF,
|
|||||||
|
|
||||||
return NewMI;
|
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/MachineFunctionPass.h"
|
||||||
#include "llvm/CodeGen/MachineInstr.h"
|
#include "llvm/CodeGen/MachineInstr.h"
|
||||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||||
|
#include "llvm/Analysis/AliasAnalysis.h"
|
||||||
#include "llvm/Target/TargetRegisterInfo.h"
|
#include "llvm/Target/TargetRegisterInfo.h"
|
||||||
#include "llvm/Target/TargetInstrInfo.h"
|
#include "llvm/Target/TargetInstrInfo.h"
|
||||||
#include "llvm/Target/TargetMachine.h"
|
#include "llvm/Target/TargetMachine.h"
|
||||||
@ -62,6 +63,7 @@ namespace {
|
|||||||
const TargetRegisterInfo *TRI;
|
const TargetRegisterInfo *TRI;
|
||||||
MachineRegisterInfo *MRI;
|
MachineRegisterInfo *MRI;
|
||||||
LiveVariables *LV;
|
LiveVariables *LV;
|
||||||
|
AliasAnalysis *AA;
|
||||||
|
|
||||||
// DistanceMap - Keep track the distance of a MI from the start of the
|
// DistanceMap - Keep track the distance of a MI from the start of the
|
||||||
// current basic block.
|
// current basic block.
|
||||||
@ -130,6 +132,7 @@ namespace {
|
|||||||
|
|
||||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||||
AU.setPreservesCFG();
|
AU.setPreservesCFG();
|
||||||
|
AU.addRequired<AliasAnalysis>();
|
||||||
AU.addPreserved<LiveVariables>();
|
AU.addPreserved<LiveVariables>();
|
||||||
AU.addPreservedID(MachineLoopInfoID);
|
AU.addPreservedID(MachineLoopInfoID);
|
||||||
AU.addPreservedID(MachineDominatorsID);
|
AU.addPreservedID(MachineDominatorsID);
|
||||||
@ -160,7 +163,7 @@ bool TwoAddressInstructionPass::Sink3AddrInstruction(MachineBasicBlock *MBB,
|
|||||||
MachineBasicBlock::iterator OldPos) {
|
MachineBasicBlock::iterator OldPos) {
|
||||||
// Check if it's safe to move this instruction.
|
// Check if it's safe to move this instruction.
|
||||||
bool SeenStore = true; // Be conservative.
|
bool SeenStore = true; // Be conservative.
|
||||||
if (!MI->isSafeToMove(TII, SeenStore))
|
if (!MI->isSafeToMove(TII, SeenStore, AA))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
unsigned DefReg = 0;
|
unsigned DefReg = 0;
|
||||||
@ -903,6 +906,7 @@ bool TwoAddressInstructionPass::runOnMachineFunction(MachineFunction &MF) {
|
|||||||
TII = TM.getInstrInfo();
|
TII = TM.getInstrInfo();
|
||||||
TRI = TM.getRegisterInfo();
|
TRI = TM.getRegisterInfo();
|
||||||
LV = getAnalysisIfAvailable<LiveVariables>();
|
LV = getAnalysisIfAvailable<LiveVariables>();
|
||||||
|
AA = &getAnalysis<AliasAnalysis>();
|
||||||
|
|
||||||
bool MadeChange = false;
|
bool MadeChange = false;
|
||||||
|
|
||||||
@ -1027,7 +1031,7 @@ bool TwoAddressInstructionPass::runOnMachineFunction(MachineFunction &MF) {
|
|||||||
// copying it.
|
// copying it.
|
||||||
if (DefMI &&
|
if (DefMI &&
|
||||||
DefMI->getDesc().isAsCheapAsAMove() &&
|
DefMI->getDesc().isAsCheapAsAMove() &&
|
||||||
DefMI->isSafeToReMat(TII, regB) &&
|
DefMI->isSafeToReMat(TII, regB, AA) &&
|
||||||
isProfitableToReMat(regB, rc, mi, DefMI, mbbi, Dist)){
|
isProfitableToReMat(regB, rc, mi, DefMI, mbbi, Dist)){
|
||||||
DEBUG(errs() << "2addr: REMATTING : " << *DefMI << "\n");
|
DEBUG(errs() << "2addr: REMATTING : " << *DefMI << "\n");
|
||||||
unsigned regASubIdx = mi->getOperand(DstIdx).getSubReg();
|
unsigned regASubIdx = mi->getOperand(DstIdx).getSubReg();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user