Index: lld/ELF/LTO.h =================================================================== --- lld/ELF/LTO.h +++ lld/ELF/LTO.h @@ -55,6 +55,7 @@ std::vector> Buff; std::vector> Files; llvm::DenseSet UsedStartStop; + llvm::StringMap ObjectToIndexFileState; std::unique_ptr LinkedObjects; }; } // namespace elf Index: lld/ELF/LTO.cpp =================================================================== --- lld/ELF/LTO.cpp +++ lld/ELF/LTO.cpp @@ -115,9 +115,11 @@ } // Creates instance of LTO. +// OnIndexWrite is callback to let caller know when LTO writes index files. // LinkedObjectsFile is an output stream to write the list of object files for // the final ThinLTO linking. Can be nullptr. -static std::unique_ptr createLTO(raw_fd_ostream *LinkedObjectsFile) { +static std::unique_ptr createLTO(lto::IndexWriteCallback OnIndexWrite, + raw_fd_ostream *LinkedObjectsFile) { lto::Config Conf; // LLD supports the new relocations. @@ -159,8 +161,8 @@ if (Config->ThinLTOIndexOnly) { std::string OldPrefix, NewPrefix; std::tie(OldPrefix, NewPrefix) = Config->ThinLTOPrefixReplace.split(';'); - Backend = lto::createWriteIndexesThinBackend(OldPrefix, NewPrefix, true, - LinkedObjectsFile, nullptr); + Backend = lto::createWriteIndexesThinBackend( + OldPrefix, NewPrefix, true, LinkedObjectsFile, OnIndexWrite); } Conf.SampleProfile = Config->LTOSampleProfile; @@ -173,7 +175,11 @@ BitcodeCompiler::BitcodeCompiler() { LinkedObjects = createLinkedObjectsFile(); - LTOObj = createLTO(LinkedObjects.get()); + LTOObj = createLTO( + [&](const std::string &Identifier) { + ObjectToIndexFileState[Identifier] = true; + }, + LinkedObjects.get()); for (Symbol *Sym : Symtab->getSymbols()) { StringRef Name = Sym->getName(); for (StringRef Prefix : {"__start_", "__stop_"}) @@ -192,13 +198,8 @@ void BitcodeCompiler::add(BitcodeFile &F) { lto::InputFile &Obj = *F.Obj; - std::string OldPrefix, NewPrefix; - std::tie(OldPrefix, NewPrefix) = Config->ThinLTOPrefixReplace.split(';'); - - // Create the empty files which, if indexed, will be overwritten later. if (Config->ThinLTOIndexOnly) - writeEmptyDistributedBuildOutputs(Obj.getName(), OldPrefix, NewPrefix, - false); + ObjectToIndexFileState.insert({Obj.getName(), false}); unsigned SymNum = 0; std::vector Syms = F.getSymbols(); @@ -281,6 +282,25 @@ }, Cache)); + // Emit empty index files for non-indexed files + if (Config->ThinLTOIndexOnly) { + std::string OldPrefix, NewPrefix; + std::tie(OldPrefix, NewPrefix) = Config->ThinLTOPrefixReplace.split(';'); + for (auto &Identifier : ObjectToIndexFileState) + if (!Identifier.getValue()) + writeEmptyDistributedBuildOutputs(Identifier.getKey(), OldPrefix, + NewPrefix, /* SkipModule */ false); + } + + // ThinLTO with index only option is required to generate only the index + // files. After that, we exit from linker and ThinLTO backend runs in a + // distributed environment. + if (Config->ThinLTOIndexOnly) { + if (Config->SaveTemps) + saveBuffer(Buff[0], Config->OutputFile + ".lto.o"); + exit(0); + } + if (!Config->ThinLTOCacheDir.empty()) pruneCache(Config->ThinLTOCacheDir, Config->ThinLTOCachePolicy); @@ -297,12 +317,6 @@ Ret.push_back(Obj); } - // ThinLTO with index only option is required to generate only the index - // files. After that, we exit from linker and ThinLTO backend runs in a - // distributed environment. - if (Config->ThinLTOIndexOnly) - exit(0); - for (std::unique_ptr &File : Files) if (File) Ret.push_back(createObjectFile(*File)); Index: lld/test/ELF/lto/thinlto.ll =================================================================== --- lld/test/ELF/lto/thinlto.ll +++ lld/test/ELF/lto/thinlto.ll @@ -42,6 +42,11 @@ ; RUN: not ls %t2.o.thinlto.bc ; RUN: not ls %t4.o.thinlto.bc +; Ensure lld generates one regular LTO file via splitting for ThinLTO builds +; RUN: rm -f %t.lto.o +; RUN: ld.lld -save-temps --plugin-opt=thinlto-index-only -shared %t.o %t2.o -o %t +; RUN: llvm-readobj -h %t.lto.o | FileCheck %s --check-prefix=FORMAT + ; First force single-threaded mode ; RUN: rm -f %t.lto.o %t1.lto.o ; RUN: ld.lld -save-temps --thinlto-jobs=1 -shared %t.o %t2.o -o %t