[llvm] r216215 - Rewrite the gold plugin to fix pr19901.

Daniel Stewart stewartd at codeaurora.org
Fri Aug 29 11:08:21 PDT 2014


Very nice, thanks Rafael!

-----Original Message-----
From: llvm-commits-bounces at cs.uiuc.edu
[mailto:llvm-commits-bounces at cs.uiuc.edu] On Behalf Of Rafael Espindola
Sent: Thursday, August 21, 2014 4:29 PM
To: llvm-commits at cs.uiuc.edu
Subject: [llvm] r216215 - Rewrite the gold plugin to fix pr19901.

Author: rafael
Date: Thu Aug 21 15:28:55 2014
New Revision: 216215

URL: http://llvm.org/viewvc/llvm-project?rev=216215&view=rev
Log:
Rewrite the gold plugin to fix pr19901.

There is a fundamental difference between how the gold API and lib/LTO view
the LTO process.

The gold API talks about a particular symbol in a particular file. The
lib/LTO API talks about a symbol in the merged module.

The merged module is then defined in terms of the IR semantics. In
particular, a linkonce_odr GV is only copied if it is used, since it is
valid to drop unused linkonce_odr GVs.

In the testcase in pr19901 both properties collide. What happens is that
gold asks us to keep a particular linkonce_odr symbol, but the IR linker
doesn't copy it to the merged module and we never have a chance to ask
lib/LTO to keep it.

This patch fixes it by having a more direct implementation of the gold API.
If it asks us to keep a symbol, we change the linkage so it is not linkonce.
If it says we can drop a symbol, we do so. All of this before we even send
the module to lib/Linker.

Since now we don't have to produce LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN,
during symbol resolution we can use a temporary LLVMContext and do lazy
module loading. This allows us to keep the minimum possible amount of
allocated memory around. This should also allow as much parallelism as we
want, since there is no shared context.

Added:
    llvm/trunk/test/tools/gold/Inputs/alias-1.ll
    llvm/trunk/test/tools/gold/Inputs/pr19901-1.ll
    llvm/trunk/test/tools/gold/alias.ll
    llvm/trunk/test/tools/gold/pr19901.ll
Modified:
    llvm/trunk/test/tools/gold/emit-llvm.ll
    llvm/trunk/test/tools/gold/mtriple.ll
    llvm/trunk/tools/gold/CMakeLists.txt
    llvm/trunk/tools/gold/Makefile
    llvm/trunk/tools/gold/gold-plugin.cpp

Added: llvm/trunk/test/tools/gold/Inputs/alias-1.ll
URL:
http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/gold/Inputs/alias-
1.ll?rev=216215&view=auto
============================================================================
==
--- llvm/trunk/test/tools/gold/Inputs/alias-1.ll (added)
+++ llvm/trunk/test/tools/gold/Inputs/alias-1.ll Thu Aug 21 15:28:55 
+++ 2014
@@ -0,0 +1 @@
+ at a = global i32 42

Added: llvm/trunk/test/tools/gold/Inputs/pr19901-1.ll
URL:
http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/gold/Inputs/pr1990
1-1.ll?rev=216215&view=auto
============================================================================
==
--- llvm/trunk/test/tools/gold/Inputs/pr19901-1.ll (added)
+++ llvm/trunk/test/tools/gold/Inputs/pr19901-1.ll Thu Aug 21 15:28:55 
+++ 2014
@@ -0,0 +1,4 @@
+target triple = "x86_64-unknown-linux-gnu"
+define linkonce_odr hidden void @f() {
+  ret void
+}

Added: llvm/trunk/test/tools/gold/alias.ll
URL:
http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/gold/alias.ll?rev=
216215&view=auto
============================================================================
==
--- llvm/trunk/test/tools/gold/alias.ll (added)
+++ llvm/trunk/test/tools/gold/alias.ll Thu Aug 21 15:28:55 2014
@@ -0,0 +1,11 @@
+; RUN: llvm-as %s -o %t.o
+; RUN: llvm-as %p/Inputs/alias-1.ll -o %t2.o ; RUN: ld -shared -o %t3.o 
+-plugin %llvmshlibdir/LLVMgold.so %t2.o %t.o \ ; RUN:  
+-plugin-opt=emit-llvm ; RUN: llvm-dis %t3.o -o - | FileCheck %s
+
+; CHECK: @a = global i32 42
+; CHECK: @b = global i32 1
+
+ at a = weak alias i32* @b
+ at b = global i32 1

Modified: llvm/trunk/test/tools/gold/emit-llvm.ll
URL:
http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/gold/emit-llvm.ll?
rev=216215&r1=216214&r2=216215&view=diff
============================================================================
==
--- llvm/trunk/test/tools/gold/emit-llvm.ll (original)
+++ llvm/trunk/test/tools/gold/emit-llvm.ll Thu Aug 21 15:28:55 2014
@@ -55,7 +55,11 @@ define linkonce_odr void @f6() unnamed_a
 @g6 = global void()* @f6
 
 
