Index: ELF/LTO.cpp =================================================================== --- ELF/LTO.cpp +++ ELF/LTO.cpp @@ -106,13 +106,6 @@ SmallPtrSet Used; collectUsedGlobalVariables(M, Used, /* CompilerUsed */ false); - // This function is called if we know that the combined LTO object will - // provide a definition of a symbol. It undefines the symbol so that the - // definition in the combined LTO object will replace it when parsed. - auto Undefine = [](Symbol *S) { - replaceBody(S, S->body()->getName(), STV_DEFAULT, 0); - }; - for (const BasicSymbolRef &Sym : Obj->symbols()) { uint32_t Flags = Sym.getFlags(); GlobalValue *GV = Obj->getSymbolGV(Sym.getRawDataRefImpl()); @@ -123,14 +116,30 @@ Symbol *S = Syms[BodyIndex++]; if (Flags & BasicSymbolRef::SF_Undefined) continue; - if (!GV) { - // Module asm symbol. - Undefine(S); - continue; - } auto *B = dyn_cast(S->body()); if (!B || B->File != &F) continue; + + // 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. + if (GV && shouldInternalize(Used, S, GV)) + InternalizedSyms.insert(GV->getName()); + + // At this point we know that either the combined LTO object will provide a + // definition of a symbol, or we will internalize it. In either case, we + // need to undefine the symbol. In the former case, the real definition + // needs to be able to replace the original definition without conflicting. + // In the latter case, we need to allow the combined LTO object to provide a + // definition with the same name, for example when doing parallel codegen. + replaceBody(S, S->body()->getName(), STV_DEFAULT, 0); + + if (!GV) + // Module asm symbol. + continue; + switch (GV->getLinkage()) { default: break; @@ -142,16 +151,6 @@ 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. - if (shouldInternalize(Used, S, GV)) - InternalizedSyms.insert(GV->getName()); - else - Undefine(S); - Keep.push_back(GV); } Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -1395,7 +1395,7 @@ if (auto *SS = dyn_cast>(Body)) SS->File->IsUsed = true; - if (Body->isUndefined() && !S->isWeak()) + if (S->IsUsedInRegularObj && Body->isUndefined() && !S->isWeak()) reportUndefined(Symtab, Body); if (auto *C = dyn_cast(Body)) Index: test/ELF/lto/parallel-internalize.ll =================================================================== --- /dev/null +++ test/ELF/lto/parallel-internalize.ll @@ -0,0 +1,22 @@ +; REQUIRES: x86 +; RUN: llvm-as -o %t.bc %s +; RUN: ld.lld -m elf_x86_64 --lto-jobs=2 -save-temps -o %t %t.bc -e foo --lto-O0 +; RUN: llvm-nm %t0.lto.o | FileCheck --check-prefix=CHECK0 %s +; RUN: llvm-nm %t1.lto.o | FileCheck --check-prefix=CHECK1 %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; CHECK0: U bar +; CHECK0: T foo +define void @foo() { + call void @bar() + ret void +} + +; CHECK1: T bar +; CHECK1: U foo +define void @bar() { + call void @foo() + ret void +}