diff options
Diffstat (limited to 'contrib/llvm/tools/lli/lli.cpp')
-rw-r--r-- | contrib/llvm/tools/lli/lli.cpp | 184 |
1 files changed, 129 insertions, 55 deletions
diff --git a/contrib/llvm/tools/lli/lli.cpp b/contrib/llvm/tools/lli/lli.cpp index 057841f..67e7cbd 100644 --- a/contrib/llvm/tools/lli/lli.cpp +++ b/contrib/llvm/tools/lli/lli.cpp @@ -13,11 +13,9 @@ // //===----------------------------------------------------------------------===// -#include "llvm/IR/LLVMContext.h" #include "OrcLazyJIT.h" -#include "RemoteMemoryManager.h" -#include "RemoteTarget.h" -#include "RemoteTargetExternal.h" +#include "RemoteJITUtils.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/ADT/Triple.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/CodeGen/LinkAllCodegenComponents.h" @@ -28,6 +26,7 @@ #include "llvm/ExecutionEngine/ObjectCache.h" #include "llvm/ExecutionEngine/OrcMCJITReplacement.h" #include "llvm/ExecutionEngine/SectionMemoryManager.h" +#include "llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Module.h" #include "llvm/IR/Type.h" @@ -262,8 +261,7 @@ public: if (!getCacheFilename(ModuleID, CacheName)) return; if (!CacheDir.empty()) { // Create user-defined cache dir. - SmallString<128> dir(CacheName); - sys::path::remove_filename(dir); + SmallString<128> dir(sys::path::parent_path(CacheName)); sys::fs::create_directories(Twine(dir)); } std::error_code EC; @@ -422,7 +420,7 @@ int main(int argc, char **argv, char * const *envp) { // If not jitting lazily, load the whole bitcode file eagerly too. if (NoLazyCompilation) { - if (std::error_code EC = Mod->materializeAllPermanently()) { + if (std::error_code EC = Mod->materializeAll()) { errs() << argv[0] << ": bitcode didn't read correctly.\n"; errs() << "Reason: " << EC.message() << "\n"; exit(1); @@ -450,7 +448,7 @@ int main(int argc, char **argv, char * const *envp) { RTDyldMemoryManager *RTDyldMM = nullptr; if (!ForceInterpreter) { if (RemoteMCJIT) - RTDyldMM = new RemoteMemoryManager(); + RTDyldMM = new ForwardingMemoryManager(); else RTDyldMM = new SectionMemoryManager(); @@ -583,6 +581,25 @@ int main(int argc, char **argv, char * const *envp) { int Result; + // Sanity check use of remote-jit: LLI currently only supports use of the + // remote JIT on Unix platforms. + if (RemoteMCJIT) { +#ifndef LLVM_ON_UNIX + errs() << "Warning: host does not support external remote targets.\n" + << " Defaulting to local execution execution\n"; + return -1; +#else + if (ChildExecPath.empty()) { + errs() << "-remote-mcjit requires -mcjit-remote-process.\n"; + exit(1); + } else if (!sys::fs::can_execute(ChildExecPath)) { + errs() << "Unable to find usable child executable: '" << ChildExecPath + << "'\n"; + return -1; + } +#endif + } + if (!RemoteMCJIT) { // If the program doesn't explicitly call exit, we will need the Exit // function later on to make an explicit call, so get the function now. @@ -630,66 +647,123 @@ int main(int argc, char **argv, char * const *envp) { // Remote target MCJIT doesn't (yet) support static constructors. No reason // it couldn't. This is a limitation of the LLI implemantation, not the // MCJIT itself. FIXME. - // - RemoteMemoryManager *MM = static_cast<RemoteMemoryManager*>(RTDyldMM); - // Everything is prepared now, so lay out our program for the target - // address space, assign the section addresses to resolve any relocations, - // and send it to the target. - - std::unique_ptr<RemoteTarget> Target; - if (!ChildExecPath.empty()) { // Remote execution on a child process -#ifndef LLVM_ON_UNIX - // FIXME: Remove this pointless fallback mode which causes tests to "pass" - // on platforms where they should XFAIL. - errs() << "Warning: host does not support external remote targets.\n" - << " Defaulting to simulated remote execution\n"; - Target.reset(new RemoteTarget); -#else - if (!sys::fs::can_execute(ChildExecPath)) { - errs() << "Unable to find usable child executable: '" << ChildExecPath - << "'\n"; - return -1; - } - Target.reset(new RemoteTargetExternal(ChildExecPath)); -#endif - } else { - // No child process name provided, use simulated remote execution. - Target.reset(new RemoteTarget); + + // Lanch the remote process and get a channel to it. + std::unique_ptr<FDRPCChannel> C = launchRemote(); + if (!C) { + errs() << "Failed to launch remote JIT.\n"; + exit(1); } - // Give the memory manager a pointer to our remote target interface object. - MM->setRemoteTarget(Target.get()); + // Create a remote target client running over the channel. + typedef orc::remote::OrcRemoteTargetClient<orc::remote::RPCChannel> MyRemote; + ErrorOr<MyRemote> R = MyRemote::Create(*C); + if (!R) { + errs() << "Could not create remote: " << R.getError().message() << "\n"; + exit(1); + } - // Create the remote target. - if (!Target->create()) { - errs() << "ERROR: " << Target->getErrorMsg() << "\n"; - return EXIT_FAILURE; + // Create a remote memory manager. + std::unique_ptr<MyRemote::RCMemoryManager> RemoteMM; + if (auto EC = R->createRemoteMemoryManager(RemoteMM)) { + errs() << "Could not create remote memory manager: " << EC.message() << "\n"; + exit(1); } - // Since we're executing in a (at least simulated) remote address space, - // we can't use the ExecutionEngine::runFunctionAsMain(). We have to - // grab the function address directly here and tell the remote target - // to execute the function. - // - // Our memory manager will map generated code into the remote address - // space as it is loaded and copy the bits over during the finalizeMemory - // operation. - // + // Forward MCJIT's memory manager calls to the remote memory manager. + static_cast<ForwardingMemoryManager*>(RTDyldMM)->setMemMgr( + std::move(RemoteMM)); + + // Forward MCJIT's symbol resolution calls to the remote. + static_cast<ForwardingMemoryManager*>(RTDyldMM)->setResolver( + orc::createLambdaResolver( + [&](const std::string &Name) { + orc::TargetAddress Addr = 0; + if (auto EC = R->getSymbolAddress(Addr, Name)) { + errs() << "Failure during symbol lookup: " << EC.message() << "\n"; + exit(1); + } + return RuntimeDyld::SymbolInfo(Addr, JITSymbolFlags::Exported); + }, + [](const std::string &Name) { return nullptr; } + )); + + // Grab the target address of the JIT'd main function on the remote and call + // it. // FIXME: argv and envp handling. - uint64_t Entry = EE->getFunctionAddress(EntryFn->getName().str()); - + orc::TargetAddress Entry = EE->getFunctionAddress(EntryFn->getName().str()); + EE->finalizeObject(); DEBUG(dbgs() << "Executing '" << EntryFn->getName() << "' at 0x" << format("%llx", Entry) << "\n"); - - if (!Target->executeCode(Entry, Result)) - errs() << "ERROR: " << Target->getErrorMsg() << "\n"; + if (auto EC = R->callIntVoid(Result, Entry)) + errs() << "ERROR: " << EC.message() << "\n"; // Like static constructors, the remote target MCJIT support doesn't handle // this yet. It could. FIXME. - // Stop the remote target - Target->stop(); + // Delete the EE - we need to tear it down *before* we terminate the session + // with the remote, otherwise it'll crash when it tries to release resources + // on a remote that has already been disconnected. + delete EE; + EE = nullptr; + + // Signal the remote target that we're done JITing. + R->terminateSession(); } return Result; } + +std::unique_ptr<FDRPCChannel> launchRemote() { +#ifndef LLVM_ON_UNIX + llvm_unreachable("launchRemote not supported on non-Unix platforms"); +#else + int PipeFD[2][2]; + pid_t ChildPID; + + // Create two pipes. + if (pipe(PipeFD[0]) != 0 || pipe(PipeFD[1]) != 0) + perror("Error creating pipe: "); + + ChildPID = fork(); + + if (ChildPID == 0) { + // In the child... + + // Close the parent ends of the pipes + close(PipeFD[0][1]); + close(PipeFD[1][0]); + + + // Execute the child process. + std::unique_ptr<char[]> ChildPath, ChildIn, ChildOut; + { + ChildPath.reset(new char[ChildExecPath.size() + 1]); + std::copy(ChildExecPath.begin(), ChildExecPath.end(), &ChildPath[0]); + ChildPath[ChildExecPath.size()] = '\0'; + std::string ChildInStr = std::to_string(PipeFD[0][0]); + ChildIn.reset(new char[ChildInStr.size() + 1]); + std::copy(ChildInStr.begin(), ChildInStr.end(), &ChildIn[0]); + ChildIn[ChildInStr.size()] = '\0'; + std::string ChildOutStr = std::to_string(PipeFD[1][1]); + ChildOut.reset(new char[ChildOutStr.size() + 1]); + std::copy(ChildOutStr.begin(), ChildOutStr.end(), &ChildOut[0]); + ChildOut[ChildOutStr.size()] = '\0'; + } + + char * const args[] = { &ChildPath[0], &ChildIn[0], &ChildOut[0], nullptr }; + int rc = execv(ChildExecPath.c_str(), args); + if (rc != 0) + perror("Error executing child process: "); + llvm_unreachable("Error executing child process"); + } + // else we're the parent... + + // Close the child ends of the pipes + close(PipeFD[0][0]); + close(PipeFD[1][1]); + + // Return an RPC channel connected to our end of the pipes. + return llvm::make_unique<FDRPCChannel>(PipeFD[1][0], PipeFD[0][1]); +#endif +} |