From 961edc8be60e7a4d02ad4729428a09da660d3901 Mon Sep 17 00:00:00 2001 From: Owen Anderson Date: Tue, 15 Jul 2008 16:28:06 +0000 Subject: [PATCH] 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 --- lib/Transforms/Scalar/GVN.cpp | 65 +++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/lib/Transforms/Scalar/GVN.cpp b/lib/Transforms/Scalar/GVN.cpp index 18a9661684f..7bbfbadf017 100644 --- a/lib/Transforms/Scalar/GVN.cpp +++ b/lib/Transforms/Scalar/GVN.cpp @@ -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 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(&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(); + DomTreeNode* DTN = DT[BB]; + DomTreeNode* PredDTN = DT[PredBB]; + + if (DTN) { + SmallPtrSet Children(DTN->begin(), DTN->end()); + for (SmallPtrSet::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::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; }