[clang] [llvm] [Clang-Repl] Add support for out-of-process execution. (PR #110418)

via cfe-commits cfe-commits at lists.llvm.org
Sun Sep 29 02:47:00 PDT 2024


https://github.com/SahilPatidar created https://github.com/llvm/llvm-project/pull/110418

This PR introduces out-of-process (OOP) execution support for Clang-Repl. With this enhancement, two new flags, `oop-executor` and `oop-executor-connect`, are added to the Clang-Repl interface. These flags enable the launch of an external executor (`llvm-jitlink-executor`), which handles code execution in a separate process.

>From d3385116da9f9020bd6bb11b0e8ee8ed16348cfd Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Fri, 7 Jun 2024 13:30:08 +0530
Subject: [PATCH 1/5] [Clang-Repl] Implement out-of-process execution interface
 for clang-repl

---
 clang/include/clang/Interpreter/Interpreter.h |   9 +-
 clang/lib/Interpreter/Interpreter.cpp         |  33 ++-
 clang/tools/clang-repl/CMakeLists.txt         |   2 +
 clang/tools/clang-repl/ClangRepl.cpp          |  75 ++++++-
 clang/tools/clang-repl/RemoteJITUtils.cpp     | 208 ++++++++++++++++++
 clang/tools/clang-repl/RemoteJITUtils.h       |  42 ++++
 llvm/lib/ExecutionEngine/Orc/LLJIT.cpp        |   3 +
 7 files changed, 364 insertions(+), 8 deletions(-)
 create mode 100644 clang/tools/clang-repl/RemoteJITUtils.cpp
 create mode 100644 clang/tools/clang-repl/RemoteJITUtils.h

diff --git a/clang/include/clang/Interpreter/Interpreter.h b/clang/include/clang/Interpreter/Interpreter.h
index 1230a3a7016fae..147794c5870335 100644
--- a/clang/include/clang/Interpreter/Interpreter.h
+++ b/clang/include/clang/Interpreter/Interpreter.h
@@ -21,6 +21,7 @@
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ExecutionEngine/JITSymbol.h"
 #include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
+#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
 #include "llvm/Support/Error.h"
 #include <memory>
 #include <vector>
@@ -129,7 +130,13 @@ class Interpreter {
 public:
   virtual ~Interpreter();
   static llvm::Expected<std::unique_ptr<Interpreter>>
-  create(std::unique_ptr<CompilerInstance> CI);
+  create(std::unique_ptr<CompilerInstance> CI,
+         std::unique_ptr<llvm::orc::LLJITBuilder> JITBuilder = nullptr);
+  static llvm::Expected<std::unique_ptr<Interpreter>>
+  createWithOOPExecutor(
+      std::unique_ptr<CompilerInstance> CI,
+      std::unique_ptr<llvm::orc::ExecutorProcessControl> EI,
+      llvm::StringRef OrcRuntimePath);
   static llvm::Expected<std::unique_ptr<Interpreter>>
   createWithCUDA(std::unique_ptr<CompilerInstance> CI,
                  std::unique_ptr<CompilerInstance> DCI);
diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp
index bc96da811d44cb..21507906618c39 100644
--- a/clang/lib/Interpreter/Interpreter.cpp
+++ b/clang/lib/Interpreter/Interpreter.cpp
@@ -45,6 +45,7 @@
 #include "clang/Serialization/ObjectFilePCHContainerReader.h"
 #include "llvm/ExecutionEngine/JITSymbol.h"
 #include "llvm/ExecutionEngine/Orc/LLJIT.h"
+#include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"
 #include "llvm/IR/Module.h"
 #include "llvm/Support/Errc.h"
 #include "llvm/Support/ErrorHandling.h"
@@ -456,10 +457,12 @@ const char *const Runtimes = R"(
 )";
 
 llvm::Expected<std::unique_ptr<Interpreter>>
-Interpreter::create(std::unique_ptr<CompilerInstance> CI) {
+Interpreter::create(std::unique_ptr<CompilerInstance> CI,
+                    std::unique_ptr<llvm::orc::LLJITBuilder> JB) {
   llvm::Error Err = llvm::Error::success();
   auto Interp =
-      std::unique_ptr<Interpreter>(new Interpreter(std::move(CI), Err));
+      std::unique_ptr<Interpreter>(new Interpreter(std::move(CI), Err,
+                                                   JB? std::move(JB): nullptr));
   if (Err)
     return std::move(Err);
 
@@ -578,6 +581,26 @@ createJITTargetMachineBuilder(const std::string &TT) {
   return llvm::orc::JITTargetMachineBuilder(llvm::Triple(TT));
 }
 
+llvm::Expected<std::unique_ptr<Interpreter>>
+Interpreter::createWithOOPExecutor(
+    std::unique_ptr<CompilerInstance> CI,
+    std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC,
+    llvm::StringRef OrcRuntimePath) {
+  const std::string &TT = CI->getTargetOpts().Triple;
+  auto JTMB = createJITTargetMachineBuilder(TT);
+  if (!JTMB)
+    return JTMB.takeError();
+  auto JB = IncrementalExecutor::createDefaultJITBuilder(std::move(*JTMB));
+  if (!JB)
+    return JB.takeError();
+  if (EPC) {
+    JB.get()->setExecutorProcessControl(std::move(EPC));
+    JB.get()->setPlatformSetUp(llvm::orc::ExecutorNativePlatform(OrcRuntimePath.str()));
+  }
+
+  return Interpreter::create(std::move(CI), std::move(*JB));
+}
+
 llvm::Error Interpreter::CreateExecutor() {
   if (IncrExecutor)
     return llvm::make_error<llvm::StringError>("Operation failed. "
@@ -702,10 +725,10 @@ llvm::Error Interpreter::LoadDynamicLibrary(const char *name) {
   if (!EE)
     return EE.takeError();
 
-  auto &DL = EE->getDataLayout();
+  // auto &DL = EE->getDataLayout();
 
-  if (auto DLSG = llvm::orc::DynamicLibrarySearchGenerator::Load(
-          name, DL.getGlobalPrefix()))
+  if (auto DLSG = llvm::orc::EPCDynamicLibrarySearchGenerator::Load(
+          EE->getExecutionSession(), name))
     EE->getMainJITDylib().addGenerator(std::move(*DLSG));
   else
     return DLSG.takeError();
diff --git a/clang/tools/clang-repl/CMakeLists.txt b/clang/tools/clang-repl/CMakeLists.txt
index 9ffe853d759caf..9c1eb1ea558c1f 100644
--- a/clang/tools/clang-repl/CMakeLists.txt
+++ b/clang/tools/clang-repl/CMakeLists.txt
@@ -4,7 +4,9 @@ set( LLVM_LINK_COMPONENTS
   LineEditor
   Option
   OrcJIT
+  OrcShared
   Support
+  TargetParser
   )
 
 add_clang_tool(clang-repl
diff --git a/clang/tools/clang-repl/ClangRepl.cpp b/clang/tools/clang-repl/ClangRepl.cpp
index 08c54e6cafa901..21359df01c270f 100644
--- a/clang/tools/clang-repl/ClangRepl.cpp
+++ b/clang/tools/clang-repl/ClangRepl.cpp
@@ -10,6 +10,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "RemoteJITUtils.h"
+
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/FrontendDiagnostic.h"
@@ -26,6 +28,8 @@
 #include "llvm/Support/TargetSelect.h"
 #include <optional>
 
+#include "llvm/ExecutionEngine/Orc/Debugging/DebuggerSupport.h"
+
 // Disable LSan for this test.
 // FIXME: Re-enable once we can assume GCC 13.2 or higher.
 // https://llvm.org/github.com/llvm/llvm-project/issues/67586.
@@ -37,7 +41,18 @@ LLVM_ATTRIBUTE_USED int __lsan_is_turned_off() { return 1; }
 static llvm::cl::opt<bool> CudaEnabled("cuda", llvm::cl::Hidden);
 static llvm::cl::opt<std::string> CudaPath("cuda-path", llvm::cl::Hidden);
 static llvm::cl::opt<std::string> OffloadArch("offload-arch", llvm::cl::Hidden);
-
+static llvm::cl::OptionCategory OOPCategory("Out-of-process Execution Options (Only available on MachO)");
+static llvm::cl::opt<std::string> OOPExecutor(
+    "oop-executor",
+    llvm::cl::desc("Launch an out-of-process executor to run code"),
+    llvm::cl::ValueOptional, llvm::cl::cat(OOPCategory));
+static llvm::cl::opt<std::string> OOPExecutorConnectTCP(
+    "opp-connect",
+    llvm::cl::desc("Connect to an out-of-process executor through a TCP socket"),
+    llvm::cl::value_desc("<hostname>:<port>"));
+static llvm::cl::opt<std::string>
+    OrcRuntimePath("orc-runtime", llvm::cl::desc("Path to the ORC runtime"),
+                   llvm::cl::cat(OOPCategory));
 static llvm::cl::list<std::string>
     ClangArgs("Xcc",
               llvm::cl::desc("Argument to pass to the CompilerInvocation"),
@@ -47,6 +62,39 @@ static llvm::cl::opt<bool> OptHostSupportsJit("host-supports-jit",
 static llvm::cl::list<std::string> OptInputs(llvm::cl::Positional,
                                              llvm::cl::desc("[code to run]"));
 
+
+static llvm::Error sanitizeOopArguments(const char *ArgV0) {
+  // Only one of -oop-executor and -oop-executor-connect can be used.
+  if (!!OOPExecutor.getNumOccurrences() &&
+      !!OOPExecutorConnectTCP.getNumOccurrences())
+    return llvm::make_error<llvm::StringError>(
+        "Only one of -" + OOPExecutor.ArgStr + " and -" +
+            OOPExecutorConnectTCP.ArgStr + " can be specified",
+        llvm::inconvertibleErrorCode());
+
+  // Out-of-process executors must run with the ORC runtime for destructor
+  // support.
+  if (OrcRuntimePath.empty() &&
+      (OOPExecutor.getNumOccurrences() ||
+       OOPExecutorConnectTCP.getNumOccurrences()))
+    return llvm::make_error<llvm::StringError>(
+        "ORC runtime required",
+        llvm::inconvertibleErrorCode());
+
+  // If -oop-executor was used but no value was specified then use a sensible
+  // default.
+  if (!!OOPExecutor.getNumOccurrences() &&
+      OOPExecutor.empty()) {
+    llvm::SmallString<256> OOPExecutorPath(llvm::sys::fs::getMainExecutable(
+        ArgV0, reinterpret_cast<void *>(&sanitizeOopArguments)));
+    llvm::sys::path::remove_filename(OOPExecutorPath);
+    llvm::sys::path::append(OOPExecutorPath, "llvm-jitlink-executor");
+    OOPExecutor = OOPExecutorPath.str().str();
+  }
+
+  return llvm::Error::success();
+}
+
 static void LLVMErrorHandler(void *UserData, const char *Message,
                              bool GenCrashDiag) {
   auto &Diags = *static_cast<clang::DiagnosticsEngine *>(UserData);
@@ -181,6 +229,25 @@ int main(int argc, const char **argv) {
     DeviceCI = ExitOnErr(CB.CreateCudaDevice());
   }
 
+  ExitOnErr(sanitizeOopArguments(argv[0]));
+
+
+  std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC;
+    // std::unique_ptr<llvm::orc::TaskDispatcher> D = nullptr;
+
+    // D = std::make_unique<llvm::orc::DynamicThreadPoolTaskDispatcher>(std::nullopt);
+
+    // if (auto EPCOrErr =
+    //         llvm::orc::SelfExecutorProcessControl::Create(nullptr, std::move(D), nullptr))
+    //   EPC = std::move(*EPCOrErr);
+  if (OOPExecutor.getNumOccurrences()) {
+    // Launch an out-of-process executor locally in a child process.
+    int PID;
+    std::tie(EPC, PID) = ExitOnErr(launchLocalExecutor(OOPExecutor));
+    CB.SetTargetTriple(EPC->getTargetTriple().getTriple());
+    llvm::outs() << "executor process id = " << PID << "\n";
+  }
+
   // FIXME: Investigate if we could use runToolOnCodeWithArgs from tooling. It
   // can replace the boilerplate code for creation of the compiler instance.
   std::unique_ptr<clang::CompilerInstance> CI;
@@ -212,11 +279,15 @@ int main(int argc, const char **argv) {
       auto CudaRuntimeLibPath = CudaPath + "/lib/libcudart.so";
       ExitOnErr(Interp->LoadDynamicLibrary(CudaRuntimeLibPath.c_str()));
     }
+  } else if (EPC) {
+    Interp = ExitOnErr(
+        clang::Interpreter::createWithOOPExecutor(std::move(CI),
+                                                  std::move(EPC),
+                                                  OrcRuntimePath));
   } else
     Interp = ExitOnErr(clang::Interpreter::create(std::move(CI)));
 
   bool HasError = false;
-
   for (const std::string &input : OptInputs) {
     if (auto Err = Interp->ParseAndExecute(input)) {
       llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), "error: ");
diff --git a/clang/tools/clang-repl/RemoteJITUtils.cpp b/clang/tools/clang-repl/RemoteJITUtils.cpp
new file mode 100644
index 00000000000000..7c896ab6d88e07
--- /dev/null
+++ b/clang/tools/clang-repl/RemoteJITUtils.cpp
@@ -0,0 +1,208 @@
+//===-- RemoteJITUtils.cpp - Utilities for remote-JITing --------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "RemoteJITUtils.h"
+
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h"
+#include "llvm/ExecutionEngine/Orc/EPCDebugObjectRegistrar.h"
+#include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"
+#include "llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h"
+#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+
+#ifdef LLVM_ON_UNIX
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#endif // LLVM_ON_UNIX
+
+using namespace llvm;
+using namespace llvm::orc;
+
+Expected<std::unique_ptr<DefinitionGenerator>>
+loadDylib(ExecutionSession &ES, StringRef RemotePath) {
+  if (auto Handle = ES.getExecutorProcessControl().loadDylib(RemotePath.data()))
+    return std::make_unique<EPCDynamicLibrarySearchGenerator>(ES, *Handle);
+  else
+    return Handle.takeError();
+}
+
+static void findLocalExecutorHelper() {}
+std::string findLocalExecutor(const char *HostArgv0) {
+  // This just needs to be some static symbol in the binary; C++ doesn't
+  // allow taking the address of ::main however.
+  uintptr_t UIntPtr = reinterpret_cast<uintptr_t>(&findLocalExecutorHelper);
+  void *VoidPtr = reinterpret_cast<void *>(UIntPtr);
+  SmallString<256> FullName(sys::fs::getMainExecutable(HostArgv0, VoidPtr));
+  sys::path::remove_filename(FullName);
+  sys::path::append(FullName, "llvm-jitlink-executor");
+  return FullName.str().str();
+}
+
+#ifndef LLVM_ON_UNIX
+
+// FIXME: Add support for Windows.
+Expected<std::pair<std::unique_ptr<SimpleRemoteEPC>, uint64_t>>
+launchLocalExecutor(StringRef ExecutablePath) {
+  return make_error<StringError>(
+      "Remote JITing not yet supported on non-unix platforms",
+      inconvertibleErrorCode());
+}
+
+// FIXME: Add support for Windows.
+Expected<std::unique_ptr<SimpleRemoteEPC>>
+connectTCPSocket(StringRef NetworkAddress) {
+  return make_error<StringError>(
+      "Remote JITing not yet supported on non-unix platforms",
+      inconvertibleErrorCode());
+}
+
+#else
+
+Expected<std::pair<std::unique_ptr<SimpleRemoteEPC>, uint64_t>>
+launchLocalExecutor(StringRef ExecutablePath) {
+  constexpr int ReadEnd = 0;
+  constexpr int WriteEnd = 1;
+
+  if (!sys::fs::can_execute(ExecutablePath))
+    return make_error<StringError>(
+        formatv("Specified executor invalid: {0}", ExecutablePath),
+        inconvertibleErrorCode());
+
+  // Pipe FDs.
+  int ToExecutor[2];
+  int FromExecutor[2];
+
+  // Create pipes to/from the executor..
+  if (pipe(ToExecutor) != 0 || pipe(FromExecutor) != 0)
+    return make_error<StringError>("Unable to create pipe for executor",
+                                   inconvertibleErrorCode());
+
+  pid_t ProcessID = fork();
+  if (ProcessID == 0) {
+    // In the child...
+
+    // Close the parent ends of the pipes
+    close(ToExecutor[WriteEnd]);
+    close(FromExecutor[ReadEnd]);
+
+    // Execute the child process.
+    std::unique_ptr<char[]> ExecPath, FDSpecifier, TestOutputFlag;
+    {
+      ExecPath = std::make_unique<char[]>(ExecutablePath.size() + 1);
+      strcpy(ExecPath.get(), ExecutablePath.data());
+
+      const char *TestOutputFlagStr = "test-jitloadergdb";
+      TestOutputFlag = std::make_unique<char[]>(strlen(TestOutputFlagStr) + 1);
+      strcpy(TestOutputFlag.get(), TestOutputFlagStr);
+
+      std::string FDSpecifierStr("filedescs=");
+      FDSpecifierStr += utostr(ToExecutor[ReadEnd]);
+      FDSpecifierStr += ',';
+      FDSpecifierStr += utostr(FromExecutor[WriteEnd]);
+      FDSpecifier = std::make_unique<char[]>(FDSpecifierStr.size() + 1);
+      strcpy(FDSpecifier.get(), FDSpecifierStr.c_str());
+    }
+
+    char *const Args[] = {ExecPath.get(), TestOutputFlag.get(),
+                          FDSpecifier.get(), nullptr};
+    int RC = execvp(ExecPath.get(), Args);
+    if (RC != 0)
+      return make_error<StringError>(
+          "Unable to launch out-of-process executor '" + ExecutablePath + "'\n",
+          inconvertibleErrorCode());
+
+    llvm_unreachable("Fork won't return in success case");
+  }
+  // else we're the parent...
+
+  // Close the child ends of the pipes
+  close(ToExecutor[ReadEnd]);
+  close(FromExecutor[WriteEnd]);
+
+  auto EPC = SimpleRemoteEPC::Create<FDSimpleRemoteEPCTransport>(
+      std::make_unique<DynamicThreadPoolTaskDispatcher>(std::nullopt),
+      SimpleRemoteEPC::Setup(),
+      FromExecutor[ReadEnd], ToExecutor[WriteEnd]);
+  if (!EPC)
+    return EPC.takeError();
+
+  return std::make_pair(std::move(*EPC), static_cast<uint64_t>(ProcessID));
+}
+
+static Expected<int> connectTCPSocketImpl(std::string Host,
+                                          std::string PortStr) {
+  addrinfo *AI;
+  addrinfo Hints{};
+  Hints.ai_family = AF_INET;
+  Hints.ai_socktype = SOCK_STREAM;
+  Hints.ai_flags = AI_NUMERICSERV;
+
+  if (int EC = getaddrinfo(Host.c_str(), PortStr.c_str(), &Hints, &AI))
+    return make_error<StringError>(
+        formatv("address resolution failed ({0})", gai_strerror(EC)),
+        inconvertibleErrorCode());
+
+  // Cycle through the returned addrinfo structures and connect to the first
+  // reachable endpoint.
+  int SockFD;
+  addrinfo *Server;
+  for (Server = AI; Server != nullptr; Server = Server->ai_next) {
+    // If socket fails, maybe it's because the address family is not supported.
+    // Skip to the next addrinfo structure.
+    if ((SockFD = socket(AI->ai_family, AI->ai_socktype, AI->ai_protocol)) < 0)
+      continue;
+
+    // If connect works, we exit the loop with a working socket.
+    if (connect(SockFD, Server->ai_addr, Server->ai_addrlen) == 0)
+      break;
+
+    close(SockFD);
+  }
+  freeaddrinfo(AI);
+
+  // Did we reach the end of the loop without connecting to a valid endpoint?
+  if (Server == nullptr)
+    return make_error<StringError>("invalid hostname",
+                                   inconvertibleErrorCode());
+
+  return SockFD;
+}
+
+Expected<std::unique_ptr<SimpleRemoteEPC>>
+connectTCPSocket(StringRef NetworkAddress) {
+  auto CreateErr = [NetworkAddress](StringRef Details) {
+    return make_error<StringError>(
+        formatv("Failed to connect TCP socket '{0}': {1}", NetworkAddress,
+                Details),
+        inconvertibleErrorCode());
+  };
+
+  StringRef Host, PortStr;
+  std::tie(Host, PortStr) = NetworkAddress.split(':');
+  if (Host.empty())
+    return CreateErr("host name cannot be empty");
+  if (PortStr.empty())
+    return CreateErr("port cannot be empty");
+  int Port = 0;
+  if (PortStr.getAsInteger(10, Port))
+    return CreateErr("port number is not a valid integer");
+
+  Expected<int> SockFD = connectTCPSocketImpl(Host.str(), PortStr.str());
+  if (!SockFD)
+    return CreateErr(toString(SockFD.takeError()));
+
+  return SimpleRemoteEPC::Create<FDSimpleRemoteEPCTransport>(
+      std::make_unique<DynamicThreadPoolTaskDispatcher>(std::nullopt),
+      SimpleRemoteEPC::Setup(), *SockFD);
+}
+
+#endif
diff --git a/clang/tools/clang-repl/RemoteJITUtils.h b/clang/tools/clang-repl/RemoteJITUtils.h
new file mode 100644
index 00000000000000..ccf1f7b913eaab
--- /dev/null
+++ b/clang/tools/clang-repl/RemoteJITUtils.h
@@ -0,0 +1,42 @@
+//===-- RemoteJITUtils.h - Utilities for remote-JITing ----------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Utilities for ExecutorProcessControl-based remote JITing with Orc and
+// JITLink.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_REMOTEJITUTILS_H
+#define LLVM_CLANG_TOOLS_REMOTEJITUTILS_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ExecutionEngine/Orc/Core.h"
+#include "llvm/ExecutionEngine/Orc/Layer.h"
+#include "llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h"
+#include "llvm/Support/Error.h"
+
+#include <cstdint>
+#include <memory>
+#include <string>
+
+/// Find the default exectuable on disk and create a JITLinkExecutor for it.
+std::string findLocalExecutor(const char *HostArgv0);
+
+llvm::Expected<std::pair<std::unique_ptr<llvm::orc::SimpleRemoteEPC>, uint64_t>>
+launchLocalExecutor(llvm::StringRef ExecutablePath);
+
+/// Create a JITLinkExecutor that connects to the given network address
+/// through a TCP socket. A valid NetworkAddress provides hostname and port,
+/// e.g. localhost:20000.
+llvm::Expected<std::unique_ptr<llvm::orc::SimpleRemoteEPC>>
+connectTCPSocket(llvm::StringRef NetworkAddress);
+
+llvm::Expected<std::unique_ptr<llvm::orc::DefinitionGenerator>>
+loadDylib(llvm::orc::ExecutionSession &ES, llvm::StringRef RemotePath);
+
+#endif
diff --git a/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp b/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp
index 19b3f3d6ea0380..3daeaafe038ec5 100644
--- a/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp
@@ -1159,6 +1159,9 @@ Expected<JITDylibSP> ExecutorNativePlatform::operator()(LLJIT &J) {
 
   auto &ES = J.getExecutionSession();
   auto &PlatformJD = ES.createBareJITDylib("<Platform>");
+  if (auto DSGOrErr = EPCDynamicLibrarySearchGenerator::GetForTargetProcess(ES)) {
+    PlatformJD.addGenerator(std::move(*DSGOrErr));
+  }
   PlatformJD.addToLinkOrder(*ProcessSymbolsJD);
 
   J.setPlatformSupport(std::make_unique<ORCPlatformSupport>(J));

>From beee5bb3f68b92ecaa2e9508041ab1b0d1425079 Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Fri, 28 Jun 2024 14:47:04 +0530
Subject: [PATCH 2/5] Refactor and improve initial code structure

---
 clang/include/clang/Interpreter/Interpreter.h |   9 +-
 .../clang/Interpreter}/RemoteJITUtils.h       |  16 +-
 clang/lib/Interpreter/CMakeLists.txt          |   1 +
 clang/lib/Interpreter/Interpreter.cpp         |  26 ++--
 .../Interpreter}/RemoteJITUtils.cpp           | 145 ++++++++----------
 clang/tools/clang-repl/ClangRepl.cpp          |  75 +++++----
 6 files changed, 129 insertions(+), 143 deletions(-)
 rename clang/{tools/clang-repl => include/clang/Interpreter}/RemoteJITUtils.h (68%)
 rename clang/{tools/clang-repl => lib/Interpreter}/RemoteJITUtils.cpp (57%)

diff --git a/clang/include/clang/Interpreter/Interpreter.h b/clang/include/clang/Interpreter/Interpreter.h
index 147794c5870335..db482f1b7e4153 100644
--- a/clang/include/clang/Interpreter/Interpreter.h
+++ b/clang/include/clang/Interpreter/Interpreter.h
@@ -133,13 +133,12 @@ class Interpreter {
   create(std::unique_ptr<CompilerInstance> CI,
          std::unique_ptr<llvm::orc::LLJITBuilder> JITBuilder = nullptr);
   static llvm::Expected<std::unique_ptr<Interpreter>>
-  createWithOOPExecutor(
-      std::unique_ptr<CompilerInstance> CI,
-      std::unique_ptr<llvm::orc::ExecutorProcessControl> EI,
-      llvm::StringRef OrcRuntimePath);
-  static llvm::Expected<std::unique_ptr<Interpreter>>
   createWithCUDA(std::unique_ptr<CompilerInstance> CI,
                  std::unique_ptr<CompilerInstance> DCI);
+  static llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>
+  createLLJITBuilder(
+      std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC,
+      llvm::StringRef OrcRuntimePath);
   const ASTContext &getASTContext() const;
   ASTContext &getASTContext();
   const CompilerInstance *getCompilerInstance() const;
diff --git a/clang/tools/clang-repl/RemoteJITUtils.h b/clang/include/clang/Interpreter/RemoteJITUtils.h
similarity index 68%
rename from clang/tools/clang-repl/RemoteJITUtils.h
rename to clang/include/clang/Interpreter/RemoteJITUtils.h
index ccf1f7b913eaab..c0f3f424629fbd 100644
--- a/clang/tools/clang-repl/RemoteJITUtils.h
+++ b/clang/include/clang/Interpreter/RemoteJITUtils.h
@@ -11,8 +11,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef LLVM_CLANG_TOOLS_REMOTEJITUTILS_H
-#define LLVM_CLANG_TOOLS_REMOTEJITUTILS_H
+#ifndef LLVM_CLANG_INTERPRETER_REMOTEJITUTILS_H
+#define LLVM_CLANG_INTERPRETER_REMOTEJITUTILS_H
 
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ExecutionEngine/Orc/Core.h"
@@ -24,11 +24,8 @@
 #include <memory>
 #include <string>
 
-/// Find the default exectuable on disk and create a JITLinkExecutor for it.
-std::string findLocalExecutor(const char *HostArgv0);
-
-llvm::Expected<std::pair<std::unique_ptr<llvm::orc::SimpleRemoteEPC>, uint64_t>>
-launchLocalExecutor(llvm::StringRef ExecutablePath);
+llvm::Expected<std::unique_ptr<llvm::orc::SimpleRemoteEPC>>
+launchExecutor(llvm::StringRef ExecutablePath);
 
 /// Create a JITLinkExecutor that connects to the given network address
 /// through a TCP socket. A valid NetworkAddress provides hostname and port,
@@ -36,7 +33,4 @@ launchLocalExecutor(llvm::StringRef ExecutablePath);
 llvm::Expected<std::unique_ptr<llvm::orc::SimpleRemoteEPC>>
 connectTCPSocket(llvm::StringRef NetworkAddress);
 
-llvm::Expected<std::unique_ptr<llvm::orc::DefinitionGenerator>>
-loadDylib(llvm::orc::ExecutionSession &ES, llvm::StringRef RemotePath);
-
-#endif
+#endif // LLVM_CLANG_INTERPRETER_REMOTEJITUTILS_H
diff --git a/clang/lib/Interpreter/CMakeLists.txt b/clang/lib/Interpreter/CMakeLists.txt
index 2cc7c59b61d318..4055898af3f35a 100644
--- a/clang/lib/Interpreter/CMakeLists.txt
+++ b/clang/lib/Interpreter/CMakeLists.txt
@@ -24,6 +24,7 @@ add_clang_library(clangInterpreter
   Interpreter.cpp
   InterpreterValuePrinter.cpp
   InterpreterUtils.cpp
+  RemoteJITUtils.cpp
   Value.cpp
   ${WASM_SRC}
   PARTIAL_SOURCES_INTENDED
diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp
index 21507906618c39..c281c917cff4b5 100644
--- a/clang/lib/Interpreter/Interpreter.cpp
+++ b/clang/lib/Interpreter/Interpreter.cpp
@@ -44,8 +44,8 @@
 #include "clang/Sema/Lookup.h"
 #include "clang/Serialization/ObjectFilePCHContainerReader.h"
 #include "llvm/ExecutionEngine/JITSymbol.h"
-#include "llvm/ExecutionEngine/Orc/LLJIT.h"
 #include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"
+#include "llvm/ExecutionEngine/Orc/LLJIT.h"
 #include "llvm/IR/Module.h"
 #include "llvm/Support/Errc.h"
 #include "llvm/Support/ErrorHandling.h"
@@ -460,9 +460,8 @@ llvm::Expected<std::unique_ptr<Interpreter>>
 Interpreter::create(std::unique_ptr<CompilerInstance> CI,
                     std::unique_ptr<llvm::orc::LLJITBuilder> JB) {
   llvm::Error Err = llvm::Error::success();
-  auto Interp =
-      std::unique_ptr<Interpreter>(new Interpreter(std::move(CI), Err,
-                                                   JB? std::move(JB): nullptr));
+  auto Interp = std::unique_ptr<Interpreter>(
+      new Interpreter(std::move(CI), Err, JB ? std::move(JB) : nullptr));
   if (Err)
     return std::move(Err);
 
@@ -581,24 +580,23 @@ createJITTargetMachineBuilder(const std::string &TT) {
   return llvm::orc::JITTargetMachineBuilder(llvm::Triple(TT));
 }
 
-llvm::Expected<std::unique_ptr<Interpreter>>
-Interpreter::createWithOOPExecutor(
-    std::unique_ptr<CompilerInstance> CI,
+llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>
+Interpreter::createLLJITBuilder(
     std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC,
     llvm::StringRef OrcRuntimePath) {
-  const std::string &TT = CI->getTargetOpts().Triple;
+  const std::string &TT = EPC->getTargetTriple().getTriple();
   auto JTMB = createJITTargetMachineBuilder(TT);
   if (!JTMB)
     return JTMB.takeError();
   auto JB = IncrementalExecutor::createDefaultJITBuilder(std::move(*JTMB));
   if (!JB)
     return JB.takeError();
-  if (EPC) {
-    JB.get()->setExecutorProcessControl(std::move(EPC));
-    JB.get()->setPlatformSetUp(llvm::orc::ExecutorNativePlatform(OrcRuntimePath.str()));
-  }
 
-  return Interpreter::create(std::move(CI), std::move(*JB));
+  (*JB)->setExecutorProcessControl(std::move(EPC));
+  (*JB)->setPlatformSetUp(
+      llvm::orc::ExecutorNativePlatform(OrcRuntimePath.str()));
+
+  return std::move(*JB);
 }
 
 llvm::Error Interpreter::CreateExecutor() {
@@ -725,8 +723,6 @@ llvm::Error Interpreter::LoadDynamicLibrary(const char *name) {
   if (!EE)
     return EE.takeError();
 
-  // auto &DL = EE->getDataLayout();
-
   if (auto DLSG = llvm::orc::EPCDynamicLibrarySearchGenerator::Load(
           EE->getExecutionSession(), name))
     EE->getMainJITDylib().addGenerator(std::move(*DLSG));
diff --git a/clang/tools/clang-repl/RemoteJITUtils.cpp b/clang/lib/Interpreter/RemoteJITUtils.cpp
similarity index 57%
rename from clang/tools/clang-repl/RemoteJITUtils.cpp
rename to clang/lib/Interpreter/RemoteJITUtils.cpp
index 7c896ab6d88e07..75f2ccf069729a 100644
--- a/clang/tools/clang-repl/RemoteJITUtils.cpp
+++ b/clang/lib/Interpreter/RemoteJITUtils.cpp
@@ -6,7 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "RemoteJITUtils.h"
+#include "clang/Interpreter/RemoteJITUtils.h"
 
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h"
@@ -27,67 +27,44 @@
 using namespace llvm;
 using namespace llvm::orc;
 
-Expected<std::unique_ptr<DefinitionGenerator>>
-loadDylib(ExecutionSession &ES, StringRef RemotePath) {
-  if (auto Handle = ES.getExecutorProcessControl().loadDylib(RemotePath.data()))
-    return std::make_unique<EPCDynamicLibrarySearchGenerator>(ES, *Handle);
-  else
-    return Handle.takeError();
-}
-
-static void findLocalExecutorHelper() {}
-std::string findLocalExecutor(const char *HostArgv0) {
-  // This just needs to be some static symbol in the binary; C++ doesn't
-  // allow taking the address of ::main however.
-  uintptr_t UIntPtr = reinterpret_cast<uintptr_t>(&findLocalExecutorHelper);
-  void *VoidPtr = reinterpret_cast<void *>(UIntPtr);
-  SmallString<256> FullName(sys::fs::getMainExecutable(HostArgv0, VoidPtr));
-  sys::path::remove_filename(FullName);
-  sys::path::append(FullName, "llvm-jitlink-executor");
-  return FullName.str().str();
-}
-
-#ifndef LLVM_ON_UNIX
-
-// FIXME: Add support for Windows.
-Expected<std::pair<std::unique_ptr<SimpleRemoteEPC>, uint64_t>>
-launchLocalExecutor(StringRef ExecutablePath) {
-  return make_error<StringError>(
-      "Remote JITing not yet supported on non-unix platforms",
-      inconvertibleErrorCode());
-}
-
-// FIXME: Add support for Windows.
 Expected<std::unique_ptr<SimpleRemoteEPC>>
-connectTCPSocket(StringRef NetworkAddress) {
+launchExecutor(StringRef ExecutablePath) {
+#ifndef LLVM_ON_UNIX
+  // FIXME: Add support for Windows.
+  return make_error<StringError>("-" + ExecutablePath +
+                                     " not supported on non-unix platforms",
+                                 inconvertibleErrorCode());
+#elif !LLVM_ENABLE_THREADS
+  // Out of process mode using SimpleRemoteEPC depends on threads.
   return make_error<StringError>(
-      "Remote JITing not yet supported on non-unix platforms",
+      "-" + ExecutablePath +
+          " requires threads, but LLVM was built with "
+          "LLVM_ENABLE_THREADS=Off",
       inconvertibleErrorCode());
-}
-
 #else
 
-Expected<std::pair<std::unique_ptr<SimpleRemoteEPC>, uint64_t>>
-launchLocalExecutor(StringRef ExecutablePath) {
-  constexpr int ReadEnd = 0;
-  constexpr int WriteEnd = 1;
-
   if (!sys::fs::can_execute(ExecutablePath))
     return make_error<StringError>(
         formatv("Specified executor invalid: {0}", ExecutablePath),
         inconvertibleErrorCode());
 
+  constexpr int ReadEnd = 0;
+  constexpr int WriteEnd = 1;
+
   // Pipe FDs.
   int ToExecutor[2];
   int FromExecutor[2];
 
+  pid_t ChildPID;
+
   // Create pipes to/from the executor..
   if (pipe(ToExecutor) != 0 || pipe(FromExecutor) != 0)
     return make_error<StringError>("Unable to create pipe for executor",
                                    inconvertibleErrorCode());
 
-  pid_t ProcessID = fork();
-  if (ProcessID == 0) {
+  ChildPID = fork();
+
+  if (ChildPID == 0) {
     // In the child...
 
     // Close the parent ends of the pipes
@@ -95,14 +72,10 @@ launchLocalExecutor(StringRef ExecutablePath) {
     close(FromExecutor[ReadEnd]);
 
     // Execute the child process.
-    std::unique_ptr<char[]> ExecPath, FDSpecifier, TestOutputFlag;
+    std::unique_ptr<char[]> ExecutorPath, FDSpecifier;
     {
-      ExecPath = std::make_unique<char[]>(ExecutablePath.size() + 1);
-      strcpy(ExecPath.get(), ExecutablePath.data());
-
-      const char *TestOutputFlagStr = "test-jitloadergdb";
-      TestOutputFlag = std::make_unique<char[]>(strlen(TestOutputFlagStr) + 1);
-      strcpy(TestOutputFlag.get(), TestOutputFlagStr);
+      ExecutorPath = std::make_unique<char[]>(ExecutablePath.size() + 1);
+      strcpy(ExecutorPath.get(), ExecutablePath.data());
 
       std::string FDSpecifierStr("filedescs=");
       FDSpecifierStr += utostr(ToExecutor[ReadEnd]);
@@ -112,15 +85,13 @@ launchLocalExecutor(StringRef ExecutablePath) {
       strcpy(FDSpecifier.get(), FDSpecifierStr.c_str());
     }
 
-    char *const Args[] = {ExecPath.get(), TestOutputFlag.get(),
-                          FDSpecifier.get(), nullptr};
-    int RC = execvp(ExecPath.get(), Args);
-    if (RC != 0)
-      return make_error<StringError>(
-          "Unable to launch out-of-process executor '" + ExecutablePath + "'\n",
-          inconvertibleErrorCode());
-
-    llvm_unreachable("Fork won't return in success case");
+    char *const Args[] = {ExecutorPath.get(), FDSpecifier.get(), nullptr};
+    int RC = execvp(ExecutorPath.get(), Args);
+    if (RC != 0) {
+      errs() << "unable to launch out-of-process executor \""
+             << ExecutorPath.get() << "\"\n";
+      exit(1);
+    }
   }
   // else we're the parent...
 
@@ -128,16 +99,16 @@ launchLocalExecutor(StringRef ExecutablePath) {
   close(ToExecutor[ReadEnd]);
   close(FromExecutor[WriteEnd]);
 
-  auto EPC = SimpleRemoteEPC::Create<FDSimpleRemoteEPCTransport>(
-      std::make_unique<DynamicThreadPoolTaskDispatcher>(std::nullopt),
-      SimpleRemoteEPC::Setup(),
-      FromExecutor[ReadEnd], ToExecutor[WriteEnd]);
-  if (!EPC)
-    return EPC.takeError();
+  auto S = SimpleRemoteEPC::Setup();
 
-  return std::make_pair(std::move(*EPC), static_cast<uint64_t>(ProcessID));
+  return SimpleRemoteEPC::Create<FDSimpleRemoteEPCTransport>(
+      std::make_unique<DynamicThreadPoolTaskDispatcher>(std::nullopt),
+      std::move(S), FromExecutor[ReadEnd], ToExecutor[WriteEnd]);
+#endif
 }
 
+#if LLVM_ON_UNIX && LLVM_ENABLE_THREADS
+
 static Expected<int> connectTCPSocketImpl(std::string Host,
                                           std::string PortStr) {
   addrinfo *AI;
@@ -150,18 +121,17 @@ static Expected<int> connectTCPSocketImpl(std::string Host,
     return make_error<StringError>(
         formatv("address resolution failed ({0})", gai_strerror(EC)),
         inconvertibleErrorCode());
-
   // Cycle through the returned addrinfo structures and connect to the first
   // reachable endpoint.
   int SockFD;
   addrinfo *Server;
   for (Server = AI; Server != nullptr; Server = Server->ai_next) {
-    // If socket fails, maybe it's because the address family is not supported.
-    // Skip to the next addrinfo structure.
+    // socket might fail, e.g. if the address family is not supported. Skip to
+    // the next addrinfo structure in such a case.
     if ((SockFD = socket(AI->ai_family, AI->ai_socktype, AI->ai_protocol)) < 0)
       continue;
 
-    // If connect works, we exit the loop with a working socket.
+    // If connect returns null, we exit the loop with a working socket.
     if (connect(SockFD, Server->ai_addr, Server->ai_addrlen) == 0)
       break;
 
@@ -169,17 +139,33 @@ static Expected<int> connectTCPSocketImpl(std::string Host,
   }
   freeaddrinfo(AI);
 
-  // Did we reach the end of the loop without connecting to a valid endpoint?
+  // If we reached the end of the loop without connecting to a valid endpoint,
+  // dump the last error that was logged in socket() or connect().
   if (Server == nullptr)
     return make_error<StringError>("invalid hostname",
                                    inconvertibleErrorCode());
 
   return SockFD;
 }
+#endif
 
 Expected<std::unique_ptr<SimpleRemoteEPC>>
 connectTCPSocket(StringRef NetworkAddress) {
-  auto CreateErr = [NetworkAddress](StringRef Details) {
+#ifndef LLVM_ON_UNIX
+  // FIXME: Add TCP support for Windows.
+  return make_error<StringError>("-" + NetworkAddress +
+                                     " not supported on non-unix platforms",
+                                 inconvertibleErrorCode());
+#elif !LLVM_ENABLE_THREADS
+  // Out of process mode using SimpleRemoteEPC depends on threads.
+  return make_error<StringError>(
+      "-" + NetworkAddress +
+          " requires threads, but LLVM was built with "
+          "LLVM_ENABLE_THREADS=Off",
+      inconvertibleErrorCode());
+#else
+
+  auto CreateErr = [NetworkAddress](Twine Details) {
     return make_error<StringError>(
         formatv("Failed to connect TCP socket '{0}': {1}", NetworkAddress,
                 Details),
@@ -189,20 +175,21 @@ connectTCPSocket(StringRef NetworkAddress) {
   StringRef Host, PortStr;
   std::tie(Host, PortStr) = NetworkAddress.split(':');
   if (Host.empty())
-    return CreateErr("host name cannot be empty");
+    return CreateErr("Host name for -" + NetworkAddress + " can not be empty");
   if (PortStr.empty())
-    return CreateErr("port cannot be empty");
+    return CreateErr("Port number in -" + NetworkAddress + " can not be empty");
   int Port = 0;
   if (PortStr.getAsInteger(10, Port))
-    return CreateErr("port number is not a valid integer");
+    return CreateErr("Port number '" + PortStr + "' is not a valid integer");
 
   Expected<int> SockFD = connectTCPSocketImpl(Host.str(), PortStr.str());
   if (!SockFD)
-    return CreateErr(toString(SockFD.takeError()));
+    return SockFD.takeError();
+
+  auto S = SimpleRemoteEPC::Setup();
 
   return SimpleRemoteEPC::Create<FDSimpleRemoteEPCTransport>(
       std::make_unique<DynamicThreadPoolTaskDispatcher>(std::nullopt),
-      SimpleRemoteEPC::Setup(), *SockFD);
-}
-
+      std::move(S), *SockFD, *SockFD);
 #endif
+}
\ No newline at end of file
diff --git a/clang/tools/clang-repl/ClangRepl.cpp b/clang/tools/clang-repl/ClangRepl.cpp
index 21359df01c270f..3502bec5f9f99c 100644
--- a/clang/tools/clang-repl/ClangRepl.cpp
+++ b/clang/tools/clang-repl/ClangRepl.cpp
@@ -10,7 +10,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "RemoteJITUtils.h"
+#include "clang/Interpreter/RemoteJITUtils.h"
 
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Frontend/CompilerInstance.h"
@@ -26,6 +26,7 @@
 #include "llvm/Support/ManagedStatic.h" // llvm_shutdown
 #include "llvm/Support/Signals.h"
 #include "llvm/Support/TargetSelect.h"
+#include "llvm/TargetParser/Host.h"
 #include <optional>
 
 #include "llvm/ExecutionEngine/Orc/Debugging/DebuggerSupport.h"
@@ -38,17 +39,21 @@
 LLVM_ATTRIBUTE_USED int __lsan_is_turned_off() { return 1; }
 #endif
 
+#define DEBUG_TYPE "clang-repl"
+
 static llvm::cl::opt<bool> CudaEnabled("cuda", llvm::cl::Hidden);
 static llvm::cl::opt<std::string> CudaPath("cuda-path", llvm::cl::Hidden);
 static llvm::cl::opt<std::string> OffloadArch("offload-arch", llvm::cl::Hidden);
-static llvm::cl::OptionCategory OOPCategory("Out-of-process Execution Options (Only available on MachO)");
-static llvm::cl::opt<std::string> OOPExecutor(
-    "oop-executor",
-    llvm::cl::desc("Launch an out-of-process executor to run code"),
-    llvm::cl::ValueOptional, llvm::cl::cat(OOPCategory));
+static llvm::cl::OptionCategory
+    OOPCategory("Out-of-process Execution Options");
+static llvm::cl::opt<std::string>
+    OOPExecutor("oop-executor",
+                llvm::cl::desc("Launch an out-of-process executor to run code"),
+                llvm::cl::ValueOptional, llvm::cl::cat(OOPCategory));
 static llvm::cl::opt<std::string> OOPExecutorConnectTCP(
-    "opp-connect",
-    llvm::cl::desc("Connect to an out-of-process executor through a TCP socket"),
+    "oop-executor-connect",
+    llvm::cl::desc(
+        "Connect to an out-of-process executor through a TCP socket"),
     llvm::cl::value_desc("<hostname>:<port>"));
 static llvm::cl::opt<std::string>
     OrcRuntimePath("orc-runtime", llvm::cl::desc("Path to the ORC runtime"),
@@ -62,7 +67,6 @@ static llvm::cl::opt<bool> OptHostSupportsJit("host-supports-jit",
 static llvm::cl::list<std::string> OptInputs(llvm::cl::Positional,
                                              llvm::cl::desc("[code to run]"));
 
-
 static llvm::Error sanitizeOopArguments(const char *ArgV0) {
   // Only one of -oop-executor and -oop-executor-connect can be used.
   if (!!OOPExecutor.getNumOccurrences() &&
@@ -74,17 +78,25 @@ static llvm::Error sanitizeOopArguments(const char *ArgV0) {
 
   // Out-of-process executors must run with the ORC runtime for destructor
   // support.
-  if (OrcRuntimePath.empty() &&
-      (OOPExecutor.getNumOccurrences() ||
-       OOPExecutorConnectTCP.getNumOccurrences()))
-    return llvm::make_error<llvm::StringError>(
-        "ORC runtime required",
-        llvm::inconvertibleErrorCode());
+  if (OrcRuntimePath.empty() && (OOPExecutor.getNumOccurrences() ||
+                                 OOPExecutorConnectTCP.getNumOccurrences())) {
+    llvm::SmallString<256> OrcPath(llvm::sys::fs::getMainExecutable(
+        ArgV0, reinterpret_cast<void *>(&sanitizeOopArguments)));
+    llvm::sys::path::remove_filename(OrcPath); // Remove clang-repl filename.
+    llvm::sys::path::remove_filename(OrcPath); // Remove ./bin directory.
+    llvm::Triple SystemTriple(llvm::sys::getProcessTriple());
+    llvm::StringRef Path;
+    if (SystemTriple.isOSBinFormatELF())
+      Path = "lib/clang/19/lib/x86_64-unknown-linux-gnu/liborc_rt.a";
+    else if (SystemTriple.isOSBinFormatMachO())
+      Path = "lib/clang/19/lib/darwin/liborc_rt_osx.a";
+    llvm::sys::path::append(OrcPath, Path);
+    OrcRuntimePath = OrcPath.str().str();
+  }
 
   // If -oop-executor was used but no value was specified then use a sensible
   // default.
-  if (!!OOPExecutor.getNumOccurrences() &&
-      OOPExecutor.empty()) {
+  if (!!OOPExecutor.getNumOccurrences() && OOPExecutor.empty()) {
     llvm::SmallString<256> OOPExecutorPath(llvm::sys::fs::getMainExecutable(
         ArgV0, reinterpret_cast<void *>(&sanitizeOopArguments)));
     llvm::sys::path::remove_filename(OOPExecutorPath);
@@ -231,21 +243,19 @@ int main(int argc, const char **argv) {
 
   ExitOnErr(sanitizeOopArguments(argv[0]));
 
-
   std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC;
-    // std::unique_ptr<llvm::orc::TaskDispatcher> D = nullptr;
-
-    // D = std::make_unique<llvm::orc::DynamicThreadPoolTaskDispatcher>(std::nullopt);
-
-    // if (auto EPCOrErr =
-    //         llvm::orc::SelfExecutorProcessControl::Create(nullptr, std::move(D), nullptr))
-    //   EPC = std::move(*EPCOrErr);
   if (OOPExecutor.getNumOccurrences()) {
     // Launch an out-of-process executor locally in a child process.
-    int PID;
-    std::tie(EPC, PID) = ExitOnErr(launchLocalExecutor(OOPExecutor));
+    EPC = ExitOnErr(launchExecutor(OOPExecutor));
+  } else if (OOPExecutorConnectTCP.getNumOccurrences()) {
+    EPC = ExitOnErr(connectTCPSocket(OOPExecutorConnectTCP));
+  }
+
+  std::unique_ptr<llvm::orc::LLJITBuilder> JB;
+  if (EPC) {
     CB.SetTargetTriple(EPC->getTargetTriple().getTriple());
-    llvm::outs() << "executor process id = " << PID << "\n";
+    JB = ExitOnErr(
+        clang::Interpreter::createLLJITBuilder(std::move(EPC), OrcRuntimePath));
   }
 
   // FIXME: Investigate if we could use runToolOnCodeWithArgs from tooling. It
@@ -279,15 +289,14 @@ int main(int argc, const char **argv) {
       auto CudaRuntimeLibPath = CudaPath + "/lib/libcudart.so";
       ExitOnErr(Interp->LoadDynamicLibrary(CudaRuntimeLibPath.c_str()));
     }
-  } else if (EPC) {
-    Interp = ExitOnErr(
-        clang::Interpreter::createWithOOPExecutor(std::move(CI),
-                                                  std::move(EPC),
-                                                  OrcRuntimePath));
+  } else if (JB) {
+    Interp =
+        ExitOnErr(clang::Interpreter::create(std::move(CI), std::move(JB)));
   } else
     Interp = ExitOnErr(clang::Interpreter::create(std::move(CI)));
 
   bool HasError = false;
+
   for (const std::string &input : OptInputs) {
     if (auto Err = Interp->ParseAndExecute(input)) {
       llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), "error: ");

>From 1fdff47ad179ffb7014cc8fce4a97cac4d833976 Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Wed, 17 Jul 2024 10:40:53 +0530
Subject: [PATCH 3/5] Add shared memory support

---
 .../clang/Interpreter/RemoteJITUtils.h        |  6 +-
 clang/lib/Interpreter/RemoteJITUtils.cpp      | 69 ++++++++++++++++++-
 clang/tools/clang-repl/ClangRepl.cpp          | 16 ++++-
 3 files changed, 85 insertions(+), 6 deletions(-)

diff --git a/clang/include/clang/Interpreter/RemoteJITUtils.h b/clang/include/clang/Interpreter/RemoteJITUtils.h
index c0f3f424629fbd..8705a3b1f669de 100644
--- a/clang/include/clang/Interpreter/RemoteJITUtils.h
+++ b/clang/include/clang/Interpreter/RemoteJITUtils.h
@@ -25,12 +25,14 @@
 #include <string>
 
 llvm::Expected<std::unique_ptr<llvm::orc::SimpleRemoteEPC>>
-launchExecutor(llvm::StringRef ExecutablePath);
+launchExecutor(llvm::StringRef ExecutablePath, bool UseSharedMemory,
+               llvm::StringRef SlabAllocateSizeString);
 
 /// Create a JITLinkExecutor that connects to the given network address
 /// through a TCP socket. A valid NetworkAddress provides hostname and port,
 /// e.g. localhost:20000.
 llvm::Expected<std::unique_ptr<llvm::orc::SimpleRemoteEPC>>
-connectTCPSocket(llvm::StringRef NetworkAddress);
+connectTCPSocket(llvm::StringRef NetworkAddress, bool UseSharedMemory,
+                 llvm::StringRef SlabAllocateSizeString);
 
 #endif // LLVM_CLANG_INTERPRETER_REMOTEJITUTILS_H
diff --git a/clang/lib/Interpreter/RemoteJITUtils.cpp b/clang/lib/Interpreter/RemoteJITUtils.cpp
index 75f2ccf069729a..a103307ebf0eae 100644
--- a/clang/lib/Interpreter/RemoteJITUtils.cpp
+++ b/clang/lib/Interpreter/RemoteJITUtils.cpp
@@ -12,6 +12,8 @@
 #include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h"
 #include "llvm/ExecutionEngine/Orc/EPCDebugObjectRegistrar.h"
 #include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"
+#include "llvm/ExecutionEngine/Orc/MapperJITLinkMemoryManager.h"
+#include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
 #include "llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h"
 #include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
 #include "llvm/Support/FileSystem.h"
@@ -27,8 +29,62 @@
 using namespace llvm;
 using namespace llvm::orc;
 
+static ExitOnError ExitOnErr;
+
+Expected<uint64_t> getSlabAllocSize(StringRef SizeString) {
+  SizeString = SizeString.trim();
+
+  uint64_t Units = 1024;
+
+  if (SizeString.ends_with_insensitive("kb"))
+    SizeString = SizeString.drop_back(2).rtrim();
+  else if (SizeString.ends_with_insensitive("mb")) {
+    Units = 1024 * 1024;
+    SizeString = SizeString.drop_back(2).rtrim();
+  } else if (SizeString.ends_with_insensitive("gb")) {
+    Units = 1024 * 1024 * 1024;
+    SizeString = SizeString.drop_back(2).rtrim();
+  }
+
+  uint64_t SlabSize = 0;
+  if (SizeString.getAsInteger(10, SlabSize))
+    return make_error<StringError>("Invalid numeric format for slab size",
+                                   inconvertibleErrorCode());
+
+  return SlabSize * Units;
+}
+
+Expected<std::unique_ptr<jitlink::JITLinkMemoryManager>>
+createSharedMemoryManager(SimpleRemoteEPC &SREPC, StringRef SlabAllocateSizeString) {
+  SharedMemoryMapper::SymbolAddrs SAs;
+  if (auto Err = SREPC.getBootstrapSymbols(
+          {{SAs.Instance, rt::ExecutorSharedMemoryMapperServiceInstanceName},
+           {SAs.Reserve,
+            rt::ExecutorSharedMemoryMapperServiceReserveWrapperName},
+           {SAs.Initialize,
+            rt::ExecutorSharedMemoryMapperServiceInitializeWrapperName},
+           {SAs.Deinitialize,
+            rt::ExecutorSharedMemoryMapperServiceDeinitializeWrapperName},
+           {SAs.Release,
+            rt::ExecutorSharedMemoryMapperServiceReleaseWrapperName}}))
+    return std::move(Err);
+
+#ifdef _WIN32
+  size_t SlabSize = 1024 * 1024;
+#else
+  size_t SlabSize = 1024 * 1024 * 1024;
+#endif
+
+  if (!SlabAllocateSizeString.empty())
+    SlabSize = ExitOnErr(getSlabAllocSize(SlabAllocateSizeString));
+
+  return MapperJITLinkMemoryManager::CreateWithMapper<SharedMemoryMapper>(
+      SlabSize, SREPC, SAs);
+}
+
 Expected<std::unique_ptr<SimpleRemoteEPC>>
-launchExecutor(StringRef ExecutablePath) {
+launchExecutor(StringRef ExecutablePath, bool UseSharedMemory,
+               llvm::StringRef SlabAllocateSizeString) {
 #ifndef LLVM_ON_UNIX
   // FIXME: Add support for Windows.
   return make_error<StringError>("-" + ExecutablePath +
@@ -100,6 +156,10 @@ launchExecutor(StringRef ExecutablePath) {
   close(FromExecutor[WriteEnd]);
 
   auto S = SimpleRemoteEPC::Setup();
+  if (UseSharedMemory)
+    S.CreateMemoryManager = [SlabAllocateSizeString](SimpleRemoteEPC &EPC) {
+      return createSharedMemoryManager(EPC, SlabAllocateSizeString);
+    };
 
   return SimpleRemoteEPC::Create<FDSimpleRemoteEPCTransport>(
       std::make_unique<DynamicThreadPoolTaskDispatcher>(std::nullopt),
@@ -150,7 +210,8 @@ static Expected<int> connectTCPSocketImpl(std::string Host,
 #endif
 
 Expected<std::unique_ptr<SimpleRemoteEPC>>
-connectTCPSocket(StringRef NetworkAddress) {
+connectTCPSocket(StringRef NetworkAddress, bool UseSharedMemory,
+                 llvm::StringRef SlabAllocateSizeString) {
 #ifndef LLVM_ON_UNIX
   // FIXME: Add TCP support for Windows.
   return make_error<StringError>("-" + NetworkAddress +
@@ -187,6 +248,10 @@ connectTCPSocket(StringRef NetworkAddress) {
     return SockFD.takeError();
 
   auto S = SimpleRemoteEPC::Setup();
+  if (UseSharedMemory)
+    S.CreateMemoryManager = [SlabAllocateSizeString](SimpleRemoteEPC &EPC) {
+      return createSharedMemoryManager(EPC, SlabAllocateSizeString);
+    };
 
   return SimpleRemoteEPC::Create<FDSimpleRemoteEPCTransport>(
       std::make_unique<DynamicThreadPoolTaskDispatcher>(std::nullopt),
diff --git a/clang/tools/clang-repl/ClangRepl.cpp b/clang/tools/clang-repl/ClangRepl.cpp
index 3502bec5f9f99c..6099dfb9af98b1 100644
--- a/clang/tools/clang-repl/ClangRepl.cpp
+++ b/clang/tools/clang-repl/ClangRepl.cpp
@@ -46,6 +46,12 @@ static llvm::cl::opt<std::string> CudaPath("cuda-path", llvm::cl::Hidden);
 static llvm::cl::opt<std::string> OffloadArch("offload-arch", llvm::cl::Hidden);
 static llvm::cl::OptionCategory
     OOPCategory("Out-of-process Execution Options");
+static llvm::cl::opt<std::string> SlabAllocateSizeString(
+    "slab-allocate",
+    llvm::cl::desc("Allocate from a slab of the given size "
+             "(allowable suffixes: Kb, Mb, Gb. default = "
+             "Kb)"),
+    llvm::cl::init(""), llvm::cl::cat(OOPCategory));
 static llvm::cl::opt<std::string>
     OOPExecutor("oop-executor",
                 llvm::cl::desc("Launch an out-of-process executor to run code"),
@@ -58,6 +64,10 @@ static llvm::cl::opt<std::string> OOPExecutorConnectTCP(
 static llvm::cl::opt<std::string>
     OrcRuntimePath("orc-runtime", llvm::cl::desc("Path to the ORC runtime"),
                    llvm::cl::cat(OOPCategory));
+static llvm::cl::opt<bool> UseSharedMemory(
+    "use-shared-memory",
+    llvm::cl::desc("Use shared memory to transfer generated code and data"),
+    llvm::cl::init(false), llvm::cl::cat(OOPCategory));
 static llvm::cl::list<std::string>
     ClangArgs("Xcc",
               llvm::cl::desc("Argument to pass to the CompilerInvocation"),
@@ -246,9 +256,11 @@ int main(int argc, const char **argv) {
   std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC;
   if (OOPExecutor.getNumOccurrences()) {
     // Launch an out-of-process executor locally in a child process.
-    EPC = ExitOnErr(launchExecutor(OOPExecutor));
+    EPC = ExitOnErr(
+        launchExecutor(OOPExecutor, UseSharedMemory, SlabAllocateSizeString));
   } else if (OOPExecutorConnectTCP.getNumOccurrences()) {
-    EPC = ExitOnErr(connectTCPSocket(OOPExecutorConnectTCP));
+    EPC = ExitOnErr(connectTCPSocket(
+        OOPExecutorConnectTCP, UseSharedMemory, SlabAllocateSizeString));
   }
 
   std::unique_ptr<llvm::orc::LLJITBuilder> JB;

>From 97e314e98d4c2235490067f661c7dafb436fcec3 Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Sun, 29 Sep 2024 14:26:58 +0530
Subject: [PATCH 4/5] Fix code format

---
 clang/lib/Interpreter/RemoteJITUtils.cpp |  3 ++-
 clang/tools/clang-repl/ClangRepl.cpp     | 11 +++++------
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/clang/lib/Interpreter/RemoteJITUtils.cpp b/clang/lib/Interpreter/RemoteJITUtils.cpp
index a103307ebf0eae..450748eb6df445 100644
--- a/clang/lib/Interpreter/RemoteJITUtils.cpp
+++ b/clang/lib/Interpreter/RemoteJITUtils.cpp
@@ -55,7 +55,8 @@ Expected<uint64_t> getSlabAllocSize(StringRef SizeString) {
 }
 
 Expected<std::unique_ptr<jitlink::JITLinkMemoryManager>>
-createSharedMemoryManager(SimpleRemoteEPC &SREPC, StringRef SlabAllocateSizeString) {
+createSharedMemoryManager(SimpleRemoteEPC &SREPC,
+                          StringRef SlabAllocateSizeString) {
   SharedMemoryMapper::SymbolAddrs SAs;
   if (auto Err = SREPC.getBootstrapSymbols(
           {{SAs.Instance, rt::ExecutorSharedMemoryMapperServiceInstanceName},
diff --git a/clang/tools/clang-repl/ClangRepl.cpp b/clang/tools/clang-repl/ClangRepl.cpp
index 6099dfb9af98b1..68c0d309a158c3 100644
--- a/clang/tools/clang-repl/ClangRepl.cpp
+++ b/clang/tools/clang-repl/ClangRepl.cpp
@@ -44,13 +44,12 @@ LLVM_ATTRIBUTE_USED int __lsan_is_turned_off() { return 1; }
 static llvm::cl::opt<bool> CudaEnabled("cuda", llvm::cl::Hidden);
 static llvm::cl::opt<std::string> CudaPath("cuda-path", llvm::cl::Hidden);
 static llvm::cl::opt<std::string> OffloadArch("offload-arch", llvm::cl::Hidden);
-static llvm::cl::OptionCategory
-    OOPCategory("Out-of-process Execution Options");
+static llvm::cl::OptionCategory OOPCategory("Out-of-process Execution Options");
 static llvm::cl::opt<std::string> SlabAllocateSizeString(
     "slab-allocate",
     llvm::cl::desc("Allocate from a slab of the given size "
-             "(allowable suffixes: Kb, Mb, Gb. default = "
-             "Kb)"),
+                   "(allowable suffixes: Kb, Mb, Gb. default = "
+                   "Kb)"),
     llvm::cl::init(""), llvm::cl::cat(OOPCategory));
 static llvm::cl::opt<std::string>
     OOPExecutor("oop-executor",
@@ -259,8 +258,8 @@ int main(int argc, const char **argv) {
     EPC = ExitOnErr(
         launchExecutor(OOPExecutor, UseSharedMemory, SlabAllocateSizeString));
   } else if (OOPExecutorConnectTCP.getNumOccurrences()) {
-    EPC = ExitOnErr(connectTCPSocket(
-        OOPExecutorConnectTCP, UseSharedMemory, SlabAllocateSizeString));
+    EPC = ExitOnErr(connectTCPSocket(OOPExecutorConnectTCP, UseSharedMemory,
+                                     SlabAllocateSizeString));
   }
 
   std::unique_ptr<llvm::orc::LLJITBuilder> JB;

>From fa27f86f0630da403f1b5143ac36a9a6ed934af7 Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Sun, 29 Sep 2024 14:53:48 +0530
Subject: [PATCH 5/5] Fix orc runtime path

---
 clang/tools/clang-repl/ClangRepl.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/tools/clang-repl/ClangRepl.cpp b/clang/tools/clang-repl/ClangRepl.cpp
index 68c0d309a158c3..9f4d4cb69bb467 100644
--- a/clang/tools/clang-repl/ClangRepl.cpp
+++ b/clang/tools/clang-repl/ClangRepl.cpp
@@ -96,9 +96,9 @@ static llvm::Error sanitizeOopArguments(const char *ArgV0) {
     llvm::Triple SystemTriple(llvm::sys::getProcessTriple());
     llvm::StringRef Path;
     if (SystemTriple.isOSBinFormatELF())
-      Path = "lib/clang/19/lib/x86_64-unknown-linux-gnu/liborc_rt.a";
+      Path = "lib/clang/20/lib/x86_64-unknown-linux-gnu/liborc_rt.a";
     else if (SystemTriple.isOSBinFormatMachO())
-      Path = "lib/clang/19/lib/darwin/liborc_rt_osx.a";
+      Path = "lib/clang/20/lib/darwin/liborc_rt_osx.a";
     llvm::sys::path::append(OrcPath, Path);
     OrcRuntimePath = OrcPath.str().str();
   }



More information about the cfe-commits mailing list