From 8ae0263471cc29c5f8278ee1ea5b678042ec6dce Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Tue, 20 Jul 2010 15:41:07 +0000 Subject: [PATCH] Beginning SplitKit - utility classes for live range splitting. This is a work in progress. So far we have some basic loop analysis to help determine where it is useful to split a live range around a loop. The actual loop splitting code from Splitter.cpp is also going to move in here. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@108842 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CMakeLists.txt | 1 + lib/CodeGen/InlineSpiller.cpp | 27 ++++++- lib/CodeGen/SplitKit.cpp | 148 ++++++++++++++++++++++++++++++++++ lib/CodeGen/SplitKit.h | 86 ++++++++++++++++++++ 4 files changed, 261 insertions(+), 1 deletion(-) create mode 100644 lib/CodeGen/SplitKit.cpp create mode 100644 lib/CodeGen/SplitKit.h diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt index ba6be3ce78c..4e377f941c0 100644 --- a/lib/CodeGen/CMakeLists.txt +++ b/lib/CodeGen/CMakeLists.txt @@ -68,6 +68,7 @@ add_llvm_library(LLVMCodeGen SjLjEHPrepare.cpp SlotIndexes.cpp Spiller.cpp + SplitKit.cpp Splitter.cpp StackProtector.cpp StackSlotColoring.cpp diff --git a/lib/CodeGen/InlineSpiller.cpp b/lib/CodeGen/InlineSpiller.cpp index 3c6c761b384..fc0357eda7b 100644 --- a/lib/CodeGen/InlineSpiller.cpp +++ b/lib/CodeGen/InlineSpiller.cpp @@ -14,6 +14,7 @@ #define DEBUG_TYPE "spiller" #include "Spiller.h" +#include "SplitKit.h" #include "VirtRegMap.h" #include "llvm/CodeGen/LiveIntervalAnalysis.h" #include "llvm/CodeGen/MachineFrameInfo.h" @@ -39,6 +40,8 @@ class InlineSpiller : public Spiller { const TargetRegisterInfo &tri_; const BitVector reserved_; + SplitAnalysis splitAnalysis_; + // Variables that are valid during spill(), but used by multiple methods. LiveInterval *li_; std::vector *newIntervals_; @@ -62,7 +65,8 @@ public: mri_(mf->getRegInfo()), tii_(*mf->getTarget().getInstrInfo()), tri_(*mf->getTarget().getRegisterInfo()), - reserved_(tri_.getReservedRegs(mf_)) {} + reserved_(tri_.getReservedRegs(mf_)), + splitAnalysis_(mf, lis, mli) {} void spill(LiveInterval *li, std::vector &newIntervals, @@ -70,6 +74,8 @@ public: SlotIndex *earliestIndex); private: + bool split(); + bool allUsesAvailableAt(const MachineInstr *OrigMI, SlotIndex OrigIdx, SlotIndex UseIdx); bool reMaterializeFor(MachineBasicBlock::iterator MI); @@ -91,6 +97,22 @@ Spiller *createInlineSpiller(MachineFunction *mf, } } +/// split - try splitting the current interval into pieces that may allocate +/// separately. Return true if successful. +bool InlineSpiller::split() { + // FIXME: Add intra-MBB splitting. + if (lis_.intervalIsInOneMBB(*li_)) + return false; + + splitAnalysis_.analyze(li_); + + if (const MachineLoop *loop = splitAnalysis_.getBestSplitLoop()) { + if (splitAroundLoop(splitAnalysis_, loop)) + return true; + } + return false; +} + /// allUsesAvailableAt - Return true if all registers used by OrigMI at /// OrigIdx are also available with the same value at UseIdx. bool InlineSpiller::allUsesAvailableAt(const MachineInstr *OrigMI, @@ -338,6 +360,9 @@ void InlineSpiller::spill(LiveInterval *li, rc_ = mri_.getRegClass(li->reg); spillIs_ = &spillIs; + if (split()) + return; + reMaterializeAll(); // Remat may handle everything. diff --git a/lib/CodeGen/SplitKit.cpp b/lib/CodeGen/SplitKit.cpp new file mode 100644 index 00000000000..4fbca10319a --- /dev/null +++ b/lib/CodeGen/SplitKit.cpp @@ -0,0 +1,148 @@ +//===---------- SplitKit.cpp - Toolkit for splitting live ranges ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the SplitAnalysis class as well as mutator functions for +// live range splitting. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "splitter" +#include "SplitKit.h" +#include "llvm/CodeGen/LiveIntervalAnalysis.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineLoopInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + + +//===----------------------------------------------------------------------===// +// Split Analysis +//===----------------------------------------------------------------------===// + +SplitAnalysis::SplitAnalysis(const MachineFunction *mf, + const LiveIntervals *lis, + const MachineLoopInfo *mli) + : mf_(*mf), + lis_(*lis), + loops_(*mli), + curli_(0) {} + +void SplitAnalysis::clear() { + usingInstrs_.clear(); + usingBlocks_.clear(); + usingLoops_.clear(); +} + +/// analyseUses - Count instructions, basic blocks, and loops using curli. +void SplitAnalysis::analyseUses() { + const MachineRegisterInfo &MRI = mf_.getRegInfo(); + for (MachineRegisterInfo::reg_iterator I = MRI.reg_begin(curli_->reg); + MachineInstr *MI = I.skipInstruction();) { + if (MI->isDebugValue() || !usingInstrs_.insert(MI)) + continue; + MachineBasicBlock *MBB = MI->getParent(); + if (usingBlocks_[MBB]++) + continue; + if (MachineLoop *Loop = loops_.getLoopFor(MBB)) + usingLoops_.insert(Loop); + } + DEBUG(dbgs() << "Counted " + << usingInstrs_.size() << " instrs, " + << usingBlocks_.size() << " blocks, " + << usingLoops_.size() << " loops in " + << *curli_ << "\n"); +} + +SplitAnalysis::LoopPeripheralUse +SplitAnalysis::analyzeLoopPeripheralUse(const MachineLoop *Loop) { + // Peripheral blocks. + SmallVector Peri; + Loop->getExitBlocks(Peri); + if (MachineBasicBlock *PredBB = Loop->getLoopPredecessor()) + Peri.push_back(PredBB); + array_pod_sort(Peri.begin(), Peri.end()); + Peri.erase(std::unique(Peri.begin(), Peri.end()), Peri.end()); + + LoopPeripheralUse use = ContainedInLoop; + for (BlockCountMap::iterator I = usingBlocks_.begin(), E = usingBlocks_.end(); + I != E; ++I) { + const MachineBasicBlock *MBB = I->first; + // Is this a peripheral block? + if (use < MultiPeripheral && + std::binary_search(Peri.begin(), Peri.end(), MBB)) { + if (I->second > 1) use = MultiPeripheral; + else use = SinglePeripheral; + continue; + } + // Is it a loop block? + if (Loop->contains(MBB)) + continue; + // It must be an unrelated block. + return OutsideLoop; + } + return use; +} + +void SplitAnalysis::analyze(const LiveInterval *li) { + clear(); + curli_ = li; + analyseUses(); +} + +const MachineLoop *SplitAnalysis::getBestSplitLoop() { + LoopPtrSet Loops, SecondLoops; + + // Find first-class and second class candidate loops. + // We prefer to split around loops where curli is used outside the periphery. + for (LoopPtrSet::const_iterator I = usingLoops_.begin(), + E = usingLoops_.end(); I != E; ++I) + switch(analyzeLoopPeripheralUse(*I)) { + case OutsideLoop: + Loops.insert(*I); + break; + case MultiPeripheral: + SecondLoops.insert(*I); + break; + default: + continue; + } + + // If there are no first class loops available, look at second class loops. + if (Loops.empty()) + Loops = SecondLoops; + + if (Loops.empty()) + return 0; + + // Pick the earliest loop. + // FIXME: Are there other heuristics to consider? + // - avoid breaking critical edges. + // - avoid impossible loops. + const MachineLoop *Best = 0; + SlotIndex BestIdx; + for (LoopPtrSet::const_iterator I = Loops.begin(), E = Loops.end(); I != E; + ++I) { + SlotIndex Idx = lis_.getMBBStartIdx((*I)->getHeader()); + if (!Best || Idx < BestIdx) + Best = *I, BestIdx = Idx; + } + return Best; +} + +//===----------------------------------------------------------------------===// +// Loop Splitting +//===----------------------------------------------------------------------===// + +bool llvm::splitAroundLoop(SplitAnalysis &sa, const MachineLoop *loop) { + return false; +} + diff --git a/lib/CodeGen/SplitKit.h b/lib/CodeGen/SplitKit.h new file mode 100644 index 00000000000..8716ccbc4de --- /dev/null +++ b/lib/CodeGen/SplitKit.h @@ -0,0 +1,86 @@ +//===---------- SplitKit.cpp - Toolkit for splitting live ranges ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the SplitAnalysis class as well as mutator functions for +// live range splitting. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/DenseMap.h" + +namespace llvm { + +class LiveInterval; +class LiveIntervals; +class MachineBasicBlock; +class MachineInstr; +class MachineFunction; +class MachineFunctionPass; +class MachineLoop; +class MachineLoopInfo; + +class SplitAnalysis { + const MachineFunction &mf_; + const LiveIntervals &lis_; + const MachineLoopInfo &loops_; + + // Current live interval. + const LiveInterval *curli_; + + // Instructions using the the current register. + typedef SmallPtrSet InstrPtrSet; + InstrPtrSet usingInstrs_; + + // The number of instructions using curli in each basic block. + typedef DenseMap BlockCountMap; + BlockCountMap usingBlocks_; + + // Loops where the curent interval is used. + typedef SmallPtrSet LoopPtrSet; + LoopPtrSet usingLoops_; + + // Sumarize statistics by counting instructions using curli_. + void analyseUses(); + +public: + SplitAnalysis(const MachineFunction *mf, const LiveIntervals *lis, + const MachineLoopInfo *mli); + + /// analyze - set curli to the specified interval, and analyze how it may be + /// split. + void analyze(const LiveInterval *li); + + /// clear - clear all data structures so SplitAnalysis is ready to analyze a + /// new interval. + void clear(); + + /// LoopPeripheralUse - how is a variable used in and around a loop? + /// Peripheral blocks are the loop predecessors and exit blocks. + enum LoopPeripheralUse { + ContainedInLoop, // All uses are inside the loop. + SinglePeripheral, // At most one instruction per peripheral block. + MultiPeripheral, // Multiple instructions in some peripheral blocks. + OutsideLoop // Uses outside loop periphery. + }; + + /// analyzeLoopPeripheralUse - Return an enum describing how curli_ is used in + /// and around the Loop. + LoopPeripheralUse analyzeLoopPeripheralUse(const MachineLoop*); + + /// getBestSplitLoop - Return the loop where curli may best be split to a + /// separate register, or NULL. + const MachineLoop *getBestSplitLoop(); +}; + +/// splitAroundLoop - Try to split curli into a separate live interval inside +/// the loop. Retun true on success. +bool splitAroundLoop(SplitAnalysis&, const MachineLoop*); + +}