Index: llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp +++ llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp @@ -6097,13 +6097,18 @@ return error("Invalid record"); break; case bitc::GLOBALVAL_SUMMARY_BLOCK_ID: - assert(VSTOffset > 0 && "Expected non-zero VST offset"); assert(!SeenValueSymbolTable && "Already read VST when parsing summary block?"); - if (std::error_code EC = - parseValueSymbolTable(VSTOffset, ValueIdToLinkageMap)) - return EC; - SeenValueSymbolTable = true; + // We might not have a VST if there were no values in the + // summary. An empty summary block generated when we are + // performing ThinLTO compiles so we don't later invoke + // the regular LTO process on them. + if (VSTOffset > 0) { + if (std::error_code EC = + parseValueSymbolTable(VSTOffset, ValueIdToLinkageMap)) + return EC; + SeenValueSymbolTable = true; + } SeenGlobalValSummary = true; if (std::error_code EC = parseEntireSummary()) return EC; Index: llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp +++ llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -3341,13 +3341,15 @@ /// Emit the per-module summary section alongside the rest of /// the module's bitcode. void ModuleBitcodeWriter::writePerModuleGlobalValueSummary() { - if (Index->begin() == Index->end()) - return; - Stream.EnterSubblock(bitc::GLOBALVAL_SUMMARY_BLOCK_ID, 4); Stream.EmitRecord(bitc::FS_VERSION, ArrayRef{INDEX_VERSION}); + if (Index->begin() == Index->end()) { + Stream.ExitBlock(); + return; + } + // Abbrev for FS_PERMODULE. BitCodeAbbrev *Abbv = new BitCodeAbbrev(); Abbv->Add(BitCodeAbbrevOp(bitc::FS_PERMODULE)); Index: llvm/trunk/lib/LTO/LTO.cpp =================================================================== --- llvm/trunk/lib/LTO/LTO.cpp +++ llvm/trunk/lib/LTO/LTO.cpp @@ -713,6 +713,16 @@ ModuleToDefinedGVSummaries(ThinLTO.ModuleMap.size()); ThinLTO.CombinedIndex.collectDefinedGVSummariesPerModule( ModuleToDefinedGVSummaries); + // Create entries for any modules that didn't have any GV summaries + // (either they didn't have any GVs to start with, or we suppressed + // generation of the summaries because they e.g. had inline assembly + // uses that couldn't be promoted/renamed on export). This is so + // InProcessThinBackend::start can still launch a backend thread, which + // is passed the map of summaries for the module, without any special + // handling for this case. + for (auto &Mod : ThinLTO.ModuleMap) + if (!ModuleToDefinedGVSummaries.count(Mod.first)) + ModuleToDefinedGVSummaries.try_emplace(Mod.first); StringMap ImportLists( ThinLTO.ModuleMap.size()); Index: llvm/trunk/test/Bitcode/thinlto-empty-summary-section.ll =================================================================== --- llvm/trunk/test/Bitcode/thinlto-empty-summary-section.ll +++ llvm/trunk/test/Bitcode/thinlto-empty-summary-section.ll @@ -0,0 +1,7 @@ +; Ensure we get a summary block even when the file is empty. +; RUN: opt -module-summary %s -o %t.o +; RUN: llvm-bcanalyzer -dump %t.o | FileCheck %s + +; CHECK: Index: llvm/trunk/test/ThinLTO/X86/Inputs/emit_imports.ll =================================================================== --- llvm/trunk/test/ThinLTO/X86/Inputs/emit_imports.ll +++ llvm/trunk/test/ThinLTO/X86/Inputs/emit_imports.ll @@ -1,3 +1,6 @@ +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + define void @g() { entry: ret void Index: llvm/trunk/test/ThinLTO/X86/Inputs/empty.ll =================================================================== --- llvm/trunk/test/ThinLTO/X86/Inputs/empty.ll +++ llvm/trunk/test/ThinLTO/X86/Inputs/empty.ll @@ -0,0 +1,2 @@ +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" Index: llvm/trunk/test/ThinLTO/X86/emit_imports.ll =================================================================== --- llvm/trunk/test/ThinLTO/X86/emit_imports.ll +++ llvm/trunk/test/ThinLTO/X86/emit_imports.ll @@ -1,7 +1,11 @@ ; RUN: opt -module-summary %s -o %t1.bc ; RUN: opt -module-summary %p/Inputs/emit_imports.ll -o %t2.bc -; RUN: llvm-lto -thinlto-action=thinlink -o %t.index.bc %t1.bc %t2.bc -; RUN: llvm-lto -thinlto-action=emitimports -thinlto-index %t.index.bc %t1.bc %t2.bc +; Include a file with an empty module summary index, to ensure that the expected +; output files are created regardless, for a distributed build system. +; RUN: opt -module-summary %p/Inputs/empty.ll -o %t3.bc +; RUN: rm -f %t3.bc.imports +; RUN: llvm-lto -thinlto-action=thinlink -o %t.index.bc %t1.bc %t2.bc %t3.bc +; RUN: llvm-lto -thinlto-action=emitimports -thinlto-index %t.index.bc %t1.bc %t2.bc %t3.bc ; The imports file for this module contains the bitcode file for ; Inputs/emit_imports.ll @@ -12,9 +16,13 @@ ; The imports file for Input/emit_imports.ll is empty as it does not import anything. ; RUN: cat %t2.bc.imports | count 0 +; The imports file for Input/empty.ll is empty but should exist. +; RUN: cat %t3.bc.imports | count 0 + ; RUN: rm -f %t1.thinlto.bc %t1.bc.imports ; RUN: rm -f %t2.thinlto.bc %t2.bc.imports -; RUN: llvm-lto2 %t1.bc %t2.bc -o %t.o \ +; RUN: rm -f %t3.bc.thinlto.bc %t3.bc.imports +; RUN: llvm-lto2 %t1.bc %t2.bc %t3.bc -o %t.o -save-temps \ ; RUN: -thinlto-distributed-indexes \ ; RUN: -r=%t1.bc,g, \ ; RUN: -r=%t1.bc,f,px \ @@ -26,6 +34,15 @@ ; The imports file for Input/emit_imports.ll is empty as it does not import anything. ; RUN: cat %t2.bc.imports | count 0 +; The imports file for Input/empty.ll is empty but should exist. +; RUN: cat %t3.bc.imports | count 0 + +; The index file should be created even for the input with an empty summary. +; RUN: ls %t3.bc.thinlto.bc + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + declare void @g(...) define void @f() { Index: llvm/trunk/test/tools/gold/X86/thinlto_emit_imports.ll =================================================================== --- llvm/trunk/test/tools/gold/X86/thinlto_emit_imports.ll +++ llvm/trunk/test/tools/gold/X86/thinlto_emit_imports.ll @@ -1,13 +1,17 @@ ; Generate summary sections and test gold handling. ; RUN: opt -module-summary %s -o %t.o ; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t2.o +; Include a file with an empty module summary index, to ensure that the expected +; output files are created regardless, for a distributed build system. +; RUN: opt -module-summary %p/Inputs/thinlto_empty.ll -o %t3.o ; Ensure gold generates imports files if requested for distributed backends. +; RUN: rm -f %t3.o.imports %t3.o.thinlto.bc ; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so \ ; RUN: --plugin-opt=thinlto \ ; RUN: --plugin-opt=thinlto-index-only \ ; RUN: --plugin-opt=thinlto-emit-imports-files \ -; RUN: -shared %t.o %t2.o -o %t3 +; RUN: -shared %t.o %t2.o %t3.o -o %t4 ; The imports file for this module contains the bitcode file for ; Inputs/thinlto.ll @@ -18,6 +22,12 @@ ; The imports file for Input/thinlto.ll is empty as it does not import anything. ; RUN: cat %t2.o.imports | count 0 +; The imports file for Input/thinlto_empty.ll is empty but should exist. +; RUN: cat %t3.o.imports | count 0 + +; The index file should be created even for the input with an empty summary. +; RUN: ls %t3.o.thinlto.bc + declare void @g(...) define void @f() {