Skip to content
LiveIntervalAnalysis.cpp 48.2 KiB
Newer Older
      std::map<unsigned, std::vector<SRInfo> >::iterator SII =
      if (SII != SpillIdxes.end() &&
          SII->second.back().vreg == NewVReg &&
          (int)index > SII->second.back().index)
        // Use(s) following the last def, it's not safe to fold the spill.
        SII->second.back().canFold = false;
      std::map<unsigned, std::vector<SRInfo> >::iterator RII =
      if (RII != RestoreIdxes.end() && RII->second.back().vreg == NewVReg)
        // If we are splitting live intervals, only fold if it's the first
        // use and there isn't another use later in the MBB.
      else if (IsNew) {
        // Only need a reload if there isn't an earlier def / use.
        if (RII == RestoreIdxes.end()) {
          std::vector<SRInfo> Infos;
          Infos.push_back(SRInfo(index, NewVReg, true));
          RestoreIdxes.insert(std::make_pair(MBBId, Infos));
        } else {
          RII->second.push_back(SRInfo(index, NewVReg, true));
        }
Evan Cheng's avatar
Evan Cheng committed
    }

    // Update spill weight.
    unsigned loopDepth = loopInfo->getLoopDepth(MBB->getBasicBlock());
    nI.weight += getSpillWeight(HasDef, HasUse, loopDepth);
bool LiveIntervals::alsoFoldARestore(int Id, int index, unsigned vr,
                        BitVector &RestoreMBBs,
                        std::map<unsigned,std::vector<SRInfo> > &RestoreIdxes) {
  if (!RestoreMBBs[Id])
    return false;
  std::vector<SRInfo> &Restores = RestoreIdxes[Id];
  for (unsigned i = 0, e = Restores.size(); i != e; ++i)
    if (Restores[i].index == index &&
        Restores[i].vreg == vr &&
        Restores[i].canFold)
      return true;
  return false;
}