-; API: f3
-; API: f5
-; API: g5
-; API: g6
+; API: f1 PREVAILING_DEF_IRONLY
+; API: f2 PREVAILING_DEF_IRONLY
+; API: f3 PREVAILING_DEF_IRONLY_EXP
+; API: f4 PREVAILING_DEF_IRONLY_EXP
+; API: f5 PREVAILING_DEF_IRONLY_EXP
+; API: f6 PREVAILING_DEF_IRONLY_EXP
+; API: g5 PREVAILING_DEF_IRONLY_EXP
+; API: g6 PREVAILING_DEF_IRONLY_EXP

Modified: llvm/trunk/test/tools/gold/mtriple.ll
URL:
http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/gold/mtriple.ll?re
v=216215&r1=216214&r2=216215&view=diff
============================================================================
==
--- llvm/trunk/test/tools/gold/mtriple.ll (original)
+++ llvm/trunk/test/tools/gold/mtriple.ll Thu Aug 21 15:28:55 2014
@@ -1,7 +1,13 @@
 ; RUN: llvm-as %s -o %t.o
 ; RUN: ld -plugin %llvmshlibdir/LLVMgold.so -m elf32ppc \
 ; RUN:    -plugin-opt=mtriple=powerpc-linux-gnu \
-; RUN:    -shared %t.o -o %t2.o
-; RUN: llvm-readobj %t2.o | FileCheck %s
+; RUN:    -plugin-opt=obj-path=%t3.o \
+; RUN:    -shared %t.o -o %t2
+; RUN: llvm-readobj --file-headers %t2 | FileCheck  --check-prefix=DSO 
+%s ; RUN: llvm-readobj --file-headers %t3.o | FileCheck 
+--check-prefix=REL %s
 
-; CHECK: Format: ELF32-ppc
+; REL:       Type: Relocatable
+; REL-NEXT:  Machine: EM_PPC
+
+; DSO:       Type: SharedObject
+; DSO-NEXT:  Machine: EM_PPC

Added: llvm/trunk/test/tools/gold/pr19901.ll
URL:
http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/gold/pr19901.ll?re
v=216215&view=auto
============================================================================
==
--- llvm/trunk/test/tools/gold/pr19901.ll (added)
+++ llvm/trunk/test/tools/gold/pr19901.ll Thu Aug 21 15:28:55 2014
@@ -0,0 +1,17 @@
+; RUN: llc %s -o %t.o -filetype=obj -relocation-model=pic ; RUN: 
+llvm-as %p/Inputs/pr19901-1.ll -o %t2.o ; RUN: ld -shared -o %t.so 
+-plugin %llvmshlibdir/LLVMgold.so %t2.o %t.o ; RUN: llvm-objdump -d 
+-symbolize %t.so | FileCheck %s
+
+; CHECK: g:
+; CHECK-NEXT: push
+; CHECK-NEXT: callq f
+
+target triple = "x86_64-unknown-linux-gnu"
+define i32 @g() {
+  call void @f()
+  ret i32 0
+}
+define linkonce_odr hidden void @f() {
+  ret void
+}

Modified: llvm/trunk/tools/gold/CMakeLists.txt
URL:
http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/gold/CMakeLists.txt?rev
=216215&r1=216214&r2=216215&view=diff
============================================================================
==
--- llvm/trunk/tools/gold/CMakeLists.txt (original)
+++ llvm/trunk/tools/gold/CMakeLists.txt Thu Aug 21 15:28:55 2014
@@ -16,7 +16,9 @@ else()
 
   set(LLVM_LINK_COMPONENTS
      ${LLVM_TARGETS_TO_BUILD}
-     LTO
+     Linker
+     BitWriter
+     IPO
      )
 
   add_llvm_loadable_module(LLVMgold

Modified: llvm/trunk/tools/gold/Makefile
URL:
http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/gold/Makefile?rev=21621
5&r1=216214&r2=216215&view=diff
============================================================================
==
--- llvm/trunk/tools/gold/Makefile (original)
+++ llvm/trunk/tools/gold/Makefile Thu Aug 21 15:28:55 2014
@@ -20,7 +20,7 @@ EXPORTED_SYMBOL_FILE = $(PROJ_SRC_DIR)/g  # early so we
can set up LINK_COMPONENTS before including Makefile.rules  include
$(LEVEL)/Makefile.config
 
-LINK_COMPONENTS := $(TARGETS_TO_BUILD) LTO
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) Linker BitWriter IPO
 
 # Because off_t is used in the public API, the largefile parts are required
for  # ABI compatibility.

