New bitcode linker flags:
authorArtem Belevich <tra@google.com>
Tue, 1 Sep 2015 17:55:55 +0000 (17:55 +0000)
committerArtem Belevich <tra@google.com>
Tue, 1 Sep 2015 17:55:55 +0000 (17:55 +0000)
-only-needed -- link in only symbols needed by destination module
-internalize -- internalize linked symbols

Differential Revision: http://reviews.llvm.org/D12459

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

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

index 2a46d755b8e060c7a0bffea8076f333ee85c3d28..3a6df80aa38d18136f4bedbf64a38f9652dea65e 100644 (file)
@@ -60,6 +60,13 @@ public:
     bool hasType(StructType *Ty);
   };
 
     bool hasType(StructType *Ty);
   };
 
+  enum Flags {
+    None = 0,
+    OverrideFromSrc = (1 << 0),
+    LinkOnlyNeeded = (1 << 1),
+    InternalizeLinkedSymbols = (1 << 2)
+  };
+
   Linker(Module *M, DiagnosticHandlerFunction DiagnosticHandler);
   Linker(Module *M);
 
   Linker(Module *M, DiagnosticHandlerFunction DiagnosticHandler);
   Linker(Module *M);
 
@@ -70,15 +77,17 @@ public:
   /// Passing OverrideSymbols as true will have symbols from Src
   /// shadow those in the Dest.
   /// Returns true on error.
   /// Passing OverrideSymbols as true will have symbols from Src
   /// shadow those in the Dest.
   /// Returns true on error.
-  bool linkInModule(Module *Src, bool OverrideSymbols = false);
+  bool linkInModule(Module *Src, unsigned Flags = Flags::None);
 
   /// \brief Set the composite to the passed-in module.
   void setModule(Module *Dst);
 
   static bool LinkModules(Module *Dest, Module *Src,
 
   /// \brief Set the composite to the passed-in module.
   void setModule(Module *Dst);
 
   static bool LinkModules(Module *Dest, Module *Src,
-                          DiagnosticHandlerFunction DiagnosticHandler);
+                          DiagnosticHandlerFunction DiagnosticHandler,
+                          unsigned Flags = Flags::None);
 
 
-  static bool LinkModules(Module *Dest, Module *Src);
+  static bool LinkModules(Module *Dest, Module *Src,
+                          unsigned Flags = Flags::None);
 
 private:
   void init(Module *M, DiagnosticHandlerFunction DiagnosticHandler);
 
 private:
   void init(Module *M, DiagnosticHandlerFunction DiagnosticHandler);
