summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Lewycky <nicholas@mxc.ca>2011-01-25 08:56:50 +0000
committerNick Lewycky <nicholas@mxc.ca>2011-01-25 08:56:50 +0000
commitb38824f866447ccf8dd0c76656755b05bcede1b1 (patch)
tree63cfa328c3b9a5e364594fc22928a0d07d8f4f3b
parent1bcb4288e500a7a0e00669627110ba76a375fd87 (diff)
downloadllvm-b38824f866447ccf8dd0c76656755b05bcede1b1.tar.gz
llvm-b38824f866447ccf8dd0c76656755b05bcede1b1.tar.bz2
llvm-b38824f866447ccf8dd0c76656755b05bcede1b1.tar.xz
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
-rw-r--r--lib/Transforms/IPO/MergeFunctions.cpp104
-rw-r--r--test/Transforms/MergeFunc/fold-weak.ll4
2 files changed, 83 insertions, 25 deletions
diff --git a/lib/Transforms/IPO/MergeFunctions.cpp b/lib/Transforms/IPO/MergeFunctions.cpp
index 49ebe65fe8..15b6c56b66 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;
diff --git a/test/Transforms/MergeFunc/fold-weak.ll b/test/Transforms/MergeFunc/fold-weak.ll
index e12473125c..23e4d33c3a 100644
--- a/test/Transforms/MergeFunc/fold-weak.ll
+++ b/test/Transforms/MergeFunc/fold-weak.ll
@@ -1,6 +1,10 @@
; RUN: opt < %s -mergefunc -S > %t
; RUN: grep {define weak} %t | count 2
; RUN: grep {call} %t | count 2
+; XFAIL: *
+
+; This test is off for a bit as we change this particular sort of folding to
+; only apply on ELF systems and not Mach-O systems.
define weak i32 @sum(i32 %x, i32 %y) {
%sum = add i32 %x, %y