mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-13 20:32:21 +00:00
EXTRACT_SUBREG coalescing support. The coalescer now treats EXTRACT_SUBREG like
(almost) a register copy. However, it always coalesced to the register of the RHS (the super-register). All uses of the result of a EXTRACT_SUBREG are sub- register uses which adds subtle complications to load folding, spiller rewrite, etc. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@42899 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
10136e7c7f
commit
32dfbeada7
@ -155,7 +155,7 @@ namespace llvm {
|
|||||||
|
|
||||||
/// copyValNumInfo - Copy the value number info for one value number to
|
/// copyValNumInfo - Copy the value number info for one value number to
|
||||||
/// another.
|
/// another.
|
||||||
void copyValNumInfo(VNInfo *DstValNo, VNInfo *SrcValNo) {
|
void copyValNumInfo(VNInfo *DstValNo, const VNInfo *SrcValNo) {
|
||||||
DstValNo->def = SrcValNo->def;
|
DstValNo->def = SrcValNo->def;
|
||||||
DstValNo->reg = SrcValNo->reg;
|
DstValNo->reg = SrcValNo->reg;
|
||||||
DstValNo->kills = SrcValNo->kills;
|
DstValNo->kills = SrcValNo->kills;
|
||||||
@ -241,11 +241,23 @@ namespace llvm {
|
|||||||
void MergeInClobberRanges(const LiveInterval &Clobbers,
|
void MergeInClobberRanges(const LiveInterval &Clobbers,
|
||||||
BumpPtrAllocator &VNInfoAllocator);
|
BumpPtrAllocator &VNInfoAllocator);
|
||||||
|
|
||||||
/// MergeRangesInAsValue - Merge all of the intervals in RHS into this live
|
/// MergeRangesInAsValue - Merge all of the live ranges in RHS into this
|
||||||
/// interval as the specified value number. The LiveRanges in RHS are
|
/// live interval as the specified value number. The LiveRanges in RHS are
|
||||||
/// allowed to overlap with LiveRanges in the current interval, but only if
|
/// allowed to overlap with LiveRanges in the current interval, but only if
|
||||||
/// the overlapping LiveRanges have the specified value number.
|
/// the overlapping LiveRanges have the specified value number.
|
||||||
void MergeRangesInAsValue(const LiveInterval &RHS, VNInfo *LHSValNo);
|
void MergeRangesInAsValue(const LiveInterval &RHS, VNInfo *LHSValNo);
|
||||||
|
|
||||||
|
/// MergeValueInAsValue - Merge all of the live ranges of a specific val#
|
||||||
|
/// in RHS into this live interval as the specified value number.
|
||||||
|
/// The LiveRanges in RHS are allowed to overlap with LiveRanges in the
|
||||||
|
/// current interval, but only if the overlapping LiveRanges have the
|
||||||
|
/// specified value number.
|
||||||
|
void MergeValueInAsValue(const LiveInterval &RHS,
|
||||||
|
VNInfo *RHSValNo, VNInfo *LHSValNo);
|
||||||
|
|
||||||
|
/// Copy - Copy the specified live interval. This copies all the fields
|
||||||
|
/// except for the register of the interval.
|
||||||
|
void Copy(const LiveInterval &RHS, BumpPtrAllocator &VNInfoAllocator);
|
||||||
|
|
||||||
bool empty() const { return ranges.empty(); }
|
bool empty() const { return ranges.empty(); }
|
||||||
|
|
||||||
|
@ -167,11 +167,6 @@ namespace llvm {
|
|||||||
return I->second;
|
return I->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// CreateNewLiveInterval - Create a new live interval with the given live
|
|
||||||
/// ranges. The new live interval will have an infinite spill weight.
|
|
||||||
LiveInterval &CreateNewLiveInterval(const LiveInterval *LI,
|
|
||||||
const std::vector<LiveRange> &LRs);
|
|
||||||
|
|
||||||
std::vector<LiveInterval*> addIntervalsForSpills(const LiveInterval& i,
|
std::vector<LiveInterval*> addIntervalsForSpills(const LiveInterval& i,
|
||||||
VirtRegMap& vrm, unsigned reg);
|
VirtRegMap& vrm, unsigned reg);
|
||||||
|
|
||||||
@ -254,8 +249,8 @@ namespace llvm {
|
|||||||
/// MI. If it is successul, MI is updated with the newly created MI and
|
/// MI. If it is successul, MI is updated with the newly created MI and
|
||||||
/// returns true.
|
/// returns true.
|
||||||
bool tryFoldMemoryOperand(MachineInstr* &MI, VirtRegMap &vrm,
|
bool tryFoldMemoryOperand(MachineInstr* &MI, VirtRegMap &vrm,
|
||||||
unsigned index, unsigned i, bool isSS,
|
MachineInstr *DefMI, unsigned index, unsigned i,
|
||||||
MachineInstr *DefMI, int slot, unsigned reg);
|
bool isSS, int slot, unsigned reg);
|
||||||
|
|
||||||
static LiveInterval createInterval(unsigned Reg);
|
static LiveInterval createInterval(unsigned Reg);
|
||||||
|
|
||||||
|
@ -418,6 +418,10 @@ public:
|
|||||||
/// none is found.
|
/// none is found.
|
||||||
int findFirstPredOperandIdx() const;
|
int findFirstPredOperandIdx() const;
|
||||||
|
|
||||||
|
/// isRegReDefinedByTwoAddr - Returns true if the Reg re-definition is due
|
||||||
|
/// to two addr elimination.
|
||||||
|
bool isRegReDefinedByTwoAddr(unsigned Reg) const;
|
||||||
|
|
||||||
/// copyKillDeadInfo - Copies kill / dead operand properties from MI.
|
/// copyKillDeadInfo - Copies kill / dead operand properties from MI.
|
||||||
///
|
///
|
||||||
void copyKillDeadInfo(const MachineInstr *MI);
|
void copyKillDeadInfo(const MachineInstr *MI);
|
||||||
|
@ -26,6 +26,7 @@ class TargetRegisterClass;
|
|||||||
|
|
||||||
class SSARegMap {
|
class SSARegMap {
|
||||||
IndexedMap<const TargetRegisterClass*, VirtReg2IndexFunctor> RegClassMap;
|
IndexedMap<const TargetRegisterClass*, VirtReg2IndexFunctor> RegClassMap;
|
||||||
|
IndexedMap<std::pair<unsigned, unsigned>, VirtReg2IndexFunctor> RegSubIdxMap;
|
||||||
unsigned NextRegNum;
|
unsigned NextRegNum;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -42,12 +43,30 @@ class SSARegMap {
|
|||||||
assert(RegClass && "Cannot create register without RegClass!");
|
assert(RegClass && "Cannot create register without RegClass!");
|
||||||
RegClassMap.grow(NextRegNum);
|
RegClassMap.grow(NextRegNum);
|
||||||
RegClassMap[NextRegNum] = RegClass;
|
RegClassMap[NextRegNum] = RegClass;
|
||||||
|
RegSubIdxMap.grow(NextRegNum);
|
||||||
|
RegSubIdxMap[NextRegNum] = std::make_pair(0,0);
|
||||||
return NextRegNum++;
|
return NextRegNum++;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned getLastVirtReg() const {
|
unsigned getLastVirtReg() const {
|
||||||
return NextRegNum - 1;
|
return NextRegNum - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setIsSubRegister(unsigned Reg, unsigned SuperReg, unsigned SubIdx) {
|
||||||
|
RegSubIdxMap[Reg] = std::make_pair(SuperReg, SubIdx);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isSubRegister(unsigned Reg) const {
|
||||||
|
return RegSubIdxMap[Reg].first != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned getSuperRegister(unsigned Reg) const {
|
||||||
|
return RegSubIdxMap[Reg].first;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned getSubRegisterIndex(unsigned Reg) const {
|
||||||
|
return RegSubIdxMap[Reg].second;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End llvm namespace
|
} // End llvm namespace
|
||||||
|
@ -47,6 +47,10 @@ namespace llvm {
|
|||||||
/// with other intervals.
|
/// with other intervals.
|
||||||
BitVector JoinedLIs;
|
BitVector JoinedLIs;
|
||||||
|
|
||||||
|
/// SubRegIdxes - Keep track of sub-register and sub-indexes.
|
||||||
|
///
|
||||||
|
std::vector<std::pair<unsigned, unsigned> > SubRegIdxes;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static char ID; // Pass identifcation, replacement for typeid
|
static char ID; // Pass identifcation, replacement for typeid
|
||||||
SimpleRegisterCoalescing() : MachineFunctionPass((intptr_t)&ID) {}
|
SimpleRegisterCoalescing() : MachineFunctionPass((intptr_t)&ID) {}
|
||||||
|
@ -383,6 +383,26 @@ void LiveInterval::MergeRangesInAsValue(const LiveInterval &RHS,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// MergeValueInAsValue - Merge all of the live ranges of a specific val#
|
||||||
|
/// in RHS into this live interval as the specified value number.
|
||||||
|
/// The LiveRanges in RHS are allowed to overlap with LiveRanges in the
|
||||||
|
/// current interval, but only if the overlapping LiveRanges have the
|
||||||
|
/// specified value number.
|
||||||
|
void LiveInterval::MergeValueInAsValue(const LiveInterval &RHS,
|
||||||
|
VNInfo *RHSValNo, VNInfo *LHSValNo) {
|
||||||
|
// TODO: Make this more efficient.
|
||||||
|
iterator InsertPos = begin();
|
||||||
|
for (const_iterator I = RHS.begin(), E = RHS.end(); I != E; ++I) {
|
||||||
|
if (I->valno != RHSValNo)
|
||||||
|
continue;
|
||||||
|
// Map the valno in the other live range to the current live range.
|
||||||
|
LiveRange Tmp = *I;
|
||||||
|
Tmp.valno = LHSValNo;
|
||||||
|
InsertPos = addRangeFrom(Tmp, InsertPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// MergeInClobberRanges - For any live ranges that are not defined in the
|
/// MergeInClobberRanges - For any live ranges that are not defined in the
|
||||||
/// current interval, but are defined in the Clobbers interval, mark them
|
/// current interval, but are defined in the Clobbers interval, mark them
|
||||||
/// used with an unknown definition value.
|
/// used with an unknown definition value.
|
||||||
@ -485,6 +505,23 @@ void LiveInterval::MergeValueNumberInto(VNInfo *V1, VNInfo *V2) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LiveInterval::Copy(const LiveInterval &RHS,
|
||||||
|
BumpPtrAllocator &VNInfoAllocator) {
|
||||||
|
ranges.clear();
|
||||||
|
valnos.clear();
|
||||||
|
preference = RHS.preference;
|
||||||
|
weight = RHS.weight;
|
||||||
|
for (unsigned i = 0, e = RHS.getNumValNums(); i != e; ++i) {
|
||||||
|
const VNInfo *VNI = RHS.getValNumInfo(i);
|
||||||
|
VNInfo *NewVNI = getNextValue(~0U, 0, VNInfoAllocator);
|
||||||
|
copyValNumInfo(NewVNI, VNI);
|
||||||
|
}
|
||||||
|
for (unsigned i = 0, e = RHS.ranges.size(); i != e; ++i) {
|
||||||
|
const LiveRange &LR = RHS.ranges[i];
|
||||||
|
addRange(LiveRange(LR.start, LR.end, getValNumInfo(LR.valno->id)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsigned LiveInterval::getSize() const {
|
unsigned LiveInterval::getSize() const {
|
||||||
unsigned Sum = 0;
|
unsigned Sum = 0;
|
||||||
for (const_iterator I = begin(), E = end(); I != E; ++I)
|
for (const_iterator I = begin(), E = end(); I != E; ++I)
|
||||||
|
@ -136,75 +136,6 @@ void LiveIntervals::print(std::ostream &O, const Module* ) const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not called?
|
|
||||||
/// CreateNewLiveInterval - Create a new live interval with the given live
|
|
||||||
/// ranges. The new live interval will have an infinite spill weight.
|
|
||||||
LiveInterval&
|
|
||||||
LiveIntervals::CreateNewLiveInterval(const LiveInterval *LI,
|
|
||||||
const std::vector<LiveRange> &LRs) {
|
|
||||||
const TargetRegisterClass *RC = mf_->getSSARegMap()->getRegClass(LI->reg);
|
|
||||||
|
|
||||||
// Create a new virtual register for the spill interval.
|
|
||||||
unsigned NewVReg = mf_->getSSARegMap()->createVirtualRegister(RC);
|
|
||||||
|
|
||||||
// Replace the old virtual registers in the machine operands with the shiny
|
|
||||||
// new one.
|
|
||||||
for (std::vector<LiveRange>::const_iterator
|
|
||||||
I = LRs.begin(), E = LRs.end(); I != E; ++I) {
|
|
||||||
unsigned Index = getBaseIndex(I->start);
|
|
||||||
unsigned End = getBaseIndex(I->end - 1) + InstrSlots::NUM;
|
|
||||||
|
|
||||||
for (; Index != End; Index += InstrSlots::NUM) {
|
|
||||||
// Skip deleted instructions
|
|
||||||
while (Index != End && !getInstructionFromIndex(Index))
|
|
||||||
Index += InstrSlots::NUM;
|
|
||||||
|
|
||||||
if (Index == End) break;
|
|
||||||
|
|
||||||
MachineInstr *MI = getInstructionFromIndex(Index);
|
|
||||||
|
|
||||||
for (unsigned J = 0, e = MI->getNumOperands(); J != e; ++J) {
|
|
||||||
MachineOperand &MOp = MI->getOperand(J);
|
|
||||||
if (MOp.isRegister() && MOp.getReg() == LI->reg)
|
|
||||||
MOp.setReg(NewVReg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LiveInterval &NewLI = getOrCreateInterval(NewVReg);
|
|
||||||
|
|
||||||
// The spill weight is now infinity as it cannot be spilled again
|
|
||||||
NewLI.weight = float(HUGE_VAL);
|
|
||||||
|
|
||||||
for (std::vector<LiveRange>::const_iterator
|
|
||||||
I = LRs.begin(), E = LRs.end(); I != E; ++I) {
|
|
||||||
DOUT << " Adding live range " << *I << " to new interval\n";
|
|
||||||
NewLI.addRange(*I);
|
|
||||||
}
|
|
||||||
|
|
||||||
DOUT << "Created new live interval " << NewLI << "\n";
|
|
||||||
return NewLI;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// isReDefinedByTwoAddr - Returns true if the Reg re-definition is due to
|
|
||||||
/// two addr elimination.
|
|
||||||
static bool isReDefinedByTwoAddr(MachineInstr *MI, unsigned Reg,
|
|
||||||
const TargetInstrInfo *TII) {
|
|
||||||
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
|
|
||||||
MachineOperand &MO1 = MI->getOperand(i);
|
|
||||||
if (MO1.isRegister() && MO1.isDef() && MO1.getReg() == Reg) {
|
|
||||||
for (unsigned j = i+1; j < e; ++j) {
|
|
||||||
MachineOperand &MO2 = MI->getOperand(j);
|
|
||||||
if (MO2.isRegister() && MO2.isUse() && MO2.getReg() == Reg &&
|
|
||||||
MI->getInstrDescriptor()->
|
|
||||||
getOperandConstraint(j, TOI::TIED_TO) == (int)i)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// isReMaterializable - Returns true if the definition MI of the specified
|
/// isReMaterializable - Returns true if the definition MI of the specified
|
||||||
/// val# of the specified interval is re-materializable.
|
/// val# of the specified interval is re-materializable.
|
||||||
bool LiveIntervals::isReMaterializable(const LiveInterval &li,
|
bool LiveIntervals::isReMaterializable(const LiveInterval &li,
|
||||||
@ -232,7 +163,7 @@ bool LiveIntervals::isReMaterializable(const LiveInterval &li,
|
|||||||
continue; // Dead val#.
|
continue; // Dead val#.
|
||||||
MachineInstr *DefMI = (DefIdx == ~0u)
|
MachineInstr *DefMI = (DefIdx == ~0u)
|
||||||
? NULL : getInstructionFromIndex(DefIdx);
|
? NULL : getInstructionFromIndex(DefIdx);
|
||||||
if (DefMI && isReDefinedByTwoAddr(DefMI, li.reg, tii_))
|
if (DefMI && DefMI->isRegReDefinedByTwoAddr(li.reg))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -243,9 +174,9 @@ bool LiveIntervals::isReMaterializable(const LiveInterval &li,
|
|||||||
/// MI. If it is successul, MI is updated with the newly created MI and
|
/// MI. If it is successul, MI is updated with the newly created MI and
|
||||||
/// returns true.
|
/// returns true.
|
||||||
bool LiveIntervals::tryFoldMemoryOperand(MachineInstr* &MI, VirtRegMap &vrm,
|
bool LiveIntervals::tryFoldMemoryOperand(MachineInstr* &MI, VirtRegMap &vrm,
|
||||||
|
MachineInstr *DefMI,
|
||||||
unsigned index, unsigned i,
|
unsigned index, unsigned i,
|
||||||
bool isSS, MachineInstr *DefMI,
|
bool isSS, int slot, unsigned reg) {
|
||||||
int slot, unsigned reg) {
|
|
||||||
MachineInstr *fmi = isSS
|
MachineInstr *fmi = isSS
|
||||||
? mri_->foldMemoryOperand(MI, i, slot)
|
? mri_->foldMemoryOperand(MI, i, slot)
|
||||||
: mri_->foldMemoryOperand(MI, i, DefMI);
|
: mri_->foldMemoryOperand(MI, i, DefMI);
|
||||||
@ -281,7 +212,8 @@ addIntervalsForSpills(const LiveInterval &li, VirtRegMap &vrm, unsigned reg) {
|
|||||||
li.print(DOUT, mri_);
|
li.print(DOUT, mri_);
|
||||||
DOUT << '\n';
|
DOUT << '\n';
|
||||||
|
|
||||||
const TargetRegisterClass* rc = mf_->getSSARegMap()->getRegClass(li.reg);
|
SSARegMap *RegMap = mf_->getSSARegMap();
|
||||||
|
const TargetRegisterClass* rc = RegMap->getRegClass(li.reg);
|
||||||
|
|
||||||
unsigned NumValNums = li.getNumValNums();
|
unsigned NumValNums = li.getNumValNums();
|
||||||
SmallVector<MachineInstr*, 4> ReMatDefs;
|
SmallVector<MachineInstr*, 4> ReMatDefs;
|
||||||
@ -364,113 +296,126 @@ addIntervalsForSpills(const LiveInterval &li, VirtRegMap &vrm, unsigned reg) {
|
|||||||
RestartInstruction:
|
RestartInstruction:
|
||||||
for (unsigned i = 0; i != MI->getNumOperands(); ++i) {
|
for (unsigned i = 0; i != MI->getNumOperands(); ++i) {
|
||||||
MachineOperand& mop = MI->getOperand(i);
|
MachineOperand& mop = MI->getOperand(i);
|
||||||
if (mop.isRegister() && mop.getReg() == li.reg) {
|
if (!mop.isRegister())
|
||||||
if (DefIsReMat) {
|
continue;
|
||||||
// If this is the rematerializable definition MI itself and
|
unsigned Reg = mop.getReg();
|
||||||
// all of its uses are rematerialized, simply delete it.
|
if (Reg == 0 || MRegisterInfo::isPhysicalRegister(Reg))
|
||||||
if (MI == OrigDefMI) {
|
continue;
|
||||||
if (CanDelete) {
|
bool isSubReg = RegMap->isSubRegister(Reg);
|
||||||
RemoveMachineInstrFromMaps(MI);
|
unsigned SubIdx = 0;
|
||||||
MI->eraseFromParent();
|
if (isSubReg) {
|
||||||
break;
|
SubIdx = RegMap->getSubRegisterIndex(Reg);
|
||||||
} else if (tryFoldMemoryOperand(MI, vrm, index, i, true,
|
Reg = RegMap->getSuperRegister(Reg);
|
||||||
DefMI, slot, li.reg)) {
|
}
|
||||||
// Folding the load/store can completely change the instruction
|
if (Reg != li.reg)
|
||||||
// in unpredictable ways, rescan it from the beginning.
|
continue;
|
||||||
goto RestartInstruction;
|
|
||||||
}
|
bool TryFold = !DefIsReMat;
|
||||||
} else if (isLoad &&
|
bool FoldSS = true;
|
||||||
tryFoldMemoryOperand(MI, vrm, index, i, isLoadSS,
|
int FoldSlot = slot;
|
||||||
DefMI, LdSlot, li.reg))
|
if (DefIsReMat) {
|
||||||
// Folding the load/store can completely change the
|
// If this is the rematerializable definition MI itself and
|
||||||
// instruction in unpredictable ways, rescan it from
|
// all of its uses are rematerialized, simply delete it.
|
||||||
// the beginning.
|
if (MI == OrigDefMI && CanDelete) {
|
||||||
goto RestartInstruction;
|
RemoveMachineInstrFromMaps(MI);
|
||||||
} else {
|
MI->eraseFromParent();
|
||||||
if (tryFoldMemoryOperand(MI, vrm, index, i, true, DefMI,
|
break;
|
||||||
slot, li.reg))
|
|
||||||
// Folding the load/store can completely change the instruction in
|
|
||||||
// unpredictable ways, rescan it from the beginning.
|
|
||||||
goto RestartInstruction;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new virtual register for the spill interval.
|
// If def for this use can't be rematerialized, then try folding.
|
||||||
unsigned NewVReg = mf_->getSSARegMap()->createVirtualRegister(rc);
|
TryFold = !OrigDefMI || (OrigDefMI && (MI == OrigDefMI || isLoad));
|
||||||
|
if (isLoad) {
|
||||||
// Scan all of the operands of this instruction rewriting operands
|
// Try fold loads (from stack slot, constant pool, etc.) into uses.
|
||||||
// to use NewVReg instead of li.reg as appropriate. We do this for
|
FoldSS = isLoadSS;
|
||||||
// two reasons:
|
FoldSlot = LdSlot;
|
||||||
//
|
|
||||||
// 1. If the instr reads the same spilled vreg multiple times, we
|
|
||||||
// want to reuse the NewVReg.
|
|
||||||
// 2. If the instr is a two-addr instruction, we are required to
|
|
||||||
// keep the src/dst regs pinned.
|
|
||||||
//
|
|
||||||
// Keep track of whether we replace a use and/or def so that we can
|
|
||||||
// create the spill interval with the appropriate range.
|
|
||||||
mop.setReg(NewVReg);
|
|
||||||
|
|
||||||
bool HasUse = mop.isUse();
|
|
||||||
bool HasDef = mop.isDef();
|
|
||||||
for (unsigned j = i+1, e = MI->getNumOperands(); j != e; ++j) {
|
|
||||||
if (MI->getOperand(j).isRegister() &&
|
|
||||||
MI->getOperand(j).getReg() == li.reg) {
|
|
||||||
MI->getOperand(j).setReg(NewVReg);
|
|
||||||
HasUse |= MI->getOperand(j).isUse();
|
|
||||||
HasDef |= MI->getOperand(j).isDef();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
vrm.grow();
|
// FIXME: fold subreg use
|
||||||
if (DefIsReMat) {
|
if (!isSubReg && TryFold &&
|
||||||
vrm.setVirtIsReMaterialized(NewVReg, DefMI/*, CanDelete*/);
|
tryFoldMemoryOperand(MI, vrm, DefMI, index, i, FoldSS, FoldSlot, Reg))
|
||||||
if (ReMatIds[I->valno->id] == VirtRegMap::MAX_STACK_SLOT) {
|
// Folding the load/store can completely change the instruction in
|
||||||
// Each valnum may have its own remat id.
|
// unpredictable ways, rescan it from the beginning.
|
||||||
ReMatIds[I->valno->id] = vrm.assignVirtReMatId(NewVReg);
|
goto RestartInstruction;
|
||||||
} else {
|
|
||||||
vrm.assignVirtReMatId(NewVReg, ReMatIds[I->valno->id]);
|
// Create a new virtual register for the spill interval.
|
||||||
}
|
unsigned NewVReg = RegMap->createVirtualRegister(rc);
|
||||||
if (!CanDelete || (HasUse && HasDef)) {
|
if (isSubReg)
|
||||||
// If this is a two-addr instruction then its use operands are
|
RegMap->setIsSubRegister(NewVReg, NewVReg, SubIdx);
|
||||||
// rematerializable but its def is not. It should be assigned a
|
|
||||||
// stack slot.
|
// Scan all of the operands of this instruction rewriting operands
|
||||||
vrm.assignVirt2StackSlot(NewVReg, slot);
|
// to use NewVReg instead of li.reg as appropriate. We do this for
|
||||||
}
|
// two reasons:
|
||||||
|
//
|
||||||
|
// 1. If the instr reads the same spilled vreg multiple times, we
|
||||||
|
// want to reuse the NewVReg.
|
||||||
|
// 2. If the instr is a two-addr instruction, we are required to
|
||||||
|
// keep the src/dst regs pinned.
|
||||||
|
//
|
||||||
|
// Keep track of whether we replace a use and/or def so that we can
|
||||||
|
// create the spill interval with the appropriate range.
|
||||||
|
mop.setReg(NewVReg);
|
||||||
|
|
||||||
|
bool HasUse = mop.isUse();
|
||||||
|
bool HasDef = mop.isDef();
|
||||||
|
for (unsigned j = i+1, e = MI->getNumOperands(); j != e; ++j) {
|
||||||
|
if (MI->getOperand(j).isRegister() &&
|
||||||
|
MI->getOperand(j).getReg() == li.reg) {
|
||||||
|
MI->getOperand(j).setReg(NewVReg);
|
||||||
|
HasUse |= MI->getOperand(j).isUse();
|
||||||
|
HasDef |= MI->getOperand(j).isDef();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vrm.grow();
|
||||||
|
if (DefIsReMat) {
|
||||||
|
vrm.setVirtIsReMaterialized(NewVReg, DefMI/*, CanDelete*/);
|
||||||
|
if (ReMatIds[I->valno->id] == VirtRegMap::MAX_STACK_SLOT) {
|
||||||
|
// Each valnum may have its own remat id.
|
||||||
|
ReMatIds[I->valno->id] = vrm.assignVirtReMatId(NewVReg);
|
||||||
} else {
|
} else {
|
||||||
|
vrm.assignVirtReMatId(NewVReg, ReMatIds[I->valno->id]);
|
||||||
|
}
|
||||||
|
if (!CanDelete || (HasUse && HasDef)) {
|
||||||
|
// If this is a two-addr instruction then its use operands are
|
||||||
|
// rematerializable but its def is not. It should be assigned a
|
||||||
|
// stack slot.
|
||||||
vrm.assignVirt2StackSlot(NewVReg, slot);
|
vrm.assignVirt2StackSlot(NewVReg, slot);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
// create a new register interval for this spill / remat.
|
vrm.assignVirt2StackSlot(NewVReg, slot);
|
||||||
LiveInterval &nI = getOrCreateInterval(NewVReg);
|
|
||||||
assert(nI.empty());
|
|
||||||
|
|
||||||
// the spill weight is now infinity as it
|
|
||||||
// cannot be spilled again
|
|
||||||
nI.weight = HUGE_VALF;
|
|
||||||
|
|
||||||
if (HasUse) {
|
|
||||||
LiveRange LR(getLoadIndex(index), getUseIndex(index)+1,
|
|
||||||
nI.getNextValue(~0U, 0, VNInfoAllocator));
|
|
||||||
DOUT << " +" << LR;
|
|
||||||
nI.addRange(LR);
|
|
||||||
}
|
|
||||||
if (HasDef) {
|
|
||||||
LiveRange LR(getDefIndex(index), getStoreIndex(index),
|
|
||||||
nI.getNextValue(~0U, 0, VNInfoAllocator));
|
|
||||||
DOUT << " +" << LR;
|
|
||||||
nI.addRange(LR);
|
|
||||||
}
|
|
||||||
|
|
||||||
added.push_back(&nI);
|
|
||||||
|
|
||||||
// update live variables if it is available
|
|
||||||
if (lv_)
|
|
||||||
lv_->addVirtualRegisterKilled(NewVReg, MI);
|
|
||||||
|
|
||||||
DOUT << "\t\t\t\tadded new interval: ";
|
|
||||||
nI.print(DOUT, mri_);
|
|
||||||
DOUT << '\n';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// create a new register interval for this spill / remat.
|
||||||
|
LiveInterval &nI = getOrCreateInterval(NewVReg);
|
||||||
|
assert(nI.empty());
|
||||||
|
|
||||||
|
// the spill weight is now infinity as it
|
||||||
|
// cannot be spilled again
|
||||||
|
nI.weight = HUGE_VALF;
|
||||||
|
|
||||||
|
if (HasUse) {
|
||||||
|
LiveRange LR(getLoadIndex(index), getUseIndex(index)+1,
|
||||||
|
nI.getNextValue(~0U, 0, VNInfoAllocator));
|
||||||
|
DOUT << " +" << LR;
|
||||||
|
nI.addRange(LR);
|
||||||
|
}
|
||||||
|
if (HasDef) {
|
||||||
|
LiveRange LR(getDefIndex(index), getStoreIndex(index),
|
||||||
|
nI.getNextValue(~0U, 0, VNInfoAllocator));
|
||||||
|
DOUT << " +" << LR;
|
||||||
|
nI.addRange(LR);
|
||||||
|
}
|
||||||
|
|
||||||
|
added.push_back(&nI);
|
||||||
|
|
||||||
|
// update live variables if it is available
|
||||||
|
if (lv_)
|
||||||
|
lv_->addVirtualRegisterKilled(NewVReg, MI);
|
||||||
|
|
||||||
|
DOUT << "\t\t\t\tadded new interval: ";
|
||||||
|
nI.print(DOUT, mri_);
|
||||||
|
DOUT << '\n';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -501,10 +446,14 @@ void LiveIntervals::handleVirtualRegisterDef(MachineBasicBlock *mbb,
|
|||||||
unsigned defIndex = getDefIndex(MIIdx);
|
unsigned defIndex = getDefIndex(MIIdx);
|
||||||
VNInfo *ValNo;
|
VNInfo *ValNo;
|
||||||
unsigned SrcReg, DstReg;
|
unsigned SrcReg, DstReg;
|
||||||
if (!tii_->isMoveInstr(*mi, SrcReg, DstReg))
|
if (tii_->isMoveInstr(*mi, SrcReg, DstReg))
|
||||||
ValNo = interval.getNextValue(defIndex, 0, VNInfoAllocator);
|
|
||||||
else
|
|
||||||
ValNo = interval.getNextValue(defIndex, SrcReg, VNInfoAllocator);
|
ValNo = interval.getNextValue(defIndex, SrcReg, VNInfoAllocator);
|
||||||
|
else if (mi->getOpcode() == TargetInstrInfo::EXTRACT_SUBREG ||
|
||||||
|
mi->getOpcode() == TargetInstrInfo::INSERT_SUBREG)
|
||||||
|
ValNo = interval.getNextValue(defIndex, mi->getOperand(1).getReg(),
|
||||||
|
VNInfoAllocator);
|
||||||
|
else
|
||||||
|
ValNo = interval.getNextValue(defIndex, 0, VNInfoAllocator);
|
||||||
|
|
||||||
assert(ValNo->id == 0 && "First value in interval is not 0?");
|
assert(ValNo->id == 0 && "First value in interval is not 0?");
|
||||||
|
|
||||||
@ -576,7 +525,7 @@ void LiveIntervals::handleVirtualRegisterDef(MachineBasicBlock *mbb,
|
|||||||
// must be due to phi elimination or two addr elimination. If this is
|
// must be due to phi elimination or two addr elimination. If this is
|
||||||
// the result of two address elimination, then the vreg is one of the
|
// the result of two address elimination, then the vreg is one of the
|
||||||
// def-and-use register operand.
|
// def-and-use register operand.
|
||||||
if (isReDefinedByTwoAddr(mi, interval.reg, tii_)) {
|
if (mi->isRegReDefinedByTwoAddr(interval.reg)) {
|
||||||
// If this is a two-address definition, then we have already processed
|
// If this is a two-address definition, then we have already processed
|
||||||
// the live range. The only problem is that we didn't realize there
|
// the live range. The only problem is that we didn't realize there
|
||||||
// are actually two values in the live interval. Because of this we
|
// are actually two values in the live interval. Because of this we
|
||||||
@ -656,10 +605,13 @@ void LiveIntervals::handleVirtualRegisterDef(MachineBasicBlock *mbb,
|
|||||||
|
|
||||||
VNInfo *ValNo;
|
VNInfo *ValNo;
|
||||||
unsigned SrcReg, DstReg;
|
unsigned SrcReg, DstReg;
|
||||||
if (!tii_->isMoveInstr(*mi, SrcReg, DstReg))
|
if (tii_->isMoveInstr(*mi, SrcReg, DstReg))
|
||||||
ValNo = interval.getNextValue(defIndex, 0, VNInfoAllocator);
|
|
||||||
else
|
|
||||||
ValNo = interval.getNextValue(defIndex, SrcReg, VNInfoAllocator);
|
ValNo = interval.getNextValue(defIndex, SrcReg, VNInfoAllocator);
|
||||||
|
else if (mi->getOpcode() == TargetInstrInfo::EXTRACT_SUBREG)
|
||||||
|
ValNo = interval.getNextValue(defIndex, mi->getOperand(1).getReg(),
|
||||||
|
VNInfoAllocator);
|
||||||
|
else
|
||||||
|
ValNo = interval.getNextValue(defIndex, 0, VNInfoAllocator);
|
||||||
|
|
||||||
unsigned killIndex = getInstructionIndex(&mbb->back()) + InstrSlots::NUM;
|
unsigned killIndex = getInstructionIndex(&mbb->back()) + InstrSlots::NUM;
|
||||||
LiveRange LR(defIndex, killIndex, ValNo);
|
LiveRange LR(defIndex, killIndex, ValNo);
|
||||||
@ -741,7 +693,9 @@ void LiveIntervals::handleRegisterDef(MachineBasicBlock *MBB,
|
|||||||
handleVirtualRegisterDef(MBB, MI, MIIdx, getOrCreateInterval(reg));
|
handleVirtualRegisterDef(MBB, MI, MIIdx, getOrCreateInterval(reg));
|
||||||
else if (allocatableRegs_[reg]) {
|
else if (allocatableRegs_[reg]) {
|
||||||
unsigned SrcReg, DstReg;
|
unsigned SrcReg, DstReg;
|
||||||
if (!tii_->isMoveInstr(*MI, SrcReg, DstReg))
|
if (MI->getOpcode() == TargetInstrInfo::EXTRACT_SUBREG)
|
||||||
|
SrcReg = MI->getOperand(1).getReg();
|
||||||
|
else if (!tii_->isMoveInstr(*MI, SrcReg, DstReg))
|
||||||
SrcReg = 0;
|
SrcReg = 0;
|
||||||
handlePhysicalRegisterDef(MBB, MI, MIIdx, getOrCreateInterval(reg), SrcReg);
|
handlePhysicalRegisterDef(MBB, MI, MIIdx, getOrCreateInterval(reg), SrcReg);
|
||||||
// Def of a register also defines its sub-registers.
|
// Def of a register also defines its sub-registers.
|
||||||
|
@ -220,6 +220,24 @@ int MachineInstr::findFirstPredOperandIdx() const {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// isRegReDefinedByTwoAddr - Returns true if the Reg re-definition is due
|
||||||
|
/// to two addr elimination.
|
||||||
|
bool MachineInstr::isRegReDefinedByTwoAddr(unsigned Reg) const {
|
||||||
|
const TargetInstrDescriptor *TID = getInstrDescriptor();
|
||||||
|
for (unsigned i = 0, e = getNumOperands(); i != e; ++i) {
|
||||||
|
const MachineOperand &MO1 = getOperand(i);
|
||||||
|
if (MO1.isRegister() && MO1.isDef() && MO1.getReg() == Reg) {
|
||||||
|
for (unsigned j = i+1; j < e; ++j) {
|
||||||
|
const MachineOperand &MO2 = getOperand(j);
|
||||||
|
if (MO2.isRegister() && MO2.isUse() && MO2.getReg() == Reg &&
|
||||||
|
TID->getOperandConstraint(j, TOI::TIED_TO) == (int)i)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// copyKillDeadInfo - Copies kill / dead operand properties from MI.
|
/// copyKillDeadInfo - Copies kill / dead operand properties from MI.
|
||||||
///
|
///
|
||||||
void MachineInstr::copyKillDeadInfo(const MachineInstr *MI) {
|
void MachineInstr::copyKillDeadInfo(const MachineInstr *MI) {
|
||||||
|
@ -567,9 +567,6 @@ void ScheduleDAG::EmitSubregNode(SDNode *Node,
|
|||||||
// TODO: If the node is a use of a CopyFromReg from a physical register
|
// TODO: If the node is a use of a CopyFromReg from a physical register
|
||||||
// fold the extract into the copy now
|
// fold the extract into the copy now
|
||||||
|
|
||||||
// TODO: Add tracking info to SSARegMap of which vregs are subregs
|
|
||||||
// to allow coalescing in the allocator
|
|
||||||
|
|
||||||
// Create the extract_subreg machine instruction.
|
// Create the extract_subreg machine instruction.
|
||||||
MachineInstr *MI =
|
MachineInstr *MI =
|
||||||
new MachineInstr(BB, TII->get(TargetInstrInfo::EXTRACT_SUBREG));
|
new MachineInstr(BB, TII->get(TargetInstrInfo::EXTRACT_SUBREG));
|
||||||
|
@ -1097,6 +1097,11 @@ namespace {
|
|||||||
// CopyToReg should be close to its uses to facilitate coalescing and
|
// CopyToReg should be close to its uses to facilitate coalescing and
|
||||||
// avoid spilling.
|
// avoid spilling.
|
||||||
return 0;
|
return 0;
|
||||||
|
else if (Opc == TargetInstrInfo::EXTRACT_SUBREG ||
|
||||||
|
Opc == TargetInstrInfo::INSERT_SUBREG)
|
||||||
|
// EXTRACT_SUBREG / INSERT_SUBREG should be close to its use to
|
||||||
|
// facilitate coalescing.
|
||||||
|
return 0;
|
||||||
else if (SU->NumSuccs == 0)
|
else if (SU->NumSuccs == 0)
|
||||||
// If SU does not have a use, i.e. it doesn't produce a value that would
|
// If SU does not have a use, i.e. it doesn't produce a value that would
|
||||||
// be consumed (e.g. store), then it terminates a chain of computation.
|
// be consumed (e.g. store), then it terminates a chain of computation.
|
||||||
@ -1308,6 +1313,14 @@ void BURegReductionPriorityQueue<SF>::AddPseudoTwoAddrDeps() {
|
|||||||
// Be conservative. Ignore if nodes aren't at the same depth.
|
// Be conservative. Ignore if nodes aren't at the same depth.
|
||||||
if (SuccSU->Depth != SU->Depth)
|
if (SuccSU->Depth != SU->Depth)
|
||||||
continue;
|
continue;
|
||||||
|
if (!SuccSU->Node || !SuccSU->Node->isTargetOpcode())
|
||||||
|
continue;
|
||||||
|
// Don't constraint extract_subreg / insert_subreg these may be
|
||||||
|
// coalesced away. We don't them close to their uses.
|
||||||
|
unsigned SuccOpc = SuccSU->Node->getTargetOpcode();
|
||||||
|
if (SuccOpc == TargetInstrInfo::EXTRACT_SUBREG ||
|
||||||
|
SuccOpc == TargetInstrInfo::INSERT_SUBREG)
|
||||||
|
continue;
|
||||||
if ((!canClobber(SuccSU, DUSU) ||
|
if ((!canClobber(SuccSU, DUSU) ||
|
||||||
(hasCopyToRegUse(SU) && !hasCopyToRegUse(SuccSU)) ||
|
(hasCopyToRegUse(SU) && !hasCopyToRegUse(SuccSU)) ||
|
||||||
(!SU->isCommutable && SuccSU->isCommutable)) &&
|
(!SU->isCommutable && SuccSU->isCommutable)) &&
|
||||||
|
@ -226,11 +226,55 @@ bool SimpleRegisterCoalescing::JoinCopy(MachineInstr *CopyMI,
|
|||||||
DOUT << "\tDst reg is unallocatable physreg.\n";
|
DOUT << "\tDst reg is unallocatable physreg.\n";
|
||||||
return true; // Not coalescable.
|
return true; // Not coalescable.
|
||||||
}
|
}
|
||||||
|
|
||||||
// If they are not of the same register class, we cannot join them.
|
bool isExtSubReg = CopyMI->getOpcode() == TargetInstrInfo::EXTRACT_SUBREG;
|
||||||
if (differingRegisterClasses(repSrcReg, repDstReg)) {
|
unsigned RealDstReg = 0;
|
||||||
|
if (isExtSubReg) {
|
||||||
|
unsigned SubIdx = CopyMI->getOperand(2).getImm();
|
||||||
|
if (SrcIsPhys)
|
||||||
|
// r1024 = EXTRACT_SUBREG EAX, 0 then r1024 is really going to be
|
||||||
|
// coalesced with AX.
|
||||||
|
repSrcReg = mri_->getSubReg(repSrcReg, SubIdx);
|
||||||
|
else if (DstIsPhys) {
|
||||||
|
// If this is a extract_subreg where dst is a physical register, e.g.
|
||||||
|
// cl = EXTRACT_SUBREG reg1024, 1
|
||||||
|
// then create and update the actual physical register allocated to RHS.
|
||||||
|
const TargetRegisterClass *RC = mf_->getSSARegMap()->getRegClass(SrcReg);
|
||||||
|
for (const unsigned *SRs = mri_->getSuperRegisters(repDstReg);
|
||||||
|
unsigned SR = *SRs; ++SRs) {
|
||||||
|
if (repDstReg == mri_->getSubReg(SR, SubIdx) &&
|
||||||
|
RC->contains(SR)) {
|
||||||
|
RealDstReg = SR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(RealDstReg && "Invalid extra_subreg instruction!");
|
||||||
|
|
||||||
|
// For this type of EXTRACT_SUBREG, conservatively
|
||||||
|
// check if the live interval of the source register interfere with the
|
||||||
|
// actual super physical register we are trying to coalesce with.
|
||||||
|
LiveInterval &RHS = li_->getInterval(repSrcReg);
|
||||||
|
if (li_->hasInterval(RealDstReg) &&
|
||||||
|
RHS.overlaps(li_->getInterval(RealDstReg))) {
|
||||||
|
DOUT << "Interfere with register ";
|
||||||
|
DEBUG(li_->getInterval(RealDstReg).print(DOUT, mri_));
|
||||||
|
return true; // Not coalescable
|
||||||
|
}
|
||||||
|
for (const unsigned* SR = mri_->getSubRegisters(RealDstReg); *SR; ++SR)
|
||||||
|
if (li_->hasInterval(*SR) && RHS.overlaps(li_->getInterval(*SR))) {
|
||||||
|
DOUT << "Interfere with sub-register ";
|
||||||
|
DEBUG(li_->getInterval(*SR).print(DOUT, mri_));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (differingRegisterClasses(repSrcReg, repDstReg)) {
|
||||||
|
// If they are not of the same register class, we cannot join them.
|
||||||
DOUT << "\tSrc/Dest are different register classes.\n";
|
DOUT << "\tSrc/Dest are different register classes.\n";
|
||||||
return true; // Not coalescable.
|
// Allow the coalescer to try again in case either side gets coalesced to
|
||||||
|
// a physical register that's compatible with the other side. e.g.
|
||||||
|
// r1024 = MOV32to32_ r1025
|
||||||
|
// but later r1024 is assigned EAX then r1025 may be coalesced with EAX.
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LiveInterval &SrcInt = li_->getInterval(repSrcReg);
|
LiveInterval &SrcInt = li_->getInterval(repSrcReg);
|
||||||
@ -286,14 +330,14 @@ bool SimpleRegisterCoalescing::JoinCopy(MachineInstr *CopyMI,
|
|||||||
// virtual register. Once the coalescing is done, it cannot be broken and
|
// virtual register. Once the coalescing is done, it cannot be broken and
|
||||||
// these are not spillable! If the destination interval uses are far away,
|
// these are not spillable! If the destination interval uses are far away,
|
||||||
// think twice about coalescing them!
|
// think twice about coalescing them!
|
||||||
if (!mopd->isDead() && (SrcIsPhys || DstIsPhys)) {
|
if (!mopd->isDead() && (SrcIsPhys || DstIsPhys) && !isExtSubReg) {
|
||||||
LiveInterval &JoinVInt = SrcIsPhys ? DstInt : SrcInt;
|
LiveInterval &JoinVInt = SrcIsPhys ? DstInt : SrcInt;
|
||||||
unsigned JoinVReg = SrcIsPhys ? repDstReg : repSrcReg;
|
unsigned JoinVReg = SrcIsPhys ? repDstReg : repSrcReg;
|
||||||
unsigned JoinPReg = SrcIsPhys ? repSrcReg : repDstReg;
|
unsigned JoinPReg = SrcIsPhys ? repSrcReg : repDstReg;
|
||||||
const TargetRegisterClass *RC = mf_->getSSARegMap()->getRegClass(JoinVReg);
|
const TargetRegisterClass *RC = mf_->getSSARegMap()->getRegClass(JoinVReg);
|
||||||
unsigned Threshold = allocatableRCRegs_[RC].count();
|
unsigned Threshold = allocatableRCRegs_[RC].count();
|
||||||
|
|
||||||
// If the virtual register live interval is long has it has low use desity,
|
// If the virtual register live interval is long but it has low use desity,
|
||||||
// do not join them, instead mark the physical register as its allocation
|
// do not join them, instead mark the physical register as its allocation
|
||||||
// preference.
|
// preference.
|
||||||
unsigned Length = JoinVInt.getSize() / InstrSlots::NUM;
|
unsigned Length = JoinVInt.getSize() / InstrSlots::NUM;
|
||||||
@ -340,7 +384,7 @@ bool SimpleRegisterCoalescing::JoinCopy(MachineInstr *CopyMI,
|
|||||||
// Coalescing failed.
|
// Coalescing failed.
|
||||||
|
|
||||||
// If we can eliminate the copy without merging the live ranges, do so now.
|
// If we can eliminate the copy without merging the live ranges, do so now.
|
||||||
if (AdjustCopiesBackFrom(SrcInt, DstInt, CopyMI))
|
if (!isExtSubReg && AdjustCopiesBackFrom(SrcInt, DstInt, CopyMI))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Otherwise, we are unable to join the intervals.
|
// Otherwise, we are unable to join the intervals.
|
||||||
@ -368,9 +412,24 @@ bool SimpleRegisterCoalescing::JoinCopy(MachineInstr *CopyMI,
|
|||||||
unsetRegisterKills(I->start, I->end, repDstReg);
|
unsetRegisterKills(I->start, I->end, repDstReg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this is a extract_subreg where dst is a physical register, e.g.
|
||||||
|
// cl = EXTRACT_SUBREG reg1024, 1
|
||||||
|
// then create and update the actual physical register allocated to RHS.
|
||||||
|
if (RealDstReg) {
|
||||||
|
unsigned CopyIdx = li_->getInstructionIndex(CopyMI);
|
||||||
|
VNInfo *DstValNo =
|
||||||
|
ResDstInt->getLiveRangeContaining(li_->getUseIndex(CopyIdx))->valno;
|
||||||
|
LiveInterval &RealDstInt = li_->getOrCreateInterval(RealDstReg);
|
||||||
|
VNInfo *ValNo = RealDstInt.getNextValue(DstValNo->def, DstValNo->reg,
|
||||||
|
li_->getVNInfoAllocator());
|
||||||
|
RealDstInt.addKills(ValNo, DstValNo->kills);
|
||||||
|
RealDstInt.MergeValueInAsValue(*ResDstInt, DstValNo, ValNo);
|
||||||
|
repDstReg = RealDstReg;
|
||||||
|
}
|
||||||
|
|
||||||
// Update the liveintervals of sub-registers.
|
// Update the liveintervals of sub-registers.
|
||||||
for (const unsigned *AS = mri_->getSubRegisters(repDstReg); *AS; ++AS)
|
for (const unsigned *AS = mri_->getSubRegisters(repDstReg); *AS; ++AS)
|
||||||
li_->getInterval(*AS).MergeInClobberRanges(*ResSrcInt,
|
li_->getOrCreateInterval(*AS).MergeInClobberRanges(*ResSrcInt,
|
||||||
li_->getVNInfoAllocator());
|
li_->getVNInfoAllocator());
|
||||||
} else {
|
} else {
|
||||||
// Merge use info if the destination is a virtual register.
|
// Merge use info if the destination is a virtual register.
|
||||||
@ -379,14 +438,25 @@ bool SimpleRegisterCoalescing::JoinCopy(MachineInstr *CopyMI,
|
|||||||
dVI.NumUses += sVI.NumUses;
|
dVI.NumUses += sVI.NumUses;
|
||||||
}
|
}
|
||||||
|
|
||||||
DOUT << "\n\t\tJoined. Result = "; ResDstInt->print(DOUT, mri_);
|
|
||||||
DOUT << "\n";
|
|
||||||
|
|
||||||
// Remember these liveintervals have been joined.
|
// Remember these liveintervals have been joined.
|
||||||
JoinedLIs.set(repSrcReg - MRegisterInfo::FirstVirtualRegister);
|
JoinedLIs.set(repSrcReg - MRegisterInfo::FirstVirtualRegister);
|
||||||
if (MRegisterInfo::isVirtualRegister(repDstReg))
|
if (MRegisterInfo::isVirtualRegister(repDstReg))
|
||||||
JoinedLIs.set(repDstReg - MRegisterInfo::FirstVirtualRegister);
|
JoinedLIs.set(repDstReg - MRegisterInfo::FirstVirtualRegister);
|
||||||
|
|
||||||
|
if (isExtSubReg && !SrcIsPhys && !DstIsPhys) {
|
||||||
|
if (!Swapped) {
|
||||||
|
// Make sure we allocate the larger super-register.
|
||||||
|
ResSrcInt->Copy(*ResDstInt, li_->getVNInfoAllocator());
|
||||||
|
std::swap(repSrcReg, repDstReg);
|
||||||
|
std::swap(ResSrcInt, ResDstInt);
|
||||||
|
}
|
||||||
|
SubRegIdxes.push_back(std::make_pair(repSrcReg,
|
||||||
|
CopyMI->getOperand(2).getImm()));
|
||||||
|
}
|
||||||
|
|
||||||
|
DOUT << "\n\t\tJoined. Result = "; ResDstInt->print(DOUT, mri_);
|
||||||
|
DOUT << "\n";
|
||||||
|
|
||||||
// repSrcReg is guarateed to be the register whose live interval that is
|
// repSrcReg is guarateed to be the register whose live interval that is
|
||||||
// being merged.
|
// being merged.
|
||||||
li_->removeInterval(repSrcReg);
|
li_->removeInterval(repSrcReg);
|
||||||
@ -857,9 +927,13 @@ void SimpleRegisterCoalescing::CopyCoalesceInMBB(MachineBasicBlock *MBB,
|
|||||||
MII != E;) {
|
MII != E;) {
|
||||||
MachineInstr *Inst = MII++;
|
MachineInstr *Inst = MII++;
|
||||||
|
|
||||||
// If this isn't a copy, we can't join intervals.
|
// If this isn't a copy nor a extract_subreg, we can't join intervals.
|
||||||
unsigned SrcReg, DstReg;
|
unsigned SrcReg, DstReg;
|
||||||
if (!tii_->isMoveInstr(*Inst, SrcReg, DstReg)) continue;
|
if (Inst->getOpcode() == TargetInstrInfo::EXTRACT_SUBREG) {
|
||||||
|
DstReg = Inst->getOperand(0).getReg();
|
||||||
|
SrcReg = Inst->getOperand(1).getReg();
|
||||||
|
} else if (!tii_->isMoveInstr(*Inst, SrcReg, DstReg))
|
||||||
|
continue;
|
||||||
|
|
||||||
bool Done = JoinCopy(Inst, SrcReg, DstReg, PhysOnly);
|
bool Done = JoinCopy(Inst, SrcReg, DstReg, PhysOnly);
|
||||||
if (TryAgain && !Done)
|
if (TryAgain && !Done)
|
||||||
@ -950,7 +1024,7 @@ void SimpleRegisterCoalescing::joinIntervals() {
|
|||||||
/// Return true if the two specified registers belong to different register
|
/// Return true if the two specified registers belong to different register
|
||||||
/// classes. The registers may be either phys or virt regs.
|
/// classes. The registers may be either phys or virt regs.
|
||||||
bool SimpleRegisterCoalescing::differingRegisterClasses(unsigned RegA,
|
bool SimpleRegisterCoalescing::differingRegisterClasses(unsigned RegA,
|
||||||
unsigned RegB) const {
|
unsigned RegB) const {
|
||||||
|
|
||||||
// Get the register classes for the first reg.
|
// Get the register classes for the first reg.
|
||||||
if (MRegisterInfo::isPhysicalRegister(RegA)) {
|
if (MRegisterInfo::isPhysicalRegister(RegA)) {
|
||||||
@ -1074,6 +1148,7 @@ void SimpleRegisterCoalescing::printRegName(unsigned reg) const {
|
|||||||
void SimpleRegisterCoalescing::releaseMemory() {
|
void SimpleRegisterCoalescing::releaseMemory() {
|
||||||
r2rMap_.clear();
|
r2rMap_.clear();
|
||||||
JoinedLIs.clear();
|
JoinedLIs.clear();
|
||||||
|
SubRegIdxes.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isZeroLengthInterval(LiveInterval *li) {
|
static bool isZeroLengthInterval(LiveInterval *li) {
|
||||||
@ -1101,7 +1176,8 @@ bool SimpleRegisterCoalescing::runOnMachineFunction(MachineFunction &fn) {
|
|||||||
E = mri_->regclass_end(); I != E; ++I)
|
E = mri_->regclass_end(); I != E; ++I)
|
||||||
allocatableRCRegs_.insert(std::make_pair(*I,mri_->getAllocatableSet(fn, *I)));
|
allocatableRCRegs_.insert(std::make_pair(*I,mri_->getAllocatableSet(fn, *I)));
|
||||||
|
|
||||||
r2rMap_.grow(mf_->getSSARegMap()->getLastVirtReg());
|
SSARegMap *RegMap = mf_->getSSARegMap();
|
||||||
|
r2rMap_.grow(RegMap->getLastVirtReg());
|
||||||
|
|
||||||
// Join (coalesce) intervals if requested.
|
// Join (coalesce) intervals if requested.
|
||||||
if (EnableJoining) {
|
if (EnableJoining) {
|
||||||
@ -1111,6 +1187,13 @@ bool SimpleRegisterCoalescing::runOnMachineFunction(MachineFunction &fn) {
|
|||||||
I->second.print(DOUT, mri_);
|
I->second.print(DOUT, mri_);
|
||||||
DOUT << "\n";
|
DOUT << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Track coalesced sub-registers.
|
||||||
|
while (!SubRegIdxes.empty()) {
|
||||||
|
std::pair<unsigned, unsigned> RI = SubRegIdxes.back();
|
||||||
|
SubRegIdxes.pop_back();
|
||||||
|
mf_->getSSARegMap()->setIsSubRegister(RI.first, rep(RI.first), RI.second);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// perform a final pass over the instructions and compute spill
|
// perform a final pass over the instructions and compute spill
|
||||||
@ -1150,8 +1233,14 @@ bool SimpleRegisterCoalescing::runOnMachineFunction(MachineFunction &fn) {
|
|||||||
if (mop.isRegister() && mop.getReg() &&
|
if (mop.isRegister() && mop.getReg() &&
|
||||||
MRegisterInfo::isVirtualRegister(mop.getReg())) {
|
MRegisterInfo::isVirtualRegister(mop.getReg())) {
|
||||||
// replace register with representative register
|
// replace register with representative register
|
||||||
unsigned reg = rep(mop.getReg());
|
unsigned OrigReg = mop.getReg();
|
||||||
mii->getOperand(i).setReg(reg);
|
unsigned reg = rep(OrigReg);
|
||||||
|
// Don't rewrite if it is a sub-register of a virtual register.
|
||||||
|
if (!RegMap->isSubRegister(OrigReg))
|
||||||
|
mii->getOperand(i).setReg(reg);
|
||||||
|
else if (MRegisterInfo::isPhysicalRegister(reg))
|
||||||
|
mii->getOperand(i).setReg(mri_->getSubReg(reg,
|
||||||
|
RegMap->getSubRegisterIndex(OrigReg)));
|
||||||
|
|
||||||
// Multiple uses of reg by the same instruction. It should not
|
// Multiple uses of reg by the same instruction. It should not
|
||||||
// contribute to spill weight again.
|
// contribute to spill weight again.
|
||||||
|
@ -242,10 +242,12 @@ namespace {
|
|||||||
/// blocks that have low register pressure (the vreg may be spilled due to
|
/// blocks that have low register pressure (the vreg may be spilled due to
|
||||||
/// register pressure in other blocks).
|
/// register pressure in other blocks).
|
||||||
class VISIBILITY_HIDDEN LocalSpiller : public Spiller {
|
class VISIBILITY_HIDDEN LocalSpiller : public Spiller {
|
||||||
|
SSARegMap *RegMap;
|
||||||
const MRegisterInfo *MRI;
|
const MRegisterInfo *MRI;
|
||||||
const TargetInstrInfo *TII;
|
const TargetInstrInfo *TII;
|
||||||
public:
|
public:
|
||||||
bool runOnMachineFunction(MachineFunction &MF, VirtRegMap &VRM) {
|
bool runOnMachineFunction(MachineFunction &MF, VirtRegMap &VRM) {
|
||||||
|
RegMap = MF.getSSARegMap();
|
||||||
MRI = MF.getTarget().getRegisterInfo();
|
MRI = MF.getTarget().getRegisterInfo();
|
||||||
TII = MF.getTarget().getInstrInfo();
|
TII = MF.getTarget().getInstrInfo();
|
||||||
DOUT << "\n**** Local spiller rewriting function '"
|
DOUT << "\n**** Local spiller rewriting function '"
|
||||||
@ -776,25 +778,33 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM) {
|
|||||||
if (!MO.isRegister() || MO.getReg() == 0)
|
if (!MO.isRegister() || MO.getReg() == 0)
|
||||||
continue; // Ignore non-register operands.
|
continue; // Ignore non-register operands.
|
||||||
|
|
||||||
if (MRegisterInfo::isPhysicalRegister(MO.getReg())) {
|
unsigned VirtReg = MO.getReg();
|
||||||
|
if (MRegisterInfo::isPhysicalRegister(VirtReg)) {
|
||||||
// Ignore physregs for spilling, but remember that it is used by this
|
// Ignore physregs for spilling, but remember that it is used by this
|
||||||
// function.
|
// function.
|
||||||
MF.setPhysRegUsed(MO.getReg());
|
MF.setPhysRegUsed(VirtReg);
|
||||||
ReusedOperands.markClobbered(MO.getReg());
|
ReusedOperands.markClobbered(VirtReg);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(MRegisterInfo::isVirtualRegister(MO.getReg()) &&
|
assert(MRegisterInfo::isVirtualRegister(VirtReg) &&
|
||||||
"Not a virtual or a physical register?");
|
"Not a virtual or a physical register?");
|
||||||
|
|
||||||
unsigned VirtReg = MO.getReg();
|
unsigned SubIdx = 0;
|
||||||
|
bool isSubReg = RegMap->isSubRegister(VirtReg);
|
||||||
|
if (isSubReg) {
|
||||||
|
SubIdx = RegMap->getSubRegisterIndex(VirtReg);
|
||||||
|
VirtReg = RegMap->getSuperRegister(VirtReg);
|
||||||
|
}
|
||||||
|
|
||||||
if (VRM.isAssignedReg(VirtReg)) {
|
if (VRM.isAssignedReg(VirtReg)) {
|
||||||
// This virtual register was assigned a physreg!
|
// This virtual register was assigned a physreg!
|
||||||
unsigned Phys = VRM.getPhys(VirtReg);
|
unsigned Phys = VRM.getPhys(VirtReg);
|
||||||
MF.setPhysRegUsed(Phys);
|
MF.setPhysRegUsed(Phys);
|
||||||
if (MO.isDef())
|
if (MO.isDef())
|
||||||
ReusedOperands.markClobbered(Phys);
|
ReusedOperands.markClobbered(Phys);
|
||||||
MI.getOperand(i).setReg(Phys);
|
unsigned RReg = isSubReg ? MRI->getSubReg(Phys, SubIdx) : Phys;
|
||||||
|
MI.getOperand(i).setReg(RReg);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -817,6 +827,24 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM) {
|
|||||||
if (ReuseSlot != VirtRegMap::NO_STACK_SLOT)
|
if (ReuseSlot != VirtRegMap::NO_STACK_SLOT)
|
||||||
PhysReg = Spills.getSpillSlotOrReMatPhysReg(ReuseSlot);
|
PhysReg = Spills.getSpillSlotOrReMatPhysReg(ReuseSlot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this is a sub-register use, make sure the reuse register is in the
|
||||||
|
// right register class. For example, for x86 not all of the 32-bit
|
||||||
|
// registers have accessible sub-registers.
|
||||||
|
// Similarly so for EXTRACT_SUBREG. Consider this:
|
||||||
|
// EDI = op
|
||||||
|
// MOV32_mr fi#1, EDI
|
||||||
|
// ...
|
||||||
|
// = EXTRACT_SUBREG fi#1
|
||||||
|
// fi#1 is available in EDI, but it cannot be reused because it's not in
|
||||||
|
// the right register file.
|
||||||
|
if (PhysReg &&
|
||||||
|
(isSubReg || MI.getOpcode() == TargetInstrInfo::EXTRACT_SUBREG)) {
|
||||||
|
const TargetRegisterClass* RC = RegMap->getRegClass(VirtReg);
|
||||||
|
if (!RC->contains(PhysReg))
|
||||||
|
PhysReg = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (PhysReg) {
|
if (PhysReg) {
|
||||||
// This spilled operand might be part of a two-address operand. If this
|
// This spilled operand might be part of a two-address operand. If this
|
||||||
// is the case, then changing it will necessarily require changing the
|
// is the case, then changing it will necessarily require changing the
|
||||||
@ -824,6 +852,7 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM) {
|
|||||||
// aren't allowed to modify the reused register. If none of these cases
|
// aren't allowed to modify the reused register. If none of these cases
|
||||||
// apply, reuse it.
|
// apply, reuse it.
|
||||||
bool CanReuse = true;
|
bool CanReuse = true;
|
||||||
|
|
||||||
int ti = TID->getOperandConstraint(i, TOI::TIED_TO);
|
int ti = TID->getOperandConstraint(i, TOI::TIED_TO);
|
||||||
if (ti != -1 &&
|
if (ti != -1 &&
|
||||||
MI.getOperand(ti).isRegister() &&
|
MI.getOperand(ti).isRegister() &&
|
||||||
@ -845,7 +874,8 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM) {
|
|||||||
<< MRI->getName(PhysReg) << " for vreg"
|
<< MRI->getName(PhysReg) << " for vreg"
|
||||||
<< VirtReg <<" instead of reloading into physreg "
|
<< VirtReg <<" instead of reloading into physreg "
|
||||||
<< MRI->getName(VRM.getPhys(VirtReg)) << "\n";
|
<< MRI->getName(VRM.getPhys(VirtReg)) << "\n";
|
||||||
MI.getOperand(i).setReg(PhysReg);
|
unsigned RReg = isSubReg ? MRI->getSubReg(PhysReg, SubIdx) : PhysReg;
|
||||||
|
MI.getOperand(i).setReg(RReg);
|
||||||
|
|
||||||
// The only technical detail we have is that we don't know that
|
// The only technical detail we have is that we don't know that
|
||||||
// PhysReg won't be clobbered by a reloaded stack slot that occurs
|
// PhysReg won't be clobbered by a reloaded stack slot that occurs
|
||||||
@ -883,7 +913,7 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
} // CanReuse
|
||||||
|
|
||||||
// Otherwise we have a situation where we have a two-address instruction
|
// Otherwise we have a situation where we have a two-address instruction
|
||||||
// whose mod/ref operand needs to be reloaded. This reload is already
|
// whose mod/ref operand needs to be reloaded. This reload is already
|
||||||
@ -917,13 +947,14 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM) {
|
|||||||
DOUT << " from physreg " << MRI->getName(PhysReg) << " for vreg"
|
DOUT << " from physreg " << MRI->getName(PhysReg) << " for vreg"
|
||||||
<< VirtReg
|
<< VirtReg
|
||||||
<< " instead of reloading into same physreg.\n";
|
<< " instead of reloading into same physreg.\n";
|
||||||
MI.getOperand(i).setReg(PhysReg);
|
unsigned RReg = isSubReg ? MRI->getSubReg(PhysReg, SubIdx) : PhysReg;
|
||||||
|
MI.getOperand(i).setReg(RReg);
|
||||||
ReusedOperands.markClobbered(PhysReg);
|
ReusedOperands.markClobbered(PhysReg);
|
||||||
++NumReused;
|
++NumReused;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TargetRegisterClass* RC = MF.getSSARegMap()->getRegClass(VirtReg);
|
const TargetRegisterClass* RC = RegMap->getRegClass(VirtReg);
|
||||||
MF.setPhysRegUsed(DesignatedReg);
|
MF.setPhysRegUsed(DesignatedReg);
|
||||||
ReusedOperands.markClobbered(DesignatedReg);
|
ReusedOperands.markClobbered(DesignatedReg);
|
||||||
MRI->copyRegToReg(MBB, &MI, DesignatedReg, PhysReg, RC, RC);
|
MRI->copyRegToReg(MBB, &MI, DesignatedReg, PhysReg, RC, RC);
|
||||||
@ -935,16 +966,17 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM) {
|
|||||||
Spills.ClobberPhysReg(DesignatedReg);
|
Spills.ClobberPhysReg(DesignatedReg);
|
||||||
|
|
||||||
Spills.addAvailable(ReuseSlot, &MI, DesignatedReg);
|
Spills.addAvailable(ReuseSlot, &MI, DesignatedReg);
|
||||||
MI.getOperand(i).setReg(DesignatedReg);
|
unsigned RReg =
|
||||||
|
isSubReg ? MRI->getSubReg(DesignatedReg, SubIdx) : DesignatedReg;
|
||||||
|
MI.getOperand(i).setReg(RReg);
|
||||||
DOUT << '\t' << *prior(MII);
|
DOUT << '\t' << *prior(MII);
|
||||||
++NumReused;
|
++NumReused;
|
||||||
continue;
|
continue;
|
||||||
}
|
} // is (PhysReg)
|
||||||
|
|
||||||
// Otherwise, reload it and remember that we have it.
|
// Otherwise, reload it and remember that we have it.
|
||||||
PhysReg = VRM.getPhys(VirtReg);
|
PhysReg = VRM.getPhys(VirtReg);
|
||||||
assert(PhysReg && "Must map virtreg to physreg!");
|
assert(PhysReg && "Must map virtreg to physreg!");
|
||||||
const TargetRegisterClass* RC = MF.getSSARegMap()->getRegClass(VirtReg);
|
|
||||||
|
|
||||||
// Note that, if we reused a register for a previous operand, the
|
// Note that, if we reused a register for a previous operand, the
|
||||||
// register we want to reload into might not actually be
|
// register we want to reload into might not actually be
|
||||||
@ -960,6 +992,7 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM) {
|
|||||||
MRI->reMaterialize(MBB, &MI, PhysReg, VRM.getReMaterializedMI(VirtReg));
|
MRI->reMaterialize(MBB, &MI, PhysReg, VRM.getReMaterializedMI(VirtReg));
|
||||||
++NumReMats;
|
++NumReMats;
|
||||||
} else {
|
} else {
|
||||||
|
const TargetRegisterClass* RC = RegMap->getRegClass(VirtReg);
|
||||||
MRI->loadRegFromStackSlot(MBB, &MI, PhysReg, SSorRMId, RC);
|
MRI->loadRegFromStackSlot(MBB, &MI, PhysReg, SSorRMId, RC);
|
||||||
++NumLoads;
|
++NumLoads;
|
||||||
}
|
}
|
||||||
@ -974,7 +1007,8 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM) {
|
|||||||
// unless it's a two-address operand.
|
// unless it's a two-address operand.
|
||||||
if (TID->getOperandConstraint(i, TOI::TIED_TO) == -1)
|
if (TID->getOperandConstraint(i, TOI::TIED_TO) == -1)
|
||||||
MI.getOperand(i).setIsKill();
|
MI.getOperand(i).setIsKill();
|
||||||
MI.getOperand(i).setReg(PhysReg);
|
unsigned RReg = isSubReg ? MRI->getSubReg(PhysReg, SubIdx) : PhysReg;
|
||||||
|
MI.getOperand(i).setReg(RReg);
|
||||||
UpdateKills(*prior(MII), RegKills, KillOps);
|
UpdateKills(*prior(MII), RegKills, KillOps);
|
||||||
DOUT << '\t' << *prior(MII);
|
DOUT << '\t' << *prior(MII);
|
||||||
}
|
}
|
||||||
@ -1002,30 +1036,28 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM) {
|
|||||||
// straight load from the virt reg slot.
|
// straight load from the virt reg slot.
|
||||||
if ((MR & VirtRegMap::isRef) && !(MR & VirtRegMap::isMod)) {
|
if ((MR & VirtRegMap::isRef) && !(MR & VirtRegMap::isMod)) {
|
||||||
int FrameIdx;
|
int FrameIdx;
|
||||||
if (unsigned DestReg = TII->isLoadFromStackSlot(&MI, FrameIdx)) {
|
unsigned DestReg = TII->isLoadFromStackSlot(&MI, FrameIdx);
|
||||||
if (FrameIdx == SS) {
|
if (DestReg && FrameIdx == SS) {
|
||||||
// If this spill slot is available, turn it into a copy (or nothing)
|
// If this spill slot is available, turn it into a copy (or nothing)
|
||||||
// instead of leaving it as a load!
|
// instead of leaving it as a load!
|
||||||
if (unsigned InReg = Spills.getSpillSlotOrReMatPhysReg(SS)) {
|
if (unsigned InReg = Spills.getSpillSlotOrReMatPhysReg(SS)) {
|
||||||
DOUT << "Promoted Load To Copy: " << MI;
|
DOUT << "Promoted Load To Copy: " << MI;
|
||||||
if (DestReg != InReg) {
|
if (DestReg != InReg) {
|
||||||
const TargetRegisterClass *RC =
|
const TargetRegisterClass *RC = RegMap->getRegClass(VirtReg);
|
||||||
MF.getSSARegMap()->getRegClass(VirtReg);
|
MRI->copyRegToReg(MBB, &MI, DestReg, InReg, RC, RC);
|
||||||
MRI->copyRegToReg(MBB, &MI, DestReg, InReg, RC, RC);
|
// Revisit the copy so we make sure to notice the effects of the
|
||||||
// Revisit the copy so we make sure to notice the effects of the
|
// operation on the destreg (either needing to RA it if it's
|
||||||
// operation on the destreg (either needing to RA it if it's
|
// virtual or needing to clobber any values if it's physical).
|
||||||
// virtual or needing to clobber any values if it's physical).
|
NextMII = &MI;
|
||||||
NextMII = &MI;
|
--NextMII; // backtrack to the copy.
|
||||||
--NextMII; // backtrack to the copy.
|
BackTracked = true;
|
||||||
BackTracked = true;
|
} else
|
||||||
} else
|
DOUT << "Removing now-noop copy: " << MI;
|
||||||
DOUT << "Removing now-noop copy: " << MI;
|
|
||||||
|
|
||||||
VRM.RemoveFromFoldedVirtMap(&MI);
|
VRM.RemoveFromFoldedVirtMap(&MI);
|
||||||
MBB.erase(&MI);
|
MBB.erase(&MI);
|
||||||
Erased = true;
|
Erased = true;
|
||||||
goto ProcessNextInst;
|
goto ProcessNextInst;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1121,7 +1153,7 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM) {
|
|||||||
|
|
||||||
// The only vregs left are stack slot definitions.
|
// The only vregs left are stack slot definitions.
|
||||||
int StackSlot = VRM.getStackSlot(VirtReg);
|
int StackSlot = VRM.getStackSlot(VirtReg);
|
||||||
const TargetRegisterClass *RC = MF.getSSARegMap()->getRegClass(VirtReg);
|
const TargetRegisterClass *RC = RegMap->getRegClass(VirtReg);
|
||||||
|
|
||||||
// If this def is part of a two-address operand, make sure to execute
|
// If this def is part of a two-address operand, make sure to execute
|
||||||
// the store from the correct physical register.
|
// the store from the correct physical register.
|
||||||
|
Loading…
Reference in New Issue
Block a user