all but CAS working on x86
[oota-llvm.git] / lib / CodeGen / LiveIntervalAnalysis.cpp
index 49015a81a85a1e8de9dafc0bc7c5bba7562ccd96..00ba2e770b05acdc2f291f422b07713b89c5001f 100644 (file)
@@ -643,6 +643,16 @@ bool LiveIntervals::isReMaterializable(const LiveInterval &li,
   const TargetInstrDesc &TID = MI->getDesc();
   if (TID.isImplicitDef())
     return true;
+
+  int FrameIdx = 0;
+  if (tii_->isLoadFromStackSlot(MI, FrameIdx) &&
+      mf_->getFrameInfo()->isImmutableObjectIndex(FrameIdx))
+    // FIXME: Let target specific isReallyTriviallyReMaterializable determines
+    // this but remember this is not safe to fold into a two-address
+    // instruction.
+    // This is a load from fixed stack slot. It can be rematerialized.
+    return true;
+
   if (tii_->isTriviallyReMaterializable(MI)) {
     isLoad = TID.isSimpleLoad();
 
@@ -655,38 +665,14 @@ bool LiveIntervals::isReMaterializable(const LiveInterval &li,
         unsigned UseIdx = getInstructionIndex(UseMI);
         if (li.FindLiveRangeContaining(UseIdx)->valno != ValNo)
           continue;
-        if (!canFoldMemoryOperand(UseMI, li.reg) &&
-            !isValNoAvailableAt(ImpLi, MI, UseIdx))
+        if (!isValNoAvailableAt(ImpLi, MI, UseIdx))
           return false;
       }
     }
     return true;
   }
 
-  int FrameIdx = 0;
-  if (!tii_->isLoadFromStackSlot(MI, FrameIdx) ||
-      !mf_->getFrameInfo()->isImmutableObjectIndex(FrameIdx))
-    return false;
-
-  // 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;
-    if (VNI == ValNo)
-      continue;
-    unsigned DefIdx = VNI->def;
-    if (DefIdx == ~1U)
-      continue; // Dead val#.
-    MachineInstr *DefMI = (DefIdx == ~0u)
-      ? NULL : getInstructionFromIndex(DefIdx);
-    if (DefMI && DefMI->isRegReDefinedByTwoAddr(li.reg)) {
-      isLoad = false;
-      return false;
-    }
-  }
-  return true;
+  return false;
 }
 
 /// isReMaterializable - Returns true if every definition of MI of every
@@ -712,33 +698,22 @@ bool LiveIntervals::isReMaterializable(const LiveInterval &li, bool &isLoad) {
   return true;
 }
 
