<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>