Have GVN do a pre-pass over the CFG that folds away unconditional branches where possible. This allows local PRE to be more aggressive.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@53615 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Owen Anderson 2008-07-15 16:28:06 +00:00
parent b79d2a6bfa
commit 961edc8be6

View File

@ -41,6 +41,7 @@ using namespace llvm;
STATISTIC(NumGVNInstr, "Number of instructions deleted");
STATISTIC(NumGVNLoad, "Number of loads deleted");
STATISTIC(NumGVNPRE, "Number of instructions PRE'd");
STATISTIC(NumGVNBlocks, "Number of blocks merged");
static cl::opt<bool> EnablePRE("enable-pre",
cl::init(false), cl::Hidden);
@ -749,6 +750,7 @@ namespace {
bool isSafeReplacement(PHINode* p, Instruction* inst);
bool performPRE(Function& F);
Value* lookupNumber(BasicBlock* BB, uint32_t num);
bool mergeBlockIntoPredecessor(BasicBlock* BB);
};
char GVN::ID = 0;
@ -1324,12 +1326,71 @@ bool GVN::performPRE(Function& F) {
return changed;
}
// GVN::iterateOnFunction - Executes one iteration of GVN
// mergeBlockIntoPredecessor - If this block is the only successor
// of its predecessor, and the edge is non-critical,
// fold it into that predecessor.
bool GVN::mergeBlockIntoPredecessor(BasicBlock* BB) {
// Can't merge the entry block.
if (pred_begin(BB) == pred_end(BB)) return false;
// Can't merge if there are multiple preds.
if (++pred_begin(BB) != pred_end(BB)) return false;
BasicBlock* PredBB = *pred_begin(BB);
// Can't merge if the edge is critical.
if (PredBB->getTerminator()->getNumSuccessors() != 1) return false;
// Begin by getting rid of unneeded PHIs.
while (PHINode *PN = dyn_cast<PHINode>(&BB->front())) {
PN->replaceAllUsesWith(PN->getIncomingValue(0));
BB->getInstList().pop_front(); // Delete the phi node...
}
// Delete the unconditional branch from the predecessor...
PredBB->getInstList().pop_back();
// Move all definitions in the successor to the predecessor...
PredBB->getInstList().splice(PredBB->end(), BB->getInstList());
// Make all PHI nodes that referred to BB now refer to Pred as their
// source...
BB->replaceAllUsesWith(PredBB);
// Finally, erase the old block and update dominator info.
DominatorTree& DT = getAnalysis<DominatorTree>();
DomTreeNode* DTN = DT[BB];
DomTreeNode* PredDTN = DT[PredBB];
if (DTN) {
SmallPtrSet<DomTreeNode*, 8> Children(DTN->begin(), DTN->end());
for (SmallPtrSet<DomTreeNode*, 8>::iterator DI = Children.begin(),
DE = Children.end(); DI != DE; ++DI)
DT.changeImmediateDominator(*DI, PredDTN);
DT.eraseNode(BB);
}
BB->eraseFromParent();
NumGVNBlocks++;
return true;
}
// iterateOnFunction - Executes one iteration of GVN
bool GVN::iterateOnFunction(Function &F) {
// Clean out global sets from any previous functions
VN.clear();
phiMap.clear();
// Merge unconditional branches, allowing PRE to catch more
// optimization opportunities.
bool mergedBlocks = false;
for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE; ) {
BasicBlock* BB = FI;
++FI;
mergedBlocks |= mergeBlockIntoPredecessor(BB);
}
for (DenseMap<BasicBlock*, ValueNumberScope*>::iterator
I = localAvail.begin(), E = localAvail.end(); I != E; ++I)
delete I->second;
@ -1346,5 +1407,5 @@ bool GVN::iterateOnFunction(Function &F) {
if (EnablePRE)
changed |= performPRE(F);
return changed;
return changed || mergedBlocks;
}