From: Jakob Stoklund Olesen Date: Wed, 19 Jan 2011 22:11:48 +0000 (+0000) Subject: Implement RAGreedy::splitAroundRegion and remove loop splitting. X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=ccdb3fcef9aeb9f683cd738afbe1cd961bb0c1ef;p=oota-llvm.git Implement RAGreedy::splitAroundRegion and remove loop splitting. Region splitting includes loop splitting as a subset, and it is more generic. The splitting heuristics for variables that are live in more than one block are now: 1. Try to create a region that covers multiple basic blocks. 2. Try to create a new live range for each block with multiple uses. 3. Spill. Steps 2 and 3 are similar to what the standard spiller is doing. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@123853 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/LiveInterval.cpp b/lib/CodeGen/LiveInterval.cpp index c6a01495163..c2dbd6ab75a 100644 --- a/lib/CodeGen/LiveInterval.cpp +++ b/lib/CodeGen/LiveInterval.cpp @@ -650,7 +650,9 @@ void LiveRange::dump() const { } void LiveInterval::print(raw_ostream &OS, const TargetRegisterInfo *TRI) const { - OS << PrintReg(reg, TRI) << ',' << weight; + OS << PrintReg(reg, TRI); + if (weight != 0) + OS << ',' << weight; if (empty()) OS << " EMPTY"; diff --git a/lib/CodeGen/RegAllocGreedy.cpp b/lib/CodeGen/RegAllocGreedy.cpp index dc45df5bb24..fa3b5871fce 100644 --- a/lib/CodeGen/RegAllocGreedy.cpp +++ b/lib/CodeGen/RegAllocGreedy.cpp @@ -83,7 +83,7 @@ class RAGreedy : public MachineFunctionPass, public RegAllocBase { /// 6. |-----------| Live-through without uses. Transparent. /// struct BlockInfo { - const MachineBasicBlock *MBB; + MachineBasicBlock *MBB; SlotIndex FirstUse; ///< First instr using current reg. SlotIndex LastUse; ///< Last instr using current reg. SlotIndex Kill; ///< Interval end point inside block. @@ -119,8 +119,8 @@ public: virtual float getPriority(LiveInterval *LI); - virtual unsigned selectOrSplit(LiveInterval &VirtReg, - SmallVectorImpl &SplitVRegs); + virtual unsigned selectOrSplit(LiveInterval&, + SmallVectorImpl&); /// Perform register allocation. virtual bool runOnMachineFunction(MachineFunction &mf); @@ -132,12 +132,12 @@ private: LiveInterval *getSingleInterference(LiveInterval&, unsigned); bool reassignVReg(LiveInterval &InterferingVReg, unsigned OldPhysReg); bool reassignInterferences(LiveInterval &VirtReg, unsigned PhysReg); - unsigned findInterferenceFreeReg(MachineLoopRange*, - LiveInterval&, AllocationOrder&); float calcInterferenceWeight(LiveInterval&, unsigned); void calcLiveBlockInfo(LiveInterval&); float calcInterferenceInfo(LiveInterval&, unsigned); float calcGlobalSplitCost(const BitVector&); + void splitAroundRegion(LiveInterval&, unsigned, const BitVector&, + SmallVectorImpl&); unsigned tryReassign(LiveInterval&, AllocationOrder&); unsigned tryRegionSplit(LiveInterval&, AllocationOrder&, @@ -323,90 +323,6 @@ unsigned RAGreedy::tryReassign(LiveInterval &VirtReg, AllocationOrder &Order) { } -//===----------------------------------------------------------------------===// -// Loop Splitting -//===----------------------------------------------------------------------===// - -/// findInterferenceFreeReg - Find a physical register in Order where Loop has -/// no interferences with VirtReg. -unsigned RAGreedy::findInterferenceFreeReg(MachineLoopRange *Loop, - LiveInterval &VirtReg, - AllocationOrder &Order) { - Order.rewind(); - while (unsigned PhysReg = Order.next()) { - bool interference = false; - for (const unsigned *AI = TRI->getOverlaps(PhysReg); *AI; ++AI) { - if (query(VirtReg, *AI).checkLoopInterference(Loop)) { - interference = true; - break; - } - } - if (!interference) - return PhysReg; - } - // No physreg found. - return 0; -} - -/// trySplit - Try to split VirtReg or one of its interferences, making it -/// assignable. -/// @return Physreg when VirtReg may be assigned and/or new SplitVRegs. -unsigned RAGreedy::trySplit(LiveInterval &VirtReg, AllocationOrder &Order, - SmallVectorImpl&SplitVRegs) { - // Don't attempt splitting on local intervals for now. - if (LIS->intervalIsInOneMBB(VirtReg)) - return 0; - - NamedRegionTimer T("Splitter", TimerGroupName, TimePassesIsEnabled); - SA->analyze(&VirtReg); - - // Get the set of loops that have VirtReg uses and are splittable. - SplitAnalysis::LoopPtrSet SplitLoopSet; - SA->getSplitLoops(SplitLoopSet); - - // Order loops by descending area. - SmallVector SplitLoops; - for (SplitAnalysis::LoopPtrSet::const_iterator I = SplitLoopSet.begin(), - E = SplitLoopSet.end(); I != E; ++I) - SplitLoops.push_back(LoopRanges->getLoopRange(*I)); - array_pod_sort(SplitLoops.begin(), SplitLoops.end(), - MachineLoopRange::byAreaDesc); - - // Find the first loop that is interference-free for some register in the - // allocation order. - MachineLoopRange *Loop = 0; - for (unsigned i = 0, e = SplitLoops.size(); i != e; ++i) { - DEBUG(dbgs() << " Checking " << *SplitLoops[i]); - if (unsigned PhysReg = findInterferenceFreeReg(SplitLoops[i], - VirtReg, Order)) { - (void)PhysReg; - Loop = SplitLoops[i]; - DEBUG(dbgs() << ": Use %" << TRI->getName(PhysReg) << '\n'); - break; - } else { - DEBUG(dbgs() << ": Interference.\n"); - } - } - - if (!Loop) { - DEBUG(dbgs() << " All candidate loops have interference.\n"); - return 0; - } - - // Execute the split around Loop. - SmallVector SpillRegs; - LiveRangeEdit LREdit(VirtReg, SplitVRegs, SpillRegs); - SplitEditor(*SA, *LIS, *VRM, *DomTree, LREdit) - .splitAroundLoop(Loop->getLoop()); - - if (VerifyEnabled) - MF->verify(this, "After splitting live range around loop"); - - // We have new split regs, don't assign anything. - return 0; -} - - //===----------------------------------------------------------------------===// // Region Splitting //===----------------------------------------------------------------------===// @@ -427,7 +343,7 @@ void RAGreedy::calcLiveBlockInfo(LiveInterval &VirtReg) { UseE = SA->UseSlots.end(); // Loop over basic blocks where VirtReg is live. - MachineFunction::const_iterator MFI = Indexes->getMBBFromIndex(LVI->start); + MachineFunction::iterator MFI = Indexes->getMBBFromIndex(LVI->start); for (;;) { // Block constraints depend on the interference pattern. // Just allocate them here, don't compute anything. @@ -665,6 +581,236 @@ float RAGreedy::calcGlobalSplitCost(const BitVector &LiveBundles) { return GlobalCost; } +/// splitAroundRegion - Split VirtReg around the region determined by +/// LiveBundles. Make an effort to avoid interference from PhysReg. +/// +/// The 'register' interval is going to contain as many uses as possible while +/// avoiding interference. The 'stack' interval is the complement constructed by +/// SplitEditor. It will contain the rest. +/// +void RAGreedy::splitAroundRegion(LiveInterval &VirtReg, unsigned PhysReg, + const BitVector &LiveBundles, + SmallVectorImpl &NewVRegs) { + DEBUG({ + dbgs() << "Splitting around region for " << PrintReg(PhysReg, TRI) + << " with bundles"; + for (int i = LiveBundles.find_first(); i>=0; i = LiveBundles.find_next(i)) + dbgs() << " EB#" << i; + dbgs() << ".\n"; + }); + + // First compute interference ranges in the live blocks. + typedef std::pair IndexPair; + SmallVector InterferenceRanges; + InterferenceRanges.resize(LiveBlocks.size()); + for (const unsigned *AI = TRI->getOverlaps(PhysReg); *AI; ++AI) { + if (!query(VirtReg, *AI).checkInterference()) + continue; + LiveIntervalUnion::SegmentIter IntI = + PhysReg2LiveUnion[*AI].find(VirtReg.beginIndex()); + if (!IntI.valid()) + continue; + for (unsigned i = 0, e = LiveBlocks.size(); i != e; ++i) { + BlockInfo &BI = LiveBlocks[i]; + if (!BI.Uses) + continue; + IndexPair &IP = InterferenceRanges[i]; + SlotIndex Start, Stop; + tie(Start, Stop) = Indexes->getMBBRange(BI.MBB); + // Skip interference-free blocks. + if (IntI.start() >= Stop) + continue; + + // First interference in block. + if (BI.LiveIn) { + IntI.advanceTo(Start); + if (!IntI.valid()) + break; + if (!IP.first.isValid() || IntI.start() < IP.first) + IP.first = IntI.start(); + } + + // Last interference in block. + if (BI.LiveOut) { + IntI.advanceTo(Stop); + if (!IntI.valid() || IntI.start() >= Stop) + --IntI; + if (!IP.second.isValid() || IntI.stop() > IP.second) + IP.second = IntI.stop(); + } + } + } + + SmallVector SpillRegs; + LiveRangeEdit LREdit(VirtReg, NewVRegs, SpillRegs); + SplitEditor SE(*SA, *LIS, *VRM, *DomTree, LREdit); + + // Create the main cross-block interval. + SE.openIntv(); + + // First add all defs that are live out of a block. + for (unsigned i = 0, e = LiveBlocks.size(); i != e; ++i) { + BlockInfo &BI = LiveBlocks[i]; + bool RegIn = LiveBundles[Bundles->getBundle(BI.MBB->getNumber(), 0)]; + bool RegOut = LiveBundles[Bundles->getBundle(BI.MBB->getNumber(), 1)]; + + // Should the register be live out? + if (!BI.LiveOut || !RegOut) + continue; + + IndexPair &IP = InterferenceRanges[i]; + SlotIndex Start, Stop; + tie(Start, Stop) = Indexes->getMBBRange(BI.MBB); + + DEBUG(dbgs() << "BB#" << BI.MBB->getNumber() << " -> EB#" + << Bundles->getBundle(BI.MBB->getNumber(), 1)); + + // Check interference leaving the block. + if (!IP.second.isValid() || IP.second < Start) { + // Block is interference-free. + DEBUG(dbgs() << ", no interference"); + if (!BI.Uses) { + assert(BI.LiveThrough && "No uses, but not live through block?"); + // Block is live-through without interference. + DEBUG(dbgs() << ", no uses" + << (RegIn ? ", live-through.\n" : ", stack in.\n")); + if (!RegIn) + SE.enterIntvAtEnd(*BI.MBB); + continue; + } + if (!BI.LiveThrough) { + DEBUG(dbgs() << ", not live-through.\n"); + SE.enterIntvBefore(BI.Def); + SE.useIntv(BI.Def, Stop); + continue; + } + if (!RegIn) { + // Block is live-through, but entry bundle is on the stack. + // Reload just before the first use. + DEBUG(dbgs() << ", not live-in, enter before first use.\n"); + SE.enterIntvBefore(BI.FirstUse); + SE.useIntv(BI.FirstUse, Stop); + continue; + } + DEBUG(dbgs() << ", live-through.\n"); + continue; + } + + // Block has interference. + DEBUG(dbgs() << ", interference to " << IP.second); + if (!BI.Uses) { + // No uses in block, avoid interference by reloading as late as possible. + DEBUG(dbgs() << ", no uses.\n"); + SE.enterIntvAtEnd(*BI.MBB); + continue; + } + if (IP.second < BI.LastUse) { + // There are interference-free uses at the end of the block. + // Find the first use that can get the live-out register. + SlotIndex Use = *std::lower_bound(SA->UseSlots.begin(), SA->UseSlots.end(), + IP.second); + DEBUG(dbgs() << ", free use at " << Use << ".\n"); + assert(Use > IP.second && Use <= BI.LastUse); + SE.enterIntvBefore(Use); + SE.useIntv(Use, Stop); + continue; + } + + // Interference is after the last use. + DEBUG(dbgs() << " after last use.\n"); + SE.enterIntvAtEnd(*BI.MBB); + } + + // Now all defs leading to live bundles are handled, do everything else. + for (unsigned i = 0, e = LiveBlocks.size(); i != e; ++i) { + BlockInfo &BI = LiveBlocks[i]; + bool RegIn = LiveBundles[Bundles->getBundle(BI.MBB->getNumber(), 0)]; + bool RegOut = LiveBundles[Bundles->getBundle(BI.MBB->getNumber(), 1)]; + + // Is the register live-in? + if (!BI.LiveIn || !RegIn) + continue; + + // We have an incoming register. Check for interference. + IndexPair &IP = InterferenceRanges[i]; + SlotIndex Start, Stop; + tie(Start, Stop) = Indexes->getMBBRange(BI.MBB); + + DEBUG(dbgs() << "EB#" << Bundles->getBundle(BI.MBB->getNumber(), 0) + << " -> BB#" << BI.MBB->getNumber()); + + // Check interference entering the block. + if (!IP.first.isValid() || IP.first > Stop) { + // Block is interference-free. + DEBUG(dbgs() << ", no interference"); + if (!BI.Uses) { + assert(BI.LiveThrough && "No uses, but not live through block?"); + // Block is live-through without interference. + if (RegOut) { + DEBUG(dbgs() << ", no uses, live-through.\n"); + SE.useIntv(Start, Stop); + } else { + DEBUG(dbgs() << ", no uses, stack-out.\n"); + SE.leaveIntvAtTop(*BI.MBB); + } + continue; + } + if (!BI.LiveThrough) { + DEBUG(dbgs() << ", killed in block.\n"); + SE.useIntv(Start, BI.Kill); + SE.leaveIntvAfter(BI.Kill); + continue; + } + if (!RegOut) { + // Block is live-through, but exit bundle is on the stack. + // Spill immediately after the last use. + DEBUG(dbgs() << ", uses, stack-out.\n"); + SE.useIntv(Start, BI.LastUse); + SE.leaveIntvAfter(BI.LastUse); + continue; + } + // Register is live-through. + DEBUG(dbgs() << ", uses, live-through.\n"); + SE.useIntv(Start, Stop); + continue; + } + + // Block has interference. + DEBUG(dbgs() << ", interference from " << IP.first); + if (!BI.Uses) { + // No uses in block, avoid interference by spilling as soon as possible. + DEBUG(dbgs() << ", no uses.\n"); + SE.leaveIntvAtTop(*BI.MBB); + continue; + } + if (IP.first > BI.FirstUse) { + // There are interference-free uses at the beginning of the block. + // Find the last use that can get the register. + SlotIndex Use = std::lower_bound(SA->UseSlots.begin(), SA->UseSlots.end(), + IP.second)[-1]; + DEBUG(dbgs() << ", free use at " << Use << ".\n"); + assert(Use >= BI.FirstUse && Use < IP.first); + SE.useIntv(Start, Use); + SE.leaveIntvAfter(Use); + continue; + } + + // Interference is before the first use. + DEBUG(dbgs() << " before first use.\n"); + SE.leaveIntvAtTop(*BI.MBB); + } + + SE.closeIntv(); + + // FIXME: Should we be more aggressive about splitting the stack region into + // per-block segments? The current approach allows the stack region to + // separate into connected components. Some components may be allocatable. + SE.finish(); + + if (VerifyEnabled) + MF->verify(this, "After splitting live range around region"); +} + unsigned RAGreedy::tryRegionSplit(LiveInterval &VirtReg, AllocationOrder &Order, SmallVectorImpl &NewVRegs) { calcLiveBlockInfo(VirtReg); @@ -676,18 +822,62 @@ unsigned RAGreedy::tryRegionSplit(LiveInterval &VirtReg, AllocationOrder &Order, float Cost = calcInterferenceInfo(VirtReg, PhysReg); if (BestReg && Cost >= BestCost) continue; - if (!SpillPlacer->placeSpills(SpillConstraints, LiveBundles)) - Cost += calcGlobalSplitCost(LiveBundles); + + SpillPlacer->placeSpills(SpillConstraints, LiveBundles); + // No live bundles, defer to splitSingleBlocks(). + if (!LiveBundles.any()) + continue; + + Cost += calcGlobalSplitCost(LiveBundles); if (!BestReg || Cost < BestCost) { BestReg = PhysReg; BestCost = Cost; BestBundles.swap(LiveBundles); } } - // FIXME: Actually execute the split. + + if (!BestReg) + return 0; + + splitAroundRegion(VirtReg, BestReg, BestBundles, NewVRegs); return 0; } + +//===----------------------------------------------------------------------===// +// Live Range Splitting +//===----------------------------------------------------------------------===// + +/// trySplit - Try to split VirtReg or one of its interferences, making it +/// assignable. +/// @return Physreg when VirtReg may be assigned and/or new NewVRegs. +unsigned RAGreedy::trySplit(LiveInterval &VirtReg, AllocationOrder &Order, + SmallVectorImpl&NewVRegs) { + NamedRegionTimer T("Splitter", TimerGroupName, TimePassesIsEnabled); + SA->analyze(&VirtReg); + + // Don't attempt splitting on local intervals for now. TBD. + if (LIS->intervalIsInOneMBB(VirtReg)) + return 0; + + // First try to split around a region spanning multiple blocks. + unsigned PhysReg = tryRegionSplit(VirtReg, Order, NewVRegs); + if (PhysReg || !NewVRegs.empty()) + return PhysReg; + + // Then isolate blocks with multiple uses. + SplitAnalysis::BlockPtrSet Blocks; + if (SA->getMultiUseBlocks(Blocks)) { + SmallVector SpillRegs; + LiveRangeEdit LREdit(VirtReg, NewVRegs, SpillRegs); + SplitEditor(*SA, *LIS, *VRM, *DomTree, LREdit).splitSingleBlocks(Blocks); + } + + // Don't assign any physregs. + return 0; +} + + //===----------------------------------------------------------------------===// // Spilling //===----------------------------------------------------------------------===// @@ -756,7 +946,7 @@ unsigned RAGreedy::trySpillInterferences(LiveInterval &VirtReg, //===----------------------------------------------------------------------===// unsigned RAGreedy::selectOrSplit(LiveInterval &VirtReg, - SmallVectorImpl &SplitVRegs) { + SmallVectorImpl &NewVRegs) { // First try assigning a free register. AllocationOrder Order(VirtReg.reg, *VRM, ReservedRegs); while (unsigned PhysReg = Order.next()) { @@ -768,20 +958,22 @@ unsigned RAGreedy::selectOrSplit(LiveInterval &VirtReg, if (unsigned PhysReg = tryReassign(VirtReg, Order)) return PhysReg; + assert(NewVRegs.empty() && "Cannot append to existing NewVRegs"); + // Try splitting VirtReg or interferences. - unsigned PhysReg = trySplit(VirtReg, Order, SplitVRegs); - if (PhysReg || !SplitVRegs.empty()) + unsigned PhysReg = trySplit(VirtReg, Order, NewVRegs); + if (PhysReg || !NewVRegs.empty()) return PhysReg; // Try to spill another interfering reg with less spill weight. - PhysReg = trySpillInterferences(VirtReg, Order, SplitVRegs); + PhysReg = trySpillInterferences(VirtReg, Order, NewVRegs); if (PhysReg) return PhysReg; // Finally spill VirtReg itself. NamedRegionTimer T("Spiller", TimerGroupName, TimePassesIsEnabled); SmallVector pendingSpills; - spiller().spill(&VirtReg, SplitVRegs, pendingSpills); + spiller().spill(&VirtReg, NewVRegs, pendingSpills); // The live virtual register requesting allocation was spilled, so tell // the caller not to allocate anything during this round. diff --git a/lib/CodeGen/SplitKit.cpp b/lib/CodeGen/SplitKit.cpp index 7ed9089ecd0..a13134403a5 100644 --- a/lib/CodeGen/SplitKit.cpp +++ b/lib/CodeGen/SplitKit.cpp @@ -867,9 +867,7 @@ void SplitEditor::leaveIntvAtTop(MachineBasicBlock &MBB) { /// LiveInterval, and ranges can be trimmed. void SplitEditor::closeIntv() { assert(openli_.getLI() && "openIntv not called before closeIntv"); - - DEBUG(dbgs() << " closeIntv cleaning up\n"); - DEBUG(dbgs() << " open " << *openli_.getLI() << '\n'); + DEBUG(dbgs() << " closeIntv " << *openli_.getLI() << '\n'); openli_.reset(0); } @@ -966,6 +964,8 @@ void SplitEditor::computeRemainder() { // FIXME: If a single value is redefined, just move the def and truncate. LiveInterval &parent = edit_.getParent(); + DEBUG(dbgs() << "computeRemainder from " << parent << '\n'); + // Values that are fully contained in the split intervals. SmallPtrSet deadValues; // Map all curli values that should have live defs in dupli.