Implement loop splitting analysis.

Determine which loop exit blocks need a 'pre-exit' block inserted.
Recognize when this would be impossible.

llvm-svn: 108941
This commit is contained in:
Jakob Stoklund Olesen 2010-07-20 21:46:58 +00:00
parent f9e6cc9af1
commit ed4075cc3b
3 changed files with 189 additions and 19 deletions

View File

@ -509,6 +509,12 @@ protected:
} }
}; };
template<class BlockT, class LoopT>
raw_ostream& operator<<(raw_ostream &OS, const LoopBase<BlockT, LoopT> &Loop) {
Loop.print(OS);
return OS;
}
class Loop : public LoopBase<BasicBlock, Loop> { class Loop : public LoopBase<BasicBlock, Loop> {
public: public:
Loop() {} Loop() {}

View File

@ -18,11 +18,17 @@
#include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineLoopInfo.h" #include "llvm/CodeGen/MachineLoopInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h" #include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h" #include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
using namespace llvm; using namespace llvm;
static cl::opt<bool>
AllowSplit("spiller-splits-edges",
cl::desc("Allow critical edge splitting during spilling"));
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Split Analysis // Split Analysis
@ -34,6 +40,7 @@ SplitAnalysis::SplitAnalysis(const MachineFunction *mf,
: mf_(*mf), : mf_(*mf),
lis_(*lis), lis_(*lis),
loops_(*mli), loops_(*mli),
tii_(*mf->getTarget().getInstrInfo()),
curli_(0) {} curli_(0) {}
void SplitAnalysis::clear() { void SplitAnalysis::clear() {
@ -42,6 +49,12 @@ void SplitAnalysis::clear() {
usingLoops_.clear(); usingLoops_.clear();
} }
bool SplitAnalysis::canAnalyzeBranch(const MachineBasicBlock *MBB) {
MachineBasicBlock *T, *F;
SmallVector<MachineOperand, 4> Cond;
return !tii_.AnalyzeBranch(const_cast<MachineBasicBlock&>(*MBB), T, F, Cond);
}
/// analyzeUses - Count instructions, basic blocks, and loops using curli. /// analyzeUses - Count instructions, basic blocks, and loops using curli.
void SplitAnalysis::analyzeUses() { void SplitAnalysis::analyzeUses() {
const MachineRegisterInfo &MRI = mf_.getRegInfo(); const MachineRegisterInfo &MRI = mf_.getRegInfo();
@ -62,29 +75,49 @@ void SplitAnalysis::analyzeUses() {
<< *curli_ << "\n"); << *curli_ << "\n");
} }
SplitAnalysis::LoopPeripheralUse // Get three sets of basic blocks surrounding a loop: Blocks inside the loop,
SplitAnalysis::analyzeLoopPeripheralUse(const MachineLoop *Loop) { // predecessor blocks, and exit blocks.
// Peripheral blocks. void SplitAnalysis::getLoopBlocks(const MachineLoop *Loop, LoopBlocks &Blocks) {
SmallVector<MachineBasicBlock*, 16> Peri; Blocks.clear();
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());
// Blocks in the loop.
Blocks.Loop.insert(Loop->block_begin(), Loop->block_end());
// Predecessor blocks.
const MachineBasicBlock *Header = Loop->getHeader();
for (MachineBasicBlock::const_pred_iterator I = Header->pred_begin(),
E = Header->pred_end(); I != E; ++I)
if (!Blocks.Loop.count(*I))
Blocks.Preds.insert(*I);
// Exit blocks.
for (MachineLoop::block_iterator I = Loop->block_begin(),
E = Loop->block_end(); I != E; ++I) {
const MachineBasicBlock *MBB = *I;
for (MachineBasicBlock::const_succ_iterator SI = MBB->succ_begin(),
SE = MBB->succ_end(); SI != SE; ++SI)
if (!Blocks.Loop.count(*SI))
Blocks.Exits.insert(*SI);
}
}
/// analyzeLoopPeripheralUse - Return an enum describing how curli_ is used in
/// and around the Loop.
SplitAnalysis::LoopPeripheralUse SplitAnalysis::
analyzeLoopPeripheralUse(const SplitAnalysis::LoopBlocks &Blocks) {
LoopPeripheralUse use = ContainedInLoop; LoopPeripheralUse use = ContainedInLoop;
for (BlockCountMap::iterator I = usingBlocks_.begin(), E = usingBlocks_.end(); for (BlockCountMap::iterator I = usingBlocks_.begin(), E = usingBlocks_.end();
I != E; ++I) { I != E; ++I) {
const MachineBasicBlock *MBB = I->first; const MachineBasicBlock *MBB = I->first;
// Is this a peripheral block? // Is this a peripheral block?
if (use < MultiPeripheral && if (use < MultiPeripheral &&
std::binary_search(Peri.begin(), Peri.end(), MBB)) { (Blocks.Preds.count(MBB) || Blocks.Exits.count(MBB))) {
if (I->second > 1) use = MultiPeripheral; if (I->second > 1) use = MultiPeripheral;
else use = SinglePeripheral; else use = SinglePeripheral;
continue; continue;
} }
// Is it a loop block? // Is it a loop block?
if (Loop->contains(MBB)) if (Blocks.Loop.count(MBB))
continue; continue;
// It must be an unrelated block. // It must be an unrelated block.
return OutsideLoop; return OutsideLoop;
@ -92,6 +125,80 @@ SplitAnalysis::analyzeLoopPeripheralUse(const MachineLoop *Loop) {
return use; return use;
} }
/// getCriticalExits - It may be necessary to partially break critical edges
/// leaving the loop if an exit block has phi uses of curli. Collect the exit
/// blocks that need special treatment into CriticalExits.
void SplitAnalysis::getCriticalExits(const SplitAnalysis::LoopBlocks &Blocks,
BlockPtrSet &CriticalExits) {
CriticalExits.clear();
// A critical exit block contains a phi def of curli, and has a predecessor
// that is not in the loop nor a loop predecessor.
// For such an exit block, the edges carrying the new variable must be moved
// to a new pre-exit block.
for (BlockPtrSet::iterator I = Blocks.Exits.begin(), E = Blocks.Exits.end();
I != E; ++I) {
const MachineBasicBlock *Succ = *I;
SlotIndex SuccIdx = lis_.getMBBStartIdx(Succ);
VNInfo *SuccVNI = curli_->getVNInfoAt(SuccIdx);
// This exit may not have curli live in at all. No need to split.
if (!SuccVNI)
continue;
// If this is not a PHI def, it is either using a value from before the
// loop, or a value defined inside the loop. Both are safe.
if (!SuccVNI->isPHIDef() || SuccVNI->def.getBaseIndex() != SuccIdx)
continue;
// This exit block does have a PHI. Does it also have a predecessor that is
// not a loop block or loop predecessor?
for (MachineBasicBlock::const_pred_iterator PI = Succ->pred_begin(),
PE = Succ->pred_end(); PI != PE; ++PI) {
const MachineBasicBlock *Pred = *PI;
if (Blocks.Loop.count(Pred) || Blocks.Preds.count(Pred))
continue;
// This is a critical exit block, and we need to split the exit edge.
CriticalExits.insert(Succ);
break;
}
}
}
/// canSplitCriticalExits - Return true if it is possible to insert new exit
/// blocks before the blocks in CriticalExits.
bool
SplitAnalysis::canSplitCriticalExits(const SplitAnalysis::LoopBlocks &Blocks,
BlockPtrSet &CriticalExits) {
// If we don't allow critical edge splitting, require no critical exits.
if (!AllowSplit)
return CriticalExits.empty();
for (BlockPtrSet::iterator I = CriticalExits.begin(), E = CriticalExits.end();
I != E; ++I) {
const MachineBasicBlock *Succ = *I;
// We want to insert a new pre-exit MBB before Succ, and change all the
// in-loop blocks to branch to the pre-exit instead of Succ.
// Check that all the in-loop predecessors can be changed.
for (MachineBasicBlock::const_pred_iterator PI = Succ->pred_begin(),
PE = Succ->pred_end(); PI != PE; ++PI) {
const MachineBasicBlock *Pred = *PI;
// The external predecessors won't be altered.
if (!Blocks.Loop.count(Pred) && !Blocks.Preds.count(Pred))
continue;
if (!canAnalyzeBranch(Pred))
return false;
}
// If Succ's layout predecessor falls through, that too must be analyzable.
// We need to insert the pre-exit block in the gap.
MachineFunction::const_iterator MFI = Succ;
if (MFI == mf_.begin())
continue;
if (!canAnalyzeBranch(--MFI))
return false;
}
// No problems found.
return true;
}
void SplitAnalysis::analyze(const LiveInterval *li) { void SplitAnalysis::analyze(const LiveInterval *li) {
clear(); clear();
curli_ = li; curli_ = li;
@ -99,22 +206,46 @@ void SplitAnalysis::analyze(const LiveInterval *li) {
} }
const MachineLoop *SplitAnalysis::getBestSplitLoop() { const MachineLoop *SplitAnalysis::getBestSplitLoop() {
assert(curli_ && "Call analyze() before getBestSplitLoop");
if (usingLoops_.empty())
return 0;
LoopPtrSet Loops, SecondLoops; LoopPtrSet Loops, SecondLoops;
LoopBlocks Blocks;
BlockPtrSet CriticalExits;
// Find first-class and second class candidate loops. // Find first-class and second class candidate loops.
// We prefer to split around loops where curli is used outside the periphery. // We prefer to split around loops where curli is used outside the periphery.
for (LoopPtrSet::const_iterator I = usingLoops_.begin(), for (LoopPtrSet::const_iterator I = usingLoops_.begin(),
E = usingLoops_.end(); I != E; ++I) E = usingLoops_.end(); I != E; ++I) {
switch(analyzeLoopPeripheralUse(*I)) { getLoopBlocks(*I, Blocks);
LoopPtrSet *LPS = 0;
switch(analyzeLoopPeripheralUse(Blocks)) {
case OutsideLoop: case OutsideLoop:
Loops.insert(*I); LPS = &Loops;
break; break;
case MultiPeripheral: case MultiPeripheral:
SecondLoops.insert(*I); LPS = &SecondLoops;
break; break;
default: case ContainedInLoop:
DEBUG(dbgs() << "ContainedInLoop: " << **I);
continue;
case SinglePeripheral:
DEBUG(dbgs() << "SinglePeripheral: " << **I);
continue; continue;
} }
// Will it be possible to split around this loop?
getCriticalExits(Blocks, CriticalExits);
DEBUG(dbgs() << CriticalExits.size() << " critical exits: " << **I);
if (!canSplitCriticalExits(Blocks, CriticalExits))
continue;
// This is a possible split.
assert(LPS);
LPS->insert(*I);
}
DEBUG(dbgs() << "Got " << Loops.size() << " + " << SecondLoops.size()
<< " candidate loops\n");
// If there are no first class loops available, look at second class loops. // If there are no first class loops available, look at second class loops.
if (Loops.empty()) if (Loops.empty())
@ -125,8 +256,6 @@ const MachineLoop *SplitAnalysis::getBestSplitLoop() {
// Pick the earliest loop. // Pick the earliest loop.
// FIXME: Are there other heuristics to consider? // FIXME: Are there other heuristics to consider?
// - avoid breaking critical edges.
// - avoid impossible loops.
const MachineLoop *Best = 0; const MachineLoop *Best = 0;
SlotIndex BestIdx; SlotIndex BestIdx;
for (LoopPtrSet::const_iterator I = Loops.begin(), E = Loops.end(); I != E; for (LoopPtrSet::const_iterator I = Loops.begin(), E = Loops.end(); I != E;
@ -135,6 +264,7 @@ const MachineLoop *SplitAnalysis::getBestSplitLoop() {
if (!Best || Idx < BestIdx) if (!Best || Idx < BestIdx)
Best = *I, BestIdx = Idx; Best = *I, BestIdx = Idx;
} }
DEBUG(dbgs() << "Best: " << *Best);
return Best; return Best;
} }

View File

@ -25,11 +25,13 @@ class MachineFunction;
class MachineFunctionPass; class MachineFunctionPass;
class MachineLoop; class MachineLoop;
class MachineLoopInfo; class MachineLoopInfo;
class TargetInstrInfo;
class SplitAnalysis { class SplitAnalysis {
const MachineFunction &mf_; const MachineFunction &mf_;
const LiveIntervals &lis_; const LiveIntervals &lis_;
const MachineLoopInfo &loops_; const MachineLoopInfo &loops_;
const TargetInstrInfo &tii_;
// Current live interval. // Current live interval.
const LiveInterval *curli_; const LiveInterval *curli_;
@ -49,6 +51,10 @@ class SplitAnalysis {
// Sumarize statistics by counting instructions using curli_. // Sumarize statistics by counting instructions using curli_.
void analyzeUses(); void analyzeUses();
/// canAnalyzeBranch - Return true if MBB ends in a branch that can be
/// analyzed.
bool canAnalyzeBranch(const MachineBasicBlock *MBB);
public: public:
SplitAnalysis(const MachineFunction *mf, const LiveIntervals *lis, SplitAnalysis(const MachineFunction *mf, const LiveIntervals *lis,
const MachineLoopInfo *mli); const MachineLoopInfo *mli);
@ -61,6 +67,24 @@ public:
/// new interval. /// new interval.
void clear(); void clear();
typedef SmallPtrSet<const MachineBasicBlock*, 16> BlockPtrSet;
// Sets of basic blocks surrounding a machine loop.
struct LoopBlocks {
BlockPtrSet Loop; // Blocks in the loop.
BlockPtrSet Preds; // Loop predecessor blocks.
BlockPtrSet Exits; // Loop exit blocks.
void clear() {
Loop.clear();
Preds.clear();
Exits.clear();
}
};
// Calculate the block sets surrounding the loop.
void getLoopBlocks(const MachineLoop *Loop, LoopBlocks &Blocks);
/// LoopPeripheralUse - how is a variable used in and around a loop? /// LoopPeripheralUse - how is a variable used in and around a loop?
/// Peripheral blocks are the loop predecessors and exit blocks. /// Peripheral blocks are the loop predecessors and exit blocks.
enum LoopPeripheralUse { enum LoopPeripheralUse {
@ -72,7 +96,17 @@ public:
/// analyzeLoopPeripheralUse - Return an enum describing how curli_ is used in /// analyzeLoopPeripheralUse - Return an enum describing how curli_ is used in
/// and around the Loop. /// and around the Loop.
LoopPeripheralUse analyzeLoopPeripheralUse(const MachineLoop*); LoopPeripheralUse analyzeLoopPeripheralUse(const LoopBlocks&);
/// getCriticalExits - It may be necessary to partially break critical edges
/// leaving the loop if an exit block has phi uses of curli. Collect the exit
/// blocks that need special treatment into CriticalExits.
void getCriticalExits(const LoopBlocks &Blocks, BlockPtrSet &CriticalExits);
/// canSplitCriticalExits - Return true if it is possible to insert new exit
/// blocks before the blocks in CriticalExits.
bool canSplitCriticalExits(const LoopBlocks &Blocks,
BlockPtrSet &CriticalExits);
/// getBestSplitLoop - Return the loop where curli may best be split to a /// getBestSplitLoop - Return the loop where curli may best be split to a
/// separate register, or NULL. /// separate register, or NULL.