summaryrefslogtreecommitdiffstats
path: root/lib/Transforms/IPO/MergeFunctions.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Transforms/IPO/MergeFunctions.cpp')
-rw-r--r--lib/Transforms/IPO/MergeFunctions.cpp658
1 files changed, 278 insertions, 380 deletions
diff --git a/lib/Transforms/IPO/MergeFunctions.cpp b/lib/Transforms/IPO/MergeFunctions.cpp
index aeeafe7..5d838f9 100644
--- a/lib/Transforms/IPO/MergeFunctions.cpp
+++ b/lib/Transforms/IPO/MergeFunctions.cpp
@@ -29,44 +29,27 @@
//
// Many functions have their address taken by the virtual function table for
// the object they belong to. However, as long as it's only used for a lookup
-// and call, this is irrelevant, and we'd like to fold such implementations.
+// and call, this is irrelevant, and we'd like to fold such functions.
//
-// * use SCC to cut down on pair-wise comparisons and solve larger cycles.
+// * switch from n^2 pair-wise comparisons to an n-way comparison for each
+// bucket.
//
-// The current implementation loops over a pair-wise comparison of all
-// functions in the program where the two functions in the pair are treated as
-// assumed to be equal until proven otherwise. We could both use fewer
-// comparisons and optimize more complex cases if we used strongly connected
-// components of the call graph.
-//
-// * be smarter about bitcast.
+// * be smarter about bitcasts.
//
// In order to fold functions, we will sometimes add either bitcast instructions
// or bitcast constant expressions. Unfortunately, this can confound further
// analysis since the two functions differ where one has a bitcast and the
-// other doesn't. We should learn to peer through bitcasts without imposing bad
-// performance properties.
-//
-// * don't emit aliases for Mach-O.
-//
-// Mach-O doesn't support aliases which means that we must avoid introducing
-// them in the bitcode on architectures which don't support them, such as
-// Mac OSX. There's a few approaches to this problem;
-// a) teach codegen to lower global aliases to thunks on platforms which don't
-// support them.
-// b) always emit thunks, and create a separate thunk-to-alias pass which
-// runs on ELF systems. This has the added benefit of transforming other
-// thunks such as those produced by a C++ frontend into aliases when legal
-// to do so.
+// other doesn't. We should learn to look through bitcasts.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "mergefunc"
#include "llvm/Transforms/IPO.h"
-#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Constants.h"
#include "llvm/InlineAsm.h"
#include "llvm/Instructions.h"
@@ -76,68 +59,103 @@
#include "llvm/Support/CallSite.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/IRBuilder.h"
+#include "llvm/Support/ValueHandle.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetData.h"
-#include <map>
#include <vector>
using namespace llvm;
STATISTIC(NumFunctionsMerged, "Number of functions merged");
namespace {
+ /// MergeFunctions finds functions which will generate identical machine code,
+ /// by considering all pointer types to be equivalent. Once identified,
+ /// MergeFunctions will fold them by replacing a call to one to a call to a
+ /// bitcast of the other.
+ ///
class MergeFunctions : public ModulePass {
public:
- static char ID; // Pass identification, replacement for typeid
- MergeFunctions() : ModulePass(&ID) {}
+ static char ID;
+ MergeFunctions() : ModulePass(ID) {}
bool runOnModule(Module &M);
private:
- bool isEquivalentGEP(const GetElementPtrInst *GEP1,
- const GetElementPtrInst *GEP2);
-
- bool equals(const BasicBlock *BB1, const BasicBlock *BB2);
- bool equals(const Function *F, const Function *G);
+ /// MergeTwoFunctions - Merge two equivalent functions. Upon completion, G
+ /// may be deleted, or may be converted into a thunk. In either case, it
+ /// should never be visited again.
+ void MergeTwoFunctions(Function *F, Function *G) const;
- bool compare(const Value *V1, const Value *V2);
+ /// WriteThunk - Replace G with a simple tail call to bitcast(F). Also
+ /// replace direct uses of G with bitcast(F).
+ void WriteThunk(Function *F, Function *G) const;
- const Function *LHS, *RHS;
- typedef DenseMap<const Value *, unsigned long> IDMap;
- IDMap Map;
- DenseMap<const Function *, IDMap> Domains;
- DenseMap<const Function *, unsigned long> DomainCount;
TargetData *TD;
};
}
char MergeFunctions::ID = 0;
-static RegisterPass<MergeFunctions> X("mergefunc", "Merge Functions");
+INITIALIZE_PASS(MergeFunctions, "mergefunc", "Merge Functions", false, false);
ModulePass *llvm::createMergeFunctionsPass() {
return new MergeFunctions();
}
-// ===----------------------------------------------------------------------===
-// Comparison of functions
-// ===----------------------------------------------------------------------===
+namespace {
+/// FunctionComparator - Compares two functions to determine whether or not
+/// they will generate machine code with the same behaviour. TargetData is
+/// used if available. The comparator always fails conservatively (erring on the
+/// side of claiming that two functions are different).
+class FunctionComparator {
+public:
+ FunctionComparator(const TargetData *TD, const Function *F1,
+ const Function *F2)
+ : F1(F1), F2(F2), TD(TD), IDMap1Count(0), IDMap2Count(0) {}
+
+ /// Compare - test whether the two functions have equivalent behaviour.
+ bool Compare();
+
+private:
+ /// Compare - test whether two basic blocks have equivalent behaviour.
+ bool Compare(const BasicBlock *BB1, const BasicBlock *BB2);
+
+ /// Enumerate - Assign or look up previously assigned numbers for the two
+ /// values, and return whether the numbers are equal. Numbers are assigned in
+ /// the order visited.
+ bool Enumerate(const Value *V1, const Value *V2);
+
+ /// isEquivalentOperation - Compare two Instructions for equivalence, similar
+ /// to Instruction::isSameOperationAs but with modifications to the type
+ /// comparison.
+ bool isEquivalentOperation(const Instruction *I1,
+ const Instruction *I2) const;
+
+ /// isEquivalentGEP - Compare two GEPs for equivalent pointer arithmetic.
+ bool isEquivalentGEP(const GEPOperator *GEP1, const GEPOperator *GEP2);
+ bool isEquivalentGEP(const GetElementPtrInst *GEP1,
+ const GetElementPtrInst *GEP2) {
+ return isEquivalentGEP(cast<GEPOperator>(GEP1), cast<GEPOperator>(GEP2));
+ }
-static unsigned long hash(const Function *F) {
- const FunctionType *FTy = F->getFunctionType();
+ /// isEquivalentType - Compare two Types, treating all pointer types as equal.
+ bool isEquivalentType(const Type *Ty1, const Type *Ty2) const;
- FoldingSetNodeID ID;
- ID.AddInteger(F->size());
- ID.AddInteger(F->getCallingConv());
- ID.AddBoolean(F->hasGC());
- ID.AddBoolean(FTy->isVarArg());
- ID.AddInteger(FTy->getReturnType()->getTypeID());
- for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i)
- ID.AddInteger(FTy->getParamType(i)->getTypeID());
- return ID.ComputeHash();
+ // The two functions undergoing comparison.
+ const Function *F1, *F2;
+
+ const TargetData *TD;
+
+ typedef DenseMap<const Value *, unsigned long> IDMap;
+ IDMap Map1, Map2;
+ unsigned long IDMap1Count, IDMap2Count;
+};
}
-/// isEquivalentType - any two pointers are equivalent. Otherwise, standard
-/// type equivalence rules apply.
-static bool isEquivalentType(const Type *Ty1, const Type *Ty2) {
+/// isEquivalentType - any two pointers in the same address space are
+/// equivalent. Otherwise, standard type equivalence rules apply.
+bool FunctionComparator::isEquivalentType(const Type *Ty1,
+ const Type *Ty2) const {
if (Ty1 == Ty2)
return true;
if (Ty1->getTypeID() != Ty2->getTypeID())
@@ -184,21 +202,6 @@ static bool isEquivalentType(const Type *Ty1, const Type *Ty2) {
return true;
}
- case Type::UnionTyID: {
- const UnionType *UTy1 = cast<UnionType>(Ty1);
- const UnionType *UTy2 = cast<UnionType>(Ty2);
-
- // TODO: we could be fancy with union(A, union(A, B)) === union(A, B), etc.
- if (UTy1->getNumElements() != UTy2->getNumElements())
- return false;
-
- for (unsigned i = 0, e = UTy1->getNumElements(); i != e; ++i) {
- if (!isEquivalentType(UTy1->getElementType(i), UTy2->getElementType(i)))
- return false;
- }
- return true;
- }
-
case Type::FunctionTyID: {
const FunctionType *FTy1 = cast<FunctionType>(Ty1);
const FunctionType *FTy2 = cast<FunctionType>(Ty2);
@@ -216,11 +219,18 @@ static bool isEquivalentType(const Type *Ty1, const Type *Ty2) {
return true;
}
- case Type::ArrayTyID:
+ case Type::ArrayTyID: {
+ const ArrayType *ATy1 = cast<ArrayType>(Ty1);
+ const ArrayType *ATy2 = cast<ArrayType>(Ty2);
+ return ATy1->getNumElements() == ATy2->getNumElements() &&
+ isEquivalentType(ATy1->getElementType(), ATy2->getElementType());
+ }
+
case Type::VectorTyID: {
- const SequentialType *STy1 = cast<SequentialType>(Ty1);
- const SequentialType *STy2 = cast<SequentialType>(Ty2);
- return isEquivalentType(STy1->getElementType(), STy2->getElementType());
+ const VectorType *VTy1 = cast<VectorType>(Ty1);
+ const VectorType *VTy2 = cast<VectorType>(Ty2);
+ return VTy1->getNumElements() == VTy2->getNumElements() &&
+ isEquivalentType(VTy1->getElementType(), VTy2->getElementType());
}
}
}
@@ -228,8 +238,8 @@ static bool isEquivalentType(const Type *Ty1, const Type *Ty2) {
/// isEquivalentOperation - determine whether the two operations are the same
/// except that pointer-to-A and pointer-to-B are equivalent. This should be
/// kept in sync with Instruction::isSameOperationAs.
-static bool
-isEquivalentOperation(const Instruction *I1, const Instruction *I2) {
+bool FunctionComparator::isEquivalentOperation(const Instruction *I1,
+ const Instruction *I2) const {
if (I1->getOpcode() != I2->getOpcode() ||
I1->getNumOperands() != I2->getNumOperands() ||
!isEquivalentType(I1->getType(), I2->getType()) ||
@@ -281,18 +291,15 @@ isEquivalentOperation(const Instruction *I1, const Instruction *I2) {
return true;
}
-bool MergeFunctions::isEquivalentGEP(const GetElementPtrInst *GEP1,
- const GetElementPtrInst *GEP2) {
+/// isEquivalentGEP - determine whether two GEP operations perform the same
+/// underlying arithmetic.
+bool FunctionComparator::isEquivalentGEP(const GEPOperator *GEP1,
+ const GEPOperator *GEP2) {
+ // When we have target data, we can reduce the GEP down to the value in bytes
+ // added to the address.
if (TD && GEP1->hasAllConstantIndices() && GEP2->hasAllConstantIndices()) {
- SmallVector<Value *, 8> Indices1, Indices2;
- for (GetElementPtrInst::const_op_iterator I = GEP1->idx_begin(),
- E = GEP1->idx_end(); I != E; ++I) {
- Indices1.push_back(*I);
- }
- for (GetElementPtrInst::const_op_iterator I = GEP2->idx_begin(),
- E = GEP2->idx_end(); I != E; ++I) {
- Indices2.push_back(*I);
- }
+ SmallVector<Value *, 8> Indices1(GEP1->idx_begin(), GEP1->idx_end());
+ SmallVector<Value *, 8> Indices2(GEP2->idx_begin(), GEP2->idx_end());
uint64_t Offset1 = TD->getIndexedOffset(GEP1->getPointerOperandType(),
Indices1.data(), Indices1.size());
uint64_t Offset2 = TD->getIndexedOffset(GEP2->getPointerOperandType(),
@@ -300,7 +307,6 @@ bool MergeFunctions::isEquivalentGEP(const GetElementPtrInst *GEP1,
return Offset1 == Offset2;
}
- // Equivalent types aren't enough.
if (GEP1->getPointerOperand()->getType() !=
GEP2->getPointerOperand()->getType())
return false;
@@ -309,19 +315,26 @@ bool MergeFunctions::isEquivalentGEP(const GetElementPtrInst *GEP1,
return false;
for (unsigned i = 0, e = GEP1->getNumOperands(); i != e; ++i) {
- if (!compare(GEP1->getOperand(i), GEP2->getOperand(i)))
+ if (!Enumerate(GEP1->getOperand(i), GEP2->getOperand(i)))
return false;
}
return true;
}
-bool MergeFunctions::compare(const Value *V1, const Value *V2) {
- if (V1 == LHS || V1 == RHS)
- if (V2 == LHS || V2 == RHS)
- return true;
+/// Enumerate - Compare two values used by the two functions under pair-wise
+/// comparison. If this is the first time the values are seen, they're added to
+/// the mapping so that we will detect mismatches on next use.
+bool FunctionComparator::Enumerate(const Value *V1, const Value *V2) {
+ // Check for function @f1 referring to itself and function @f2 referring to
+ // itself, or referring to each other, or both referring to either of them.
+ // They're all equivalent if the two functions are otherwise equivalent.
+ if (V1 == F1 && V2 == F2)
+ return true;
+ if (V1 == F2 && V2 == F1)
+ return true;
- // TODO: constant expressions in terms of LHS and RHS
+ // TODO: constant expressions with GEP or references to F1 or F2.
if (isa<Constant>(V1))
return V1 == V2;
@@ -332,228 +345,138 @@ bool MergeFunctions::compare(const Value *V1, const Value *V2) {
IA1->getConstraintString() == IA2->getConstraintString();
}
- // We enumerate constants globally and arguments, basic blocks or
- // instructions within the function they belong to.
- const Function *Domain1 = NULL;
- if (const Argument *A = dyn_cast<Argument>(V1)) {
- Domain1 = A->getParent();
- } else if (const BasicBlock *BB = dyn_cast<BasicBlock>(V1)) {
- Domain1 = BB->getParent();
- } else if (const Instruction *I = dyn_cast<Instruction>(V1)) {
- Domain1 = I->getParent()->getParent();
- }
-
- const Function *Domain2 = NULL;
- if (const Argument *A = dyn_cast<Argument>(V2)) {
- Domain2 = A->getParent();
- } else if (const BasicBlock *BB = dyn_cast<BasicBlock>(V2)) {
- Domain2 = BB->getParent();
- } else if (const Instruction *I = dyn_cast<Instruction>(V2)) {
- Domain2 = I->getParent()->getParent();
- }
-
- if (Domain1 != Domain2)
- if (Domain1 != LHS && Domain1 != RHS)
- if (Domain2 != LHS && Domain2 != RHS)
- return false;
-
- IDMap &Map1 = Domains[Domain1];
unsigned long &ID1 = Map1[V1];
if (!ID1)
- ID1 = ++DomainCount[Domain1];
+ ID1 = ++IDMap1Count;
- IDMap &Map2 = Domains[Domain2];
unsigned long &ID2 = Map2[V2];
if (!ID2)
- ID2 = ++DomainCount[Domain2];
+ ID2 = ++IDMap2Count;
return ID1 == ID2;
}
-bool MergeFunctions::equals(const BasicBlock *BB1, const BasicBlock *BB2) {
- BasicBlock::const_iterator FI = BB1->begin(), FE = BB1->end();
- BasicBlock::const_iterator GI = BB2->begin(), GE = BB2->end();
+/// Compare - test whether two basic blocks have equivalent behaviour.
+bool FunctionComparator::Compare(const BasicBlock *BB1, const BasicBlock *BB2) {
+ BasicBlock::const_iterator F1I = BB1->begin(), F1E = BB1->end();
+ BasicBlock::const_iterator F2I = BB2->begin(), F2E = BB2->end();
do {
- if (!compare(FI, GI))
+ if (!Enumerate(F1I, F2I))
return false;
- if (isa<GetElementPtrInst>(FI) && isa<GetElementPtrInst>(GI)) {
- const GetElementPtrInst *GEP1 = cast<GetElementPtrInst>(FI);
- const GetElementPtrInst *GEP2 = cast<GetElementPtrInst>(GI);
+ if (const GetElementPtrInst *GEP1 = dyn_cast<GetElementPtrInst>(F1I)) {
+ const GetElementPtrInst *GEP2 = dyn_cast<GetElementPtrInst>(F2I);
+ if (!GEP2)
+ return false;
- if (!compare(GEP1->getPointerOperand(), GEP2->getPointerOperand()))
+ if (!Enumerate(GEP1->getPointerOperand(), GEP2->getPointerOperand()))
return false;
if (!isEquivalentGEP(GEP1, GEP2))
return false;
} else {
- if (!isEquivalentOperation(FI, GI))
+ if (!isEquivalentOperation(F1I, F2I))
return false;
- for (unsigned i = 0, e = FI->getNumOperands(); i != e; ++i) {
- Value *OpF = FI->getOperand(i);
- Value *OpG = GI->getOperand(i);
+ assert(F1I->getNumOperands() == F2I->getNumOperands());
+ for (unsigned i = 0, e = F1I->getNumOperands(); i != e; ++i) {
+ Value *OpF1 = F1I->getOperand(i);
+ Value *OpF2 = F2I->getOperand(i);
- if (!compare(OpF, OpG))
+ if (!Enumerate(OpF1, OpF2))
return false;
- if (OpF->getValueID() != OpG->getValueID() ||
- !isEquivalentType(OpF->getType(), OpG->getType()))
+ if (OpF1->getValueID() != OpF2->getValueID() ||
+ !isEquivalentType(OpF1->getType(), OpF2->getType()))
return false;
}
}
- ++FI, ++GI;
- } while (FI != FE && GI != GE);
+ ++F1I, ++F2I;
+ } while (F1I != F1E && F2I != F2E);
- return FI == FE && GI == GE;
+ return F1I == F1E && F2I == F2E;
}
-bool MergeFunctions::equals(const Function *F, const Function *G) {
+/// Compare - test whether the two functions have equivalent behaviour.
+bool FunctionComparator::Compare() {
// We need to recheck everything, but check the things that weren't included
// in the hash first.
- if (F->getAttributes() != G->getAttributes())
+ if (F1->getAttributes() != F2->getAttributes())
return false;
- if (F->hasGC() != G->hasGC())
+ if (F1->hasGC() != F2->hasGC())
return false;
- if (F->hasGC() && F->getGC() != G->getGC())
+ if (F1->hasGC() && F1->getGC() != F2->getGC())
return false;
- if (F->hasSection() != G->hasSection())
+ if (F1->hasSection() != F2->hasSection())
return false;
- if (F->hasSection() && F->getSection() != G->getSection())
+ if (F1->hasSection() && F1->getSection() != F2->getSection())
return false;
- if (F->isVarArg() != G->isVarArg())
+ if (F1->isVarArg() != F2->isVarArg())
return false;
// TODO: if it's internal and only used in direct calls, we could handle this
// case too.
- if (F->getCallingConv() != G->getCallingConv())
+ if (F1->getCallingConv() != F2->getCallingConv())
return false;
- if (!isEquivalentType(F->getFunctionType(), G->getFunctionType()))
+ if (!isEquivalentType(F1->getFunctionType(), F2->getFunctionType()))
return false;
- assert(F->arg_size() == G->arg_size() &&
+ assert(F1->arg_size() == F2->arg_size() &&
"Identical functions have a different number of args.");
- LHS = F;
- RHS = G;
-
// Visit the arguments so that they get enumerated in the order they're
// passed in.
- for (Function::const_arg_iterator fi = F->arg_begin(), gi = G->arg_begin(),
- fe = F->arg_end(); fi != fe; ++fi, ++gi) {
- if (!compare(fi, gi))
+ for (Function::const_arg_iterator f1i = F1->arg_begin(),
+ f2i = F2->arg_begin(), f1e = F1->arg_end(); f1i != f1e; ++f1i, ++f2i) {
+ if (!Enumerate(f1i, f2i))
llvm_unreachable("Arguments repeat");
}
- SmallVector<const BasicBlock *, 8> FBBs, GBBs;
- SmallSet<const BasicBlock *, 128> VisitedBBs; // in terms of F.
- FBBs.push_back(&F->getEntryBlock());
- GBBs.push_back(&G->getEntryBlock());
- VisitedBBs.insert(FBBs[0]);
- while (!FBBs.empty()) {
- const BasicBlock *FBB = FBBs.pop_back_val();
- const BasicBlock *GBB = GBBs.pop_back_val();
- if (!compare(FBB, GBB) || !equals(FBB, GBB)) {
- Domains.clear();
- DomainCount.clear();
- return false;
- }
- const TerminatorInst *FTI = FBB->getTerminator();
- const TerminatorInst *GTI = GBB->getTerminator();
- assert(FTI->getNumSuccessors() == GTI->getNumSuccessors());
- for (unsigned i = 0, e = FTI->getNumSuccessors(); i != e; ++i) {
- if (!VisitedBBs.insert(FTI->getSuccessor(i)))
- continue;
- FBBs.push_back(FTI->getSuccessor(i));
- GBBs.push_back(GTI->getSuccessor(i));
- }
- }
+ // We do a CFG-ordered walk since the actual ordering of the blocks in the
+ // 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
+ // artifact, this also means that unreachable blocks are ignored.
+ SmallVector<const BasicBlock *, 8> F1BBs, F2BBs;
+ SmallSet<const BasicBlock *, 128> VisitedBBs; // in terms of F1.
- Domains.clear();
- DomainCount.clear();
- return true;
-}
+ F1BBs.push_back(&F1->getEntryBlock());
+ F2BBs.push_back(&F2->getEntryBlock());
-// ===----------------------------------------------------------------------===
-// Folding of functions
-// ===----------------------------------------------------------------------===
-
-// Cases:
-// * F is external strong, G is external strong:
-// turn G into a thunk to F (1)
-// * F is external strong, G is external weak:
-// turn G into a thunk to F (1)
-// * F is external weak, G is external weak:
-// unfoldable
-// * F is external strong, G is internal:
-// address of G taken:
-// turn G into a thunk to F (1)
-// address of G not taken:
-// make G an alias to F (2)
-// * F is internal, G is external weak
-// address of F is taken:
-// turn G into a thunk to F (1)
-// address of F is not taken:
-// make G an alias of F (2)
-// * F is internal, G is internal:
-// address of F and G are taken:
-// turn G into a thunk to F (1)
-// address of G is not taken:
-// make G an alias to F (2)
-//
-// alias requires linkage == (external,local,weak) fallback to creating a thunk
-// external means 'externally visible' linkage != (internal,private)
-// internal means linkage == (internal,private)
-// weak means linkage mayBeOverridable
-// being external implies that the address is taken
-//
-// 1. turn G into a thunk to F
-// 2. make G an alias to F
+ VisitedBBs.insert(F1BBs[0]);
+ while (!F1BBs.empty()) {
+ const BasicBlock *F1BB = F1BBs.pop_back_val();
+ const BasicBlock *F2BB = F2BBs.pop_back_val();
-enum LinkageCategory {
- ExternalStrong,
- ExternalWeak,
- Internal
-};
+ if (!Enumerate(F1BB, F2BB) || !Compare(F1BB, F2BB))
+ return false;
-static LinkageCategory categorize(const Function *F) {
- switch (F->getLinkage()) {
- case GlobalValue::InternalLinkage:
- case GlobalValue::PrivateLinkage:
- case GlobalValue::LinkerPrivateLinkage:
- return Internal;
-
- case GlobalValue::WeakAnyLinkage:
- case GlobalValue::WeakODRLinkage:
- case GlobalValue::ExternalWeakLinkage:
- case GlobalValue::LinkerPrivateWeakLinkage:
- return ExternalWeak;
-
- case GlobalValue::ExternalLinkage:
- case GlobalValue::AvailableExternallyLinkage:
- case GlobalValue::LinkOnceAnyLinkage:
- case GlobalValue::LinkOnceODRLinkage:
- case GlobalValue::AppendingLinkage:
- case GlobalValue::DLLImportLinkage:
- case GlobalValue::DLLExportLinkage:
- case GlobalValue::CommonLinkage:
- return ExternalStrong;
- }
+ const TerminatorInst *F1TI = F1BB->getTerminator();
+ const TerminatorInst *F2TI = F2BB->getTerminator();
- llvm_unreachable("Unknown LinkageType.");
- return ExternalWeak;
+ assert(F1TI->getNumSuccessors() == F2TI->getNumSuccessors());
+ for (unsigned i = 0, e = F1TI->getNumSuccessors(); i != e; ++i) {
+ if (!VisitedBBs.insert(F1TI->getSuccessor(i)))
+ continue;
+
+ F1BBs.push_back(F1TI->getSuccessor(i));
+ F2BBs.push_back(F2TI->getSuccessor(i));
+ }
+ }
+ return true;
}
-static void ThunkGToF(Function *F, Function *G) {
+/// WriteThunk - Replace G with a simple tail call to bitcast(F). Also replace
+/// direct uses of G with bitcast(F).
+void MergeFunctions::WriteThunk(Function *F, Function *G) const {
if (!G->mayBeOverridden()) {
// Redirect direct callers of G to F.
Constant *BitcastF = ConstantExpr::getBitCast(F, G->getType());
@@ -567,33 +490,34 @@ static void ThunkGToF(Function *F, Function *G) {
}
}
+ // If G was internal then we may have replaced all uses if G with F. If so,
+ // stop here and delete G. There's no need for a thunk.
+ if (G->hasLocalLinkage() && G->use_empty()) {
+ G->eraseFromParent();
+ return;
+ }
+
Function *NewG = Function::Create(G->getFunctionType(), G->getLinkage(), "",
G->getParent());
BasicBlock *BB = BasicBlock::Create(F->getContext(), "", NewG);
+ IRBuilder<false> Builder(BB);
SmallVector<Value *, 16> Args;
unsigned i = 0;
const FunctionType *FFTy = F->getFunctionType();
for (Function::arg_iterator AI = NewG->arg_begin(), AE = NewG->arg_end();
AI != AE; ++AI) {
- if (FFTy->getParamType(i) == AI->getType()) {
- Args.push_back(AI);
- } else {
- Args.push_back(new BitCastInst(AI, FFTy->getParamType(i), "", BB));
- }
+ Args.push_back(Builder.CreateBitCast(AI, FFTy->getParamType(i)));
++i;
}
- CallInst *CI = CallInst::Create(F, Args.begin(), Args.end(), "", BB);
+ CallInst *CI = Builder.CreateCall(F, Args.begin(), Args.end());
CI->setTailCall();
CI->setCallingConv(F->getCallingConv());
if (NewG->getReturnType()->isVoidTy()) {
- ReturnInst::Create(F->getContext(), BB);
- } else if (CI->getType() != NewG->getReturnType()) {
- Value *BCI = new BitCastInst(CI, NewG->getReturnType(), "", BB);
- ReturnInst::Create(F->getContext(), BCI, BB);
+ Builder.CreateRetVoid();
} else {
- ReturnInst::Create(F->getContext(), CI, BB);
+ Builder.CreateRet(Builder.CreateBitCast(CI, NewG->getReturnType()));
}
NewG->copyAttributesFrom(G);
@@ -602,152 +526,126 @@ static void ThunkGToF(Function *F, Function *G) {
G->eraseFromParent();
}
-static void AliasGToF(Function *F, Function *G) {
- // Darwin will trigger llvm_unreachable if asked to codegen an alias.
- return ThunkGToF(F, G);
-
-#if 0
- if (!G->hasExternalLinkage() && !G->hasLocalLinkage() && !G->hasWeakLinkage())
- return ThunkGToF(F, G);
-
- GlobalAlias *GA = new GlobalAlias(
- G->getType(), G->getLinkage(), "",
- ConstantExpr::getBitCast(F, G->getType()), G->getParent());
- F->setAlignment(std::max(F->getAlignment(), G->getAlignment()));
- GA->takeName(G);
- GA->setVisibility(G->getVisibility());
- G->replaceAllUsesWith(GA);
- G->eraseFromParent();
-#endif
-}
-
-static bool fold(std::vector<Function *> &FnVec, unsigned i, unsigned j) {
- Function *F = FnVec[i];
- Function *G = FnVec[j];
-
- LinkageCategory catF = categorize(F);
- LinkageCategory catG = categorize(G);
-
- if (catF == ExternalWeak || (catF == Internal && catG == ExternalStrong)) {
- std::swap(FnVec[i], FnVec[j]);
- std::swap(F, G);
- std::swap(catF, catG);
- }
-
- switch (catF) {
- case ExternalStrong:
- switch (catG) {
- case ExternalStrong:
- case ExternalWeak:
- ThunkGToF(F, G);
- break;
- case Internal:
- if (G->hasAddressTaken())
- ThunkGToF(F, G);
- else
- AliasGToF(F, G);
- break;
- }
- break;
-
- case ExternalWeak: {
- assert(catG == ExternalWeak);
+/// MergeTwoFunctions - Merge two equivalent functions. Upon completion,
+/// Function G is deleted.
+void MergeFunctions::MergeTwoFunctions(Function *F, Function *G) const {
+ if (F->isWeakForLinker()) {
+ assert(G->isWeakForLinker());
// Make them both thunks to the same internal function.
- F->setAlignment(std::max(F->getAlignment(), G->getAlignment()));
Function *H = Function::Create(F->getFunctionType(), F->getLinkage(), "",
F->getParent());
H->copyAttributesFrom(F);
H->takeName(F);
F->replaceAllUsesWith(H);
- ThunkGToF(F, G);
- ThunkGToF(F, H);
+ unsigned MaxAlignment = std::max(G->getAlignment(), H->getAlignment());
- F->setLinkage(GlobalValue::InternalLinkage);
- } break;
-
- case Internal:
- switch (catG) {
- case ExternalStrong:
- llvm_unreachable(0);
- // fall-through
- case ExternalWeak:
- if (F->hasAddressTaken())
- ThunkGToF(F, G);
- else
- AliasGToF(F, G);
- break;
- case Internal: {
- bool addrTakenF = F->hasAddressTaken();
- bool addrTakenG = G->hasAddressTaken();
- if (!addrTakenF && addrTakenG) {
- std::swap(FnVec[i], FnVec[j]);
- std::swap(F, G);
- std::swap(addrTakenF, addrTakenG);
- }
+ WriteThunk(F, G);
+ WriteThunk(F, H);
- if (addrTakenF && addrTakenG) {
- ThunkGToF(F, G);
- } else {
- assert(!addrTakenG);
- AliasGToF(F, G);
- }
- } break;
- } break;
+ F->setAlignment(MaxAlignment);
+ F->setLinkage(GlobalValue::InternalLinkage);
+ } else {
+ WriteThunk(F, G);
}
++NumFunctionsMerged;
- return true;
}
-// ===----------------------------------------------------------------------===
-// Pass definition
-// ===----------------------------------------------------------------------===
+static unsigned ProfileFunction(const Function *F) {
+ const FunctionType *FTy = F->getFunctionType();
-bool MergeFunctions::runOnModule(Module &M) {
- bool Changed = false;
+ FoldingSetNodeID ID;
+ ID.AddInteger(F->size());
+ ID.AddInteger(F->getCallingConv());
+ ID.AddBoolean(F->hasGC());
+ ID.AddBoolean(FTy->isVarArg());
+ ID.AddInteger(FTy->getReturnType()->getTypeID());
+ for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i)
+ ID.AddInteger(FTy->getParamType(i)->getTypeID());
+ return ID.ComputeHash();
+}
- std::map<unsigned long, std::vector<Function *> > FnMap;
+class ComparableFunction {
+public:
+ ComparableFunction(Function *Func, TargetData *TD)
+ : Func(Func), Hash(ProfileFunction(Func)), TD(TD) {}
- for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) {
- if (F->isDeclaration())
- continue;
+ AssertingVH<Function> const Func;
+ const unsigned Hash;
+ TargetData * const TD;
+};
- FnMap[hash(F)].push_back(F);
+struct MergeFunctionsEqualityInfo {
+ static ComparableFunction *getEmptyKey() {
+ return reinterpret_cast<ComparableFunction*>(0);
+ }
+ static ComparableFunction *getTombstoneKey() {
+ return reinterpret_cast<ComparableFunction*>(-1);
}
+ static unsigned getHashValue(const ComparableFunction *CF) {
+ return CF->Hash;
+ }
+ static bool isEqual(const ComparableFunction *LHS,
+ const ComparableFunction *RHS) {
+ if (LHS == RHS)
+ return true;
+ if (LHS == getEmptyKey() || LHS == getTombstoneKey() ||
+ RHS == getEmptyKey() || RHS == getTombstoneKey())
+ return false;
+ assert(LHS->TD == RHS->TD && "Comparing functions for different targets");
+ return FunctionComparator(LHS->TD, LHS->Func, RHS->Func).Compare();
+ }
+};
+bool MergeFunctions::runOnModule(Module &M) {
+ typedef DenseSet<ComparableFunction *, MergeFunctionsEqualityInfo> FnSetType;
+
+ bool Changed = false;
TD = getAnalysisIfAvailable<TargetData>();
+ std::vector<Function *> Funcs;
+ for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) {
+ if (!F->isDeclaration() && !F->hasAvailableExternallyLinkage())
+ Funcs.push_back(F);
+ }
+
bool LocalChanged;
do {
LocalChanged = false;
- DEBUG(dbgs() << "size: " << FnMap.size() << "\n");
- for (std::map<unsigned long, std::vector<Function *> >::iterator
- I = FnMap.begin(), E = FnMap.end(); I != E; ++I) {
- std::vector<Function *> &FnVec = I->second;
- DEBUG(dbgs() << "hash (" << I->first << "): " << FnVec.size() << "\n");
-
- for (int i = 0, e = FnVec.size(); i != e; ++i) {
- for (int j = i + 1; j != e; ++j) {
- bool isEqual = equals(FnVec[i], FnVec[j]);
-
- DEBUG(dbgs() << " " << FnVec[i]->getName()
- << (isEqual ? " == " : " != ")
- << FnVec[j]->getName() << "\n");
-
- if (isEqual) {
- if (fold(FnVec, i, j)) {
- LocalChanged = true;
- FnVec.erase(FnVec.begin() + j);
- --j, --e;
- }
- }
- }
- }
+ FnSetType FnSet;
+ for (unsigned i = 0, e = Funcs.size(); i != e;) {
+ Function *F = Funcs[i];
+ ComparableFunction *NewF = new ComparableFunction(F, TD);
+ std::pair<FnSetType::iterator, bool> Result = FnSet.insert(NewF);
+ if (!Result.second) {
+ ComparableFunction *&OldF = *Result.first;
+ assert(OldF && "Expected a hash collision");
+
+ // NewF will be deleted in favour of OldF unless NewF is strong and
+ // OldF is weak in which case swap them to keep the strong definition.
+
+ if (OldF->Func->isWeakForLinker() && !NewF->Func->isWeakForLinker())
+ std::swap(OldF, NewF);
+
+ DEBUG(dbgs() << " " << OldF->Func->getName() << " == "
+ << NewF->Func->getName() << '\n');
+
+ Funcs.erase(Funcs.begin() + i);
+ --e;
+
+ Function *DeleteF = NewF->Func;
+ delete NewF;
+ MergeTwoFunctions(OldF->Func, DeleteF);
+ LocalChanged = true;
+ Changed = true;
+ } else {
+ ++i;
+ }
}
- Changed |= LocalChanged;
+ DeleteContainerPointers(FnSet);
} while (LocalChanged);
return Changed;
OpenPOWER on IntegriCloud