mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-23 02:32:11 +00:00
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:
parent
204496d58e
commit
676dd7c80b
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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: "
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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!");
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
14
test/CodeGen/X86/2008-03-10-RegAllocInfLoop.ll
Normal file
14
test/CodeGen/X86/2008-03-10-RegAllocInfLoop.ll
Normal 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
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user