Index: include/llvm/Analysis/ModuleSummaryAnalysis.h =================================================================== --- include/llvm/Analysis/ModuleSummaryAnalysis.h +++ include/llvm/Analysis/ModuleSummaryAnalysis.h @@ -36,7 +36,7 @@ ModuleSummaryIndex buildModuleSummaryIndex( const Module &M, std::function GetBFICallback, - ProfileSummaryInfo *PSI); + ProfileSummaryInfo *PSI, bool LTOUnit = false); /// Analysis pass to provide the ModuleSummaryIndex object. class ModuleSummaryIndexAnalysis Index: include/llvm/Bitcode/BitcodeReader.h =================================================================== --- include/llvm/Bitcode/BitcodeReader.h +++ include/llvm/Bitcode/BitcodeReader.h @@ -51,6 +51,7 @@ struct BitcodeLTOInfo { bool IsThinLTO; bool HasSummary; + bool LTOUnit; }; /// Represents a module in a bitcode file. Index: include/llvm/Bitcode/BitcodeWriterPass.h =================================================================== --- include/llvm/Bitcode/BitcodeWriterPass.h +++ include/llvm/Bitcode/BitcodeWriterPass.h @@ -36,10 +36,13 @@ /// /// If \c EmitModuleHash, compute and emit the module hash in the bitcode /// (currently for use in ThinLTO incremental build). +/// +/// If \c LTOUnit, module was compiled with LTO and had LTOUnit enabled. ModulePass *createBitcodeWriterPass(raw_ostream &Str, bool ShouldPreserveUseListOrder = false, bool EmitSummaryIndex = false, - bool EmitModuleHash = false); + bool EmitModuleHash = false, + bool LTOUnit = false); /// Check whether a pass is a BitcodeWriterPass. bool isBitcodeWriterPass(Pass *P); @@ -53,6 +56,7 @@ bool ShouldPreserveUseListOrder; bool EmitSummaryIndex; bool EmitModuleHash; + bool LTOUnit; public: /// Construct a bitcode writer pass around a particular output stream. @@ -62,12 +66,15 @@ /// /// If \c EmitSummaryIndex, emit the summary index (currently /// for use in ThinLTO optimization). + /// + /// If \c LTOUnit, module was compiled with LTO and had LTOUnit enabled. explicit BitcodeWriterPass(raw_ostream &OS, bool ShouldPreserveUseListOrder = false, bool EmitSummaryIndex = false, - bool EmitModuleHash = false) + bool EmitModuleHash = false, bool LTOUnit = false) : OS(OS), ShouldPreserveUseListOrder(ShouldPreserveUseListOrder), - EmitSummaryIndex(EmitSummaryIndex), EmitModuleHash(EmitModuleHash) {} + EmitSummaryIndex(EmitSummaryIndex), EmitModuleHash(EmitModuleHash), + LTOUnit(LTOUnit) {} /// Run the bitcode writer pass, and output the module to the selected /// output stream. Index: include/llvm/IR/ModuleSummaryIndex.h =================================================================== --- include/llvm/IR/ModuleSummaryIndex.h +++ include/llvm/IR/ModuleSummaryIndex.h @@ -796,6 +796,9 @@ /// union. bool HaveGVs; + // True if the index was created for a module compiled with -flto-unit. + bool LTOUnit; + std::set CfiFunctionDefs; std::set CfiFunctionDecls; @@ -815,7 +818,8 @@ public: // See HaveGVs variable comment. - ModuleSummaryIndex(bool HaveGVs) : HaveGVs(HaveGVs), Saver(Alloc) {} + ModuleSummaryIndex(bool HaveGVs, bool LTOUnit = false) + : HaveGVs(HaveGVs), LTOUnit(LTOUnit), Saver(Alloc) {} bool haveGVs() const { return HaveGVs; } @@ -902,6 +906,9 @@ SkipModuleByDistributedBackend = true; } + bool ltoUnit() const { return LTOUnit; } + void setLtoUnit() { LTOUnit = true; } + bool isGlobalValueLive(const GlobalValueSummary *GVS) const { return !WithGlobalValueDeadStripping || GVS->isLive(); } Index: include/llvm/LTO/LTO.h =================================================================== --- include/llvm/LTO/LTO.h +++ include/llvm/LTO/LTO.h @@ -387,6 +387,9 @@ Error runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache); mutable bool CalledGetMaxTasks = false; + + // Use Optional to distinguish false from not yet initialized. + Optional LTOUnit; }; /// The resolution for a symbol. The linker must provide a SymbolResolution for Index: include/llvm/Transforms/IPO.h =================================================================== --- include/llvm/Transforms/IPO.h +++ include/llvm/Transforms/IPO.h @@ -269,7 +269,8 @@ /// Write ThinLTO-ready bitcode to Str. ModulePass *createWriteThinLTOBitcodePass(raw_ostream &Str, - raw_ostream *ThinLinkOS = nullptr); + raw_ostream *ThinLinkOS, + bool LTOUnit); } // End llvm namespace Index: include/llvm/Transforms/IPO/ThinLTOBitcodeWriter.h =================================================================== --- include/llvm/Transforms/IPO/ThinLTOBitcodeWriter.h +++ include/llvm/Transforms/IPO/ThinLTOBitcodeWriter.h @@ -26,12 +26,15 @@ : public PassInfoMixin { raw_ostream &OS; raw_ostream *ThinLinkOS; + bool LTOUnit; public: // Writes bitcode to OS. Also write thin link file to ThinLinkOS, if - // it's not nullptr. - ThinLTOBitcodeWriterPass(raw_ostream &OS, raw_ostream *ThinLinkOS) - : OS(OS), ThinLinkOS(ThinLinkOS) {} + // it's not nullptr. LTOUnit will be true if the corresponding + // codegen option was set. + ThinLTOBitcodeWriterPass(raw_ostream &OS, raw_ostream *ThinLinkOS, + bool LTOUnit) + : OS(OS), ThinLinkOS(ThinLinkOS), LTOUnit(LTOUnit) {} PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); }; Index: lib/Analysis/ModuleSummaryAnalysis.cpp =================================================================== --- lib/Analysis/ModuleSummaryAnalysis.cpp +++ lib/Analysis/ModuleSummaryAnalysis.cpp @@ -419,9 +419,9 @@ ModuleSummaryIndex llvm::buildModuleSummaryIndex( const Module &M, std::function GetBFICallback, - ProfileSummaryInfo *PSI) { + ProfileSummaryInfo *PSI, bool LTOUnit) { assert(PSI); - ModuleSummaryIndex Index(/*HaveGVs=*/true); + ModuleSummaryIndex Index(/*HaveGVs=*/true, LTOUnit); // Identify the local values in the llvm.used and llvm.compiler.used sets, // which should not be exported as they would then require renaming and Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -5233,15 +5233,22 @@ break; case bitc::FS_FLAGS: { // [flags] uint64_t Flags = Record[0]; - // Scan flags (set only on the combined index). - assert(Flags <= 0x3 && "Unexpected bits in flag"); + // Scan flags. + assert(Flags <= 0x7 && "Unexpected bits in flag"); // 1 bit: WithGlobalValueDeadStripping flag. + // Set on combined index only. if (Flags & 0x1) TheIndex.setWithGlobalValueDeadStripping(); // 1 bit: SkipModuleByDistributedBackend flag. + // Set on combined index only. if (Flags & 0x2) TheIndex.setSkipModuleByDistributedBackend(); + // 1 bit: LTOUnit flag. + // Set on per module indexes. It is up to the client to validate + // the consistency of this flag across modules being linked. + if (Flags & 0x4) + TheIndex.setLtoUnit(); break; } case bitc::FS_VALUE_GUID: { // [valueid, refguid] @@ -5820,6 +5827,44 @@ return std::move(Index); } +static Expected getLTOUnitFlag(BitstreamCursor &Stream, unsigned ID) { + if (Stream.EnterSubBlock(ID)) + return error("Invalid record"); + SmallVector Record; + + while (true) { + BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); + + switch (Entry.Kind) { + case BitstreamEntry::SubBlock: // Handled for us already. + case BitstreamEntry::Error: + return error("Malformed block"); + case BitstreamEntry::EndBlock: + // If no flags record found, conservatively return false. + return false; + case BitstreamEntry::Record: + // The interesting case. + break; + } + + // Look for the FS_FLAGS record. + Record.clear(); + auto BitCode = Stream.readRecord(Entry.ID, Record); + switch (BitCode) { + default: // Default behavior: ignore. + break; + case bitc::FS_FLAGS: { // [flags] + uint64_t Flags = Record[0]; + // Scan flags. + assert(Flags <= 0x7 && "Unexpected bits in flag"); + + return Flags & 0x4; + } + } + } + llvm_unreachable("Exit infinite loop"); +} + // Check if the given bitcode buffer contains a global value summary block. Expected BitcodeModule::getLTOInfo() { BitstreamCursor Stream(Buffer); @@ -5835,14 +5880,25 @@ case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: - return BitcodeLTOInfo{/*IsThinLTO=*/false, /*HasSummary=*/false}; + return BitcodeLTOInfo{/*IsThinLTO=*/false, /*HasSummary=*/false, + /*LTOUnit=*/false}; case BitstreamEntry::SubBlock: - if (Entry.ID == bitc::GLOBALVAL_SUMMARY_BLOCK_ID) - return BitcodeLTOInfo{/*IsThinLTO=*/true, /*HasSummary=*/true}; + if (Entry.ID == bitc::GLOBALVAL_SUMMARY_BLOCK_ID) { + Expected LTOUnit = getLTOUnitFlag(Stream, Entry.ID); + if (!LTOUnit) + return LTOUnit.takeError(); + return BitcodeLTOInfo{/*IsThinLTO=*/true, /*HasSummary=*/true, + *LTOUnit}; + } - if (Entry.ID == bitc::FULL_LTO_GLOBALVAL_SUMMARY_BLOCK_ID) - return BitcodeLTOInfo{/*IsThinLTO=*/false, /*HasSummary=*/true}; + if (Entry.ID == bitc::FULL_LTO_GLOBALVAL_SUMMARY_BLOCK_ID) { + Expected LTOUnit = getLTOUnitFlag(Stream, Entry.ID); + if (!LTOUnit) + return LTOUnit.takeError(); + return BitcodeLTOInfo{/*IsThinLTO=*/false, /*HasSummary=*/true, + *LTOUnit}; + } // Ignore other sub-blocks. if (Stream.SkipBlock()) Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -3562,6 +3562,13 @@ Stream.EmitRecord(bitc::FS_VERSION, ArrayRef{INDEX_VERSION}); + // Write the index flags. + uint64_t Flags = 0; + // Bits 1 and 2 are set only in the combined index, skip them. + if (Index->ltoUnit()) + Flags |= 0x4; + Stream.EmitRecord(bitc::FS_FLAGS, ArrayRef{Flags}); + if (Index->begin() == Index->end()) { Stream.ExitBlock(); return; @@ -3674,6 +3681,8 @@ Flags |= 0x1; if (Index.skipModuleByDistributedBackend()) Flags |= 0x2; + if (Index.ltoUnit()) + Flags |= 0x4; Stream.EmitRecord(bitc::FS_FLAGS, ArrayRef{Flags}); for (const auto &GVI : valueIds()) { Index: lib/Bitcode/Writer/BitcodeWriterPass.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriterPass.cpp +++ lib/Bitcode/Writer/BitcodeWriterPass.cpp @@ -20,9 +20,11 @@ using namespace llvm; PreservedAnalyses BitcodeWriterPass::run(Module &M, ModuleAnalysisManager &AM) { - const ModuleSummaryIndex *Index = + ModuleSummaryIndex *Index = EmitSummaryIndex ? &(AM.getResult(M)) : nullptr; + if (LTOUnit) + Index->setLtoUnit(); WriteBitcodeToFile(M, OS, ShouldPreserveUseListOrder, Index, EmitModuleHash); return PreservedAnalyses::all(); } @@ -33,28 +35,33 @@ bool ShouldPreserveUseListOrder; bool EmitSummaryIndex; bool EmitModuleHash; + bool LTOUnit; public: static char ID; // Pass identification, replacement for typeid - WriteBitcodePass() : ModulePass(ID), OS(dbgs()) { + WriteBitcodePass() : ModulePass(ID), OS(dbgs()), LTOUnit(false) { initializeWriteBitcodePassPass(*PassRegistry::getPassRegistry()); } explicit WriteBitcodePass(raw_ostream &o, bool ShouldPreserveUseListOrder, - bool EmitSummaryIndex, bool EmitModuleHash) + bool EmitSummaryIndex, bool EmitModuleHash, + bool LTOUnit) : ModulePass(ID), OS(o), ShouldPreserveUseListOrder(ShouldPreserveUseListOrder), - EmitSummaryIndex(EmitSummaryIndex), EmitModuleHash(EmitModuleHash) { + EmitSummaryIndex(EmitSummaryIndex), EmitModuleHash(EmitModuleHash), + LTOUnit(LTOUnit) { initializeWriteBitcodePassPass(*PassRegistry::getPassRegistry()); } StringRef getPassName() const override { return "Bitcode Writer"; } bool runOnModule(Module &M) override { - const ModuleSummaryIndex *Index = + ModuleSummaryIndex *Index = EmitSummaryIndex ? &(getAnalysis().getIndex()) : nullptr; + if (LTOUnit) + Index->setLtoUnit(); WriteBitcodeToFile(M, OS, ShouldPreserveUseListOrder, Index, EmitModuleHash); return false; @@ -76,9 +83,10 @@ ModulePass *llvm::createBitcodeWriterPass(raw_ostream &Str, bool ShouldPreserveUseListOrder, - bool EmitSummaryIndex, bool EmitModuleHash) { - return new WriteBitcodePass(Str, ShouldPreserveUseListOrder, - EmitSummaryIndex, EmitModuleHash); + bool EmitSummaryIndex, + bool EmitModuleHash, bool LTOUnit) { + return new WriteBitcodePass(Str, ShouldPreserveUseListOrder, EmitSummaryIndex, + EmitModuleHash, LTOUnit); } bool llvm::isBitcodeWriterPass(Pass *P) { Index: lib/LTO/LTO.cpp =================================================================== --- lib/LTO/LTO.cpp +++ lib/LTO/LTO.cpp @@ -520,6 +520,14 @@ if (!LTOInfo) return LTOInfo.takeError(); + if (LTOUnit.hasValue()) { + if (LTOUnit.getValue() != LTOInfo->LTOUnit) + return make_error("Expect all bitcode to be compiled with " + "same value of -f[no-]lto-unit", + inconvertibleErrorCode()); + } else + LTOUnit = LTOInfo->LTOUnit; + BitcodeModule BM = Input.Mods[ModI]; auto ModSyms = Input.module_symbols(ModI); addModuleToGlobalRes(ModSyms, {ResI, ResE}, Index: lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp =================================================================== --- lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp +++ lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp @@ -204,7 +204,8 @@ // regular LTO module with an index for summary-based dead stripping. ProfileSummaryInfo PSI(M); M.addModuleFlag(Module::Error, "ThinLTO", uint32_t(0)); - ModuleSummaryIndex Index = buildModuleSummaryIndex(M, nullptr, &PSI); + ModuleSummaryIndex Index = buildModuleSummaryIndex(M, nullptr, &PSI, + /*LTOUnit=*/true); WriteBitcodeToFile(M, OS, /*ShouldPreserveUseListOrder=*/false, &Index); if (ThinLinkOS) @@ -379,13 +380,14 @@ // FIXME: Try to re-use BSI and PFI from the original module here. ProfileSummaryInfo PSI(M); - ModuleSummaryIndex Index = buildModuleSummaryIndex(M, nullptr, &PSI); + ModuleSummaryIndex Index = buildModuleSummaryIndex(M, nullptr, &PSI, + /*LTOUnit=*/true); // Mark the merged module as requiring full LTO. We still want an index for // it though, so that it can participate in summary-based dead stripping. MergedM->addModuleFlag(Module::Error, "ThinLTO", uint32_t(0)); ModuleSummaryIndex MergedMIndex = - buildModuleSummaryIndex(*MergedM, nullptr, &PSI); + buildModuleSummaryIndex(*MergedM, nullptr, &PSI, /*LTOUnit=*/true); SmallVector Buffer; @@ -429,12 +431,17 @@ void writeThinLTOBitcode(raw_ostream &OS, raw_ostream *ThinLinkOS, function_ref AARGetter, - Module &M, const ModuleSummaryIndex *Index) { - // See if this module has any type metadata. If so, we need to split it. - if (requiresSplit(M)) + Module &M, ModuleSummaryIndex *Index, bool LTOUnit) { + // See if this module has any type metadata and the client requested + // an LTOUnit. If so, we need to split it. + if (LTOUnit && requiresSplit(M)) return splitAndWriteThinLTOBitcode(OS, ThinLinkOS, AARGetter, M); - // Otherwise we can just write it out as a regular module. + // Otherwise we can just write it out as a regular module. However, + // record in the index whether it was compiled with LTOUnit, for later + // consistency checking when linking the resulting modules. + if (LTOUnit) + Index->setLtoUnit(); // Save the module hash produced for the full bitcode, which will // be used in the backends, and use that in the minimized bitcode @@ -454,24 +461,28 @@ // The output stream on which to emit a minimized module for use // just in the thin link, if requested. raw_ostream *ThinLinkOS; + bool LTOUnit; public: static char ID; // Pass identification, replacement for typeid - WriteThinLTOBitcode() : ModulePass(ID), OS(dbgs()), ThinLinkOS(nullptr) { + WriteThinLTOBitcode() + : ModulePass(ID), OS(dbgs()), ThinLinkOS(nullptr), LTOUnit(false) { initializeWriteThinLTOBitcodePass(*PassRegistry::getPassRegistry()); } - explicit WriteThinLTOBitcode(raw_ostream &o, raw_ostream *ThinLinkOS) - : ModulePass(ID), OS(o), ThinLinkOS(ThinLinkOS) { + explicit WriteThinLTOBitcode(raw_ostream &o, raw_ostream *ThinLinkOS, + bool LTOUnit) + : ModulePass(ID), OS(o), ThinLinkOS(ThinLinkOS), LTOUnit(LTOUnit) { initializeWriteThinLTOBitcodePass(*PassRegistry::getPassRegistry()); } StringRef getPassName() const override { return "ThinLTO Bitcode Writer"; } bool runOnModule(Module &M) override { - const ModuleSummaryIndex *Index = + ModuleSummaryIndex *Index = &(getAnalysis().getIndex()); - writeThinLTOBitcode(OS, ThinLinkOS, LegacyAARGetter(*this), M, Index); + writeThinLTOBitcode(OS, ThinLinkOS, LegacyAARGetter(*this), M, Index, + LTOUnit); return true; } void getAnalysisUsage(AnalysisUsage &AU) const override { @@ -493,8 +504,9 @@ "Write ThinLTO Bitcode", false, true) ModulePass *llvm::createWriteThinLTOBitcodePass(raw_ostream &Str, - raw_ostream *ThinLinkOS) { - return new WriteThinLTOBitcode(Str, ThinLinkOS); + raw_ostream *ThinLinkOS, + bool LTOUnit) { + return new WriteThinLTOBitcode(Str, ThinLinkOS, LTOUnit); } PreservedAnalyses @@ -505,6 +517,6 @@ [&FAM](Function &F) -> AAResults & { return FAM.getResult(F); }, - M, &AM.getResult(M)); + M, &AM.getResult(M), LTOUnit); return PreservedAnalyses::all(); } Index: test/Bitcode/thinlto-alias.ll =================================================================== --- test/Bitcode/thinlto-alias.ll +++ test/Bitcode/thinlto-alias.ll @@ -18,6 +18,7 @@ ; CHECK-NEXT: Index: test/Bitcode/thinlto-alias2.ll =================================================================== --- test/Bitcode/thinlto-alias2.ll +++ test/Bitcode/thinlto-alias2.ll @@ -4,6 +4,7 @@ ; CHECK: ; CHECK-NEXT: Index: test/Bitcode/thinlto-function-summary-callgraph-cast.ll =================================================================== --- test/Bitcode/thinlto-function-summary-callgraph-cast.ll +++ test/Bitcode/thinlto-function-summary-callgraph-cast.ll @@ -5,6 +5,7 @@ ; CHECK: ; "another_caller" has only references but no calls. Index: test/Bitcode/thinlto-function-summary-callgraph-pgo.ll =================================================================== --- test/Bitcode/thinlto-function-summary-callgraph-pgo.ll +++ test/Bitcode/thinlto-function-summary-callgraph-pgo.ll @@ -16,6 +16,7 @@ ; CHECK-NEXT: ; CHECK-NEXT: Index: test/Bitcode/thinlto-function-summary-callgraph-profile-summary.ll =================================================================== --- test/Bitcode/thinlto-function-summary-callgraph-profile-summary.ll +++ test/Bitcode/thinlto-function-summary-callgraph-profile-summary.ll @@ -46,6 +46,7 @@ ; CHECK-NEXT: ; op4=hot1 op6=cold op8=hot2 op10=hot4 op12=none1 op14=hot3 op16=none2 op18=none3 op20=123 ; CHECK-NEXT: Index: test/Bitcode/thinlto-function-summary-callgraph-relbf.ll =================================================================== --- test/Bitcode/thinlto-function-summary-callgraph-relbf.ll +++ test/Bitcode/thinlto-function-summary-callgraph-relbf.ll @@ -12,6 +12,7 @@ ; CHECK-NEXT: Index: test/Bitcode/thinlto-function-summary-callgraph-sample-profile-summary.ll =================================================================== --- test/Bitcode/thinlto-function-summary-callgraph-sample-profile-summary.ll +++ test/Bitcode/thinlto-function-summary-callgraph-sample-profile-summary.ll @@ -29,6 +29,7 @@ ; CHECK-LABEL: ; op4=none1 op6=hot1 op8=cold1 op10=none2 op12=hot2 op14=cold2 op16=none3 op18=hot3 op20=cold3 op22=123 ; CHECK-NEXT: Index: test/Bitcode/thinlto-function-summary-callgraph.ll =================================================================== --- test/Bitcode/thinlto-function-summary-callgraph.ll +++ test/Bitcode/thinlto-function-summary-callgraph.ll @@ -17,6 +17,7 @@ ; CHECK-NEXT: Index: test/Bitcode/thinlto-function-summary.ll =================================================================== --- test/Bitcode/thinlto-function-summary.ll +++ test/Bitcode/thinlto-function-summary.ll @@ -17,6 +17,7 @@ ; BC-NEXT: &1 | FileCheck %s --check-prefix=NOERROR --allow-empty + +; Linking bitcode both without LTOUnit set should work +; RUN: opt -module-summary -o %t1 %s +; RUN: llvm-bcanalyzer -dump %t1 | FileCheck %s --check-prefix=NOLTOUNIT +; RUN: opt -module-summary -o %t2 %s +; RUN: llvm-bcanalyzer -dump %t2 | FileCheck %s --check-prefix=NOLTOUNIT +; RUN: llvm-lto2 run -o %t3 %t1 %t2 2>&1 | FileCheck %s --check-prefix=NOERROR --allow-empty + +; Linking bitcode with different values of LTOUnit should fail +; RUN: opt -thinlto-bc -o %t1 %s +; RUN: llvm-bcanalyzer -dump %t1 | FileCheck %s --check-prefix=LTOUNIT +; RUN: opt -module-summary -o %t2 %s +; RUN: llvm-bcanalyzer -dump %t2 | FileCheck %s --check-prefix=NOLTOUNIT +; RUN: not llvm-lto2 run -o %t3 %t1 %t2 2>&1 | FileCheck %s --check-prefix=ERROR + +; Linking bitcode with different values of LTOUnit should fail (reverse order) +; RUN: opt -module-summary -o %t1 %s +; RUN: llvm-bcanalyzer -dump %t1 | FileCheck %s --check-prefix=NOLTOUNIT +; RUN: opt -thinlto-bc -o %t2 %s +; RUN: llvm-bcanalyzer -dump %t2 | FileCheck %s --check-prefix=LTOUNIT +; RUN: not llvm-lto2 run -o %t3 %t1 %t2 2>&1 | FileCheck %s --check-prefix=ERROR + +; ERROR: Expect all bitcode to be compiled with same value of -f[no-]lto-unit +; NOERROR-NOT: Expect all bitcode to be compiled with same value of -f[no-]lto-unit + +; LTOUNIT: +; NOLTOUNIT: + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" Index: tools/opt/NewPMDriver.cpp =================================================================== --- tools/opt/NewPMDriver.cpp +++ tools/opt/NewPMDriver.cpp @@ -308,7 +308,8 @@ break; case OK_OutputThinLTOBitcode: MPM.addPass(ThinLTOBitcodeWriterPass( - Out->os(), ThinLTOLinkOut ? &ThinLTOLinkOut->os() : nullptr)); + Out->os(), ThinLTOLinkOut ? &ThinLTOLinkOut->os() : nullptr, + /*LTOUnit=*/true)); break; } Index: tools/opt/opt.cpp =================================================================== --- tools/opt/opt.cpp +++ tools/opt/opt.cpp @@ -813,7 +813,7 @@ Passes.add(createPrintModulePass(*OS, "", PreserveAssemblyUseListOrder)); } else if (OutputThinLTOBC) Passes.add(createWriteThinLTOBitcodePass( - *OS, ThinLinkOut ? &ThinLinkOut->os() : nullptr)); + *OS, ThinLinkOut ? &ThinLinkOut->os() : nullptr, /*LTOUnit=*/true)); else Passes.add(createBitcodeWriterPass(*OS, PreserveBitcodeUseListOrder, EmitSummaryIndex, EmitModuleHash));