Linker: Add flag to override linkage rules
authorDuncan P. N. Exon Smith <dexonsmith@apple.com>
Wed, 22 Apr 2015 04:11:00 +0000 (04:11 +0000)
committerDuncan P. N. Exon Smith <dexonsmith@apple.com>
Wed, 22 Apr 2015 04:11:00 +0000 (04:11 +0000)
Add a flag to lib/Linker (and `llvm-link`) to override linkage rules.
When set, the functions in the source module *always* replace those in
the destination module.

The `llvm-link` option is `-override=abc.ll`.  All the "regular" modules
are loaded and linked first, followed by the `-override` modules.  This
is useful for debugging workflows where some subset of the module (e.g.,
a single function) is extracted into a separate file where it's
optimized differently, before being merged back in.

Patch by Luqman Aden!

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@235473 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Linker/Linker.h
lib/Linker/LinkModules.cpp
test/Linker/Inputs/override-different-linkage.ll [new file with mode: 0644]
test/Linker/Inputs/override-with-internal-linkage-2.ll [new file with mode: 0644]
test/Linker/Inputs/override-with-internal-linkage.ll [new file with mode: 0644]
test/Linker/Inputs/override.ll [new file with mode: 0644]
test/Linker/override-different-linkage.ll [new file with mode: 0644]
test/Linker/override-with-internal-linkage-2.ll [new file with mode: 0644]
test/Linker/override-with-internal-linkage.ll [new file with mode: 0644]
test/Linker/override.ll [new file with mode: 0644]
tools/llvm-link/llvm-link.cpp

index 5ca815c325a087347bf466f06dec71bf603de03c..c43b90e9cd2638aece501fef86cc25dd86ab2735 100644 (file)
@@ -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);
index 1e0c5e9858e05882a9f5a14f8e16c90730a4c187..65a02a71c709614eca7825eabac0be58b9683f14 100644 (file)
@@ -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 (file)
index 0000000..bc15140
--- /dev/null
@@ -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 (file)
index 0000000..2f54a15
--- /dev/null
@@ -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 (file)
index 0000000..6e06fa5
--- /dev/null
@@ -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 (file)
index 0000000..6e06fa5
--- /dev/null
@@ -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 (file)
index 0000000..19961f2
--- /dev/null
@@ -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 (file)
index 0000000..2de52a9
--- /dev/null
@@ -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 (file)
index 0000000..f1163d3
--- /dev/null
@@ -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 (file)
index 0000000..015cb4c
--- /dev/null
@@ -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
+}
index 9f287e4fdb6141e0e3904cc8bc4a9e085ea10ee6..369f3477fe5c99434cd1ce74d1c3b40ba6cf7292 100644 (file)
@@ -38,6 +38,11 @@ static cl::list<std::string>
 InputFilenames(cl::Positional, cl::OneOrMore,
                cl::desc("<input bitcode files>"));
 
+static cl::list<std::string> OverridingInputs(
+    "override", cl::ZeroOrMore, cl::value_desc("filename"),
+    cl::desc(
+        "input bitcode file which can override previously defined symbol(s)"));
+
 static cl::opt<std::string>
 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<std::string> &Files) {
+                      const cl::list<std::string> &Files,
+                      bool OverrideDuplicateSymbols) {
   for (const auto &File : Files) {
     std::unique_ptr<Module> 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<Module>("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;