aboutsummaryrefslogtreecommitdiff
path: root/tools/gold/gold-plugin.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/gold/gold-plugin.cpp')
-rw-r--r--tools/gold/gold-plugin.cpp99
1 files changed, 78 insertions, 21 deletions
diff --git a/tools/gold/gold-plugin.cpp b/tools/gold/gold-plugin.cpp
index 50e102b04595..9b783d19a283 100644
--- a/tools/gold/gold-plugin.cpp
+++ b/tools/gold/gold-plugin.cpp
@@ -12,6 +12,7 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/ADT/Statistic.h"
#include "llvm/Bitcode/BitcodeReader.h"
#include "llvm/Bitcode/BitcodeWriter.h"
#include "llvm/CodeGen/CommandFlags.h"
@@ -20,7 +21,9 @@
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/LTO/Caching.h"
#include "llvm/LTO/LTO.h"
+#include "llvm/Object/Error.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
@@ -105,8 +108,6 @@ static std::list<claimed_file> Modules;
static DenseMap<int, void *> FDToLeaderHandle;
static StringMap<ResolutionInfo> ResInfo;
static std::vector<std::string> Cleanup;
-static llvm::TargetOptions TargetOpts;
-static size_t MaxTasks;
namespace options {
enum OutputType {
@@ -165,6 +166,12 @@ namespace options {
// corresponding bitcode file, will use a path formed by replacing the
// bitcode file's path prefix matching oldprefix with newprefix.
static std::string thinlto_prefix_replace;
+ // Option to control the name of modules encoded in the individual index
+ // files for a distributed backend. This enables the use of minimized
+ // bitcode files for the thin link, assuming the name of the full bitcode
+ // file used in the backend differs just in some part of the file suffix.
+ // If specified, expects a string of the form "oldsuffix:newsuffix".
+ static std::string thinlto_object_suffix_replace;
// Optional path to a directory for caching ThinLTO objects.
static std::string cache_dir;
// Additional options to pass into the code generator.
@@ -207,6 +214,12 @@ namespace options {
thinlto_prefix_replace = opt.substr(strlen("thinlto-prefix-replace="));
if (thinlto_prefix_replace.find(';') == std::string::npos)
message(LDPL_FATAL, "thinlto-prefix-replace expects 'old;new' format");
+ } else if (opt.startswith("thinlto-object-suffix-replace=")) {
+ thinlto_object_suffix_replace =
+ opt.substr(strlen("thinlto-object-suffix-replace="));
+ if (thinlto_object_suffix_replace.find(';') == std::string::npos)
+ message(LDPL_FATAL,
+ "thinlto-object-suffix-replace expects 'old;new' format");
} else if (opt.startswith("cache-dir=")) {
cache_dir = opt.substr(strlen("cache-dir="));
} else if (opt.size() == 2 && opt[0] == 'O') {
@@ -452,7 +465,7 @@ static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file,
EC == object::object_error::bitcode_section_not_found)
*claimed = 0;
else
- message(LDPL_ERROR,
+ message(LDPL_FATAL,
"LLVM gold plugin has failed to create LTO module: %s",
EI.message().c_str());
});
@@ -485,8 +498,6 @@ static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file,
sys::path::filename(Obj->getSourceFileName()).str();
for (auto &Sym : Obj->symbols()) {
- uint32_t Symflags = Sym.getFlags();
-
cf.syms.push_back(ld_plugin_symbol());
ld_plugin_symbol &sym = cf.syms.back();
sym.version = nullptr;
@@ -512,20 +523,20 @@ static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file,
break;
}
- if (Symflags & object::BasicSymbolRef::SF_Undefined) {
+ if (Sym.isUndefined()) {
sym.def = LDPK_UNDEF;
- if (Symflags & object::BasicSymbolRef::SF_Weak)
+ if (Sym.isWeak())
sym.def = LDPK_WEAKUNDEF;
- } else if (Symflags & object::BasicSymbolRef::SF_Common)
+ } else if (Sym.isCommon())
sym.def = LDPK_COMMON;
- else if (Symflags & object::BasicSymbolRef::SF_Weak)
+ else if (Sym.isWeak())
sym.def = LDPK_WEAKDEF;
else
sym.def = LDPK_DEF;
sym.size = 0;
sym.comdat_key = nullptr;
- int CI = check(Sym.getComdatIndex());
+ int CI = Sym.getComdatIndex();
if (CI != -1) {
StringRef C = Obj->getComdatTable()[CI];
sym.comdat_key = strdup(C.str().c_str());
@@ -567,8 +578,35 @@ static const void *getSymbolsAndView(claimed_file &F) {
return View;
}
-static void addModule(LTO &Lto, claimed_file &F, const void *View) {
- MemoryBufferRef BufferRef(StringRef((const char *)View, F.filesize), F.name);
+/// Parse the thinlto-object-suffix-replace option into the \p OldSuffix and
+/// \p NewSuffix strings, if it was specified.
+static void getThinLTOOldAndNewSuffix(std::string &OldSuffix,
+ std::string &NewSuffix) {
+ assert(options::thinlto_object_suffix_replace.empty() ||
+ options::thinlto_object_suffix_replace.find(";") != StringRef::npos);
+ StringRef SuffixReplace = options::thinlto_object_suffix_replace;
+ std::pair<StringRef, StringRef> Split = SuffixReplace.split(";");
+ OldSuffix = Split.first.str();
+ NewSuffix = Split.second.str();
+}
+
+/// Given the original \p Path to an output file, replace any filename
+/// suffix matching \p OldSuffix with \p NewSuffix.
+static std::string getThinLTOObjectFileName(const std::string Path,
+ const std::string &OldSuffix,
+ const std::string &NewSuffix) {
+ if (OldSuffix.empty() && NewSuffix.empty())
+ return Path;
+ StringRef NewPath = Path;
+ NewPath.consume_back(OldSuffix);
+ std::string NewNewPath = NewPath.str() + NewSuffix;
+ return NewPath.str() + NewSuffix;
+}
+
+static void addModule(LTO &Lto, claimed_file &F, const void *View,
+ StringRef Filename) {
+ MemoryBufferRef BufferRef(StringRef((const char *)View, F.filesize),
+ Filename);
Expected<std::unique_ptr<InputFile>> ObjOrErr = InputFile::create(BufferRef);
if (!ObjOrErr)
@@ -637,7 +675,7 @@ static void recordFile(std::string Filename, bool TempOutFile) {
/// indicating whether a temp file should be generated, and an optional task id.
/// The new filename generated is returned in \p NewFilename.
static void getOutputFileName(SmallString<128> InFilename, bool TempOutFile,
- SmallString<128> &NewFilename, int TaskID = -1) {
+ SmallString<128> &NewFilename, int TaskID) {
if (TempOutFile) {
std::error_code EC =
sys::fs::createTemporaryFile("lto-llvm", "o", NewFilename);
@@ -646,7 +684,7 @@ static void getOutputFileName(SmallString<128> InFilename, bool TempOutFile,
EC.message().c_str());
} else {
NewFilename = InFilename;
- if (TaskID >= 0)
+ if (TaskID > 0)
NewFilename += utostr(TaskID);
}
}
@@ -790,19 +828,31 @@ static ld_plugin_status allSymbolsReadHook() {
if (options::thinlto_index_only)
getThinLTOOldAndNewPrefix(OldPrefix, NewPrefix);
+ std::string OldSuffix, NewSuffix;
+ getThinLTOOldAndNewSuffix(OldSuffix, NewSuffix);
+ // Set for owning string objects used as buffer identifiers.
+ StringSet<> ObjectFilenames;
+
for (claimed_file &F : Modules) {
if (options::thinlto && !HandleToInputFile.count(F.leader_handle))
HandleToInputFile.insert(std::make_pair(
F.leader_handle, llvm::make_unique<PluginInputFile>(F.handle)));
const void *View = getSymbolsAndView(F);
+ // In case we are thin linking with a minimized bitcode file, ensure
+ // the module paths encoded in the index reflect where the backends
+ // will locate the full bitcode files for compiling/importing.
+ std::string Identifier =
+ getThinLTOObjectFileName(F.name, OldSuffix, NewSuffix);
+ auto ObjFilename = ObjectFilenames.insert(Identifier);
+ assert(ObjFilename.second);
if (!View) {
if (options::thinlto_index_only)
// Write empty output files that may be expected by the distributed
// build system.
- writeEmptyDistributedBuildOutputs(F.name, OldPrefix, NewPrefix);
+ writeEmptyDistributedBuildOutputs(Identifier, OldPrefix, NewPrefix);
continue;
}
- addModule(*Lto, F, View);
+ addModule(*Lto, F, View, ObjFilename.first->first());
}
SmallString<128> Filename;
@@ -813,7 +863,7 @@ static ld_plugin_status allSymbolsReadHook() {
Filename = output_name + ".o";
bool SaveTemps = !Filename.empty();
- MaxTasks = Lto->getMaxTasks();
+ size_t MaxTasks = Lto->getMaxTasks();
std::vector<uintptr_t> IsTemporary(MaxTasks);
std::vector<SmallString<128>> Filenames(MaxTasks);
@@ -821,21 +871,26 @@ static ld_plugin_status allSymbolsReadHook() {
[&](size_t Task) -> std::unique_ptr<lto::NativeObjectStream> {
IsTemporary[Task] = !SaveTemps;
getOutputFileName(Filename, /*TempOutFile=*/!SaveTemps, Filenames[Task],
- MaxTasks > 1 ? Task : -1);
+ Task);
int FD;
std::error_code EC =
sys::fs::openFileForWrite(Filenames[Task], FD, sys::fs::F_None);
if (EC)
- message(LDPL_FATAL, "Could not open file: %s", EC.message().c_str());
+ message(LDPL_FATAL, "Could not open file %s: %s", Filenames[Task].c_str(),
+ EC.message().c_str());
return llvm::make_unique<lto::NativeObjectStream>(
llvm::make_unique<llvm::raw_fd_ostream>(FD, true));
};
- auto AddFile = [&](size_t Task, StringRef Path) { Filenames[Task] = Path; };
+ auto AddBuffer = [&](size_t Task, std::unique_ptr<MemoryBuffer> MB) {
+ // Note that this requires that the memory buffers provided to AddBuffer are
+ // backed by a file.
+ Filenames[Task] = MB->getBufferIdentifier();
+ };
NativeObjectCache Cache;
if (!options::cache_dir.empty())
- Cache = localCache(options::cache_dir, AddFile);
+ Cache = check(localCache(options::cache_dir, AddBuffer));
check(Lto->run(AddStream, Cache));
@@ -844,6 +899,8 @@ static ld_plugin_status allSymbolsReadHook() {
return LDPS_OK;
if (options::thinlto_index_only) {
+ if (llvm::AreStatisticsEnabled())
+ llvm::PrintStatistics();
cleanup_hook();
exit(0);
}