Modified: llvm/trunk/tools/gold/gold-plugin.cpp
URL:
http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/gold/gold-plugin.cpp?re
v=216215&r1=216214&r2=216215&view=diff
============================================================================
==
--- llvm/trunk/tools/gold/gold-plugin.cpp (original)
+++ llvm/trunk/tools/gold/gold-plugin.cpp Thu Aug 21 15:28:55 2014
@@ -13,13 +13,27 @@
 
//===----------------------------------------------------------------------=
==//
 
 #include "llvm/Config/config.h" // plugin-api.h requires HAVE_STDINT_H
-#include "llvm-c/lto.h"
 #include "llvm/ADT/StringSet.h"
+#include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/CodeGen/Analysis.h"
 #include "llvm/CodeGen/CommandFlags.h"
-#include "llvm/LTO/LTOCodeGenerator.h"
-#include "llvm/LTO/LTOModule.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Verifier.h"
+#include "llvm/Linker/Linker.h"
+#include "llvm/MC/SubtargetFeature.h"
+#include "llvm/Object/IRObjectFile.h"
+#include "llvm/PassManager.h"
+#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/Host.h"
 #include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/TargetRegistry.h"
 #include "llvm/Support/TargetSelect.h"
+#include "llvm/Target/TargetLibraryInfo.h"
+#include "llvm/Transforms/IPO.h"
+#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#include "llvm/Transforms/Utils/GlobalStatus.h"
+#include "llvm/Transforms/Utils/ModuleUtils.h"
 #include <list>
 #include <plugin-api.h>
 #include <system_error>
@@ -46,18 +60,18 @@ static ld_plugin_status discard_message(
   abort();
 }
 
+static ld_plugin_get_input_file get_input_file = nullptr; static 
+ld_plugin_release_input_file release_input_file = nullptr;
 static ld_plugin_add_symbols add_symbols = nullptr;  static
ld_plugin_get_symbols get_symbols = nullptr;  static
ld_plugin_add_input_file add_input_file = nullptr;  static
ld_plugin_set_extra_library_path set_extra_library_path = nullptr;  static
ld_plugin_get_view get_view = nullptr;  static ld_plugin_message message =
discard_message; -static lto_codegen_model output_type =
LTO_CODEGEN_PIC_MODEL_STATIC;
+static Reloc::Model RelocationModel = Reloc::Default;
 static std::string output_name = "";
 static std::list<claimed_file> Modules;  static std::vector<std::string>
Cleanup; -static LTOCodeGenerator *CodeGen = nullptr; -static StringSet<>
CannotBeHidden;  static llvm::TargetOptions TargetOpts;
 
 namespace options {
@@ -108,6 +122,11 @@ namespace options {
       }
     } else {
       // Save this option to pass to the code generator.
+      // ParseCommandLineOptions() expects argv[0] to be program name.
Lazily
+      // add that.
+      if (extra.empty())
+        extra.push_back("LLVMgold");
+
       extra.push_back(opt_);
     }
   }
