diff --git a/test/tools/gold/X86/Inputs/thinlto_emit_linked_objects.ll b/test/tools/gold/X86/Inputs/thinlto_emit_linked_objects.ll new file mode 100644 index 00000000000..c6c2046b31a --- /dev/null +++ b/test/tools/gold/X86/Inputs/thinlto_emit_linked_objects.ll @@ -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 +} diff --git a/test/tools/gold/X86/thinlto_emit_linked_objects.ll b/test/tools/gold/X86/thinlto_emit_linked_objects.ll new file mode 100644 index 00000000000..0b099063c0d --- /dev/null +++ b/test/tools/gold/X86/thinlto_emit_linked_objects.ll @@ -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(...) diff --git a/tools/gold/gold-plugin.cpp b/tools/gold/gold-plugin.cpp index e3351c29fcd..c8b02e6fa14 100644 --- a/tools/gold/gold-plugin.cpp +++ b/tools/gold/gold-plugin.cpp @@ -188,6 +188,16 @@ namespace options { // the import decisions, and exit afterwards. The assumption is // that the build system will launch the backend processes. 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, // 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 @@ -233,6 +243,9 @@ namespace options { thinlto = true; } else if (opt == "thinlto-index-only") { 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") { thinlto_emit_imports_files = true; } else if (opt.startswith("thinlto-prefix-replace=")) { @@ -1409,6 +1422,18 @@ static ld_plugin_status thinLTOLink(raw_fd_ostream *ApiFile) { std::string 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 // contains summaries only for its own global values, and for any that // should be imported. @@ -1417,6 +1442,18 @@ static ld_plugin_status thinLTOLink(raw_fd_ostream *ApiFile) { std::string NewModulePath = 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, sys::fs::OpenFlags::F_None); if (EC) @@ -1438,6 +1475,9 @@ static ld_plugin_status thinLTOLink(raw_fd_ostream *ApiFile) { } } + if (ObjFileOS) + ObjFileOS->close(); + cleanup_hook(); exit(0); }