[llvm-commits] [llvm] r48490 - in /llvm/trunk: lib/CodeGen/SimpleRegisterCoalescing.cpp lib/CodeGen/SimpleRegisterCoalescing.h test/CodeGen/PowerPC/2008-03-17-RegScavengerCrash.ll

Evan Cheng evan.cheng at apple.com
Tue Mar 18 01:26:47 PDT 2008


Author: evancheng
Date: Tue Mar 18 03:26:47 2008
New Revision: 48490

URL: http://llvm.org/viewvc/llvm-project?rev=48490&view=rev
Log:
Rewrite code that propagate isDead information after a dead copy is coalesced. This remove some ugly spaghetti code and fixed a number of subtle bugs.

Added:
    llvm/trunk/test/CodeGen/PowerPC/2008-03-17-RegScavengerCrash.ll
Modified:
    llvm/trunk/lib/CodeGen/SimpleRegisterCoalescing.cpp
    llvm/trunk/lib/CodeGen/SimpleRegisterCoalescing.h

Modified: llvm/trunk/lib/CodeGen/SimpleRegisterCoalescing.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SimpleRegisterCoalescing.cpp?rev=48490&r1=48489&r2=48490&view=diff

==============================================================================
--- llvm/trunk/lib/CodeGen/SimpleRegisterCoalescing.cpp (original)
+++ llvm/trunk/lib/CodeGen/SimpleRegisterCoalescing.cpp Tue Mar 18 03:26:47 2008
@@ -479,28 +479,143 @@
   }
 }
 
