diff --git a/llvm/lib/Linker/CMakeLists.txt b/llvm/lib/Linker/CMakeLists.txt --- a/llvm/lib/Linker/CMakeLists.txt +++ b/llvm/lib/Linker/CMakeLists.txt @@ -10,6 +10,7 @@ LINK_COMPONENTS Core + Object Support TransformUtils ) diff --git a/llvm/lib/Linker/IRMover.cpp b/llvm/lib/Linker/IRMover.cpp --- a/llvm/lib/Linker/IRMover.cpp +++ b/llvm/lib/Linker/IRMover.cpp @@ -17,6 +17,7 @@ #include "llvm/IR/GVMaterializer.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/TypeFinder.h" +#include "llvm/Object/ModuleSymbolTable.h" #include "llvm/Support/Error.h" #include "llvm/Transforms/Utils/Cloning.h" #include @@ -1438,12 +1439,6 @@ DstM.setTargetTriple(SrcTriple.merge(DstTriple)); - // Append the module inline asm string. - if (!IsPerformingImport && !SrcM->getModuleInlineAsm().empty()) { - DstM.appendModuleInlineAsm(adjustInlineAsm(SrcM->getModuleInlineAsm(), - SrcTriple)); - } - // Loop over all of the linked values to compute type mappings. computeTypeMapping(); @@ -1474,6 +1469,24 @@ // are properly remapped. linkNamedMDNodes(); + if (!IsPerformingImport && !SrcM->getModuleInlineAsm().empty()) { + // Append the module inline asm string. + DstM.appendModuleInlineAsm(adjustInlineAsm(SrcM->getModuleInlineAsm(), + SrcTriple)); + } else if (IsPerformingImport) { + // Import any symver directives for symbols in DstM. + ModuleSymbolTable::CollectAsmSymvers(*SrcM, + [&](StringRef Name, StringRef Alias) { + if (DstM.getNamedValue(Name)) { + SmallString<256> S(".symver "); + S += Name; + S += ", "; + S += Alias; + DstM.appendModuleInlineAsm(S); + } + }); + } + // Merge the module flags into the DstM module. return linkModuleFlagsMetadata(); } diff --git a/llvm/test/ThinLTO/X86/Inputs/import-symver-foo.ll b/llvm/test/ThinLTO/X86/Inputs/import-symver-foo.ll new file mode 100644 --- /dev/null +++ b/llvm/test/ThinLTO/X86/Inputs/import-symver-foo.ll @@ -0,0 +1,12 @@ +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" + +module asm ".symver bar, bar@BAR_1.2.3" + +declare dso_local i32 @bar() + +define dso_local i32 @foo() { +entry: + %call = tail call i32 @bar() + ret i32 %call +} diff --git a/llvm/test/ThinLTO/X86/import-symver.ll b/llvm/test/ThinLTO/X86/import-symver.ll new file mode 100644 --- /dev/null +++ b/llvm/test/ThinLTO/X86/import-symver.ll @@ -0,0 +1,28 @@ +; RUN: opt -thinlto-bc %s -o %t1.bc +; RUN: opt -thinlto-bc %p/Inputs/import-symver-foo.ll -o %t2.bc +; RUN: llvm-lto -thinlto-action=thinlink %t1.bc %t2.bc -o %t3.index.bc + +; RUN: llvm-lto -thinlto-action=import -exported-symbol=main %t1.bc -thinlto-index=%t3.index.bc +; RUN: llvm-dis %t1.bc.thinlto.imported.bc -o - | FileCheck --check-prefix=IMPORT %s + +; RUN: llvm-lto -thinlto-action=import -exported-symbol=main -import-instr-limit=0 %t1.bc -thinlto-index=%t3.index.bc +; RUN: llvm-dis %t1.bc.thinlto.imported.bc -o - | FileCheck --check-prefix=NOIMPORT %s + +; When @bar gets imported, the symver must be imported too. +; IMPORT: module asm ".symver bar, bar@BAR_1.2.3" +; IMPORT: declare dso_local i32 @bar() + +; When @bar isn't imported, the symver is also not imported. +; NOIMPORT-NOT: module asm +; NOIMPORT-NOT: declare dso_local i32 @bar() + +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" + +declare dso_local i32 @foo() + +define dso_local i32 @main() { +entry: + %call = tail call i32 @foo() + ret i32 %call +} diff --git a/llvm/utils/gn/secondary/llvm/lib/Linker/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/Linker/BUILD.gn --- a/llvm/utils/gn/secondary/llvm/lib/Linker/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/lib/Linker/BUILD.gn @@ -2,6 +2,7 @@ output_name = "LLVMLinker" deps = [ "//llvm/lib/IR", + "//llvm/lib/Object", "//llvm/lib/Support", "//llvm/lib/Transforms/Utils", ]