void LiveIntervals::eraseRestoreInfo(int Id, int index, unsigned vr,
                        BitVector &RestoreMBBs,
                        std::map<unsigned,std::vector<SRInfo> > &RestoreIdxes) {
  if (!RestoreMBBs[Id])
    return;
  std::vector<SRInfo> &Restores = RestoreIdxes[Id];
  for (unsigned i = 0, e = Restores.size(); i != e; ++i)
    if (Restores[i].index == index && Restores[i].vreg)
      Restores[i].index = -1;
}
Evan Cheng's avatar
Evan Cheng committed
std::vector<LiveInterval*> LiveIntervals::
Evan Cheng's avatar
Evan Cheng committed
addIntervalsForSpills(const LiveInterval &li,
                      const LoopInfo *loopInfo, VirtRegMap &vrm) {
Evan Cheng's avatar
Evan Cheng committed
  // Since this is called after the analysis is done we don't know if
  // LiveVariables is available
  lv_ = getAnalysisToUpdate<LiveVariables>();

  assert(li.weight != HUGE_VALF &&
         "attempt to spill already spilled interval!");

  DOUT << "\t\t\t\tadding intervals for spills for interval: ";
  li.print(DOUT, mri_);
  DOUT << '\n';

Evan Cheng's avatar
Evan Cheng committed
  // Each bit specify whether it a spill is required in the MBB.
  BitVector SpillMBBs(mf_->getNumBlockIDs());
  std::map<unsigned, std::vector<SRInfo> > SpillIdxes;
  BitVector RestoreMBBs(mf_->getNumBlockIDs());
  std::map<unsigned, std::vector<SRInfo> > RestoreIdxes;
  std::map<unsigned,unsigned> MBBVRegsMap;
Evan Cheng's avatar
Evan Cheng committed
  std::vector<LiveInterval*> NewLIs;
  SSARegMap *RegMap = mf_->getSSARegMap();
  const TargetRegisterClass* rc = RegMap->getRegClass(li.reg);

  unsigned NumValNums = li.getNumValNums();
  SmallVector<MachineInstr*, 4> ReMatDefs;
  ReMatDefs.resize(NumValNums, NULL);
  SmallVector<MachineInstr*, 4> ReMatOrigDefs;
  ReMatOrigDefs.resize(NumValNums, NULL);
  SmallVector<int, 4> ReMatIds;
  ReMatIds.resize(NumValNums, VirtRegMap::MAX_STACK_SLOT);
  BitVector ReMatDelete(NumValNums);
  unsigned Slot = VirtRegMap::MAX_STACK_SLOT;

Evan Cheng's avatar
Evan Cheng committed
  // Spilling a split live interval. It cannot be split any further. Also,
  // it's also guaranteed to be a single val# / range interval.
  if (vrm.getPreSplitReg(li.reg)) {
    vrm.setIsSplitFromReg(li.reg, 0);
    bool DefIsReMat = vrm.isReMaterialized(li.reg);
    Slot = vrm.getStackSlot(li.reg);
    assert(Slot != VirtRegMap::MAX_STACK_SLOT);
    MachineInstr *ReMatDefMI = DefIsReMat ?
      vrm.getReMaterializedMI(li.reg) : NULL;
    int LdSlot = 0;
    bool isLoadSS = DefIsReMat && tii_->isLoadFromStackSlot(ReMatDefMI, LdSlot);
    bool isLoad = isLoadSS ||
      (DefIsReMat && (ReMatDefMI->getInstrDescriptor()->Flags & M_LOAD_FLAG));
    bool IsFirstRange = true;
    for (LiveInterval::Ranges::const_iterator
           I = li.ranges.begin(), E = li.ranges.end(); I != E; ++I) {
      // If this is a split live interval with multiple ranges, it means there
      // are two-address instructions that re-defined the value. Only the
      // first def can be rematerialized!
      if (IsFirstRange) {
        rewriteInstructionsForSpills(li, false, I, NULL, ReMatDefMI,
                             Slot, LdSlot, isLoad, isLoadSS, DefIsReMat,
                             false, vrm, RegMap, rc, ReMatIds, loopInfo,
                             SpillMBBs, SpillIdxes, RestoreMBBs, RestoreIdxes,
Evan Cheng's avatar
Evan Cheng committed
      } else {
        rewriteInstructionsForSpills(li, false, I, NULL, 0,
                             Slot, 0, false, false, false,
                             false, vrm, RegMap, rc, ReMatIds, loopInfo,
                             SpillMBBs, SpillIdxes, RestoreMBBs, RestoreIdxes,
Evan Cheng's avatar
Evan Cheng committed
      }
      IsFirstRange = false;
    }
    return NewLIs;
  }

  bool TrySplit = SplitAtBB && !intervalIsInOneMBB(li);
  if (SplitLimit != -1 && (int)numSplits >= SplitLimit)
    TrySplit = false;
  if (TrySplit)
    ++numSplits;
Evan Cheng's avatar
Evan Cheng committed
  bool NeedStackSlot = false;
  for (LiveInterval::const_vni_iterator i = li.vni_begin(), e = li.vni_end();
       i != e; ++i) {
    const VNInfo *VNI = *i;
    unsigned VN = VNI->id;
    unsigned DefIdx = VNI->def;
    if (DefIdx == ~1U)
      continue; // Dead val#.
    // Is the def for the val# rematerializable?
Evan Cheng's avatar
Evan Cheng committed
    MachineInstr *ReMatDefMI = (DefIdx == ~0u)
      ? 0 : getInstructionFromIndex(DefIdx);
    if (ReMatDefMI && isReMaterializable(li, VNI, ReMatDefMI)) {
Evan Cheng's avatar
Evan Cheng committed
      // Remember how to remat the def of this val#.
Evan Cheng's avatar
Evan Cheng committed
      ReMatOrigDefs[VN] = ReMatDefMI;
Evan Cheng's avatar
Evan Cheng committed
      // Original def may be modified so we have to make a copy here. vrm must
      // delete these!
Evan Cheng's avatar
Evan Cheng committed
      ReMatDefs[VN] = ReMatDefMI = ReMatDefMI->clone();
      vrm.setVirtIsReMaterialized(li.reg, ReMatDefMI);
Evan Cheng's avatar
Evan Cheng committed

      bool CanDelete = true;
      if (VNI->hasPHIKill) {
        // A kill is a phi node, not all of its uses can be rematerialized.
Evan Cheng's avatar
Evan Cheng committed
        // It must not be deleted.
        CanDelete = false;
        // Need a stack slot if there is any live range where uses cannot be
        // rematerialized.
        NeedStackSlot = true;
Evan Cheng's avatar
Evan Cheng committed
      }
      if (CanDelete)
        ReMatDelete.set(VN);
    } else {
      // Need a stack slot if there is any live range where uses cannot be
      // rematerialized.
      NeedStackSlot = true;
    }
  }

  // One stack slot per live interval.
Evan Cheng's avatar
Evan Cheng committed
  if (NeedStackSlot && vrm.getPreSplitReg(li.reg) == 0)
Evan Cheng's avatar
Evan Cheng committed
    Slot = vrm.assignVirt2StackSlot(li.reg);

  // Create new intervals and rewrite defs and uses.
  for (LiveInterval::Ranges::const_iterator
         I = li.ranges.begin(), E = li.ranges.end(); I != E; ++I) {
Evan Cheng's avatar
Evan Cheng committed
    MachineInstr *ReMatDefMI = ReMatDefs[I->valno->id];
    MachineInstr *ReMatOrigDefMI = ReMatOrigDefs[I->valno->id];
    bool DefIsReMat = ReMatDefMI != NULL;
Evan Cheng's avatar
Evan Cheng committed
    bool CanDelete = ReMatDelete[I->valno->id];
    int LdSlot = 0;
Evan Cheng's avatar
Evan Cheng committed
    bool isLoadSS = DefIsReMat && tii_->isLoadFromStackSlot(ReMatDefMI, LdSlot);
Evan Cheng's avatar
Evan Cheng committed
    bool isLoad = isLoadSS ||
Evan Cheng's avatar
Evan Cheng committed
      (DefIsReMat && (ReMatDefMI->getInstrDescriptor()->Flags & M_LOAD_FLAG));
    rewriteInstructionsForSpills(li, TrySplit, I, ReMatOrigDefMI, ReMatDefMI,
                               Slot, LdSlot, isLoad, isLoadSS, DefIsReMat,
                               CanDelete, vrm, RegMap, rc, ReMatIds, loopInfo,
                               SpillMBBs, SpillIdxes, RestoreMBBs, RestoreIdxes,
  // Insert spills / restores if we are splitting.
  if (!TrySplit)
    return NewLIs;

  if (NeedStackSlot) {
    int Id = SpillMBBs.find_first();
    while (Id != -1) {
      std::vector<SRInfo> &spills = SpillIdxes[Id];
      for (unsigned i = 0, e = spills.size(); i != e; ++i) {
        int index = spills[i].index;
        unsigned VReg = spills[i].vreg;
        bool DoFold = spills[i].canFold;
        bool isReMat = vrm.isReMaterialized(VReg);
        MachineInstr *MI = getInstructionFromIndex(index);
        int OpIdx = -1;
        bool FoldedLoad = false;
        if (DoFold) {
          for (unsigned j = 0, ee = MI->getNumOperands(); j != ee; ++j) {
            MachineOperand &MO = MI->getOperand(j);
            if (!MO.isRegister() || MO.getReg() != VReg)
              continue;
            if (MO.isUse()) {
              // Can't fold if it's two-address code and the use isn't the
              // first and only use.
              // If there are more than one uses, a load is still needed.
              if (!isReMat && !FoldedLoad &&
                  alsoFoldARestore(Id, index,VReg,RestoreMBBs,RestoreIdxes)) {
                FoldedLoad = true;
                continue;
              } else {
                OpIdx = -1;
                break;
              }
            }
            OpIdx = (int)j;
          }
        }
        // Fold the store into the def if possible.
        if (OpIdx == -1)
          DoFold = false;
        if (DoFold) {
          if (tryFoldMemoryOperand(MI, vrm, NULL, index,OpIdx,true,Slot,VReg)) {
            if (FoldedLoad)
              // Folded a two-address instruction, do not issue a load.
              eraseRestoreInfo(Id, index, VReg, RestoreMBBs, RestoreIdxes);
          } else
            DoFold = false;
        }

        // Else tell the spiller to issue a store for us.
        if (!DoFold)
          vrm.addSpillPoint(VReg, MI);
      }
  int Id = RestoreMBBs.find_first();
  while (Id != -1) {
    std::vector<SRInfo> &restores = RestoreIdxes[Id];
    for (unsigned i = 0, e = restores.size(); i != e; ++i) {
      int index = restores[i].index;
      if (index == -1)
        continue;
      unsigned VReg = restores[i].vreg;
      bool DoFold = restores[i].canFold;
Evan Cheng's avatar
Evan Cheng committed
      MachineInstr *MI = getInstructionFromIndex(index);
      int OpIdx = -1;
Evan Cheng's avatar
Evan Cheng committed
        for (unsigned j = 0, ee = MI->getNumOperands(); j != ee; ++j) {
          MachineOperand &MO = MI->getOperand(j);
          if (!MO.isRegister() || MO.getReg() != VReg)
            continue;
Evan Cheng's avatar
Evan Cheng committed
            // Can't fold if it's two-address code.            
            OpIdx = -1;
            break;
          }
          if (OpIdx != -1) {
            // Multiple uses, do not fold!
            OpIdx = -1;
            break;
          }
Evan Cheng's avatar
Evan Cheng committed
          OpIdx = (int)j;
        }
      }

      // Fold the load into the use if possible.
      if (OpIdx == -1)
        DoFold = false;
      if (DoFold) {
        if (vrm.isReMaterialized(VReg)) {
          MachineInstr *ReMatDefMI = vrm.getReMaterializedMI(VReg);
          int LdSlot = 0;
          bool isLoadSS = tii_->isLoadFromStackSlot(ReMatDefMI, LdSlot);
          // If the rematerializable def is a load, also try to fold it.
          if (isLoadSS ||
              (ReMatDefMI->getInstrDescriptor()->Flags & M_LOAD_FLAG))
            DoFold = tryFoldMemoryOperand(MI, vrm, ReMatDefMI, index, OpIdx,
                                          isLoadSS, LdSlot, VReg);
          else
            DoFold = false;
        } else
          DoFold = tryFoldMemoryOperand(MI, vrm, NULL, index, OpIdx,
                                        true, Slot, VReg);
      }
      // If folding is not possible / failed, then tell the spiller to issue a
      // load / rematerialization for us.
      if (!DoFold)
        vrm.addRestorePoint(VReg, MI);
Evan Cheng's avatar
Evan Cheng committed
    }
Evan Cheng's avatar
Evan Cheng committed
  }

  // Finalize spill weights.
  for (unsigned i = 0, e = NewLIs.size(); i != e; ++i)
    NewLIs[i]->weight /= NewLIs[i]->getSize();
Evan Cheng's avatar
Evan Cheng committed
  return NewLIs;
}