Index: lld/trunk/ELF/LTO.h =================================================================== --- lld/trunk/ELF/LTO.h +++ lld/trunk/ELF/LTO.h @@ -55,6 +55,7 @@ std::vector> Files; llvm::DenseSet UsedStartStop; std::unique_ptr IndexFile; + llvm::StringMap ObjectToIndexFileState; }; } // namespace elf } // namespace lld Index: lld/trunk/ELF/LTO.cpp =================================================================== --- lld/trunk/ELF/LTO.cpp +++ lld/trunk/ELF/LTO.cpp @@ -137,9 +137,13 @@ if (!Path.empty()) IndexFile = openFile(Path); + auto OnIndexWrite = [&](const std::string &Identifier) { + ObjectToIndexFileState[Identifier] = true; + }; + Backend = lto::createWriteIndexesThinBackend( Config->ThinLTOPrefixReplace.first, Config->ThinLTOPrefixReplace.second, - Config->ThinLTOEmitImportsFiles, IndexFile.get(), nullptr); + Config->ThinLTOEmitImportsFiles, IndexFile.get(), OnIndexWrite); } else if (Config->ThinLTOJobs != -1U) { Backend = lto::createInProcessThinBackend(Config->ThinLTOJobs); } @@ -167,14 +171,8 @@ lto::InputFile &Obj = *F.Obj; bool IsExec = !Config->Shared && !Config->Relocatable; - // Create the empty files which, if indexed, will be overwritten later. - if (Config->ThinLTOIndexOnly) { - std::string Path = getThinLTOOutputFile(Obj.getName()); - openFile(Path + ".thinlto.bc"); - - if (Config->ThinLTOEmitImportsFiles) - openFile(Path + ".imports"); - } + if (Config->ThinLTOIndexOnly) + ObjectToIndexFileState.insert({Obj.getName(), false}); ArrayRef Syms = F.getSymbols(); ArrayRef ObjSyms = Obj.symbols(); @@ -226,7 +224,6 @@ // Merge all the bitcode files we have seen, codegen the result // and return the resulting ObjectFile(s). std::vector BitcodeCompiler::compile() { - std::vector Ret; unsigned MaxTasks = LTOObj->getMaxTasks(); Buff.resize(MaxTasks); Files.resize(MaxTasks); @@ -249,20 +246,16 @@ }, Cache)); - if (!Config->ThinLTOCacheDir.empty()) - pruneCache(Config->ThinLTOCacheDir, Config->ThinLTOCachePolicy); - - for (unsigned I = 0; I != MaxTasks; ++I) { - if (Buff[I].empty()) - continue; - if (Config->SaveTemps) { - if (I == 0) - saveBuffer(Buff[I], Config->OutputFile + ".lto.o"); - else - saveBuffer(Buff[I], Config->OutputFile + Twine(I) + ".lto.o"); - } - InputFile *Obj = createObjectFile(MemoryBufferRef(Buff[I], "lto.tmp")); - Ret.push_back(Obj); + // Emit empty index files for non-indexed files + if (Config->ThinLTOIndexOnly) { + for (auto &Identifier : ObjectToIndexFileState) + if (!Identifier.getValue()) { + std::string Path = getThinLTOOutputFile(Identifier.getKey()); + openFile(Path + ".thinlto.bc"); + + if (Config->ThinLTOEmitImportsFiles) + openFile(Path + ".imports"); + } } // If LazyObjFile has not been added to link, emit empty index files. @@ -286,6 +279,9 @@ openFile(Path + ".imports"); } + if (Config->SaveTemps) + saveBuffer(Buff[0], Config->OutputFile + ".lto.o"); + // 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. @@ -293,6 +289,22 @@ IndexFile->close(); return {}; } + if (!Config->ThinLTOCacheDir.empty()) + pruneCache(Config->ThinLTOCacheDir, Config->ThinLTOCachePolicy); + + std::vector Ret; + for (unsigned I = 0; I != MaxTasks; ++I) { + if (Buff[I].empty()) + continue; + if (Config->SaveTemps) { + if (I == 0) + saveBuffer(Buff[I], Config->OutputFile + ".lto.o"); + else + saveBuffer(Buff[I], Config->OutputFile + Twine(I) + ".lto.o"); + } + InputFile *Obj = createObjectFile(MemoryBufferRef(Buff[I], "lto.tmp")); + Ret.push_back(Obj); + } for (std::unique_ptr &File : Files) if (File) Index: lld/trunk/test/ELF/lto/thinlto.ll =================================================================== --- lld/trunk/test/ELF/lto/thinlto.ll +++ lld/trunk/test/ELF/lto/thinlto.ll @@ -49,6 +49,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 @@ -70,6 +75,7 @@ ; NM1: T f ; NM1-NOT: U g ; NM2: T g +; FORMAT: Format: ELF64-x86-64 ; The backend index for this module contains summaries from itself and ; Inputs/thinlto.ll, as it imports from the latter.