Skip to content

Commit e97aab8

Browse files
committed
[ThinLTO] Fix import of multiply defined global variables
Currently, if there is a module that contains a strong definition of a global variable and a module that has both a weak definition for the same global and a reference to it, it may result in an undefined symbol error while linking with ThinLTO. It happens because: * the strong definition become internal because it is read-only and can be imported; * the weak definition gets replaced by a declaration because it's non-prevailing; * the strong definition failed to be imported because the destination module already contains another definition of the global yet this def is non-prevailing. The patch adds a check to computeImportForReferencedGlobals() that allows considering a global variable for being imported even if the module contains a definition of it in the case this def has an interposable linkage type. Note that currently the check is based only on the linkage type (and this seems to be enough at the moment), but it might be worth to account the information whether the def is prevailing or not. Reviewed By: tejohnson Differential Revision: https://reviews.llvm.org/D95943
1 parent 38ab47c commit e97aab8

File tree

2 files changed

+60
-1
lines changed

2 files changed

+60
-1
lines changed

llvm/lib/Transforms/IPO/FunctionImport.cpp

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,14 +275,37 @@ updateValueInfoForIndirectCalls(const ModuleSummaryIndex &Index, ValueInfo VI) {
275275
return Index.getValueInfo(GUID);
276276
}
277277

278+
static bool shouldImportGlobal(const ValueInfo &VI,
279+
const GVSummaryMapTy &DefinedGVSummaries) {
280+
const auto &GVS = DefinedGVSummaries.find(VI.getGUID());
281+
if (GVS == DefinedGVSummaries.end())
282+
return true;
283+
// We should not skip import if the module contains a definition with
284+
// interposable linkage type. This is required for correctness in
285+
// the situation with two following conditions:
286+
// * the def with interposable linkage is non-prevailing,
287+
// * there is a prevailing def available for import and marked read-only.
288+
// In this case, the non-prevailing def will be converted to a declaration,
289+
// while the prevailing one becomes internal, thus no definitions will be
290+
// available for linking. In order to prevent undefined symbol link error,
291+
// the prevailing definition must be imported.
292+
// FIXME: Consider adding a check that the suitable prevailing definition
293+
// exists and marked read-only.
294+
if (VI.getSummaryList().size() > 1 &&
295+
GlobalValue::isInterposableLinkage(GVS->second->linkage()))
296+
return true;
297+
298+
return false;
299+
}
300+
278301
static void computeImportForReferencedGlobals(
279302
const GlobalValueSummary &Summary, const ModuleSummaryIndex &Index,
280303
const GVSummaryMapTy &DefinedGVSummaries,
281304
SmallVectorImpl<EdgeInfo> &Worklist,
282305
FunctionImporter::ImportMapTy &ImportList,
283306
StringMap<FunctionImporter::ExportSetTy> *ExportLists) {
284307
for (auto &VI : Summary.refs()) {
285-
if (DefinedGVSummaries.count(VI.getGUID())) {
308+
if (!shouldImportGlobal(VI, DefinedGVSummaries)) {
286309
LLVM_DEBUG(
287310
dbgs() << "Ref ignored! Target already in destination module.\n");
288311
continue;
@@ -378,6 +401,9 @@ static void computeImportForFunction(
378401
continue;
379402

380403
if (DefinedGVSummaries.count(VI.getGUID())) {
404+
// FIXME: Consider not skipping import if the module contains
405+
// a non-prevailing def with interposable linkage. The prevailing copy
406+
// can safely be imported (see shouldImportGlobal()).
381407
LLVM_DEBUG(dbgs() << "ignored! Target already in destination module.\n");
382408
continue;
383409
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
; RUN: split-file %s %t.dir
2+
3+
; RUN: opt -module-summary %t.dir/1.ll -o %t1.bc
4+
; RUN: opt -module-summary %t.dir/2.ll -o %t2.bc
5+
6+
; RUN: llvm-lto2 run -save-temps %t1.bc %t2.bc -o %t.out \
7+
; RUN: -r=%t1.bc,main,plx \
8+
; RUN: -r=%t1.bc,G \
9+
; RUN: -r=%t2.bc,G,pl
10+
; RUN: llvm-dis %t.out.1.3.import.bc -o - | FileCheck %s
11+
; RUN: llvm-dis %t.out.2.3.import.bc -o - | FileCheck %s
12+
13+
; Test that a non-prevailing def with interposable linkage doesn't prevent
14+
; importing a suitable definition from a prevailing module.
15+
16+
; CHECK: @G = internal local_unnamed_addr global i32 42
17+
18+
;--- 1.ll
19+
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
20+
target triple = "x86_64-unknown-linux-gnu"
21+
22+
@G = weak dso_local local_unnamed_addr global i32 0, align 4
23+
24+
define dso_local i32 @main() local_unnamed_addr {
25+
%1 = load i32, i32* @G, align 4
26+
ret i32 %1
27+
}
28+
29+
;--- 2.ll
30+
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
31+
target triple = "x86_64-unknown-linux-gnu"
32+
33+
@G = dso_local local_unnamed_addr global i32 42, align 4

0 commit comments

Comments
 (0)