-/// ShortenDeadCopyLiveRange - Shorten a live range as it's artificially
-/// extended by a dead copy. Mark the last use (if any) of the val# as kill
-/// as ends the live range there. If there isn't another use, then this
-/// live range is dead.
+/// removeRange - Wrapper for LiveInterval::removeRange. This removes a range
+/// from a physical register live interval as well as from the live intervals
+/// of its sub-registers.
+static void removeRange(LiveInterval &li, unsigned Start, unsigned End,
+                        LiveIntervals *li_, const TargetRegisterInfo *tri_) {
+  li.removeRange(Start, End, true);
+  if (TargetRegisterInfo::isPhysicalRegister(li.reg)) {
+    for (const unsigned* SR = tri_->getSubRegisters(li.reg); *SR; ++SR) {
+      if (!li_->hasInterval(*SR))
+        continue;
+      LiveInterval &sli = li_->getInterval(*SR);
+      unsigned RemoveEnd = Start;
+      while (RemoveEnd != End) {
+        LiveInterval::iterator LR = sli.FindLiveRangeContaining(Start);
+        if (LR == sli.end())
+          break;
+        RemoveEnd = (LR->end < End) ? LR->end : End;
+        sli.removeRange(Start, RemoveEnd, true);
+        Start = RemoveEnd;
+      }
+    }
+  }
+}
+
+/// removeIntervalIfEmpty - Check if the live interval of a physical register
+/// is empty, if so remove it and also remove the empty intervals of its
+/// sub-registers.
+static void removeIntervalIfEmpty(LiveInterval &li, LiveIntervals *li_,
+                                  const TargetRegisterInfo *tri_) {
+  if (li.empty()) {
+    li_->removeInterval(li.reg);
+    if (TargetRegisterInfo::isPhysicalRegister(li.reg))
+      for (const unsigned* SR = tri_->getSubRegisters(li.reg); *SR; ++SR) {
+        if (!li_->hasInterval(*SR))
+          continue;
+        LiveInterval &sli = li_->getInterval(*SR);
+        if (sli.empty())
+          li_->removeInterval(*SR);
+      }
+  }
+}
+
+/// ShortenDeadCopyLiveRange - Shorten a live range defined by a dead copy.
+///
 void SimpleRegisterCoalescing::ShortenDeadCopyLiveRange(LiveInterval &li,
                                                         MachineInstr *CopyMI) {
   unsigned CopyIdx = li_->getInstructionIndex(CopyMI);
   LiveInterval::iterator MLR =
     li.FindLiveRangeContaining(li_->getDefIndex(CopyIdx));
+  if (MLR == li.end())
+    return;  // Already removed by ShortenDeadCopySrcLiveRange.
   unsigned RemoveStart = MLR->start;
   unsigned RemoveEnd = MLR->end;
+  // Remove the liverange that's defined by this.
+  if (RemoveEnd == li_->getDefIndex(CopyIdx)+1) {
+    removeRange(li, RemoveStart, RemoveEnd, li_, tri_);
+    removeIntervalIfEmpty(li, li_, tri_);
+  }
+}
+
+/// ShortenDeadCopyLiveRange - Shorten a live range as it's artificially
+/// extended by a dead copy. Mark the last use (if any) of the val# as kill
+/// as ends the live range there. If there isn't another use, then this
+/// live range is dead.
+void
+SimpleRegisterCoalescing::ShortenDeadCopySrcLiveRange(LiveInterval &li,
+                                                      MachineInstr *CopyMI) {
+  unsigned CopyIdx = li_->getInstructionIndex(CopyMI);
+  if (CopyIdx == 0) {
+    // FIXME: special case: function live in. It can be a general case if the
+    // first instruction index starts at > 0 value.
+    assert(TargetRegisterInfo::isPhysicalRegister(li.reg));
+    // Live-in to the function but dead. Remove it from entry live-in set.
+    mf_->begin()->removeLiveIn(li.reg);
+    LiveInterval::iterator LR = li.FindLiveRangeContaining(CopyIdx);
+    removeRange(li, LR->start, LR->end, li_, tri_);
+    removeIntervalIfEmpty(li, li_, tri_);
+    return;
+  }
+
+  LiveInterval::iterator LR = li.FindLiveRangeContaining(CopyIdx-1);
+  if (LR == li.end())
+    // Livein but defined by a phi.
+    return;
+
+  unsigned RemoveStart = LR->start;
+  unsigned RemoveEnd = li_->getDefIndex(CopyIdx)+1;
+  if (LR->end > RemoveEnd)
+    // More uses past this copy? Nothing to do.
+    return;
+
   unsigned LastUseIdx;
-  MachineOperand *LastUse = lastRegisterUse(RemoveStart, CopyIdx, li.reg,
-                                            LastUseIdx);
+  MachineOperand *LastUse =
+    lastRegisterUse(LR->start, CopyIdx-1, li.reg, LastUseIdx);
   if (LastUse) {
-    // Shorten the liveinterval to the end of last use.
+    // There are uses before the copy, just shorten the live range to the end
+    // of last use.
     LastUse->setIsKill();
-    RemoveStart = li_->getDefIndex(LastUseIdx);
+    MachineInstr *LastUseMI = LastUse->getParent();
+    removeRange(li, li_->getDefIndex(LastUseIdx), LR->end, li_, tri_);
+    unsigned SrcReg, DstReg;
+    if (tii_->isMoveInstr(*LastUseMI, SrcReg, DstReg) &&
+        DstReg == li.reg) {
+      // Last use is itself an identity code.
+      int DeadIdx = LastUseMI->findRegisterDefOperandIdx(li.reg, false, tri_);
+      LastUseMI->getOperand(DeadIdx).setIsDead();
+    }
+    return;
   }
-  li.removeRange(RemoveStart, RemoveEnd, true);
-  if (li.empty())
-    li_->removeInterval(li.reg);
+
+  // Is it livein?
+  MachineBasicBlock *CopyMBB = CopyMI->getParent();
+  unsigned MBBStart = li_->getMBBStartIdx(CopyMBB);
+  if (LR->start <= MBBStart && LR->end > MBBStart) {
+    if (LR->start == 0) {
+      assert(TargetRegisterInfo::isPhysicalRegister(li.reg));
+      // Live-in to the function but dead. Remove it from entry live-in set.
+      mf_->begin()->removeLiveIn(li.reg);
+    }
+    removeRange(li, LR->start, LR->end, li_, tri_);
+    // FIXME: Shorten intervals in BBs that reaches this BB.
+  } else {
+    // Not livein into BB.
+    MachineInstr *DefMI =
+      li_->getInstructionFromIndex(li_->getDefIndex(RemoveStart));
+    if (DefMI && DefMI != CopyMI) {
+      int DeadIdx = DefMI->findRegisterDefOperandIdx(li.reg, false, tri_);
+      if (DeadIdx != -1) {
+        DefMI->getOperand(DeadIdx).setIsDead();
+        // A dead def should have a single cycle interval.
+        ++RemoveStart;
+      }
+    }
+    removeRange(li, RemoveStart, LR->end, li_, tri_);
+  }
+
+  removeIntervalIfEmpty(li, li_, tri_);
 }
 
 /// JoinCopy - Attempt to join intervals corresponding to SrcReg/DstReg,
@@ -638,48 +753,15 @@
   DOUT << " and "; DstInt.print(DOUT, tri_);
   DOUT << ": ";
 
-  // Check if it is necessary to propagate "isDead" property before intervals
-  // are joined.
+  // Check if it is necessary to propagate "isDead" property.
   MachineOperand *mopd = CopyMI->findRegisterDefOperand(DstReg, false);
   bool isDead = mopd->isDead();
-  bool isShorten = false;
-  unsigned SrcStart = 0, RemoveStart = 0;
-  unsigned SrcEnd = 0, RemoveEnd = 0;
-  if (isDead) {
-    unsigned CopyIdx = li_->getInstructionIndex(CopyMI);
-    LiveInterval::iterator SrcLR =
-      SrcInt.FindLiveRangeContaining(li_->getUseIndex(CopyIdx));
-    RemoveStart = SrcStart = SrcLR->start;
-    RemoveEnd   = SrcEnd   = SrcLR->end;
-    if (SrcEnd > li_->getDefIndex(CopyIdx)) {
-      // If there are other uses of SrcReg beyond the copy, there is nothing to do.
-      isDead = false;
-    } else {
-      unsigned LastUseIdx;
-      MachineOperand *LastUse =
-        lastRegisterUse(SrcStart, CopyIdx, SrcReg, LastUseIdx);
-      if (LastUse) {
-        // There are uses before the copy, just shorten the live range to the end
-        // of last use.
-        LastUse->setIsKill();
-        isDead = false;
-        isShorten = true;
-        RemoveStart = li_->getDefIndex(LastUseIdx);
-      } else {
-        // This live range is truly dead. Remove it.
-        MachineInstr *SrcMI = li_->getInstructionFromIndex(SrcStart);
-        if (SrcMI && SrcMI->modifiesRegister(SrcReg, tri_))
-          // A dead def should have a single cycle interval.
-          ++RemoveStart;
-      }
-    }
-  }
 
   // We need to be careful about coalescing a source physical register with a
   // 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) && !isExtSubReg) {
+  if (!isDead && (SrcIsPhys || DstIsPhys) && !isExtSubReg) {
     LiveInterval &JoinVInt = SrcIsPhys ? DstInt : SrcInt;
     unsigned JoinVReg = SrcIsPhys ? DstReg : SrcReg;
     unsigned JoinPReg = SrcIsPhys ? SrcReg : DstReg;
@@ -708,31 +790,7 @@
   // always canonicalizes DstInt to be it.  The output "SrcInt" will not have
   // been modified, so we can use this information below to update aliases.
   bool Swapped = false;
-  if (JoinIntervals(DstInt, SrcInt, Swapped)) {
-    if (isDead) {
-      // Result of the copy is dead. Propagate this property.
-      if (SrcStart == 0) {
-        assert(TargetRegisterInfo::isPhysicalRegister(SrcReg) &&
-               "Live-in must be a physical register!");
-        // Live-in to the function but dead. Remove it from entry live-in set.
-        // JoinIntervals may end up swapping the two intervals.
-        mf_->begin()->removeLiveIn(SrcReg);
-      } else {
-        MachineInstr *SrcMI = li_->getInstructionFromIndex(SrcStart);
-        if (SrcMI) {
-          int DeadIdx = SrcMI->findRegisterDefOperandIdx(SrcReg, false, tri_);
-          if (DeadIdx != -1)
-            SrcMI->getOperand(DeadIdx).setIsDead();
-        }
-      }
-    }
-
-    if (isShorten || isDead) {
-      // Shorten the destination live interval.
-      if (Swapped)
-        SrcInt.removeRange(RemoveStart, RemoveEnd, true);
-    }
-  } else {
+  if (!JoinIntervals(DstInt, SrcInt, Swapped)) {
     // Coalescing failed.
     
     // If we can eliminate the copy without merging the live ranges, do so now.
@@ -1566,6 +1624,14 @@
     // Delete all coalesced copies.
     for (SmallPtrSet<MachineInstr*,32>::iterator I = JoinedCopies.begin(),
            E = JoinedCopies.end(); I != E; ++I) {
+      MachineInstr *CopyMI = *I;
+      unsigned SrcReg, DstReg;
+      tii_->isMoveInstr(*CopyMI, SrcReg, DstReg);
+      if (CopyMI->registerDefIsDead(DstReg)) {
+        LiveInterval &li = li_->getInterval(DstReg);
+        ShortenDeadCopySrcLiveRange(li, CopyMI);
+        ShortenDeadCopyLiveRange(li, CopyMI);
+      }
       li_->RemoveMachineInstrFromMaps(*I);
       (*I)->eraseFromParent();
       ++numPeep;
@@ -1584,12 +1650,15 @@
       // if the move will be an identity move delete it
       unsigned srcReg, dstReg;
       if (tii_->isMoveInstr(*mii, srcReg, dstReg) && srcReg == dstReg) {
-        // remove from def list
-        LiveInterval &RegInt = li_->getOrCreateInterval(srcReg);
-        // If def of this move instruction is dead, remove its live range from
-        // the dstination register's live interval.
-        if (mii->registerDefIsDead(dstReg))
-          ShortenDeadCopyLiveRange(RegInt, mii);
+        if (li_->hasInterval(srcReg)) {
+          LiveInterval &RegInt = li_->getInterval(srcReg);
+          // If def of this move instruction is dead, remove its live range
+          // from the dstination register's live interval.
+          if (mii->registerDefIsDead(dstReg)) {
+            ShortenDeadCopySrcLiveRange(RegInt, mii);
+            ShortenDeadCopyLiveRange(RegInt, mii);
+          }
+        }
         li_->RemoveMachineInstrFromMaps(mii);
         mii = mbbi->erase(mii);
         ++numPeep;

Modified: llvm/trunk/lib/CodeGen/SimpleRegisterCoalescing.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SimpleRegisterCoalescing.h?rev=48490&r1=48489&r2=48490&view=diff

==============================================================================
--- llvm/trunk/lib/CodeGen/SimpleRegisterCoalescing.h (original)
+++ llvm/trunk/lib/CodeGen/SimpleRegisterCoalescing.h Tue Mar 18 03:26:47 2008
@@ -205,11 +205,15 @@
     /// due to live range lengthening as the result of coalescing.
     void RemoveUnnecessaryKills(unsigned Reg, LiveInterval &LI);
 
+    /// ShortenDeadCopyLiveRange - Shorten a live range defined by a dead copy.
+    ///
+    void ShortenDeadCopyLiveRange(LiveInterval &li, MachineInstr *CopyMI);
+
     /// ShortenDeadCopyLiveRange - Shorten a live range as it's artificially
     /// extended by a dead copy. Mark the last use (if any) of the val# as kill
     /// as ends the live range there. If there isn't another use, then this
     /// live range is dead.
-    void ShortenDeadCopyLiveRange(LiveInterval &li, MachineInstr *CopyMI);
+    void ShortenDeadCopySrcLiveRange(LiveInterval &li, MachineInstr *CopyMI);
 
     /// lastRegisterUse - Returns the last use of the specific register between
     /// cycles Start and End or NULL if there are no uses.

Added: llvm/trunk/test/CodeGen/PowerPC/2008-03-17-RegScavengerCrash.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/PowerPC/2008-03-17-RegScavengerCrash.ll?rev=48490&view=auto

==============================================================================
--- llvm/trunk/test/CodeGen/PowerPC/2008-03-17-RegScavengerCrash.ll (added)
+++ llvm/trunk/test/CodeGen/PowerPC/2008-03-17-RegScavengerCrash.ll Tue Mar 18 03:26:47 2008
@@ -0,0 +1,31 @@
+; RUN: llvm-as < %s | llc -march=ppc32 -enable-ppc32-regscavenger
+
+	%struct._cpp_strbuf = type { i8*, i32, i32 }
+	%struct.cpp_string = type { i32, i8* }
+
+declare fastcc void @emit_numeric_escape(i32, i32, %struct._cpp_strbuf*, i32) nounwind 
+
+define i32 @cpp_interpret_string(i32 %pfile, %struct.cpp_string* %from, i32 %wide) nounwind  {
+entry:
+	%tmp61 = load i32* null, align 4		; <i32> [#uses=1]
+	%toBool = icmp eq i32 %wide, 0		; <i1> [#uses=2]
+	%iftmp.87.0 = select i1 %toBool, i32 %tmp61, i32 0		; <i32> [#uses=2]
+	%tmp69 = icmp ult i32 %iftmp.87.0, 33		; <i1> [#uses=1]
+	%min = select i1 %tmp69, i32 %iftmp.87.0, i32 32		; <i32> [#uses=1]
+	%tmp71 = icmp ugt i32 %min, 31		; <i1> [#uses=1]
+	br i1 %tmp71, label %bb79, label %bb75
+bb75:		; preds = %entry
+	ret i32 0
+bb79:		; preds = %entry
+	br i1 %toBool, label %bb103, label %bb94
+bb94:		; preds = %bb79
+	br i1 false, label %bb729, label %bb130.preheader
+bb103:		; preds = %bb79
+	ret i32 0
+bb130.preheader:		; preds = %bb94
+	%tmp134 = getelementptr %struct.cpp_string* %from, i32 0, i32 1		; <i8**> [#uses=0]
+	ret i32 0
+bb729:		; preds = %bb94
+	call fastcc void @emit_numeric_escape( i32 %pfile, i32 0, %struct._cpp_strbuf* null, i32 %wide ) nounwind 
+	ret i32 1
+}





More information about the llvm-commits mailing list