[llvm-commits] [llvm] r48218 - in /llvm/trunk: include/llvm/CodeGen/LiveIntervalAnalysis.h include/llvm/Target/TargetRegisterInfo.h lib/CodeGen/LiveIntervalAnalysis.cpp lib/CodeGen/RegAllocLinearScan.cpp lib/CodeGen/SelectionDAG/ScheduleDAG.cpp lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp lib/CodeGen/VirtRegMap.cpp lib/CodeGen/VirtRegMap.h lib/Target/TargetRegisterInfo.cpp test/CodeGen/X86/2008-03-10-RegAllocInfLoop.ll

Evan Cheng evan.cheng at apple.com
Tue Mar 11 00:19:34 PDT 2008


Author: evancheng
Date: Tue Mar 11 02:19:34 2008
New Revision: 48218

URL: http://llvm.org/viewvc/llvm-project?rev=48218&view=rev
Log:
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.

Added:
    llvm/trunk/test/CodeGen/X86/2008-03-10-RegAllocInfLoop.ll
Modified:
    llvm/trunk/include/llvm/CodeGen/LiveIntervalAnalysis.h
    llvm/trunk/include/llvm/Target/TargetRegisterInfo.h
    llvm/trunk/lib/CodeGen/LiveIntervalAnalysis.cpp
    llvm/trunk/lib/CodeGen/RegAllocLinearScan.cpp
    llvm/trunk/lib/CodeGen/SelectionDAG/ScheduleDAG.cpp
    llvm/trunk/lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp
    llvm/trunk/lib/CodeGen/VirtRegMap.cpp
    llvm/trunk/lib/CodeGen/VirtRegMap.h
    llvm/trunk/lib/Target/TargetRegisterInfo.cpp

Modified: llvm/trunk/include/llvm/CodeGen/LiveIntervalAnalysis.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/LiveIntervalAnalysis.h?rev=48218&r1=48217&r2=48218&view=diff

==============================================================================
--- llvm/trunk/include/llvm/CodeGen/LiveIntervalAnalysis.h (original)
+++ llvm/trunk/include/llvm/CodeGen/LiveIntervalAnalysis.h Tue Mar 11 02:19:34 2008
@@ -282,11 +282,25 @@
     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 @@
     /// 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;

Modified: llvm/trunk/include/llvm/Target/TargetRegisterInfo.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Target/TargetRegisterInfo.h?rev=48218&r1=48217&r2=48218&view=diff

==============================================================================
--- llvm/trunk/include/llvm/Target/TargetRegisterInfo.h (original)
+++ llvm/trunk/include/llvm/Target/TargetRegisterInfo.h Tue Mar 11 02:19:34 2008
@@ -321,9 +321,10 @@
   }
 
   /// 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

Modified: llvm/trunk/lib/CodeGen/LiveIntervalAnalysis.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/LiveIntervalAnalysis.cpp?rev=48218&r1=48217&r2=48218&view=diff

==============================================================================
--- llvm/trunk/lib/CodeGen/LiveIntervalAnalysis.cpp (original)
+++ llvm/trunk/lib/CodeGen/LiveIntervalAnalysis.cpp Tue Mar 11 02:19:34 2008
@@ -1620,3 +1620,81 @@
 
   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);
+      }
+    }
+  }
+}

Modified: llvm/trunk/lib/CodeGen/RegAllocLinearScan.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/RegAllocLinearScan.cpp?rev=48218&r1=48217&r2=48218&view=diff

==============================================================================
--- llvm/trunk/lib/CodeGen/RegAllocLinearScan.cpp (original)
+++ llvm/trunk/lib/CodeGen/RegAllocLinearScan.cpp Tue Mar 11 02:19:34 2008
@@ -561,6 +561,7 @@
   // 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 @@
     }
 
     // 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: "

Modified: llvm/trunk/lib/CodeGen/SelectionDAG/ScheduleDAG.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/ScheduleDAG.cpp?rev=48218&r1=48217&r2=48218&view=diff

==============================================================================
--- llvm/trunk/lib/CodeGen/SelectionDAG/ScheduleDAG.cpp (original)
+++ llvm/trunk/lib/CodeGen/SelectionDAG/ScheduleDAG.cpp Tue Mar 11 02:19:34 2008
@@ -61,7 +61,7 @@
         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 @@
   }
 
   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 @@
       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;
     }

Modified: llvm/trunk/lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp?rev=48218&r1=48217&r2=48218&view=diff

==============================================================================
--- llvm/trunk/lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp (original)
+++ llvm/trunk/lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp Tue Mar 11 02:19:34 2008
@@ -768,7 +768,7 @@
           // 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!");

Modified: llvm/trunk/lib/CodeGen/VirtRegMap.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/VirtRegMap.cpp?rev=48218&r1=48217&r2=48218&view=diff

==============================================================================
--- llvm/trunk/lib/CodeGen/VirtRegMap.cpp (original)
+++ llvm/trunk/lib/CodeGen/VirtRegMap.cpp Tue Mar 11 02:19:34 2008
@@ -125,6 +125,21 @@
   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 @@
   MI2VirtMap.erase(MI);
   SpillPt2VirtMap.erase(MI);
   RestorePt2VirtMap.erase(MI);
+  EmergencySpillMap.erase(MI);
 }
 
 void VirtRegMap::print(std::ostream &OS) const {
@@ -1043,6 +1059,30 @@
     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);

Modified: llvm/trunk/lib/CodeGen/VirtRegMap.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/VirtRegMap.h?rev=48218&r1=48217&r2=48218&view=diff

==============================================================================
--- llvm/trunk/lib/CodeGen/VirtRegMap.h (original)
+++ llvm/trunk/lib/CodeGen/VirtRegMap.h Tue Mar 11 02:19:34 2008
@@ -93,6 +93,17 @@
     /// 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 @@
       }
     }
 
+    /// @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 @@
       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;

Modified: llvm/trunk/lib/Target/TargetRegisterInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/TargetRegisterInfo.cpp?rev=48218&r1=48217&r2=48218&view=diff

==============================================================================
--- llvm/trunk/lib/Target/TargetRegisterInfo.cpp (original)
+++ llvm/trunk/lib/Target/TargetRegisterInfo.cpp Tue Mar 11 02:19:34 2008
@@ -34,20 +34,21 @@
 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,

Added: llvm/trunk/test/CodeGen/X86/2008-03-10-RegAllocInfLoop.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/2008-03-10-RegAllocInfLoop.ll?rev=48218&view=auto

==============================================================================
--- llvm/trunk/test/CodeGen/X86/2008-03-10-RegAllocInfLoop.ll (added)
+++ llvm/trunk/test/CodeGen/X86/2008-03-10-RegAllocInfLoop.ll Tue Mar 11 02:19:34 2008
@@ -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
+}





More information about the llvm-commits mailing list