diff options
-rw-r--r-- | include/llvm/CodeGen/LiveInterval.h | 4 | ||||
-rw-r--r-- | include/llvm/CodeGen/LiveIntervalAnalysis.h | 37 | ||||
-rw-r--r-- | lib/CodeGen/LiveIntervalAnalysis.cpp | 349 | ||||
-rw-r--r-- | lib/CodeGen/RegAllocLinearScan.cpp | 22 | ||||
-rw-r--r-- | lib/CodeGen/SimpleRegisterCoalescing.cpp | 6 | ||||
-rw-r--r-- | lib/CodeGen/VirtRegMap.cpp | 246 | ||||
-rw-r--r-- | lib/CodeGen/VirtRegMap.h | 29 |
7 files changed, 410 insertions, 283 deletions
diff --git a/include/llvm/CodeGen/LiveInterval.h b/include/llvm/CodeGen/LiveInterval.h index 5d9db57da0..068a15d9a2 100644 --- a/include/llvm/CodeGen/LiveInterval.h +++ b/include/llvm/CodeGen/LiveInterval.h @@ -83,7 +83,6 @@ namespace llvm { unsigned reg; // the register of this interval unsigned preference; // preferred register to allocate for this interval float weight; // weight of this interval - MachineInstr* remat; // definition if the definition rematerializable Ranges ranges; // the ranges in which this register is live /// ValueNumberInfo - If the value number definition is undefined (e.g. phi @@ -101,7 +100,7 @@ namespace llvm { public: LiveInterval(unsigned Reg, float Weight) - : reg(Reg), preference(0), weight(Weight), remat(NULL) { + : reg(Reg), preference(0), weight(Weight) { } typedef Ranges::iterator iterator; @@ -128,7 +127,6 @@ namespace llvm { void swap(LiveInterval& other) { std::swap(reg, other.reg); std::swap(weight, other.weight); - std::swap(remat, other.remat); std::swap(ranges, other.ranges); std::swap(ValueNumberInfo, other.ValueNumberInfo); } diff --git a/include/llvm/CodeGen/LiveIntervalAnalysis.h b/include/llvm/CodeGen/LiveIntervalAnalysis.h index 4783df40bd..8e7a100b96 100644 --- a/include/llvm/CodeGen/LiveIntervalAnalysis.h +++ b/include/llvm/CodeGen/LiveIntervalAnalysis.h @@ -25,6 +25,8 @@ #include "llvm/ADT/BitVector.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/IndexedMap.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" namespace llvm { @@ -41,9 +43,9 @@ namespace llvm { const TargetInstrInfo* tii_; LiveVariables* lv_; - /// MBB2IdxMap - The index of the first instruction in the specified basic - /// block. - std::vector<unsigned> MBB2IdxMap; + /// MBB2IdxMap - The indexes of the first and last instructions in the + /// specified basic block. + std::vector<std::pair<unsigned, unsigned> > MBB2IdxMap; typedef std::map<MachineInstr*, unsigned> Mi2IndexMap; Mi2IndexMap mi2iMap_; @@ -56,6 +58,8 @@ namespace llvm { BitVector allocatableRegs_; + std::vector<MachineInstr*> ClonedMIs; + public: static char ID; // Pass identification, replacement for typeid LiveIntervals() : MachineFunctionPass((intptr_t)&ID) {} @@ -118,10 +122,19 @@ namespace llvm { unsigned getMBBStartIdx(MachineBasicBlock *MBB) const { return getMBBStartIdx(MBB->getNumber()); } - unsigned getMBBStartIdx(unsigned MBBNo) const { assert(MBBNo < MBB2IdxMap.size() && "Invalid MBB number!"); - return MBB2IdxMap[MBBNo]; + return MBB2IdxMap[MBBNo].first; + } + + /// getMBBEndIdx - Return the store index of the last instruction in the + /// specified MachineBasicBlock. + unsigned getMBBEndIdx(MachineBasicBlock *MBB) const { + return getMBBEndIdx(MBB->getNumber()); + } + unsigned getMBBEndIdx(unsigned MBBNo) const { + assert(MBBNo < MBB2IdxMap.size() && "Invalid MBB number!"); + return MBB2IdxMap[MBBNo].second; } /// getInstructionIndex - returns the base index of instr @@ -155,8 +168,7 @@ namespace llvm { const std::vector<LiveRange> &LRs); std::vector<LiveInterval*> addIntervalsForSpills(const LiveInterval& i, - VirtRegMap& vrm, - int slot); + VirtRegMap& vrm, unsigned reg); // Interval removal @@ -225,6 +237,17 @@ namespace llvm { unsigned MIIdx, LiveInterval &interval, bool isAlias = false); + /// isReMaterializable - Returns true if the definition MI of the specified + /// val# of the specified interval is re-materializable. + bool isReMaterializable(const LiveInterval &li, unsigned ValNum, + MachineInstr *MI); + + /// tryFoldMemoryOperand - Attempts to fold a spill / restore from slot + /// to reg into ith operand of specified MI. If it is successul, MI is + /// updated with the newly created MI and returns true. + bool tryFoldMemoryOperand(MachineInstr* &MI, VirtRegMap &vrm, unsigned index, + unsigned i, int slot, unsigned reg); + static LiveInterval createInterval(unsigned Reg); void printRegName(unsigned reg) const; diff --git a/lib/CodeGen/LiveIntervalAnalysis.cpp b/lib/CodeGen/LiveIntervalAnalysis.cpp index ebf3c57230..bd8137730b 100644 --- a/lib/CodeGen/LiveIntervalAnalysis.cpp +++ b/lib/CodeGen/LiveIntervalAnalysis.cpp @@ -30,7 +30,6 @@ #include "llvm/Target/TargetMachine.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" -#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/STLExtras.h" #include <algorithm> @@ -60,6 +59,8 @@ void LiveIntervals::releaseMemory() { mi2iMap_.clear(); i2miMap_.clear(); r2iMap_.clear(); + for (unsigned i = 0, e = ClonedMIs.size(); i != e; ++i) + delete ClonedMIs[i]; } /// runOnMachineFunction - Register allocate the whole function @@ -74,13 +75,12 @@ bool LiveIntervals::runOnMachineFunction(MachineFunction &fn) { // Number MachineInstrs and MachineBasicBlocks. // Initialize MBB indexes to a sentinal. - MBB2IdxMap.resize(mf_->getNumBlockIDs(), ~0U); + MBB2IdxMap.resize(mf_->getNumBlockIDs(), std::make_pair(~0U,~0U)); unsigned MIIndex = 0; for (MachineFunction::iterator MBB = mf_->begin(), E = mf_->end(); MBB != E; ++MBB) { - // Set the MBB2IdxMap entry for this MBB. - MBB2IdxMap[MBB->getNumber()] = MIIndex; + unsigned StartIdx = MIIndex; for (MachineBasicBlock::iterator I = MBB->begin(), E = MBB->end(); I != E; ++I) { @@ -89,6 +89,9 @@ bool LiveIntervals::runOnMachineFunction(MachineFunction &fn) { i2miMap_.push_back(I); MIIndex += InstrSlots::NUM; } + + // Set the MBB2IdxMap entry for this MBB. + MBB2IdxMap[MBB->getNumber()] = std::make_pair(StartIdx, MIIndex - 1); } computeIntervals(); @@ -175,8 +178,76 @@ LiveIntervals::CreateNewLiveInterval(const LiveInterval *LI, return NewLI; } +/// isReDefinedByTwoAddr - Returns true if the Reg re-definition is due to +/// two addr elimination. +static bool isReDefinedByTwoAddr(MachineInstr *MI, unsigned Reg, + const TargetInstrInfo *TII) { + for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { + MachineOperand &MO1 = MI->getOperand(i); + if (MO1.isRegister() && MO1.isDef() && MO1.getReg() == Reg) { + for (unsigned j = i+1; j < e; ++j) { + MachineOperand &MO2 = MI->getOperand(j); + if (MO2.isRegister() && MO2.isUse() && MO2.getReg() == Reg && + MI->getInstrDescriptor()-> + getOperandConstraint(j, TOI::TIED_TO) == (int)i) + return true; + } + } + } + return false; +} + +/// isReMaterializable - Returns true if the definition MI of the specified +/// val# of the specified interval is re-materializable. +bool LiveIntervals::isReMaterializable(const LiveInterval &li, unsigned ValNum, + MachineInstr *MI) { + if (tii_->isTriviallyReMaterializable(MI)) + return true; + + int FrameIdx = 0; + if (!tii_->isLoadFromStackSlot(MI, FrameIdx) || + !mf_->getFrameInfo()->isFixedObjectIndex(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. + for (unsigned i = 0, e = li.getNumValNums(); i != e; ++i) { + if (i == ValNum) + continue; + unsigned DefIdx = li.getDefForValNum(i); + if (DefIdx == ~1U) + continue; // Dead val#. + MachineInstr *DefMI = (DefIdx == ~0u) + ? NULL : getInstructionFromIndex(DefIdx); + if (DefMI && isReDefinedByTwoAddr(DefMI, li.reg, tii_)) + return false; + } + return true; +} + +bool LiveIntervals::tryFoldMemoryOperand(MachineInstr* &MI, VirtRegMap &vrm, + unsigned index, unsigned i, + int slot, unsigned reg) { + MachineInstr *fmi = mri_->foldMemoryOperand(MI, i, slot); + if (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_) + lv_->instructionChanged(MI, fmi); + MachineBasicBlock &MBB = *MI->getParent(); + vrm.virtFolded(reg, MI, i, fmi); + mi2iMap_.erase(MI); + i2miMap_[index/InstrSlots::NUM] = fmi; + mi2iMap_[fmi] = index; + MI = MBB.insert(MBB.erase(MI), fmi); + ++numFolded; + return true; + } + return false; +} + std::vector<LiveInterval*> LiveIntervals:: -addIntervalsForSpills(const LiveInterval &li, VirtRegMap &vrm, int slot) { +addIntervalsForSpills(const LiveInterval &li, VirtRegMap &vrm, unsigned reg) { // since this is called after the analysis is done we don't know if // LiveVariables is available lv_ = getAnalysisToUpdate<LiveVariables>(); @@ -192,10 +263,72 @@ addIntervalsForSpills(const LiveInterval &li, VirtRegMap &vrm, int slot) { const TargetRegisterClass* rc = mf_->getSSARegMap()->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; + + bool NeedStackSlot = false; + for (unsigned i = 0; i != NumValNums; ++i) { + unsigned DefIdx = li.getDefForValNum(i); + if (DefIdx == ~1U) + continue; // Dead val#. + // Is the def for the val# rematerializable? + MachineInstr *DefMI = (DefIdx == ~0u) + ? NULL : getInstructionFromIndex(DefIdx); + if (DefMI && isReMaterializable(li, i, DefMI)) { + // Remember how to remat the def of this val#. + ReMatOrigDefs[i] = DefMI; + // Original def may be modified so we have to make a copy here. vrm must + // delete these! + ReMatDefs[i] = DefMI = DefMI->clone(); + vrm.setVirtIsReMaterialized(reg, DefMI); + + bool CanDelete = true; + const SmallVector<unsigned, 4> &kills = li.getKillsForValNum(i); + for (unsigned j = 0, ee = kills.size(); j != ee; ++j) { + unsigned KillIdx = kills[j]; + MachineInstr *KillMI = (KillIdx & 1) + ? NULL : getInstructionFromIndex(KillIdx); + // Kill is a phi node, not all of its uses can be rematerialized. + // It must not be deleted. + if (!KillMI) { + CanDelete = false; + // Need a stack slot if there is any live range where uses cannot be + // rematerialized. + NeedStackSlot = true; + break; + } + } + + if (CanDelete) + ReMatDelete.set(i); + } else { + // Need a stack slot if there is any live range where uses cannot be + // rematerialized. + NeedStackSlot = true; + } + } + + // One stack slot per live interval. + if (NeedStackSlot) + slot = vrm.assignVirt2StackSlot(reg); + for (LiveInterval::Ranges::const_iterator - i = li.ranges.begin(), e = li.ranges.end(); i != e; ++i) { - unsigned index = getBaseIndex(i->start); - unsigned end = getBaseIndex(i->end-1) + InstrSlots::NUM; + I = li.ranges.begin(), E = li.ranges.end(); I != E; ++I) { + MachineInstr *DefMI = ReMatDefs[I->ValId]; + MachineInstr *OrigDefMI = ReMatOrigDefs[I->ValId]; + bool DefIsReMat = DefMI != NULL; + bool CanDelete = ReMatDelete[I->ValId]; + int LdSlot = 0; + bool isLoadSS = DefIsReMat && tii_->isLoadFromStackSlot(DefMI, LdSlot); + unsigned index = getBaseIndex(I->start); + unsigned end = getBaseIndex(I->end-1) + InstrSlots::NUM; for (; index != end; index += InstrSlots::NUM) { // skip deleted instructions while (index != end && !getInstructionFromIndex(index)) @@ -208,87 +341,109 @@ addIntervalsForSpills(const LiveInterval &li, VirtRegMap &vrm, int slot) { for (unsigned i = 0; i != MI->getNumOperands(); ++i) { MachineOperand& mop = MI->getOperand(i); if (mop.isRegister() && mop.getReg() == li.reg) { - MachineInstr *fmi = li.remat ? NULL - : mri_->foldMemoryOperand(MI, i, slot); - if (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_) - lv_->instructionChanged(MI, fmi); - MachineBasicBlock &MBB = *MI->getParent(); - vrm.virtFolded(li.reg, MI, i, fmi); - mi2iMap_.erase(MI); - i2miMap_[index/InstrSlots::NUM] = fmi; - mi2iMap_[fmi] = index; - MI = MBB.insert(MBB.erase(MI), fmi); - ++numFolded; - // Folding the load/store can completely change the instruction in - // unpredictable ways, rescan it from the beginning. - goto RestartInstruction; + if (DefIsReMat) { + // If this is the rematerializable definition MI itself and + // all of its uses are rematerialized, simply delete it. + if (MI == OrigDefMI) { + if (CanDelete) { + RemoveMachineInstrFromMaps(MI); + MI->eraseFromParent(); + break; + } else if (tryFoldMemoryOperand(MI, vrm, index, i, slot, li.reg)) + // Folding the load/store can completely change the instruction + // in unpredictable ways, rescan it from the beginning. + goto RestartInstruction; + } else if (isLoadSS && + tryFoldMemoryOperand(MI, vrm, index, i, LdSlot, li.reg)){ + // FIXME: Other rematerializable loads can be folded as well. + // Folding the load/store can completely change the + // instruction in unpredictable ways, rescan it from + // the beginning. + goto RestartInstruction; + } } else { - // Create a new virtual register for the spill interval. - unsigned NewVReg = mf_->getSSARegMap()->createVirtualRegister(rc); + if (tryFoldMemoryOperand(MI, vrm, index, i, slot, li.reg)) + // Folding the load/store can completely change the instruction in + // unpredictable ways, rescan it from the beginning. + goto RestartInstruction; + } + + // Create a new virtual register for the spill interval. + unsigned NewVReg = mf_->getSSARegMap()->createVirtualRegister(rc); - // Scan all of the operands of this instruction rewriting operands - // to use NewVReg instead of li.reg as appropriate. We do this for - // two reasons: - // - // 1. If the instr reads the same spilled vreg multiple times, we - // want to reuse the NewVReg. - // 2. If the instr is a two-addr instruction, we are required to - // keep the src/dst regs pinned. - // - // Keep track of whether we replace a use and/or def so that we can - // create the spill interval with the appropriate range. - mop.setReg(NewVReg); + // Scan all of the operands of this instruction rewriting operands + // to use NewVReg instead of li.reg as appropriate. We do this for + // two reasons: + // + // 1. If the instr reads the same spilled vreg multiple times, we + // want to reuse the NewVReg. + // 2. If the instr is a two-addr instruction, we are required to + // keep the src/dst regs pinned. + // + // Keep track of whether we replace a use and/or def so that we can + // create the spill interval with the appropriate range. + mop.setReg(NewVReg); - bool HasUse = mop.isUse(); - bool HasDef = mop.isDef(); - for (unsigned j = i+1, e = MI->getNumOperands(); j != e; ++j) { - if (MI->getOperand(j).isReg() && - MI->getOperand(j).getReg() == li.reg) { - MI->getOperand(j).setReg(NewVReg); - HasUse |= MI->getOperand(j).isUse(); - HasDef |= MI->getOperand(j).isDef(); - } + bool HasUse = mop.isUse(); + bool HasDef = mop.isDef(); + for (unsigned j = i+1, e = MI->getNumOperands(); j != e; ++j) { + if (MI->getOperand(j).isReg() && + MI->getOperand(j).getReg() == li.reg) { + MI->getOperand(j).setReg(NewVReg); + HasUse |= MI->getOperand(j).isUse(); + HasDef |= MI->getOperand(j).isDef(); } + } - // create a new register for this spill - vrm.grow(); - if (li.remat) - vrm.setVirtIsReMaterialized(NewVReg, li.remat); - vrm.assignVirt2StackSlot(NewVReg, slot); - LiveInterval &nI = getOrCreateInterval(NewVReg); - nI.remat = li.remat; - assert(nI.empty()); - - // the spill weight is now infinity as it - // cannot be spilled again - nI.weight = HUGE_VALF; - - if (HasUse) { - LiveRange LR(getLoadIndex(index), getUseIndex(index), - nI.getNextValue(~0U, 0)); - DOUT << " +" << LR; - nI.addRange(LR); + vrm.grow(); + if (DefIsReMat) { + vrm.setVirtIsReMaterialized(NewVReg, DefMI/*, CanDelete*/); + if (ReMatIds[I->ValId] == VirtRegMap::MAX_STACK_SLOT) { + // Each valnum may have its own remat id. + ReMatIds[I->ValId] = vrm.assignVirtReMatId(NewVReg); + } else { + vrm.assignVirtReMatId(NewVReg, ReMatIds[I->ValId]); } - if (HasDef) { - LiveRange LR(getDefIndex(index), getStoreIndex(index), - nI.getNextValue(~0U, 0)); - DOUT << " +" << LR; - nI.addRange(LR); + if (!CanDelete || (HasUse && HasDef)) { + // If this is a two-addr instruction then its use operands are + // rematerializable but its def is not. It should be assigned a + // stack slot. + vrm.assignVirt2StackSlot(NewVReg, slot); } + } else { + vrm.assignVirt2StackSlot(NewVReg, slot); + } + + // create a new register interval for this spill / remat. + LiveInterval &nI = getOrCreateInterval(NewVReg); + assert(nI.empty()); + + // the spill weight is now infinity as it + // cannot be spilled again + nI.weight = HUGE_VALF; + + if (HasUse) { + LiveRange LR(getLoadIndex(index), getUseIndex(index), + nI.getNextValue(~0U, 0)); + DOUT << " +" << LR; + nI.addRange(LR); + } + if (HasDef) { + LiveRange LR(getDefIndex(index), getStoreIndex(index), + nI.getNextValue(~0U, 0)); + DOUT << " +" << LR; + nI.addRange(LR); + } - added.push_back(&nI); + added.push_back(&nI); - // update live variables if it is available - if (lv_) - lv_->addVirtualRegisterKilled(NewVReg, MI); + // update live variables if it is available + if (lv_) + lv_->addVirtualRegisterKilled(NewVReg, MI); - DOUT << "\t\t\t\tadded new interval: "; - nI.print(DOUT, mri_); - DOUT << '\n'; - } + DOUT << "\t\t\t\tadded new interval: "; + nI.print(DOUT, mri_); + DOUT << '\n'; } } } @@ -304,25 +459,6 @@ void LiveIntervals::printRegName(unsigned reg) const { cerr << "%reg" << reg; } -/// isReDefinedByTwoAddr - Returns true if the Reg re-definition is due to -/// two addr elimination. -static bool isReDefinedByTwoAddr(MachineInstr *MI, unsigned Reg, - const TargetInstrInfo *TII) { - for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { - MachineOperand &MO1 = MI->getOperand(i); - if (MO1.isRegister() && MO1.isDef() && MO1.getReg() == Reg) { - for (unsigned j = i+1; j < e; ++j) { - MachineOperand &MO2 = MI->getOperand(j); - if (MO2.isRegister() && MO2.isUse() && MO2.getReg() == Reg && - MI->getInstrDescriptor()-> - getOperandConstraint(j, TOI::TIED_TO) == (int)i) - return true; - } - } - } - return false; -} - void LiveIntervals::handleVirtualRegisterDef(MachineBasicBlock *mbb, MachineBasicBlock::iterator mi, unsigned MIIdx, @@ -335,16 +471,6 @@ void LiveIntervals::handleVirtualRegisterDef(MachineBasicBlock *mbb, // done once for the vreg. We use an empty interval to detect the first // time we see a vreg. if (interval.empty()) { - // Remember if the definition can be rematerialized. All load's from fixed - // stack slots are re-materializable. The target may permit other - // instructions to be re-materialized as well. - int FrameIdx = 0; - if (vi.DefInst && - (tii_->isTriviallyReMaterializable(vi.DefInst) || - (tii_->isLoadFromStackSlot(vi.DefInst, FrameIdx) && - mf_->getFrameInfo()->isFixedObjectIndex(FrameIdx)))) - interval.remat = vi.DefInst; - // Get the Idx of the defining instructions. unsigned defIndex = getDefIndex(MIIdx); unsigned ValNum; @@ -421,9 +547,6 @@ void LiveIntervals::handleVirtualRegisterDef(MachineBasicBlock *mbb, } } else { - // Can no longer safely assume definition is rematerializable. - interval.remat = NULL; - // If this is the second time we see a virtual register definition, it // must be due to phi elimination or two addr elimination. If this is // the result of two address elimination, then the vreg is one of the @@ -487,7 +610,7 @@ void LiveIntervals::handleVirtualRegisterDef(MachineBasicBlock *mbb, DOUT << " Removing [" << Start << "," << End << "] from: "; interval.print(DOUT, mri_); DOUT << "\n"; interval.removeRange(Start, End); - interval.addKillForValNum(0, Start); + interval.addKillForValNum(0, Start-1); // odd # means phi node DOUT << " RESULT: "; interval.print(DOUT, mri_); // Replace the interval with one of a NEW value number. Note that this @@ -514,7 +637,7 @@ void LiveIntervals::handleVirtualRegisterDef(MachineBasicBlock *mbb, unsigned killIndex = getInstructionIndex(&mbb->back()) + InstrSlots::NUM; LiveRange LR(defIndex, killIndex, ValNum); interval.addRange(LR); - interval.addKillForValNum(ValNum, killIndex); + interval.addKillForValNum(ValNum, killIndex-1); // odd # means phi node DOUT << " +" << LR; } } diff --git a/lib/CodeGen/RegAllocLinearScan.cpp b/lib/CodeGen/RegAllocLinearScan.cpp index 01d43fd908..6929b91645 100644 --- a/lib/CodeGen/RegAllocLinearScan.cpp +++ b/lib/CodeGen/RegAllocLinearScan.cpp @@ -305,7 +305,7 @@ void RALinScan::linearScan() for (unsigned i = 0, e = handled_.size(); i != e; ++i) { LiveInterval *HI = handled_[i]; unsigned Reg = HI->reg; - if (!vrm_->hasStackSlot(Reg) && HI->liveAt(StartIdx)) { + if (vrm_->isAssignedReg(Reg) && HI->liveAt(StartIdx)) { assert(MRegisterInfo::isVirtualRegister(Reg)); Reg = vrm_->getPhys(Reg); MBB->addLiveIn(Reg); @@ -605,14 +605,8 @@ void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur) // linearscan. if (cur->weight != HUGE_VALF && cur->weight <= minWeight) { DOUT << "\t\t\tspilling(c): " << *cur << '\n'; - // if the current interval is re-materializable, remember so and don't - // assign it a spill slot. - if (cur->remat) - vrm_->setVirtIsReMaterialized(cur->reg, cur->remat); - int slot = cur->remat ? vrm_->assignVirtReMatId(cur->reg) - : vrm_->assignVirt2StackSlot(cur->reg); std::vector<LiveInterval*> added = - li_->addIntervalsForSpills(*cur, *vrm_, slot); + li_->addIntervalsForSpills(*cur, *vrm_, cur->reg); if (added.empty()) return; // Early exit if all spills were folded. @@ -663,12 +657,8 @@ void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur) cur->overlapsFrom(*i->first, i->second)) { DOUT << "\t\t\tspilling(a): " << *i->first << '\n'; earliestStart = std::min(earliestStart, i->first->beginNumber()); - if (i->first->remat) - vrm_->setVirtIsReMaterialized(reg, i->first->remat); - int slot = i->first->remat ? vrm_->assignVirtReMatId(reg) - : vrm_->assignVirt2StackSlot(reg); std::vector<LiveInterval*> newIs = - li_->addIntervalsForSpills(*i->first, *vrm_, slot); + li_->addIntervalsForSpills(*i->first, *vrm_, reg); std::copy(newIs.begin(), newIs.end(), std::back_inserter(added)); spilled.insert(reg); } @@ -680,12 +670,8 @@ void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur) cur->overlapsFrom(*i->first, i->second-1)) { DOUT << "\t\t\tspilling(i): " << *i->first << '\n'; earliestStart = std::min(earliestStart, i->first->beginNumber()); - if (i->first->remat) - vrm_->setVirtIsReMaterialized(reg, i->first->remat); - int slot = i->first->remat ? vrm_->assignVirtReMatId(reg) - : vrm_->assignVirt2StackSlot(reg); std::vector<LiveInterval*> newIs = - li_->addIntervalsForSpills(*i->first, *vrm_, slot); + li_->addIntervalsForSpills(*i->first, *vrm_, reg); std::copy(newIs.begin(), newIs.end(), std::back_inserter(added)); spilled.insert(reg); } diff --git a/lib/CodeGen/SimpleRegisterCoalescing.cpp b/lib/CodeGen/SimpleRegisterCoalescing.cpp index e71b9d4c0f..fef2fde32a 100644 --- a/lib/CodeGen/SimpleRegisterCoalescing.cpp +++ b/lib/CodeGen/SimpleRegisterCoalescing.cpp @@ -1123,12 +1123,6 @@ bool SimpleRegisterCoalescing::runOnMachineFunction(MachineFunction &fn) { continue; LiveInterval &RegInt = li_->getInterval(reg); float w = (mop.isUse()+mop.isDef()) * powf(10.0F, (float)loopDepth); - // If the definition instruction is re-materializable, its spill - // weight is half of what it would have been normally unless it's - // a load from fixed stack slot. - int Dummy; - if (RegInt.remat && !tii_->isLoadFromStackSlot(RegInt.remat, Dummy)) - w /= 2; RegInt.weight += w; UniqueUses.insert(reg); } diff --git a/lib/CodeGen/VirtRegMap.cpp b/lib/CodeGen/VirtRegMap.cpp index 196e849cc5..9d57a0a267 100644 --- a/lib/CodeGen/VirtRegMap.cpp +++ b/lib/CodeGen/VirtRegMap.cpp @@ -62,13 +62,17 @@ namespace { VirtRegMap::VirtRegMap(MachineFunction &mf) : TII(*mf.getTarget().getInstrInfo()), MF(mf), Virt2PhysMap(NO_PHYS_REG), Virt2StackSlotMap(NO_STACK_SLOT), + Virt2ReMatIdMap(NO_STACK_SLOT), ReMatMap(NULL), ReMatId(MAX_STACK_SLOT+1) { grow(); } void VirtRegMap::grow() { - Virt2PhysMap.grow(MF.getSSARegMap()->getLastVirtReg()); - Virt2StackSlotMap.grow(MF.getSSARegMap()->getLastVirtReg()); + unsigned LastVirtReg = MF.getSSARegMap()->getLastVirtReg(); + Virt2PhysMap.grow(LastVirtReg); + Virt2StackSlotMap.grow(LastVirtReg); + Virt2ReMatIdMap.grow(LastVirtReg); + ReMatMap.grow(LastVirtReg); } int VirtRegMap::assignVirt2StackSlot(unsigned virtReg) { @@ -95,19 +99,19 @@ void VirtRegMap::assignVirt2StackSlot(unsigned virtReg, int frameIndex) { int VirtRegMap::assignVirtReMatId(unsigned virtReg) { assert(MRegisterInfo::isVirtualRegister(virtReg)); - assert(Virt2StackSlotMap[virtReg] == NO_STACK_SLOT && + assert(Virt2ReMatIdMap[virtReg] == NO_STACK_SLOT && "attempt to assign re-mat id to already spilled register"); - const MachineInstr *DefMI = getReMaterializedMI(virtReg); - int FrameIdx; - if (TII.isLoadFromStackSlot((MachineInstr*)DefMI, FrameIdx)) { - // Load from stack slot is re-materialize as reload from the stack slot! - Virt2StackSlotMap[virtReg] = FrameIdx; - return FrameIdx; - } - Virt2StackSlotMap[virtReg] = ReMatId; + Virt2ReMatIdMap[virtReg] = ReMatId; return ReMatId++; } +void VirtRegMap::assignVirtReMatId(unsigned virtReg, int id) { + assert(MRegisterInfo::isVirtualRegister(virtReg)); + assert(Virt2ReMatIdMap[virtReg] == NO_STACK_SLOT && + "attempt to assign re-mat id to already spilled register"); + Virt2ReMatIdMap[virtReg] = id; +} + void VirtRegMap::virtFolded(unsigned VirtReg, MachineInstr *OldMI, unsigned OpNo, MachineInstr *NewMI) { // Move previous memory references folded to new instruction. @@ -194,7 +198,7 @@ bool SimpleSpiller::runOnMachineFunction(MachineFunction &MF, VirtRegMap &VRM) { if (MRegisterInfo::isVirtualRegister(MO.getReg())) { unsigned VirtReg = MO.getReg(); unsigned PhysReg = VRM.getPhys(VirtReg); - if (VRM.hasStackSlot(VirtReg)) { + if (!VRM.isAssignedReg(VirtReg)) { int StackSlot = VRM.getStackSlot(VirtReg); const TargetRegisterClass* RC = MF.getSSARegMap()->getRegClass(VirtReg); @@ -246,43 +250,41 @@ namespace { DOUT << "\n**** Local spiller rewriting function '" << MF.getFunction()->getName() << "':\n"; - std::vector<MachineInstr *> ReMatedMIs; for (MachineFunction::iterator MBB = MF.begin(), E = MF.end(); MBB != E; ++MBB) - RewriteMBB(*MBB, VRM, ReMatedMIs); - for (unsigned i = 0, e = ReMatedMIs.size(); i != e; ++i) - delete ReMatedMIs[i]; + RewriteMBB(*MBB, VRM); return true; } private: - void RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM, - std::vector<MachineInstr*> &ReMatedMIs); + void RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM); }; } /// AvailableSpills - As the local spiller is scanning and rewriting an MBB from -/// top down, keep track of which spills slots are available in each register. +/// top down, keep track of which spills slots or remat are available in each +/// register. /// /// Note that not all physregs are created equal here. In particular, some /// physregs are reloads that we are allowed to clobber or ignore at any time. /// Other physregs are values that the register allocated program is using that /// we cannot CHANGE, but we can read if we like. We keep track of this on a -/// per-stack-slot basis as the low bit in the value of the SpillSlotsAvailable -/// entries. The predicate 'canClobberPhysReg()' checks this bit and -/// addAvailable sets it if. +/// per-stack-slot / remat id basis as the low bit in the value of the +/// SpillSlotsAvailable entries. The predicate 'canClobberPhysReg()' checks +/// this bit and addAvailable sets it if. namespace { class VISIBILITY_HIDDEN AvailableSpills { const MRegisterInfo *MRI; const TargetInstrInfo *TII; - // SpillSlotsAvailable - This map keeps track of all of the spilled virtual - // register values that are still available, due to being loaded or stored to, - // but not invalidated yet. - std::map<int, unsigned> SpillSlotsAvailable; + // SpillSlotsOrReMatsAvailable - This map keeps track of all of the spilled + // or remat'ed virtual register values that are still available, due to being + // loaded or stored to, but not invalidated yet. + std::map<int, unsigned> SpillSlotsOrReMatsAvailable; - // PhysRegsAvailable - This is the inverse of SpillSlotsAvailable, indicating - // which stack slot values are currently held by a physreg. This is used to - // invalidate entries in SpillSlotsAvailable when a physreg is modified. + // PhysRegsAvailable - This is the inverse of SpillSlotsOrReMatsAvailable, + // indicating which stack slot values are currently held by a physreg. This + // is used to invalidate entries in SpillSlotsOrReMatsAvailable when a + // physreg is modified. std::multimap<unsigned, int> PhysRegsAvailable; void disallowClobberPhysRegOnly(unsigned PhysReg); @@ -295,41 +297,43 @@ public: const MRegisterInfo *getRegInfo() const { return MRI; } - /// getSpillSlotPhysReg - If the specified stack slot is available in a - /// physical register, return that PhysReg, otherwise return 0. - unsigned getSpillSlotPhysReg(int Slot) const { - std::map<int, unsigned>::const_iterator I = SpillSlotsAvailable.find(Slot); - if (I != SpillSlotsAvailable.end()) { + /// getSpillSlotOrReMatPhysReg - If the specified stack slot or remat is + /// available in a physical register, return that PhysReg, otherwise + /// return 0. + unsigned getSpillSlotOrReMatPhysReg(int Slot) const { + std::map<int, unsigned>::const_iterator I = + SpillSlotsOrReMatsAvailable.find(Slot); + if (I != SpillSlotsOrReMatsAvailable.end()) { return I->second >> 1; // Remove the CanClobber bit. } return 0; } - /// addAvailable - Mark that the specified stack slot is available in the - /// specified physreg. If CanClobber is true, the physreg can be modified at - /// any time without changing the semantics of the program. - void addAvailable(int Slot, MachineInstr *MI, unsigned Reg, + /// addAvailable - Mark that the specified stack slot / remat is available in + /// the specified physreg. If CanClobber is true, the physreg can be modified + /// at any time without changing the semantics of the program. + void addAvailable(int SlotOrReMat, MachineInstr *MI, unsigned Reg, bool CanClobber = true) { // If this stack slot is thought to be available in some other physreg, // remove its record. - ModifyStackSlot(Slot); + ModifyStackSlotOrReMat(SlotOrReMat); - PhysRegsAvailable.insert(std::make_pair(Reg, Slot)); - SpillSlotsAvailable[Slot] = (Reg << 1) | (unsigned)CanClobber; + PhysRegsAvailable.insert(std::make_pair(Reg, SlotOrReMat)); + SpillSlotsOrReMatsAvailable[SlotOrReMat] = (Reg << 1) | (unsigned)CanClobber; - if (Slot > VirtRegMap::MAX_STACK_SLOT) - DOUT << "Remembering RM#" << Slot-VirtRegMap::MAX_STACK_SLOT-1; + if (SlotOrReMat > VirtRegMap::MAX_STACK_SLOT) + DOUT << "Remembering RM#" << SlotOrReMat-VirtRegMap::MAX_STACK_SLOT-1; else - DOUT << "Remembering SS#" << Slot; + DOUT << "Remembering SS#" << SlotOrReMat; DOUT << " in physreg " << MRI->getName(Reg) << "\n"; } /// canClobberPhysReg - Return true if the spiller is allowed to change the /// value of the specified stackslot register if it desires. The specified /// stack slot must be available in a physreg for this query to make sense. - bool canClobberPhysReg(int Slot) const { - assert(SpillSlotsAvailable.count(Slot) && "Slot not available!"); - return SpillSlotsAvailable.find(Slot)->second & 1; + bool canClobberPhysReg(int SlotOrReMat) const { + assert(SpillSlotsOrReMatsAvailable.count(SlotOrReMat) && "Value not available!"); + return SpillSlotsOrReMatsAvailable.find(SlotOrReMat)->second & 1; } /// disallowClobberPhysReg - Unset the CanClobber bit of the specified @@ -342,10 +346,10 @@ public: /// it and any of its aliases. void ClobberPhysReg(unsigned PhysReg); - /// ModifyStackSlot - This method is called when the value in a stack slot + /// ModifyStackSlotOrReMat - This method is called when the value in a stack slot /// changes. This removes information about which register the previous value /// for this slot lives in (as the previous value is dead now).< |