diff --git a/include/llvm/Bitcode/BitcodeReader.h b/include/llvm/Bitcode/BitcodeReader.h index ce8bdd9cf0b..0d7cc141f2c 100644 --- a/include/llvm/Bitcode/BitcodeReader.h +++ b/include/llvm/Bitcode/BitcodeReader.h @@ -51,6 +51,7 @@ class Module; struct BitcodeLTOInfo { bool IsThinLTO; bool HasSummary; + bool EnableSplitLTOUnit; }; /// Represents a module in a bitcode file. diff --git a/include/llvm/IR/ModuleSummaryIndex.h b/include/llvm/IR/ModuleSummaryIndex.h index 6653795d503..a1acee49447 100644 --- a/include/llvm/IR/ModuleSummaryIndex.h +++ b/include/llvm/IR/ModuleSummaryIndex.h @@ -831,6 +831,13 @@ private: /// 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 @@ private: 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 @@ public: 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(); } diff --git a/include/llvm/LTO/LTO.h b/include/llvm/LTO/LTO.h index 15390873056..534d9b6f3f2 100644 --- a/include/llvm/LTO/LTO.h +++ b/include/llvm/LTO/LTO.h @@ -400,6 +400,9 @@ private: 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 diff --git a/lib/Analysis/ModuleSummaryAnalysis.cpp b/lib/Analysis/ModuleSummaryAnalysis.cpp index 6bda1d1b1a3..87f76d43bb1 100644 --- a/lib/Analysis/ModuleSummaryAnalysis.cpp +++ b/lib/Analysis/ModuleSummaryAnalysis.cpp @@ -457,7 +457,11 @@ ModuleSummaryIndex llvm::buildModuleSummaryIndex( 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 diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp index 2f3d2f3f032..fe051e7a912 100644 --- a/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/lib/Bitcode/Reader/BitcodeReader.cpp @@ -5294,18 +5294,30 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) { 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 @@ Expected> BitcodeModule::getSummary() { 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 @@ Expected BitcodeModule::getLTOInfo() { 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()) diff --git a/lib/Bitcode/Writer/BitcodeWriter.cpp b/lib/Bitcode/Writer/BitcodeWriter.cpp index 68d79edceaf..ba4f932e2e6 100644 --- a/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -3618,6 +3618,13 @@ void ModuleBitcodeWriterBase::writePerModuleGlobalValueSummary() { 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 @@ void IndexBitcodeWriter::writeCombinedGlobalValueSummary() { 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()) { diff --git a/lib/LTO/LTO.cpp b/lib/LTO/LTO.cpp index f736ef8b7f9..3a955060dea 100644 --- a/lib/LTO/LTO.cpp +++ b/lib/LTO/LTO.cpp @@ -546,6 +546,15 @@ Error LTO::addModule(InputFile &Input, unsigned ModI, 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}, diff --git a/lib/Transforms/IPO/LowerTypeTests.cpp b/lib/Transforms/IPO/LowerTypeTests.cpp index e4dcd4d4dd7..87c65db0951 100644 --- a/lib/Transforms/IPO/LowerTypeTests.cpp +++ b/lib/Transforms/IPO/LowerTypeTests.cpp @@ -1702,6 +1702,13 @@ bool LowerTypeTestsModule::lower() { !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(); diff --git a/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp b/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp index a5382c4638d..510ecb516dc 100644 --- a/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp +++ b/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp @@ -418,8 +418,18 @@ void splitAndWriteThinLTOBitcode( } } -// 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 @@ bool requiresSplit(Module &M) { 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); diff --git a/lib/Transforms/IPO/WholeProgramDevirt.cpp b/lib/Transforms/IPO/WholeProgramDevirt.cpp index 37905daee4c..48bd0cda759 100644 --- a/lib/Transforms/IPO/WholeProgramDevirt.cpp +++ b/lib/Transforms/IPO/WholeProgramDevirt.cpp @@ -1563,6 +1563,17 @@ bool DevirtModule::run() { 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. diff --git a/test/Bitcode/thinlto-alias.ll b/test/Bitcode/thinlto-alias.ll index 835d720c69e..f3896d2baba 100644 --- a/test/Bitcode/thinlto-alias.ll +++ b/test/Bitcode/thinlto-alias.ll @@ -18,6 +18,7 @@ ; CHECK-NEXT: diff --git a/test/Bitcode/thinlto-alias2.ll b/test/Bitcode/thinlto-alias2.ll index 3d68e3fd4ba..8b04ee75ac5 100644 --- a/test/Bitcode/thinlto-alias2.ll +++ b/test/Bitcode/thinlto-alias2.ll @@ -4,6 +4,7 @@ ; CHECK: ; CHECK-NEXT: diff --git a/test/Bitcode/thinlto-function-summary-callgraph-cast.ll b/test/Bitcode/thinlto-function-summary-callgraph-cast.ll index 79644403d38..d4b4d5491c1 100644 --- a/test/Bitcode/thinlto-function-summary-callgraph-cast.ll +++ b/test/Bitcode/thinlto-function-summary-callgraph-cast.ll @@ -5,6 +5,7 @@ ; CHECK: ; "another_caller" has only references but no calls. diff --git a/test/Bitcode/thinlto-function-summary-callgraph-pgo.ll b/test/Bitcode/thinlto-function-summary-callgraph-pgo.ll index e332224343e..b9613f732ed 100644 --- a/test/Bitcode/thinlto-function-summary-callgraph-pgo.ll +++ b/test/Bitcode/thinlto-function-summary-callgraph-pgo.ll @@ -16,6 +16,7 @@ ; CHECK-NEXT: ; CHECK-NEXT: diff --git a/test/Bitcode/thinlto-function-summary-callgraph-profile-summary.ll b/test/Bitcode/thinlto-function-summary-callgraph-profile-summary.ll index 31c99c189ac..0cd10982dd5 100644 --- a/test/Bitcode/thinlto-function-summary-callgraph-profile-summary.ll +++ b/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: diff --git a/test/Bitcode/thinlto-function-summary-callgraph-relbf.ll b/test/Bitcode/thinlto-function-summary-callgraph-relbf.ll index 6c144652225..7c7a6f6c924 100644 --- a/test/Bitcode/thinlto-function-summary-callgraph-relbf.ll +++ b/test/Bitcode/thinlto-function-summary-callgraph-relbf.ll @@ -12,6 +12,7 @@ ; CHECK-NEXT: diff --git a/test/Bitcode/thinlto-function-summary-callgraph-sample-profile-summary.ll b/test/Bitcode/thinlto-function-summary-callgraph-sample-profile-summary.ll index d1f980ab5f6..8bf65ab5e21 100644 --- a/test/Bitcode/thinlto-function-summary-callgraph-sample-profile-summary.ll +++ b/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: diff --git a/test/Bitcode/thinlto-function-summary-callgraph.ll b/test/Bitcode/thinlto-function-summary-callgraph.ll index a605b7ec221..0969b849bc0 100644 --- a/test/Bitcode/thinlto-function-summary-callgraph.ll +++ b/test/Bitcode/thinlto-function-summary-callgraph.ll @@ -17,6 +17,7 @@ ; CHECK-NEXT: diff --git a/test/Bitcode/thinlto-function-summary.ll b/test/Bitcode/thinlto-function-summary.ll index be7e9749086..67c50379e7a 100644 --- a/test/Bitcode/thinlto-function-summary.ll +++ b/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" diff --git a/test/ThinLTO/X86/cache-icall.ll b/test/ThinLTO/X86/cache-icall.ll index 5e64a713ffa..034ff97cede 100644 --- a/test/ThinLTO/X86/cache-icall.ll +++ b/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 diff --git a/test/ThinLTO/X86/cfi-devirt.ll b/test/ThinLTO/X86/cfi-devirt.ll index 7ade794d498..45d6960b505 100644 --- a/test/ThinLTO/X86/cfi-devirt.ll +++ b/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" diff --git a/test/ThinLTO/X86/cfi-distributed.ll b/test/ThinLTO/X86/cfi-distributed.ll index 94f3f95c298..53392285154 100644 --- a/test/ThinLTO/X86/cfi-distributed.ll +++ b/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 \ diff --git a/test/ThinLTO/X86/cfi-icall.ll b/test/ThinLTO/X86/cfi-icall.ll index 1ab184f1f19..42c26f15893 100644 --- a/test/ThinLTO/X86/cfi-icall.ll +++ b/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 \ diff --git a/test/ThinLTO/X86/cfi.ll b/test/ThinLTO/X86/cfi.ll index 9b1bde3b615..0edddb82be9 100644 --- a/test/ThinLTO/X86/cfi.ll +++ b/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 \ diff --git a/test/ThinLTO/X86/devirt-after-icp.ll b/test/ThinLTO/X86/devirt-after-icp.ll index 987221787e2..fd5dcb728aa 100644 --- a/test/ThinLTO/X86/devirt-after-icp.ll +++ b/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. diff --git a/test/Transforms/ThinLTOBitcodeWriter/circular-reference.ll b/test/Transforms/ThinLTOBitcodeWriter/circular-reference.ll index eeda7932449..fb239b0a8a2 100644 --- a/test/Transforms/ThinLTOBitcodeWriter/circular-reference.ll +++ b/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 diff --git a/test/Transforms/ThinLTOBitcodeWriter/comdat.ll b/test/Transforms/ThinLTOBitcodeWriter/comdat.ll index caea48e0a54..a43fa1cf3eb 100644 --- a/test/Transforms/ThinLTOBitcodeWriter/comdat.ll +++ b/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 diff --git a/test/Transforms/ThinLTOBitcodeWriter/filter-alias.ll b/test/Transforms/ThinLTOBitcodeWriter/filter-alias.ll index eb0cbe78a73..200d494f247 100644 --- a/test/Transforms/ThinLTOBitcodeWriter/filter-alias.ll +++ b/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{{.*}}= diff --git a/test/Transforms/ThinLTOBitcodeWriter/function-alias.ll b/test/Transforms/ThinLTOBitcodeWriter/function-alias.ll index 119b8219bab..a1dbd963296 100644 --- a/test/Transforms/ThinLTOBitcodeWriter/function-alias.ll +++ b/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" diff --git a/test/Transforms/ThinLTOBitcodeWriter/pr33536.ll b/test/Transforms/ThinLTOBitcodeWriter/pr33536.ll index 661d0739401..c405c369e05 100644 --- a/test/Transforms/ThinLTOBitcodeWriter/pr33536.ll +++ b/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 diff --git a/test/Transforms/ThinLTOBitcodeWriter/split-internal-typeid.ll b/test/Transforms/ThinLTOBitcodeWriter/split-internal-typeid.ll index a43db9a3755..290df00fa9e 100644 --- a/test/Transforms/ThinLTOBitcodeWriter/split-internal-typeid.ll +++ b/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 diff --git a/test/Transforms/ThinLTOBitcodeWriter/split-internal1.ll b/test/Transforms/ThinLTOBitcodeWriter/split-internal1.ll index 6d18c4f6f65..42a06bdf2bf 100644 --- a/test/Transforms/ThinLTOBitcodeWriter/split-internal1.ll +++ b/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 diff --git a/test/Transforms/ThinLTOBitcodeWriter/split-internal2.ll b/test/Transforms/ThinLTOBitcodeWriter/split-internal2.ll index fbe618f08e3..02fc3d18850 100644 --- a/test/Transforms/ThinLTOBitcodeWriter/split-internal2.ll +++ b/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 diff --git a/test/Transforms/ThinLTOBitcodeWriter/split-vfunc-internal.ll b/test/Transforms/ThinLTOBitcodeWriter/split-vfunc-internal.ll index 087796b5031..7ebb30ae1aa 100644 --- a/test/Transforms/ThinLTOBitcodeWriter/split-vfunc-internal.ll +++ b/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 diff --git a/test/Transforms/ThinLTOBitcodeWriter/split-vfunc.ll b/test/Transforms/ThinLTOBitcodeWriter/split-vfunc.ll index 66d37d5e8ae..fcf575188f7 100644 --- a/test/Transforms/ThinLTOBitcodeWriter/split-vfunc.ll +++ b/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 diff --git a/test/Transforms/ThinLTOBitcodeWriter/split.ll b/test/Transforms/ThinLTOBitcodeWriter/split.ll index 08ed92e7ebe..5502f7a2632 100644 --- a/test/Transforms/ThinLTOBitcodeWriter/split.ll +++ b/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 diff --git a/test/Transforms/ThinLTOBitcodeWriter/symver.ll b/test/Transforms/ThinLTOBitcodeWriter/symver.ll index 078825cf468..8acdd0c6a68 100644 --- a/test/Transforms/ThinLTOBitcodeWriter/symver.ll +++ b/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 diff --git a/test/Transforms/ThinLTOBitcodeWriter/unsplittable.ll b/test/Transforms/ThinLTOBitcodeWriter/unsplittable.ll index 5413e0f6188..46c87bc4e1f 100644 --- a/test/Transforms/ThinLTOBitcodeWriter/unsplittable.ll +++ b/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 @@ define void @h() comdat { 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"} diff --git a/test/Transforms/ThinLTOBitcodeWriter/x86/module-asm.ll b/test/Transforms/ThinLTOBitcodeWriter/x86/module-asm.ll index 15e47785cbe..587ab3fbb50 100644 --- a/test/Transforms/ThinLTOBitcodeWriter/x86/module-asm.ll +++ b/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 diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp index 266603992aa..a4967a234d9 100644 --- a/tools/opt/opt.cpp +++ b/tools/opt/opt.cpp @@ -103,6 +103,10 @@ static cl::opt 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 @@ int main(int argc, char **argv) { 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)