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

Reid Kleckner rnk at google.com
Fri Aug 22 09:46:14 PDT 2014


Nice!


On Thu, Aug 21, 2014 at 1:28 PM, Rafael Espindola <
rafael.espindola at gmail.com> wrote:

> 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/pr19901-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?rev=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?rev=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=216215&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?rev=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
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20140822/f3657100/attachment.html>


More information about the llvm-commits mailing list