Index: ELF/LTO.h =================================================================== --- ELF/LTO.h +++ ELF/LTO.h @@ -23,6 +23,7 @@ #include "lld/Core/LLVM.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringSet.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/Linker/IRMover.h" @@ -46,6 +47,7 @@ llvm::IRMover Mover{Combined}; SmallString<0> OwningData; std::unique_ptr MB; + llvm::StringSet<> InternalizedSyms; }; } } Index: ELF/LTO.cpp =================================================================== --- ELF/LTO.cpp +++ ELF/LTO.cpp @@ -22,6 +22,7 @@ #include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/IPO.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" +#include "llvm/Transforms/Utils/ModuleUtils.h" using namespace llvm; using namespace llvm::object; @@ -75,6 +76,7 @@ unsigned BodyIndex = 0; ArrayRef Bodies = F.getSymbols(); + SmallPtrSet Used; for (const BasicSymbolRef &Sym : Obj->symbols()) { GlobalValue *GV = Obj->getSymbolGV(Sym.getRawDataRefImpl()); assert(GV); @@ -95,6 +97,18 @@ GV->setLinkage(GlobalValue::WeakODRLinkage); break; } + // We collect the set of symbols we want to internalize here + // and change the linkage after the IRMover executed, i.e. after + // we imported the symbols and satisfied undefined references + // to it. We can't just change linkage here because otherwise + // the IRMover will just rename the symbol. + + // Shared libraries need to be handled slightly differently. + // For now, let's be conservative and just never internalize + // symbols when creating a shared library. + if (!Config->Shared && !Used.count(GV) && !B->isUsedInRegularObj()) + InternalizedSyms.insert(GV->getName()); + Keep.push_back(GV); } } @@ -104,10 +118,22 @@ [](GlobalValue &, IRMover::ValueAdder) {}); } +static void internalize(GlobalValue &GV) { + assert(!GV.hasLocalLinkage() && + "Trying to internalize a symbol with local linkage!") ; + GV.setLinkage(GlobalValue::InternalLinkage); +} + // Merge all the bitcode files we have seen, codegen the result // and return the resulting ObjectFile. template std::unique_ptr> BitcodeCompiler::compile() { + for (const auto &Name : InternalizedSyms) { + GlobalValue *GV = Combined.getNamedValue(Name.first()); + assert(GV); + internalize(*GV); + } + if (Config->SaveTemps) saveBCFile(Combined, ".lto.bc"); Index: ELF/SymbolTable.cpp =================================================================== --- ELF/SymbolTable.cpp +++ ELF/SymbolTable.cpp @@ -214,6 +214,16 @@ SymbolBody *Existing = Sym->Body; + // We want to internalize symbols for LTO to be effective, + // but we can internalize only those that are not referenced + // from regular objects. + if (auto *BC = dyn_cast(Existing)) + if (auto *U = dyn_cast(New)) + BC->setUsedInRegularObj(); + if (auto *U = dyn_cast(Existing)) + if (auto *BC = dyn_cast(New)) + BC->setUsedInRegularObj(); + if (Lazy *L = dyn_cast(Existing)) { if (auto *Undef = dyn_cast(New)) { addMemberFile(Undef, L); Index: ELF/Symbols.h =================================================================== --- ELF/Symbols.h +++ ELF/Symbols.h @@ -92,6 +92,8 @@ template typename ELFT::uint getVA(typename ELFT::uint Addend = 0) const; + void setUsedInRegularObj() { IsUsedInRegularObj = true; } + template typename ELFT::uint getGotVA() const; template typename ELFT::uint getGotPltVA() const; template typename ELFT::uint getPltVA() const; @@ -120,7 +122,8 @@ IsFunc = Type == llvm::ELF::STT_FUNC; IsTls = Type == llvm::ELF::STT_TLS; IsGnuIFunc = Type == llvm::ELF::STT_GNU_IFUNC; - IsUsedInRegularObj = K != SharedKind && K != LazyKind; + IsUsedInRegularObj = + K != SharedKind && K != LazyKind && K != DefinedBitcodeKind; } const unsigned SymbolKind : 8; @@ -318,7 +321,6 @@ std::unique_ptr getMember(); void setWeak() { IsWeak = true; } - void setUsedInRegularObj() { IsUsedInRegularObj = true; } private: ArchiveFile *File; Index: test/ELF/lto/internalize-basic.ll =================================================================== --- /dev/null +++ test/ELF/lto/internalize-basic.ll @@ -0,0 +1,18 @@ +; REQUIRES: x86 +; RUN: llvm-as %s -o %t.o +; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -save-temps +; RUN: llvm-dis %t2.lto.bc -o - | FileCheck %s + +target triple = "x86_64-unknown-linux-gnu" +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +define void @_start() { + ret void +} + +define hidden void @foo() { + ret void +} + +; Check that foo function is correctly internalized. +; CHECK: define internal void @foo()