When the register allocator runs out of registers, spill a physical register around the def's and use's of the interval being allocated to make it possible for the interval to target a register and spill it right away and restore a register for uses. This likely generates terrible code but is before than aborting.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@48218 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Evan Cheng 2008-03-11 07:19:34 +00:00
parent 204496d58e
commit 676dd7c80b
10 changed files with 228 additions and 17 deletions

View File

@ -282,11 +282,25 @@ namespace llvm {
addIntervalsForSpills(const LiveInterval& i,
const MachineLoopInfo *loopInfo, VirtRegMap& vrm);
/// spillPhysRegAroundRegDefsUses - Spill the specified physical register
/// around all defs and uses of the specified interval.
void spillPhysRegAroundRegDefsUses(const LiveInterval &li,
unsigned PhysReg, VirtRegMap &vrm);
/// isReMaterializable - Returns true if every definition of MI of every
/// val# of the specified interval is re-materializable. Also returns true
/// by reference if all of the defs are load instructions.
bool isReMaterializable(const LiveInterval &li, bool &isLoad);
/// getRepresentativeReg - Find the largest super register of the specified
/// physical register.
unsigned getRepresentativeReg(unsigned Reg) const;
/// getNumConflictsWithPhysReg - Return the number of uses and defs of the
/// specified interval that conflicts with the specified physical register.
unsigned getNumConflictsWithPhysReg(const LiveInterval &li,
unsigned PhysReg) const;
private:
/// computeIntervals - Compute live intervals.
void computeIntervals();
@ -360,6 +374,10 @@ namespace llvm {
/// within a single basic block.
bool intervalIsInOneMBB(const LiveInterval &li) const;
/// hasAllocatableSuperReg - Return true if the specified physical register
/// has any super register that's allocatable.
bool hasAllocatableSuperReg(unsigned Reg) const;
/// SRInfo - Spill / restore info.
struct SRInfo {
int index;

View File

@ -321,9 +321,10 @@ public:
}
/// getPhysicalRegisterRegClass - Returns the Register Class of a physical
/// register of the given type.
const TargetRegisterClass *getPhysicalRegisterRegClass(MVT::ValueType VT,
unsigned Reg) const;
/// register of the given type. If type is MVT::Other, then just return any
/// register class the register belongs to.
const TargetRegisterClass *getPhysicalRegisterRegClass(unsigned Reg,
MVT::ValueType VT = MVT::Other) const;
/// getAllocatableSet - Returns a bitset indexed by register number
/// indicating if a register is allocatable or not. If a register class is

View File

@ -1620,3 +1620,81 @@ addIntervalsForSpills(const LiveInterval &li,
return RetNewLIs;
}
/// hasAllocatableSuperReg - Return true if the specified physical register has
/// any super register that's allocatable.
bool LiveIntervals::hasAllocatableSuperReg(unsigned Reg) const {
for (const unsigned* AS = tri_->getSuperRegisters(Reg); *AS; ++AS)
if (allocatableRegs_[*AS] && hasInterval(*AS))
return true;
return false;
}
/// getRepresentativeReg - Find the largest super register of the specified
/// physical register.
unsigned LiveIntervals::getRepresentativeReg(unsigned Reg) const {
// Find the largest super-register that is allocatable.
unsigned BestReg = Reg;
for (const unsigned* AS = tri_->getSuperRegisters(Reg); *AS; ++AS) {
unsigned SuperReg = *AS;
if (!hasAllocatableSuperReg(SuperReg) && hasInterval(SuperReg)) {
BestReg = SuperReg;
break;
}
}
return BestReg;
}
/// getNumConflictsWithPhysReg - Return the number of uses and defs of the
/// specified interval that conflicts with the specified physical register.
unsigned LiveIntervals::getNumConflictsWithPhysReg(const LiveInterval &li,
unsigned PhysReg) const {
unsigned NumConflicts = 0;
const LiveInterval &pli = getInterval(getRepresentativeReg(PhysReg));
for (MachineRegisterInfo::reg_iterator I = mri_->reg_begin(li.reg),
E = mri_->reg_end(); I != E; ++I) {
MachineOperand &O = I.getOperand();
MachineInstr *MI = O.getParent();
unsigned Index = getInstructionIndex(MI);
if (pli.liveAt(Index))
++NumConflicts;
}
return NumConflicts;
}
/// spillPhysRegAroundRegDefsUses - Spill the specified physical register
/// around all defs and uses of the specified interval.
void LiveIntervals::spillPhysRegAroundRegDefsUses(const LiveInterval &li,
unsigned PhysReg, VirtRegMap &vrm) {
unsigned SpillReg = getRepresentativeReg(PhysReg);
for (const unsigned *AS = tri_->getAliasSet(PhysReg); *AS; ++AS)
// If there are registers which alias PhysReg, but which are not a
// sub-register of the chosen representative super register. Assert
// since we can't handle it yet.
assert(*AS == SpillReg || !allocatableRegs_[*AS] ||
tri_->isSuperRegister(*AS, SpillReg));
LiveInterval &pli = getInterval(SpillReg);
SmallPtrSet<MachineInstr*, 8> SeenMIs;
for (MachineRegisterInfo::reg_iterator I = mri_->reg_begin(li.reg),
E = mri_->reg_end(); I != E; ++I) {
MachineOperand &O = I.getOperand();
MachineInstr *MI = O.getParent();
if (SeenMIs.count(MI))
continue;
SeenMIs.insert(MI);
unsigned Index = getInstructionIndex(MI);
if (pli.liveAt(Index)) {
vrm.addEmergencySpill(SpillReg, MI);
pli.removeRange(getLoadIndex(Index), getStoreIndex(Index)+1);
for (const unsigned* AS = tri_->getSubRegisters(SpillReg); *AS; ++AS) {
if (!hasInterval(*AS))
continue;
LiveInterval &spli = getInterval(*AS);
if (spli.liveAt(Index))
spli.removeRange(getLoadIndex(Index), getStoreIndex(Index)+1);
}
}
}
}

View File

@ -561,6 +561,7 @@ void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur)
// is very bad (it contains all callee clobbered registers for any functions
// with a call), so we want to avoid doing that if possible.
unsigned physReg = getFreePhysReg(cur);
unsigned BestPhysReg = physReg;
if (physReg) {
// We got a register. However, if it's in the fixed_ list, we might
// conflict with it. Check to see if we conflict with it or any of its
@ -685,8 +686,27 @@ void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur)
}
// All registers must have inf weight. Just grab one!
if (!minReg)
minReg = *RC->allocation_order_begin(*mf_);
if (!minReg) {
if (BestPhysReg)
minReg = BestPhysReg;
else {
// Get the physical register with the fewest conflicts.
unsigned MinConflicts = ~0U;
for (TargetRegisterClass::iterator i = RC->allocation_order_begin(*mf_),
e = RC->allocation_order_end(*mf_); i != e; ++i) {
unsigned reg = *i;
unsigned NumConflicts = li_->getNumConflictsWithPhysReg(*cur, reg);
if (NumConflicts <= MinConflicts) {
MinConflicts = NumConflicts;
minReg = reg;
}
}
}
if (cur->weight == HUGE_VALF || cur->getSize() == 1)
// Spill a physical register around defs and uses.
li_->spillPhysRegAroundRegDefsUses(*cur, minReg, *vrm_);
}
}
DOUT << "\t\tregister with min weight: "

