EXTRACT_SUBREG coalescing support. The coalescer now treats EXTRACT_SUBREG like
authorEvan Cheng <evan.cheng@apple.com>
Fri, 12 Oct 2007 08:50:34 +0000 (08:50 +0000)
committerEvan Cheng <evan.cheng@apple.com>
Fri, 12 Oct 2007 08:50:34 +0000 (08:50 +0000)
(almost) a register copy. However, it always coalesced to the register of the
RHS (the super-register). All uses of the result of a EXTRACT_SUBREG are sub-
register uses which adds subtle complications to load folding, spiller rewrite,
etc.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@42899 91177308-0d34-0410-b5e6-96231b3b80d8

12 files changed:
include/llvm/CodeGen/LiveInterval.h
include/llvm/CodeGen/LiveIntervalAnalysis.h
include/llvm/CodeGen/MachineInstr.h
include/llvm/CodeGen/SSARegMap.h
include/llvm/CodeGen/SimpleRegisterCoalescing.h
lib/CodeGen/LiveInterval.cpp
lib/CodeGen/LiveIntervalAnalysis.cpp
lib/CodeGen/MachineInstr.cpp
lib/CodeGen/SelectionDAG/ScheduleDAG.cpp
lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp
lib/CodeGen/SimpleRegisterCoalescing.cpp
lib/CodeGen/VirtRegMap.cpp

