aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorEvan Cheng <evan.cheng@apple.com>2008-03-11 07:19:34 +0000
committerEvan Cheng <evan.cheng@apple.com>2008-03-11 07:19:34 +0000
commit676dd7c80b6f91178452535ac45ca58feb23cc42 (patch)
tree33282790f7a542b3ef2f3af7a23646d8f8514a1c /lib
parent204496d58e7e740f0da6d41c6214a91d67950d26 (diff)
downloadexternal_llvm-676dd7c80b6f91178452535ac45ca58feb23cc42.zip
external_llvm-676dd7c80b6f91178452535ac45ca58feb23cc42.tar.gz
external_llvm-676dd7c80b6f91178452535ac45ca58feb23cc42.tar.bz2
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
Diffstat (limited to 'lib')
-rw-r--r--lib/CodeGen/LiveIntervalAnalysis.cpp78
-rw-r--r--lib/CodeGen/RegAllocLinearScan.cpp24
-rw-r--r--lib/CodeGen/SelectionDAG/ScheduleDAG.cpp11
-rw-r--r--lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp2
-rw-r--r--lib/CodeGen/VirtRegMap.cpp40
-rw-r--r--lib/CodeGen/VirtRegMap.h40
-rw-r--r--lib/Target/TargetRegisterInfo.cpp11
7 files changed, 192 insertions, 14 deletions
diff --git a/lib/CodeGen/LiveIntervalAnalysis.cpp b/lib/CodeGen/LiveIntervalAnalysis.cpp
index d710d48..7931804 100644
--- a/lib/CodeGen/LiveIntervalAnalysis.cpp
+++ b/lib/CodeGen/LiveIntervalAnalysis.cpp
@@ -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);
+ }
+ }
+ }
+}
diff --git a/lib/CodeGen/RegAllocLinearScan.cpp b/lib/CodeGen/RegAllocLinearScan.cpp
index d43cc19..12e7d6a 100644
--- a/lib/CodeGen/RegAllocLinearScan.cpp
+++ b/lib/CodeGen/RegAllocLinearScan.cpp
@@ -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: "
diff --git a/lib/CodeGen/SelectionDAG/ScheduleDAG.cpp b/lib/CodeGen/SelectionDAG/ScheduleDAG.cpp
index 032ef5e..c042acb 100644
--- a/lib/CodeGen/SelectionDAG/ScheduleDAG.cpp
+++ b/lib/CodeGen/SelectionDAG/ScheduleDAG.cpp
@@ -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;
}
diff --git a/lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp b/lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp
index df57f74..0d3926f 100644
--- a/lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp
+++ b/lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp
@@ -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!");
diff --git a/lib/CodeGen/VirtRegMap.cpp b/lib/CodeGen/VirtRegMap.cpp
index c39ac61..cce36e5 100644
--- a/lib/CodeGen/VirtRegMap.cpp
+++ b/lib/CodeGen/VirtRegMap.cpp
@@ -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);
diff --git a/lib/CodeGen/VirtRegMap.h b/lib/CodeGen/VirtRegMap.h
index d1c14f6..7ebf31e 100644
--- a/lib/CodeGen/VirtRegMap.h
+++ b/lib/CodeGen/VirtRegMap.h
@@ -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;
diff --git a/lib/Target/TargetRegisterInfo.cpp b/lib/Target/TargetRegisterInfo.cpp
index 11f1b3d..0f8373b 100644
--- a/lib/Target/TargetRegisterInfo.cpp
+++ b/lib/Target/TargetRegisterInfo.cpp
@@ -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,