diff --git a/include/llvm/Linker/Linker.h b/include/llvm/Linker/Linker.h index 5ca815c325a..c43b90e9cd2 100644 --- a/include/llvm/Linker/Linker.h +++ b/include/llvm/Linker/Linker.h @@ -68,8 +68,10 @@ public: void deleteModule(); /// \brief Link \p Src into the composite. The source is destroyed. + /// Passing OverrideSymbols as true will have symbols from Src + /// shadow those in the Dest. /// Returns true on error. - bool linkInModule(Module *Src); + bool linkInModule(Module *Src, bool OverrideSymbols = false); /// \brief Set the composite to the passed-in module. void setModule(Module *Dst); diff --git a/lib/Linker/LinkModules.cpp b/lib/Linker/LinkModules.cpp index 1e0c5e9858e..65a02a71c70 100644 --- a/lib/Linker/LinkModules.cpp +++ b/lib/Linker/LinkModules.cpp @@ -424,12 +424,17 @@ class ModuleLinker { DiagnosticHandlerFunction DiagnosticHandler; + /// For symbol clashes, prefer those from Src. + bool OverrideFromSrc; + public: ModuleLinker(Module *dstM, Linker::IdentifiedStructTypeSet &Set, Module *srcM, - DiagnosticHandlerFunction DiagnosticHandler) + DiagnosticHandlerFunction DiagnosticHandler, + bool OverrideFromSrc) : DstM(dstM), SrcM(srcM), TypeMap(Set), ValMaterializer(TypeMap, DstM, LazilyLinkGlobalValues), - DiagnosticHandler(DiagnosticHandler) {} + DiagnosticHandler(DiagnosticHandler), OverrideFromSrc(OverrideFromSrc) { + } bool run(); @@ -725,6 +730,12 @@ bool ModuleLinker::getComdatResult(const Comdat *SrcC, bool ModuleLinker::shouldLinkFromSource(bool &LinkFromSrc, const GlobalValue &Dest, const GlobalValue &Src) { + // Should we unconditionally use the Src? + if (OverrideFromSrc) { + LinkFromSrc = true; + return false; + } + // We always have to add Src if it has appending linkage. if (Src.hasAppendingLinkage()) { LinkFromSrc = true; @@ -1071,8 +1082,9 @@ bool ModuleLinker::linkGlobalValueProto(GlobalValue *SGV) { } else { // If the GV is to be lazily linked, don't create it just yet. // The ValueMaterializerTy will deal with creating it if it's used. - if (!DGV && (SGV->hasLocalLinkage() || SGV->hasLinkOnceLinkage() || - SGV->hasAvailableExternallyLinkage())) { + if (!DGV && !OverrideFromSrc && + (SGV->hasLocalLinkage() || SGV->hasLinkOnceLinkage() || + SGV->hasAvailableExternallyLinkage())) { DoNotLinkFromSource.insert(SGV); return false; } @@ -1738,9 +1750,9 @@ void Linker::deleteModule() { Composite = nullptr; } -bool Linker::linkInModule(Module *Src) { +bool Linker::linkInModule(Module *Src, bool OverrideSymbols) { ModuleLinker TheLinker(Composite, IdentifiedStructTypes, Src, - DiagnosticHandler); + DiagnosticHandler, OverrideSymbols); bool RetCode = TheLinker.run(); Composite->dropTriviallyDeadConstantArrays(); return RetCode; diff --git a/test/Linker/Inputs/override-different-linkage.ll b/test/Linker/Inputs/override-different-linkage.ll new file mode 100644 index 00000000000..bc151409180 --- /dev/null +++ b/test/Linker/Inputs/override-different-linkage.ll @@ -0,0 +1,4 @@ +define linkonce i32 @foo(i32 %i) { +entry: + ret i32 4 +} diff --git a/test/Linker/Inputs/override-with-internal-linkage-2.ll b/test/Linker/Inputs/override-with-internal-linkage-2.ll new file mode 100644 index 00000000000..2f54a1511fa --- /dev/null +++ b/test/Linker/Inputs/override-with-internal-linkage-2.ll @@ -0,0 +1,4 @@ +define internal i32 @foo(i32 %i) { +entry: + ret i32 4 +} diff --git a/test/Linker/Inputs/override-with-internal-linkage.ll b/test/Linker/Inputs/override-with-internal-linkage.ll new file mode 100644 index 00000000000..6e06fa5c4f7 --- /dev/null +++ b/test/Linker/Inputs/override-with-internal-linkage.ll @@ -0,0 +1,4 @@ +define i32 @foo(i32 %i) { +entry: + ret i32 4 +} diff --git a/test/Linker/Inputs/override.ll b/test/Linker/Inputs/override.ll new file mode 100644 index 00000000000..6e06fa5c4f7 --- /dev/null +++ b/test/Linker/Inputs/override.ll @@ -0,0 +1,4 @@ +define i32 @foo(i32 %i) { +entry: + ret i32 4 +} diff --git a/test/Linker/override-different-linkage.ll b/test/Linker/override-different-linkage.ll new file mode 100644 index 00000000000..19961f2486a --- /dev/null +++ b/test/Linker/override-different-linkage.ll @@ -0,0 +1,19 @@ +; RUN: llvm-link %s -override %S/Inputs/override-different-linkage.ll -S | FileCheck %s +; RUN: llvm-link -override %S/Inputs/override-different-linkage.ll %s -S | FileCheck %s + + +; CHECK-LABEL: define linkonce i32 @foo +; CHECK-NEXT: entry: +; CHECK-NEXT: ret i32 4 +define weak i32 @foo(i32 %i) { +entry: + %add = add nsw i32 %i, %i + ret i32 %add +} + +; Function Attrs: nounwind ssp uwtable +define i32 @main(i32 %argc, i8** %argv) { +entry: + %a = call i32 @foo(i32 2) + ret i32 %a +} diff --git a/test/Linker/override-with-internal-linkage-2.ll b/test/Linker/override-with-internal-linkage-2.ll new file mode 100644 index 00000000000..2de52a925b2 --- /dev/null +++ b/test/Linker/override-with-internal-linkage-2.ll @@ -0,0 +1,23 @@ +; RUN: llvm-link %s -override %S/Inputs/override-with-internal-linkage-2.ll -S | FileCheck %s +; RUN: llvm-link -override %S/Inputs/override-with-internal-linkage-2.ll %s -S | FileCheck %s + +; CHECK-LABEL: define i32 @foo +; CHECK-NEXT: entry: +; CHECK-NEXT: %add = add nsw i32 %i, %i +; CHECK-NEXT: ret i32 %add +define i32 @foo(i32 %i) { +entry: + %add = add nsw i32 %i, %i + ret i32 %add +} + +; CHECK-LABEL: define internal i32 @foo1 +; CHECK-NEXT: entry: +; CHECK-NEXT: ret i32 4 + +; Function Attrs: nounwind ssp uwtable +define i32 @main(i32 %argc, i8** %argv) { +entry: + %a = call i32 @foo(i32 2) + ret i32 %a +} diff --git a/test/Linker/override-with-internal-linkage.ll b/test/Linker/override-with-internal-linkage.ll new file mode 100644 index 00000000000..f1163d32174 --- /dev/null +++ b/test/Linker/override-with-internal-linkage.ll @@ -0,0 +1,23 @@ +; RUN: llvm-link %s -override %S/Inputs/override-with-internal-linkage.ll -S | FileCheck %s +; RUN: llvm-link -override %S/Inputs/override-with-internal-linkage.ll %s -S | FileCheck %s + +; CHECK-LABEL: define internal i32 @foo2 +; CHECK-NEXT: entry: +; CHECK-NEXT: %add = add nsw i32 %i, %i +; CHECK-NEXT: ret i32 %add + +; CHECK-LABEL: define i32 @foo +; CHECK-NEXT: entry: +; CHECK-NEXT: ret i32 4 +define internal i32 @foo(i32 %i) { +entry: + %add = add nsw i32 %i, %i + ret i32 %add +} + +; Function Attrs: nounwind ssp uwtable +define i32 @main(i32 %argc, i8** %argv) { +entry: + %a = call i32 @foo(i32 2) + ret i32 %a +} diff --git a/test/Linker/override.ll b/test/Linker/override.ll new file mode 100644 index 00000000000..015cb4c382a --- /dev/null +++ b/test/Linker/override.ll @@ -0,0 +1,19 @@ +; RUN: llvm-link %s -override %S/Inputs/override.ll -S | FileCheck %s +; RUN: llvm-link -override %S/Inputs/override.ll %s -S | FileCheck %s + + +; CHECK-LABEL: define i32 @foo +; CHECK-NEXT: entry: +; CHECK-NEXT: ret i32 4 +define i32 @foo(i32 %i) { +entry: + %add = add nsw i32 %i, %i + ret i32 %add +} + +; Function Attrs: nounwind ssp uwtable +define i32 @main(i32 %argc, i8** %argv) { +entry: + %a = call i32 @foo(i32 2) + ret i32 %a +} diff --git a/tools/llvm-link/llvm-link.cpp b/tools/llvm-link/llvm-link.cpp index 9f287e4fdb6..369f3477fe5 100644 --- a/tools/llvm-link/llvm-link.cpp +++ b/tools/llvm-link/llvm-link.cpp @@ -38,6 +38,11 @@ static cl::list InputFilenames(cl::Positional, cl::OneOrMore, cl::desc("")); +static cl::list OverridingInputs( + "override", cl::ZeroOrMore, cl::value_desc("filename"), + cl::desc( + "input bitcode file which can override previously defined symbol(s)")); + static cl::opt OutputFilename("o", cl::desc("Override output filename"), cl::init("-"), cl::value_desc("filename")); @@ -108,7 +113,8 @@ static void diagnosticHandler(const DiagnosticInfo &DI) { } static bool linkFiles(const char *argv0, LLVMContext &Context, Linker &L, - const cl::list &Files) { + const cl::list &Files, + bool OverrideDuplicateSymbols) { for (const auto &File : Files) { std::unique_ptr M = loadFile(argv0, File, Context); if (!M.get()) { @@ -124,7 +130,7 @@ static bool linkFiles(const char *argv0, LLVMContext &Context, Linker &L, if (Verbose) errs() << "Linking in '" << File << "'\n"; - if (L.linkInModule(M.get())) + if (L.linkInModule(M.get(), OverrideDuplicateSymbols)) return false; } @@ -143,7 +149,12 @@ int main(int argc, char **argv) { auto Composite = make_unique("llvm-link", Context); Linker L(Composite.get(), diagnosticHandler); - if (!linkFiles(argv[0], Context, L, InputFilenames)) + // First add all the regular input files + if (!linkFiles(argv[0], Context, L, InputFilenames, false)) + return 1; + + // Next the -override ones. + if (!linkFiles(argv[0], Context, L, OverridingInputs, true)) return 1; if (DumpAsm) errs() << "Here's the assembly:\n" << *Composite;