-/// tryFoldMemoryOperand - Attempts to fold either a spill / restore from
-/// slot / to reg or any rematerialized load into ith operand of specified
-/// 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 InstrIdx,
-                                         SmallVector<unsigned, 2> &Ops,
-                                         bool isSS, int Slot, unsigned Reg) {
-  unsigned MRInfo = 0;
+/// FilterFoldedOps - Filter out two-address use operands. Return
+/// true if it finds any issue with the operands that ought to prevent
+/// folding.
+static bool FilterFoldedOps(MachineInstr *MI,
+                            SmallVector<unsigned, 2> &Ops,
+                            unsigned &MRInfo,
+                            SmallVector<unsigned, 2> &FoldOps) {
   const TargetInstrDesc &TID = MI->getDesc();
-  // If it is an implicit def instruction, just delete it.
-  if (TID.isImplicitDef()) {
-    RemoveMachineInstrFromMaps(MI);
-    vrm.RemoveMachineInstrFromMaps(MI);
-    MI->eraseFromParent();
-    ++numFolds;
-    return true;
-  }
 
-  SmallVector<unsigned, 2> FoldOps;
+  MRInfo = 0;
   for (unsigned i = 0, e = Ops.size(); i != e; ++i) {
     unsigned OpIdx = Ops[i];
     MachineOperand &MO = MI->getOperand(OpIdx);
     // FIXME: fold subreg use.
     if (MO.getSubReg())
-      return false;
+      return true;
     if (MO.isDef())
       MRInfo |= (unsigned)VirtRegMap::isMod;
     else {
@@ -752,10 +727,46 @@ bool LiveIntervals::tryFoldMemoryOperand(MachineInstr* &MI,
     }
     FoldOps.push_back(OpIdx);
   }
+  return false;
+}
+                           
+
+/// tryFoldMemoryOperand - Attempts to fold either a spill / restore from
+/// slot / to reg or any rematerialized load into ith operand of specified
+/// 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 InstrIdx,
+                                         SmallVector<unsigned, 2> &Ops,
+                                         bool isSS, int Slot, unsigned Reg) {
+  const TargetInstrDesc &TID = MI->getDesc();
+  // If it is an implicit def instruction, just delete it.
+  if (TID.isImplicitDef()) {
+    RemoveMachineInstrFromMaps(MI);
+    vrm.RemoveMachineInstrFromMaps(MI);
+    MI->eraseFromParent();
+    ++numFolds;
+    return true;
+  }
+
+  // Filter the list of operand indexes that are to be folded. Abort if
+  // any operand will prevent folding.
+  unsigned MRInfo = 0;
+  SmallVector<unsigned, 2> FoldOps;
+  if (FilterFoldedOps(MI, Ops, MRInfo, FoldOps))
+    return false;
+
+  // Can't fold a load from fixed stack slot into a two address instruction.
+  if (isSS && DefMI && (MRInfo & VirtRegMap::isMod))
+    return false;
 
   MachineInstr *fmi = isSS ? tii_->foldMemoryOperand(*mf_, MI, FoldOps, Slot)
                            : tii_->foldMemoryOperand(*mf_, MI, FoldOps, DefMI);
   if (fmi) {
+    // Remember this instruction uses the spill slot.
+    if (isSS) vrm.addSpillSlotUse(Slot, fmi);
+
     // Attempt to fold the memory reference into the instruction. If
     // we can do this, we don't need to insert spill code.
     if (lv_)
@@ -780,33 +791,19 @@ bool LiveIntervals::tryFoldMemoryOperand(MachineInstr* &MI,
 /// canFoldMemoryOperand - Returns true if the specified load / store
 /// folding is possible.
 bool LiveIntervals::canFoldMemoryOperand(MachineInstr *MI,
-                                         SmallVector<unsigned, 2> &Ops) const {
+                                         SmallVector<unsigned, 2> &Ops,
+                                         bool ReMatLoad) const {
+  // Filter the list of operand indexes that are to be folded. Abort if
+  // any operand will prevent folding.
+  unsigned MRInfo = 0;
   SmallVector<unsigned, 2> FoldOps;
-  for (unsigned i = 0, e = Ops.size(); i != e; ++i) {
-    unsigned OpIdx = Ops[i];
-    // FIXME: fold subreg use.
-    if (MI->getOperand(OpIdx).getSubReg())
-      return false;
-    FoldOps.push_back(OpIdx);
-  }
+  if (FilterFoldedOps(MI, Ops, MRInfo, FoldOps))
+    return false;
 
-  return tii_->canFoldMemoryOperand(MI, FoldOps);
-}
+  // Can't fold a remat'ed load into a two address instruction.
+  if (ReMatLoad && (MRInfo & VirtRegMap::isMod))
+    return false;
 
-bool LiveIntervals::canFoldMemoryOperand(MachineInstr *MI, unsigned Reg) const {
-  SmallVector<unsigned, 2> FoldOps;
-  for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
-    MachineOperand& mop = MI->getOperand(i);
-    if (!mop.isRegister())
-      continue;
-    unsigned UseReg = mop.getReg();
-    if (UseReg != Reg) 
-      continue;
-    // FIXME: fold subreg use.
-    if (mop.getSubReg())
-      return false;
-    FoldOps.push_back(i);
-  }
   return tii_->canFoldMemoryOperand(MI, FoldOps);
 }
 
@@ -863,7 +860,7 @@ rewriteInstructionForSpills(const LiveInterval &li, const VNInfo *VNI,
                  const TargetRegisterClass* rc,
                  SmallVector<int, 4> &ReMatIds,
                  const MachineLoopInfo *loopInfo,
-                 unsigned &NewVReg, bool &HasDef, bool &HasUse,
+                 unsigned &NewVReg, unsigned ImpUse, bool &HasDef, bool &HasUse,
                  std::map<unsigned,unsigned> &MBBVRegsMap,
                  std::vector<LiveInterval*> &NewLIs) {
   bool CanFold = false;
@@ -894,7 +891,8 @@ rewriteInstructionForSpills(const LiveInterval &li, const VNInfo *VNI,
           // spill weight of the register interval.
           unsigned loopDepth = loopInfo->getLoopDepth(MI->getParent());
           LiveInterval &ImpLi = getInterval(ImpUse);
-          ImpLi.weight -= getSpillWeight(false, true, loopDepth);
+          ImpLi.weight -=
+            getSpillWeight(false, true, loopDepth) / ImpLi.getSize();
         }
         RemoveMachineInstrFromMaps(MI);
         vrm.RemoveMachineInstrFromMaps(MI);
@@ -956,7 +954,7 @@ rewriteInstructionForSpills(const LiveInterval &li, const VNInfo *VNI,
           goto RestartInstruction;
         }
       } else {
-        CanFold = canFoldMemoryOperand(MI, Ops);
+        CanFold = canFoldMemoryOperand(MI, Ops, DefIsReMat && isLoad);
       }
     } else
       CanFold = false;
@@ -982,16 +980,6 @@ rewriteInstructionForSpills(const LiveInterval &li, const VNInfo *VNI,
             
     if (CreatedNewVReg) {
       if (DefIsReMat) {
-        unsigned ImpUse = getReMatImplicitUse(li, ReMatDefMI);
-        if (ImpUse) {
-          // Re-matting an instruction with virtual register use. Add the
-          // register as an implicit use on the use MI and update the register
-          // interval's spill weight.
-          unsigned loopDepth = loopInfo->getLoopDepth(MI->getParent());
-          LiveInterval &ImpLi = getInterval(ImpUse);
-          ImpLi.weight += getSpillWeight(false, true, loopDepth);
-          MI->addOperand(MachineOperand::CreateReg(ImpUse, false, true));
-        }
         vrm.setVirtIsReMaterialized(NewVReg, ReMatDefMI/*, CanDelete*/);
         if (ReMatIds[VNI->id] == VirtRegMap::MAX_STACK_SLOT) {
           // Each valnum may have its own remat id.
@@ -1016,6 +1004,11 @@ rewriteInstructionForSpills(const LiveInterval &li, const VNInfo *VNI,
       vrm.assignVirt2StackSlot(NewVReg, Slot);
     }
 
+    // Re-matting an instruction with virtual register use. Add the
+    // register as an implicit use on the use MI.
+    if (DefIsReMat && ImpUse)
+      MI->addOperand(MachineOperand::CreateReg(ImpUse, false, true));
+
     // create a new register interval for this spill / remat.
     LiveInterval &nI = getOrCreateInterval(NewVReg);
     if (CreatedNewVReg) {
@@ -1129,6 +1122,7 @@ rewriteInstructionsForSpills(const LiveInterval &li, bool TrySplit,
   }
   std::sort(RewriteMIs.begin(), RewriteMIs.end(), RewriteInfoCompare());
 
+  unsigned ImpUse = DefIsReMat ? getReMatImplicitUse(li, ReMatDefMI) : 0;
   // Now rewrite the defs and uses.
   for (unsigned i = 0, e = RewriteMIs.size(); i != e; ) {
     RewriteInfo &rwi = RewriteMIs[i];
@@ -1139,13 +1133,26 @@ rewriteInstructionsForSpills(const LiveInterval &li, bool TrySplit,
     MachineInstr *MI = rwi.MI;
     // If MI def and/or use the same register multiple times, then there
     // are multiple entries.
+    unsigned NumUses = MIHasUse;
     while (i != e && RewriteMIs[i].MI == MI) {
       assert(RewriteMIs[i].Index == index);
-      MIHasUse |= RewriteMIs[i].HasUse;
+      bool isUse = RewriteMIs[i].HasUse;
+      if (isUse) ++NumUses;
+      MIHasUse |= isUse;
       MIHasDef |= RewriteMIs[i].HasDef;
       ++i;
     }
     MachineBasicBlock *MBB = MI->getParent();
+
+    if (ImpUse && MI != ReMatDefMI) {
+      // Re-matting an instruction with virtual register use. Update the
+      // register interval's spill weight.
+      unsigned loopDepth = loopInfo->getLoopDepth(MI->getParent());
+      LiveInterval &ImpLi = getInterval(ImpUse);
+      ImpLi.weight +=
+        getSpillWeight(false, true, loopDepth) * NumUses / ImpLi.getSize();
+    }
+
     unsigned MBBId = MBB->getNumber();
     unsigned ThisVReg = 0;
     if (TrySplit) {
@@ -1185,7 +1192,7 @@ rewriteInstructionsForSpills(const LiveInterval &li, bool TrySplit,
                                 index, end, MI, ReMatOrigDefMI, ReMatDefMI,
                                 Slot, LdSlot, isLoad, isLoadSS, DefIsReMat,
                                 CanDelete, vrm, rc, ReMatIds, loopInfo, NewVReg,
-                                HasDef, HasUse, MBBVRegsMap, NewLIs);
+                                ImpUse, HasDef, HasUse, MBBVRegsMap, NewLIs);
     if (!HasDef && !HasUse)
       continue;
 
@@ -1570,7 +1577,9 @@ addIntervalsForSpills(const LiveInterval &li,
             // interval's spill weight.
             unsigned loopDepth = loopInfo->getLoopDepth(MI->getParent());
             LiveInterval &ImpLi = getInterval(ImpUse);
-            ImpLi.weight += getSpillWeight(false, true, loopDepth);
+            ImpLi.weight +=
+              getSpillWeight(false, true, loopDepth) / ImpLi.getSize();
+
             MI->addOperand(MachineOperand::CreateReg(ImpUse, false, true));
           }
         }