[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