Index: llvm/lib/Linker/IRMover.cpp =================================================================== --- llvm/lib/Linker/IRMover.cpp +++ llvm/lib/Linker/IRMover.cpp @@ -708,6 +708,25 @@ SGV->getThreadLocalMode(), SGV->getAddressSpace()); } + if (IsPerformingImport) { + // If there's a symver for the imported symbol, import it too. + NamedMDNode *Symvers = SGV->getParent()->getNamedMetadata("symvers"); + if (Symvers) { + // FIXME: Use a faster data structure. + for (MDNode *Tuple : Symvers->operands()) { + StringRef Name = cast(Tuple->getOperand(0))->getString(); + StringRef Alias = cast(Tuple->getOperand(1))->getString(); + if (Name == SGV->getName()) { + SmallString<256> S(".symver "); + S += Name; + S += ", "; + S += Alias; + DstM.appendModuleInlineAsm(S); + } + } + } + } + if (ForDefinition) NewGV->setLinkage(SGV->getLinkage()); else if (SGV->hasExternalWeakLinkage()) Index: llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp =================================================================== --- llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp +++ llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp @@ -475,6 +475,24 @@ // Write it out as an unsplit ThinLTO module. + // Add symver metadata. + // FIXME: Move to a helper function, since splitAndWriteThinLTOBitcode() has the same code? + SmallVector Symvers; + ModuleSymbolTable::CollectAsmSymvers(M, [&](StringRef Name, StringRef Alias) { + Function *F = M.getFunction(Name); + if (!F || F->use_empty()) + return; + auto &Ctx = M.getContext(); + Symvers.push_back(MDTuple::get( + Ctx, {MDString::get(Ctx, Name), MDString::get(Ctx, Alias)})); + }); + if (!Symvers.empty()) { + llvm::errs () << "writing symvers metadata\n"; + NamedMDNode *NMD = M.getOrInsertNamedMetadata("symvers"); + for (auto MD : Symvers) + NMD->addOperand(MD); + } + // Save the module hash produced for the full bitcode, which will // be used in the backends, and use that in the minimized bitcode // produced for the full link. Index: llvm/test/ThinLTO/X86/Inputs/import-symver-foo.ll =================================================================== --- /dev/null +++ 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 +} Index: llvm/test/ThinLTO/X86/import-symver.ll =================================================================== --- /dev/null +++ llvm/test/ThinLTO/X86/import-symver.ll @@ -0,0 +1,21 @@ +; 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 %s + +; When @bar gets imported, the symver must be imported too. +; CHECK: module asm ".symver bar, bar@BAR_1.2.3" +; CHECK: 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 +} Index: llvm/test/Transforms/ThinLTOBitcodeWriter/symver.ll =================================================================== --- llvm/test/Transforms/ThinLTOBitcodeWriter/symver.ll +++ llvm/test/Transforms/ThinLTOBitcodeWriter/symver.ll @@ -1,6 +1,8 @@ ; RUN: opt -thinlto-bc -thinlto-split-lto-unit -o %t %s ; RUN: llvm-modextract -n 1 -o - %t | llvm-dis | FileCheck %s +; RUN: opt -thinlto-bc %s | llvm-dis | FileCheck %s + ; The target assembly parser is required to parse the symver directives ; REQUIRES: x86-registered-target