[clang] [clang-repl] MakeJITBuilder attribute in JITConfig (PR #159693)
Abhinav Kumar via cfe-commits
cfe-commits at lists.llvm.org
Fri Sep 19 10:13:05 PDT 2025
https://github.com/kr-2003 updated https://github.com/llvm/llvm-project/pull/159693
>From 733ffcdabee19cae2557f7dad8754c55ddf29314 Mon Sep 17 00:00:00 2001
From: kr-2003 <kumar.kr.abhinav at gmail.com>
Date: Fri, 19 Sep 2025 07:21:22 +0530
Subject: [PATCH 1/4] LLJITBuilder in JITConfig
---
clang/include/clang/Interpreter/Interpreter.h | 29 +++--
clang/lib/Interpreter/Interpreter.cpp | 115 ++++++++++--------
2 files changed, 82 insertions(+), 62 deletions(-)
diff --git a/clang/include/clang/Interpreter/Interpreter.h b/clang/include/clang/Interpreter/Interpreter.h
index 078d70b3b1749..7d734897e5584 100644
--- a/clang/include/clang/Interpreter/Interpreter.h
+++ b/clang/include/clang/Interpreter/Interpreter.h
@@ -1,4 +1,5 @@
-//===--- Interpreter.h - Incremental Compilation and Execution---*- C++ -*-===//
+//===------ Interpreter.h - Incremental Compilation and Execution---*- C++
+//-*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -19,12 +20,14 @@
#include "clang/Interpreter/Value.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/FunctionExtras.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 <cstdint>
#include <memory>
+#include <optional>
#include <vector>
namespace llvm {
@@ -32,6 +35,7 @@ namespace orc {
class LLJIT;
class LLJITBuilder;
class ThreadSafeContext;
+class JITTargetMachineBuilder;
} // namespace orc
} // namespace llvm
@@ -132,18 +136,25 @@ class Interpreter {
/// Representing the slab allocation size for memory management in kb.
unsigned SlabAllocateSize = 0;
/// Path to the ORC runtime library.
- std::string OrcRuntimePath = "";
+ std::optional<std::string> OrcRuntimePath;
/// PID of the out-of-process JIT executor.
uint32_t ExecutorPID = 0;
- /// Custom lambda to be executed inside child process/executor
- std::function<void()> CustomizeFork = nullptr;
- /// An optional code model to provide to the JITTargetMachineBuilder
- std::optional<llvm::CodeModel::Model> CM = std::nullopt;
+
+ /// Factory function for creating LLJITBuilder instances.
+ /// This allows clients to customize JIT builder creation while still
+ /// providing sensible defaults.
+ llvm::unique_function<llvm::Expected<
+ std::unique_ptr<llvm::orc::LLJITBuilder>>(const JITConfig &)>
+ MakeJITBuilder = makeDefaultJITBuilder;
JITConfig()
: IsOutOfProcess(false), OOPExecutor(""), OOPExecutorConnect(""),
- UseSharedMemory(false), SlabAllocateSize(0), OrcRuntimePath(""),
- ExecutorPID(0), CustomizeFork(nullptr), CM(std::nullopt) {}
+ UseSharedMemory(false), SlabAllocateSize(0), OrcRuntimePath(),
+ ExecutorPID(0) {}
+
+ /// Default JIT builder factory function
+ static llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>
+ makeDefaultJITBuilder(const JITConfig &Config);
};
protected:
@@ -237,4 +248,4 @@ class Interpreter {
};
} // namespace clang
-#endif // LLVM_CLANG_INTERPRETER_INTERPRETER_H
+#endif // LLVM_CLANG_INTERPRETER_INTERPRETER_H
\ No newline at end of file
diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp
index 9cc1c450b7650..a613fbf1b8370 100644
--- a/clang/lib/Interpreter/Interpreter.cpp
+++ b/clang/lib/Interpreter/Interpreter.cpp
@@ -350,15 +350,26 @@ const char *const Runtimes = R"(
EXTERN_C void __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType, ...);
)";
+static llvm::Expected<llvm::orc::JITTargetMachineBuilder>
+createJITTargetMachineBuilder(const std::string &TT) {
+ if (TT == llvm::sys::getProcessTriple())
+ // This fails immediately if the target backend is not registered
+ return llvm::orc::JITTargetMachineBuilder::detectHost();
+
+ // If the target backend is not registered, LLJITBuilder::create() will fail
+ return llvm::orc::JITTargetMachineBuilder(llvm::Triple(TT));
+}
+
+// 5. Update outOfProcessJITBuilder to work with the new system
llvm::Expected<std::pair<std::unique_ptr<llvm::orc::LLJITBuilder>, uint32_t>>
Interpreter::outOfProcessJITBuilder(JITConfig Config) {
std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC;
uint32_t childPid = -1;
+
if (!Config.OOPExecutor.empty()) {
// Launch an out-of-process executor locally in a child process.
auto ResultOrErr = IncrementalExecutor::launchExecutor(
- Config.OOPExecutor, Config.UseSharedMemory, Config.SlabAllocateSize,
- Config.CustomizeFork);
+ Config.OOPExecutor, Config.UseSharedMemory, Config.SlabAllocateSize);
if (!ResultOrErr)
return ResultOrErr.takeError();
childPid = ResultOrErr->second;
@@ -381,8 +392,10 @@ Interpreter::outOfProcessJITBuilder(JITConfig Config) {
std::unique_ptr<llvm::orc::LLJITBuilder> JB;
if (EPC) {
- auto JBOrErr = clang::Interpreter::createLLJITBuilder(
- std::move(EPC), Config.OrcRuntimePath);
+ std::string RuntimePath =
+ Config.OrcRuntimePath ? *Config.OrcRuntimePath : "";
+ auto JBOrErr =
+ clang::Interpreter::createLLJITBuilder(std::move(EPC), RuntimePath);
if (!JBOrErr)
return JBOrErr.takeError();
JB = std::move(*JBOrErr);
@@ -422,9 +435,9 @@ llvm::Expected<std::unique_ptr<Interpreter>>
Interpreter::create(std::unique_ptr<CompilerInstance> CI, JITConfig Config) {
llvm::Error Err = llvm::Error::success();
- std::unique_ptr<llvm::orc::LLJITBuilder> JB;
-
- if (Config.IsOutOfProcess) {
+ // Auto-discover ORC runtime path if not provided and out-of-process is
+ // enabled
+ if (Config.IsOutOfProcess && !Config.OrcRuntimePath) {
const TargetInfo &TI = CI->getTarget();
const llvm::Triple &Triple = TI.getTriple();
@@ -440,16 +453,22 @@ Interpreter::create(std::unique_ptr<CompilerInstance> CI, JITConfig Config) {
"Failed to create driver compilation for out-of-process JIT",
std::error_code());
}
- if (Config.OrcRuntimePath == "") {
- const clang::driver::ToolChain &TC = C->getDefaultToolChain();
+ const clang::driver::ToolChain &TC = C->getDefaultToolChain();
+ auto OrcRuntimePathOrErr = getOrcRuntimePath(TC);
+ if (!OrcRuntimePathOrErr) {
+ return OrcRuntimePathOrErr.takeError();
+ }
- auto OrcRuntimePathOrErr = getOrcRuntimePath(TC);
- if (!OrcRuntimePathOrErr) {
- return OrcRuntimePathOrErr.takeError();
- }
+ Config.OrcRuntimePath = *OrcRuntimePathOrErr;
+ }
- Config.OrcRuntimePath = *OrcRuntimePathOrErr;
- }
+ std::unique_ptr<llvm::orc::LLJITBuilder> JB;
+ if (Config.IsOutOfProcess ||
+ /* other conditions where we need custom builder */) {
+ auto JBOrErr = Config.MakeJITBuilder(Config);
+ if (!JBOrErr)
+ return JBOrErr.takeError();
+ JB = std::move(*JBOrErr);
}
auto Interp = std::unique_ptr<Interpreter>(new Interpreter(
@@ -590,16 +609,6 @@ Interpreter::Parse(llvm::StringRef Code) {
return LastPTU;
}
-static llvm::Expected<llvm::orc::JITTargetMachineBuilder>
-createJITTargetMachineBuilder(const std::string &TT) {
- if (TT == llvm::sys::getProcessTriple())
- // This fails immediately if the target backend is not registered
- return llvm::orc::JITTargetMachineBuilder::detectHost();
-
- // If the target backend is not registered, LLJITBuilder::create() will fail
- return llvm::orc::JITTargetMachineBuilder(llvm::Triple(TT));
-}
-
llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>
Interpreter::createLLJITBuilder(
std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC,
@@ -629,39 +638,16 @@ llvm::Error Interpreter::CreateExecutor(JITConfig Config) {
"No code generator available",
std::error_code());
- const std::string &TT = getCompilerInstance()->getTargetOpts().Triple;
- llvm::Triple TargetTriple(TT);
- bool IsWindowsTarget = TargetTriple.isOSWindows();
-
- if (!IsWindowsTarget && Config.IsOutOfProcess) {
- if (!JITBuilder) {
- auto ResOrErr = outOfProcessJITBuilder(Config);
- if (!ResOrErr)
- return ResOrErr.takeError();
- JITBuilder = std::move(ResOrErr->first);
- Config.ExecutorPID = ResOrErr->second;
- }
- if (!JITBuilder)
- return llvm::make_error<llvm::StringError>(
- "Operation failed. No LLJITBuilder for out-of-process JIT",
- std::error_code());
- }
-
if (!JITBuilder) {
- auto JTMB = createJITTargetMachineBuilder(TT);
- if (!JTMB)
- return JTMB.takeError();
- if (Config.CM)
- JTMB->setCodeModel(Config.CM);
- auto JB = IncrementalExecutor::createDefaultJITBuilder(std::move(*JTMB));
- if (!JB)
- return JB.takeError();
- JITBuilder = std::move(*JB);
+ // Use the factory function to create the builder
+ auto JBOrErr = Config.MakeJITBuilder(Config);
+ if (!JBOrErr)
+ return JBOrErr.takeError();
+ JITBuilder = std::move(*JBOrErr);
}
llvm::Error Err = llvm::Error::success();
- // Fix: Declare Executor as the appropriate unique_ptr type
std::unique_ptr<IncrementalExecutor> Executor;
#ifdef __EMSCRIPTEN__
@@ -803,4 +789,27 @@ llvm::Error Interpreter::LoadDynamicLibrary(const char *name) {
return llvm::Error::success();
}
+
+llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>
+Interpreter::JITConfig::makeDefaultJITBuilder(const JITConfig &Config) {
+ // Handle out-of-process JIT case
+ if (Config.IsOutOfProcess) {
+ if (!Config.OOPExecutor.empty() || !Config.OOPExecutorConnect.empty()) {
+ auto ResOrErr = Interpreter::outOfProcessJITBuilder(Config);
+ if (!ResOrErr)
+ return ResOrErr.takeError();
+ return std::move(ResOrErr->first);
+ }
+ }
+
+ // Handle in-process JIT case
+ // This would typically extract the target triple from somewhere accessible
+ // For now, we'll assume it's passed via some mechanism or use process triple
+ std::string TT = llvm::sys::getProcessTriple(); // This might need adjustment
+ auto JTMB = createJITTargetMachineBuilder(TT);
+ if (!JTMB)
+ return JTMB.takeError();
+
+ return IncrementalExecutor::createDefaultJITBuilder(std::move(*JTMB));
+}
} // end namespace clang
>From 53b25f4839b5e354d3e1174bd29aec26dd36bcb3 Mon Sep 17 00:00:00 2001
From: kr-2003 <kumar.kr.abhinav at gmail.com>
Date: Fri, 19 Sep 2025 08:01:35 +0530
Subject: [PATCH 2/4] Refactoring code
---
clang/include/clang/Interpreter/Interpreter.h | 4 ++--
clang/lib/Interpreter/Interpreter.cpp | 13 ++-----------
2 files changed, 4 insertions(+), 13 deletions(-)
diff --git a/clang/include/clang/Interpreter/Interpreter.h b/clang/include/clang/Interpreter/Interpreter.h
index 7d734897e5584..ef56f319e00ef 100644
--- a/clang/include/clang/Interpreter/Interpreter.h
+++ b/clang/include/clang/Interpreter/Interpreter.h
@@ -1,5 +1,5 @@
-//===------ Interpreter.h - Incremental Compilation and Execution---*- C++
-//-*-===//
+//===--- Interpreter.h - Incremental Compilation and Execution---*- C++ -*-===//
+
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp
index a613fbf1b8370..c33a037408d61 100644
--- a/clang/lib/Interpreter/Interpreter.cpp
+++ b/clang/lib/Interpreter/Interpreter.cpp
@@ -353,14 +353,11 @@ const char *const Runtimes = R"(
static llvm::Expected<llvm::orc::JITTargetMachineBuilder>
createJITTargetMachineBuilder(const std::string &TT) {
if (TT == llvm::sys::getProcessTriple())
- // This fails immediately if the target backend is not registered
return llvm::orc::JITTargetMachineBuilder::detectHost();
- // If the target backend is not registered, LLJITBuilder::create() will fail
return llvm::orc::JITTargetMachineBuilder(llvm::Triple(TT));
}
-// 5. Update outOfProcessJITBuilder to work with the new system
llvm::Expected<std::pair<std::unique_ptr<llvm::orc::LLJITBuilder>, uint32_t>>
Interpreter::outOfProcessJITBuilder(JITConfig Config) {
std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC;
@@ -435,8 +432,6 @@ llvm::Expected<std::unique_ptr<Interpreter>>
Interpreter::create(std::unique_ptr<CompilerInstance> CI, JITConfig Config) {
llvm::Error Err = llvm::Error::success();
- // Auto-discover ORC runtime path if not provided and out-of-process is
- // enabled
if (Config.IsOutOfProcess && !Config.OrcRuntimePath) {
const TargetInfo &TI = CI->getTarget();
const llvm::Triple &Triple = TI.getTriple();
@@ -463,8 +458,7 @@ Interpreter::create(std::unique_ptr<CompilerInstance> CI, JITConfig Config) {
}
std::unique_ptr<llvm::orc::LLJITBuilder> JB;
- if (Config.IsOutOfProcess ||
- /* other conditions where we need custom builder */) {
+ if (Config.IsOutOfProcess) {
auto JBOrErr = Config.MakeJITBuilder(Config);
if (!JBOrErr)
return JBOrErr.takeError();
@@ -802,10 +796,7 @@ Interpreter::JITConfig::makeDefaultJITBuilder(const JITConfig &Config) {
}
}
- // Handle in-process JIT case
- // This would typically extract the target triple from somewhere accessible
- // For now, we'll assume it's passed via some mechanism or use process triple
- std::string TT = llvm::sys::getProcessTriple(); // This might need adjustment
+ std::string TT = llvm::sys::getProcessTriple();
auto JTMB = createJITTargetMachineBuilder(TT);
if (!JTMB)
return JTMB.takeError();
>From 88fd4cfda4d187b049282ff5068d96f7fffd1cbe Mon Sep 17 00:00:00 2001
From: kr-2003 <kumar.kr.abhinav at gmail.com>
Date: Fri, 19 Sep 2025 19:11:14 +0530
Subject: [PATCH 3/4] Resolving unique function
---
clang/include/clang/Interpreter/Interpreter.h | 5 +++--
clang/lib/Interpreter/Interpreter.cpp | 5 -----
2 files changed, 3 insertions(+), 7 deletions(-)
diff --git a/clang/include/clang/Interpreter/Interpreter.h b/clang/include/clang/Interpreter/Interpreter.h
index ef56f319e00ef..e066e05c20406 100644
--- a/clang/include/clang/Interpreter/Interpreter.h
+++ b/clang/include/clang/Interpreter/Interpreter.h
@@ -23,6 +23,7 @@
#include "llvm/ADT/FunctionExtras.h"
#include "llvm/ExecutionEngine/JITSymbol.h"
#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
+#include "llvm/ExecutionEngine/Orc/LLJIT.h"
#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
#include "llvm/Support/Error.h"
#include <cstdint>
@@ -143,8 +144,8 @@ class Interpreter {
/// Factory function for creating LLJITBuilder instances.
/// This allows clients to customize JIT builder creation while still
/// providing sensible defaults.
- llvm::unique_function<llvm::Expected<
- std::unique_ptr<llvm::orc::LLJITBuilder>>(const JITConfig &)>
+ std::function<llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>(
+ const JITConfig &)>
MakeJITBuilder = makeDefaultJITBuilder;
JITConfig()
diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp
index c33a037408d61..5847d85154a80 100644
--- a/clang/lib/Interpreter/Interpreter.cpp
+++ b/clang/lib/Interpreter/Interpreter.cpp
@@ -278,12 +278,7 @@ Interpreter::Interpreter(std::unique_ptr<CompilerInstance> Instance,
if (Act->getCodeGen()) {
Act->CacheCodeGenModule();
- // The initial PTU is filled by `-include` or by CUDA includes
- // automatically.
if (!CI->getPreprocessorOpts().Includes.empty()) {
- // We can't really directly pass the CachedInCodeGenModule to the Jit
- // because it will steal it, causing dangling references as explained in
- // Interpreter::Execute
auto M = llvm::CloneModule(*Act->getCachedCodeGenModule());
ASTContext &C = CI->getASTContext();
IncrParser->RegisterPTU(C.getTranslationUnitDecl(), std::move(M));
>From db59b3aedf9bdadd40b3c39a6c8a3e1190fdb84a Mon Sep 17 00:00:00 2001
From: kr-2003 <kumar.kr.abhinav at gmail.com>
Date: Fri, 19 Sep 2025 22:42:47 +0530
Subject: [PATCH 4/4] Adding customFork in JitConfig
---
clang/include/clang/Interpreter/Interpreter.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/clang/include/clang/Interpreter/Interpreter.h b/clang/include/clang/Interpreter/Interpreter.h
index e066e05c20406..a0540151561e9 100644
--- a/clang/include/clang/Interpreter/Interpreter.h
+++ b/clang/include/clang/Interpreter/Interpreter.h
@@ -140,7 +140,8 @@ class Interpreter {
std::optional<std::string> OrcRuntimePath;
/// PID of the out-of-process JIT executor.
uint32_t ExecutorPID = 0;
-
+ /// Custom lambda to be executed inside child process/executor
+ std::function<void()> CustomizeFork = nullptr;
/// Factory function for creating LLJITBuilder instances.
/// This allows clients to customize JIT builder creation while still
/// providing sensible defaults.
More information about the cfe-commits
mailing list