MergeFunctions Pass, introduced total ordering among top-level comparison

methods.
    
Patch changes return type of FunctionComparator::compare() and
FunctionComparator::compare(const BasicBlock*, const BasicBlock*)
methods from bool (equal or not) to {-1, 0, 1} (less, equal, great).
    
This patch belongs to patch series that improves MergeFunctions
performance time from O(N*N) to O(N*log(N)).



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@211437 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Stepan Dyatkovskiy 2014-06-21 17:55:51 +00:00
parent 6b7ff6be9c
commit 23a7bfce97

View File

@ -167,14 +167,14 @@ class FunctionComparator {
public: public:
FunctionComparator(const DataLayout *DL, const Function *F1, FunctionComparator(const DataLayout *DL, const Function *F1,
const Function *F2) const Function *F2)
: F1(F1), F2(F2), DL(DL) {} : FnL(F1), FnR(F2), DL(DL) {}
/// Test whether the two functions have equivalent behaviour. /// Test whether the two functions have equivalent behaviour.
bool compare(); int compare();
private: private:
/// Test whether two basic blocks have equivalent behaviour. /// Test whether two basic blocks have equivalent behaviour.
bool compare(const BasicBlock *BB1, const BasicBlock *BB2); int compare(const BasicBlock *BBL, const BasicBlock *BBR);
/// Constants comparison. /// Constants comparison.
/// Its analog to lexicographical comparison between hypothetical numbers /// Its analog to lexicographical comparison between hypothetical numbers
@ -411,7 +411,7 @@ private:
int cmpAttrs(const AttributeSet L, const AttributeSet R) const; int cmpAttrs(const AttributeSet L, const AttributeSet R) const;
// The two functions undergoing comparison. // The two functions undergoing comparison.
const Function *F1, *F2; const Function *FnL, *FnR;
const DataLayout *DL; const DataLayout *DL;
@ -922,13 +922,13 @@ int FunctionComparator::cmpGEP(const GEPOperator *GEPL,
/// See comments in declaration for more details. /// See comments in declaration for more details.
int FunctionComparator::cmpValues(const Value *L, const Value *R) { int FunctionComparator::cmpValues(const Value *L, const Value *R) {
// Catch self-reference case. // Catch self-reference case.
if (L == F1) { if (L == FnL) {
if (R == F2) if (R == FnR)
return 0; return 0;
return -1; return -1;
} }
if (R == F2) { if (R == FnR) {
if (L == F1) if (L == FnL)
return 0; return 0;
return 1; return 1;
} }
@ -962,90 +962,102 @@ int FunctionComparator::cmpValues(const Value *L, const Value *R) {
return cmpNumbers(LeftSN.first->second, RightSN.first->second); return cmpNumbers(LeftSN.first->second, RightSN.first->second);
} }
// Test whether two basic blocks have equivalent behaviour. // Test whether two basic blocks have equivalent behaviour.
bool FunctionComparator::compare(const BasicBlock *BB1, const BasicBlock *BB2) { int FunctionComparator::compare(const BasicBlock *BBL, const BasicBlock *BBR) {
BasicBlock::const_iterator F1I = BB1->begin(), F1E = BB1->end(); BasicBlock::const_iterator InstL = BBL->begin(), InstLE = BBL->end();
BasicBlock::const_iterator F2I = BB2->begin(), F2E = BB2->end(); BasicBlock::const_iterator InstR = BBR->begin(), InstRE = BBR->end();
do { do {
if (!enumerate(F1I, F2I)) if (int Res = cmpValues(InstL, InstR))
return false; return Res;
if (const GetElementPtrInst *GEP1 = dyn_cast<GetElementPtrInst>(F1I)) { const GetElementPtrInst *GEPL = dyn_cast<GetElementPtrInst>(InstL);
const GetElementPtrInst *GEP2 = dyn_cast<GetElementPtrInst>(F2I); const GetElementPtrInst *GEPR = dyn_cast<GetElementPtrInst>(InstR);
if (!GEP2)
return false;
if (!enumerate(GEP1->getPointerOperand(), GEP2->getPointerOperand())) if (GEPL && !GEPR)
return false; return 1;
if (GEPR && !GEPL)
return -1;
if (!isEquivalentGEP(GEP1, GEP2)) if (GEPL && GEPR) {
return false; if (int Res =
cmpValues(GEPL->getPointerOperand(), GEPR->getPointerOperand()))
return Res;
if (int Res = cmpGEP(GEPL, GEPR))
return Res;
} else { } else {
if (!isEquivalentOperation(F1I, F2I)) if (int Res = cmpOperation(InstL, InstR))
return false; return Res;
assert(InstL->getNumOperands() == InstR->getNumOperands());
assert(F1I->getNumOperands() == F2I->getNumOperands()); for (unsigned i = 0, e = InstL->getNumOperands(); i != e; ++i) {
for (unsigned i = 0, e = F1I->getNumOperands(); i != e; ++i) { Value *OpL = InstL->getOperand(i);
Value *OpF1 = F1I->getOperand(i); Value *OpR = InstR->getOperand(i);
Value *OpF2 = F2I->getOperand(i); if (int Res = cmpValues(OpL, OpR))
return Res;
if (!enumerate(OpF1, OpF2)) if (int Res = cmpNumbers(OpL->getValueID(), OpR->getValueID()))
return false; return Res;
// TODO: Already checked in cmpOperation
if (OpF1->getValueID() != OpF2->getValueID() || if (int Res = cmpType(OpL->getType(), OpR->getType()))
!isEquivalentType(OpF1->getType(), OpF2->getType())) return Res;
return false;
} }
} }
++F1I, ++F2I; ++InstL, ++InstR;
} while (F1I != F1E && F2I != F2E); } while (InstL != InstLE && InstR != InstRE);
return F1I == F1E && F2I == F2E; if (InstL != InstLE && InstR == InstRE)
return 1;
if (InstL == InstLE && InstR != InstRE)
return -1;
return 0;
} }
// Test whether the two functions have equivalent behaviour. // Test whether the two functions have equivalent behaviour.
bool FunctionComparator::compare() { int FunctionComparator::compare() {
// We need to recheck everything, but check the things that weren't included
// in the hash first.
sn_mapL.clear(); sn_mapL.clear();
sn_mapR.clear(); sn_mapR.clear();
if (F1->getAttributes() != F2->getAttributes()) if (int Res = cmpAttrs(FnL->getAttributes(), FnR->getAttributes()))
return false; return Res;
if (F1->hasGC() != F2->hasGC()) if (int Res = cmpNumbers(FnL->hasGC(), FnR->hasGC()))
return false; return Res;
if (F1->hasGC() && F1->getGC() != F2->getGC()) if (FnL->hasGC()) {
return false; if (int Res = cmpNumbers((uint64_t)FnL->getGC(), (uint64_t)FnR->getGC()))
return Res;
}
if (F1->hasSection() != F2->hasSection()) if (int Res = cmpNumbers(FnL->hasSection(), FnR->hasSection()))
return false; return Res;
if (F1->hasSection() && F1->getSection() != F2->getSection()) if (FnL->hasSection()) {
return false; if (int Res = cmpStrings(FnL->getSection(), FnR->getSection()))
return Res;
}
if (F1->isVarArg() != F2->isVarArg()) if (int Res = cmpNumbers(FnL->isVarArg(), FnR->isVarArg()))
return false; return Res;
// TODO: if it's internal and only used in direct calls, we could handle this // TODO: if it's internal and only used in direct calls, we could handle this
// case too. // case too.
if (F1->getCallingConv() != F2->getCallingConv()) if (int Res = cmpNumbers(FnL->getCallingConv(), FnR->getCallingConv()))
return false; return Res;
if (!isEquivalentType(F1->getFunctionType(), F2->getFunctionType())) if (int Res = cmpType(FnL->getFunctionType(), FnR->getFunctionType()))
return false; return Res;
assert(F1->arg_size() == F2->arg_size() && assert(FnL->arg_size() == FnR->arg_size() &&
"Identically typed functions have different numbers of args!"); "Identically typed functions have different numbers of args!");
// Visit the arguments so that they get enumerated in the order they're // Visit the arguments so that they get enumerated in the order they're
// passed in. // passed in.
for (Function::const_arg_iterator f1i = F1->arg_begin(), for (Function::const_arg_iterator ArgLI = FnL->arg_begin(),
f2i = F2->arg_begin(), f1e = F1->arg_end(); f1i != f1e; ++f1i, ++f2i) { ArgRI = FnR->arg_begin(),
if (!enumerate(f1i, f2i)) ArgLE = FnL->arg_end();
ArgLI != ArgLE; ++ArgLI, ++ArgRI) {
if (cmpValues(ArgLI, ArgRI) != 0)
llvm_unreachable("Arguments repeat!"); llvm_unreachable("Arguments repeat!");
} }
@ -1053,33 +1065,36 @@ bool FunctionComparator::compare() {
// linked list is immaterial. Our walk starts at the entry block for both // linked list is immaterial. Our walk starts at the entry block for both
// functions, then takes each block from each terminator in order. As an // functions, then takes each block from each terminator in order. As an
// artifact, this also means that unreachable blocks are ignored. // artifact, this also means that unreachable blocks are ignored.
SmallVector<const BasicBlock *, 8> F1BBs, F2BBs; SmallVector<const BasicBlock *, 8> FnLBBs, FnRBBs;
SmallSet<const BasicBlock *, 128> VisitedBBs; // in terms of F1. SmallSet<const BasicBlock *, 128> VisitedBBs; // in terms of F1.
F1BBs.push_back(&F1->getEntryBlock()); FnLBBs.push_back(&FnL->getEntryBlock());
F2BBs.push_back(&F2->getEntryBlock()); FnRBBs.push_back(&FnR->getEntryBlock());
VisitedBBs.insert(F1BBs[0]); VisitedBBs.insert(FnLBBs[0]);
while (!F1BBs.empty()) { while (!FnLBBs.empty()) {
const BasicBlock *F1BB = F1BBs.pop_back_val(); const BasicBlock *BBL = FnLBBs.pop_back_val();
const BasicBlock *F2BB = F2BBs.pop_back_val(); const BasicBlock *BBR = FnRBBs.pop_back_val();
if (!enumerate(F1BB, F2BB) || !compare(F1BB, F2BB)) if (int Res = cmpValues(BBL, BBR))
return false; return Res;
const TerminatorInst *F1TI = F1BB->getTerminator(); if (int Res = compare(BBL, BBR))
const TerminatorInst *F2TI = F2BB->getTerminator(); return Res;
assert(F1TI->getNumSuccessors() == F2TI->getNumSuccessors()); const TerminatorInst *TermL = BBL->getTerminator();
for (unsigned i = 0, e = F1TI->getNumSuccessors(); i != e; ++i) { const TerminatorInst *TermR = BBR->getTerminator();
if (!VisitedBBs.insert(F1TI->getSuccessor(i)))
assert(TermL->getNumSuccessors() == TermR->getNumSuccessors());
for (unsigned i = 0, e = TermL->getNumSuccessors(); i != e; ++i) {
if (!VisitedBBs.insert(TermL->getSuccessor(i)))
continue; continue;
F1BBs.push_back(F1TI->getSuccessor(i)); FnLBBs.push_back(TermL->getSuccessor(i));
F2BBs.push_back(F2TI->getSuccessor(i)); FnRBBs.push_back(TermR->getSuccessor(i));
} }
} }
return true; return 0;
} }
namespace { namespace {
@ -1226,8 +1241,8 @@ bool DenseMapInfo<ComparableFunction>::isEqual(const ComparableFunction &LHS,
assert(LHS.getDataLayout() == RHS.getDataLayout() && assert(LHS.getDataLayout() == RHS.getDataLayout() &&
"Comparing functions for different targets"); "Comparing functions for different targets");
return FunctionComparator(LHS.getDataLayout(), LHS.getFunc(), return FunctionComparator(LHS.getDataLayout(), LHS.getFunc(), RHS.getFunc())
RHS.getFunc()).compare(); .compare() == 0;
} }
// Replace direct callers of Old with New. // Replace direct callers of Old with New.