[clang] [llvm] [compiler-rt] [clang-repl] [ORC] Add support for out-of-process execution on ELF (PR #79936)

via cfe-commits cfe-commits at lists.llvm.org
Mon Jan 29 19:06:36 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: None (jameshu15869)

<details>
<summary>Changes</summary>

This PR adds initial support for out-of-process execution through llvm-jitlink-executor to clang-repl on ELF. The out-of-process executor can be invoked with "-oop-executor" or "-oop-executor-connect=<host>" on ELF platforms. Now, clang-repl depends upon the ORC runtime to support static initializers and deinitializers. 

This PR modifies the ORC ELFNix platform to allow JITDylibs to be reinitialized through the "__orc_rt_jit_dlupdate" function, since clang-repl incrementally adds static initializers to a single JITDylib. 

On x86_64 linux, the following tests pass with the out-of-process executor flag. However, a new new testing file (out-of-process.cpp) was added with select tests to restrict the test to ELF only. 

- code-undo.cpp
- const.cpp
- execute-stmts.cpp
- execute-weak.cpp
- global-dtor.cpp
- incremental-mode.cpp
- inline-virtual.cpp
- lambda.cpp
- multiline.cpp
- sanity.cpp

---

Patch is 28.44 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/79936.diff


13 Files Affected:

- (modified) clang/include/clang/Interpreter/Interpreter.h (+10) 
- (modified) clang/lib/Interpreter/IncrementalExecutor.cpp (+29) 
- (modified) clang/lib/Interpreter/IncrementalExecutor.h (+3) 
- (modified) clang/lib/Interpreter/Interpreter.cpp (+33-5) 
- (modified) clang/test/Interpreter/dynamic-library.cpp (+1) 
- (added) clang/test/Interpreter/out-of-process.cpp (+61) 
- (modified) clang/tools/clang-repl/CMakeLists.txt (+2) 
- (modified) clang/tools/clang-repl/ClangRepl.cpp (+230) 
- (modified) compiler-rt/lib/orc/dlfcn_wrapper.cpp (+14) 
- (modified) compiler-rt/lib/orc/elfnix_platform.cpp (+39) 
- (modified) compiler-rt/lib/orc/elfnix_platform.h (+1) 
- (modified) llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp (+9-1) 
- (modified) llvm/lib/ExecutionEngine/Orc/LLJIT.cpp (+23-1) 


``````````diff
diff --git a/clang/include/clang/Interpreter/Interpreter.h b/clang/include/clang/Interpreter/Interpreter.h
index 43573fb1a4b89..314beb7b72dac 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/ExecutorProcessControl.h"
 #include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
 #include "llvm/Support/Error.h"
 #include <memory>
@@ -81,6 +82,11 @@ class Interpreter {
   // An optional parser for CUDA offloading
   std::unique_ptr<IncrementalParser> DeviceParser;
 
+  // An optional parameter for an out-of-process executor
+  std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC;
+
+  llvm::StringRef OrcRuntimePath;
+
   Interpreter(std::unique_ptr<CompilerInstance> CI, llvm::Error &Err);
 
   llvm::Error CreateExecutor();
@@ -98,6 +104,10 @@ class Interpreter {
   static llvm::Expected<std::unique_ptr<Interpreter>>
   createWithCUDA(std::unique_ptr<CompilerInstance> CI,
                  std::unique_ptr<CompilerInstance> DCI);
+  static llvm::Expected<std::unique_ptr<Interpreter>>
+  createWithOutOfProcessExecutor(
+      std::unique_ptr<CompilerInstance> CI,
+      std::unique_ptr<llvm::orc::ExecutorProcessControl> EI, llvm::StringRef OrcRuntimePath);
   const ASTContext &getASTContext() const;
   ASTContext &getASTContext();
   const CompilerInstance *getCompilerInstance() const;
diff --git a/clang/lib/Interpreter/IncrementalExecutor.cpp b/clang/lib/Interpreter/IncrementalExecutor.cpp
index 40bcef94797d4..30b24caa4a594 100644
--- a/clang/lib/Interpreter/IncrementalExecutor.cpp
+++ b/clang/lib/Interpreter/IncrementalExecutor.cpp
@@ -63,6 +63,35 @@ IncrementalExecutor::IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC,
   }
 }
 
+IncrementalExecutor::IncrementalExecutor(
+    llvm::orc::ThreadSafeContext &TSC, llvm::Error &Err,
+    const clang::TargetInfo &TI,
+    std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC, llvm::StringRef OrcRuntimePath)
+    : TSCtx(TSC) {
+  using namespace llvm::orc;
+  llvm::ErrorAsOutParameter EAO(&Err);
+
+  auto JTMB = JITTargetMachineBuilder(TI.getTriple());
+  JTMB.addFeatures(TI.getTargetOpts().Features);
+  LLJITBuilder Builder;
+  Builder.setJITTargetMachineBuilder(JTMB);
+  Builder.setPrePlatformSetup([](LLJIT &J) {
+    // Try to enable debugging of JIT'd code (only works with JITLink for
+    // ELF and MachO).
+    consumeError(enableDebuggerSupport(J));
+    return llvm::Error::success();
+  });
+  Builder.setExecutorProcessControl(std::move(EPC));
+  Builder.setPlatformSetUp(llvm::orc::ExecutorNativePlatform(OrcRuntimePath.str()));
+
+  if (auto JitOrErr = Builder.create()) {
+    Jit = std::move(*JitOrErr);
+  } else {
+    Err = JitOrErr.takeError();
+    return;
+  }
+}
+
 IncrementalExecutor::~IncrementalExecutor() {}
 
 llvm::Error IncrementalExecutor::addModule(PartialTranslationUnit &PTU) {
diff --git a/clang/lib/Interpreter/IncrementalExecutor.h b/clang/lib/Interpreter/IncrementalExecutor.h
index dd0a210a06141..a73ba9035182c 100644
--- a/clang/lib/Interpreter/IncrementalExecutor.h
+++ b/clang/lib/Interpreter/IncrementalExecutor.h
@@ -46,6 +46,9 @@ class IncrementalExecutor {
 
   IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC, llvm::Error &Err,
                       const clang::TargetInfo &TI);
+  IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC, llvm::Error &Err,
+                      const clang::TargetInfo &TI,
+                      std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC, llvm::StringRef OrcRuntimePath);
   ~IncrementalExecutor();
 
   llvm::Error addModule(PartialTranslationUnit &PTU);
diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp
index 7968c62cbd3e7..13e6be3b54abc 100644
--- a/clang/lib/Interpreter/Interpreter.cpp
+++ b/clang/lib/Interpreter/Interpreter.cpp
@@ -36,6 +36,7 @@
 #include "clang/Lex/PreprocessorOptions.h"
 #include "clang/Sema/Lookup.h"
 #include "llvm/ExecutionEngine/JITSymbol.h"
+#include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"
 #include "llvm/ExecutionEngine/Orc/LLJIT.h"
 #include "llvm/IR/Module.h"
 #include "llvm/Support/Errc.h"
@@ -242,6 +243,15 @@ Interpreter::~Interpreter() {
           llvm::Twine("Failed to clean up IncrementalExecutor: ") +
           toString(std::move(Err)));
   }
