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 EnableSplitLTOUnit = 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 EnableSplitLTOUnit; }; /// 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,14 @@ /// /// If \c EmitModuleHash, compute and emit the module hash in the bitcode /// (currently for use in ThinLTO incremental build). +/// +/// If \c EnableSplitLTOUnit, module was compiled with LTO and had LTOUnit +/// splitting enabled. ModulePass *createBitcodeWriterPass(raw_ostream &Str, bool ShouldPreserveUseListOrder = false, bool EmitSummaryIndex = false, - bool EmitModuleHash = false); + bool EmitModuleHash = false, + bool EnableSplitLTOUnit = false); /// Check whether a pass is a BitcodeWriterPass. bool isBitcodeWriterPass(Pass *P); @@ -53,6 +57,7 @@ bool ShouldPreserveUseListOrder; bool EmitSummaryIndex; bool EmitModuleHash; + bool EnableSplitLTOUnit; public: /// Construct a bitcode writer pass around a particular output stream. @@ -62,12 +67,17 @@ /// /// If \c EmitSummaryIndex, emit the summary index (currently /// for use in ThinLTO optimization). + /// + /// If \c EnableSplitLTOUnit, module was compiled with LTO and had LTOUnit + /// splitting enabled. explicit BitcodeWriterPass(raw_ostream &OS, bool ShouldPreserveUseListOrder = false, bool EmitSummaryIndex = false, - bool EmitModuleHash = false) + bool EmitModuleHash = false, + bool EnableSplitLTOUnit = false) : OS(OS), ShouldPreserveUseListOrder(ShouldPreserveUseListOrder), - EmitSummaryIndex(EmitSummaryIndex), EmitModuleHash(EmitModuleHash) {} + EmitSummaryIndex(EmitSummaryIndex), EmitModuleHash(EmitModuleHash), + EnableSplitLTOUnit(EnableSplitLTOUnit) {} /// 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 @@ -800,6 +800,9 @@ /// union. bool HaveGVs; + // True if the index was created for a module compiled with -fsplit-lto-unit. + bool EnableSplitLTOUnit; + std::set CfiFunctionDefs; std::set CfiFunctionDecls; @@ -819,7 +822,9 @@ public: // See HaveGVs variable comment. - ModuleSummaryIndex(bool HaveGVs) : HaveGVs(HaveGVs), Saver(Alloc) {} + ModuleSummaryIndex(bool HaveGVs, bool EnableSplitLTOUnit = false) + : HaveGVs(HaveGVs), EnableSplitLTOUnit(EnableSplitLTOUnit), Saver(Alloc) { + } bool haveGVs() const { return HaveGVs; } @@ -906,6 +911,9 @@ SkipModuleByDistributedBackend = true; } + bool enableSplitLtoUnit() const { return EnableSplitLTOUnit; } + void setEnableSplitLtoUnit() { EnableSplitLTOUnit = 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 EnableSplitLTOUnit; }; /// 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 EnableSplitLTOUnit); } // 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,16 @@ : public PassInfoMixin { raw_ostream &OS; raw_ostream *ThinLinkOS; + bool EnableSplitLTOUnit; 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. EnableSplitLTOUnit will be true if the corresponding + // codegen option was set. + ThinLTOBitcodeWriterPass(raw_ostream &OS, raw_ostream *ThinLinkOS, + bool EnableSplitLTOUnit) + : OS(OS), ThinLinkOS(ThinLinkOS), EnableSplitLTOUnit(EnableSplitLTOUnit) { + } PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); }; Index: lib/Analysis/ModuleSummaryAnalysis.cpp =================================================================== --- lib/Analysis/ModuleSummaryAnalysis.cpp +++ lib/Analysis/ModuleSummaryAnalysis.cpp @@ -422,9 +422,9 @@ ModuleSummaryIndex llvm::buildModuleSummaryIndex( const Module &M, std::function GetBFICallback, - ProfileSummaryInfo *PSI) { + ProfileSummaryInfo *PSI, bool EnableSplitLTOUnit) { assert(PSI); - ModuleSummaryIndex Index(/*HaveGVs=*/true); + ModuleSummaryIndex Index(/*HaveGVs=*/true, EnableSplitLTOUnit); // 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 @@ -5283,15 +5283,24 @@ 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: DisableSplitLTOUnit flag. + // Set on per module indexes. It is up to the client to validate + // the consistency of this flag across modules being linked. + // We recorded the reverse of the EnableSplitLtoUnit flag, for backwards + // compatibility with older bitcode when splitting was enabled by default. + if (!(Flags & 0x4)) + TheIndex.setEnableSplitLtoUnit(); break; } case bitc::FS_VALUE_GUID: { // [valueid, refguid] @@ -5870,6 +5879,47 @@ return std::move(Index); } +static Expected getEnableSplitLTOUnitFlag(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"); + + // We recorded the reverse of the EnableSplitLtoUnit flag, for backwards + // compatibility with older bitcode when splitting was enabled by default. + 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); @@ -5885,14 +5935,27 @@ case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: - return BitcodeLTOInfo{/*IsThinLTO=*/false, /*HasSummary=*/false}; + return BitcodeLTOInfo{/*IsThinLTO=*/false, /*HasSummary=*/false, + /*EnableSplitLTOUnit=*/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 EnableSplitLTOUnit = + getEnableSplitLTOUnitFlag(Stream, Entry.ID); + if (!EnableSplitLTOUnit) + return EnableSplitLTOUnit.takeError(); + return BitcodeLTOInfo{/*IsThinLTO=*/true, /*HasSummary=*/true, + *EnableSplitLTOUnit}; + } - 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 EnableSplitLTOUnit = + getEnableSplitLTOUnitFlag(Stream, Entry.ID); + if (!EnableSplitLTOUnit) + return EnableSplitLTOUnit.takeError(); + return BitcodeLTOInfo{/*IsThinLTO=*/false, /*HasSummary=*/true, + *EnableSplitLTOUnit}; + } // Ignore other sub-blocks. if (Stream.SkipBlock()) Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -3613,6 +3613,15 @@ 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. + // We record the reverse of the EnableSplitLtoUnit flag, for backwards + // compatibility with older bitcode when splitting was enabled by default. + if (!Index->enableSplitLtoUnit()) + Flags |= 0x4; + Stream.EmitRecord(bitc::FS_FLAGS, ArrayRef{Flags}); + if (Index->begin() == Index->end()) { Stream.ExitBlock(); return; @@ -3725,6 +3734,10 @@ Flags |= 0x1; if (Index.skipModuleByDistributedBackend()) Flags |= 0x2; + // We record the reverse of the EnableSplitLtoUnit flag, for backwards + // compatibility with older bitcode when splitting was enabled by default. + if (!Index.enableSplitLtoUnit()) + 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 (EnableSplitLTOUnit) + Index->setEnableSplitLtoUnit(); WriteBitcodeToFile(M, OS, ShouldPreserveUseListOrder, Index, EmitModuleHash); return PreservedAnalyses::all(); } @@ -33,28 +35,33 @@ bool ShouldPreserveUseListOrder; bool EmitSummaryIndex; bool EmitModuleHash; + bool EnableSplitLTOUnit; public: static char ID; // Pass identification, replacement for typeid - WriteBitcodePass() : ModulePass(ID), OS(dbgs()) { + WriteBitcodePass() : ModulePass(ID), OS(dbgs()), EnableSplitLTOUnit(false) { initializeWriteBitcodePassPass(*PassRegistry::getPassRegistry()); } explicit WriteBitcodePass(raw_ostream &o, bool ShouldPreserveUseListOrder, - bool EmitSummaryIndex, bool EmitModuleHash) + bool EmitSummaryIndex, bool EmitModuleHash, + bool EnableSplitLTOUnit) : ModulePass(ID), OS(o), ShouldPreserveUseListOrder(ShouldPreserveUseListOrder), - EmitSummaryIndex(EmitSummaryIndex), EmitModuleHash(EmitModuleHash) { + EmitSummaryIndex(EmitSummaryIndex), EmitModuleHash(EmitModuleHash), + EnableSplitLTOUnit(EnableSplitLTOUnit) { 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 (EnableSplitLTOUnit) + Index->setEnableSplitLtoUnit(); WriteBitcodeToFile(M, OS, ShouldPreserveUseListOrder, Index, EmitModuleHash); return false; @@ -76,9 +83,11 @@ ModulePass *llvm::createBitcodeWriterPass(raw_ostream &Str, bool ShouldPreserveUseListOrder, - bool EmitSummaryIndex, bool EmitModuleHash) { - return new WriteBitcodePass(Str, ShouldPreserveUseListOrder, - EmitSummaryIndex, EmitModuleHash); + bool EmitSummaryIndex, + bool EmitModuleHash, + bool EnableSplitLTOUnit) { + return new WriteBitcodePass(Str, ShouldPreserveUseListOrder, EmitSummaryIndex, + EmitModuleHash, EnableSplitLTOUnit); } bool llvm::isBitcodeWriterPass(Pass *P) { Index: lib/LTO/LTO.cpp =================================================================== --- lib/LTO/LTO.cpp +++ lib/LTO/LTO.cpp @@ -532,6 +532,14 @@ if (!LTOInfo) return LTOInfo.takeError(); + if (EnableSplitLTOUnit.hasValue()) { + if (EnableSplitLTOUnit.getValue() != LTOInfo->EnableSplitLTOUnit) + return make_error("Expect all bitcode to be compiled with " + "same value of -f[no-]split-lto-unit", + inconvertibleErrorCode()); + } else + EnableSplitLTOUnit = LTOInfo->EnableSplitLTOUnit; + 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,9 @@ // 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, + /*EnableSplitLTOUnit=*/true); WriteBitcodeToFile(M, OS, /*ShouldPreserveUseListOrder=*/false, &Index); if (ThinLinkOS) @@ -379,13 +381,15 @@ // 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, + /*EnableSplitLTOUnit=*/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); + ModuleSummaryIndex MergedMIndex = buildModuleSummaryIndex( + *MergedM, nullptr, &PSI, /*EnableSplitLTOUnit=*/true); SmallVector Buffer; @@ -429,12 +433,18 @@ 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 EnableSplitLTOUnit) { + // See if this module has any type metadata and the client requested + // a split LTOUnit. If so, we need to split it. + if (EnableSplitLTOUnit && 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 split LTOUnit enabled, + // for later consistency checking when linking the resulting modules. + if (EnableSplitLTOUnit) + Index->setEnableSplitLtoUnit(); // 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 +464,30 @@ // The output stream on which to emit a minimized module for use // just in the thin link, if requested. raw_ostream *ThinLinkOS; + bool EnableSplitLTOUnit; public: static char ID; // Pass identification, replacement for typeid - WriteThinLTOBitcode() : ModulePass(ID), OS(dbgs()), ThinLinkOS(nullptr) { + WriteThinLTOBitcode() + : ModulePass(ID), OS(dbgs()), ThinLinkOS(nullptr), + EnableSplitLTOUnit(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 EnableSplitLTOUnit) + : ModulePass(ID), OS(o), ThinLinkOS(ThinLinkOS), + EnableSplitLTOUnit(EnableSplitLTOUnit) { 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, + EnableSplitLTOUnit); return true; } void getAnalysisUsage(AnalysisUsage &AU) const override { @@ -493,18 +509,20 @@ "Write ThinLTO Bitcode", false, true) ModulePass *llvm::createWriteThinLTOBitcodePass(raw_ostream &Str, - raw_ostream *ThinLinkOS) { - return new WriteThinLTOBitcode(Str, ThinLinkOS); + raw_ostream *ThinLinkOS, + bool EnableSplitLTOUnit) { + return new WriteThinLTOBitcode(Str, ThinLinkOS, EnableSplitLTOUnit); } PreservedAnalyses llvm::ThinLTOBitcodeWriterPass::run(Module &M, ModuleAnalysisManager &AM) { FunctionAnalysisManager &FAM = AM.getResult(M).getManager(); - writeThinLTOBitcode(OS, ThinLinkOS, - [&FAM](Function &F) -> AAResults & { - return FAM.getResult(F); - }, - M, &AM.getResult(M)); + writeThinLTOBitcode( + OS, ThinLinkOS, + [&FAM](Function &F) -> AAResults & { + return FAM.getResult(F); + }, + M, &AM.getResult(M), EnableSplitLTOUnit); 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-deadstrip-flag.ll =================================================================== --- test/Bitcode/thinlto-deadstrip-flag.ll +++ test/Bitcode/thinlto-deadstrip-flag.ll @@ -5,14 +5,14 @@ ; RUN: llvm-lto2 run %t.o -o %t.out -thinlto-distributed-indexes \ ; RUN: -r %t.o,glob,plx ; RUN: llvm-bcanalyzer -dump %t.o.thinlto.bc | FileCheck %s --check-prefix=WITHDEAD -; WITHDEAD: +; WITHDEAD: ; Ensure dead stripping performed flag is not set on distributed index ; when option used to disable dead stripping computation. ; RUN: llvm-lto2 run %t.o -o %t.out -thinlto-distributed-indexes \ ; RUN: -r %t.o,glob,plx -compute-dead=false ; RUN: llvm-bcanalyzer -dump %t.o.thinlto.bc | FileCheck %s --check-prefix=NODEAD -; NODEAD: +; NODEAD: target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" 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 @@ -19,6 +19,7 @@ ; BC-NEXT: &1 | FileCheck %s --check-prefix=NOERROR --allow-empty + +; Linking bitcode both without EnableSplitLTOUnit set should work +; RUN: opt -module-summary -o %t1 %s +; RUN: llvm-bcanalyzer -dump %t1 | FileCheck %s --check-prefix=NOSPLITLTOUNIT +; RUN: opt -module-summary -o %t2 %s +; RUN: llvm-bcanalyzer -dump %t2 | FileCheck %s --check-prefix=NOSPLITLTOUNIT +; RUN: llvm-lto2 run -o %t3 %t1 %t2 2>&1 | FileCheck %s --check-prefix=NOERROR --allow-empty + +; Linking bitcode with different values of EnableSplitLTOUnit should fail +; RUN: opt -thinlto-bc -o %t1 %s +; RUN: llvm-bcanalyzer -dump %t1 | FileCheck %s --check-prefix=SPLITLTOUNIT +; RUN: opt -module-summary -o %t2 %s +; RUN: llvm-bcanalyzer -dump %t2 | FileCheck %s --check-prefix=NOSPLITLTOUNIT +; RUN: not llvm-lto2 run -o %t3 %t1 %t2 2>&1 | FileCheck %s --check-prefix=ERROR + +; Linking bitcode with different values of EnableSplitLTOUnit should fail +; (reverse order) +; RUN: opt -module-summary -o %t1 %s +; RUN: llvm-bcanalyzer -dump %t1 | FileCheck %s --check-prefix=NOSPLITLTOUNIT +; RUN: opt -thinlto-bc -o %t2 %s +; RUN: llvm-bcanalyzer -dump %t2 | FileCheck %s --check-prefix=SPLITLTOUNIT +; 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-]split-lto-unit +; NOERROR-NOT: Expect all bitcode to be compiled with same value of -f[no-]split-lto-unit + +; The flag should be set when splitting is disabled (for backwards compatibility +; with older bitcode where it was always enabled). +; SPLITLTOUNIT: +; NOSPLITLTOUNIT: + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" Index: test/tools/gold/X86/v1.12/thinlto_emit_linked_objects.ll =================================================================== --- test/tools/gold/X86/v1.12/thinlto_emit_linked_objects.ll +++ test/tools/gold/X86/v1.12/thinlto_emit_linked_objects.ll @@ -35,14 +35,14 @@ ; should not be set. ; RUN: llvm-bcanalyzer --dump %t1.o.thinlto.bc | FileCheck %s -check-prefixes=CHECK-BC1 ; CHECK-BC1: +; CHECK-BC1: ; CHECK-BC1: +; CHECK-BC2: ; CHECK-BC2: os(), ThinLTOLinkOut ? &ThinLTOLinkOut->os() : nullptr)); + Out->os(), ThinLTOLinkOut ? &ThinLTOLinkOut->os() : nullptr, + /*EnableSplitLTOUnit=*/true)); break; } Index: tools/opt/opt.cpp =================================================================== --- tools/opt/opt.cpp +++ tools/opt/opt.cpp @@ -813,7 +813,8 @@ Passes.add(createPrintModulePass(*OS, "", PreserveAssemblyUseListOrder)); } else if (OutputThinLTOBC) Passes.add(createWriteThinLTOBitcodePass( - *OS, ThinLinkOut ? &ThinLinkOut->os() : nullptr)); + *OS, ThinLinkOut ? &ThinLinkOut->os() : nullptr, + /*EnableSplitLTOUnit=*/true)); else Passes.add(createBitcodeWriterPass(*OS, PreserveBitcodeUseListOrder, EmitSummaryIndex, EmitModuleHash));