Add a pass to name anonymous/nameless function

Summary:
For correct handling of alias to nameless
function, we need to be able to refer them through a GUID in the summary.
Here we name them using a hash of the non-private global names in the module.

Reviewers: tejohnson

Subscribers: joker.eph, llvm-commits

Differential Revision: http://reviews.llvm.org/D18883

From: Mehdi Amini <mehdi.amini@apple.com>
llvm-svn: 266132
This commit is contained in:
Mehdi Amini 2016-04-12 21:35:28 +00:00
parent 03a2cdacee
commit 6875fa5607
8 changed files with 142 additions and 0 deletions

View File

@ -221,6 +221,7 @@ void initializeMergedLoadStoreMotionPass(PassRegistry &);
void initializeMetaRenamerPass(PassRegistry&);
void initializeMergeFunctionsPass(PassRegistry&);
void initializeModuleDebugInfoPrinterPass(PassRegistry&);
void initializeNameAnonFunctionPass(PassRegistry &);
void initializeNaryReassociatePass(PassRegistry&);
void initializeNoAAPass(PassRegistry&);
void initializeObjCARCAAWrapperPassPass(PassRegistry&);

View File

@ -503,6 +503,9 @@ FunctionPass *createLoopVersioningPass();
//
FunctionPass *createLoopDataPrefetchPass();
///===---------------------------------------------------------------------===//
ModulePass *createNameAnonFunctionPass();
} // End llvm namespace
#endif

View File

@ -61,6 +61,11 @@ std::pair<Function *, Function *> createSanitizerCtorAndInitFunctions(
Module &M, StringRef CtorName, StringRef InitName,
ArrayRef<Type *> InitArgTypes, ArrayRef<Value *> InitArgs,
StringRef VersionCheckName = StringRef());
/// Rename all the anon functions in the module using a hash computed from
/// the list of public globals in the module.
bool nameUnamedFunctions(Module &M);
} // End llvm namespace
#endif // LLVM_TRANSFORMS_UTILS_MODULEUTILS_H

View File

@ -247,6 +247,8 @@ void PassManagerBuilder::addFunctionSimplificationPasses(
if (PrepareForThinLTO) {
MPM.add(createAggressiveDCEPass()); // Delete dead instructions
addInstructionCombiningPass(MPM); // Combine silly seq's
// Rename anon function to export them
MPM.add(createNameAnonFunctionPass());
return;
}
// Rotate Loop - disable header duplication at -Oz

View File

@ -31,6 +31,7 @@ add_llvm_library(LLVMTransformUtils
MemorySSA.cpp
MetaRenamer.cpp
ModuleUtils.cpp
NameAnonFunctions.cpp
PromoteMemoryToRegister.cpp
SSAUpdater.cpp
SanitizerStats.cpp

View File

@ -0,0 +1,102 @@
//===- NameAnonFunctions.cpp - ThinLTO Summary-based Function Import ------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements naming anonymous function to make sure they can be
// refered to by ThinLTO.
//
//===----------------------------------------------------------------------===//
#include "llvm/ADT/SmallString.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/MD5.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"
using namespace llvm;
// Compute a "unique" hash for the module based on the name of the public
// functions.
class ModuleHasher {
Module &TheModule;
std::string TheHash;
public:
ModuleHasher(Module &M) : TheModule(M) {}
/// Return the lazily computed hash.
std::string &get() {
if (!TheHash.empty())
// Cache hit :)
return TheHash;
MD5 Hasher;
for (auto &F : TheModule) {
if (F.isDeclaration() || F.hasLocalLinkage() || !F.hasName())
continue;
auto Name = F.getName();
Hasher.update(Name);
}
for (auto &GV : TheModule.globals()) {
if (GV.isDeclaration() || GV.hasLocalLinkage() || !GV.hasName())
continue;
auto Name = GV.getName();
Hasher.update(Name);
}
// Now return the result.
MD5::MD5Result Hash;
Hasher.final(Hash);
SmallString<32> Result;
MD5::stringifyResult(Hash, Result);
TheHash = Result.str();
return TheHash;
}
};
// Rename all the anon functions in the module
bool llvm::nameUnamedFunctions(Module &M) {
bool Changed = false;
ModuleHasher ModuleHash(M);
int count = 0;
for (auto &F : M) {
if (F.hasName())
continue;
F.setName(Twine("anon.") + ModuleHash.get() + "." + Twine(count++));
Changed = true;
}
return Changed;
}
namespace {
// Simple pass that provides a name to every anon function.
class NameAnonFunction : public ModulePass {
public:
/// Pass identification, replacement for typeid
static char ID;
/// Specify pass name for debug output
const char *getPassName() const override { return "Name Anon Functions"; }
explicit NameAnonFunction() : ModulePass(ID) {}
bool runOnModule(Module &M) override { return nameUnamedFunctions(M); }
};
char NameAnonFunction::ID = 0;
} // anonymous namespace
INITIALIZE_PASS_BEGIN(NameAnonFunction, "name-anon-functions",
"Provide a name to nameless functions", false, false)
INITIALIZE_PASS_END(NameAnonFunction, "name-anon-functions",
"Provide a name to nameless functions", false, false)
namespace llvm {
Pass *createNameAnonFunctionPass() { return new NameAnonFunction(); }
}

View File

@ -28,6 +28,7 @@ void llvm::initializeTransformUtils(PassRegistry &Registry) {
initializeLoopSimplifyPass(Registry);
initializeLowerInvokePass(Registry);
initializeLowerSwitchPass(Registry);
initializeNameAnonFunctionPass(Registry);
initializePromotePassPass(Registry);
initializeUnifyFunctionExitNodesPass(Registry);
initializeInstSimplifierPass(Registry);

View File

@ -0,0 +1,27 @@
; RUN: opt -S -name-anon-functions < %s | FileCheck %s
; foo contribute to the unique hash for the module
define void @foo() {
ret void
}
; bar is internal, and does not contribute to the unique hash for the module
define internal void @bar() {
ret void
}
; CHECK: define void @anon.acbd18db4cc2f85cedef654fccc4a4d8.0()
; CHECK: define void @anon.acbd18db4cc2f85cedef654fccc4a4d8.1()
; CHECK: define void @anon.acbd18db4cc2f85cedef654fccc4a4d8.2()
define void @0() {
ret void
}
define void @1() {
ret void
}
define void @2() {
ret void
}