View File

@ -61,7 +61,7 @@ static void CheckForPhysRegDependency(SDNode *Def, SDNode *Use, unsigned Op,
II.ImplicitDefs[ResNo - II.getNumDefs()] == Reg) {
PhysReg = Reg;
const TargetRegisterClass *RC =
TRI->getPhysicalRegisterRegClass(Def->getValueType(ResNo), Reg);
TRI->getPhysicalRegisterRegClass(Reg, Def->getValueType(ResNo));
Cost = RC->getCopyCost();
}
}
@ -433,7 +433,7 @@ void ScheduleDAG::EmitCopyFromReg(SDNode *Node, unsigned ResNo,
}
const TargetRegisterClass *SrcRC = 0, *DstRC = 0;
SrcRC = TRI->getPhysicalRegisterRegClass(Node->getValueType(ResNo), SrcReg);
SrcRC = TRI->getPhysicalRegisterRegClass(SrcReg, Node->getValueType(ResNo));
// Figure out the register class to create for the destreg.
if (VRBase) {
@ -862,14 +862,13 @@ void ScheduleDAG::EmitNode(SDNode *Node, unsigned InstanceNo,
if (TargetRegisterInfo::isVirtualRegister(SrcReg))
SrcTRC = RegInfo.getRegClass(SrcReg);
else
SrcTRC = TRI->getPhysicalRegisterRegClass(SrcVal.getValueType(),SrcReg);
SrcTRC = TRI->getPhysicalRegisterRegClass(SrcReg,SrcVal.getValueType());
if (TargetRegisterInfo::isVirtualRegister(DestReg))
DstTRC = RegInfo.getRegClass(DestReg);
else
DstTRC = TRI->getPhysicalRegisterRegClass(
Node->getOperand(1).getValueType(),
DestReg);
DstTRC = TRI->getPhysicalRegisterRegClass(DestReg,
Node->getOperand(1).getValueType());
TII->copyRegToReg(*BB, BB->end(), DestReg, SrcReg, DstTRC, SrcTRC);
break;
}

View File

@ -768,7 +768,7 @@ void ScheduleDAGRRList::ListScheduleBottomUp() {
// Issue expensive cross register class copies.
MVT::ValueType VT = getPhysicalRegisterVT(LRDef->Node, Reg, TII);
const TargetRegisterClass *RC =
TRI->getPhysicalRegisterRegClass(VT, Reg);
TRI->getPhysicalRegisterRegClass(Reg, VT);
const TargetRegisterClass *DestRC = TRI->getCrossCopyRegClass(RC);
if (!DestRC) {
assert(false && "Don't know how to copy this physical register!");

View File

@ -125,6 +125,21 @@ void VirtRegMap::assignVirtReMatId(unsigned virtReg, int id) {
Virt2ReMatIdMap[virtReg] = id;
}
int VirtRegMap::getEmergencySpillSlot(const TargetRegisterClass *RC) {
std::map<const TargetRegisterClass*, int>::iterator I =
EmergencySpillSlots.find(RC);
if (I != EmergencySpillSlots.end())
return I->second;
int SS = MF.getFrameInfo()->CreateStackObject(RC->getSize(),
RC->getAlignment());
if (LowSpillSlot == NO_STACK_SLOT)
LowSpillSlot = SS;
if (HighSpillSlot == NO_STACK_SLOT || SS > HighSpillSlot)
HighSpillSlot = SS;
I->second = SS;
return SS;
}
void VirtRegMap::addSpillSlotUse(int FI, MachineInstr *MI) {
if (!MF.getFrameInfo()->isFixedObjectIndex(FI)) {
assert(FI >= 0 && "Spill slot index should not be negative!");
@ -164,6 +179,7 @@ void VirtRegMap::RemoveMachineInstrFromMaps(MachineInstr *MI) {
MI2VirtMap.erase(MI);
SpillPt2VirtMap.erase(MI);
RestorePt2VirtMap.erase(MI);
EmergencySpillMap.erase(MI);
}
void VirtRegMap::print(std::ostream &OS) const {
@ -1043,6 +1059,30 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM) {
MachineInstr &MI = *MII;
const TargetInstrDesc &TID = MI.getDesc();
if (VRM.hasEmergencySpills(&MI)) {
// Spill physical register(s) in the rare case the allocator has run out
// of registers to allocate.
SmallSet<int, 4> UsedSS;
std::vector<unsigned> &EmSpills = VRM.getEmergencySpills(&MI);
for (unsigned i = 0, e = EmSpills.size(); i != e; ++i) {
unsigned PhysReg = EmSpills[i];
const TargetRegisterClass *RC =
TRI->getPhysicalRegisterRegClass(PhysReg);
assert(RC && "Unable to determine register class!");
int SS = VRM.getEmergencySpillSlot(RC);
if (UsedSS.count(SS))
assert(0 && "Need to spill more than one physical registers!");
UsedSS.insert(SS);
TII->storeRegToStackSlot(MBB, MII, PhysReg, true, SS, RC);
MachineInstr *StoreMI = prior(MII);
VRM.addSpillSlotUse(SS, StoreMI);
TII->loadRegFromStackSlot(MBB, next(MII), PhysReg, SS, RC);
MachineInstr *LoadMI = next(MII);
VRM.addSpillSlotUse(SS, LoadMI);
++NumSpills;
}
}
// Insert restores here if asked to.
if (VRM.isRestorePt(&MI)) {
std::vector<unsigned> &RestoreRegs = VRM.getRestorePtRestores(&MI);

View File

@ -93,6 +93,17 @@ namespace llvm {
/// splitting.
std::map<MachineInstr*, std::vector<unsigned> > RestorePt2VirtMap;
/// EmergencySpillMap - This records the physical registers that should
/// be spilled / restored around the MachineInstr since the register
/// allocator has run out of registers.
std::map<MachineInstr*, std::vector<unsigned> > EmergencySpillMap;
/// EmergencySpillSlots - This records emergency spill slots used to
/// spill physical registers when the register allocator runs out of
/// registers. Ideally only one stack slot is used per function per
/// register class.
std::map<const TargetRegisterClass*, int> EmergencySpillSlots;
/// ReMatId - Instead of assigning a stack slot to a to be rematerialized
/// virtual register, an unique id is being assigned. This keeps track of
/// the highest id used so far. Note, this starts at (1<<18) to avoid
@ -293,6 +304,8 @@ namespace llvm {
}
}
/// @brief - transfer restore point information from one instruction to
/// another.
void transferRestorePts(MachineInstr *Old, MachineInstr *New) {
std::map<MachineInstr*,std::vector<unsigned> >::iterator I =
RestorePt2VirtMap.find(Old);
@ -306,6 +319,33 @@ namespace llvm {
RestorePt2VirtMap.erase(I);
}
/// @brief records that the specified physical register must be spilled
/// around the specified machine instr.
void addEmergencySpill(unsigned PhysReg, MachineInstr *MI) {
if (EmergencySpillMap.find(MI) != EmergencySpillMap.end())
EmergencySpillMap[MI].push_back(PhysReg);
else {
std::vector<unsigned> PhysRegs;
PhysRegs.push_back(PhysReg);
EmergencySpillMap.insert(std::make_pair(MI, PhysRegs));
}
}
/// @brief returns true if one or more physical registers must be spilled
/// around the specified instruction.
bool hasEmergencySpills(MachineInstr *MI) const {
return EmergencySpillMap.find(MI) != EmergencySpillMap.end();
}
/// @brief returns the physical registers to be spilled and restored around
/// the instruction.
std::vector<unsigned> &getEmergencySpills(MachineInstr *MI) {
return EmergencySpillMap[MI];
}
/// @brief return or get a emergency spill slot for the register class.
int getEmergencySpillSlot(const TargetRegisterClass *RC);
/// @brief Return lowest spill slot index.
int getLowSpillSlot() const {
return LowSpillSlot;

View File

@ -34,20 +34,21 @@ TargetRegisterInfo::TargetRegisterInfo(const TargetRegisterDesc *D, unsigned NR,
TargetRegisterInfo::~TargetRegisterInfo() {}
/// getPhysicalRegisterRegClass - Returns the Register Class of a physical
/// register.
/// register of the given type. If type is MVT::Other, then just return any
/// register class the register belongs to.
const TargetRegisterClass *
TargetRegisterInfo::getPhysicalRegisterRegClass(MVT::ValueType VT,
unsigned reg) const {
TargetRegisterInfo::getPhysicalRegisterRegClass(unsigned reg,
MVT::ValueType VT) const {
assert(isPhysicalRegister(reg) && "reg must be a physical register");
// Pick the register class of the right type that contains this physreg.
for (regclass_iterator I = regclass_begin(), E = regclass_end(); I != E; ++I)
if ((*I)->hasType(VT) && (*I)->contains(reg))
if ((VT == MVT::Other || (*I)->hasType(VT))
&& (*I)->contains(reg))
return *I;
assert(false && "Couldn't find the register class");
return 0;
}
/// getAllocatableSetForRC - Toggle the bits that represent allocatable
/// registers for the specific register class.
static void getAllocatableSetForRC(MachineFunction &MF,

View File

@ -0,0 +1,14 @@
; RUN: llvm-as < %s | llc -mtriple=i386-pc-linux-gnu -relocation-model=pic -disable-fp-elim
; PR2134
declare fastcc i8* @w_addchar(i8*, i32*, i32*, i8 signext ) nounwind
define x86_stdcallcc i32 @parse_backslash(i8** inreg %word, i32* inreg %word_length, i32* inreg %max_length) nounwind {
entry:
%tmp6 = load i8* null, align 1 ; <i8> [#uses=1]
br label %bb13
bb13: ; preds = %entry
%tmp26 = call fastcc i8* @w_addchar( i8* null, i32* %word_length, i32* %max_length, i8 signext %tmp6 ) nounwind ; <i8*> [#uses=1]
store i8* %tmp26, i8** %word, align 4
ret i32 0
}