index 3b84454455e917942111b76c916755f8237ade2f..9d5e0b475d8b2a470316aa9bf98c639218d6cda3 100644 (file)
@@ -425,19 +425,23 @@ class ModuleLinker {
   DiagnosticHandlerFunction DiagnosticHandler;
 
   /// For symbol clashes, prefer those from Src.
   DiagnosticHandlerFunction DiagnosticHandler;
 
   /// For symbol clashes, prefer those from Src.
-  bool OverrideFromSrc;
+  unsigned Flags;
 
 public:
   ModuleLinker(Module *dstM, Linker::IdentifiedStructTypeSet &Set, Module *srcM,
 
 public:
   ModuleLinker(Module *dstM, Linker::IdentifiedStructTypeSet &Set, Module *srcM,
-               DiagnosticHandlerFunction DiagnosticHandler,
-               bool OverrideFromSrc)
+               DiagnosticHandlerFunction DiagnosticHandler, unsigned Flags)
       : DstM(dstM), SrcM(srcM), TypeMap(Set),
         ValMaterializer(TypeMap, DstM, LazilyLinkGlobalValues),
       : DstM(dstM), SrcM(srcM), TypeMap(Set),
         ValMaterializer(TypeMap, DstM, LazilyLinkGlobalValues),
-        DiagnosticHandler(DiagnosticHandler), OverrideFromSrc(OverrideFromSrc) {
-  }
+        DiagnosticHandler(DiagnosticHandler), Flags(Flags) {}
 
   bool run();
 
 
   bool run();
 
+  bool shouldOverrideFromSrc() { return Flags & Linker::OverrideFromSrc; }
+  bool shouldLinkOnlyNeeded() { return Flags & Linker::LinkOnlyNeeded; }
+  bool shouldInternalizeLinkedSymbols() {
+    return Flags & Linker::InternalizeLinkedSymbols;
+  }
+
 private:
   bool shouldLinkFromSource(bool &LinkFromSrc, const GlobalValue &Dest,
                             const GlobalValue &Src);
 private:
   bool shouldLinkFromSource(bool &LinkFromSrc, const GlobalValue &Dest,
                             const GlobalValue &Src);
@@ -730,7 +734,7 @@ bool ModuleLinker::shouldLinkFromSource(bool &LinkFromSrc,
                                         const GlobalValue &Dest,
                                         const GlobalValue &Src) {
   // Should we unconditionally use the Src?
                                         const GlobalValue &Dest,
                                         const GlobalValue &Src) {
   // Should we unconditionally use the Src?
-  if (OverrideFromSrc) {
+  if (shouldOverrideFromSrc()) {
     LinkFromSrc = true;
     return false;
   }
     LinkFromSrc = true;
     return false;
   }
@@ -1081,13 +1085,20 @@ 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.
   } 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 && !OverrideFromSrc &&
+    if (!DGV && !shouldOverrideFromSrc() &&
         (SGV->hasLocalLinkage() || SGV->hasLinkOnceLinkage() ||
          SGV->hasAvailableExternallyLinkage())) {
       DoNotLinkFromSource.insert(SGV);
       return false;
     }
 
         (SGV->hasLocalLinkage() || SGV->hasLinkOnceLinkage() ||
          SGV->hasAvailableExternallyLinkage())) {
       DoNotLinkFromSource.insert(SGV);
       return false;
     }
 
+    // When we only want to link in unresolved dependencies, blacklist
+    // the symbol unless unless DestM has a matching declaration (DGV).
+    if (shouldLinkOnlyNeeded() && !(DGV && DGV->isDeclaration())) {
+      DoNotLinkFromSource.insert(SGV);
+      return false;
+    }
+
     NewGV = copyGlobalValueProto(TypeMap, *DstM, SGV);
 
     if (DGV && isa<Function>(DGV))
     NewGV = copyGlobalValueProto(TypeMap, *DstM, SGV);
 
     if (DGV && isa<Function>(DGV))
