diff --git a/llvm/lib/Transforms/IPO/FunctionImport.cpp b/llvm/lib/Transforms/IPO/FunctionImport.cpp --- a/llvm/lib/Transforms/IPO/FunctionImport.cpp +++ b/llvm/lib/Transforms/IPO/FunctionImport.cpp @@ -275,6 +275,29 @@ return Index.getValueInfo(GUID); } +static bool shouldImportGlobal(const ValueInfo &VI, + const GVSummaryMapTy &DefinedGVSummaries) { + const auto &GVS = DefinedGVSummaries.find(VI.getGUID()); + if (GVS == DefinedGVSummaries.end()) + return true; + // We should not skip import if the module contains a definition with + // interposable linkage type. This is required for correctness in + // the situation with two following conditions: + // * the def with interposable linkage is non-prevailing, + // * there is a prevailing def available for import and marked read-only. + // In this case, the non-prevailing def will be converted to a declaration, + // while the prevailing one becomes internal, thus no definitions will be + // available for linking. In order to prevent undefined symbol link error, + // the prevailing definition must be imported. + // FIXME: Consider adding a check that the suitable prevailing definition + // exists and marked read-only. + if (VI.getSummaryList().size() > 1 && + GlobalValue::isInterposableLinkage(GVS->second->linkage())) + return true; + + return false; +} + static void computeImportForReferencedGlobals( const GlobalValueSummary &Summary, const ModuleSummaryIndex &Index, const GVSummaryMapTy &DefinedGVSummaries, @@ -282,7 +305,7 @@ FunctionImporter::ImportMapTy &ImportList, StringMap *ExportLists) { for (auto &VI : Summary.refs()) { - if (DefinedGVSummaries.count(VI.getGUID())) { + if (!shouldImportGlobal(VI, DefinedGVSummaries)) { LLVM_DEBUG( dbgs() << "Ref ignored! Target already in destination module.\n"); continue; @@ -378,6 +401,9 @@ continue; if (DefinedGVSummaries.count(VI.getGUID())) { + // FIXME: Consider not skipping import if the module contains + // a non-prevailing def with interposable linkage. The prevailing copy + // can safely be imported (see shouldImportGlobal()). LLVM_DEBUG(dbgs() << "ignored! Target already in destination module.\n"); continue; } diff --git a/llvm/test/ThinLTO/X86/weak_globals_import.ll b/llvm/test/ThinLTO/X86/weak_globals_import.ll new file mode 100644 --- /dev/null +++ b/llvm/test/ThinLTO/X86/weak_globals_import.ll @@ -0,0 +1,33 @@ +; RUN: split-file %s %t.dir + +; RUN: opt -module-summary %t.dir/1.ll -o %t1.bc +; RUN: opt -module-summary %t.dir/2.ll -o %t2.bc + +; RUN: llvm-lto2 run -save-temps %t1.bc %t2.bc -o %t.out \ +; RUN: -r=%t1.bc,main,plx \ +; RUN: -r=%t1.bc,G \ +; RUN: -r=%t2.bc,G,pl +; RUN: llvm-dis %t.out.1.3.import.bc -o - | FileCheck %s +; RUN: llvm-dis %t.out.2.3.import.bc -o - | FileCheck %s + +; Test that a non-prevailing def with interposable linkage doesn't prevent +; importing a suitable definition from a prevailing module. + +; CHECK: @G = internal local_unnamed_addr global i32 42 + +;--- 1.ll +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@G = weak dso_local local_unnamed_addr global i32 0, align 4 + +define dso_local i32 @main() local_unnamed_addr { + %1 = load i32, i32* @G, align 4 + ret i32 %1 +} + +;--- 2.ll +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@G = dso_local local_unnamed_addr global i32 42, align 4