mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-08-09 11:25:55 +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:
@@ -41,6 +41,7 @@ using namespace llvm;
|
|||||||
STATISTIC(NumGVNInstr, "Number of instructions deleted");
|
STATISTIC(NumGVNInstr, "Number of instructions deleted");
|
||||||
STATISTIC(NumGVNLoad, "Number of loads deleted");
|
STATISTIC(NumGVNLoad, "Number of loads deleted");
|
||||||
STATISTIC(NumGVNPRE, "Number of instructions PRE'd");
|
STATISTIC(NumGVNPRE, "Number of instructions PRE'd");
|
||||||
|
STATISTIC(NumGVNBlocks, "Number of blocks merged");
|
||||||
|
|
||||||
static cl::opt<bool> EnablePRE("enable-pre",
|
static cl::opt<bool> EnablePRE("enable-pre",
|
||||||
cl::init(false), cl::Hidden);
|
cl::init(false), cl::Hidden);
|
||||||
@@ -749,6 +750,7 @@ namespace {
|
|||||||
bool isSafeReplacement(PHINode* p, Instruction* inst);
|
bool isSafeReplacement(PHINode* p, Instruction* inst);
|
||||||
bool performPRE(Function& F);
|
bool performPRE(Function& F);
|
||||||
Value* lookupNumber(BasicBlock* BB, uint32_t num);
|
Value* lookupNumber(BasicBlock* BB, uint32_t num);
|
||||||
|
bool mergeBlockIntoPredecessor(BasicBlock* BB);
|
||||||
};
|
};
|
||||||
|
|
||||||
char GVN::ID = 0;
|
char GVN::ID = 0;
|
||||||
@@ -1324,12 +1326,71 @@ bool GVN::performPRE(Function& F) {
|
|||||||
return changed;
|
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) {
|
bool GVN::iterateOnFunction(Function &F) {
|
||||||
// Clean out global sets from any previous functions
|
// Clean out global sets from any previous functions
|
||||||
VN.clear();
|
VN.clear();
|
||||||
phiMap.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
|
for (DenseMap<BasicBlock*, ValueNumberScope*>::iterator
|
||||||
I = localAvail.begin(), E = localAvail.end(); I != E; ++I)
|
I = localAvail.begin(), E = localAvail.end(); I != E; ++I)
|
||||||
delete I->second;
|
delete I->second;
|
||||||
@@ -1346,5 +1407,5 @@ bool GVN::iterateOnFunction(Function &F) {
|
|||||||
if (EnablePRE)
|
if (EnablePRE)
|
||||||
changed |= performPRE(F);
|
changed |= performPRE(F);
|
||||||
|
|
||||||
return changed;
|
return changed || mergedBlocks;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user