Index: llvm/trunk/include/llvm/LTO/LTO.h =================================================================== --- llvm/trunk/include/llvm/LTO/LTO.h +++ llvm/trunk/include/llvm/LTO/LTO.h @@ -398,6 +398,8 @@ Error runRegularLTO(AddStreamFn AddStream); Error runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache); + Error checkPartiallySplit(); + mutable bool CalledGetMaxTasks = false; // Use Optional to distinguish false from not yet initialized. Index: llvm/trunk/lib/LTO/LTO.cpp =================================================================== --- llvm/trunk/lib/LTO/LTO.cpp +++ llvm/trunk/lib/LTO/LTO.cpp @@ -20,6 +20,7 @@ #include "llvm/Config/llvm-config.h" #include "llvm/IR/AutoUpgrade.h" #include "llvm/IR/DiagnosticPrinter.h" +#include "llvm/IR/Intrinsics.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Mangler.h" #include "llvm/IR/Metadata.h" @@ -808,6 +809,45 @@ return RegularLTO.ParallelCodeGenParallelismLevel + ThinLTO.ModuleMap.size(); } +// If only some of the modules were split, we cannot correctly handle +// code that contains type tests or type checked loads. +Error LTO::checkPartiallySplit() { + if (!ThinLTO.CombinedIndex.partiallySplitLTOUnits()) + return Error::success(); + + Function *TypeTestFunc = RegularLTO.CombinedModule->getFunction( + Intrinsic::getName(Intrinsic::type_test)); + Function *TypeCheckedLoadFunc = RegularLTO.CombinedModule->getFunction( + Intrinsic::getName(Intrinsic::type_checked_load)); + + // First check if there are type tests / type checked loads in the + // merged regular LTO module IR. + if ((TypeTestFunc && !TypeTestFunc->use_empty()) || + (TypeCheckedLoadFunc && !TypeCheckedLoadFunc->use_empty())) + return make_error( + "inconsistent LTO Unit splitting (recompile with -fsplit-lto-unit)", + inconvertibleErrorCode()); + + // Otherwise check if there are any recorded in the combined summary from the + // ThinLTO modules. + for (auto &P : ThinLTO.CombinedIndex) { + for (auto &S : P.second.SummaryList) { + auto *FS = dyn_cast(S.get()); + if (!FS) + continue; + if (!FS->type_test_assume_vcalls().empty() || + !FS->type_checked_load_vcalls().empty() || + !FS->type_test_assume_const_vcalls().empty() || + !FS->type_checked_load_const_vcalls().empty() || + !FS->type_tests().empty()) + return make_error( + "inconsistent LTO Unit splitting (recompile with -fsplit-lto-unit)", + inconvertibleErrorCode()); + } + } + return Error::success(); +} + Error LTO::run(AddStreamFn AddStream, NativeObjectCache Cache) { // Compute "dead" symbols, we don't want to import/export these! DenseSet GUIDPreservedSymbols; @@ -850,6 +890,17 @@ StatsFile->keep(); } + // Finalize linking of regular LTO modules containing summaries now that + // we have computed liveness information. + for (auto &M : RegularLTO.ModsWithSummaries) + if (Error Err = linkRegularLTO(std::move(M), + /*LivenessFromIndex=*/true)) + return Err; + + // Ensure we don't have inconsistently split LTO units with type tests. + if (Error Err = checkPartiallySplit()) + return Err; + Error Result = runRegularLTO(AddStream); if (!Result) Result = runThinLTO(AddStream, Cache); @@ -861,11 +912,6 @@ } Error LTO::runRegularLTO(AddStreamFn AddStream) { - for (auto &M : RegularLTO.ModsWithSummaries) - if (Error Err = linkRegularLTO(std::move(M), - /*LivenessFromIndex=*/true)) - return Err; - // Make sure commons have the right size/alignment: we kept the largest from // all the prevailing when adding the inputs, and we apply it here. const DataLayout &DL = RegularLTO.CombinedModule->getDataLayout(); Index: llvm/trunk/lib/Transforms/IPO/LowerTypeTests.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/LowerTypeTests.cpp +++ llvm/trunk/lib/Transforms/IPO/LowerTypeTests.cpp @@ -1692,6 +1692,14 @@ } bool LowerTypeTestsModule::lower() { + // If only some of the modules were split, we cannot correctly perform + // this transformation. We already checked for the presense of type tests + // with partially split modules during the thin link, and would have emitted + // an error if any were found, so here we can simply return. + if ((ExportSummary && ExportSummary->partiallySplitLTOUnits()) || + (ImportSummary && ImportSummary->partiallySplitLTOUnits())) + return false; + Function *TypeTestFunc = M.getFunction(Intrinsic::getName(Intrinsic::type_test)); Function *ICallBranchFunnelFunc = @@ -1701,13 +1709,6 @@ !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/WholeProgramDevirt.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/WholeProgramDevirt.cpp +++ llvm/trunk/lib/Transforms/IPO/WholeProgramDevirt.cpp @@ -1563,23 +1563,20 @@ } bool DevirtModule::run() { + // If only some of the modules were split, we cannot correctly perform + // this transformation. We already checked for the presense of type tests + // with partially split modules during the thin link, and would have emitted + // an error if any were found, so here we can simply return. + if ((ExportSummary && ExportSummary->partiallySplitLTOUnits()) || + (ImportSummary && ImportSummary->partiallySplitLTOUnits())) + return false; + Function *TypeTestFunc = M.getFunction(Intrinsic::getName(Intrinsic::type_test)); Function *TypeCheckedLoadFunc = 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/ThinLTO/X86/cfi-devirt.ll =================================================================== --- llvm/trunk/test/ThinLTO/X86/cfi-devirt.ll +++ llvm/trunk/test/ThinLTO/X86/cfi-devirt.ll @@ -20,8 +20,8 @@ ; 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=REMARK -dump-input=always -; RUN: llvm-dis %t3.1.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR -dump-input=always +; RUN: -r=%t.o,_ZTV1C,px 2>&1 | FileCheck %s --check-prefix=REMARK +; RUN: llvm-dis %t3.1.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR ; New PM ; FIXME: Fix machine verifier issues and remove -verify-machineinstrs=0. PR39436. @@ -39,17 +39,18 @@ ; 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=REMARK -dump-input=always -; RUN: llvm-dis %t3.1.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR -dump-input=always +; RUN: -r=%t.o,_ZTV1C,px 2>&1 | FileCheck %s --check-prefix=REMARK +; RUN: llvm-dis %t3.1.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR ; 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. +; that does not have a split LTO Unit. Use -thinlto-distributed-indexes +; to ensure it is being caught in the thin link. ; 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 -thinlto-threads=1 \ +; RUN: not llvm-lto2 run %t.o %t2.o -thinlto-distributed-indexes \ +; RUN: -verify-machineinstrs=0 \ ; RUN: -o %t3 \ ; RUN: -r=%t.o,test,px \ ; RUN: -r=%t.o,_ZN1A1nEi,p \ @@ -62,8 +63,8 @@ ; 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 -dump-input=always -; ERROR: LLVM ERROR: inconsistent LTO Unit splitting with llvm.type.test or llvm.type.checked.load +; RUN: -r=%t.o,_ZTV1C,px 2>&1 | FileCheck %s --check-prefix=ERROR +; ERROR: failed: inconsistent LTO Unit splitting (recompile with -fsplit-lto-unit) target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-grtev4-linux-gnu"