[ThinLTO/gold] Support for getting list of included objects from gold

Summary:
In the distributed backend case, the ThinLink step and the final native
object link are separate processes. This can be problematic when archive
libraries are involved in the link (e.g. via --start-lib/--end-lib
pairs). The linker only includes objects from libraries when
there is a strong reference to them, and depending on the intervening
ThinLTO backend processes' importing/inlining, the strong references
may appear different in the two link steps. See D22356 and D22467
for two scenarios where this causes issues.

To ensure that the final link includes the same objects, this patch
adds support for an "=filename" form of the thinlto-index-only plugin
option, in which case objects gold included in the link are emitted to
the given filename. This should be used as input to the final link (e.g.
via the @filename option to gold), instead of listing all the objects
within --start-lib/--end-lib pairs again.

Note that the support for the gold callback that identifies included
objects was added in gold version 1.12.

Reviewers: davidxl, mehdi_amini

Subscribers: llvm-commits, mehdi_amini

Differential Revision: https://reviews.llvm.org/D22677

llvm-svn: 276450
This commit is contained in:
Teresa Johnson 2016-07-22 18:20:22 +00:00
parent e04d0eff29
commit 1e2708c9e0
3 changed files with 92 additions and 0 deletions

View File

@ -0,0 +1,7 @@
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
define void @foo() {
entry:
ret void
}

View File

@ -0,0 +1,45 @@
; First generate bitcode with a module summary index for each file
; RUN: opt -module-summary %s -o %t.o
; RUN: opt -module-summary %p/Inputs/thinlto_emit_linked_objects.ll -o %t2.o
; Next do the ThinLink step, specifying thinlto-index-only so that the gold
; plugin exits after generating individual indexes. The objects the linker
; decided to include in the link should be emitted into the file specified
; after 'thinlto-index-only='. Note that in this test both files should
; be included in the link, but in a case where there was an object in
; a library that had no strongly referenced symbols, that file would not
; be included in the link and listed in the emitted file. However, this
; requires gold version 1.12.
; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so \
; RUN: --plugin-opt=thinlto \
; RUN: --plugin-opt=thinlto-index-only=%t3 \
; RUN: -o %t5 \
; RUN: %t.o \
; RUN: --start-lib %t2.o --end-lib
; Do the same check for a thin archive (note that non-thin archives don't play
; well with thinlto-index-only because we need to have an object file to
; import from in the distributed ThinLTO backends).
; RUN: llvm-ar Tr %t2.a %t2.o
; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so \
; RUN: --plugin-opt=thinlto \
; RUN: --plugin-opt=thinlto-index-only=%t4 \
; RUN: -o %t5 \
; RUN: %t.o \
; RUN: %t2.a
; RUN: cat %t3 | FileCheck %s
; RUN: cat %t4 | FileCheck %s
; CHECK: thinlto_emit_linked_objects.ll.tmp.o
; CHECK: thinlto_emit_linked_objects.ll.tmp2.o
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
define i32 @main() {
entry:
call void (...) @foo()
ret i32 0
}
declare void @foo(...)

View File

@ -188,6 +188,16 @@ namespace options {
// the import decisions, and exit afterwards. The assumption is // the import decisions, and exit afterwards. The assumption is
// that the build system will launch the backend processes. // that the build system will launch the backend processes.
static bool thinlto_index_only = false; static bool thinlto_index_only = false;
// If non-empty, holds the name of a file in which to write the list of
// oject files gold selected for inclusion in the link after symbol
// resolution (i.e. they had selected symbols). This will only be non-empty
// in the thinlto_index_only case. It is used to identify files, which may
// have originally been within archive libraries specified via
// --start-lib/--end-lib pairs, that should be included in the final
// native link process (since intervening function importing and inlining
// may change the symbol resolution detected in the final link and which
// files to include out of --start-lib/--end-lib libraries as a result).
static std::string thinlto_linked_objects_file;
// If true, when generating individual index files for distributed backends, // If true, when generating individual index files for distributed backends,
// also generate a "${bitcodefile}.imports" file at the same location for each // also generate a "${bitcodefile}.imports" file at the same location for each
// bitcode file, listing the files it imports from in plain text. This is to // bitcode file, listing the files it imports from in plain text. This is to
@ -233,6 +243,9 @@ namespace options {
thinlto = true; thinlto = true;
} else if (opt == "thinlto-index-only") { } else if (opt == "thinlto-index-only") {
thinlto_index_only = true; thinlto_index_only = true;
} else if (opt.startswith("thinlto-index-only=")) {
thinlto_index_only = true;
thinlto_linked_objects_file = opt.substr(strlen("thinlto-index-only="));
} else if (opt == "thinlto-emit-imports-files") { } else if (opt == "thinlto-emit-imports-files") {
thinlto_emit_imports_files = true; thinlto_emit_imports_files = true;
} else if (opt.startswith("thinlto-prefix-replace=")) { } else if (opt.startswith("thinlto-prefix-replace=")) {
@ -1409,6 +1422,18 @@ static ld_plugin_status thinLTOLink(raw_fd_ostream *ApiFile) {
std::string OldPrefix, NewPrefix; std::string OldPrefix, NewPrefix;
getThinLTOOldAndNewPrefix(OldPrefix, NewPrefix); getThinLTOOldAndNewPrefix(OldPrefix, NewPrefix);
// If the user requested a list of objects gold included in the link,
// create and open the requested file.
raw_fd_ostream *ObjFileOS = nullptr;
if (!options::thinlto_linked_objects_file.empty()) {
std::error_code EC;
ObjFileOS = new raw_fd_ostream(options::thinlto_linked_objects_file, EC,
sys::fs::OpenFlags::F_None);
if (EC)
message(LDPL_FATAL, "Unable to open %s for writing: %s",
options::thinlto_linked_objects_file.c_str(),
EC.message().c_str());
}
// For each input bitcode file, generate an individual index that // For each input bitcode file, generate an individual index that
// contains summaries only for its own global values, and for any that // contains summaries only for its own global values, and for any that
// should be imported. // should be imported.
@ -1417,6 +1442,18 @@ static ld_plugin_status thinLTOLink(raw_fd_ostream *ApiFile) {
std::string NewModulePath = std::string NewModulePath =
getThinLTOOutputFile(F.name, OldPrefix, NewPrefix); getThinLTOOutputFile(F.name, OldPrefix, NewPrefix);
if (!options::thinlto_linked_objects_file.empty()) {
// If gold included any symbols from ths file in the link, emit path
// to the final object file, which should be included in the final
// native link.
if (get_symbols(F.handle, F.syms.size(), F.syms.data()) !=
LDPS_NO_SYMS) {
assert(ObjFileOS);
*ObjFileOS << NewModulePath << "\n";
}
}
raw_fd_ostream OS((Twine(NewModulePath) + ".thinlto.bc").str(), EC, raw_fd_ostream OS((Twine(NewModulePath) + ".thinlto.bc").str(), EC,
sys::fs::OpenFlags::F_None); sys::fs::OpenFlags::F_None);
if (EC) if (EC)
@ -1438,6 +1475,9 @@ static ld_plugin_status thinLTOLink(raw_fd_ostream *ApiFile) {
} }
} }
if (ObjFileOS)
ObjFileOS->close();
cleanup_hook(); cleanup_hook();
exit(0); exit(0);
} }