@@ -145,10 +164,10 @@ ld_plugin_status onload(ld_plugin_tv *tv
           case LDPO_REL:  // .o
           case LDPO_DYN:  // .so
           case LDPO_PIE:  // position independent executable
-            output_type = LTO_CODEGEN_PIC_MODEL_DYNAMIC;
+            RelocationModel = Reloc::PIC_;
             break;
           case LDPO_EXEC:  // .exe
-            output_type = LTO_CODEGEN_PIC_MODEL_STATIC;
+            RelocationModel = Reloc::Static;
             break;
           default:
             message(LDPL_ERROR, "Unknown output file type %d",
tv->tv_u.tv_val); @@ -183,6 +202,12 @@ ld_plugin_status onload(ld_plugin_tv
*tv
         if (callback(cleanup_hook) != LDPS_OK)
           return LDPS_ERR;
       } break;
+      case LDPT_GET_INPUT_FILE:
+        get_input_file = tv->tv_u.tv_get_input_file;
+        break;
+      case LDPT_RELEASE_INPUT_FILE:
+        release_input_file = tv->tv_u.tv_release_input_file;
+        break;
       case LDPT_ADD_SYMBOLS:
         add_symbols = tv->tv_u.tv_add_symbols;
         break;
@@ -218,28 +243,15 @@ ld_plugin_status onload(ld_plugin_tv *tv
   if (!RegisteredAllSymbolsRead)
     return LDPS_OK;
 
-  CodeGen = new LTOCodeGenerator();
-
-  // Pass through extra options to the code generator.
-  if (!options::extra.empty()) {
-    for (const char *Opt : options::extra)
-      CodeGen->setCodeGenDebugOptions(Opt);
+  if (!get_input_file) {
+    message(LDPL_ERROR, "get_input_file not passed to LLVMgold.");
+    return LDPS_ERR;
   }
-
-  CodeGen->parseCodeGenDebugOptions();
-  if (MAttrs.size()) {
-    std::string Attrs;
-    for (unsigned I = 0; I < MAttrs.size(); ++I) {
-      if (I > 0)
-        Attrs.append(",");
-      Attrs.append(MAttrs[I]);
-    }
-    CodeGen->setAttr(Attrs.c_str());
+  if (!release_input_file) {
+    message(LDPL_ERROR, "relesase_input_file not passed to LLVMgold.");
+    return LDPS_ERR;
   }
 
-  TargetOpts = InitTargetOptionsFromCodeGenFlags();
-  CodeGen->setTargetOptions(TargetOpts);
-
   return LDPS_OK;
 }
 
@@ -248,13 +260,16 @@ ld_plugin_status onload(ld_plugin_tv *tv  ///
possible.
 static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file,
                                         int *claimed) {
-  const void *view;
+  LLVMContext Context;
   std::unique_ptr<MemoryBuffer> buffer;
   if (get_view) {
+    const void *view;
     if (get_view(file->handle, &view) != LDPS_OK) {
       message(LDPL_ERROR, "Failed to get a view of %s", file->name);
       return LDPS_ERR;
     }
+    buffer.reset(MemoryBuffer::getMemBuffer(
+        StringRef((char *)view, file->filesize), "", false));
   } else {
     int64_t offset = 0;
     // Gold has found what might be IR part-way inside of a file, such as
@@ -270,95 +285,89 @@ static ld_plugin_status claim_file_hook(
       return LDPS_ERR;
     }
     buffer = std::move(BufferOrErr.get());
-    view = buffer->getBufferStart();
   }
 
-  if (!LTOModule::isBitcodeFile(view, file->filesize))
+  ErrorOr<object::IRObjectFile *> ObjOrErr =
+      object::IRObjectFile::createIRObjectFile(buffer->getMemBufferRef(),
+                                               Context);  
+ std::error_code EC = ObjOrErr.getError();  if (EC == 
+ BitcodeError::InvalidBitcodeSignature)
     return LDPS_OK;
 
   *claimed = 1;
 
-  std::string Error;
-  LTOModule *M =
-      LTOModule::createFromBuffer(view, file->filesize, TargetOpts, Error);
-  if (!M) {
+  if (EC) {
     message(LDPL_ERROR, "LLVM gold plugin has failed to create LTO module:
%s",
-            Error.c_str());
+            EC.message().c_str());
     return LDPS_ERR;
   }
+  std::unique_ptr<object::IRObjectFile> Obj(ObjOrErr.get());
 
   Modules.resize(Modules.size() + 1);
   claimed_file &cf = Modules.back();
 
-  if (!options::triple.empty())
-    M->setTargetTriple(options::triple.c_str());
-
   cf.handle = file->handle;
-  unsigned sym_count = M->getSymbolCount();
-  cf.syms.reserve(sym_count);
 
-  for (unsigned i = 0; i != sym_count; ++i) {
-    lto_symbol_attributes attrs = M->getSymbolAttributes(i);
-    if ((attrs & LTO_SYMBOL_SCOPE_MASK) == LTO_SYMBOL_SCOPE_INTERNAL)
+  for (auto &Sym : Obj->symbols()) {
+    uint32_t Symflags = Sym.getFlags();
+    if (!(Symflags & object::BasicSymbolRef::SF_Global))
+      continue;
+
+    if (Symflags & object::BasicSymbolRef::SF_FormatSpecific)
       continue;
 
     cf.syms.push_back(ld_plugin_symbol());
     ld_plugin_symbol &sym = cf.syms.back();
-    sym.name = strdup(M->getSymbolName(i));
     sym.version = nullptr;
 
-    int scope = attrs & LTO_SYMBOL_SCOPE_MASK;
-    bool CanBeHidden = scope == LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN;
-    if (!CanBeHidden)
-      CannotBeHidden.insert(sym.name);
-    switch (scope) {
-      case LTO_SYMBOL_SCOPE_HIDDEN:
+    SmallString<64> Name;
+    {
+      raw_svector_ostream OS(Name);
+      Sym.printName(OS);
+    }
+    sym.name = strdup(Name.c_str());
+
+    const GlobalValue *GV = Obj->getSymbolGV(Sym.getRawDataRefImpl());
+
+    sym.visibility = LDPV_DEFAULT;
+    if (GV) {
+      switch (GV->getVisibility()) {
+      case GlobalValue::DefaultVisibility:
+        sym.visibility = LDPV_DEFAULT;
+        break;
+      case GlobalValue::HiddenVisibility:
         sym.visibility = LDPV_HIDDEN;
         break;
-      case LTO_SYMBOL_SCOPE_PROTECTED:
+      case GlobalValue::ProtectedVisibility:
         sym.visibility = LDPV_PROTECTED;
         break;
-      case 0: // extern
-      case LTO_SYMBOL_SCOPE_DEFAULT:
-      case LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN:
-        sym.visibility = LDPV_DEFAULT;
-        break;
-      default:
-        message(LDPL_ERROR, "Unknown scope attribute: %d", scope);
-        return LDPS_ERR;
+      }
     }
 
-    int definition = attrs & LTO_SYMBOL_DEFINITION_MASK;
-    sym.comdat_key = nullptr;
-    switch (definition) {
-      case LTO_SYMBOL_DEFINITION_REGULAR:
-        sym.def = LDPK_DEF;
-        break;
-      case LTO_SYMBOL_DEFINITION_UNDEFINED:
-        sym.def = LDPK_UNDEF;
-        break;
-      case LTO_SYMBOL_DEFINITION_TENTATIVE:
-        sym.def = LDPK_COMMON;
-        break;
-      case LTO_SYMBOL_DEFINITION_WEAK:
-        sym.comdat_key = sym.name;
-        sym.def = LDPK_WEAKDEF;
-        break;
-      case LTO_SYMBOL_DEFINITION_WEAKUNDEF:
+    if (Symflags & object::BasicSymbolRef::SF_Undefined) {
+      sym.def = LDPK_UNDEF;
+      if (GV && GV->hasExternalWeakLinkage())
         sym.def = LDPK_WEAKUNDEF;
-        break;
-      default:
-        message(LDPL_ERROR, "Unknown definition attribute: %d",
definition);
-        return LDPS_ERR;
+    } else {
+      sym.def = LDPK_DEF;
+      if (GV) {
+        assert(!GV->hasExternalWeakLinkage() &&
+               !GV->hasAvailableExternallyLinkage() && "Not a
declaration!");
+        if (GV->hasCommonLinkage())
+          sym.def = LDPK_COMMON;
+        else if (GV->isWeakForLinker())
+          sym.def = LDPK_WEAKDEF;
+      }
     }
 
     sym.size = 0;
+    sym.comdat_key = nullptr;
+    if (GV && (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage()))
+      sym.comdat_key = sym.name;
 
     sym.resolution = LDPR_UNKNOWN;
   }
 
-  cf.syms.reserve(cf.syms.size());
-
   if (!cf.syms.empty()) {
     if (add_symbols(cf.handle, cf.syms.size(), &cf.syms[0]) != LDPS_OK) {
       message(LDPL_ERROR, "Unable to add symbols!"); @@ -366,51 +375,311 @@
static ld_plugin_status claim_file_hook(
     }
   }
 
-  if (CodeGen) {
-    std::string Error;
-    if (!CodeGen->addModule(M, Error)) {
-      message(LDPL_ERROR, "Error linking module: %s", Error.c_str());
-      return LDPS_ERR;
+  return LDPS_OK;
+}
+
+static void keepGlobalValue(GlobalValue &GV) {
+  assert(!GV.hasLocalLinkage());
+
+  switch (GV.getLinkage()) {
+  default:
+    break;
+  case GlobalValue::LinkOnceAnyLinkage:
+    GV.setLinkage(GlobalValue::WeakAnyLinkage);
+    break;
+  case GlobalValue::LinkOnceODRLinkage:
+    GV.setLinkage(GlobalValue::WeakODRLinkage);
+    break;
+  }
+
+  assert(!GV.isDiscardableIfUnused());
+}
+
+static bool isDeclaration(const GlobalValue &V) {
+  if (V.hasAvailableExternallyLinkage())
+    return true;
+
+  if (V.isMaterializable())
+    return false;
+
+  return V.isDeclaration();
+}
+
+static void internalize(GlobalValue &GV) {
+  if (isDeclaration(GV))
+    return; // We get here if there is a matching asm definition.
+  if (!GV.hasLocalLinkage())
+    GV.setLinkage(GlobalValue::InternalLinkage);
+}
+
+static void drop(GlobalValue &GV) {
+  if (auto *F = dyn_cast<Function>(&GV)) {
+    F->deleteBody();
+    return;
+  }
+
+  if (auto *Var = dyn_cast<GlobalVariable>(&GV)) {
+    Var->setInitializer(nullptr);
+    Var->setLinkage(GlobalValue::ExternalLinkage);
+    return;
+  }
+
+  auto &Alias = cast<GlobalAlias>(GV);
+  Module &M = *Alias.getParent();
+  PointerType &Ty = *cast<PointerType>(Alias.getType());
+  GlobalValue::LinkageTypes L = Alias.getLinkage();
+  auto *Var =
+      new GlobalVariable(M, Ty.getElementType(), /*isConstant*/ false, L,
+                         /*Initializer*/ nullptr);
+  Var->takeName(&Alias);
+  Alias.replaceAllUsesWith(Var);
+}
+
+static const char *getResolutionName(ld_plugin_symbol_resolution R) {
+  switch (R) {
+  case LDPR_UNKNOWN:
+    return "UNKNOWN";
+  case LDPR_UNDEF:
+    return "UNDEF";
+  case LDPR_PREVAILING_DEF:
+    return "PREVAILING_DEF";
+  case LDPR_PREVAILING_DEF_IRONLY:
+    return "PREVAILING_DEF_IRONLY";
+  case LDPR_PREEMPTED_REG:
+    return "PREEMPTED_REG";
+  case LDPR_PREEMPTED_IR:
+    return "PREEMPTED_IR";
+  case LDPR_RESOLVED_IR:
+    return "RESOLVED_IR";
+  case LDPR_RESOLVED_EXEC:
+    return "RESOLVED_EXEC";
+  case LDPR_RESOLVED_DYN:
+    return "RESOLVED_DYN";
+  case LDPR_PREVAILING_DEF_IRONLY_EXP:
+    return "PREVAILING_DEF_IRONLY_EXP";
+  }
+}
+
+static std::unique_ptr<Module>
+getModuleForFile(LLVMContext &Context, claimed_file &F, raw_fd_ostream
*ApiFile,
+                 StringSet<> &Internalize, StringSet<> &Maybe) {
+  ld_plugin_input_file File;
+  if (get_input_file(F.handle, &File) != LDPS_OK)
+    message(LDPL_FATAL, "Failed to get file information");
+
+  if (get_symbols(F.handle, F.syms.size(), &F.syms[0]) != LDPS_OK)
+    message(LDPL_FATAL, "Failed to get symbol information");
+
+  const void *View;
+  if (get_view(F.handle, &View) != LDPS_OK)
+    message(LDPL_FATAL, "Failed to get a view of file");
+
+  std::unique_ptr<MemoryBuffer> Buffer(MemoryBuffer::getMemBuffer(
+      StringRef((char *)View, File.filesize), "", false));
+
+  if (release_input_file(F.handle) != LDPS_OK)
+    message(LDPL_FATAL, "Failed to release file information");
+
+  ErrorOr<Module *> MOrErr = getLazyBitcodeModule(Buffer.get(), 
+ Context);
+
+  if (std::error_code EC = MOrErr.getError())
+    message(LDPL_FATAL, "Could not read bitcode from file : %s",
+            EC.message().c_str());
+  Buffer.release();
+
+  std::unique_ptr<Module> M(MOrErr.get());
+
+  SmallPtrSet<GlobalValue *, 8> Used;
+  collectUsedGlobalVariables(*M, Used, /*CompilerUsed*/ false);
+
+  std::vector<GlobalValue *> Drop;
+  for (ld_plugin_symbol &Sym : F.syms) {
+    ld_plugin_symbol_resolution Resolution =
+        (ld_plugin_symbol_resolution)Sym.resolution;
+
+    if (options::generate_api_file)
+      *ApiFile << Sym.name << ' ' << getResolutionName(Resolution) << 
+ '\n';
+
+    GlobalValue *GV = M->getNamedValue(Sym.name);
+    if (!GV)
+      continue; // Asm symbol.
+
+    switch (Resolution) {
+    case LDPR_UNKNOWN:
+      llvm_unreachable("Unexpected resolution");
+
+    case LDPR_RESOLVED_IR:
+    case LDPR_RESOLVED_EXEC:
+    case LDPR_RESOLVED_DYN:
+    case LDPR_UNDEF:
+      assert(isDeclaration(*GV));
+      break;
+
+    case LDPR_PREVAILING_DEF_IRONLY: {
+      if (!Used.count(GV)) {
+        // Since we use the regular lib/Linker, we cannot just internalize
GV
+        // now or it will not be copied to the merged module. Instead we
force
+        // it to be copied and then internalize it.
+        keepGlobalValue(*GV);
+        Internalize.insert(Sym.name);
+      }
+      break;
+    }
+
+    case LDPR_PREVAILING_DEF:
+      keepGlobalValue(*GV);
+      break;
+
+    case LDPR_PREEMPTED_REG:
+    case LDPR_PREEMPTED_IR:
+      Drop.push_back(GV);
+      break;
+
+    case LDPR_PREVAILING_DEF_IRONLY_EXP: {
+      // We can only check for address uses after we merge the modules. The
+      // reason is that this GV might have a copy in another module
+      // and in that module the address might be significant, but that
+      // copy will be LDPR_PREEMPTED_IR.
+      if (GV->hasLinkOnceODRLinkage())
+        Maybe.insert(Sym.name);
+      keepGlobalValue(*GV);
+      break;
+    }
     }
+
+    free(Sym.name);
+    Sym.name = nullptr;
+    Sym.comdat_key = nullptr;
   }
 
-  delete M;
+  if (!Drop.empty()) {
+    // This is horrible. Given how lazy loading is implemented, dropping
+    // the body while there is a materializer present doesn't work, the
+    // linker will just read the body back.
+    M->materializeAllPermanently();
+    for (auto *GV : Drop)
+      drop(*GV);
+  }
 
-  return LDPS_OK;
+  return M;
 }
 
-static bool mustPreserve(ld_plugin_symbol &Sym) {
-  if (Sym.resolution == LDPR_PREVAILING_DEF)
-    return true;
-  if (Sym.resolution == LDPR_PREVAILING_DEF_IRONLY_EXP)
-    return CannotBeHidden.count(Sym.name);
-  return false;
+static void runLTOPasses(Module &M, TargetMachine &TM) {
+  PassManager passes;
+  PassManagerBuilder PMB;
+  PMB.LibraryInfo = new 
+TargetLibraryInfo(Triple(TM.getTargetTriple()));
+  PMB.Inliner = createFunctionInliningPass();
+  PMB.VerifyInput = true;
+  PMB.VerifyOutput = true;
+  PMB.populateLTOPassManager(passes, &TM);
+  passes.run(M);
+}
+
+static void codegen(Module &M) {
+  const std::string &TripleStr = M.getTargetTriple();
+  Triple TheTriple(TripleStr);
+
+  std::string ErrMsg;
+  const Target *TheTarget = TargetRegistry::lookupTarget(TripleStr, 
+ ErrMsg);  if (!TheTarget)
+    message(LDPL_FATAL, "Target not found: %s", ErrMsg.c_str());
+
+  if (unsigned NumOpts = options::extra.size())
+    cl::ParseCommandLineOptions(NumOpts, &options::extra[0]);
+
+  SubtargetFeatures Features;
+  Features.getDefaultSubtargetFeatures(TheTriple);
+  for (const std::string &A : MAttrs)
+    Features.AddFeature(A);
+
+  TargetOptions Options = InitTargetOptionsFromCodeGenFlags();
+  std::unique_ptr<TargetMachine> TM(TheTarget->createTargetMachine(
+      TripleStr, options::mcpu, Features.getString(), Options,
RelocationModel,
+      CodeModel::Default, CodeGenOpt::Aggressive));
+
+  runLTOPasses(M, *TM);
+
+  PassManager CodeGenPasses;
+  CodeGenPasses.add(new DataLayoutPass(&M));
+
+  SmallString<128> Filename;
+  int FD;
+  if (options::obj_path.empty()) {
+    std::error_code EC =
+        sys::fs::createTemporaryFile("lto-llvm", "o", FD, Filename);
+    if (EC)
+      message(LDPL_FATAL, "Could not create temorary file: %s",
+              EC.message().c_str());
+  } else {
+    Filename = options::obj_path;
+    std::error_code EC =
+        sys::fs::openFileForWrite(Filename.c_str(), FD, sys::fs::F_None);
+    if (EC)
+      message(LDPL_FATAL, "Could not open file: %s", 
+ EC.message().c_str());  }
+
+  {
+    raw_fd_ostream OS(FD, true);
+    formatted_raw_ostream FOS(OS);
+
+    if (TM->addPassesToEmitFile(CodeGenPasses, FOS,
+                                TargetMachine::CGFT_ObjectFile))
+      message(LDPL_FATAL, "Failed to setup codegen");
+    CodeGenPasses.run(M);
+  }
+
+  if (add_input_file(Filename.c_str()) != LDPS_OK)
+    message(LDPL_FATAL,
+            "Unable to add .o file to the link. File left behind in: %s",
+            Filename.c_str());
+
+  if (options::obj_path.empty())
+    Cleanup.push_back(Filename.c_str());
 }
 
 /// gold informs us that all symbols have been read. At this point, we use
/// get_symbols to see if any of our definitions have been overridden by a
/// native object file. Then, perform optimization and codegen.
-static ld_plugin_status allSymbolsReadHook(raw_fd_ostream *apiFile) {
-  assert(CodeGen);
+static ld_plugin_status allSymbolsReadHook(raw_fd_ostream *ApiFile) {
+  if (Modules.empty())
+    return LDPS_OK;
 
-  for (claimed_file &F : Modules) {
-    if (F.syms.empty())
-      continue;
-    get_symbols(F.handle, F.syms.size(), &F.syms[0]);
-    for (ld_plugin_symbol &Sym : F.syms) {
-      if (mustPreserve(Sym)) {
-        CodeGen->addMustPreserveSymbol(Sym.name);
+  LLVMContext Context;
+  std::unique_ptr<Module> Combined(new Module("ld-temp.o", Context));  
+ Linker L(Combined.get());
 
-        if (options::generate_api_file)
-          (*apiFile) << Sym.name << "\n";
-      }
+  std::string DefaultTriple = sys::getDefaultTargetTriple();
+
+  StringSet<> Internalize;
+  StringSet<> Maybe;
+  for (claimed_file &F : Modules) {
+    std::unique_ptr<Module> M =
+        getModuleForFile(Context, F, ApiFile, Internalize, Maybe);
+    if (!options::triple.empty())
+      M->setTargetTriple(options::triple.c_str());
+    else if (M->getTargetTriple().empty()) {
+      M->setTargetTriple(DefaultTriple);
     }
+
+    std::string ErrMsg;
+    if (L.linkInModule(M.get(), &ErrMsg))
+      message(LDPL_FATAL, "Failed to link module: %s", ErrMsg.c_str());  
+ }
+
+  for (const auto &Name : Internalize) {
+    GlobalValue *GV = Combined->getNamedValue(Name.first());
+    if (GV)
+      internalize(*GV);
   }
 
-  CodeGen->setCodePICModel(output_type);
-  CodeGen->setDebugInfo(LTO_DEBUG_MODEL_DWARF);
-  if (!options::mcpu.empty())
-    CodeGen->setCpu(options::mcpu.c_str());
+  for (const auto &Name : Maybe) {
+    GlobalValue *GV = Combined->getNamedValue(Name.first());
+    if (!GV)
+      continue;
+    GV->setLinkage(GlobalValue::LinkOnceODRLinkage);
+    if (canBeOmittedFromSymbolTable(GV))
+      internalize(*GV);
+  }
 
   if (options::generate_bc_file != options::BC_NO) {
     std::string path;
@@ -420,42 +689,22 @@ static ld_plugin_status allSymbolsReadHo
       path = options::bc_path;
     else
       path = output_name + ".bc";
-    std::string Error;
-    if (!CodeGen->writeMergedModules(path.c_str(), Error))
-      message(LDPL_FATAL, "Failed to write the output file.");
+    {
+      std::string Error;
+      raw_fd_ostream OS(path.c_str(), Error, sys::fs::OpenFlags::F_None);
+      if (!Error.empty())
+        message(LDPL_FATAL, "Failed to write the output file.");
+      WriteBitcodeToFile(L.getModule(), OS);
+    }
     if (options::generate_bc_file == options::BC_ONLY)
       return LDPS_OK;
   }
 
-  std::string ObjPath;
-  {
-    const char *Temp;
-    std::string Error;
-    if (!CodeGen->compile_to_file(&Temp, /*DisableOpt*/ false,
/*DisableInline*/
-                                  false, /*DisableGVNLoadPRE*/ false,
Error))
-      message(LDPL_ERROR, "Could not produce a combined object file\n");
-    ObjPath = Temp;
-  }
-
-  for (claimed_file &F : Modules) {
-    for (ld_plugin_symbol &Sym : F.syms)
-      free(Sym.name);
-  }
-
-  if (add_input_file(ObjPath.c_str()) != LDPS_OK) {
-    message(LDPL_ERROR, "Unable to add .o file to the link.");
-    message(LDPL_ERROR, "File left behind in: %s", ObjPath.c_str());
-    return LDPS_ERR;
-  }
+  codegen(*L.getModule());
 
   if (!options::extra_library_path.empty() &&
-      set_extra_library_path(options::extra_library_path.c_str()) !=
LDPS_OK) {
-    message(LDPL_ERROR, "Unable to set the extra library path.");
-    return LDPS_ERR;
-  }
-
-  if (options::obj_path.empty())
-    Cleanup.push_back(ObjPath);
+      set_extra_library_path(options::extra_library_path.c_str()) !=
LDPS_OK)
+    message(LDPL_FATAL, "Unable to set the extra library path.");
 
   return LDPS_OK;
 }
@@ -466,15 +715,13 @@ static ld_plugin_status all_symbols_read
     Ret = allSymbolsReadHook(nullptr);
   } else {
     std::string Error;
-    raw_fd_ostream apiFile("apifile.txt", Error, sys::fs::F_None);
+    raw_fd_ostream ApiFile("apifile.txt", Error, sys::fs::F_None);
     if (!Error.empty())
       message(LDPL_FATAL, "Unable to open apifile.txt for writing: %s",
               Error.c_str());
-    Ret = allSymbolsReadHook(&apiFile);
+    Ret = allSymbolsReadHook(&ApiFile);
   }
 
-  delete CodeGen;
-
   if (options::generate_bc_file == options::BC_ONLY)
     exit(0);
 


_______________________________________________
llvm-commits mailing list
llvm-commits at cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits




More information about the llvm-commits mailing list