Newer
Older
//===-- LiveRangeEdit.cpp - Basic tools for editing a register live range -===//
Jakob Stoklund Olesen
committed
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// The LiveRangeEdit class represents changes done to a virtual register when it
// is spilled or split.
//===----------------------------------------------------------------------===//
Jakob Stoklund Olesen
committed
#define DEBUG_TYPE "regalloc"
Jakob Stoklund Olesen
committed
#include "VirtRegMap.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/Statistic.h"
Jakob Stoklund Olesen
committed
#include "llvm/CodeGen/CalcSpillWeights.h"
Jakob Stoklund Olesen
committed
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
Pete Cooper
committed
#include "llvm/CodeGen/LiveRangeEdit.h"
Jakob Stoklund Olesen
committed
#include "llvm/CodeGen/MachineRegisterInfo.h"
Jakob Stoklund Olesen
committed
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
Jakob Stoklund Olesen
committed
using namespace llvm;
STATISTIC(NumDCEDeleted, "Number of instructions deleted by DCE");
STATISTIC(NumDCEFoldedLoads, "Number of single use loads folded after DCE");
STATISTIC(NumFracRanges, "Number of live ranges fractured by DCE");
David Blaikie
committed
void LiveRangeEdit::Delegate::anchor() { }
LiveInterval &LiveRangeEdit::createFrom(unsigned OldReg) {
Jakob Stoklund Olesen
committed
unsigned VReg = MRI.createVirtualRegister(MRI.getRegClass(OldReg));
Pete Cooper
committed
if (VRM) {
VRM->grow();
VRM->setIsSplitFromReg(VReg, VRM->getOriginal(OldReg));
}
Jakob Stoklund Olesen
committed
LiveInterval &LI = LIS.getOrCreateInterval(VReg);
NewRegs.push_back(&LI);
Jakob Stoklund Olesen
committed
return LI;
Jakob Stoklund Olesen
committed
}
bool LiveRangeEdit::checkRematerializable(VNInfo *VNI,
Jakob Stoklund Olesen
committed
const MachineInstr *DefMI,
AliasAnalysis *aa) {
assert(DefMI && "Missing instruction");
ScannedRemattable = true;
if (!TII.isTriviallyReMaterializable(DefMI, aa))
return false;
Remattable.insert(VNI);
Jakob Stoklund Olesen
committed
}
void LiveRangeEdit::scanRemattable(AliasAnalysis *aa) {
for (LiveInterval::vni_iterator I = getParent().vni_begin(),
E = getParent().vni_end(); I != E; ++I) {
Jakob Stoklund Olesen
committed
VNInfo *VNI = *I;
if (VNI->isUnused())
continue;
MachineInstr *DefMI = LIS.getInstructionFromIndex(VNI->def);
Jakob Stoklund Olesen
committed
if (!DefMI)
continue;
checkRematerializable(VNI, DefMI, aa);
Jakob Stoklund Olesen
committed
}
ScannedRemattable = true;
Jakob Stoklund Olesen
committed
}
bool LiveRangeEdit::anyRematerializable(AliasAnalysis *aa) {
if (!ScannedRemattable)
scanRemattable(aa);
return !Remattable.empty();
Jakob Stoklund Olesen
committed
}
Jakob Stoklund Olesen
committed
/// allUsesAvailableAt - Return true if all registers used by OrigMI at
/// OrigIdx are also available with the same value at UseIdx.
bool LiveRangeEdit::allUsesAvailableAt(const MachineInstr *OrigMI,
SlotIndex OrigIdx,
SlotIndex UseIdx) {
OrigIdx = OrigIdx.getRegSlot(true);
UseIdx = UseIdx.getRegSlot(true);
Jakob Stoklund Olesen
committed
for (unsigned i = 0, e = OrigMI->getNumOperands(); i != e; ++i) {
const MachineOperand &MO = OrigMI->getOperand(i);
if (!MO.isReg() || !MO.getReg() || !MO.readsReg())
Jakob Stoklund Olesen
committed
continue;
// We can't remat physreg uses, unless it is a constant.
if (TargetRegisterInfo::isPhysicalRegister(MO.getReg())) {
if (MRI.isConstantPhysReg(MO.getReg(), VRM->getMachineFunction()))
continue;
return false;
}
LiveInterval &li = LIS.getInterval(MO.getReg());
Jakob Stoklund Olesen
committed
const VNInfo *OVNI = li.getVNInfoAt(OrigIdx);
if (!OVNI)
continue;
if (OVNI != li.getVNInfoAt(UseIdx))
return false;
}
return true;
}
bool LiveRangeEdit::canRematerializeAt(Remat &RM,
SlotIndex UseIdx,
bool cheapAsAMove) {
assert(ScannedRemattable && "Call anyRematerializable first");
Jakob Stoklund Olesen
committed
// Use scanRemattable info.
if (!Remattable.count(RM.ParentVNI))
return false;
Jakob Stoklund Olesen
committed
Jakob Stoklund Olesen
committed
// No defining instruction provided.
SlotIndex DefIdx;
if (RM.OrigMI)
DefIdx = LIS.getInstructionIndex(RM.OrigMI);
Jakob Stoklund Olesen
committed
else {
DefIdx = RM.ParentVNI->def;
RM.OrigMI = LIS.getInstructionFromIndex(DefIdx);
Jakob Stoklund Olesen
committed
assert(RM.OrigMI && "No defining instruction for remattable value");
}
Jakob Stoklund Olesen
committed
// If only cheap remats were requested, bail out early.
if (cheapAsAMove && !RM.OrigMI->isAsCheapAsAMove())
return false;
Jakob Stoklund Olesen
committed
// Verify that all used registers are available with the same values.
if (!allUsesAvailableAt(RM.OrigMI, DefIdx, UseIdx))
return false;
Jakob Stoklund Olesen
committed
return true;
Jakob Stoklund Olesen
committed
}
SlotIndex LiveRangeEdit::rematerializeAt(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
unsigned DestReg,
const Remat &RM,
Jakob Stoklund Olesen
committed
const TargetRegisterInfo &tri,
bool Late) {
Jakob Stoklund Olesen
committed
assert(RM.OrigMI && "Invalid remat");
TII.reMaterialize(MBB, MI, DestReg, 0, RM.OrigMI, tri);
Rematted.insert(RM.ParentVNI);
return LIS.getSlotIndexes()->insertMachineInstrInMaps(--MI, Late)
Jakob Stoklund Olesen
committed
}
void LiveRangeEdit::eraseVirtReg(unsigned Reg) {
if (TheDelegate && TheDelegate->LRE_CanEraseVirtReg(Reg))
LIS.removeInterval(Reg);
}
Jakob Stoklund Olesen
committed
bool LiveRangeEdit::foldAsLoad(LiveInterval *LI,
SmallVectorImpl<MachineInstr*> &Dead) {
Jakob Stoklund Olesen
committed
MachineInstr *DefMI = 0, *UseMI = 0;
// Check that there is a single def and a single use.
for (MachineRegisterInfo::reg_nodbg_iterator I = MRI.reg_nodbg_begin(LI->reg),
E = MRI.reg_nodbg_end(); I != E; ++I) {
MachineOperand &MO = I.getOperand();
MachineInstr *MI = MO.getParent();
if (MO.isDef()) {
if (DefMI && DefMI != MI)
return false;
if (!MI->canFoldAsLoad())
Jakob Stoklund Olesen
committed
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
return false;
DefMI = MI;
} else if (!MO.isUndef()) {
if (UseMI && UseMI != MI)
return false;
// FIXME: Targets don't know how to fold subreg uses.
if (MO.getSubReg())
return false;
UseMI = MI;
}
}
if (!DefMI || !UseMI)
return false;
DEBUG(dbgs() << "Try to fold single def: " << *DefMI
<< " into single use: " << *UseMI);
SmallVector<unsigned, 8> Ops;
if (UseMI->readsWritesVirtualRegister(LI->reg, &Ops).second)
return false;
MachineInstr *FoldMI = TII.foldMemoryOperand(UseMI, Ops, DefMI);
if (!FoldMI)
return false;
DEBUG(dbgs() << " folded: " << *FoldMI);
LIS.ReplaceMachineInstrInMaps(UseMI, FoldMI);
UseMI->eraseFromParent();
DefMI->addRegisterDead(LI->reg, 0);
Dead.push_back(DefMI);
++NumDCEFoldedLoads;
Jakob Stoklund Olesen
committed
return true;
}
void LiveRangeEdit::eliminateDeadDefs(SmallVectorImpl<MachineInstr*> &Dead,
ArrayRef<unsigned> RegsBeingSpilled) {
SetVector<LiveInterval*,
SmallVector<LiveInterval*, 8>,
SmallPtrSet<LiveInterval*, 8> > ToShrink;
for (;;) {
// Erase all dead defs.
while (!Dead.empty()) {
MachineInstr *MI = Dead.pop_back_val();
assert(MI->allDefsAreDead() && "Def isn't really dead");
SlotIndex Idx = LIS.getInstructionIndex(MI).getRegSlot();
// Never delete inline asm.
if (MI->isInlineAsm()) {
DEBUG(dbgs() << "Won't delete: " << Idx << '\t' << *MI);
// Use the same criteria as DeadMachineInstructionElim.
bool SawStore = false;
if (!MI->isSafeToMove(&TII, 0, SawStore)) {
DEBUG(dbgs() << "Can't delete: " << Idx << '\t' << *MI);
DEBUG(dbgs() << "Deleting dead def " << Idx << '\t' << *MI);
// Collect virtual registers to be erased after MI is gone.
SmallVector<unsigned, 8> RegsToErase;
// Check for live intervals that may shrink
for (MachineInstr::mop_iterator MOI = MI->operands_begin(),
MOE = MI->operands_end(); MOI != MOE; ++MOI) {
if (!MOI->isReg())
continue;
unsigned Reg = MOI->getReg();
if (!TargetRegisterInfo::isVirtualRegister(Reg))
continue;
LiveInterval &LI = LIS.getInterval(Reg);
Jakob Stoklund Olesen
committed
// Shrink read registers, unless it is likely to be expensive and
// unlikely to change anything. We typically don't want to shrink the
// PIC base register that has lots of uses everywhere.
// Always shrink COPY uses that probably come from live range splitting.
if (MI->readsVirtualRegister(Reg) &&
(MI->isCopy() || MOI->isDef() || MRI.hasOneNonDBGUse(Reg) ||
LI.killedAt(Idx)))
// Remove defined value.
if (MOI->isDef()) {
if (VNInfo *VNI = LI.getVNInfoAt(Idx)) {
if (TheDelegate)
TheDelegate->LRE_WillShrinkVirtReg(LI.reg);
LI.removeValNo(VNI);
if (LI.empty())
RegsToErase.push_back(Reg);
if (TheDelegate)
TheDelegate->LRE_WillEraseInstruction(MI);
LIS.RemoveMachineInstrFromMaps(MI);
MI->eraseFromParent();
++NumDCEDeleted;
// Erase any virtregs that are now empty and unused. There may be <undef>
// uses around. Keep the empty live range in that case.
for (unsigned i = 0, e = RegsToErase.size(); i != e; ++i) {
unsigned Reg = RegsToErase[i];
if (LIS.hasInterval(Reg) && MRI.reg_nodbg_empty(Reg)) {
ToShrink.remove(&LIS.getInterval(Reg));
eraseVirtReg(Reg);
}
}
}
if (ToShrink.empty())
break;
// Shrink just one live interval. Then delete new dead defs.
Jakob Stoklund Olesen
committed
LiveInterval *LI = ToShrink.back();
if (foldAsLoad(LI, Dead))
Jakob Stoklund Olesen
committed
continue;
if (TheDelegate)
TheDelegate->LRE_WillShrinkVirtReg(LI->reg);
Jakob Stoklund Olesen
committed
if (!LIS.shrinkToUses(LI, &Dead))
continue;
// Don't create new intervals for a register being spilled.
// The new intervals would have to be spilled anyway so its not worth it.
// Also they currently aren't spilled so creating them and not spilling
// them results in incorrect code.
bool BeingSpilled = false;
for (unsigned i = 0, e = RegsBeingSpilled.size(); i != e; ++i) {
if (LI->reg == RegsBeingSpilled[i]) {
BeingSpilled = true;
break;
}
}
if (BeingSpilled) continue;
Jakob Stoklund Olesen
committed
// LI may have been separated, create new intervals.
LI->RenumberValues(LIS);
ConnectedVNInfoEqClasses ConEQ(LIS);
unsigned NumComp = ConEQ.Classify(LI);
if (NumComp <= 1)
continue;
++NumFracRanges;
Pete Cooper
committed
bool IsOriginal = VRM && VRM->getOriginal(LI->reg) == LI->reg;
Jakob Stoklund Olesen
committed
DEBUG(dbgs() << NumComp << " components: " << *LI << '\n');
SmallVector<LiveInterval*, 8> Dups(1, LI);
for (unsigned i = 1; i != NumComp; ++i) {
Dups.push_back(&createFrom(LI->reg));
// If LI is an original interval that hasn't been split yet, make the new
// intervals their own originals instead of referring to LI. The original
// interval must contain all the split products, and LI doesn't.
if (IsOriginal)
VRM->setIsSplitFromReg(Dups.back()->reg, 0);
if (TheDelegate)
TheDelegate->LRE_DidCloneVirtReg(Dups.back()->reg, LI->reg);
Jakob Stoklund Olesen
committed
ConEQ.Distribute(&Dups[0], MRI);
DEBUG({
for (unsigned i = 0; i != NumComp; ++i)
dbgs() << '\t' << *Dups[i] << '\n';
});
Jakob Stoklund Olesen
committed
void LiveRangeEdit::calculateRegClassAndHint(MachineFunction &MF,
const MachineLoopInfo &Loops) {
VirtRegAuxInfo VRAI(MF, LIS, Loops);
for (iterator I = begin(), E = end(); I != E; ++I) {
LiveInterval &LI = **I;
if (MRI.recomputeRegClass(LI.reg, MF.getTarget()))
DEBUG(dbgs() << "Inflated " << PrintReg(LI.reg) << " to "
<< MRI.getRegClass(LI.reg)->getName() << '\n');
Jakob Stoklund Olesen
committed
VRAI.CalculateWeightAndHint(LI);
}
}