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.

llvm-svn: 124182
This commit is contained in:
Nick Lewycky 2011-01-25 08:56:50 +00:00
parent ad25145255
commit f1cec164ce
2 changed files with 83 additions and 25 deletions

View File

@ -68,6 +68,7 @@ using namespace llvm;
STATISTIC(NumFunctionsMerged, "Number of functions merged"); STATISTIC(NumFunctionsMerged, "Number of functions merged");
STATISTIC(NumThunksWritten, "Number of thunks generated"); STATISTIC(NumThunksWritten, "Number of thunks generated");
STATISTIC(NumAliasesWritten, "Number of aliases generated");
STATISTIC(NumDoubleWeak, "Number of new functions created"); STATISTIC(NumDoubleWeak, "Number of new functions created");
/// ProfileFunction - Creates a hash-code for the function which is the same /// ProfileFunction - Creates a hash-code for the function which is the same
@ -164,7 +165,8 @@ namespace {
class MergeFunctions : public ModulePass { class MergeFunctions : public ModulePass {
public: public:
static char ID; static char ID;
MergeFunctions() : ModulePass(ID) { MergeFunctions()
: ModulePass(ID), HasGlobalAliases(false) {
initializeMergeFunctionsPass(*PassRegistry::getPassRegistry()); initializeMergeFunctionsPass(*PassRegistry::getPassRegistry());
} }
@ -189,21 +191,34 @@ private:
/// queue the functions. /// queue the functions.
void RemoveUsers(Value *V); 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 /// MergeTwoFunctions - Merge two equivalent functions. Upon completion, G
/// may be deleted, or may be converted into a thunk. In either case, it /// may be deleted, or may be converted into a thunk. In either case, it
/// should never be visited again. /// should never be visited again.
void MergeTwoFunctions(Function *F, Function *G); 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 /// WriteThunk - Replace G with a simple tail call to bitcast(F). Also
/// replace direct uses of G with bitcast(F). Deletes G. /// replace direct uses of G with bitcast(F). Deletes G.
void WriteThunk(Function *F, Function *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 /// The set of all distinct functions. Use the Insert and Remove methods to
/// modify it. /// modify it.
FnSetType FnSet; FnSetType FnSet;
/// TargetData for more accurate GEP comparisons. May be NULL. /// TargetData for more accurate GEP comparisons. May be NULL.
TargetData *TD; TargetData *TD;
/// Whether or not the target supports global aliases.
bool HasGlobalAliases;
}; };
} // end anonymous namespace } // end anonymous namespace
@ -587,22 +602,39 @@ bool FunctionComparator::Compare() {
return true; 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 /// WriteThunk - Replace G with a simple tail call to bitcast(F). Also replace
/// direct uses of G with bitcast(F). Deletes G. /// direct uses of G with bitcast(F). Deletes G.
void MergeFunctions::WriteThunk(Function *F, Function *G) { void MergeFunctions::WriteThunk(Function *F, Function *G) {
if (!G->mayBeOverridden()) { if (!G->mayBeOverridden()) {
// Redirect direct callers of G to F. // Redirect direct callers of G to F.
Constant *BitcastF = ConstantExpr::getBitCast(F, G->getType()); replaceDirectCallers(G, F);
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);
}
}
} }
// If G was internal then we may have replaced all uses of G with F. If so, // 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; ++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, /// MergeTwoFunctions - Merge two equivalent functions. Upon completion,
/// Function G is deleted. /// Function G is deleted.
void MergeFunctions::MergeTwoFunctions(Function *F, Function *G) { void MergeFunctions::MergeTwoFunctions(Function *F, Function *G) {
if (F->mayBeOverridden()) { if (F->mayBeOverridden()) {
assert(G->mayBeOverridden()); assert(G->mayBeOverridden());
// Make them both thunks to the same internal function. if (HasGlobalAliases) {
Function *H = Function::Create(F->getFunctionType(), F->getLinkage(), "", // Make them both thunks to the same internal function.
F->getParent()); Function *H = Function::Create(F->getFunctionType(), F->getLinkage(), "",
H->copyAttributesFrom(F); F->getParent());
H->takeName(F); H->copyAttributesFrom(F);
RemoveUsers(F); H->takeName(F);
F->replaceAllUsesWith(H); RemoveUsers(F);
F->replaceAllUsesWith(H);
unsigned MaxAlignment = std::max(G->getAlignment(), H->getAlignment()); unsigned MaxAlignment = std::max(G->getAlignment(), H->getAlignment());
WriteThunk(F, G); WriteAlias(F, G);
WriteThunk(F, H); WriteAlias(F, H);
F->setAlignment(MaxAlignment); F->setAlignment(MaxAlignment);
F->setLinkage(GlobalValue::PrivateLinkage); 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; ++NumDoubleWeak;
} else { } else {
WriteThunk(F, G); WriteThunkOrAlias(F, G);
} }
++NumFunctionsMerged; ++NumFunctionsMerged;

View File

@ -1,6 +1,10 @@
; RUN: opt < %s -mergefunc -S > %t ; RUN: opt < %s -mergefunc -S > %t
; RUN: grep {define weak} %t | count 2 ; RUN: grep {define weak} %t | count 2
; RUN: grep {call} %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) { define weak i32 @sum(i32 %x, i32 %y) {
%sum = add i32 %x, %y %sum = add i32 %x, %y