<div dir="ltr">Nice!</div><div class="gmail_extra"><br><br><div class="gmail_quote">On Thu, Aug 21, 2014 at 1:28 PM, Rafael Espindola <span dir="ltr"><<a href="mailto:rafael.espindola@gmail.com" target="_blank">rafael.espindola@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: rafael<br>
Date: Thu Aug 21 15:28:55 2014<br>
New Revision: 216215<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=216215&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=216215&view=rev</a><br>
Log:<br>
Rewrite the gold plugin to fix pr19901.<br>
<br>
There is a fundamental difference between how the gold API and lib/LTO view<br>
the LTO process.<br>
<br>
The gold API talks about a particular symbol in a particular file. The lib/LTO<br>
API talks about a symbol in the merged module.<br>
<br>
The merged module is then defined in terms of the IR semantics. In particular,<br>
a linkonce_odr GV is only copied if it is used, since it is valid to drop<br>
unused linkonce_odr GVs.<br>
<br>
In the testcase in pr19901 both properties collide. What happens is that gold<br>
asks us to keep a particular linkonce_odr symbol, but the IR linker doesn't<br>
copy it to the merged module and we never have a chance to ask lib/LTO to keep<br>
it.<br>
<br>
This patch fixes it by having a more direct implementation of the gold API. If<br>
it asks us to keep a symbol, we change the linkage so it is not linkonce. If it<br>
says we can drop a symbol, we do so. All of this before we even send the module<br>
to lib/Linker.<br>
<br>
Since now we don't have to produce LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN,<br>
during symbol resolution we can use a temporary LLVMContext and do lazy<br>
module loading. This allows us to keep the minimum possible amount of<br>
allocated memory around. This should also allow as much parallelism as<br>
we want, since there is no shared context.<br>
<br>
Added:<br>
    llvm/trunk/test/tools/gold/Inputs/alias-1.ll<br>
    llvm/trunk/test/tools/gold/Inputs/pr19901-1.ll<br>
    llvm/trunk/test/tools/gold/alias.ll<br>
    llvm/trunk/test/tools/gold/pr19901.ll<br>
Modified:<br>
    llvm/trunk/test/tools/gold/emit-llvm.ll<br>
    llvm/trunk/test/tools/gold/mtriple.ll<br>
    llvm/trunk/tools/gold/CMakeLists.txt<br>
    llvm/trunk/tools/gold/Makefile<br>
    llvm/trunk/tools/gold/gold-plugin.cpp<br>
<br>
Added: llvm/trunk/test/tools/gold/Inputs/alias-1.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/gold/Inputs/alias-1.ll?rev=216215&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/gold/Inputs/alias-1.ll?rev=216215&view=auto</a><br>

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

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

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

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

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

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

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

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

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