mirror of
https://github.com/RPCSX/llvm.git
synced 2025-02-11 15:26:40 +00:00
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:
parent
b79d2a6bfa
commit
961edc8be6
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user