index 50ac158590377f1665f99abaa5c57743f1176f01..34e53a9a67842209429fd9cb27a8f4828b0c6847 100644 (file)
@@ -155,7 +155,7 @@ namespace llvm {
     
     /// copyValNumInfo - Copy the value number info for one value number to
     /// another.
-    void copyValNumInfo(VNInfo *DstValNo, VNInfo *SrcValNo) {
+    void copyValNumInfo(VNInfo *DstValNo, const VNInfo *SrcValNo) {
       DstValNo->def = SrcValNo->def;
       DstValNo->reg = SrcValNo->reg;
       DstValNo->kills = SrcValNo->kills;
@@ -241,11 +241,23 @@ namespace llvm {
     void MergeInClobberRanges(const LiveInterval &Clobbers,
                               BumpPtrAllocator &VNInfoAllocator);
 
-    /// MergeRangesInAsValue - Merge all of the intervals in RHS into this live
-    /// interval as the specified value number.  The LiveRanges in RHS are
+    /// MergeRangesInAsValue - Merge all of the live ranges in RHS into this
+    /// live interval as the specified value number.  The LiveRanges in RHS are
     /// allowed to overlap with LiveRanges in the current interval, but only if
     /// the overlapping LiveRanges have the specified value number.
     void MergeRangesInAsValue(const LiveInterval &RHS, VNInfo *LHSValNo);
+
+    /// MergeValueInAsValue - Merge all of the live ranges of a specific val#
+    /// in RHS into this live interval as the specified value number.
+    /// The LiveRanges in RHS are allowed to overlap with LiveRanges in the
+    /// current interval, but only if the overlapping LiveRanges have the
+    /// specified value number.
+    void MergeValueInAsValue(const LiveInterval &RHS,
+                             VNInfo *RHSValNo, VNInfo *LHSValNo);
+
+    /// Copy - Copy the specified live interval. This copies all the fields
+    /// except for the register of the interval.
+    void Copy(const LiveInterval &RHS, BumpPtrAllocator &VNInfoAllocator);
     
     bool empty() const { return ranges.empty(); }
 
index 671de02eeeb6b1001ec61453063bbea8c8342d76..bf0a8295d5fad0f8a1222609d69194a09740abdc 100644 (file)
@@ -167,11 +167,6 @@ namespace llvm {
       return I->second;
     }
 
-    /// CreateNewLiveInterval - Create a new live interval with the given live
-    /// ranges. The new live interval will have an infinite spill weight.
-    LiveInterval &CreateNewLiveInterval(const LiveInterval *LI,
-                                        const std::vector<LiveRange> &LRs);
-
     std::vector<LiveInterval*> addIntervalsForSpills(const LiveInterval& i,
                                                  VirtRegMap& vrm, unsigned reg);
 
@@ -254,8 +249,8 @@ namespace llvm {
     /// MI. If it is successul, MI is updated with the newly created MI and
     /// returns true.
     bool tryFoldMemoryOperand(MachineInstr* &MI, VirtRegMap &vrm,
-                              unsigned index, unsigned i, bool isSS,
-                              MachineInstr *DefMI, int slot, unsigned reg);
+                              MachineInstr *DefMI, unsigned index, unsigned i,
+                              bool isSS, int slot, unsigned reg);
 
     static LiveInterval createInterval(unsigned Reg);
 
index 3dbda8dc787086b34f8f20b14432a051c9102ec2..beba6923ee7832749f0569aeccb875b61cfb7dd3 100644 (file)
@@ -418,6 +418,10 @@ public:
   /// none is found.
   int findFirstPredOperandIdx() const;
   
+  /// isRegReDefinedByTwoAddr - Returns true if the Reg re-definition is due
+  /// to two addr elimination.
+  bool isRegReDefinedByTwoAddr(unsigned Reg) const;
+
   /// copyKillDeadInfo - Copies kill / dead operand properties from MI.
   ///
   void copyKillDeadInfo(const MachineInstr *MI);
index 97d8d6988c4ff5dc0c9e53eb93c2b1003cd49740..a92222a5c36fbaa32034eb73f61aedb3873d1a34 100644 (file)
@@ -26,6 +26,7 @@ class TargetRegisterClass;
 
 class SSARegMap {
   IndexedMap<const TargetRegisterClass*, VirtReg2IndexFunctor> RegClassMap;
+  IndexedMap<std::pair<unsigned, unsigned>, VirtReg2IndexFunctor> RegSubIdxMap;
   unsigned NextRegNum;
 
  public:
@@ -42,12 +43,30 @@ class SSARegMap {
     assert(RegClass && "Cannot create register without RegClass!");
     RegClassMap.grow(NextRegNum);
     RegClassMap[NextRegNum] = RegClass;
+    RegSubIdxMap.grow(NextRegNum);
+    RegSubIdxMap[NextRegNum] = std::make_pair(0,0);
     return NextRegNum++;
   }
 
   unsigned getLastVirtReg() const {
     return NextRegNum - 1;
   }
+
+  void setIsSubRegister(unsigned Reg, unsigned SuperReg, unsigned SubIdx) {
+    RegSubIdxMap[Reg] = std::make_pair(SuperReg, SubIdx);
+  }
+
+  bool isSubRegister(unsigned Reg) const {
+    return RegSubIdxMap[Reg].first != 0;
+  }
+
+  unsigned getSuperRegister(unsigned Reg) const {
+    return RegSubIdxMap[Reg].first;
+  }
+
+  unsigned getSubRegisterIndex(unsigned Reg) const {
+    return RegSubIdxMap[Reg].second;
+  }
 };
 
 } // End llvm namespace
index 4e760815b9cce86d52edc7d922f2285daabf2b5f..00095dd176169cdf0da754ac19302a9eb7d842f5 100644 (file)
@@ -47,6 +47,10 @@ namespace llvm {
     /// with other intervals.
     BitVector JoinedLIs;
 
+    /// SubRegIdxes - Keep track of sub-register and sub-indexes.
+    ///
+    std::vector<std::pair<unsigned, unsigned> > SubRegIdxes;
+
   public:
     static char ID; // Pass identifcation, replacement for typeid
     SimpleRegisterCoalescing() : MachineFunctionPass((intptr_t)&ID) {}
index f205d0c5e283fd4e3c3cb7a7238e7e4d35b3e615..b2f7d7fe13d30817dd84ee7feb7f4c50809a9f8e 100644 (file)
@@ -383,6 +383,26 @@ void LiveInterval::MergeRangesInAsValue(const LiveInterval &RHS,
 }
 
 
+/// MergeValueInAsValue - Merge all of the live ranges of a specific val#
+/// in RHS into this live interval as the specified value number.
+/// The LiveRanges in RHS are allowed to overlap with LiveRanges in the
+/// current interval, but only if the overlapping LiveRanges have the
+/// specified value number.
+void LiveInterval::MergeValueInAsValue(const LiveInterval &RHS,
+                                       VNInfo *RHSValNo, VNInfo *LHSValNo) {
+  // TODO: Make this more efficient.
+  iterator InsertPos = begin();
+  for (const_iterator I = RHS.begin(), E = RHS.end(); I != E; ++I) {
+    if (I->valno != RHSValNo)
+      continue;
+    // Map the valno in the other live range to the current live range.
+    LiveRange Tmp = *I;
+    Tmp.valno = LHSValNo;
+    InsertPos = addRangeFrom(Tmp, InsertPos);
+  }
+}
+
+
 /// MergeInClobberRanges - For any live ranges that are not defined in the
 /// current interval, but are defined in the Clobbers interval, mark them
 /// used with an unknown definition value.
@@ -485,6 +505,23 @@ void LiveInterval::MergeValueNumberInto(VNInfo *V1, VNInfo *V2) {
   }
 }
 
+void LiveInterval::Copy(const LiveInterval &RHS,
+                        BumpPtrAllocator &VNInfoAllocator) {
+  ranges.clear();
+  valnos.clear();
+  preference = RHS.preference;
+  weight = RHS.weight;
+  for (unsigned i = 0, e = RHS.getNumValNums(); i != e; ++i) {
+    const VNInfo *VNI = RHS.getValNumInfo(i);
+    VNInfo *NewVNI = getNextValue(~0U, 0, VNInfoAllocator);
+    copyValNumInfo(NewVNI, VNI);
+  }
+  for (unsigned i = 0, e = RHS.ranges.size(); i != e; ++i) {
+    const LiveRange &LR = RHS.ranges[i];
+    addRange(LiveRange(LR.start, LR.end, getValNumInfo(LR.valno->id)));
+  }
+}
+
 unsigned LiveInterval::getSize() const {
   unsigned Sum = 0;
   for (const_iterator I = begin(), E = end(); I != E; ++I)
index 5ada75ca016c87f91abd241f78f14c0899f02bf3..5ed24a3be232a7f1544c13aa43b3b770c1a45de2 100644 (file)
@@ -136,75 +136,6 @@ void LiveIntervals::print(std::ostream &O, const Module* ) const {
   }
 }
 
-// Not called?
-/// CreateNewLiveInterval - Create a new live interval with the given live
-/// ranges. The new live interval will have an infinite spill weight.
-LiveInterval&
-LiveIntervals::CreateNewLiveInterval(const LiveInterval *LI,
-                                     const std::vector<LiveRange> &LRs) {
-  const TargetRegisterClass *RC = mf_->getSSARegMap()->getRegClass(LI->reg);
-
-  // Create a new virtual register for the spill interval.
-  unsigned NewVReg = mf_->getSSARegMap()->createVirtualRegister(RC);
-
-  // Replace the old virtual registers in the machine operands with the shiny
-  // new one.
-  for (std::vector<LiveRange>::const_iterator
-         I = LRs.begin(), E = LRs.end(); I != E; ++I) {
-    unsigned Index = getBaseIndex(I->start);
-    unsigned End = getBaseIndex(I->end - 1) + InstrSlots::NUM;
-
-    for (; Index != End; Index += InstrSlots::NUM) {
-      // Skip deleted instructions
-      while (Index != End && !getInstructionFromIndex(Index))
-        Index += InstrSlots::NUM;
-
-      if (Index == End) break;
-
-      MachineInstr *MI = getInstructionFromIndex(Index);
-
-      for (unsigned J = 0, e = MI->getNumOperands(); J != e; ++J) {
-        MachineOperand &MOp = MI->getOperand(J);
-        if (MOp.isRegister() && MOp.getReg() == LI->reg)
-          MOp.setReg(NewVReg);
-      }
-    }
-  }
-
-  LiveInterval &NewLI = getOrCreateInterval(NewVReg);
-
-  // The spill weight is now infinity as it cannot be spilled again
-  NewLI.weight = float(HUGE_VAL);
-
-  for (std::vector<LiveRange>::const_iterator
-         I = LRs.begin(), E = LRs.end(); I != E; ++I) {
-    DOUT << "  Adding live range " << *I << " to new interval\n";
-    NewLI.addRange(*I);
-  }
-            
-  DOUT << "Created new live interval " << NewLI << "\n";
-  return NewLI;
-}
-
-/// isReDefinedByTwoAddr - Returns true if the Reg re-definition is due to
-/// two addr elimination.
-static bool isReDefinedByTwoAddr(MachineInstr *MI, unsigned Reg,
-                                const TargetInstrInfo *TII) {
-  for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
-    MachineOperand &MO1 = MI->getOperand(i);
-    if (MO1.isRegister() && MO1.isDef() && MO1.getReg() == Reg) {
-      for (unsigned j = i+1; j < e; ++j) {
-        MachineOperand &MO2 = MI->getOperand(j);
-        if (MO2.isRegister() && MO2.isUse() && MO2.getReg() == Reg &&
-            MI->getInstrDescriptor()->
-            getOperandConstraint(j, TOI::TIED_TO) == (int)i)
-          return true;
-      }
-    }
-  }
-  return false;
-}
-
 /// isReMaterializable - Returns true if the definition MI of the specified
 /// val# of the specified interval is re-materializable.
 bool LiveIntervals::isReMaterializable(const LiveInterval &li,
@@ -232,7 +163,7 @@ bool LiveIntervals::isReMaterializable(const LiveInterval &li,
       continue; // Dead val#.
     MachineInstr *DefMI = (DefIdx == ~0u)
       ? NULL : getInstructionFromIndex(DefIdx);
-    if (DefMI && isReDefinedByTwoAddr(DefMI, li.reg, tii_))
+    if (DefMI && DefMI->isRegReDefinedByTwoAddr(li.reg))
       return false;
   }
   return true;
@@ -243,9 +174,9 @@ bool LiveIntervals::isReMaterializable(const LiveInterval &li,
 /// MI. If it is successul, MI is updated with the newly created MI and
 /// returns true.
 bool LiveIntervals::tryFoldMemoryOperand(MachineInstr* &MI, VirtRegMap &vrm,
+                                         MachineInstr *DefMI,
                                          unsigned index, unsigned i,
-                                         bool isSS, MachineInstr *DefMI,
-                                         int slot, unsigned reg) {
+                                         bool isSS, int slot, unsigned reg) {
   MachineInstr *fmi = isSS
     ? mri_->foldMemoryOperand(MI, i, slot)
     : mri_->foldMemoryOperand(MI, i, DefMI);
@@ -281,7 +212,8 @@ addIntervalsForSpills(const LiveInterval &li, VirtRegMap &vrm, unsigned reg) {
   li.print(DOUT, mri_);
   DOUT << '\n';
 
-  const TargetRegisterClass* rc = mf_->getSSARegMap()->getRegClass(li.reg);
+  SSARegMap *RegMap = mf_->getSSARegMap();
+  const TargetRegisterClass* rc = RegMap->getRegClass(li.reg);
 
   unsigned NumValNums = li.getNumValNums();
   SmallVector<MachineInstr*, 4> ReMatDefs;
@@ -364,113 +296,126 @@ addIntervalsForSpills(const LiveInterval &li, VirtRegMap &vrm, unsigned reg) {
     RestartInstruction:
       for (unsigned i = 0; i != MI->getNumOperands(); ++i) {
         MachineOperand& mop = MI->getOperand(i);
-        if (mop.isRegister() && mop.getReg() == li.reg) {
-          if (DefIsReMat) {
-            // If this is the rematerializable definition MI itself and
-            // all of its uses are rematerialized, simply delete it.
-            if (MI == OrigDefMI) {
-              if (CanDelete) {
-                RemoveMachineInstrFromMaps(MI);
-                MI->eraseFromParent();
-                break;
-              } else if (tryFoldMemoryOperand(MI, vrm, index, i, true,
-                                              DefMI, slot, li.reg)) {
-                // Folding the load/store can completely change the instruction
-                // in unpredictable ways, rescan it from the beginning.
-                goto RestartInstruction;
-              }
-            } else if (isLoad &&
-                       tryFoldMemoryOperand(MI, vrm, index, i, isLoadSS,
-                                            DefMI, LdSlot, li.reg))
-                // Folding the load/store can completely change the
-                // instruction in unpredictable ways, rescan it from
-                // the beginning.
-                goto RestartInstruction;
-          } else {
-            if (tryFoldMemoryOperand(MI,  vrm, index, i, true, DefMI,
-                                     slot, li.reg))
-              // Folding the load/store can completely change the instruction in
-              // unpredictable ways, rescan it from the beginning.
-              goto RestartInstruction;
+        if (!mop.isRegister())
+          continue;
+        unsigned Reg = mop.getReg();
+        if (Reg == 0 || MRegisterInfo::isPhysicalRegister(Reg))
+          continue;
+        bool isSubReg = RegMap->isSubRegister(Reg);
+        unsigned SubIdx = 0;
+        if (isSubReg) {
+          SubIdx = RegMap->getSubRegisterIndex(Reg);
+          Reg = RegMap->getSuperRegister(Reg);
+        }
+        if (Reg != li.reg)
+          continue;
+
+        bool TryFold = !DefIsReMat;
+        bool FoldSS = true;
+        int FoldSlot = slot;
+        if (DefIsReMat) {
+          // If this is the rematerializable definition MI itself and
+          // all of its uses are rematerialized, simply delete it.
+          if (MI == OrigDefMI && CanDelete) {
+            RemoveMachineInstrFromMaps(MI);
+            MI->eraseFromParent();
+            break;
           }
 
-          // Create a new virtual register for the spill interval.
-          unsigned NewVReg = mf_->getSSARegMap()->createVirtualRegister(rc);
+          // If def for this use can't be rematerialized, then try folding.
+          TryFold = !OrigDefMI || (OrigDefMI && (MI == OrigDefMI || isLoad));
+          if (isLoad) {
+            // Try fold loads (from stack slot, constant pool, etc.) into uses.
+            FoldSS = isLoadSS;
+            FoldSlot = LdSlot;
+          }
+        }
+
+        // FIXME: fold subreg use
+        if (!isSubReg && TryFold &&
+            tryFoldMemoryOperand(MI, vrm, DefMI, index, i, FoldSS, FoldSlot, Reg))
+          // Folding the load/store can completely change the instruction in
+          // unpredictable ways, rescan it from the beginning.
+          goto RestartInstruction;
+
+        // Create a new virtual register for the spill interval.
+        unsigned NewVReg = RegMap->createVirtualRegister(rc);
+        if (isSubReg)
+          RegMap->setIsSubRegister(NewVReg, NewVReg, SubIdx);
             
-          // Scan all of the operands of this instruction rewriting operands
-          // to use NewVReg instead of li.reg as appropriate.  We do this for
-          // two reasons:
-          //
-          //   1. If the instr reads the same spilled vreg multiple times, we
-          //      want to reuse the NewVReg.
-          //   2. If the instr is a two-addr instruction, we are required to
-          //      keep the src/dst regs pinned.
-          //
-          // Keep track of whether we replace a use and/or def so that we can
-          // create the spill interval with the appropriate range. 
-          mop.setReg(NewVReg);
+        // Scan all of the operands of this instruction rewriting operands
+        // to use NewVReg instead of li.reg as appropriate.  We do this for
+        // two reasons:
+        //
+        //   1. If the instr reads the same spilled vreg multiple times, we
+        //      want to reuse the NewVReg.
+        //   2. If the instr is a two-addr instruction, we are required to
+        //      keep the src/dst regs pinned.
+        //
+        // Keep track of whether we replace a use and/or def so that we can
+        // create the spill interval with the appropriate range. 
+        mop.setReg(NewVReg);
             
-          bool HasUse = mop.isUse();
-          bool HasDef = mop.isDef();
-          for (unsigned j = i+1, e = MI->getNumOperands(); j != e; ++j) {
-            if (MI->getOperand(j).isRegister() &&
-                MI->getOperand(j).getReg() == li.reg) {
-              MI->getOperand(j).setReg(NewVReg);
-              HasUse |= MI->getOperand(j).isUse();
-              HasDef |= MI->getOperand(j).isDef();
-            }
+        bool HasUse = mop.isUse();
+        bool HasDef = mop.isDef();
+        for (unsigned j = i+1, e = MI->getNumOperands(); j != e; ++j) {
+          if (MI->getOperand(j).isRegister() &&
+              MI->getOperand(j).getReg() == li.reg) {
+            MI->getOperand(j).setReg(NewVReg);
+            HasUse |= MI->getOperand(j).isUse();
+            HasDef |= MI->getOperand(j).isDef();
           }
+        }
 
-          vrm.grow();
-          if (DefIsReMat) {
-            vrm.setVirtIsReMaterialized(NewVReg, DefMI/*, CanDelete*/);
-            if (ReMatIds[I->valno->id] == VirtRegMap::MAX_STACK_SLOT) {
-              // Each valnum may have its own remat id.
-              ReMatIds[I->valno->id] = vrm.assignVirtReMatId(NewVReg);
-            } else {
-              vrm.assignVirtReMatId(NewVReg, ReMatIds[I->valno->id]);
-            }
-            if (!CanDelete || (HasUse && HasDef)) {
-              // If this is a two-addr instruction then its use operands are
-              // rematerializable but its def is not. It should be assigned a
-              // stack slot.
-              vrm.assignVirt2StackSlot(NewVReg, slot);
-            }
+        vrm.grow();
+        if (DefIsReMat) {
+          vrm.setVirtIsReMaterialized(NewVReg, DefMI/*, CanDelete*/);
+          if (ReMatIds[I->valno->id] == VirtRegMap::MAX_STACK_SLOT) {
+            // Each valnum may have its own remat id.
+            ReMatIds[I->valno->id] = vrm.assignVirtReMatId(NewVReg);
           } else {
+            vrm.assignVirtReMatId(NewVReg, ReMatIds[I->valno->id]);
+          }
+          if (!CanDelete || (HasUse && HasDef)) {
+            // If this is a two-addr instruction then its use operands are
+            // rematerializable but its def is not. It should be assigned a
+            // stack slot.
             vrm.assignVirt2StackSlot(NewVReg, slot);
           }
+        } else {
+          vrm.assignVirt2StackSlot(NewVReg, slot);
+        }
 
-          // create a new register interval for this spill / remat.
-          LiveInterval &nI = getOrCreateInterval(NewVReg);
-          assert(nI.empty());
+        // create a new register interval for this spill / remat.
+        LiveInterval &nI = getOrCreateInterval(NewVReg);
+        assert(nI.empty());
 
-          // the spill weight is now infinity as it
-          // cannot be spilled again
-          nI.weight = HUGE_VALF;
+        // the spill weight is now infinity as it
+        // cannot be spilled again
+        nI.weight = HUGE_VALF;
 
-          if (HasUse) {
-            LiveRange LR(getLoadIndex(index), getUseIndex(index)+1,
-                         nI.getNextValue(~0U, 0, VNInfoAllocator));
-            DOUT << " +" << LR;
-            nI.addRange(LR);
-          }
-          if (HasDef) {
-            LiveRange LR(getDefIndex(index), getStoreIndex(index),
-                         nI.getNextValue(~0U, 0, VNInfoAllocator));
-            DOUT << " +" << LR;
-            nI.addRange(LR);
-          }
+        if (HasUse) {
+          LiveRange LR(getLoadIndex(index), getUseIndex(index)+1,
+                       nI.getNextValue(~0U, 0, VNInfoAllocator));
+          DOUT << " +" << LR;
+          nI.addRange(LR);
+        }
+        if (HasDef) {
+          LiveRange LR(getDefIndex(index), getStoreIndex(index),
+                       nI.getNextValue(~0U, 0, VNInfoAllocator));
+          DOUT << " +" << LR;
+          nI.addRange(LR);
+        }
             
-          added.push_back(&nI);
+        added.push_back(&nI);
 
-          // update live variables if it is available
-          if (lv_)
-            lv_->addVirtualRegisterKilled(NewVReg, MI);
+        // update live variables if it is available
+        if (lv_)
+          lv_->addVirtualRegisterKilled(NewVReg, MI);
             
-          DOUT << "\t\t\t\tadded new interval: ";
-          nI.print(DOUT, mri_);
-          DOUT << '\n';
-        }
+        DOUT << "\t\t\t\tadded new interval: ";
+        nI.print(DOUT, mri_);
+        DOUT << '\n';
       }
     }
   }
@@ -501,10 +446,14 @@ void LiveIntervals::handleVirtualRegisterDef(MachineBasicBlock *mbb,
     unsigned defIndex = getDefIndex(MIIdx);
     VNInfo *ValNo;
     unsigned SrcReg, DstReg;
-    if (!tii_->isMoveInstr(*mi, SrcReg, DstReg))
-      ValNo = interval.getNextValue(defIndex, 0, VNInfoAllocator);
-    else
+    if (tii_->isMoveInstr(*mi, SrcReg, DstReg))
       ValNo = interval.getNextValue(defIndex, SrcReg, VNInfoAllocator);
+    else if (mi->getOpcode() == TargetInstrInfo::EXTRACT_SUBREG ||
+             mi->getOpcode() == TargetInstrInfo::INSERT_SUBREG)
+      ValNo = interval.getNextValue(defIndex, mi->getOperand(1).getReg(),
+                                    VNInfoAllocator);
+    else
+      ValNo = interval.getNextValue(defIndex, 0, VNInfoAllocator);
 
     assert(ValNo->id == 0 && "First value in interval is not 0?");
 
@@ -576,7 +525,7 @@ void LiveIntervals::handleVirtualRegisterDef(MachineBasicBlock *mbb,
     // must be due to phi elimination or two addr elimination.  If this is
     // the result of two address elimination, then the vreg is one of the
     // def-and-use register operand.
-    if (isReDefinedByTwoAddr(mi, interval.reg, tii_)) {
+    if (mi->isRegReDefinedByTwoAddr(interval.reg)) {
       // If this is a two-address definition, then we have already processed
       // the live range.  The only problem is that we didn't realize there
       // are actually two values in the live interval.  Because of this we
@@ -656,10 +605,13 @@ void LiveIntervals::handleVirtualRegisterDef(MachineBasicBlock *mbb,
       
       VNInfo *ValNo;
       unsigned SrcReg, DstReg;
-      if (!tii_->isMoveInstr(*mi, SrcReg, DstReg))
-        ValNo = interval.getNextValue(defIndex, 0, VNInfoAllocator);
-      else
+      if (tii_->isMoveInstr(*mi, SrcReg, DstReg))
         ValNo = interval.getNextValue(defIndex, SrcReg, VNInfoAllocator);
+      else if (mi->getOpcode() == TargetInstrInfo::EXTRACT_SUBREG)
+        ValNo = interval.getNextValue(defIndex, mi->getOperand(1).getReg(),
+                                      VNInfoAllocator);
+      else
+        ValNo = interval.getNextValue(defIndex, 0, VNInfoAllocator);
       
       unsigned killIndex = getInstructionIndex(&mbb->back()) + InstrSlots::NUM;
       LiveRange LR(defIndex, killIndex, ValNo);
@@ -741,7 +693,9 @@ void LiveIntervals::handleRegisterDef(MachineBasicBlock *MBB,
     handleVirtualRegisterDef(MBB, MI, MIIdx, getOrCreateInterval(reg));
   else if (allocatableRegs_[reg]) {
     unsigned SrcReg, DstReg;
-    if (!tii_->isMoveInstr(*MI, SrcReg, DstReg))
+    if (MI->getOpcode() == TargetInstrInfo::EXTRACT_SUBREG)
+      SrcReg = MI->getOperand(1).getReg();
+    else if (!tii_->isMoveInstr(*MI, SrcReg, DstReg))
       SrcReg = 0;
     handlePhysicalRegisterDef(MBB, MI, MIIdx, getOrCreateInterval(reg), SrcReg);
     // Def of a register also defines its sub-registers.
index 1634c7880e20b92d781b0f74e91f2a42c60c930c..1ac955a743c400a60b805bffbc9879b217eae952 100644 (file)
@@ -220,6 +220,24 @@ int MachineInstr::findFirstPredOperandIdx() const {
   return -1;
 }
   
+/// isRegReDefinedByTwoAddr - Returns true if the Reg re-definition is due
+/// to two addr elimination.
+bool MachineInstr::isRegReDefinedByTwoAddr(unsigned Reg) const {
+  const TargetInstrDescriptor *TID = getInstrDescriptor();
+  for (unsigned i = 0, e = getNumOperands(); i != e; ++i) {
+    const MachineOperand &MO1 = getOperand(i);
+    if (MO1.isRegister() && MO1.isDef() && MO1.getReg() == Reg) {
+      for (unsigned j = i+1; j < e; ++j) {
+        const MachineOperand &MO2 = getOperand(j);
+        if (MO2.isRegister() && MO2.isUse() && MO2.getReg() == Reg &&
+            TID->getOperandConstraint(j, TOI::TIED_TO) == (int)i)
+          return true;
+      }
+    }
+  }
+  return false;
+}
+
 /// copyKillDeadInfo - Copies kill / dead operand properties from MI.
 ///
 void MachineInstr::copyKillDeadInfo(const MachineInstr *MI) {
index b616b7e4825818d503cddaf74a3b5cf34b88a246..bb5379c34917ff64fc008c7368b492eb3c1ca8fa 100644 (file)
@@ -567,9 +567,6 @@ void ScheduleDAG::EmitSubregNode(SDNode *Node,
     // TODO: If the node is a use of a CopyFromReg from a physical register
     // fold the extract into the copy now
 
-    // TODO: Add tracking info to SSARegMap of which vregs are subregs
-    // to allow coalescing in the allocator
-    
     // Create the extract_subreg machine instruction.
     MachineInstr *MI =
       new MachineInstr(BB, TII->get(TargetInstrInfo::EXTRACT_SUBREG));
index c1a85096157d29168621cf4356690236d683eb8c..2baf24d7d54b33235406353ac37d57ff2f681021 100644 (file)
@@ -1097,6 +1097,11 @@ namespace {
         // CopyToReg should be close to its uses to facilitate coalescing and
         // avoid spilling.
         return 0;
+      else if (Opc == TargetInstrInfo::EXTRACT_SUBREG ||
+               Opc == TargetInstrInfo::INSERT_SUBREG)
+        // EXTRACT_SUBREG / INSERT_SUBREG should be close to its use to
+        // facilitate coalescing.
+        return 0;
       else if (SU->NumSuccs == 0)
         // If SU does not have a use, i.e. it doesn't produce a value that would
         // be consumed (e.g. store), then it terminates a chain of computation.
@@ -1308,6 +1313,14 @@ void BURegReductionPriorityQueue<SF>::AddPseudoTwoAddrDeps() {
           // Be conservative. Ignore if nodes aren't at the same depth.
           if (SuccSU->Depth != SU->Depth)
             continue;
+          if (!SuccSU->Node || !SuccSU->Node->isTargetOpcode())
+            continue;
+          // Don't constraint extract_subreg / insert_subreg these may be
+          // coalesced away. We don't them close to their uses.
+          unsigned SuccOpc = SuccSU->Node->getTargetOpcode();
+          if (SuccOpc == TargetInstrInfo::EXTRACT_SUBREG ||
+              SuccOpc == TargetInstrInfo::INSERT_SUBREG)
+            continue;
           if ((!canClobber(SuccSU, DUSU) ||
                (hasCopyToRegUse(SU) && !hasCopyToRegUse(SuccSU)) ||
                (!SU->isCommutable && SuccSU->isCommutable)) &&
index 59e9e4501a28edf622a853eb32f86fc4770abb21..9d43750f1c68ca2ce73a4e3361a15d8da48d0947 100644 (file)
@@ -226,11 +226,55 @@ bool SimpleRegisterCoalescing::JoinCopy(MachineInstr *CopyMI,
     DOUT << "\tDst reg is unallocatable physreg.\n";
     return true;  // Not coalescable.
   }
-  
-  // If they are not of the same register class, we cannot join them.
-  if (differingRegisterClasses(repSrcReg, repDstReg)) {
+
+  bool isExtSubReg = CopyMI->getOpcode() == TargetInstrInfo::EXTRACT_SUBREG;
+  unsigned RealDstReg = 0;
+  if (isExtSubReg) {
+    unsigned SubIdx = CopyMI->getOperand(2).getImm();
+    if (SrcIsPhys)
+      // r1024 = EXTRACT_SUBREG EAX, 0 then r1024 is really going to be
+      // coalesced with AX.
+      repSrcReg = mri_->getSubReg(repSrcReg, SubIdx);
+    else if (DstIsPhys) {
+      // If this is a extract_subreg where dst is a physical register, e.g.
+      // cl = EXTRACT_SUBREG reg1024, 1
+      // then create and update the actual physical register allocated to RHS.
+      const TargetRegisterClass *RC = mf_->getSSARegMap()->getRegClass(SrcReg);
+      for (const unsigned *SRs = mri_->getSuperRegisters(repDstReg);
+           unsigned SR = *SRs; ++SRs) {
+        if (repDstReg == mri_->getSubReg(SR, SubIdx) &&
+            RC->contains(SR)) {
+          RealDstReg = SR;
+          break;
+        }
+      }
+      assert(RealDstReg && "Invalid extra_subreg instruction!");
+
+      // For this type of EXTRACT_SUBREG, conservatively
+      // check if the live interval of the source register interfere with the
+      // actual super physical register we are trying to coalesce with.
+      LiveInterval &RHS = li_->getInterval(repSrcReg);
+      if (li_->hasInterval(RealDstReg) &&
+          RHS.overlaps(li_->getInterval(RealDstReg))) {
+        DOUT << "Interfere with register ";
+        DEBUG(li_->getInterval(RealDstReg).print(DOUT, mri_));
+        return true; // Not coalescable
+      }
+      for (const unsigned* SR = mri_->getSubRegisters(RealDstReg); *SR; ++SR)
+        if (li_->hasInterval(*SR) && RHS.overlaps(li_->getInterval(*SR))) {
+          DOUT << "Interfere with sub-register ";
+          DEBUG(li_->getInterval(*SR).print(DOUT, mri_));
+          return true;
+        }
+    }
+  } else if (differingRegisterClasses(repSrcReg, repDstReg)) {
+    // If they are not of the same register class, we cannot join them.
     DOUT << "\tSrc/Dest are different register classes.\n";
-    return true;  // Not coalescable.
+    // Allow the coalescer to try again in case either side gets coalesced to
+    // a physical register that's compatible with the other side. e.g.
+    // r1024 = MOV32to32_ r1025
+    // but later r1024 is assigned EAX then r1025 may be coalesced with EAX.
+    return false;
   }
   
   LiveInterval &SrcInt = li_->getInterval(repSrcReg);
@@ -286,14 +330,14 @@ bool SimpleRegisterCoalescing::JoinCopy(MachineInstr *CopyMI,
   // virtual register. Once the coalescing is done, it cannot be broken and
   // these are not spillable! If the destination interval uses are far away,
   // think twice about coalescing them!
-  if (!mopd->isDead() && (SrcIsPhys || DstIsPhys)) {
+  if (!mopd->isDead() && (SrcIsPhys || DstIsPhys) && !isExtSubReg) {
     LiveInterval &JoinVInt = SrcIsPhys ? DstInt : SrcInt;
     unsigned JoinVReg = SrcIsPhys ? repDstReg : repSrcReg;
     unsigned JoinPReg = SrcIsPhys ? repSrcReg : repDstReg;
     const TargetRegisterClass *RC = mf_->getSSARegMap()->getRegClass(JoinVReg);
     unsigned Threshold = allocatableRCRegs_[RC].count();
 
-    // If the virtual register live interval is long has it has low use desity,
+    // If the virtual register live interval is long but it has low use desity,
     // do not join them, instead mark the physical register as its allocation
     // preference.
     unsigned Length = JoinVInt.getSize() / InstrSlots::NUM;
@@ -340,7 +384,7 @@ bool SimpleRegisterCoalescing::JoinCopy(MachineInstr *CopyMI,
     // Coalescing failed.
     
     // If we can eliminate the copy without merging the live ranges, do so now.
-    if (AdjustCopiesBackFrom(SrcInt, DstInt, CopyMI))
+    if (!isExtSubReg && AdjustCopiesBackFrom(SrcInt, DstInt, CopyMI))
       return true;
 
     // Otherwise, we are unable to join the intervals.
@@ -368,9 +412,24 @@ bool SimpleRegisterCoalescing::JoinCopy(MachineInstr *CopyMI,
         unsetRegisterKills(I->start, I->end, repDstReg);
     }
 
+    // If this is a extract_subreg where dst is a physical register, e.g.
+    // cl = EXTRACT_SUBREG reg1024, 1
+    // then create and update the actual physical register allocated to RHS.
+    if (RealDstReg) {
+      unsigned CopyIdx = li_->getInstructionIndex(CopyMI);
+      VNInfo *DstValNo =
+        ResDstInt->getLiveRangeContaining(li_->getUseIndex(CopyIdx))->valno;
+      LiveInterval &RealDstInt = li_->getOrCreateInterval(RealDstReg);
+      VNInfo *ValNo = RealDstInt.getNextValue(DstValNo->def, DstValNo->reg,
+                                              li_->getVNInfoAllocator());
+      RealDstInt.addKills(ValNo, DstValNo->kills);
+      RealDstInt.MergeValueInAsValue(*ResDstInt, DstValNo, ValNo);
+      repDstReg = RealDstReg;
+    }
+
     // Update the liveintervals of sub-registers.
     for (const unsigned *AS = mri_->getSubRegisters(repDstReg); *AS; ++AS)
-      li_->getInterval(*AS).MergeInClobberRanges(*ResSrcInt,
+      li_->getOrCreateInterval(*AS).MergeInClobberRanges(*ResSrcInt,
                                                  li_->getVNInfoAllocator());
   } else {
     // Merge use info if the destination is a virtual register.
@@ -379,14 +438,25 @@ bool SimpleRegisterCoalescing::JoinCopy(MachineInstr *CopyMI,
     dVI.NumUses += sVI.NumUses;
   }
 
-  DOUT << "\n\t\tJoined.  Result = "; ResDstInt->print(DOUT, mri_);
-  DOUT << "\n";
-
   // Remember these liveintervals have been joined.
   JoinedLIs.set(repSrcReg - MRegisterInfo::FirstVirtualRegister);
   if (MRegisterInfo::isVirtualRegister(repDstReg))
     JoinedLIs.set(repDstReg - MRegisterInfo::FirstVirtualRegister);
 
+  if (isExtSubReg && !SrcIsPhys && !DstIsPhys) {
+    if (!Swapped) {
+      // Make sure we allocate the larger super-register.
+      ResSrcInt->Copy(*ResDstInt, li_->getVNInfoAllocator());
+      std::swap(repSrcReg, repDstReg);
+      std::swap(ResSrcInt, ResDstInt);
+    }
+    SubRegIdxes.push_back(std::make_pair(repSrcReg,
+                                         CopyMI->getOperand(2).getImm()));
+  }
+
+  DOUT << "\n\t\tJoined.  Result = "; ResDstInt->print(DOUT, mri_);
+  DOUT << "\n";
+
   // repSrcReg is guarateed to be the register whose live interval that is
   // being merged.
   li_->removeInterval(repSrcReg);
@@ -857,9 +927,13 @@ void SimpleRegisterCoalescing::CopyCoalesceInMBB(MachineBasicBlock *MBB,
        MII != E;) {
     MachineInstr *Inst = MII++;
     
-    // If this isn't a copy, we can't join intervals.
+    // If this isn't a copy nor a extract_subreg, we can't join intervals.
     unsigned SrcReg, DstReg;
-    if (!tii_->isMoveInstr(*Inst, SrcReg, DstReg)) continue;
+    if (Inst->getOpcode() == TargetInstrInfo::EXTRACT_SUBREG) {
+      DstReg = Inst->getOperand(0).getReg();
+      SrcReg = Inst->getOperand(1).getReg();
+    } else if (!tii_->isMoveInstr(*Inst, SrcReg, DstReg))
+      continue;
     
     bool Done = JoinCopy(Inst, SrcReg, DstReg, PhysOnly);
     if (TryAgain && !Done)
@@ -950,7 +1024,7 @@ void SimpleRegisterCoalescing::joinIntervals() {
 /// Return true if the two specified registers belong to different register
 /// classes.  The registers may be either phys or virt regs.
 bool SimpleRegisterCoalescing::differingRegisterClasses(unsigned RegA,
-                                             unsigned RegB) const {
+                                                        unsigned RegB) const {
 
   // Get the register classes for the first reg.
   if (MRegisterInfo::isPhysicalRegister(RegA)) {
@@ -1074,6 +1148,7 @@ void SimpleRegisterCoalescing::printRegName(unsigned reg) const {
 void SimpleRegisterCoalescing::releaseMemory() {
    r2rMap_.clear();
    JoinedLIs.clear();
+   SubRegIdxes.clear();
 }
 
 static bool isZeroLengthInterval(LiveInterval *li) {
@@ -1101,7 +1176,8 @@ bool SimpleRegisterCoalescing::runOnMachineFunction(MachineFunction &fn) {
          E = mri_->regclass_end(); I != E; ++I)
     allocatableRCRegs_.insert(std::make_pair(*I,mri_->getAllocatableSet(fn, *I)));
 
-  r2rMap_.grow(mf_->getSSARegMap()->getLastVirtReg());
+  SSARegMap *RegMap = mf_->getSSARegMap();
+  r2rMap_.grow(RegMap->getLastVirtReg());
 
   // Join (coalesce) intervals if requested.
   if (EnableJoining) {
@@ -1111,6 +1187,13 @@ bool SimpleRegisterCoalescing::runOnMachineFunction(MachineFunction &fn) {
       I->second.print(DOUT, mri_);
       DOUT << "\n";
     }
+
+    // Track coalesced sub-registers.
+    while (!SubRegIdxes.empty()) {
+      std::pair<unsigned, unsigned> RI = SubRegIdxes.back();
+      SubRegIdxes.pop_back();
+      mf_->getSSARegMap()->setIsSubRegister(RI.first, rep(RI.first), RI.second);
+    }
   }
 
   // perform a final pass over the instructions and compute spill
@@ -1150,8 +1233,14 @@ bool SimpleRegisterCoalescing::runOnMachineFunction(MachineFunction &fn) {
           if (mop.isRegister() && mop.getReg() &&
               MRegisterInfo::isVirtualRegister(mop.getReg())) {
             // replace register with representative register
-            unsigned reg = rep(mop.getReg());
-            mii->getOperand(i).setReg(reg);
+            unsigned OrigReg = mop.getReg();
+            unsigned reg = rep(OrigReg);
+            // Don't rewrite if it is a sub-register of a virtual register.
+            if (!RegMap->isSubRegister(OrigReg))
+              mii->getOperand(i).setReg(reg);
+            else if (MRegisterInfo::isPhysicalRegister(reg))
+              mii->getOperand(i).setReg(mri_->getSubReg(reg,
+                                         RegMap->getSubRegisterIndex(OrigReg)));
 
             // Multiple uses of reg by the same instruction. It should not
             // contribute to spill weight again.
index c6ac4b208d0c31d2d160f24814b98e7efee6f762..ebdbb86c2bdda896a4ae5d03a6f2c5b751e8e9f5 100644 (file)
@@ -242,10 +242,12 @@ namespace {
   /// blocks that have low register pressure (the vreg may be spilled due to
   /// register pressure in other blocks).
   class VISIBILITY_HIDDEN LocalSpiller : public Spiller {
+    SSARegMap *RegMap;
     const MRegisterInfo *MRI;
     const TargetInstrInfo *TII;
   public:
     bool runOnMachineFunction(MachineFunction &MF, VirtRegMap &VRM) {
+      RegMap = MF.getSSARegMap();
       MRI = MF.getTarget().getRegisterInfo();
       TII = MF.getTarget().getInstrInfo();
       DOUT << "\n**** Local spiller rewriting function '"
@@ -776,25 +778,33 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM) {
       if (!MO.isRegister() || MO.getReg() == 0)
         continue;   // Ignore non-register operands.
       
-      if (MRegisterInfo::isPhysicalRegister(MO.getReg())) {
+      unsigned VirtReg = MO.getReg();
+      if (MRegisterInfo::isPhysicalRegister(VirtReg)) {
         // Ignore physregs for spilling, but remember that it is used by this
         // function.
-        MF.setPhysRegUsed(MO.getReg());
-        ReusedOperands.markClobbered(MO.getReg());
+        MF.setPhysRegUsed(VirtReg);
+        ReusedOperands.markClobbered(VirtReg);
         continue;
       }
       
-      assert(MRegisterInfo::isVirtualRegister(MO.getReg()) &&
+      assert(MRegisterInfo::isVirtualRegister(VirtReg) &&
              "Not a virtual or a physical register?");
       
-      unsigned VirtReg = MO.getReg();
+      unsigned SubIdx = 0;
+      bool isSubReg = RegMap->isSubRegister(VirtReg);
+      if (isSubReg) {
+        SubIdx = RegMap->getSubRegisterIndex(VirtReg);
+        VirtReg = RegMap->getSuperRegister(VirtReg);
+      }
+
       if (VRM.isAssignedReg(VirtReg)) {
         // This virtual register was assigned a physreg!
         unsigned Phys = VRM.getPhys(VirtReg);
         MF.setPhysRegUsed(Phys);
         if (MO.isDef())
           ReusedOperands.markClobbered(Phys);
-        MI.getOperand(i).setReg(Phys);
+        unsigned RReg = isSubReg ? MRI->getSubReg(Phys, SubIdx) : Phys;
+        MI.getOperand(i).setReg(RReg);
         continue;
       }
       
@@ -817,6 +827,24 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM) {
         if (ReuseSlot != VirtRegMap::NO_STACK_SLOT)
           PhysReg = Spills.getSpillSlotOrReMatPhysReg(ReuseSlot);
       }
+
+      // If this is a sub-register use, make sure the reuse register is in the
+      // right register class. For example, for x86 not all of the 32-bit
+      // registers have accessible sub-registers.
+      // Similarly so for EXTRACT_SUBREG. Consider this:
+      // EDI = op
+      // MOV32_mr fi#1, EDI
+      // ...
+      //       = EXTRACT_SUBREG fi#1
+      // fi#1 is available in EDI, but it cannot be reused because it's not in
+      // the right register file.
+      if (PhysReg &&
+          (isSubReg || MI.getOpcode() == TargetInstrInfo::EXTRACT_SUBREG)) {
+        const TargetRegisterClass* RC = RegMap->getRegClass(VirtReg);
+        if (!RC->contains(PhysReg))
+          PhysReg = 0;
+      }
+
       if (PhysReg) {
         // This spilled operand might be part of a two-address operand.  If this
         // is the case, then changing it will necessarily require changing the 
@@ -824,6 +852,7 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM) {
         // aren't allowed to modify the reused register.  If none of these cases
         // apply, reuse it.
         bool CanReuse = true;
+
         int ti = TID->getOperandConstraint(i, TOI::TIED_TO);
         if (ti != -1 &&
             MI.getOperand(ti).isRegister() && 
@@ -845,7 +874,8 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM) {
                << MRI->getName(PhysReg) << " for vreg"
                << VirtReg <<" instead of reloading into physreg "
                << MRI->getName(VRM.getPhys(VirtReg)) << "\n";
-          MI.getOperand(i).setReg(PhysReg);
+          unsigned RReg = isSubReg ? MRI->getSubReg(PhysReg, SubIdx) : PhysReg;
+          MI.getOperand(i).setReg(RReg);
 
           // The only technical detail we have is that we don't know that
           // PhysReg won't be clobbered by a reloaded stack slot that occurs
@@ -883,7 +913,7 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM) {
             }
           }
           continue;
-        }
+        }  // CanReuse
         
         // Otherwise we have a situation where we have a two-address instruction
         // whose mod/ref operand needs to be reloaded.  This reload is already
@@ -917,13 +947,14 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM) {
           DOUT << " from physreg " << MRI->getName(PhysReg) << " for vreg"
                << VirtReg
                << " instead of reloading into same physreg.\n";
-          MI.getOperand(i).setReg(PhysReg);
+          unsigned RReg = isSubReg ? MRI->getSubReg(PhysReg, SubIdx) : PhysReg;
+          MI.getOperand(i).setReg(RReg);
           ReusedOperands.markClobbered(PhysReg);
           ++NumReused;
           continue;
         }
         
-        const TargetRegisterClass* RC = MF.getSSARegMap()->getRegClass(VirtReg);
+        const TargetRegisterClass* RC = RegMap->getRegClass(VirtReg);
         MF.setPhysRegUsed(DesignatedReg);
         ReusedOperands.markClobbered(DesignatedReg);
         MRI->copyRegToReg(MBB, &MI, DesignatedReg, PhysReg, RC, RC);
@@ -935,16 +966,17 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM) {
         Spills.ClobberPhysReg(DesignatedReg);
         
         Spills.addAvailable(ReuseSlot, &MI, DesignatedReg);
-        MI.getOperand(i).setReg(DesignatedReg);
+        unsigned RReg =
+          isSubReg ? MRI->getSubReg(DesignatedReg, SubIdx) : DesignatedReg;
+        MI.getOperand(i).setReg(RReg);
         DOUT << '\t' << *prior(MII);
         ++NumReused;
         continue;
-      }
+      } // is (PhysReg)
       
       // Otherwise, reload it and remember that we have it.
       PhysReg = VRM.getPhys(VirtReg);
       assert(PhysReg && "Must map virtreg to physreg!");
-      const TargetRegisterClass* RC = MF.getSSARegMap()->getRegClass(VirtReg);
 
       // Note that, if we reused a register for a previous operand, the
       // register we want to reload into might not actually be
@@ -960,6 +992,7 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM) {
         MRI->reMaterialize(MBB, &MI, PhysReg, VRM.getReMaterializedMI(VirtReg));
         ++NumReMats;
       } else {
+        const TargetRegisterClass* RC = RegMap->getRegClass(VirtReg);
         MRI->loadRegFromStackSlot(MBB, &MI, PhysReg, SSorRMId, RC);
         ++NumLoads;
       }
@@ -974,7 +1007,8 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM) {
       // unless it's a two-address operand.
       if (TID->getOperandConstraint(i, TOI::TIED_TO) == -1)
         MI.getOperand(i).setIsKill();
-      MI.getOperand(i).setReg(PhysReg);
+      unsigned RReg = isSubReg ? MRI->getSubReg(PhysReg, SubIdx) : PhysReg;
+      MI.getOperand(i).setReg(RReg);
       UpdateKills(*prior(MII), RegKills, KillOps);
       DOUT << '\t' << *prior(MII);
     }
@@ -1002,30 +1036,28 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM) {
       // straight load from the virt reg slot.
       if ((MR & VirtRegMap::isRef) && !(MR & VirtRegMap::isMod)) {
         int FrameIdx;
-        if (unsigned DestReg = TII->isLoadFromStackSlot(&MI, FrameIdx)) {
-          if (FrameIdx == SS) {
-            // If this spill slot is available, turn it into a copy (or nothing)
-            // instead of leaving it as a load!
-            if (unsigned InReg = Spills.getSpillSlotOrReMatPhysReg(SS)) {
-              DOUT << "Promoted Load To Copy: " << MI;
-              if (DestReg != InReg) {
-                const TargetRegisterClass *RC =
-                  MF.getSSARegMap()->getRegClass(VirtReg);
-                MRI->copyRegToReg(MBB, &MI, DestReg, InReg, RC, RC);
-                // Revisit the copy so we make sure to notice the effects of the
-                // operation on the destreg (either needing to RA it if it's 
-                // virtual or needing to clobber any values if it's physical).
-                NextMII = &MI;
-                --NextMII;  // backtrack to the copy.
-                BackTracked = true;
-              } else
-                DOUT << "Removing now-noop copy: " << MI;
+        unsigned DestReg = TII->isLoadFromStackSlot(&MI, FrameIdx);
+        if (DestReg && FrameIdx == SS) {
+          // If this spill slot is available, turn it into a copy (or nothing)
+          // instead of leaving it as a load!
+          if (unsigned InReg = Spills.getSpillSlotOrReMatPhysReg(SS)) {
+            DOUT << "Promoted Load To Copy: " << MI;
+            if (DestReg != InReg) {
+              const TargetRegisterClass *RC = RegMap->getRegClass(VirtReg);
+              MRI->copyRegToReg(MBB, &MI, DestReg, InReg, RC, RC);
+              // Revisit the copy so we make sure to notice the effects of the
+              // operation on the destreg (either needing to RA it if it's 
+              // virtual or needing to clobber any values if it's physical).
+              NextMII = &MI;
+              --NextMII;  // backtrack to the copy.
+              BackTracked = true;
+            } else
+              DOUT << "Removing now-noop copy: " << MI;
 
-              VRM.RemoveFromFoldedVirtMap(&MI);
-              MBB.erase(&MI);
-              Erased = true;
-              goto ProcessNextInst;
-            }
+            VRM.RemoveFromFoldedVirtMap(&MI);
+            MBB.erase(&MI);
+            Erased = true;
+            goto ProcessNextInst;
           }
         }
       }
@@ -1121,7 +1153,7 @@ void LocalSpiller::RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM) {
 
         // The only vregs left are stack slot definitions.
         int StackSlot = VRM.getStackSlot(VirtReg);
-        const TargetRegisterClass *RC = MF.getSSARegMap()->getRegClass(VirtReg);
+        const TargetRegisterClass *RC = RegMap->getRegClass(VirtReg);
 
         // If this def is part of a two-address operand, make sure to execute
         // the store from the correct physical register.