#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
#include "llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h"
#include "llvm/ExecutionEngine/Orc/ThreadSafeModule.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/raw_ostream.h"
#include "../ExampleModules.h"
#include "RemoteJITUtils.h"
#include <memory>
#include <string>
using namespace llvm;
using namespace llvm::orc;
static cl::list<std::string> InputFiles(cl::Positional, cl::OneOrMore,
cl::desc("<input files>"));
static cl::list<std::string> InputArgv("args", cl::Positional,
cl::desc("<program arguments>..."),
cl::PositionalEatsArgs);
static cl::list<std::string>
Dylibs("dlopen", cl::desc("Dynamic libraries to load before linking"),
cl::value_desc("filename"));
static cl::opt<std::string>
OOPExecutor("executor", cl::desc("Set the out-of-process executor"),
cl::value_desc("filename"));
static cl::opt<std::string> OOPExecutorConnectTCP(
"connect",
cl::desc("Connect to an out-of-process executor through a TCP socket"),
cl::value_desc("<hostname>:<port>"));
static cl::opt<bool>
WaitForDebugger("wait-for-debugger",
cl::desc("Wait for user input before entering JITed code"),
cl::init(false));
ExitOnError ExitOnErr;
int main(int argc, char *argv[]) {
InitLLVM X(argc, argv);
InitializeNativeTarget();
InitializeNativeTargetAsmPrinter();
ExitOnErr.setBanner(std::string(argv[0]) + ": ");
cl::ParseCommandLineOptions(argc, argv, "LLJITWithRemoteDebugging");
std::unique_ptr<SimpleRemoteEPC> EPC;
if (OOPExecutorConnectTCP.getNumOccurrences() > 0) {
EPC = ExitOnErr(connectTCPSocket(OOPExecutorConnectTCP));
outs() << "Connected to executor at " << OOPExecutorConnectTCP << "\n";
} else {
std::string Path =
OOPExecutor.empty() ? findLocalExecutor(argv[0]) : OOPExecutor;
outs() << "Found out-of-process executor: " << Path << "\n";
uint64_t PID;
std::tie(EPC, PID) = ExitOnErr(launchLocalExecutor(Path));
outs() << "Launched executor in subprocess: " << PID << "\n";
}
if (WaitForDebugger) {
outs() << "Attach a debugger and press any key to continue.\n";
fflush(stdin);
getchar();
}
std::vector<ThreadSafeModule> TSMs;
for (const std::string &Path : InputFiles) {
outs() << "Parsing input IR code from: " << Path << "\n";
TSMs.push_back(ExitOnErr(parseExampleModuleFromFile(Path)));
}
StringRef TT;
StringRef MainModuleName;
TSMs.front().withModuleDo([&MainModuleName, &TT](Module &M) {
MainModuleName = M.getName();
TT = M.getTargetTriple();
});
for (const ThreadSafeModule &TSM : TSMs)
ExitOnErr(TSM.withModuleDo([TT, MainModuleName](Module &M) -> Error {
if (M.getTargetTriple() != TT)
return make_error<StringError>(
formatv("Different target triples in input files:\n"
" '{0}' in '{1}'\n '{2}' in '{3}'",
TT, MainModuleName, M.getTargetTriple(), M.getName()),
inconvertibleErrorCode());
return Error::success();
}));
JITTargetMachineBuilder JTMB((Triple(TT)));
JTMB.setCodeModel(CodeModel::Small);
JTMB.setRelocationModel(Reloc::PIC_);
outs() << "Initializing LLJIT for remote executor\n";
auto J = ExitOnErr(LLJITBuilder()
.setExecutorProcessControl(std::move(EPC))
.setJITTargetMachineBuilder(std::move(JTMB))
.setObjectLinkingLayerCreator([&](auto &ES, const auto &TT) {
return std::make_unique<ObjectLinkingLayer>(ES);
})
.create());
ExitOnErr(addDebugSupport(J->getObjLinkingLayer()));
for (const std::string &Path : Dylibs)
J->getMainJITDylib().addGenerator(
ExitOnErr(loadDylib(J->getExecutionSession(), Path)));
for (ThreadSafeModule &TSM : TSMs)
ExitOnErr(J->addIRModule(std::move(TSM)));
auto MainAddr = ExitOnErr(J->lookup("main"));
outs() << "Running: main(";
int Pos = 0;
std::vector<std::string> ActualArgv{"LLJITWithRemoteDebugging"};
for (const std::string &Arg : InputArgv) {
outs() << (Pos++ == 0 ? "" : ", ") << "\"" << Arg << "\"";
ActualArgv.push_back(Arg);
}
outs() << ")\n";
{
ExecutorProcessControl &EPC =
J->getExecutionSession().getExecutorProcessControl();
int Result = ExitOnErr(EPC.runAsMain(MainAddr, ActualArgv));
outs() << "Exit code: " << Result << "\n";
}
return 0;
}