Index: include/llvm/LTO/LTOCodeGenerator.h =================================================================== --- include/llvm/LTO/LTOCodeGenerator.h +++ include/llvm/LTO/LTOCodeGenerator.h @@ -39,6 +39,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringMap.h" +#include "llvm/IR/GlobalValue.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" #include @@ -47,7 +48,6 @@ namespace llvm { class LLVMContext; class DiagnosticInfo; - class GlobalValue; class Linker; class Mangler; class MemoryBuffer; @@ -154,6 +154,7 @@ void initializeLTOPasses(); bool compileOptimizedToFile(const char **Name); + void restoreLinkageForExternals(); void applyScopeRestrictions(); void applyRestriction(GlobalValue &GV, ArrayRef Libcalls, std::vector &MustPreserveList, @@ -178,6 +179,7 @@ Reloc::Model RelocModel = Reloc::Default; StringSet MustPreserveSymbols; StringSet AsmUndefinedRefs; + StringMap ExternalSymbols; std::vector CodegenOptions; std::string FeatureStr; std::string MCpu; Index: lib/LTO/LTOCodeGenerator.cpp =================================================================== --- lib/LTO/LTOCodeGenerator.cpp +++ lib/LTO/LTOCodeGenerator.cpp @@ -56,6 +56,10 @@ #include using namespace llvm; +static cl::opt +RestoreExternals("restore-globals", cl::Hidden, cl::init(false), + cl::desc("Restore original linkage of internalized globals")); + const char* LTOCodeGenerator::getVersionString() { #ifdef LLVM_VERSION_INFO return PACKAGE_NAME " version " PACKAGE_VERSION ", " LLVM_VERSION_INFO; @@ -347,6 +351,12 @@ if (isa(GV) && std::binary_search(Libcalls.begin(), Libcalls.end(), GV.getName())) AsmUsed.insert(&GV); + + // Record the linkage type of non-local symbols so they can be restored prior + // to module splitting. + if (RestoreExternals && !GV.hasAvailableExternallyLinkage() && + !GV.hasLocalLinkage() && GV.hasName()) + ExternalSymbols.insert(std::make_pair(GV.getName(), GV.getLinkage())); } static void findUsedValues(GlobalVariable *LLVMUsed, @@ -454,6 +464,35 @@ ScopeRestrictionsDone = true; } +/// Restore original linkage for symbols that may have been internalized +void LTOCodeGenerator::restoreLinkageForExternals() { + if (!ShouldInternalize || !RestoreExternals) + return; + + assert(ScopeRestrictionsDone && + "Cannot externalize without internalization!"); + + if (ExternalSymbols.empty()) + return; + + auto externalize = [this](GlobalValue &GV) { + if (!GV.hasLocalLinkage() || !GV.hasName()) + return; + + auto I = ExternalSymbols.find(GV.getName()); + if (I == ExternalSymbols.end()) + return; + + GV.setLinkage(I->second); + }; + + std::for_each(MergedModule->begin(), MergedModule->end(), externalize); + std::for_each(MergedModule->global_begin(), MergedModule->global_end(), + externalize); + std::for_each(MergedModule->alias_begin(), MergedModule->alias_end(), + externalize); +} + /// Optimize merged modules using various IPO passes bool LTOCodeGenerator::optimize(bool DisableVerify, bool DisableInline, bool DisableGVNLoadPRE, @@ -504,6 +543,10 @@ preCodeGenPasses.add(createObjCARCContractPass()); preCodeGenPasses.run(*MergedModule); + // Re-externalize globals that may have been internalized to increase scope + // for splitting + restoreLinkageForExternals(); + // Do code generation. We need to preserve the module in case the client calls // writeMergedModules() after compilation, but we only need to allow this at // parallelism level 1. This is achieved by having splitCodeGen return the Index: test/LTO/X86/restore-externals.ll =================================================================== --- /dev/null +++ test/LTO/X86/restore-externals.ll @@ -0,0 +1,23 @@ +; Check that "internalizedfn" is re-externalized prior to CodeGen +; +; RUN: llvm-as < %s > %t1 +; RUN: llvm-lto -exported-symbol=preservedfn -restore-globals -filetype=asm -o - %t1 | FileCheck %s +; +; CHECK: .globl internalizedfn + +target triple = "x86_64-unknown-linux-gnu" + +declare void @f() + +define void @internalizedfn() noinline { +entry: + call void @f() + ret void +} + +define void @preservedfn() { +entry: + call void @internalizedfn() + ret void +} +