summaryrefslogtreecommitdiffstats
path: root/llvm/tools/llvm-lto2/llvm-lto2.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/tools/llvm-lto2/llvm-lto2.cpp')
-rw-r--r--llvm/tools/llvm-lto2/llvm-lto2.cpp168
1 files changed, 168 insertions, 0 deletions
diff --git a/llvm/tools/llvm-lto2/llvm-lto2.cpp b/llvm/tools/llvm-lto2/llvm-lto2.cpp
new file mode 100644
index 00000000000..b9300b93990
--- /dev/null
+++ b/llvm/tools/llvm-lto2/llvm-lto2.cpp
@@ -0,0 +1,168 @@
+//===-- llvm-lto2: test harness for the resolution-based LTO interface ----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This program takes in a list of bitcode files, links them and performs
+// link-time optimization according to the provided symbol resolutions using the
+// resolution-based LTO interface, and outputs one or more object files.
+//
+// This program is intended to eventually replace llvm-lto which uses the legacy
+// LTO interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/LTO/LTO.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/TargetSelect.h"
+
+using namespace llvm;
+using namespace lto;
+using namespace object;
+
+static cl::list<std::string> InputFilenames(cl::Positional, cl::OneOrMore,
+ cl::desc("<input bitcode files>"));
+
+static cl::opt<std::string> OutputFilename("o", cl::Required,
+ cl::desc("Output filename"),
+ cl::value_desc("filename"));
+
+static cl::opt<bool> SaveTemps("save-temps", cl::desc("Save temporary files"));
+
+static cl::list<std::string> SymbolResolutions(
+ "r",
+ cl::desc("Specify a symbol resolution: filename,symbolname,resolution\n"
+ "where \"resolution\" is a sequence (which may be empty) of the\n"
+ "following characters:\n"
+ " p - prevailing: the linker has chosen this definition of the\n"
+ " symbol\n"
+ " l - local: the definition of this symbol is unpreemptable at\n"
+ " runtime and is known to be in this linkage unit\n"
+ " x - externally visible: the definition of this symbol is\n"
+ " visible outside of the LTO unit\n"
+ "A resolution for each symbol must be specified."),
+ cl::ZeroOrMore);
+
+static void check(Error E, std::string Msg) {
+ if (!E)
+ return;
+ handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) {
+ errs() << "llvm-lto: " << Msg << ": " << EIB.message().c_str() << '\n';
+ });
+ exit(1);
+}
+
+template <typename T> static T check(Expected<T> E, std::string Msg) {
+ if (E)
+ return std::move(*E);
+ check(E.takeError(), Msg);
+ return T();
+}
+
+static void check(std::error_code EC, std::string Msg) {
+ check(errorCodeToError(EC), Msg);
+}
+
+template <typename T> static T check(ErrorOr<T> E, std::string Msg) {
+ if (E)
+ return std::move(*E);
+ check(E.getError(), Msg);
+ return T();
+}
+
+int main(int argc, char **argv) {
+ InitializeAllTargets();
+ InitializeAllTargetMCs();
+ InitializeAllAsmPrinters();
+ InitializeAllAsmParsers();
+
+ cl::ParseCommandLineOptions(argc, argv, "Resolution-based LTO test harness");
+
+ std::map<std::pair<std::string, std::string>, SymbolResolution>
+ CommandLineResolutions;
+ for (std::string R : SymbolResolutions) {
+ StringRef Rest = R;
+ StringRef FileName, SymbolName;
+ std::tie(FileName, Rest) = Rest.split(',');
+ if (Rest.empty()) {
+ llvm::errs() << "invalid resolution: " << R << '\n';
+ return 1;
+ }
+ std::tie(SymbolName, Rest) = Rest.split(',');
+ SymbolResolution Res;
+ for (char C : Rest) {
+ if (C == 'p')
+ Res.Prevailing = true;
+ else if (C == 'l')
+ Res.FinalDefinitionInLinkageUnit = true;
+ else if (C == 'x')
+ Res.VisibleToRegularObj = true;
+ else
+ llvm::errs() << "invalid character " << C << " in resolution: " << R
+ << '\n';
+ }
+ CommandLineResolutions[{FileName, SymbolName}] = Res;
+ }
+
+ std::vector<std::unique_ptr<MemoryBuffer>> MBs;
+
+ Config Conf;
+ Conf.DiagHandler = [](const DiagnosticInfo &) {
+ exit(1);
+ };
+
+ if (SaveTemps)
+ check(Conf.addSaveTemps(OutputFilename), "Config::addSaveTemps failed");
+
+ LTO Lto(std::move(Conf));
+
+ bool HasErrors = false;
+ for (std::string F : InputFilenames) {
+ std::unique_ptr<MemoryBuffer> MB = check(MemoryBuffer::getFile(F), F);
+ std::unique_ptr<InputFile> Input =
+ check(InputFile::create(MB->getMemBufferRef()), F);
+
+ std::vector<SymbolResolution> Res;
+ for (const InputFile::Symbol &Sym : Input->symbols()) {
+ auto I = CommandLineResolutions.find({F, Sym.getName()});
+ if (I == CommandLineResolutions.end()) {
+ llvm::errs() << argv[0] << ": missing symbol resolution for " << F
+ << ',' << Sym.getName() << '\n';
+ HasErrors = true;
+ } else {
+ Res.push_back(I->second);
+ CommandLineResolutions.erase(I);
+ }
+ }
+
+ if (HasErrors)
+ continue;
+
+ MBs.push_back(std::move(MB));
+ check(Lto.add(std::move(Input), Res), F);
+ }
+
+ if (!CommandLineResolutions.empty()) {
+ HasErrors = true;
+ for (auto UnusedRes : CommandLineResolutions)
+ llvm::errs() << argv[0] << ": unused symbol resolution for "
+ << UnusedRes.first.first << ',' << UnusedRes.first.second
+ << '\n';
+ }
+ if (HasErrors)
+ return 1;
+
+ auto AddStream = [&](size_t Task) {
+ std::string Path = OutputFilename + "." + utostr(Task);
+ std::error_code EC;
+ auto S = llvm::make_unique<raw_fd_ostream>(Path, EC, sys::fs::F_None);
+ check(EC, Path);
+ return S;
+ };
+
+ check(Lto.run(AddStream), "LTO::run failed");
+}
OpenPOWER on IntegriCloud