Index: llvm/trunk/include/llvm/Bitcode/BitcodeReader.h =================================================================== --- llvm/trunk/include/llvm/Bitcode/BitcodeReader.h +++ llvm/trunk/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: llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h =================================================================== --- llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h +++ llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h @@ -831,6 +831,13 @@ /// union. bool HaveGVs; + // True if the index was created for a module compiled with -fsplit-lto-unit. + bool EnableSplitLTOUnit; + + // True if some of the modules were compiled with -fsplit-lto-unit and + // some were not. Set when the combined index is created during the thin link. + bool PartiallySplitLTOUnits = false; + std::set CfiFunctionDefs; std::set CfiFunctionDecls; @@ -850,7 +857,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; } @@ -940,6 +949,12 @@ SkipModuleByDistributedBackend = true; } + bool enableSplitLTOUnit() const { return EnableSplitLTOUnit; } + void setEnableSplitLTOUnit() { EnableSplitLTOUnit = true; } + + bool partiallySplitLTOUnits() const { return PartiallySplitLTOUnits; } + void setPartiallySplitLTOUnits() { PartiallySplitLTOUnits = true; } + bool isGlobalValueLive(const GlobalValueSummary *GVS) const { return !WithGlobalValueDeadStripping || GVS->isLive(); } Index: llvm/trunk/include/llvm/LTO/LTO.h =================================================================== --- llvm/trunk/include/llvm/LTO/LTO.h +++ llvm/trunk/include/llvm/LTO/LTO.h @@ -400,6 +400,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: llvm/trunk/lib/Analysis/ModuleSummaryAnalysis.cpp =================================================================== --- llvm/trunk/lib/Analysis/ModuleSummaryAnalysis.cpp +++ llvm/trunk/lib/Analysis/ModuleSummaryAnalysis.cpp @@ -457,7 +457,11 @@ std::function GetBFICallback, ProfileSummaryInfo *PSI) { assert(PSI); - ModuleSummaryIndex Index(/*HaveGVs=*/true); + bool EnableSplitLTOUnit = false; + if (auto *MD = mdconst::extract_or_null( + M.getModuleFlag("EnableSplitLTOUnit"))) + EnableSplitLTOUnit = MD->getZExtValue(); + 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: llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp +++ llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp @@ -5294,18 +5294,30 @@ 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 <= 0x1f && "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: HasSyntheticEntryCounts flag. + // Set on combined index only. if (Flags & 0x4) TheIndex.setHasSyntheticEntryCounts(); + // 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. + if (Flags & 0x8) + TheIndex.setEnableSplitLTOUnit(); + // 1 bit: PartiallySplitLTOUnits flag. + // Set on combined index only. + if (Flags & 0x10) + TheIndex.setPartiallySplitLTOUnits(); break; } case bitc::FS_VALUE_GUID: { // [valueid, refguid] @@ -5917,6 +5929,46 @@ 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 true to mimic + // behavior before this flag was added. + return true; + 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 <= 0x1f && "Unexpected bits in flag"); + + return Flags & 0x8; + } + } + } + llvm_unreachable("Exit infinite loop"); +} + // Check if the given bitcode buffer contains a global value summary block. Expected BitcodeModule::getLTOInfo() { BitstreamCursor Stream(Buffer); @@ -5932,14 +5984,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::FULL_LTO_GLOBALVAL_SUMMARY_BLOCK_ID) - return BitcodeLTOInfo{/*IsThinLTO=*/false, /*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) { + 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: llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp +++ llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -3618,6 +3618,13 @@ Stream.EmitRecord(bitc::FS_VERSION, ArrayRef{INDEX_VERSION}); + // Write the index flags. + uint64_t Flags = 0; + // Bits 1-3 are set only in the combined index, skip them. + if (Index->enableSplitLTOUnit()) + Flags |= 0x8; + Stream.EmitRecord(bitc::FS_FLAGS, ArrayRef{Flags}); + if (Index->begin() == Index->end()) { Stream.ExitBlock(); return; @@ -3734,6 +3741,10 @@ Flags |= 0x2; if (Index.hasSyntheticEntryCounts()) Flags |= 0x4; + if (Index.enableSplitLTOUnit()) + Flags |= 0x8; + if (Index.partiallySplitLTOUnits()) + Flags |= 0x10; Stream.EmitRecord(bitc::FS_FLAGS, ArrayRef{Flags}); for (const auto &GVI : valueIds()) { Index: llvm/trunk/lib/LTO/LTO.cpp =================================================================== --- llvm/trunk/lib/LTO/LTO.cpp +++ llvm/trunk/lib/LTO/LTO.cpp @@ -546,6 +546,15 @@ if (!LTOInfo) return LTOInfo.takeError(); + if (EnableSplitLTOUnit.hasValue()) { + // If only some modules were split, flag this in the index so that + // we can skip or error on optimizations that need consistently split + // modules (whole program devirt and lower type tests). + if (EnableSplitLTOUnit.getValue() != LTOInfo->EnableSplitLTOUnit) + ThinLTO.CombinedIndex.setPartiallySplitLTOUnits(); + } else + EnableSplitLTOUnit = LTOInfo->EnableSplitLTOUnit; + BitcodeModule BM = Input.Mods[ModI]; auto ModSyms = Input.module_symbols(ModI); addModuleToGlobalRes(ModSyms, {ResI, ResE}, Index: llvm/trunk/lib/Transforms/IPO/LowerTypeTests.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/LowerTypeTests.cpp +++ llvm/trunk/lib/Transforms/IPO/LowerTypeTests.cpp @@ -1702,6 +1702,13 @@ !ExportSummary && !ImportSummary) return false; + // If only some of the modules were split, we cannot correctly handle + // code that contains type tests. + if (TypeTestFunc && !TypeTestFunc->use_empty() && + ((ExportSummary && ExportSummary->partiallySplitLTOUnits()) || + (ImportSummary && ImportSummary->partiallySplitLTOUnits()))) + report_fatal_error("inconsistent LTO Unit splitting with llvm.type.test"); + if (ImportSummary) { if (TypeTestFunc) { for (auto UI = TypeTestFunc->use_begin(), UE = TypeTestFunc->use_end(); Index: llvm/trunk/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp +++ llvm/trunk/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp @@ -418,8 +418,18 @@ } } -// Returns whether this module needs to be split because it uses type metadata. +// Returns whether this module needs to be split because splitting is +// enabled and it uses type metadata. bool requiresSplit(Module &M) { + // First check if the LTO Unit splitting has been enabled. + bool EnableSplitLTOUnit = false; + if (auto *MD = mdconst::extract_or_null( + M.getModuleFlag("EnableSplitLTOUnit"))) + EnableSplitLTOUnit = MD->getZExtValue(); + if (!EnableSplitLTOUnit) + return false; + + // Module only needs to be split if it contains type metadata. for (auto &GO : M.global_objects()) { if (GO.hasMetadata(LLVMContext::MD_type)) return true; @@ -431,7 +441,7 @@ 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. + // Split module if splitting is enabled and it contains any type metadata. if (requiresSplit(M)) return splitAndWriteThinLTOBitcode(OS, ThinLinkOS, AARGetter, M); Index: llvm/trunk/lib/Transforms/IPO/WholeProgramDevirt.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/WholeProgramDevirt.cpp +++ llvm/trunk/lib/Transforms/IPO/WholeProgramDevirt.cpp @@ -1563,6 +1563,17 @@ M.getFunction(Intrinsic::getName(Intrinsic::type_checked_load)); Function *AssumeFunc = M.getFunction(Intrinsic::getName(Intrinsic::assume)); + // If only some of the modules were split, we cannot correctly handle + // code that contains type tests or type checked loads. + if ((ExportSummary && ExportSummary->partiallySplitLTOUnits()) || + (ImportSummary && ImportSummary->partiallySplitLTOUnits())) { + if ((TypeTestFunc && !TypeTestFunc->use_empty()) || + (TypeCheckedLoadFunc && !TypeCheckedLoadFunc->use_empty())) + report_fatal_error("inconsistent LTO Unit splitting with llvm.type.test " + "or llvm.type.checked.load"); + return false; + } + // Normally if there are no users of the devirtualization intrinsics in the // module, this pass has nothing to do. But if we are exporting, we also need // to handle any users that appear only in the function summaries. Index: llvm/trunk/test/Bitcode/thinlto-alias.ll =================================================================== --- llvm/trunk/test/Bitcode/thinlto-alias.ll +++ llvm/trunk/test/Bitcode/thinlto-alias.ll @@ -18,6 +18,7 @@ ; CHECK-NEXT: Index: llvm/trunk/test/Bitcode/thinlto-alias2.ll =================================================================== --- llvm/trunk/test/Bitcode/thinlto-alias2.ll +++ llvm/trunk/test/Bitcode/thinlto-alias2.ll @@ -4,6 +4,7 @@ ; CHECK: ; CHECK-NEXT: Index: llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-cast.ll =================================================================== --- llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-cast.ll +++ llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-cast.ll @@ -5,6 +5,7 @@ ; CHECK: ; "another_caller" has only references but no calls. Index: llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-pgo.ll =================================================================== --- llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-pgo.ll +++ llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-pgo.ll @@ -16,6 +16,7 @@ ; CHECK-NEXT: ; CHECK-NEXT: Index: llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-profile-summary.ll =================================================================== --- llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-profile-summary.ll +++ llvm/trunk/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: llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-relbf.ll =================================================================== --- llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-relbf.ll +++ llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-relbf.ll @@ -12,6 +12,7 @@ ; CHECK-NEXT: Index: llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-sample-profile-summary.ll =================================================================== --- llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-sample-profile-summary.ll +++ llvm/trunk/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: llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph.ll =================================================================== --- llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph.ll +++ llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph.ll @@ -17,6 +17,7 @@ ; CHECK-NEXT: Index: llvm/trunk/test/Bitcode/thinlto-function-summary.ll =================================================================== --- llvm/trunk/test/Bitcode/thinlto-function-summary.ll +++ llvm/trunk/test/Bitcode/thinlto-function-summary.ll @@ -19,6 +19,7 @@ ; BC-NEXT: +; NOSPLITLTOUNIT: + +; Check that the corresponding module flag is set when expected. +; ENABLESPLITFLAG: !{i32 1, !"EnableSplitLTOUnit", i32 1} +; NOENABLESPLITFLAG-NOT: !{i32 1, !"EnableSplitLTOUnit", i32 1} + +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/cache-icall.ll =================================================================== --- llvm/trunk/test/ThinLTO/X86/cache-icall.ll +++ llvm/trunk/test/ThinLTO/X86/cache-icall.ll @@ -4,8 +4,8 @@ ; This affects code generated for any users of f(). Make sure that we don't pull a stale object ; file for %t.o from the cache. -; RUN: opt -module-hash -module-summary -thinlto-bc %s -o %t.bc -; RUN: opt -module-hash -module-summary -thinlto-bc %p/Inputs/cache-icall.ll -o %t2.bc +; RUN: opt -module-hash -module-summary -thinlto-bc -thinlto-split-lto-unit %s -o %t.bc +; RUN: opt -module-hash -module-summary -thinlto-bc -thinlto-split-lto-unit %p/Inputs/cache-icall.ll -o %t2.bc ; RUN: rm -Rf %t.cache && mkdir %t.cache Index: llvm/trunk/test/ThinLTO/X86/cfi-devirt.ll =================================================================== --- llvm/trunk/test/ThinLTO/X86/cfi-devirt.ll +++ llvm/trunk/test/ThinLTO/X86/cfi-devirt.ll @@ -2,7 +2,7 @@ ; Test CFI devirtualization through the thin link and backend. -; RUN: opt -thinlto-bc -o %t.o %s +; RUN: opt -thinlto-bc -thinlto-split-lto-unit -o %t.o %s ; Legacy PM ; FIXME: Fix machine verifier issues and remove -verify-machineinstrs=0. PR39436. @@ -44,6 +44,27 @@ ; REMARK: single-impl: devirtualized a call to _ZN1A1nEi +; Next check that we emit an error when trying to LTO link this module +; containing an llvm.type.checked.load (with a split LTO Unit) with one +; that does not have a split LTO Unit. +; RUN: opt -thinlto-bc -o %t2.o %S/Inputs/empty.ll +; RUN: not llvm-lto2 run %t.o %t2.o -save-temps -pass-remarks=. \ +; RUN: -verify-machineinstrs=0 \ +; RUN: -o %t3 \ +; RUN: -r=%t.o,test,px \ +; RUN: -r=%t.o,_ZN1A1nEi,p \ +; RUN: -r=%t.o,_ZN1B1fEi,p \ +; RUN: -r=%t.o,_ZN1C1fEi,p \ +; RUN: -r=%t.o,empty,p \ +; RUN: -r=%t.o,_ZTV1B, \ +; RUN: -r=%t.o,_ZTV1C, \ +; RUN: -r=%t.o,_ZN1A1nEi, \ +; RUN: -r=%t.o,_ZN1B1fEi, \ +; RUN: -r=%t.o,_ZN1C1fEi, \ +; RUN: -r=%t.o,_ZTV1B,px \ +; RUN: -r=%t.o,_ZTV1C,px 2>&1 | FileCheck %s --check-prefix=ERROR +; ERROR: LLVM ERROR: inconsistent LTO Unit splitting with llvm.type.test or llvm.type.checked.load + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-grtev4-linux-gnu" Index: llvm/trunk/test/ThinLTO/X86/cfi-distributed.ll =================================================================== --- llvm/trunk/test/ThinLTO/X86/cfi-distributed.ll +++ llvm/trunk/test/ThinLTO/X86/cfi-distributed.ll @@ -3,8 +3,8 @@ ; Test to ensure that only referenced type ID records are emitted into ; each distributed index file. -; RUN: opt -thinlto-bc -o %t1.o %s -; RUN: opt -thinlto-bc -o %t2.o %p/Inputs/cfi-distributed.ll +; RUN: opt -thinlto-bc -thinlto-split-lto-unit -o %t1.o %s +; RUN: opt -thinlto-bc -thinlto-split-lto-unit -o %t2.o %p/Inputs/cfi-distributed.ll ; RUN: llvm-lto2 run -thinlto-distributed-indexes %t1.o %t2.o \ ; RUN: -o %t3 \ Index: llvm/trunk/test/ThinLTO/X86/cfi-icall.ll =================================================================== --- llvm/trunk/test/ThinLTO/X86/cfi-icall.ll +++ llvm/trunk/test/ThinLTO/X86/cfi-icall.ll @@ -1,4 +1,4 @@ -; RUN: opt -thinlto-bc %s -o %t1.bc +; RUN: opt -thinlto-bc -thinlto-split-lto-unit %s -o %t1.bc ; RUN: llvm-lto2 run -thinlto-distributed-indexes %t1.bc -o %t.out -save-temps \ ; RUN: -r %t1.bc,foo,plx \ ; RUN: -r %t1.bc,bar,x \ Index: llvm/trunk/test/ThinLTO/X86/cfi.ll =================================================================== --- llvm/trunk/test/ThinLTO/X86/cfi.ll +++ llvm/trunk/test/ThinLTO/X86/cfi.ll @@ -2,7 +2,7 @@ ; Test CFI through the thin link and backend. -; RUN: opt -thinlto-bc -o %t.o %s +; RUN: opt -thinlto-bc -thinlto-split-lto-unit -o %t.o %s ; Legacy PM ; RUN: llvm-lto2 run -save-temps %t.o \ Index: llvm/trunk/test/ThinLTO/X86/devirt-after-icp.ll =================================================================== --- llvm/trunk/test/ThinLTO/X86/devirt-after-icp.ll +++ llvm/trunk/test/ThinLTO/X86/devirt-after-icp.ll @@ -42,7 +42,7 @@ ; will use the same vtable pointer. Without a dominance check, we could ; incorrectly devirtualize a->foo() to B::foo(); -; RUN: opt -thinlto-bc -o %t.o %s +; RUN: opt -thinlto-bc -thinlto-split-lto-unit -o %t.o %s ; Legacy PM ; FIXME: Fix machine verifier issues and remove -verify-machineinstrs=0. PR39436. Index: llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/circular-reference.ll =================================================================== --- llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/circular-reference.ll +++ llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/circular-reference.ll @@ -1,4 +1,4 @@ -; RUN: opt -thinlto-bc -o %t %s +; RUN: opt -thinlto-bc -thinlto-split-lto-unit -o %t %s ; RUN: llvm-modextract -b -n 0 -o - %t | llvm-dis | FileCheck --check-prefix=M0 %s ; RUN: llvm-modextract -b -n 1 -o - %t | llvm-dis | FileCheck --check-prefix=M1 %s Index: llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/comdat.ll =================================================================== --- llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/comdat.ll +++ llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/comdat.ll @@ -1,4 +1,4 @@ -; RUN: opt -thinlto-bc -o %t %s +; RUN: opt -thinlto-bc -thinlto-split-lto-unit -o %t %s ; RUN: llvm-modextract -n 0 -o - %t | llvm-dis | FileCheck --check-prefix=THIN %s ; RUN: llvm-modextract -n 1 -o - %t | llvm-dis | FileCheck --check-prefix=MERGED %s Index: llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/filter-alias.ll =================================================================== --- llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/filter-alias.ll +++ llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/filter-alias.ll @@ -1,4 +1,4 @@ -; RUN: opt -thinlto-bc -o %t %s +; RUN: opt -thinlto-bc -thinlto-split-lto-unit -o %t %s ; RUN: llvm-modextract -n 0 -o - %t | llvm-dis | FileCheck --check-prefix=CHECK0 %s ; RUN: llvm-modextract -n 1 -o - %t | llvm-dis | FileCheck --check-prefix=CHECK1 %s ; CHECK0-NOT: @{{.*}}anon{{.*}}= Index: llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/function-alias.ll =================================================================== --- llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/function-alias.ll +++ llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/function-alias.ll @@ -1,4 +1,4 @@ -; RUN: opt -thinlto-bc -o %t %s +; RUN: opt -thinlto-bc -thinlto-split-lto-unit -o %t %s ; RUN: llvm-modextract -n 1 -o - %t | llvm-dis | FileCheck --check-prefix=CHECK1 %s target triple = "x86_64-unknown-linux-gnu" Index: llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/pr33536.ll =================================================================== --- llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/pr33536.ll +++ llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/pr33536.ll @@ -1,7 +1,7 @@ ; Test for a bug specific to the new pass manager where we may build a domtree ; to make more precise AA queries for functions. ; -; RUN: opt -aa-pipeline=default -passes='no-op-module' -debug-pass-manager -thinlto-bc -o %t %s +; RUN: opt -aa-pipeline=default -passes='no-op-module' -debug-pass-manager -thinlto-bc -thinlto-split-lto-unit -o %t %s ; RUN: llvm-modextract -b -n 0 -o - %t | llvm-dis | FileCheck --check-prefix=M0 %s ; RUN: llvm-modextract -b -n 1 -o - %t | llvm-dis | FileCheck --check-prefix=M1 %s Index: llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split-internal-typeid.ll =================================================================== --- llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split-internal-typeid.ll +++ llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split-internal-typeid.ll @@ -1,4 +1,4 @@ -; RUN: opt -thinlto-bc -o %t %s +; RUN: opt -thinlto-bc -thinlto-split-lto-unit -o %t %s ; RUN: llvm-modextract -b -n 0 -o %t0 %t ; RUN: llvm-modextract -b -n 1 -o %t1 %t ; RUN: not llvm-modextract -b -n 2 -o - %t 2>&1 | FileCheck --check-prefix=ERROR %s Index: llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split-internal1.ll =================================================================== --- llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split-internal1.ll +++ llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split-internal1.ll @@ -1,4 +1,4 @@ -; RUN: opt -thinlto-bc -o %t %s +; RUN: opt -thinlto-bc -thinlto-split-lto-unit -o %t %s ; RUN: llvm-modextract -b -n 0 -o %t0 %t ; RUN: llvm-modextract -b -n 1 -o %t1 %t ; RUN: not llvm-modextract -b -n 2 -o - %t 2>&1 | FileCheck --check-prefix=ERROR %s Index: llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split-internal2.ll =================================================================== --- llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split-internal2.ll +++ llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split-internal2.ll @@ -1,4 +1,4 @@ -; RUN: opt -thinlto-bc -o %t %s +; RUN: opt -thinlto-bc -thinlto-split-lto-unit -o %t %s ; RUN: llvm-modextract -b -n 0 -o %t0 %t ; RUN: llvm-modextract -b -n 1 -o %t1 %t ; RUN: not llvm-modextract -b -n 2 -o - %t 2>&1 | FileCheck --check-prefix=ERROR %s Index: llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split-vfunc-internal.ll =================================================================== --- llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split-vfunc-internal.ll +++ llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split-vfunc-internal.ll @@ -1,4 +1,4 @@ -; RUN: opt -thinlto-bc -o %t %s +; RUN: opt -thinlto-bc -thinlto-split-lto-unit -o %t %s ; RUN: llvm-modextract -b -n 0 -o - %t | llvm-dis | FileCheck --check-prefix=M0 %s ; RUN: llvm-modextract -b -n 1 -o - %t | llvm-dis | FileCheck --check-prefix=M1 %s Index: llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split-vfunc.ll =================================================================== --- llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split-vfunc.ll +++ llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split-vfunc.ll @@ -1,4 +1,4 @@ -; RUN: opt -thinlto-bc -o %t %s +; RUN: opt -thinlto-bc -thinlto-split-lto-unit -o %t %s ; RUN: llvm-modextract -b -n 0 -o - %t | llvm-dis | FileCheck --check-prefix=M0 %s ; RUN: llvm-modextract -b -n 1 -o - %t | llvm-dis | FileCheck --check-prefix=M1 %s Index: llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split.ll =================================================================== --- llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split.ll +++ llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/split.ll @@ -1,6 +1,6 @@ ; Generate bitcode files with summary, as well as minimized bitcode without ; the debug metadata for the thin link. -; RUN: opt -thinlto-bc -thin-link-bitcode-file=%t2 -o %t %s +; RUN: opt -thinlto-bc -thin-link-bitcode-file=%t2 -thinlto-split-lto-unit -o %t %s ; RUN: llvm-modextract -b -n 0 -o %t0.bc %t ; RUN: llvm-modextract -b -n 1 -o %t1.bc %t ; RUN: llvm-modextract -b -n 0 -o %t0.thinlink.bc %t2 Index: llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/symver.ll =================================================================== --- llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/symver.ll +++ llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/symver.ll @@ -1,4 +1,4 @@ -; RUN: opt -thinlto-bc -o %t %s +; RUN: opt -thinlto-bc -thinlto-split-lto-unit -o %t %s ; RUN: llvm-modextract -n 1 -o - %t | llvm-dis | FileCheck %s ; The target assembly parser is required to parse the symver directives Index: llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/unsplittable.ll =================================================================== --- llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/unsplittable.ll +++ llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/unsplittable.ll @@ -1,4 +1,4 @@ -; RUN: opt -thinlto-bc -thin-link-bitcode-file=%t2 -o %t %s +; RUN: opt -thinlto-bc -thin-link-bitcode-file=%t2 -thinlto-split-lto-unit -o %t %s ; RUN: llvm-dis -o - %t | FileCheck %s ; RUN: llvm-bcanalyzer -dump %t | FileCheck --check-prefix=BCA %s ; When not splitting the module, the thin link bitcode file should simply be a @@ -28,7 +28,8 @@ ret void } -; CHECK: !llvm.module.flags = !{![[FLAG:[0-9]+]]} -; CHECK: ![[FLAG]] = !{i32 1, !"ThinLTO", i32 0} +; CHECK: !llvm.module.flags = !{![[FLAG1:[0-9]+]], ![[FLAG2:[0-9]+]]} +; CHECK: ![[FLAG1]] = !{i32 1, !"EnableSplitLTOUnit", i32 1} +; CHECK: ![[FLAG2]] = !{i32 1, !"ThinLTO", i32 0} !0 = !{i32 0, !"typeid"} Index: llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/x86/module-asm.ll =================================================================== --- llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/x86/module-asm.ll +++ llvm/trunk/test/Transforms/ThinLTOBitcodeWriter/x86/module-asm.ll @@ -1,4 +1,4 @@ -; RUN: opt -thinlto-bc -o %t %s +; RUN: opt -thinlto-bc -thinlto-split-lto-unit -o %t %s ; RUN: llvm-modextract -b -n 0 -o - %t | llvm-dis | FileCheck --check-prefix=M0 %s ; RUN: llvm-modextract -b -n 1 -o - %t | llvm-dis | FileCheck --check-prefix=M1 %s Index: llvm/trunk/tools/opt/opt.cpp =================================================================== --- llvm/trunk/tools/opt/opt.cpp +++ llvm/trunk/tools/opt/opt.cpp @@ -103,6 +103,10 @@ OutputThinLTOBC("thinlto-bc", cl::desc("Write output as ThinLTO-ready bitcode")); +static cl::opt + SplitLTOUnit("thinlto-split-lto-unit", + cl::desc("Enable splitting of a ThinLTO LTOUnit")); + static cl::opt ThinLinkBitcodeFile( "thin-link-bitcode-file", cl::value_desc("filename"), cl::desc( @@ -596,6 +600,9 @@ if (CheckBitcodeOutputToConsole(Out->os(), !Quiet)) NoOutput = true; + if (OutputThinLTOBC) + M->addModuleFlag(Module::Error, "EnableSplitLTOUnit", SplitLTOUnit); + if (PassPipeline.getNumOccurrences() > 0) { OutputKind OK = OK_NoOutput; if (!NoOutput)