mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-08-09 11:25:55 +00:00
[GVN] Split critical-edge on the fly, instead of postpone edge-splitting to next
iteration. This on step toward non-iterative GVN. My local hack suggests that getting rid of iteration will speedup GVN by 30%+ on a medium sized input (2k LOC, C++). I cannot explain why not 2x or more at this moment. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@181532 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -45,6 +45,7 @@
|
|||||||
#include "llvm/Target/TargetLibraryInfo.h"
|
#include "llvm/Target/TargetLibraryInfo.h"
|
||||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||||
#include "llvm/Transforms/Utils/SSAUpdater.h"
|
#include "llvm/Transforms/Utils/SSAUpdater.h"
|
||||||
|
#include <vector>
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
using namespace PatternMatch;
|
using namespace PatternMatch;
|
||||||
|
|
||||||
@@ -692,6 +693,7 @@ namespace {
|
|||||||
void cleanupGlobalSets();
|
void cleanupGlobalSets();
|
||||||
void verifyRemoved(const Instruction *I) const;
|
void verifyRemoved(const Instruction *I) const;
|
||||||
bool splitCriticalEdges();
|
bool splitCriticalEdges();
|
||||||
|
BasicBlock *splitCriticalEdges(BasicBlock *Pred, BasicBlock *Succ);
|
||||||
unsigned replaceAllDominatedUsesWith(Value *From, Value *To,
|
unsigned replaceAllDominatedUsesWith(Value *From, Value *To,
|
||||||
const BasicBlockEdge &Root);
|
const BasicBlockEdge &Root);
|
||||||
bool propagateEquality(Value *LHS, Value *RHS, const BasicBlockEdge &Root);
|
bool propagateEquality(Value *LHS, Value *RHS, const BasicBlockEdge &Root);
|
||||||
@@ -1513,7 +1515,7 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock,
|
|||||||
for (unsigned i = 0, e = UnavailableBlocks.size(); i != e; ++i)
|
for (unsigned i = 0, e = UnavailableBlocks.size(); i != e; ++i)
|
||||||
FullyAvailableBlocks[UnavailableBlocks[i]] = false;
|
FullyAvailableBlocks[UnavailableBlocks[i]] = false;
|
||||||
|
|
||||||
SmallVector<std::pair<TerminatorInst*, unsigned>, 4> NeedToSplit;
|
SmallVector<BasicBlock *, 4> CriticalEdgePred;
|
||||||
for (pred_iterator PI = pred_begin(LoadBB), E = pred_end(LoadBB);
|
for (pred_iterator PI = pred_begin(LoadBB), E = pred_end(LoadBB);
|
||||||
PI != E; ++PI) {
|
PI != E; ++PI) {
|
||||||
BasicBlock *Pred = *PI;
|
BasicBlock *Pred = *PI;
|
||||||
@@ -1536,20 +1538,14 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned SuccNum = GetSuccessorNumber(Pred, LoadBB);
|
CriticalEdgePred.push_back(Pred);
|
||||||
NeedToSplit.push_back(std::make_pair(Pred->getTerminator(), SuccNum));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!NeedToSplit.empty()) {
|
|
||||||
toSplit.append(NeedToSplit.begin(), NeedToSplit.end());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decide whether PRE is profitable for this load.
|
// Decide whether PRE is profitable for this load.
|
||||||
unsigned NumUnavailablePreds = PredLoads.size();
|
unsigned NumUnavailablePreds = PredLoads.size();
|
||||||
assert(NumUnavailablePreds != 0 &&
|
assert(NumUnavailablePreds != 0 &&
|
||||||
"Fully available value should be eliminated above!");
|
"Fully available value should already be eliminated!");
|
||||||
|
|
||||||
// If this load is unavailable in multiple predecessors, reject it.
|
// If this load is unavailable in multiple predecessors, reject it.
|
||||||
// FIXME: If we could restructure the CFG, we could make a common pred with
|
// FIXME: If we could restructure the CFG, we could make a common pred with
|
||||||
@@ -1558,6 +1554,17 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock,
|
|||||||
if (NumUnavailablePreds != 1)
|
if (NumUnavailablePreds != 1)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// Split critical edges, and update the unavailable predecessors accordingly.
|
||||||
|
for (SmallVector<BasicBlock *, 4>::iterator I = CriticalEdgePred.begin(),
|
||||||
|
E = CriticalEdgePred.end(); I != E; I++) {
|
||||||
|
BasicBlock *OrigPred = *I;
|
||||||
|
BasicBlock *NewPred = splitCriticalEdges(OrigPred, LoadBB);
|
||||||
|
PredLoads.erase(OrigPred);
|
||||||
|
PredLoads[NewPred] = 0;
|
||||||
|
DEBUG(dbgs() << "Split critical edge " << OrigPred->getName() << "->"
|
||||||
|
<< LoadBB->getName() << '\n');
|
||||||
|
}
|
||||||
|
|
||||||
// Check if the load can safely be moved to all the unavailable predecessors.
|
// Check if the load can safely be moved to all the unavailable predecessors.
|
||||||
bool CanDoPRE = true;
|
bool CanDoPRE = true;
|
||||||
SmallVector<Instruction*, 8> NewInsts;
|
SmallVector<Instruction*, 8> NewInsts;
|
||||||
@@ -1594,7 +1601,9 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock,
|
|||||||
if (MD) MD->removeInstruction(I);
|
if (MD) MD->removeInstruction(I);
|
||||||
I->eraseFromParent();
|
I->eraseFromParent();
|
||||||
}
|
}
|
||||||
return false;
|
// HINT:Don't revert the edge-splitting as following transformation may
|
||||||
|
// also need to split these critial edges.
|
||||||
|
return !CriticalEdgePred.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Okay, we can eliminate this load by inserting a reload in the predecessor
|
// Okay, we can eliminate this load by inserting a reload in the predecessor
|
||||||
@@ -2297,8 +2306,6 @@ bool GVN::runOnFunction(Function& F) {
|
|||||||
while (ShouldContinue) {
|
while (ShouldContinue) {
|
||||||
DEBUG(dbgs() << "GVN iteration: " << Iteration << "\n");
|
DEBUG(dbgs() << "GVN iteration: " << Iteration << "\n");
|
||||||
ShouldContinue = iterateOnFunction(F);
|
ShouldContinue = iterateOnFunction(F);
|
||||||
if (splitCriticalEdges())
|
|
||||||
ShouldContinue = true;
|
|
||||||
Changed |= ShouldContinue;
|
Changed |= ShouldContinue;
|
||||||
++Iteration;
|
++Iteration;
|
||||||
}
|
}
|
||||||
@@ -2310,6 +2317,7 @@ bool GVN::runOnFunction(Function& F) {
|
|||||||
Changed |= PREChanged;
|
Changed |= PREChanged;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Should perform GVN again after PRE does something. PRE can move
|
// FIXME: Should perform GVN again after PRE does something. PRE can move
|
||||||
// computations into blocks where they become fully redundant. Note that
|
// computations into blocks where they become fully redundant. Note that
|
||||||
// we can't do this until PRE's critical edge splitting updates memdep.
|
// we can't do this until PRE's critical edge splitting updates memdep.
|
||||||
@@ -2543,6 +2551,15 @@ bool GVN::performPRE(Function &F) {
|
|||||||
return Changed;
|
return Changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Split the critical edge connecting the given two blocks, and return
|
||||||
|
/// the block inserted to the critical edge.
|
||||||
|
BasicBlock *GVN::splitCriticalEdges(BasicBlock *Pred, BasicBlock *Succ) {
|
||||||
|
BasicBlock *BB = SplitCriticalEdge(Pred, Succ, this);
|
||||||
|
if (MD)
|
||||||
|
MD->invalidateCachedPredecessors();
|
||||||
|
return BB;
|
||||||
|
}
|
||||||
|
|
||||||
/// splitCriticalEdges - Split critical edges found during the previous
|
/// splitCriticalEdges - Split critical edges found during the previous
|
||||||
/// iteration that may enable further optimization.
|
/// iteration that may enable further optimization.
|
||||||
bool GVN::splitCriticalEdges() {
|
bool GVN::splitCriticalEdges() {
|
||||||
@@ -2569,9 +2586,18 @@ bool GVN::iterateOnFunction(Function &F) {
|
|||||||
RE = RPOT.end(); RI != RE; ++RI)
|
RE = RPOT.end(); RI != RE; ++RI)
|
||||||
Changed |= processBlock(*RI);
|
Changed |= processBlock(*RI);
|
||||||
#else
|
#else
|
||||||
|
// Save the blocks this function have before transformation begins. GVN may
|
||||||
|
// split critical edge, and hence may invalidate the RPO/DT iterator.
|
||||||
|
//
|
||||||
|
std::vector<BasicBlock *> BBVect;
|
||||||
|
BBVect.reserve(256);
|
||||||
for (df_iterator<DomTreeNode*> DI = df_begin(DT->getRootNode()),
|
for (df_iterator<DomTreeNode*> DI = df_begin(DT->getRootNode()),
|
||||||
DE = df_end(DT->getRootNode()); DI != DE; ++DI)
|
DE = df_end(DT->getRootNode()); DI != DE; ++DI)
|
||||||
Changed |= processBlock(DI->getBlock());
|
BBVect.push_back(DI->getBlock());
|
||||||
|
|
||||||
|
for (std::vector<BasicBlock *>::iterator I = BBVect.begin(), E = BBVect.end();
|
||||||
|
I != E; I++)
|
||||||
|
Changed |= processBlock(*I);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return Changed;
|
return Changed;
|
||||||
|
Reference in New Issue
Block a user