Fix for PR1831: if all defs of an interval are re-materializable, then it's a preferred spill candiate.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@44644 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/llvm/CodeGen/LiveIntervalAnalysis.h b/include/llvm/CodeGen/LiveIntervalAnalysis.h
index 19865e5..83d8d1d 100644
--- a/include/llvm/CodeGen/LiveIntervalAnalysis.h
+++ b/include/llvm/CodeGen/LiveIntervalAnalysis.h
@@ -233,6 +233,11 @@
     addIntervalsForSpills(const LiveInterval& i,
                           const LoopInfo *loopInfo, 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);
+
   private:      
     /// computeIntervals - Compute live intervals.
     void computeIntervals();
@@ -265,9 +270,10 @@
                               LiveInterval &interval, bool isAlias = false);
 
     /// isReMaterializable - Returns true if the definition MI of the specified
-    /// val# of the specified interval is re-materializable.
+    /// val# of the specified interval is re-materializable. Also returns true
+    /// by reference if the def is a load.
     bool isReMaterializable(const LiveInterval &li, const VNInfo *ValNo,
-                            MachineInstr *MI);
+                            MachineInstr *MI, bool &isLoad);
 
     /// tryFoldMemoryOperand - Attempts to fold either a spill / restore from
     /// slot / to reg or any rematerialized load into ith operand of specified
diff --git a/lib/CodeGen/LiveIntervalAnalysis.cpp b/lib/CodeGen/LiveIntervalAnalysis.cpp
index a9e6948..9262734 100644
--- a/lib/CodeGen/LiveIntervalAnalysis.cpp
+++ b/lib/CodeGen/LiveIntervalAnalysis.cpp
@@ -607,12 +607,16 @@
 /// isReMaterializable - Returns true if the definition MI of the specified
 /// val# of the specified interval is re-materializable.
 bool LiveIntervals::isReMaterializable(const LiveInterval &li,
-                                       const VNInfo *ValNo, MachineInstr *MI) {
+                                       const VNInfo *ValNo, MachineInstr *MI,
+                                       bool &isLoad) {
   if (DisableReMat)
     return false;
 
-  if (tii_->isTriviallyReMaterializable(MI))
+  isLoad = false;
+  if (tii_->isTriviallyReMaterializable(MI)) {
+    isLoad = MI->getInstrDescriptor()->Flags & M_LOAD_FLAG;
     return true;
+  }
 
   int FrameIdx = 0;
   if (!tii_->isLoadFromStackSlot(MI, FrameIdx) ||
@@ -621,6 +625,7 @@
 
   // This is a load from fixed stack slot. It can be rematerialized unless it's
   // re-defined by a two-address instruction.
+  isLoad = true;
   for (LiveInterval::const_vni_iterator i = li.vni_begin(), e = li.vni_end();
        i != e; ++i) {
     const VNInfo *VNI = *i;
@@ -631,8 +636,32 @@
       continue; // Dead val#.
     MachineInstr *DefMI = (DefIdx == ~0u)
       ? NULL : getInstructionFromIndex(DefIdx);
-    if (DefMI && DefMI->isRegReDefinedByTwoAddr(li.reg))
+    if (DefMI && DefMI->isRegReDefinedByTwoAddr(li.reg)) {
+      isLoad = false;
       return false;
+    }
+  }
+  return true;
+}
+
+/// isReMaterializable - Returns true if every definition of MI of every
+/// val# of the specified interval is re-materializable.
+bool LiveIntervals::isReMaterializable(const LiveInterval &li, bool &isLoad) {
+  isLoad = false;
+  for (LiveInterval::const_vni_iterator i = li.vni_begin(), e = li.vni_end();
+       i != e; ++i) {
+    const VNInfo *VNI = *i;
+    unsigned DefIdx = VNI->def;
+    if (DefIdx == ~1U)
+      continue; // Dead val#.
+    // Is the def for the val# rematerializable?
+    if (DefIdx == ~0u)
+      return false;
+    MachineInstr *ReMatDefMI = getInstructionFromIndex(DefIdx);
+    bool DefIsLoad = false;
+    if (!ReMatDefMI || !isReMaterializable(li, VNI, ReMatDefMI, DefIsLoad))
+      return false;
+    isLoad |= DefIsLoad;
   }
   return true;
 }
@@ -1225,7 +1254,8 @@
     // Is the def for the val# rematerializable?
     MachineInstr *ReMatDefMI = (DefIdx == ~0u)
       ? 0 : getInstructionFromIndex(DefIdx);
-    if (ReMatDefMI && isReMaterializable(li, VNI, ReMatDefMI)) {
+    bool dummy;
+    if (ReMatDefMI && isReMaterializable(li, VNI, ReMatDefMI, dummy)) {
       // Remember how to remat the def of this val#.
       ReMatOrigDefs[VN] = ReMatDefMI;
       // Original def may be modified so we have to make a copy here. vrm must
diff --git a/lib/CodeGen/SimpleRegisterCoalescing.cpp b/lib/CodeGen/SimpleRegisterCoalescing.cpp
index 3d2669b..6eec5ab 100644
--- a/lib/CodeGen/SimpleRegisterCoalescing.cpp
+++ b/lib/CodeGen/SimpleRegisterCoalescing.cpp
@@ -1485,6 +1485,20 @@
       // it and hope it will be easier to allocate for this li.
       if (isZeroLengthInterval(&LI))
         LI.weight = HUGE_VALF;
+      else {
+        bool isLoad = false;
+        if (li_->isReMaterializable(LI, isLoad)) {
+          // If all of the definitions of the interval are re-materializable,
+          // it is a preferred candidate for spilling. If non of the defs are
+          // loads, then it's potentially very cheap to re-materialize.
+          // FIXME: this gets much more complicated once we support non-trivial
+          // re-materialization.
+          if (isLoad)
+            LI.weight *= 0.9F;
+          else
+            LI.weight *= 0.5F;
+        }
+      }
 
       // Slightly prefer live interval that has been assigned a preferred reg.
       if (LI.preference)
diff --git a/test/CodeGen/ARM/lsr-code-insertion.ll b/test/CodeGen/ARM/lsr-code-insertion.ll
index 507c891..3881e91 100644
--- a/test/CodeGen/ARM/lsr-code-insertion.ll
+++ b/test/CodeGen/ARM/lsr-code-insertion.ll
@@ -1,4 +1,5 @@
-; RUN: llvm-as < %s | llc -stats |& grep {40.*Number of machine instrs printed}
+; RUN: llvm-as < %s | llc -stats |& grep {39.*Number of machine instrs printed}
+; RUN: llvm-as < %s | llc -stats |& grep {.*Number of re-materialization}
 ; This test really wants to check that the resultant "cond_true" block only 
 ; has a single store in it, and that cond_true55 only has code to materialize 
 ; the constant and do a store.  We do *not* want something like this:
@@ -7,7 +8,6 @@
 ;        add r8, r0, r6
 ;        str r10, [r8, #+4]
 ;
-; XFAIL: *
 target triple = "arm-apple-darwin8"
 
 define void @foo(i32* %mc, i32* %mpp, i32* %ip, i32* %dpp, i32* %tpmm, i32 %M, i32* %tpim, i32* %tpdm, i32* %bp, i32* %ms, i32 %xmb) {