diff options
-rw-r--r-- | include/llvm/CodeGen/LiveIntervalAnalysis.h | 18 | ||||
-rw-r--r-- | include/llvm/Target/TargetRegisterInfo.h | 7 | ||||
-rw-r--r-- | lib/CodeGen/LiveIntervalAnalysis.cpp | 78 | ||||
-rw-r--r-- | lib/CodeGen/RegAllocLinearScan.cpp | 24 | ||||
-rw-r--r-- | lib/CodeGen/SelectionDAG/ScheduleDAG.cpp | 11 | ||||
-rw-r--r-- | lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp | 2 | ||||
-rw-r--r-- | lib/CodeGen/VirtRegMap.cpp | 40 | ||||
-rw-r--r-- | lib/CodeGen/VirtRegMap.h | 40 | ||||
-rw-r--r-- | lib/Target/TargetRegisterInfo.cpp | 11 | ||||
-rw-r--r-- | test/CodeGen/X86/2008-03-10-RegAllocInfLoop.ll | 14 |
10 files changed, 228 insertions, 17 deletions
diff --git a/include/llvm/CodeGen/LiveIntervalAnalysis.h b/include/llvm/CodeGen/LiveIntervalAnalysis.h index f2991c6..a6e0816 100644 --- a/include/llvm/CodeGen/LiveIntervalAnalysis.h +++ b/include/llvm/CodeGen/LiveIntervalAnalysis.h @@ -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; diff --git a/include/llvm/Target/TargetRegisterInfo.h b/include/llvm/Target/TargetRegisterInfo.h index e13ebda..2050e5a 100644 --- a/include/llvm/Target/TargetRegisterInfo.h +++ b/include/llvm/Target/TargetRegisterInfo.h @@ -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 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, diff --git a/test/CodeGen/X86/2008-03-10-RegAllocInfLoop.ll b/test/CodeGen/X86/2008-03-10-RegAllocInfLoop.ll new file mode 100644 index 0000000..b858592 --- /dev/null +++ b/test/CodeGen/X86/2008-03-10-RegAllocInfLoop.ll @@ -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 +} |