[clang] [REAPPLY][Clang-Repl] Add support for out-of-process execution. #110418 (PR #144064)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Jun 15 22:06:21 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: None (SahilPatidar)
<details>
<summary>Changes</summary>
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.
---
Patch is 28.12 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/144064.diff
9 Files Affected:
- (modified) clang/include/clang/Interpreter/Interpreter.h (+6-1)
- (added) clang/include/clang/Interpreter/RemoteJITUtils.h (+38)
- (modified) clang/lib/Interpreter/CMakeLists.txt (+1)
- (modified) clang/lib/Interpreter/Interpreter.cpp (+29-8)
- (added) clang/lib/Interpreter/RemoteJITUtils.cpp (+267)
- (added) clang/test/Interpreter/out-of-process.cpp (+88)
- (modified) clang/test/lit.cfg.py (+25)
- (modified) clang/tools/clang-repl/CMakeLists.txt (+2)
- (modified) clang/tools/clang-repl/ClangRepl.cpp (+122-1)
``````````diff
diff --git a/clang/include/clang/Interpreter/Interpreter.h b/clang/include/clang/Interpreter/Interpreter.h
index f8663e3193a18..78dff1165dcf5 100644
--- a/clang/include/clang/Interpreter/Interpreter.h
+++ b/clang/include/clang/Interpreter/Interpreter.h
@@ -20,6 +20,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>
@@ -136,10 +137,14 @@ 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>>
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/include/clang/Interpreter/RemoteJITUtils.h b/clang/include/clang/Interpreter/RemoteJITUtils.h
new file mode 100644
index 0000000000000..8705a3b1f669d
--- /dev/null
+++ b/clang/include/clang/Interpreter/RemoteJITUtils.h
@@ -0,0 +1,38 @@
+//===-- 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_INTERPRETER_REMOTEJITUTILS_H
+#define LLVM_CLANG_INTERPRETER_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>
+
+llvm::Expected<std::unique_ptr<llvm::orc::SimpleRemoteEPC>>
+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, bool UseSharedMemory,
+ llvm::StringRef SlabAllocateSizeString);
+
+#endif // LLVM_CLANG_INTERPRETER_REMOTEJITUTILS_H
diff --git a/clang/lib/Interpreter/CMakeLists.txt b/clang/lib/Interpreter/CMakeLists.txt
index bf70cdfbee01e..38cf139fa86a6 100644
--- a/clang/lib/Interpreter/CMakeLists.txt
+++ b/clang/lib/Interpreter/CMakeLists.txt
@@ -27,6 +27,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 84feff82c63a7..30051a24662c6 100644
--- a/clang/lib/Interpreter/Interpreter.cpp
+++ b/clang/lib/Interpreter/Interpreter.cpp
@@ -46,6 +46,7 @@
#include "clang/Sema/Lookup.h"
#include "clang/Serialization/ObjectFilePCHContainerReader.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"
@@ -455,10 +456,11 @@ 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));
+ auto Interp = std::unique_ptr<Interpreter>(
+ new Interpreter(std::move(CI), Err, JB ? std::move(JB) : nullptr));
if (Err)
return std::move(Err);
@@ -617,6 +619,25 @@ createJITTargetMachineBuilder(const std::string &TT) {
return llvm::orc::JITTargetMachineBuilder(llvm::Triple(TT));
}
+llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>
+Interpreter::createLLJITBuilder(
+ std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC,
+ llvm::StringRef OrcRuntimePath) {
+ 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();
+
+ (*JB)->setExecutorProcessControl(std::move(EPC));
+ (*JB)->setPlatformSetUp(
+ llvm::orc::ExecutorNativePlatform(OrcRuntimePath.str()));
+
+ return std::move(*JB);
+}
+
llvm::Error Interpreter::CreateExecutor() {
if (IncrExecutor)
return llvm::make_error<llvm::StringError>("Operation failed. "
@@ -756,11 +777,11 @@ 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()))
- EE->getMainJITDylib().addGenerator(std::move(*DLSG));
+ if (auto DLSG = llvm::orc::EPCDynamicLibrarySearchGenerator::Load(
+ EE->getExecutionSession(), name))
+ // FIXME: Eventually we should put each library in its own JITDylib and
+ // turn off process symbols by default.
+ EE->getProcessSymbolsJITDylib()->addGenerator(std::move(*DLSG));
else
return DLSG.takeError();
#endif
diff --git a/clang/lib/Interpreter/RemoteJITUtils.cpp b/clang/lib/Interpreter/RemoteJITUtils.cpp
new file mode 100644
index 0000000000000..24a5f729f2dcb
--- /dev/null
+++ b/clang/lib/Interpreter/RemoteJITUtils.cpp
@@ -0,0 +1,267 @@
+//===-- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// FIXME: Unify this code with similar functionality in llvm-jitlink.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Interpreter/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/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"
+#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<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()) {
+ if (auto S = getSlabAllocSize(SlabAllocateSizeString))
+ SlabSize = *S;
+ else
+ return S.takeError();
+ }
+
+ return MapperJITLinkMemoryManager::CreateWithMapper<SharedMemoryMapper>(
+ SlabSize, SREPC, SAs);
+}
+
+Expected<std::unique_ptr<SimpleRemoteEPC>>
+launchExecutor(StringRef ExecutablePath, bool UseSharedMemory,
+ llvm::StringRef SlabAllocateSizeString) {
+#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>(
+ "-" + ExecutablePath +
+ " requires threads, but LLVM was built with "
+ "LLVM_ENABLE_THREADS=Off",
+ inconvertibleErrorCode());
+#else
+
+ 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());
+
+ 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[]>(ExecutablePath.size() + 1);
+ strcpy(ExecutorPath.get(), ExecutablePath.data());
+
+ 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[] = {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...
+
+ // Close the child ends of the pipes
+ close(ToExecutor[ReadEnd]);
+ 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),
+ 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;
+ 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) {
+ // 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 make_error<StringError>("invalid hostname",
+ inconvertibleErrorCode());
+
+ return SockFD;
+}
+#endif
+
+Expected<std::unique_ptr<SimpleRemoteEPC>>
+connectTCPSocket(StringRef NetworkAddress, bool UseSharedMemory,
+ llvm::StringRef SlabAllocateSizeString) {
+#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),
+ inconvertibleErrorCode());
+ };
+
+ StringRef Host, PortStr;
+ std::tie(Host, PortStr) = NetworkAddress.split(':');
+ if (Host.empty())
+ return CreateErr("Host name for -" + NetworkAddress + " can not be empty");
+ if (PortStr.empty())
+ return CreateErr("Port number in -" + NetworkAddress + " can not be empty");
+ int Port = 0;
+ if (PortStr.getAsInteger(10, Port))
+ return CreateErr("Port number '" + PortStr + "' is not a valid integer");
+
+ Expected<int> SockFD = connectTCPSocketImpl(Host.str(), PortStr.str());
+ if (!SockFD)
+ 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),
+ std::move(S), *SockFD, *SockFD);
+#endif
+}
diff --git a/clang/test/Interpreter/out-of-process.cpp b/clang/test/Interpreter/out-of-process.cpp
new file mode 100644
index 0000000000000..6922ca6e82053
--- /dev/null
+++ b/clang/test/Interpreter/out-of-process.cpp
@@ -0,0 +1,88 @@
+// REQUIRES: host-supports-jit, host-supports-out-of-process-jit, x86_64-linux
+
+// RUN: cat %s | clang-repl -oop-executor -orc-runtime | FileCheck %s
+
+extern "C" int printf(const char *, ...);
+
+int intVar = 0;
+double doubleVar = 3.14;
+%undo
+double doubleVar = 2.71;
+
+auto r1 = printf("intVar = %d\n", intVar);
+// CHECK: intVar = 0
+auto r2 = printf("doubleVar = %.2f\n", doubleVar);
+// CHECK: doubleVar = 2.71
+
+// Test redefinition with inline and static functions.
+int add(int a, int b, int c) { return a + b + c; }
+%undo // Revert to the initial version of add
+inline int add(int a, int b) { return a + b; }
+
+auto r3 = printf("add(1, 2) = %d\n", add(1, 2));
+// CHECK-NEXT: add(1, 2) = 3
+
+// Test inline and lambda functions with variations.
+inline int square(int x) { return x * x; }
+auto lambdaSquare = [](int x) { return x * x; };
+auto lambdaMult = [](int a, int b) { return a * b; };
+
+auto r4 = printf("square(4) = %d\n", square(4));
+// CHECK-NEXT: square(4) = 16
+auto lambda_r1 = printf("lambdaSquare(5) = %d\n", lambdaSquare(5));
+// CHECK-NEXT: lambdaSquare(5) = 25
+auto lambda_r2 = printf("lambdaMult(2, 3) = %d\n", lambdaMult(2, 3));
+// CHECK-NEXT: lambdaMult(2, 3) = 6
+
+%undo // Undo previous lambda assignments
+auto lambda_r3 = lambdaMult(3, 4); // Should fail or revert to the original lambda
+
+// Test weak and strong symbol linkage.
+int __attribute__((weak)) weakFunc() { return 42; }
+int strongFunc() { return 100; }
+%undo // Revert the weak function
+
+auto r5 = printf("weakFunc() = %d\n", weakFunc());
+// CHECK: weakFunc() = 42
+auto r6 = printf("strongFunc() = %d\n", strongFunc());
+// CHECK-NEXT: strongFunc() = 100
+
+// Weak variable linkage with different types.
+int varA = 20;
+static __typeof(varA) weakVarA __attribute__((__weakref__("varA")));
+char charVar = 'c';
+static __typeof(charVar) weakCharVar __attribute__((__weakref__("charVar")));
+auto r7 = printf("weakVarA = %d\n", weakVarA);
+// CHECK: weakVarA = 20
+auto r8 = printf("weakCharVar = %c\n", weakCharVar);
+// CHECK-NEXT: weakCharVar = c
+
+// Test complex lambdas with captures.
+int captureVar = 5;
+auto captureLambda = [](int x) { return x + captureVar; };
+int result1 = captureLambda(10);
+%undo // Undo capture lambda
+
+auto r9 = printf("captureLambda(10) = %d\n", result1);
+// CHECK: captureLambda(10) = 15
+
+// Multiline statement test with arithmetic operations.
+int sum = \
+ 5 + \
+ 10;
+int prod = sum * 2;
+auto r10 = printf("sum = %d, prod = %d\n", sum, prod);
+// CHECK: sum = 15, prod = 30
+
+// Test multiline functions and macro behavior.
+#define MULTIPLY(a, b) ((a) * (b))
+
+int complexFunc(int x) \
+{ \
+ return MULTIPLY(x, 2) + x; \
+}
+
+auto r11 = printf("complexFunc(5) = %d\n", complexFunc(5));
+// CHECK: complexFunc(5) = 15
+
+%quit
\ No newline at end of file
diff --git a/clang/test/lit.cfg.py b/clang/test/lit.cfg.py
index 2b35bb5dcbdaf..0f82f2089ac58 100644
--- a/clang/test/lit.cfg.py
+++ b/clang/test/lit.cfg.py
@@ -116,6 +116,28 @@
if config.clang_examples:
config.available_features.add("examples")
+def have_host_out_of_process_jit_feature_support():
+ clang_repl_exe = lit.util.which("clang-repl", config.clang_tools_dir)
+
+ if not clang_repl_exe:
+ return False
+
+ testcode = b"\n".join([b"int i = 0;", b"%quit"])
+
+ try:
+ clang_repl_cmd = subprocess.run(
+ [clang_repl_exe, "-orc-runtime", "-oop-executor"],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ input=testcode,
+ )
+ except OSError:
+ return False
+
+ if clang_repl_cmd.returncode == 0:
+ return True
+
+ return False
def have_host_jit_feature_support(feature_name):
clang_repl_exe = lit.util.which("clang-repl", config.clang_tools_dir)
@@ -169,6 +191,9 @@ def have_host_clang_repl_cuda():
if have_host_clang_repl_cuda():
config.available_features.add('host-supports-cuda')
+ if have_host_out_of_process_jit_feature_support():
+ config.available_features.add("host-supports-out-of-process-jit")
+
if confi...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/144064
More information about the cfe-commits
mailing list