[mlir][LLVM] `LLVMTypeConverter`: Tighten materialization checks (#116532)
[llvm-project.git] / llvm / examples / OrcV2Examples / LLJITWithRemoteDebugging / RemoteJITUtils.cpp
blob83c5899852d64f94e085e482bd88190eaf86ea51
1 //===-- RemoteJITUtils.cpp - Utilities for remote-JITing --------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "RemoteJITUtils.h"
11 #include "llvm/ADT/StringExtras.h"
12 #include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h"
13 #include "llvm/ExecutionEngine/Orc/EPCDebugObjectRegistrar.h"
14 #include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"
15 #include "llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h"
16 #include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
17 #include "llvm/Support/FileSystem.h"
18 #include "llvm/Support/Path.h"
20 #ifdef LLVM_ON_UNIX
21 #include <netdb.h>
22 #include <netinet/in.h>
23 #include <sys/socket.h>
24 #include <unistd.h>
25 #endif // LLVM_ON_UNIX
27 using namespace llvm;
28 using namespace llvm::orc;
30 Expected<std::unique_ptr<DefinitionGenerator>>
31 loadDylib(ExecutionSession &ES, StringRef RemotePath) {
32 if (auto Handle = ES.getExecutorProcessControl().getDylibMgr().loadDylib(
33 RemotePath.data()))
34 return std::make_unique<EPCDynamicLibrarySearchGenerator>(ES, *Handle);
35 else
36 return Handle.takeError();
39 static void findLocalExecutorHelper() {}
40 std::string findLocalExecutor(const char *HostArgv0) {
41 // This just needs to be some static symbol in the binary; C++ doesn't
42 // allow taking the address of ::main however.
43 uintptr_t UIntPtr = reinterpret_cast<uintptr_t>(&findLocalExecutorHelper);
44 void *VoidPtr = reinterpret_cast<void *>(UIntPtr);
45 SmallString<256> FullName(sys::fs::getMainExecutable(HostArgv0, VoidPtr));
46 sys::path::remove_filename(FullName);
47 sys::path::append(FullName, "llvm-jitlink-executor");
48 return FullName.str().str();
51 #ifndef LLVM_ON_UNIX
53 // FIXME: Add support for Windows.
54 Expected<std::pair<std::unique_ptr<SimpleRemoteEPC>, uint64_t>>
55 launchLocalExecutor(StringRef ExecutablePath) {
56 return make_error<StringError>(
57 "Remote JITing not yet supported on non-unix platforms",
58 inconvertibleErrorCode());
61 // FIXME: Add support for Windows.
62 Expected<std::unique_ptr<SimpleRemoteEPC>>
63 connectTCPSocket(StringRef NetworkAddress) {
64 return make_error<StringError>(
65 "Remote JITing not yet supported on non-unix platforms",
66 inconvertibleErrorCode());
69 #else
71 Expected<std::pair<std::unique_ptr<SimpleRemoteEPC>, uint64_t>>
72 launchLocalExecutor(StringRef ExecutablePath) {
73 constexpr int ReadEnd = 0;
74 constexpr int WriteEnd = 1;
76 if (!sys::fs::can_execute(ExecutablePath))
77 return make_error<StringError>(
78 formatv("Specified executor invalid: {0}", ExecutablePath),
79 inconvertibleErrorCode());
81 // Pipe FDs.
82 int ToExecutor[2];
83 int FromExecutor[2];
85 // Create pipes to/from the executor..
86 if (pipe(ToExecutor) != 0 || pipe(FromExecutor) != 0)
87 return make_error<StringError>("Unable to create pipe for executor",
88 inconvertibleErrorCode());
90 pid_t ProcessID = fork();
91 if (ProcessID == 0) {
92 // In the child...
94 // Close the parent ends of the pipes
95 close(ToExecutor[WriteEnd]);
96 close(FromExecutor[ReadEnd]);
98 // Execute the child process.
99 std::unique_ptr<char[]> ExecPath, FDSpecifier, TestOutputFlag;
101 ExecPath = std::make_unique<char[]>(ExecutablePath.size() + 1);
102 strcpy(ExecPath.get(), ExecutablePath.data());
104 const char *TestOutputFlagStr = "test-jitloadergdb";
105 TestOutputFlag = std::make_unique<char[]>(strlen(TestOutputFlagStr) + 1);
106 strcpy(TestOutputFlag.get(), TestOutputFlagStr);
108 std::string FDSpecifierStr("filedescs=");
109 FDSpecifierStr += utostr(ToExecutor[ReadEnd]);
110 FDSpecifierStr += ',';
111 FDSpecifierStr += utostr(FromExecutor[WriteEnd]);
112 FDSpecifier = std::make_unique<char[]>(FDSpecifierStr.size() + 1);
113 strcpy(FDSpecifier.get(), FDSpecifierStr.c_str());
116 char *const Args[] = {ExecPath.get(), TestOutputFlag.get(),
117 FDSpecifier.get(), nullptr};
118 int RC = execvp(ExecPath.get(), Args);
119 if (RC != 0)
120 return make_error<StringError>(
121 "Unable to launch out-of-process executor '" + ExecutablePath + "'\n",
122 inconvertibleErrorCode());
124 llvm_unreachable("Fork won't return in success case");
126 // else we're the parent...
128 // Close the child ends of the pipes
129 close(ToExecutor[ReadEnd]);
130 close(FromExecutor[WriteEnd]);
132 auto EPC = SimpleRemoteEPC::Create<FDSimpleRemoteEPCTransport>(
133 std::make_unique<DynamicThreadPoolTaskDispatcher>(std::nullopt),
134 SimpleRemoteEPC::Setup(),
135 FromExecutor[ReadEnd], ToExecutor[WriteEnd]);
136 if (!EPC)
137 return EPC.takeError();
139 return std::make_pair(std::move(*EPC), static_cast<uint64_t>(ProcessID));
142 static Expected<int> connectTCPSocketImpl(std::string Host,
143 std::string PortStr) {
144 addrinfo *AI;
145 addrinfo Hints{};
146 Hints.ai_family = AF_INET;
147 Hints.ai_socktype = SOCK_STREAM;
148 Hints.ai_flags = AI_NUMERICSERV;
150 if (int EC = getaddrinfo(Host.c_str(), PortStr.c_str(), &Hints, &AI))
151 return make_error<StringError>(
152 formatv("address resolution failed ({0})", gai_strerror(EC)),
153 inconvertibleErrorCode());
155 // Cycle through the returned addrinfo structures and connect to the first
156 // reachable endpoint.
157 int SockFD;
158 addrinfo *Server;
159 for (Server = AI; Server != nullptr; Server = Server->ai_next) {
160 // If socket fails, maybe it's because the address family is not supported.
161 // Skip to the next addrinfo structure.
162 if ((SockFD = socket(AI->ai_family, AI->ai_socktype, AI->ai_protocol)) < 0)
163 continue;
165 // If connect works, we exit the loop with a working socket.
166 if (connect(SockFD, Server->ai_addr, Server->ai_addrlen) == 0)
167 break;
169 close(SockFD);
171 freeaddrinfo(AI);
173 // Did we reach the end of the loop without connecting to a valid endpoint?
174 if (Server == nullptr)
175 return make_error<StringError>("invalid hostname",
176 inconvertibleErrorCode());
178 return SockFD;
181 Expected<std::unique_ptr<SimpleRemoteEPC>>
182 connectTCPSocket(StringRef NetworkAddress) {
183 auto CreateErr = [NetworkAddress](StringRef Details) {
184 return make_error<StringError>(
185 formatv("Failed to connect TCP socket '{0}': {1}", NetworkAddress,
186 Details),
187 inconvertibleErrorCode());
190 StringRef Host, PortStr;
191 std::tie(Host, PortStr) = NetworkAddress.split(':');
192 if (Host.empty())
193 return CreateErr("host name cannot be empty");
194 if (PortStr.empty())
195 return CreateErr("port cannot be empty");
196 int Port = 0;
197 if (PortStr.getAsInteger(10, Port))
198 return CreateErr("port number is not a valid integer");
200 Expected<int> SockFD = connectTCPSocketImpl(Host.str(), PortStr.str());
201 if (!SockFD)
202 return CreateErr(toString(SockFD.takeError()));
204 return SimpleRemoteEPC::Create<FDSimpleRemoteEPCTransport>(
205 std::make_unique<DynamicThreadPoolTaskDispatcher>(std::nullopt),
206 SimpleRemoteEPC::Setup(), *SockFD);
209 #endif