@@ -1249,6 +1260,9 @@ void ModuleLinker::linkAliasBody(GlobalAlias &Dst, GlobalAlias &Src) {
 bool ModuleLinker::linkGlobalValueBody(GlobalValue &Src) {
   Value *Dst = ValueMap[&Src];
   assert(Dst);
 bool ModuleLinker::linkGlobalValueBody(GlobalValue &Src) {
   Value *Dst = ValueMap[&Src];
   assert(Dst);
+  if (shouldInternalizeLinkedSymbols())
+    if (auto *DGV = dyn_cast<GlobalValue>(Dst))
+      DGV->setLinkage(GlobalValue::InternalLinkage);
   if (auto *F = dyn_cast<Function>(&Src))
     return linkFunctionBody(cast<Function>(*Dst), *F);
   if (auto *GVar = dyn_cast<GlobalVariable>(&Src)) {
   if (auto *F = dyn_cast<Function>(&Src))
     return linkFunctionBody(cast<Function>(*Dst), *F);
   if (auto *GVar = dyn_cast<GlobalVariable>(&Src)) {
@@ -1632,6 +1646,11 @@ bool ModuleLinker::run() {
     GlobalValue *SGV = LazilyLinkGlobalValues.back();
     LazilyLinkGlobalValues.pop_back();
 
     GlobalValue *SGV = LazilyLinkGlobalValues.back();
     LazilyLinkGlobalValues.pop_back();
 
+    // Skip declarations that ValueMaterializer may have created in
+    // case we link in only some of SrcM.
+    if (shouldLinkOnlyNeeded() && SGV->isDeclaration())
+      continue;
+
     assert(!SGV->isDeclaration() && "users should not pass down decls");
     if (linkGlobalValueBody(*SGV))
       return true;
     assert(!SGV->isDeclaration() && "users should not pass down decls");
     if (linkGlobalValueBody(*SGV))
       return true;
@@ -1759,9 +1778,9 @@ void Linker::deleteModule() {
   Composite = nullptr;
 }
 
   Composite = nullptr;
 }
 
-bool Linker::linkInModule(Module *Src, bool OverrideSymbols) {
+bool Linker::linkInModule(Module *Src, unsigned Flags) {
   ModuleLinker TheLinker(Composite, IdentifiedStructTypes, Src,
   ModuleLinker TheLinker(Composite, IdentifiedStructTypes, Src,
-                         DiagnosticHandler, OverrideSymbols);
+                         DiagnosticHandler, Flags);
   bool RetCode = TheLinker.run();
   Composite->dropTriviallyDeadConstantArrays();
   return RetCode;
   bool RetCode = TheLinker.run();
   Composite->dropTriviallyDeadConstantArrays();
   return RetCode;
@@ -1781,14 +1800,15 @@ void Linker::setModule(Module *Dst) {
 /// Upon failure, the Dest module could be in a modified state, and shouldn't be
 /// relied on to be consistent.
 bool Linker::LinkModules(Module *Dest, Module *Src,
 /// Upon failure, the Dest module could be in a modified state, and shouldn't be
 /// relied on to be consistent.
 bool Linker::LinkModules(Module *Dest, Module *Src,
-                         DiagnosticHandlerFunction DiagnosticHandler) {
+                         DiagnosticHandlerFunction DiagnosticHandler,
+                         unsigned Flags) {
   Linker L(Dest, DiagnosticHandler);
   Linker L(Dest, DiagnosticHandler);
-  return L.linkInModule(Src);
+  return L.linkInModule(Src, Flags);
 }
 
 }
 
-bool Linker::LinkModules(Module *Dest, Module *Src) {
+bool Linker::LinkModules(Module *Dest, Module *Src, unsigned Flags) {
   Linker L(Dest);
   Linker L(Dest);
-  return L.linkInModule(Src);
+  return L.linkInModule(Src, Flags);
 }
 
 //===----------------------------------------------------------------------===//
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/test/Linker/Inputs/linkage.c.ll b/test/Linker/Inputs/linkage.c.ll
new file mode 100644 (file)
index 0000000..6aedf5a
--- /dev/null
@@ -0,0 +1,4 @@
+@X = global i32 5
+@U = global i32 6
+define i32 @foo() { ret i32 7 }
+define i32 @unused() { ret i32 8 }
diff --git a/test/Linker/link-flags.ll b/test/Linker/link-flags.ll
new file mode 100644 (file)
index 0000000..4c56aed
--- /dev/null
@@ -0,0 +1,21 @@
+; RUN: llvm-as %S/Inputs/linkage.b.ll -o %t.b.bc
+; RUN: llvm-as %S/Inputs/linkage.c.ll -o %t.c.bc
+; RUN: llvm-link -S %t.b.bc %t.c.bc | FileCheck %s -check-prefix=B -check-prefix=C -check-prefix=CU
+; RUN: llvm-link -S -only-needed %t.b.bc %t.c.bc | FileCheck %s -check-prefix=B -check-prefix=C -check-prefix=CN
+; RUN: llvm-link -S -internalize %t.b.bc %t.c.bc | FileCheck %s -check-prefix=B -check-prefix=CI
+; RUN: llvm-link -S -internalize -only-needed %t.b.bc %t.c.bc | FileCheck %s -check-prefix=B -check-prefix=CN
+
+C-LABEL: @X = global i32 5
+CI-LABEL: @X = internal global i32 5
+CU-LABEL:@U = global i32 6
+CI-LABEL:@U = internal global i32 6
+CN-LABEL-NOT:@U
+
+B-LABEL: define void @bar() {
+
+C-LABEL: define i32 @foo()
+CI-LABEL: define internal i32 @foo()
+
+CU-LABEL:define i32 @unused() {
+CI-LABEL:define internal i32 @unused() {
+CN-LABEL-NOT:@unused()
index 369f3477fe5c99434cd1ce74d1c3b40ba6cf7292..7f294f3e71966d0f04b9d1d4d9c437029d4adfaf 100644 (file)
@@ -47,6 +47,12 @@ static cl::opt<std::string>
 OutputFilename("o", cl::desc("Override output filename"), cl::init("-"),
                cl::value_desc("filename"));
 
 OutputFilename("o", cl::desc("Override output filename"), cl::init("-"),
                cl::value_desc("filename"));
 
+static cl::opt<bool>
+Internalize("internalize", cl::desc("Internalize linked symbols"));
+
+static cl::opt<bool>
+OnlyNeeded("only-needed", cl::desc("Link only needed symbols"));
+
 static cl::opt<bool>
 Force("f", cl::desc("Enable binary output on terminals"));
 
 static cl::opt<bool>
 Force("f", cl::desc("Enable binary output on terminals"));
 
@@ -114,7 +120,9 @@ static void diagnosticHandler(const DiagnosticInfo &DI) {
 
 static bool linkFiles(const char *argv0, LLVMContext &Context, Linker &L,
                       const cl::list<std::string> &Files,
 
 static bool linkFiles(const char *argv0, LLVMContext &Context, Linker &L,
                       const cl::list<std::string> &Files,
-                      bool OverrideDuplicateSymbols) {
+                      unsigned Flags) {
+  // Filter out flags that don't apply to the first file we load.
+  unsigned ApplicableFlags = Flags & Linker::Flags::OverrideFromSrc;
   for (const auto &File : Files) {
     std::unique_ptr<Module> M = loadFile(argv0, File, Context);
     if (!M.get()) {
   for (const auto &File : Files) {
     std::unique_ptr<Module> M = loadFile(argv0, File, Context);
     if (!M.get()) {
@@ -130,8 +138,10 @@ static bool linkFiles(const char *argv0, LLVMContext &Context, Linker &L,
     if (Verbose)
       errs() << "Linking in '" << File << "'\n";
 
     if (Verbose)
       errs() << "Linking in '" << File << "'\n";
 
-    if (L.linkInModule(M.get(), OverrideDuplicateSymbols))
+    if (L.linkInModule(M.get(), ApplicableFlags))
       return false;
       return false;
+    // All linker flags apply to linking of subsequent files.
+    ApplicableFlags = Flags;
   }
 
   return true;
   }
 
   return true;
@@ -149,12 +159,19 @@ int main(int argc, char **argv) {
   auto Composite = make_unique<Module>("llvm-link", Context);
   Linker L(Composite.get(), diagnosticHandler);
 
   auto Composite = make_unique<Module>("llvm-link", Context);
   Linker L(Composite.get(), diagnosticHandler);
 
+  unsigned Flags = Linker::Flags::None;
+  if (Internalize)
+    Flags |= Linker::Flags::InternalizeLinkedSymbols;
+  if (OnlyNeeded)
+    Flags |= Linker::Flags::LinkOnlyNeeded;
+
   // First add all the regular input files
   // First add all the regular input files
-  if (!linkFiles(argv[0], Context, L, InputFilenames, false))
+  if (!linkFiles(argv[0], Context, L, InputFilenames, Flags))
     return 1;
 
   // Next the -override ones.
     return 1;
 
   // Next the -override ones.
-  if (!linkFiles(argv[0], Context, L, OverridingInputs, true))
+  if (!linkFiles(argv[0], Context, L, OverridingInputs,
+                 Flags | Linker::Flags::OverrideFromSrc))
     return 1;
 
   if (DumpAsm) errs() << "Here's the assembly:\n" << *Composite;
     return 1;
 
   if (DumpAsm) errs() << "Here's the assembly:\n" << *Composite;