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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits