The coalescer does not coalesce a virtual register to a physical register if any...
authorEvan Cheng <evan.cheng@apple.com>
Wed, 7 Jan 2009 02:08:57 +0000 (02:08 +0000)
committerEvan Cheng <evan.cheng@apple.com>
Wed, 7 Jan 2009 02:08:57 +0000 (02:08 +0000)
v1024 = EDI  // not killed
      =
      = EDI

One possible solution is for the coalescer to examine the sub-register live intervals in the same manner as the physical register. Another possibility is to examine defs and uses (when needed) of sub-registers. Both solutions are too expensive. For now, look for "short virtual intervals" and scan instructions to look for conflict instead.

This is a small win on x86-64. e.g. It shaves 403.gcc by ~80 instructions.

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

include/llvm/CodeGen/LiveIntervalAnalysis.h
lib/CodeGen/LiveIntervalAnalysis.cpp
lib/CodeGen/SimpleRegisterCoalescing.cpp
test/CodeGen/X86/phys_subreg_coalesce.ll [new file with mode: 0644]

index 9dd5526149227153b872545d731f22fc13e0d7ec..52ee8852c67e795a0a6f348409945ce461b917de 100644 (file)
@@ -24,6 +24,7 @@
 #include "llvm/CodeGen/LiveInterval.h"
 #include "llvm/ADT/BitVector.h"
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/Support/Allocator.h"
 #include <cmath>
@@ -256,6 +257,12 @@ namespace llvm {
     bool conflictsWithPhysRegDef(const LiveInterval &li, VirtRegMap &vrm,
                                  unsigned reg);
 
+    /// conflictsWithPhysRegRef - Similar to conflictsWithPhysRegRef except
+    /// it can check use as well.
+    bool conflictsWithPhysRegRef(LiveInterval &li, unsigned Reg,
+                                 bool CheckUse,
+                                 SmallPtrSet<MachineInstr*,32> &JoinedCopies);
+
     /// findLiveInMBBs - Given a live range, if the value of the range
     /// is live in any MBB returns true as well as the list of basic blocks
     /// in which the value is live.
index 1900c1a4d7d79410e364206901c467d2317d6c47..22595895627b62ec5b81110eb31870f24cab235a 100644 (file)
@@ -323,6 +323,47 @@ bool LiveIntervals::conflictsWithPhysRegDef(const LiveInterval &li,
   return false;
 }
 
+/// conflictsWithPhysRegRef - Similar to conflictsWithPhysRegRef except
+/// it can check use as well.
+bool LiveIntervals::conflictsWithPhysRegRef(LiveInterval &li,
+                                            unsigned Reg, bool CheckUse,
+                                  SmallPtrSet<MachineInstr*,32> &JoinedCopies) {
+  for (LiveInterval::Ranges::const_iterator
+         I = li.ranges.begin(), E = li.ranges.end(); I != E; ++I) {
+    for (unsigned index = getBaseIndex(I->start),
+           end = getBaseIndex(I->end-1) + InstrSlots::NUM; index != end;
+         index += InstrSlots::NUM) {
+      // Skip deleted instructions.
+      MachineInstr *MI = 0;
+      while (index != end) {
+        MI = getInstructionFromIndex(index);
+        if (MI)
+          break;
+        index += InstrSlots::NUM;
+      }
+      if (index == end) break;
+
+      if (JoinedCopies.count(MI))
+        continue;
+      for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
+        MachineOperand& MO = MI->getOperand(i);
+        if (!MO.isReg())
+          continue;
+        if (MO.isUse() && !CheckUse)
+          continue;
+        unsigned PhysReg = MO.getReg();
+        if (PhysReg == 0 || TargetRegisterInfo::isVirtualRegister(PhysReg))
+          continue;
+        if (tri_->isSubRegister(Reg, PhysReg))
+          return true;
+      }
+    }
+  }
+
+  return false;
+}
+
+
 void LiveIntervals::printRegName(unsigned reg) const {
   if (TargetRegisterInfo::isPhysicalRegister(reg))
     cerr << tri_->getName(reg);
@@ -794,10 +835,15 @@ unsigned LiveIntervals::getVNInfoSourceReg(const VNInfo *VNI) const {
   if (!VNI->copy)
     return 0;
 
-  if (VNI->copy->getOpcode() == TargetInstrInfo::EXTRACT_SUBREG)
-    return VNI->copy->getOperand(1).getReg();
-  if (VNI->copy->getOpcode() == TargetInstrInfo::INSERT_SUBREG)
+  if (VNI->copy->getOpcode() == TargetInstrInfo::EXTRACT_SUBREG) {
+    // If it's extracting out of a physical register, return the sub-register.
+    unsigned Reg = VNI->copy->getOperand(1).getReg();
+    if (TargetRegisterInfo::isPhysicalRegister(Reg))
+      Reg = tri_->getSubReg(Reg, VNI->copy->getOperand(2).getImm());
+    return Reg;
+  } else if (VNI->copy->getOpcode() == TargetInstrInfo::INSERT_SUBREG)
     return VNI->copy->getOperand(2).getReg();
+
   unsigned SrcReg, DstReg;
   if (tii_->isMoveInstr(*VNI->copy, SrcReg, DstReg))
     return SrcReg;
index cfc77eef046157c9ba0311d896c646f3344d05a6..7f36ef5bcef184405822599ea0dfe6a400475a61 100644 (file)
@@ -1276,8 +1276,8 @@ bool SimpleRegisterCoalescing::JoinCopy(CopyRec &TheCopy, bool &Again) {
       // preference.
       unsigned Length = li_->getApproximateInstructionCount(JoinVInt);
       if (Length > Threshold &&
-          (((float)std::distance(mri_->use_begin(JoinVReg),
-                              mri_->use_end()) / Length) < (1.0 / Threshold))) {
+          (((float)std::distance(mri_->use_begin(JoinVReg), mri_->use_end())
+            / Length) < (1.0 / Threshold))) {
         JoinVInt.preference = JoinPReg;
         ++numAborts;
         DOUT << "\tMay tie down a physical register, abort!\n";
@@ -1334,7 +1334,7 @@ bool SimpleRegisterCoalescing::JoinCopy(CopyRec &TheCopy, bool &Again) {
   assert(TargetRegisterInfo::isVirtualRegister(SrcReg) &&
          "LiveInterval::join didn't work right!");
                                
-  // If we're about to merge live ranges into a physical register live range,
+  // If we're about to merge live ranges into a physical register live interval,
   // we have to update any aliased register's live ranges to indicate that they
   // have clobbered values for this range.
   if (TargetRegisterInfo::isPhysicalRegister(DstReg)) {
@@ -1712,8 +1712,9 @@ bool SimpleRegisterCoalescing::SimpleJoin(LiveInterval &LHS, LiveInterval &RHS){
 /// physreg, this method always canonicalizes LHS to be it.  The output
 /// "RHS" will not have been modified, so we can use this information
 /// below to update aliases.
-bool SimpleRegisterCoalescing::JoinIntervals(LiveInterval &LHS,
-                                             LiveInterval &RHS, bool &Swapped) {
+bool
+SimpleRegisterCoalescing::JoinIntervals(LiveInterval &LHS, LiveInterval &RHS,
+                                        bool &Swapped) {
   // Compute the final value assignment, assuming that the live ranges can be
   // coalesced.
   SmallVector<int, 16> LHSValNoAssignments;
@@ -1721,26 +1722,43 @@ bool SimpleRegisterCoalescing::JoinIntervals(LiveInterval &LHS,
   DenseMap<VNInfo*, VNInfo*> LHSValsDefinedFromRHS;
   DenseMap<VNInfo*, VNInfo*> RHSValsDefinedFromLHS;
   SmallVector<VNInfo*, 16> NewVNInfo;
-                          
+
   // If a live interval is a physical register, conservatively check if any
   // of its sub-registers is overlapping the live interval of the virtual
   // register. If so, do not coalesce.
   if (TargetRegisterInfo::isPhysicalRegister(LHS.reg) &&
       *tri_->getSubRegisters(LHS.reg)) {
-    for (const unsigned* SR = tri_->getSubRegisters(LHS.reg); *SR; ++SR)
-      if (li_->hasInterval(*SR) && RHS.overlaps(li_->getInterval(*SR))) {
-        DOUT << "Interfere with sub-register ";
-        DEBUG(li_->getInterval(*SR).print(DOUT, tri_));
+    // If it's coalescing a virtual register to a physical register, estimate
+    // its live interval length. This is the *cost* of scanning an entire live
+    // interval. If the cost is low, we'll do an exhaustive check instead.
+    if (RHS.containsOneValue() &&
+        li_->getApproximateInstructionCount(RHS) <= 10) {
+      // Perform a more exhaustive check for some common cases.
+      if (li_->conflictsWithPhysRegRef(RHS, LHS.reg, true, JoinedCopies))
         return false;
-      }
+    } else {
+      for (const unsigned* SR = tri_->getSubRegisters(LHS.reg); *SR; ++SR)
+        if (li_->hasInterval(*SR) && RHS.overlaps(li_->getInterval(*SR))) {
+          DOUT << "Interfere with sub-register ";
+          DEBUG(li_->getInterval(*SR).print(DOUT, tri_));
+          return false;
+        }
+    }
   } else if (TargetRegisterInfo::isPhysicalRegister(RHS.reg) &&
              *tri_->getSubRegisters(RHS.reg)) {
-    for (const unsigned* SR = tri_->getSubRegisters(RHS.reg); *SR; ++SR)
-      if (li_->hasInterval(*SR) && LHS.overlaps(li_->getInterval(*SR))) {
-        DOUT << "Interfere with sub-register ";
-        DEBUG(li_->getInterval(*SR).print(DOUT, tri_));
+    if (LHS.containsOneValue() &&
+        li_->getApproximateInstructionCount(LHS) <= 10) {
+      // Perform a more exhaustive check for some common cases.
+      if (li_->conflictsWithPhysRegRef(LHS, RHS.reg, false, JoinedCopies))
         return false;
-      }
+    } else {
+      for (const unsigned* SR = tri_->getSubRegisters(RHS.reg); *SR; ++SR)
+        if (li_->hasInterval(*SR) && LHS.overlaps(li_->getInterval(*SR))) {
+          DOUT << "Interfere with sub-register ";
+          DEBUG(li_->getInterval(*SR).print(DOUT, tri_));
+          return false;
+        }
+    }
   }
                           
   // Compute ultimate value numbers for the LHS and RHS values.
@@ -1755,7 +1773,7 @@ bool SimpleRegisterCoalescing::JoinIntervals(LiveInterval &LHS,
     VNInfo *RHSValNoInfo = NULL;
     VNInfo *RHSValNoInfo0 = RHS.getValNumInfo(0);
     unsigned RHSSrcReg = li_->getVNInfoSourceReg(RHSValNoInfo0);
-    if ((RHSSrcReg == 0 || RHSSrcReg != LHS.reg)) {
+    if (RHSSrcReg == 0 || RHSSrcReg != LHS.reg) {
       // If RHS is not defined as a copy from the LHS, we can use simpler and
       // faster checks to see if the live ranges are coalescable.  This joiner
       // can't swap the LHS/RHS intervals though.
diff --git a/test/CodeGen/X86/phys_subreg_coalesce.ll b/test/CodeGen/X86/phys_subreg_coalesce.ll
new file mode 100644 (file)
index 0000000..789a4ba
--- /dev/null
@@ -0,0 +1,24 @@
+; RUN: llvm-as < %s | llc -mtriple=x86_64-apple-darwin9 -mattr=+sse2 | not grep movl
+
+       %struct.dpoint = type { double, double }
+
+define %struct.dpoint @midpoint(i64 %p1.0, i64 %p2.0) nounwind readnone {
+entry:
+       %0 = trunc i64 %p1.0 to i32             ; <i32> [#uses=1]
+       %1 = sitofp i32 %0 to double            ; <double> [#uses=1]
+       %2 = trunc i64 %p2.0 to i32             ; <i32> [#uses=1]
+       %3 = sitofp i32 %2 to double            ; <double> [#uses=1]
+       %4 = add double %1, %3          ; <double> [#uses=1]
+       %5 = mul double %4, 5.000000e-01                ; <double> [#uses=1]
+       %6 = lshr i64 %p1.0, 32         ; <i64> [#uses=1]
+       %7 = trunc i64 %6 to i32                ; <i32> [#uses=1]
+       %8 = sitofp i32 %7 to double            ; <double> [#uses=1]
+       %9 = lshr i64 %p2.0, 32         ; <i64> [#uses=1]
+       %10 = trunc i64 %9 to i32               ; <i32> [#uses=1]
+       %11 = sitofp i32 %10 to double          ; <double> [#uses=1]
+       %12 = add double %8, %11                ; <double> [#uses=1]
+       %13 = mul double %12, 5.000000e-01              ; <double> [#uses=1]
+       %mrv3 = insertvalue %struct.dpoint undef, double %5, 0          ; <%struct.dpoint> [#uses=1]
+       %mrv4 = insertvalue %struct.dpoint %mrv3, double %13, 1         ; <%struct.dpoint> [#uses=1]
+       ret %struct.dpoint %mrv4
+}