+
+    if (EPC) {
+    if (auto Err = EPC->disconnect()) {
+      llvm::report_fatal_error(
+          llvm::Twine("Failed to clean up EPC (IncrementalExecutor has not yet "
+                      "been created): ") +
+          toString(std::move(Err)));
+    }
+  }
 }
 
 // These better to put in a runtime header but we can't. This is because we
@@ -315,6 +325,20 @@ Interpreter::createWithCUDA(std::unique_ptr<CompilerInstance> CI,
   return Interp;
 }
 
+
+llvm::Expected<std::unique_ptr<Interpreter>>
+Interpreter::createWithOutOfProcessExecutor(
+    std::unique_ptr<CompilerInstance> CI,
+    std::unique_ptr<llvm::orc::ExecutorProcessControl> EI, llvm::StringRef OrcRuntimePath) {
+  auto Interp = create(std::move(CI));
+  if (auto E = Interp.takeError()) {
+    return std::move(E);
+  }
+  (*Interp)->EPC = std::move(EI);
+  (*Interp)->OrcRuntimePath = OrcRuntimePath;
+  return Interp;
+}
+
 const CompilerInstance *Interpreter::getCompilerInstance() const {
   return IncrParser->getCI();
 }
@@ -363,7 +387,13 @@ llvm::Error Interpreter::CreateExecutor() {
   const clang::TargetInfo &TI =
       getCompilerInstance()->getASTContext().getTargetInfo();
   llvm::Error Err = llvm::Error::success();
-  auto Executor = std::make_unique<IncrementalExecutor>(*TSCtx, Err, TI);
+  std::unique_ptr<IncrementalExecutor> Executor;
+  if (EPC) {
+    Executor =
+        std::make_unique<IncrementalExecutor>(*TSCtx, Err, TI, std::move(EPC), OrcRuntimePath);
+  } else {
+    Executor = std::make_unique<IncrementalExecutor>(*TSCtx, Err, TI);
+  }
   if (!Err)
     IncrExecutor = std::move(Executor);
 
@@ -460,10 +490,8 @@ llvm::Error Interpreter::LoadDynamicLibrary(const char *name) {
   if (!EE)
     return EE.takeError();
 
-  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/test/Interpreter/dynamic-library.cpp b/clang/test/Interpreter/dynamic-library.cpp
index 6c4621f729c1c..c2d186f71ebfe 100644
--- a/clang/test/Interpreter/dynamic-library.cpp
+++ b/clang/test/Interpreter/dynamic-library.cpp
@@ -15,6 +15,7 @@
 // }
 
 // RUN: cat %s | env LD_LIBRARY_PATH=%S/Inputs:$LD_LIBRARY_PATH clang-repl | FileCheck %s
+// RUN: cat %s | env LD_LIBRARY_PATH=%S/Inputs:$LD_LIBRARY_PATH clang-repl -oop-executor | FileCheck %s
 
 extern "C" int printf(const char* format, ...);
 
diff --git a/clang/test/Interpreter/out-of-process.cpp b/clang/test/Interpreter/out-of-process.cpp
new file mode 100644
index 0000000000000..ddbf86ec65881
--- /dev/null
+++ b/clang/test/Interpreter/out-of-process.cpp
@@ -0,0 +1,61 @@
+// REQUIRES: host-supports-jit, x86_64-linux
+// RUN: cat %s | clang-repl | FileCheck %s
+// RUN: cat %s | clang-repl -oop-executor | FileCheck %s
+
+extern "C" int printf(const char *, ...);
+
+// Test code undo.
+int x1 = 0;
+int x2 = 42;
+%undo
+int x2 = 24;
+auto r1 = printf("x1 = %d\n", x1);
+// CHECK: x1 = 0
+auto r2 = printf("x2 = %d\n", x2);
+// CHECK-NEXT: x2 = 24
+int foo() { return 1; }
+%undo
+int foo() { return 2; }
+auto r3 = printf("foo() = %d\n", foo());
+// CHECK-NEXT: foo() = 2
+inline int bar() { return 42;}
+auto r4 = bar();
+%undo
+auto r5 = bar();
+
+// Test weak execution.
+int __attribute__((weak)) weak_bar() { return 42; }
+auto r6 = printf("bar() = %d\n", weak_bar());
+// CHECK: bar() = 42
+int a = 12;
+static __typeof(a) b __attribute__((__weakref__("a")));
+int c = b;
+
+// Test lambdas.
+auto l1 = []() { printf("ONE\n"); return 42; };
+auto l2 = []() { printf("TWO\n"); return 17; };
+auto lambda_r1 = l1();
+// CHECK: ONE
+auto lambda_r2 = l2();
+// CHECK: TWO
+auto lambda_r3 = l2();
+// CHECK: TWO
+
+// Test multiline.
+int i = \
+  12;
+printf("i=%d\n", i);
+// CHECK: i=12
+void f(int x) \ 
+{                                               \
+  printf("x=\
+          %d", x); \
+}
+f(i);
+// CHECK: x=12
+
+// Test global destructor.
+struct D { float f = 1.0; D *m = nullptr; D(){} ~D() { printf("D[f=%f, m=0x%llx]\n", f, reinterpret_cast<unsigned long long>(m)); }} d;
+// CHECK: D[f=1.000000, m=0x0]
+
+%quit
diff --git a/clang/tools/clang-repl/CMakeLists.txt b/clang/tools/clang-repl/CMakeLists.txt
index 2ccbe292fd49e..adf4ea4180cba 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 5663c2c5a6c92..1c43e7b503646 100644
--- a/clang/tools/clang-repl/ClangRepl.cpp
+++ b/clang/tools/clang-repl/ClangRepl.cpp
@@ -16,13 +16,21 @@
 #include "clang/Interpreter/CodeCompletion.h"
 #include "clang/Interpreter/Interpreter.h"
 
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
 #include "llvm/ExecutionEngine/Orc/LLJIT.h"
+#include "llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h"
 #include "llvm/LineEditor/LineEditor.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/ManagedStatic.h" // llvm_shutdown
 #include "llvm/Support/Signals.h"
 #include "llvm/Support/TargetSelect.h"
+#include "llvm/TargetParser/Host.h"
+#include <netdb.h>
 #include <optional>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 // Disable LSan for this test.
 // FIXME: Re-enable once we can assume GCC 13.2 or higher.
@@ -45,6 +53,21 @@ 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::cl::OptionCategory OOPCategory(
+    "Out-of-process Execution Options (Only available on ELF/Linux)");
+static llvm::cl::opt<std::string> OutOfProcessExecutor(
+    "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> OutOfProcessExecutorConnect(
+    "oop-executor-connect",
+    llvm::cl::desc("Connect to an out-of-process executor via TCP"),
+    llvm::cl::cat(OOPCategory));
+static llvm::cl::opt<std::string> OrcRuntimePath(
+    "orc-runtime",
+    llvm::cl::desc("Path to the ORC runtime"),
+    llvm::cl::cat(OOPCategory));
+
 static void LLVMErrorHandler(void *UserData, const char *Message,
                              bool GenCrashDiag) {
   auto &Diags = *static_cast<clang::DiagnosticsEngine *>(UserData);
@@ -143,6 +166,201 @@ ReplListCompleter::operator()(llvm::StringRef Buffer, size_t Pos,
   return Comps;
 }
 
+static llvm::Error sanitizeOopArguments(const char *ArgV0) {
+  llvm::Triple SystemTriple(llvm::sys::getProcessTriple());
+  if ((OutOfProcessExecutor.getNumOccurrences() ||
+       OutOfProcessExecutorConnect.getNumOccurrences()) &&
+      (!SystemTriple.isOSBinFormatELF()))
+    return llvm::make_error<llvm::StringError>(
+        "Out-process-executors are currently only supported on ELF",
+        llvm::inconvertibleErrorCode());
+
+  // Only one of -oop-executor and -oop-executor-connect can be used.
+  if (!!OutOfProcessExecutor.getNumOccurrences() &&
+      !!OutOfProcessExecutorConnect.getNumOccurrences())
+    return llvm::make_error<llvm::StringError>(
+        "Only one of -" + OutOfProcessExecutor.ArgStr + " and -" +
+            OutOfProcessExecutorConnect.ArgStr + " can be specified",
+        llvm::inconvertibleErrorCode());
+
+  // If -oop-executor was used but no value was specified then use a sensible
+  // default.
+  if (!!OutOfProcessExecutor.getNumOccurrences() &&
+      OutOfProcessExecutor.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");
+    OutOfProcessExecutor = OOPExecutorPath.str().str();
+  }
+
+  // Out-of-process executors must run with the ORC runtime for destructor support.
+  if (OrcRuntimePath.empty() && (OutOfProcessExecutor.getNumOccurrences() || OutOfProcessExecutorConnect.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::sys::path::append(OrcPath, "lib/clang/18/lib/x86_64-unknown-linux-gnu/liborc_rt.a");
+    OrcRuntimePath = OrcPath.str().str();
+  }
+
+  return llvm::Error::success();
+}
+
+static llvm::Expected<std::unique_ptr<llvm::orc::ExecutorProcessControl>>
+launchExecutor() {
+  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 llvm::make_error<llvm::StringError>(
+        "Unable to create pipe for executor", llvm::inconvertibleErrorCode());
+
+  ChildPID = fork();
+
+  if (ChildPID == 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[]> ExecutorPath, FDSpecifier;
+    {
+      ExecutorPath = std::make_unique<char[]>(OutOfProcessExecutor.size() + 1);
+      strcpy(ExecutorPath.get(), OutOfProcessExecutor.data());
+
+      std::string FDSpecifierStr("filedescs=");
+      FDSpecifierStr += llvm::utostr(ToExecutor[ReadEnd]);
+      FDSpecifierStr += ',';
+      FDSpecifierStr += llvm::utostr(FromExecutor[WriteEnd]);
+      FDSpecifier = std::make_unique<char[]>(FDSpecifierStr.size() + 1);
+      strcpy(FDSpecifier.get(), FDSpecifierStr.c_str());
+    }
+
+    char *const Args[] = {ExecutorPath.get(), FDSpecifier.get(), nullptr};
+    int RC = execvp(ExecutorPath.get(), Args);
+    if (RC != 0) {
+      llvm::errs() << "unable to launch out-of-process executor \""
+                   << ExecutorPath.get() << "\"\n";
+      exit(1);
+    }
+  }
+  // else we're the parent...
+
+  // Close the child ends of the pipes
+  close(ToExecutor[ReadEnd]);
+  close(FromExecutor[WriteEnd]);
+
+  auto S = llvm::orc::SimpleRemoteEPC::Setup();
+
+  return llvm::orc::SimpleRemoteEPC::Create<
+      llvm::orc::FDSimpleRemoteEPCTransport>(
+      std::make_unique<llvm::orc::DynamicThreadPoolTaskDispatcher>(),
+      std::move(S), FromExecutor[ReadEnd], ToExecutor[WriteEnd]);
+}
+
+#if LLVM_ON_UNIX && LLVM_ENABLE_THREADS
+static llvm::Error createTCPSocketError(llvm::Twine Details) {
+  return llvm::make_error<llvm::StringError>(
+      formatv("Failed to connect TCP socket '{0}': {1}",
+              OutOfProcessExecutorConnect, Details),
+      llvm::inconvertibleErrorCode());
+}
+
+static llvm::Expected<int> connectTCPSocket(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 createTCPSocketError("Address resolution failed (" +
+                                llvm::StringRef(gai_strerror(EC)) + ")");
+
+  // 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) {
+    // 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 returns null, we exit the loop with a working socket.
+    if (connect(SockFD, Server->ai_addr, Server->ai_addrlen) == 0)
+      break;
+
+    close(SockFD);
+  }
+  freeaddrinfo(AI);
+
+  // 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 createTCPSocketError(std::strerror(errno));
+
+  return SockFD;
+}
+#endif
+
+static llvm::Expected<std::unique_ptr<llvm::orc::ExecutorProcessControl>>
+connectToExecutor() {
+#ifndef LLVM_ON_UNIX
+  // FIXME: Add TCP support for Windows.
+  return llvm::make_error<StringError>(
+      "-" + OutOfProcessExecutorConnect.ArgStr +
+          " not supported on non-unix platforms",
+      inconvertibleErrorCode());
+#elif !LLVM_ENABLE_THREADS
+  // Out of process mode using SimpleRemoteEPC depends on threads.
+  return llvm::make_error<StringError>(
+      "-" + OutOfProcessExecutorConnect.ArgStr +
+          " requires threads, but LLVM was built with "
+          "LLVM_ENABLE_THREADS=Off",
+      inconvertibleErrorCode());
+#else
+
+  llvm::StringRef Host, PortStr;
+  std::tie(Host, PortStr) =
+      llvm::StringRef(OutOfProcessExecutorConnect).split(':');
+  if (Host.empty())
+    return createTCPSocketError("Host name for -" +
+                                OutOfProcessExecutorConnect.ArgStr +
+                                " can not be empty");
+  if (PortStr.empty())
+    return createTCPSocketError("Port number in -" +
+                                OutOfProcessExecutorConnect.ArgStr +
+                                " can not be empty");
+  int Port = 0;
+  if (PortStr.getAsInteger(10, Port))
+    return createTCPSocketError("Port number '" + PortStr +
+                                "' is not a valid integer");
+
+  llvm::Expected<int> SockFD = connectTCPSocket(Host.str(), PortStr.str());
+  if (!SockFD)
+    return SockFD.takeError();
+
+  auto S = llvm::orc::SimpleRemoteEPC::Setup();
+
+  return llvm::orc::SimpleRemoteEPC::Create<
+      llvm::orc::FDSimpleRemoteEPCTransport>(
+      std::make_unique<llvm::orc::DynamicThreadPoolTaskDispatcher>(),
+      std::move(S), *SockFD, *SockFD);
+#endif
+}
+
 llvm::ExitOnError ExitOnErr;
 int main(int argc, const char **argv) {
   ExitOnErr.setBanner("clang-repl: ");
@@ -205,6 +423,8 @@ int main(int argc, const char **argv) {
   if (CudaEnabled)
     DeviceCI->LoadRequestedPlugins();
 
+  ExitOnErr(sanitizeOopArguments(argv[0]));
+
   std::unique_ptr<clang::Interpreter> Interp;
 
   if (CudaEnabled) {
@@ -217,6 +437,16 @@ int main(int argc, const char **argv) {
       auto CudaRuntimeLibPath = CudaPath + "/lib/libcudart.so";
       ExitOnErr(Interp->LoadDynamicLibrary(CudaRuntimeLibPath.c_str()));
     }
+  } else if (OutOfProcessExecutor.getNumOccurrences()) {
+    // Create an instance of llvm-jitlink-executor in a separate process.
+    auto oopExecutor = ExitOnErr(launchExecutor());
+    Interp = ExitOnErr(clang::Interpreter::createWithOutOfProcessExecutor(
+        std::move(CI), std::move(oopExecutor), OrcRuntimePath));
+  } else if (OutOfProcessExecutorConnect.getNumOccurrences()) {
+    /// If -oop-executor-connect is passed then connect to the executor.
+    auto REPC = ExitOnErr(connectToExecutor());
+    Interp = ExitOnErr(clang::Interpreter::createWithOutOfProcessExecutor(
+        std::move(CI), std::move(REPC), OrcRuntimePath));
   } else
     Interp = ExitOnErr(clang::Interpreter::create(std::move(CI)));
 
diff --git a/compiler-rt/lib/orc/dlfcn_wrapper.cpp b/compiler-rt/lib/orc/dlfcn_wrapper.cpp
index ece63da2cb48e..a8b207d27157e 100644
--- a/compiler-rt/lib/orc/dlfcn_wrapper.cpp
+++ b/compiler-rt/lib/orc/dlfcn_wrapper.cpp
@@ -20,6 +20,7 @@ using namespace __orc_rt;
 
 extern "C" const char *__orc_rt_jit_dlerror();
 extern "C" void *__orc_rt_jit_dlopen(const char *pat...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/79936


More information about the cfe-commits mailing list