Index: include/llvm/InitializePasses.h =================================================================== --- include/llvm/InitializePasses.h +++ include/llvm/InitializePasses.h @@ -221,6 +221,7 @@ void initializeMetaRenamerPass(PassRegistry&); void initializeMergeFunctionsPass(PassRegistry&); void initializeModuleDebugInfoPrinterPass(PassRegistry&); +void initializeNameAnonFunctionPass(PassRegistry &); void initializeNaryReassociatePass(PassRegistry&); void initializeNoAAPass(PassRegistry&); void initializeObjCARCAAWrapperPassPass(PassRegistry&); Index: include/llvm/Transforms/Scalar.h =================================================================== --- include/llvm/Transforms/Scalar.h +++ include/llvm/Transforms/Scalar.h @@ -503,6 +503,9 @@ // FunctionPass *createLoopDataPrefetchPass(); +///===---------------------------------------------------------------------===// +ModulePass *createNameAnonFunctionPass(); + } // End llvm namespace #endif Index: include/llvm/Transforms/Utils/ModuleUtils.h =================================================================== --- include/llvm/Transforms/Utils/ModuleUtils.h +++ include/llvm/Transforms/Utils/ModuleUtils.h @@ -61,6 +61,11 @@ Module &M, StringRef CtorName, StringRef InitName, ArrayRef InitArgTypes, ArrayRef 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 Index: lib/Transforms/IPO/PassManagerBuilder.cpp =================================================================== --- lib/Transforms/IPO/PassManagerBuilder.cpp +++ lib/Transforms/IPO/PassManagerBuilder.cpp @@ -247,6 +247,8 @@ 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 Index: lib/Transforms/Utils/CMakeLists.txt =================================================================== --- lib/Transforms/Utils/CMakeLists.txt +++ lib/Transforms/Utils/CMakeLists.txt @@ -31,6 +31,7 @@ MemorySSA.cpp MetaRenamer.cpp ModuleUtils.cpp + NameAnonFunctions.cpp PromoteMemoryToRegister.cpp SSAUpdater.cpp SanitizerStats.cpp Index: lib/Transforms/Utils/NameAnonFunctions.cpp =================================================================== --- /dev/null +++ lib/Transforms/Utils/NameAnonFunctions.cpp @@ -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(); } +} Index: lib/Transforms/Utils/Utils.cpp =================================================================== --- lib/Transforms/Utils/Utils.cpp +++ lib/Transforms/Utils/Utils.cpp @@ -28,6 +28,7 @@ initializeLoopSimplifyPass(Registry); initializeLowerInvokePass(Registry); initializeLowerSwitchPass(Registry); + initializeNameAnonFunctionPass(Registry); initializePromotePassPass(Registry); initializeUnifyFunctionExitNodesPass(Registry); initializeInstSimplifierPass(Registry); Index: test/Transforms/NameAnonFunctions/rename.ll =================================================================== --- /dev/null +++ test/Transforms/NameAnonFunctions/rename.ll @@ -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 +} +