diff options
author | Nick Lewycky <nicholas@mxc.ca> | 2011-01-25 08:56:50 +0000 |
---|---|---|
committer | Nick Lewycky <nicholas@mxc.ca> | 2011-01-25 08:56:50 +0000 |
commit | b38824f866447ccf8dd0c76656755b05bcede1b1 (patch) | |
tree | 63cfa328c3b9a5e364594fc22928a0d07d8f4f3b /lib/Transforms | |
parent | 1bcb4288e500a7a0e00669627110ba76a375fd87 (diff) | |
download | external_llvm-b38824f866447ccf8dd0c76656755b05bcede1b1.zip external_llvm-b38824f866447ccf8dd0c76656755b05bcede1b1.tar.gz external_llvm-b38824f866447ccf8dd0c76656755b05bcede1b1.tar.bz2 |
Teach mergefunc how to emit aliases safely again -- but keep it turned it off
for now. It's controlled by the HasGlobalAliases variable which is not attached
to any flag yet.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@124182 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Transforms')
-rw-r--r-- | lib/Transforms/IPO/MergeFunctions.cpp | 104 |
1 files changed, 79 insertions, 25 deletions
diff --git a/lib/Transforms/IPO/MergeFunctions.cpp b/lib/Transforms/IPO/MergeFunctions.cpp index 49ebe65..15b6c56 100644 --- a/lib/Transforms/IPO/MergeFunctions.cpp +++ b/lib/Transforms/IPO/MergeFunctions.cpp @@ -68,6 +68,7 @@ using namespace llvm; STATISTIC(NumFunctionsMerged, "Number of functions merged"); STATISTIC(NumThunksWritten, "Number of thunks generated"); +STATISTIC(NumAliasesWritten, "Number of aliases generated"); STATISTIC(NumDoubleWeak, "Number of new functions created"); /// ProfileFunction - Creates a hash-code for the function which is the same @@ -164,7 +165,8 @@ namespace { class MergeFunctions : public ModulePass { public: static char ID; - MergeFunctions() : ModulePass(ID) { + MergeFunctions() + : ModulePass(ID), HasGlobalAliases(false) { initializeMergeFunctionsPass(*PassRegistry::getPassRegistry()); } @@ -189,21 +191,34 @@ private: /// queue the functions. void RemoveUsers(Value *V); + /// Replace all direct calls of Old with calls of New. Will bitcast New if + /// necessary to make types match. + void replaceDirectCallers(Function *Old, Function *New); + /// 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); + /// WriteThunkOrAlias - Replace G with a thunk or an alias to F. Deletes G. + void WriteThunkOrAlias(Function *F, Function *G); + /// WriteThunk - Replace G with a simple tail call to bitcast(F). Also /// replace direct uses of G with bitcast(F). Deletes G. void WriteThunk(Function *F, Function *G); + /// WriteAlias - Replace G with an alias to F. Deletes G. + void WriteAlias(Function *F, Function *G); + /// The set of all distinct functions. Use the Insert and Remove methods to /// modify it. FnSetType FnSet; /// TargetData for more accurate GEP comparisons. May be NULL. TargetData *TD; + + /// Whether or not the target supports global aliases. + bool HasGlobalAliases; }; } // end anonymous namespace @@ -587,22 +602,39 @@ bool FunctionComparator::Compare() { return true; } +/// Replace direct callers of Old with New. +void MergeFunctions::replaceDirectCallers(Function *Old, Function *New) { + Constant *BitcastNew = ConstantExpr::getBitCast(New, Old->getType()); + for (Value::use_iterator UI = Old->use_begin(), UE = Old->use_end(); + UI != UE;) { + Value::use_iterator TheIter = UI; + ++UI; + CallSite CS(*TheIter); + if (CS && CS.isCallee(TheIter)) { + Remove(CS.getInstruction()->getParent()->getParent()); + TheIter.getUse().set(BitcastNew); + } + } +} + +void MergeFunctions::WriteThunkOrAlias(Function *F, Function *G) { + if (HasGlobalAliases && G->hasUnnamedAddr()) { + if (G->hasExternalLinkage() || G->hasLocalLinkage() || + G->hasWeakLinkage()) { + WriteAlias(F, G); + return; + } + } + + WriteThunk(F, G); +} + /// WriteThunk - Replace G with a simple tail call to bitcast(F). Also replace /// direct uses of G with bitcast(F). Deletes G. void MergeFunctions::WriteThunk(Function *F, Function *G) { if (!G->mayBeOverridden()) { // Redirect direct callers of G to F. - Constant *BitcastF = ConstantExpr::getBitCast(F, G->getType()); - for (Value::use_iterator UI = G->use_begin(), UE = G->use_end(); - UI != UE;) { - Value::use_iterator TheIter = UI; - ++UI; - CallSite CS(*TheIter); - if (CS && CS.isCallee(TheIter)) { - Remove(CS.getInstruction()->getParent()->getParent()); - TheIter.getUse().set(BitcastF); - } - } + replaceDirectCallers(G, F); } // If G was internal then we may have replaced all uses of G with F. If so, @@ -645,31 +677,53 @@ void MergeFunctions::WriteThunk(Function *F, Function *G) { ++NumThunksWritten; } +/// WriteAlias - Replace G with an alias to F and delete G. +void MergeFunctions::WriteAlias(Function *F, Function *G) { + Constant *BitcastF = ConstantExpr::getBitCast(F, G->getType()); + GlobalAlias *GA = new GlobalAlias(G->getType(), G->getLinkage(), "", + BitcastF, G->getParent()); + F->setAlignment(std::max(F->getAlignment(), G->getAlignment())); + GA->takeName(G); + GA->setVisibility(G->getVisibility()); + RemoveUsers(G); + G->replaceAllUsesWith(GA); + G->eraseFromParent(); + + DEBUG(dbgs() << "WriteAlias: " << GA->getName() << '\n'); + ++NumAliasesWritten; +} + /// MergeTwoFunctions - Merge two equivalent functions. Upon completion, /// Function G is deleted. void MergeFunctions::MergeTwoFunctions(Function *F, Function *G) { if (F->mayBeOverridden()) { assert(G->mayBeOverridden()); - // Make them both thunks to the same internal function. - Function *H = Function::Create(F->getFunctionType(), F->getLinkage(), "", - F->getParent()); - H->copyAttributesFrom(F); - H->takeName(F); - RemoveUsers(F); - F->replaceAllUsesWith(H); + if (HasGlobalAliases) { + // Make them both thunks to the same internal function. + Function *H = Function::Create(F->getFunctionType(), F->getLinkage(), "", + F->getParent()); + H->copyAttributesFrom(F); + H->takeName(F); + RemoveUsers(F); + F->replaceAllUsesWith(H); - unsigned MaxAlignment = std::max(G->getAlignment(), H->getAlignment()); + unsigned MaxAlignment = std::max(G->getAlignment(), H->getAlignment()); - WriteThunk(F, G); - WriteThunk(F, H); + WriteAlias(F, G); + WriteAlias(F, H); - F->setAlignment(MaxAlignment); - F->setLinkage(GlobalValue::PrivateLinkage); + F->setAlignment(MaxAlignment); + F->setLinkage(GlobalValue::PrivateLinkage); + } else { + // We can't merge them. Instead, pick one and update all direct callers + // to call it and hope that we improve the instruction cache hit rate. + replaceDirectCallers(G, F); + } ++NumDoubleWeak; } else { - WriteThunk(F, G); + WriteThunkOrAlias(F, G); } ++NumFunctionsMerged; |