aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTeresa Johnson <tejohnson@google.com>2019-02-14 21:22:50 +0000
committerYi Kong <yikong@google.com>2019-03-01 10:32:13 -0800
commitc322391378a0ba8e41a2dbcad0859c78997b3fdc (patch)
tree052a5606b6dc6d6ece3061c454277bae8406b4b9
parenta4c8940d5c26cee0b333460c12326f716ecd9106 (diff)
downloadllvm-c322391378a0ba8e41a2dbcad0859c78997b3fdc.tar.gz
[ThinLTO] Detect partially split modules during the thin link
Summary: The changes to disable LTO unit splitting by default (r350949) and detect inconsistently split LTO units (r350948) are causing some crashes when the inconsistency is detected in multiple threads simultaneously. Fix that by having the code always look for the inconsistently split LTO units during the thin link, by checking for the presence of type tests recorded in the summaries. Modify test added in r350948 to remove single threading required to fix a bot failure due to this issue (and some debugging options added in the process of diagnosing it). Reviewers: pcc Subscribers: mehdi_amini, inglorion, eraman, steven_wu, dexonsmith, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D57561 Change-Id: I1df30bf57e0fb8b23a2444e07f1e0a04eb8ef2ea git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@354062 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/llvm/LTO/LTO.h2
-rw-r--r--lib/LTO/LTO.cpp56
-rw-r--r--lib/Transforms/IPO/LowerTypeTests.cpp15
-rw-r--r--lib/Transforms/IPO/WholeProgramDevirt.cpp19
-rw-r--r--test/ThinLTO/X86/cfi-devirt.ll19
5 files changed, 79 insertions, 32 deletions
diff --git a/include/llvm/LTO/LTO.h b/include/llvm/LTO/LTO.h
index d3949aa33b2..1f9d764f068 100644
--- a/include/llvm/LTO/LTO.h
+++ b/include/llvm/LTO/LTO.h
@@ -398,6 +398,8 @@ private:
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.
diff --git a/lib/LTO/LTO.cpp b/lib/LTO/LTO.cpp
index 23a4a4011f7..8e0d532fa7e 100644
--- a/lib/LTO/LTO.cpp
+++ b/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 @@ unsigned LTO::getMaxTasks() const {
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<StringError>(
+ "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<FunctionSummary>(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<StringError>(
+ "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<GlobalValue::GUID> GUIDPreservedSymbols;
@@ -850,6 +890,17 @@ Error LTO::run(AddStreamFn AddStream, NativeObjectCache Cache) {
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::run(AddStreamFn AddStream, NativeObjectCache Cache) {
}
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();
diff --git a/lib/Transforms/IPO/LowerTypeTests.cpp b/lib/Transforms/IPO/LowerTypeTests.cpp
index 2f8a96be875..398005d2234 100644
--- a/lib/Transforms/IPO/LowerTypeTests.cpp
+++ b/lib/Transforms/IPO/LowerTypeTests.cpp
@@ -1692,6 +1692,14 @@ void LowerTypeTestsModule::replaceDirectCalls(Value *Old, Value *New) {
}
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 @@ 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/WholeProgramDevirt.cpp b/lib/Transforms/IPO/WholeProgramDevirt.cpp
index ab6f0eb660f..6b6dd6194e1 100644
--- a/lib/Transforms/IPO/WholeProgramDevirt.cpp
+++ b/lib/Transforms/IPO/WholeProgramDevirt.cpp
@@ -1563,23 +1563,20 @@ void DevirtModule::removeRedundantTypeTests() {
}
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.
diff --git a/test/ThinLTO/X86/cfi-devirt.ll b/test/ThinLTO/X86/cfi-devirt.ll
index 3fd0486c7e8..2ea6fc4cac0 100644
--- a/test/ThinLTO/X86/cfi-devirt.ll
+++ b/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"