Stefan Gränitz 30c4561e36 [ORC] Add JITLink-compatible remote memory-manager and LLJITWithChildProcess example
This adds RemoteJITLinkMemoryManager is a new subclass of OrcRemoteTargetClient. It implements jitlink::JITLinkMemoryManager and targets the OrcRemoteTargetRPCAPI.

Behavior should be very similar to RemoteRTDyldMemoryManager. The essential differnce with JITLink is that allocations work in isolation from its memory manager. Thus, the RemoteJITLinkMemoryManager might be seen as "JITLink allocation factory".

RPCMMAlloc is another subclass of OrcRemoteTargetClient and implements the actual functionality. It allocates working memory on the host and target memory on the remote target. Upon finalization working memory is copied over to the tagrte address space. Finalization can be asynchronous for JITLink allocations, but I don't see that it makes a difference here.

Differential Revision: https://reviews.llvm.org/D85919
2020-08-14 11:34:44 +02:00

129 lines
4.2 KiB
C++

//===--- LLJITWithLazyReexports.cpp - LLJIT example with custom laziness --===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// In this example we will execute JITed code in a child process:
//
// 1. Launch a remote process.
// 2. Create a JITLink-compatible remote memory manager.
// 3. Use LLJITBuilder to create a (greedy) LLJIT instance.
// 4. Add the Add1Example module and execute add1().
// 5. Terminate the remote target session.
//
//===----------------------------------------------------------------------===//
#include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
#include "llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Error.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>
#define DEBUG_TYPE "orc"
using namespace llvm;
using namespace llvm::orc;
// Executable running in the child process for remote execution. It communicates
// via stdin/stdout pipes.
cl::opt<std::string>
ChildExecPath("remote-process", cl::Required,
cl::desc("Specify the filename of the process to launch for "
"remote JITing."),
cl::value_desc("filename"));
int main(int argc, char *argv[]) {
InitLLVM X(argc, argv);
InitializeNativeTarget();
InitializeNativeTargetAsmPrinter();
cl::ParseCommandLineOptions(argc, argv, "LLJITWithChildProcess");
ExitOnError ExitOnErr;
ExitOnErr.setBanner(std::string(argv[0]) + ": ");
if (!sys::fs::can_execute(ChildExecPath)) {
WithColor::error(errs(), argv[0])
<< "Child executable invalid: '" << ChildExecPath << "'\n";
return -1;
}
ExecutionSession ES;
ES.setErrorReporter([&](Error Err) { ExitOnErr(std::move(Err)); });
// Launch the remote process and get a channel to it.
pid_t ChildPID;
std::unique_ptr<FDRawChannel> Ch = launchRemote(ChildExecPath, ChildPID);
if (!Ch) {
WithColor::error(errs(), argv[0]) << "Failed to launch remote JIT.\n";
exit(1);
}
LLVM_DEBUG({
dbgs()
<< "Launched executable in subprocess " << ChildPID << ":\n"
<< ChildExecPath << "\n\n"
<< "You may want to attach a debugger now. Press enter to continue.\n";
fflush(stdin);
getchar();
});
std::unique_ptr<remote::OrcRemoteTargetClient> Client =
ExitOnErr(remote::OrcRemoteTargetClient::Create(*Ch, ES));
// Create a JITLink-compatible remote memory manager.
using MemManager = remote::OrcRemoteTargetClient::RemoteJITLinkMemoryManager;
std::unique_ptr<MemManager> RemoteMM =
ExitOnErr(Client->createRemoteJITLinkMemoryManager());
// Our remote target is running on the host system.
auto JTMB = ExitOnErr(JITTargetMachineBuilder::detectHost());
JTMB.setCodeModel(CodeModel::Small);
// Create an LLJIT instance with a JITLink ObjectLinkingLayer.
auto J = ExitOnErr(
LLJITBuilder()
.setJITTargetMachineBuilder(std::move(JTMB))
.setObjectLinkingLayerCreator(
[&](ExecutionSession &ES,
const Triple &TT) -> std::unique_ptr<ObjectLayer> {
return std::make_unique<ObjectLinkingLayer>(ES, *RemoteMM);
})
.create());
auto M = ExitOnErr(parseExampleModule(Add1Example, "add1"));
ExitOnErr(J->addIRModule(std::move(M)));
// Look up the JIT'd function.
auto Add1Sym = ExitOnErr(J->lookup("add1"));
// Run in child target.
Expected<int> Result = Client->callIntInt(Add1Sym.getAddress(), 42);
if (Result)
outs() << "add1(42) = " << *Result << "\n";
else
ES.reportError(Result.takeError());
// Signal the remote target that we're done JITing.
ExitOnErr(Client->terminateSession());
LLVM_DEBUG(dbgs() << "Subprocess terminated\n");
return 0;
}