[clang] 9bcf43c - [clang-repl] Simplify the logic around out of process execution. NFC (#175322)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Jan 10 09:12:34 PST 2026
Author: Vassil Vassilev
Date: 2026-01-10T19:12:30+02:00
New Revision: 9bcf43c0f38145932791a3788845f2562e774e87
URL: https://github.com/llvm/llvm-project/commit/9bcf43c0f38145932791a3788845f2562e774e87
DIFF: https://github.com/llvm/llvm-project/commit/9bcf43c0f38145932791a3788845f2562e774e87.diff
LOG: [clang-repl] Simplify the logic around out of process execution. NFC (#175322)
cc: @aaronj0, @Vipul-Cariappa
Added:
Modified:
clang/include/clang/Interpreter/Interpreter.h
clang/lib/Interpreter/IncrementalExecutor.cpp
clang/lib/Interpreter/IncrementalExecutor.h
clang/lib/Interpreter/Interpreter.cpp
clang/tools/clang-repl/ClangRepl.cpp
clang/unittests/Interpreter/InterpreterExtensionsTest.cpp
clang/unittests/Interpreter/OutOfProcessInterpreterTests.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Interpreter/Interpreter.h b/clang/include/clang/Interpreter/Interpreter.h
index 078d70b3b1749..c4ddfb067be0f 100644
--- a/clang/include/clang/Interpreter/Interpreter.h
+++ b/clang/include/clang/Interpreter/Interpreter.h
@@ -38,7 +38,7 @@ class ThreadSafeContext;
namespace clang {
namespace driver {
-class ToolChain;
+class Compilation;
} // namespace driver
class CompilerInstance;
@@ -50,6 +50,8 @@ class IncrementalCUDADeviceParser;
/// Create a pre-configured \c CompilerInstance for incremental processing.
class IncrementalCompilerBuilder {
+ using DriverCompilationFn = llvm::Error(const driver::Compilation &);
+
public:
IncrementalCompilerBuilder() {}
@@ -68,11 +70,16 @@ class IncrementalCompilerBuilder {
// CUDA specific
void SetCudaSDK(llvm::StringRef path) { CudaSDKPath = path; };
+ // Hand over the compilation.
+ void SetDriverCompilationCallback(std::function<DriverCompilationFn> C) {
+ CompilationCB = C;
+ }
+
llvm::Expected<std::unique_ptr<CompilerInstance>> CreateCudaHost();
llvm::Expected<std::unique_ptr<CompilerInstance>> CreateCudaDevice();
private:
- static llvm::Expected<std::unique_ptr<CompilerInstance>>
+ llvm::Expected<std::unique_ptr<CompilerInstance>>
create(std::string TT, std::vector<const char *> &ClangArgv);
llvm::Expected<std::unique_ptr<CompilerInstance>> createCuda(bool device);
@@ -82,6 +89,44 @@ class IncrementalCompilerBuilder {
llvm::StringRef OffloadArch;
llvm::StringRef CudaSDKPath;
+
+ std::optional<std::function<DriverCompilationFn>> CompilationCB;
+};
+
+// FIXME: Consider deriving from the LLJITBuilder into a common interpreter
+// creation configuraion class.
+class IncrementalExecutorBuilder {
+public:
+ /// Indicates whether out-of-process JIT execution is enabled.
+ bool IsOutOfProcess = false;
+ /// Path to the out-of-process JIT executor.
+ std::string OOPExecutor = "";
+ std::string OOPExecutorConnect = "";
+ /// Indicates whether to use shared memory for communication.
+ bool UseSharedMemory = false;
+ /// Representing the slab allocation size for memory management in kb.
+ unsigned SlabAllocateSize = 0;
+ /// Path to the ORC runtime library.
+ 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;
+ std::function<llvm::Error(const driver::Compilation &)>
+ UpdateOrcRuntimePathCB = [this](const driver::Compilation &C) {
+ return UpdateOrcRuntimePath(C);
+ };
+
+ ~IncrementalExecutorBuilder();
+
+ llvm::Expected<std::unique_ptr<IncrementalExecutor>>
+ create(llvm::orc::ThreadSafeContext &TSC,
+ llvm::orc::LLJITBuilder &JITBuilder);
+
+private:
+ llvm::Error UpdateOrcRuntimePath(const driver::Compilation &C);
};
class IncrementalAction;
@@ -120,42 +165,16 @@ class Interpreter {
/// An optional compiler instance for CUDA offloading
std::unique_ptr<CompilerInstance> DeviceCI;
-public:
- struct JITConfig {
- /// Indicates whether out-of-process JIT execution is enabled.
- bool IsOutOfProcess = false;
- /// Path to the out-of-process JIT executor.
- std::string OOPExecutor = "";
- std::string OOPExecutorConnect = "";
- /// Indicates whether to use shared memory for communication.
- bool UseSharedMemory = false;
- /// Representing the slab allocation size for memory management in kb.
- unsigned SlabAllocateSize = 0;
- /// Path to the ORC runtime library.
- 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;
-
- JITConfig()
- : IsOutOfProcess(false), OOPExecutor(""), OOPExecutorConnect(""),
- UseSharedMemory(false), SlabAllocateSize(0), OrcRuntimePath(""),
- ExecutorPID(0), CustomizeFork(nullptr), CM(std::nullopt) {}
- };
-
protected:
// Derived classes can use an extended interface of the Interpreter.
Interpreter(std::unique_ptr<CompilerInstance> Instance, llvm::Error &Err,
std::unique_ptr<llvm::orc::LLJITBuilder> JITBuilder = nullptr,
std::unique_ptr<clang::ASTConsumer> Consumer = nullptr,
- JITConfig Config = JITConfig());
+ std::unique_ptr<IncrementalExecutorBuilder> IEB = nullptr);
// Create the internal IncrementalExecutor, or re-create it after calling
// ResetExecutor().
- llvm::Error CreateExecutor(JITConfig Config = JITConfig());
+ llvm::Error CreateExecutor();
// Delete the internal IncrementalExecutor. This causes a hard shutdown of the
// JIT engine. In particular, it doesn't run cleanup or destructors.
@@ -164,18 +183,14 @@ class Interpreter {
public:
virtual ~Interpreter();
static llvm::Expected<std::unique_ptr<Interpreter>>
- create(std::unique_ptr<CompilerInstance> CI, JITConfig Config = {});
+ create(std::unique_ptr<CompilerInstance> CI,
+ std::unique_ptr<IncrementalExecutorBuilder> IEB = 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);
- static llvm::Expected<
- std::pair<std::unique_ptr<llvm::orc::LLJITBuilder>, uint32_t>>
- outOfProcessJITBuilder(JITConfig Config);
- static llvm::Expected<std::string>
- getOrcRuntimePath(const driver::ToolChain &TC);
const ASTContext &getASTContext() const;
ASTContext &getASTContext();
@@ -221,6 +236,8 @@ class Interpreter {
std::unique_ptr<llvm::orc::LLJITBuilder> JITBuilder;
+ std::unique_ptr<IncrementalExecutorBuilder> IncrExecutorBuilder;
+
/// @}
/// @name Value and pretty printing support
/// @{
diff --git a/clang/lib/Interpreter/IncrementalExecutor.cpp b/clang/lib/Interpreter/IncrementalExecutor.cpp
index 11ab2cfaac17a..f0069c4924f7a 100644
--- a/clang/lib/Interpreter/IncrementalExecutor.cpp
+++ b/clang/lib/Interpreter/IncrementalExecutor.cpp
@@ -69,9 +69,8 @@ IncrementalExecutor::createDefaultJITBuilder(
IncrementalExecutor::IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC,
llvm::orc::LLJITBuilder &JITBuilder,
- Interpreter::JITConfig Config,
llvm::Error &Err)
- : TSCtx(TSC), OutOfProcessChildPid(Config.ExecutorPID) {
+ : TSCtx(TSC) {
using namespace llvm::orc;
llvm::ErrorAsOutParameter EAO(&Err);
diff --git a/clang/lib/Interpreter/IncrementalExecutor.h b/clang/lib/Interpreter/IncrementalExecutor.h
index bb1ec33452515..c11c99b9bff8d 100644
--- a/clang/lib/Interpreter/IncrementalExecutor.h
+++ b/clang/lib/Interpreter/IncrementalExecutor.h
@@ -46,7 +46,6 @@ class IncrementalExecutor {
using CtorDtorIterator = llvm::orc::CtorDtorIterator;
std::unique_ptr<llvm::orc::LLJIT> Jit;
llvm::orc::ThreadSafeContext &TSCtx;
- uint32_t OutOfProcessChildPid = -1;
llvm::DenseMap<const PartialTranslationUnit *, llvm::orc::ResourceTrackerSP>
ResourceTrackers;
@@ -58,8 +57,7 @@ class IncrementalExecutor {
enum SymbolNameKind { IRName, LinkerName };
IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC,
- llvm::orc::LLJITBuilder &JITBuilder,
- Interpreter::JITConfig Config, llvm::Error &Err);
+ llvm::orc::LLJITBuilder &JITBuilder, llvm::Error &Err);
virtual ~IncrementalExecutor();
virtual llvm::Error addModule(PartialTranslationUnit &PTU);
@@ -71,8 +69,6 @@ class IncrementalExecutor {
llvm::orc::LLJIT &GetExecutionEngine() { return *Jit; }
- uint32_t getOutOfProcessChildPid() const { return OutOfProcessChildPid; }
-
static llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>
createDefaultJITBuilder(llvm::orc::JITTargetMachineBuilder JTMB);
diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp
index 1a6f6ea0813b7..0d9f66c4ff07b 100644
--- a/clang/lib/Interpreter/Interpreter.cpp
+++ b/clang/lib/Interpreter/Interpreter.cpp
@@ -182,6 +182,10 @@ IncrementalCompilerBuilder::create(std::string TT,
llvm::ArrayRef<const char *> RF = llvm::ArrayRef(ClangArgv);
std::unique_ptr<driver::Compilation> Compilation(Driver.BuildCompilation(RF));
+ if (CompilationCB)
+ if (auto Err = (*CompilationCB)(*Compilation.get()))
+ return std::move(Err);
+
if (Compilation->getArgs().hasArg(options::OPT_v))
Compilation->getJobs().Print(llvm::errs(), "\n", /*Quote=*/false);
@@ -247,12 +251,80 @@ IncrementalCompilerBuilder::CreateCudaHost() {
return IncrementalCompilerBuilder::createCuda(false);
}
+IncrementalExecutorBuilder::~IncrementalExecutorBuilder() = default;
+
+llvm::Expected<std::unique_ptr<IncrementalExecutor>>
+IncrementalExecutorBuilder::create(llvm::orc::ThreadSafeContext &TSC,
+ llvm::orc::LLJITBuilder &JITBuilder) {
+ llvm::Error Err = llvm::Error::success();
+ std::unique_ptr<IncrementalExecutor> Executor;
+#ifdef __EMSCRIPTEN__
+ Executor = std::make_unique<WasmIncrementalExecutor>(TSC);
+#else
+ Executor = std::make_unique<IncrementalExecutor>(TSC, JITBuilder, Err);
+#endif
+
+ if (Err)
+ return std::move(Err);
+
+ return std::move(Executor);
+}
+
+llvm::Error
+IncrementalExecutorBuilder::UpdateOrcRuntimePath(const driver::Compilation &C) {
+ if (!IsOutOfProcess)
+ return llvm::Error::success();
+
+ const std::array<const char *, 3> OrcRTLibNames = {
+ "liborc_rt.a", "liborc_rt_osx.a", "liborc_rt-x86_64.a"};
+
+ auto findInDir = [&](llvm::StringRef Base) -> std::optional<std::string> {
+ for (const char *LibName : OrcRTLibNames) {
+ llvm::SmallString<256> CandidatePath(Base);
+ llvm::sys::path::append(CandidatePath, LibName);
+ if (llvm::sys::fs::exists(CandidatePath))
+ return std::string(CandidatePath.str());
+ }
+ return std::nullopt;
+ };
+
+ const driver::ToolChain &TC = C.getDefaultToolChain();
+ std::string SearchedPaths;
+ if (std::optional<std::string> CompilerRTPath = TC.getCompilerRTPath()) {
+ if (auto Found = findInDir(*CompilerRTPath)) {
+ OrcRuntimePath = *Found;
+ return llvm::Error::success();
+ }
+ SearchedPaths += *CompilerRTPath;
+ } else {
+ return llvm::make_error<llvm::StringError>("CompilerRT path not found",
+ std::error_code());
+ }
+
+ if (std::optional<std::string> ResourceDir = TC.getRuntimePath()) {
+ if (auto Found = findInDir(*ResourceDir)) {
+ OrcRuntimePath = *Found;
+ return llvm::Error::success();
+ }
+ if (!SearchedPaths.empty())
+ SearchedPaths += "; ";
+ SearchedPaths += *ResourceDir;
+ } else {
+ return llvm::make_error<llvm::StringError>("ResourceDir path not found",
+ std::error_code());
+ }
+
+ return llvm::make_error<llvm::StringError>(
+ llvm::Twine("OrcRuntime library not found in: ") + SearchedPaths,
+ std::error_code());
+}
+
Interpreter::Interpreter(std::unique_ptr<CompilerInstance> Instance,
llvm::Error &ErrOut,
std::unique_ptr<llvm::orc::LLJITBuilder> JITBuilder,
std::unique_ptr<clang::ASTConsumer> Consumer,
- JITConfig Config)
- : JITBuilder(std::move(JITBuilder)) {
+ std::unique_ptr<IncrementalExecutorBuilder> IEB)
+ : JITBuilder(std::move(JITBuilder)), IncrExecutorBuilder(std::move(IEB)) {
CI = std::move(Instance);
llvm::ErrorAsOutParameter EAO(&ErrOut);
auto LLVMCtx = std::make_unique<llvm::LLVMContext>();
@@ -286,7 +358,7 @@ Interpreter::Interpreter(std::unique_ptr<CompilerInstance> Instance,
ASTContext &C = CI->getASTContext();
IncrParser->RegisterPTU(C.getTranslationUnitDecl(), std::move(M));
}
- if (llvm::Error Err = CreateExecutor(Config)) {
+ if (llvm::Error Err = CreateExecutor()) {
ErrOut = joinErrors(std::move(ErrOut), std::move(Err));
return;
}
@@ -348,25 +420,28 @@ const char *const Runtimes = R"(
EXTERN_C void __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType, ...);
)";
-llvm::Expected<std::pair<std::unique_ptr<llvm::orc::LLJITBuilder>, uint32_t>>
-Interpreter::outOfProcessJITBuilder(JITConfig Config) {
+static llvm::Expected<
+ std::pair<std::unique_ptr<llvm::orc::LLJITBuilder>, uint32_t>>
+outOfProcessJITBuilder(const IncrementalExecutorBuilder &IncrExecutorBuilder) {
std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC;
uint32_t childPid = -1;
- if (!Config.OOPExecutor.empty()) {
+ if (!IncrExecutorBuilder.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);
+ IncrExecutorBuilder.OOPExecutor, IncrExecutorBuilder.UseSharedMemory,
+ IncrExecutorBuilder.SlabAllocateSize,
+ IncrExecutorBuilder.CustomizeFork);
if (!ResultOrErr)
return ResultOrErr.takeError();
childPid = ResultOrErr->second;
auto EPCOrErr = std::move(ResultOrErr->first);
EPC = std::move(EPCOrErr);
- } else if (Config.OOPExecutorConnect != "") {
+ } else if (IncrExecutorBuilder.OOPExecutorConnect != "") {
#if LLVM_ON_UNIX && LLVM_ENABLE_THREADS
auto EPCOrErr = IncrementalExecutor::connectTCPSocket(
- Config.OOPExecutorConnect, Config.UseSharedMemory,
- Config.SlabAllocateSize);
+ IncrExecutorBuilder.OOPExecutorConnect,
+ IncrExecutorBuilder.UseSharedMemory,
+ IncrExecutorBuilder.SlabAllocateSize);
if (!EPCOrErr)
return EPCOrErr.takeError();
EPC = std::move(*EPCOrErr);
@@ -380,7 +455,7 @@ Interpreter::outOfProcessJITBuilder(JITConfig Config) {
std::unique_ptr<llvm::orc::LLJITBuilder> JB;
if (EPC) {
auto JBOrErr = clang::Interpreter::createLLJITBuilder(
- std::move(EPC), Config.OrcRuntimePath);
+ std::move(EPC), IncrExecutorBuilder.OrcRuntimePath);
if (!JBOrErr)
return JBOrErr.takeError();
JB = std::move(*JBOrErr);
@@ -389,84 +464,14 @@ Interpreter::outOfProcessJITBuilder(JITConfig Config) {
return std::make_pair(std::move(JB), childPid);
}
-llvm::Expected<std::string>
-Interpreter::getOrcRuntimePath(const driver::ToolChain &TC) {
- const std::array<const char *, 3> OrcRTLibNames = {
- "liborc_rt.a", "liborc_rt_osx.a", "liborc_rt-x86_64.a"};
-
- auto findInDir = [&](llvm::StringRef Base) -> std::optional<std::string> {
- for (const char *LibName : OrcRTLibNames) {
- llvm::SmallString<256> CandidatePath(Base);
- llvm::sys::path::append(CandidatePath, LibName);
- if (llvm::sys::fs::exists(CandidatePath))
- return std::string(CandidatePath.str());
- }
- return std::nullopt;
- };
-
- std::string SearchedPaths;
-
- if (std::optional<std::string> CompilerRTPath = TC.getCompilerRTPath()) {
- if (auto Found = findInDir(*CompilerRTPath))
- return *Found;
- SearchedPaths += *CompilerRTPath;
- } else {
- return llvm::make_error<llvm::StringError>("CompilerRT path not found",
- std::error_code());
- }
-
- if (std::optional<std::string> ResourceDir = TC.getRuntimePath()) {
- if (auto Found = findInDir(*ResourceDir))
- return *Found;
- if (!SearchedPaths.empty())
- SearchedPaths += "; ";
- SearchedPaths += *ResourceDir;
- } else {
- return llvm::make_error<llvm::StringError>("ResourceDir path not found",
- std::error_code());
- }
-
- return llvm::make_error<llvm::StringError>(
- llvm::Twine("OrcRuntime library not found in: ") + SearchedPaths,
- std::error_code());
-}
-
-llvm::Expected<std::unique_ptr<Interpreter>>
-Interpreter::create(std::unique_ptr<CompilerInstance> CI, JITConfig Config) {
-
- if (Config.IsOutOfProcess) {
- const TargetInfo &TI = CI->getTarget();
- const llvm::Triple &Triple = TI.getTriple();
-
- DiagnosticsEngine &Diags = CI->getDiagnostics();
- std::string BinaryName = llvm::sys::fs::getMainExecutable(nullptr, nullptr);
- driver::Driver Driver(BinaryName, Triple.str(), Diags);
- // Need fake args to get the driver to create a compilation.
- std::vector<const char *> Args = {"clang", "--version"};
- std::unique_ptr<clang::driver::Compilation> C(
- Driver.BuildCompilation(Args));
- if (!C) {
- return llvm::make_error<llvm::StringError>(
- "Failed to create driver compilation for out-of-process JIT",
- std::error_code());
- }
- if (Config.OrcRuntimePath == "") {
- const clang::driver::ToolChain &TC = C->getDefaultToolChain();
-
- auto OrcRuntimePathOrErr = getOrcRuntimePath(TC);
- if (!OrcRuntimePathOrErr) {
- return OrcRuntimePathOrErr.takeError();
- }
-
- Config.OrcRuntimePath = *OrcRuntimePathOrErr;
- }
- }
-
+llvm::Expected<std::unique_ptr<Interpreter>> Interpreter::create(
+ std::unique_ptr<CompilerInstance> CI,
+ std::unique_ptr<IncrementalExecutorBuilder> IEB /*=nullptr*/) {
llvm::Error Err = llvm::Error::success();
std::unique_ptr<llvm::orc::LLJITBuilder> JB;
auto Interp = std::unique_ptr<Interpreter>(new Interpreter(
- std::move(CI), Err, std::move(JB), /*Consumer=*/nullptr, Config));
+ std::move(CI), Err, std::move(JB), /*Consumer=*/nullptr, std::move(IEB)));
if (auto E = std::move(Err))
return std::move(E);
@@ -560,7 +565,7 @@ size_t Interpreter::getEffectivePTUSize() const {
uint32_t Interpreter::getOutOfProcessExecutorPID() const {
if (IncrExecutor)
- return IncrExecutor->getOutOfProcessChildPid();
+ return IncrExecutorBuilder->ExecutorPID;
return -1;
}
@@ -627,7 +632,7 @@ Interpreter::createLLJITBuilder(
return std::move(*JB);
}
-llvm::Error Interpreter::CreateExecutor(JITConfig Config) {
+llvm::Error Interpreter::CreateExecutor() {
if (IncrExecutor)
return llvm::make_error<llvm::StringError>("Operation failed. "
"Execution engine exists",
@@ -641,13 +646,16 @@ llvm::Error Interpreter::CreateExecutor(JITConfig Config) {
llvm::Triple TargetTriple(TT);
bool IsWindowsTarget = TargetTriple.isOSWindows();
- if (!IsWindowsTarget && Config.IsOutOfProcess) {
+ if (!IncrExecutorBuilder)
+ IncrExecutorBuilder = std::make_unique<IncrementalExecutorBuilder>();
+
+ if (!IsWindowsTarget && IncrExecutorBuilder->IsOutOfProcess) {
if (!JITBuilder) {
- auto ResOrErr = outOfProcessJITBuilder(Config);
+ auto ResOrErr = outOfProcessJITBuilder(*IncrExecutorBuilder);
if (!ResOrErr)
return ResOrErr.takeError();
JITBuilder = std::move(ResOrErr->first);
- Config.ExecutorPID = ResOrErr->second;
+ IncrExecutorBuilder->ExecutorPID = ResOrErr->second;
}
if (!JITBuilder)
return llvm::make_error<llvm::StringError>(
@@ -659,29 +667,19 @@ llvm::Error Interpreter::CreateExecutor(JITConfig Config) {
auto JTMB = createJITTargetMachineBuilder(TT);
if (!JTMB)
return JTMB.takeError();
- if (Config.CM)
- JTMB->setCodeModel(Config.CM);
+ if (IncrExecutorBuilder->CM)
+ JTMB->setCodeModel(IncrExecutorBuilder->CM);
auto JB = IncrementalExecutor::createDefaultJITBuilder(std::move(*JTMB));
if (!JB)
return JB.takeError();
JITBuilder = std::move(*JB);
}
- llvm::Error Err = llvm::Error::success();
-
- // Fix: Declare Executor as the appropriate unique_ptr type
- std::unique_ptr<IncrementalExecutor> Executor;
-
-#ifdef __EMSCRIPTEN__
- Executor = std::make_unique<WasmIncrementalExecutor>(*TSCtx);
-#else
- Executor =
- std::make_unique<IncrementalExecutor>(*TSCtx, *JITBuilder, Config, Err);
-#endif
- if (!Err)
- IncrExecutor = std::move(Executor);
+ auto ExecutorOrErr = IncrExecutorBuilder->create(*TSCtx, *JITBuilder);
+ if (ExecutorOrErr)
+ IncrExecutor = std::move(*ExecutorOrErr);
- return Err;
+ return ExecutorOrErr.takeError();
}
void Interpreter::ResetExecutor() { IncrExecutor.reset(); }
diff --git a/clang/tools/clang-repl/ClangRepl.cpp b/clang/tools/clang-repl/ClangRepl.cpp
index 066f526cba9ae..e94749555ad1a 100644
--- a/clang/tools/clang-repl/ClangRepl.cpp
+++ b/clang/tools/clang-repl/ClangRepl.cpp
@@ -291,6 +291,22 @@ int main(int argc, const char **argv) {
clang::IncrementalCompilerBuilder CB;
CB.SetCompilerArgs(ClangArgv);
+ auto IEB = std::make_unique<clang::IncrementalExecutorBuilder>();
+ IEB->IsOutOfProcess = !OOPExecutor.empty() || !OOPExecutorConnect.empty();
+ IEB->OOPExecutor = OOPExecutor;
+ if (!OrcRuntimePath.empty())
+ IEB->OrcRuntimePath = OrcRuntimePath;
+ else
+ CB.SetDriverCompilationCallback(IEB->UpdateOrcRuntimePathCB);
+
+ auto SizeOrErr = getSlabAllocSize(SlabAllocateSizeString);
+ if (!SizeOrErr) {
+ llvm::logAllUnhandledErrors(SizeOrErr.takeError(), llvm::errs(), "error: ");
+ return EXIT_FAILURE;
+ }
+ IEB->SlabAllocateSize = *SizeOrErr;
+ IEB->UseSharedMemory = UseSharedMemory;
+
std::unique_ptr<clang::CompilerInstance> DeviceCI;
if (CudaEnabled) {
if (!CudaPath.empty())
@@ -306,18 +322,6 @@ int main(int argc, const char **argv) {
ExitOnErr(sanitizeOopArguments(argv[0]));
- clang::Interpreter::JITConfig Config;
- Config.IsOutOfProcess = !OOPExecutor.empty() || !OOPExecutorConnect.empty();
- Config.OOPExecutor = OOPExecutor;
- Config.OrcRuntimePath = OrcRuntimePath;
- auto SizeOrErr = getSlabAllocSize(SlabAllocateSizeString);
- if (!SizeOrErr) {
- llvm::logAllUnhandledErrors(SizeOrErr.takeError(), llvm::errs(), "error: ");
- return EXIT_FAILURE;
- }
- Config.SlabAllocateSize = *SizeOrErr;
- Config.UseSharedMemory = UseSharedMemory;
-
// 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;
@@ -350,7 +354,8 @@ int main(int argc, const char **argv) {
ExitOnErr(Interp->LoadDynamicLibrary(CudaRuntimeLibPath.c_str()));
}
} else {
- Interp = ExitOnErr(clang::Interpreter::create(std::move(CI), Config));
+ Interp =
+ ExitOnErr(clang::Interpreter::create(std::move(CI), std::move(IEB)));
}
bool HasError = false;
diff --git a/clang/unittests/Interpreter/InterpreterExtensionsTest.cpp b/clang/unittests/Interpreter/InterpreterExtensionsTest.cpp
index f50f6e320776d..07a4a224f16bc 100644
--- a/clang/unittests/Interpreter/InterpreterExtensionsTest.cpp
+++ b/clang/unittests/Interpreter/InterpreterExtensionsTest.cpp
@@ -65,45 +65,6 @@ class InterpreterExtensionsTest : public InterpreterTestBase {
}
};
-struct OutOfProcInterpreter : public Interpreter {
- OutOfProcInterpreter(
- std::unique_ptr<CompilerInstance> CI, llvm::Error &ErrOut,
- std::unique_ptr<clang::ASTConsumer> Consumer,
- std::unique_ptr<llvm::orc::LLJITBuilder> JITBuilder = nullptr)
- : Interpreter(std::move(CI), ErrOut, std::move(JITBuilder),
- std::move(Consumer)) {}
-};
-
-TEST_F(InterpreterExtensionsTest, FindRuntimeInterface) {
-// FIXME : WebAssembly doesn't currently support Jit (see
-// https: // github.com/llvm/llvm-project/pull/150977#discussion_r2237521095).
-// so this check of HostSupportsJIT has been skipped
-// over until support is added, and HostSupportsJIT can return true.
-#ifndef __EMSCRIPTEN__
- if (!HostSupportsJIT())
- GTEST_SKIP();
-#endif
- clang::IncrementalCompilerBuilder CB;
- llvm::Error ErrOut = llvm::Error::success();
- auto CI = cantFail(CB.CreateCpp());
- // Do not attach the default consumer which is specialized for in-process.
- class NoopConsumer : public ASTConsumer {};
- std::unique_ptr<ASTConsumer> C = std::make_unique<NoopConsumer>();
- OutOfProcInterpreter I(std::move(CI), ErrOut, std::move(C),
- /*JITBuilder=*/nullptr);
- cantFail(std::move(ErrOut));
- cantFail(I.Parse("int a = 1; a"));
- cantFail(I.Parse("int b = 2; b"));
- cantFail(I.Parse("int c = 3; c"));
-
- // Make sure no clang::Value logic is attached by the Interpreter.
- Value V1;
- llvm::cantFail(I.ParseAndExecute("int x = 42;"));
- llvm::cantFail(I.ParseAndExecute("x", &V1));
- EXPECT_FALSE(V1.isValid());
- EXPECT_FALSE(V1.hasValue());
-}
-
class CustomJBInterpreter : public Interpreter {
using CustomJITBuilderCreatorFunction =
std::function<llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>()>;
diff --git a/clang/unittests/Interpreter/OutOfProcessInterpreterTests.cpp b/clang/unittests/Interpreter/OutOfProcessInterpreterTests.cpp
index 704ddc37e642e..d33005244d8da 100644
--- a/clang/unittests/Interpreter/OutOfProcessInterpreterTests.cpp
+++ b/clang/unittests/Interpreter/OutOfProcessInterpreterTests.cpp
@@ -27,6 +27,7 @@
#include "llvm/TargetParser/Host.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+
#include <memory>
#include <signal.h>
#include <sstream>
@@ -101,47 +102,34 @@ static std::string getExecutorPath() {
return ExecutorPath.str().str();
}
-static std::string getOrcRuntimePath() {
- llvm::SmallString<256> RuntimePath(llvm::sys::fs::getMainExecutable(
- nullptr, reinterpret_cast<void *>(&getOrcRuntimePath)));
- removePathComponent(5, RuntimePath);
- llvm::sys::path::append(RuntimePath, CLANG_INSTALL_LIBDIR_BASENAME, "clang",
- CLANG_VERSION_MAJOR_STRING, "lib");
-
- llvm::Triple SystemTriple(llvm::sys::getProcessTriple());
- if (SystemTriple.isOSBinFormatMachO()) {
- llvm::sys::path::append(RuntimePath, "darwin", "liborc_rt_osx.a");
- } else if (SystemTriple.isOSBinFormatELF()) {
- llvm::sys::path::append(RuntimePath, "x86_64-unknown-linux-gnu",
- "liborc_rt.a");
- }
- return RuntimePath.str().str();
-}
+struct OutOfProcessInterpreterInfo {
+ std::string OrcRuntimePath;
+ std::unique_ptr<Interpreter> Interpreter;
+};
-static std::unique_ptr<Interpreter>
+static OutOfProcessInterpreterInfo
createInterpreterWithRemoteExecution(std::shared_ptr<IOContext> io_ctx,
const Args &ExtraArgs = {}) {
Args ClangArgs = {"-Xclang", "-emit-llvm-only"};
llvm::append_range(ClangArgs, ExtraArgs);
- auto CB = clang::IncrementalCompilerBuilder();
- CB.SetCompilerArgs(ClangArgs);
- auto CI = cantFail(CB.CreateCpp());
- clang::Interpreter::JITConfig Config;
+ auto Config = std::make_unique<IncrementalExecutorBuilder>();
llvm::Triple SystemTriple(llvm::sys::getProcessTriple());
if (SystemTriple.isOSBinFormatELF() || SystemTriple.isOSBinFormatMachO()) {
- Config.IsOutOfProcess = true;
- Config.OOPExecutor = getExecutorPath();
- Config.UseSharedMemory = false;
- Config.SlabAllocateSize = 0;
- Config.OrcRuntimePath = getOrcRuntimePath();
-
+ Config->IsOutOfProcess = true;
+ Config->OOPExecutor = getExecutorPath();
+ Config->UseSharedMemory = false;
+ Config->SlabAllocateSize = 0;
+
+ // Capture the raw file descriptors by value explicitly. This lambda will
+ // be invoked in the child process after fork(), so capturing the fd ints is
+ // safe and avoids capturing FILE* pointers or outer 'this'.
int stdin_fd = fileno(io_ctx->stdin_file.get());
int stdout_fd = fileno(io_ctx->stdout_file.get());
int stderr_fd = fileno(io_ctx->stderr_file.get());
- Config.CustomizeFork = [=] {
+ Config->CustomizeFork = [stdin_fd, stdout_fd, stderr_fd]() {
auto redirect = [](int from, int to) {
if (from != to) {
dup2(from, to);
@@ -153,15 +141,21 @@ createInterpreterWithRemoteExecution(std::shared_ptr<IOContext> io_ctx,
redirect(stdout_fd, STDOUT_FILENO);
redirect(stderr_fd, STDERR_FILENO);
+ // Unbuffer the stdio in the child; useful for deterministic tests.
setvbuf(stdout, nullptr, _IONBF, 0);
setvbuf(stderr, nullptr, _IONBF, 0);
+ // Helpful marker for the unit-test to assert that fork customization ran.
printf("CustomizeFork executed\n");
fflush(stdout);
};
}
-
- return cantFail(clang::Interpreter::create(std::move(CI), Config));
+ auto CB = IncrementalCompilerBuilder();
+ CB.SetCompilerArgs(ClangArgs);
+ CB.SetDriverCompilationCallback(Config->UpdateOrcRuntimePathCB);
+ auto CI = cantFail(CB.CreateCpp());
+ return {Config->OrcRuntimePath,
+ cantFail(Interpreter::create(std::move(CI), std::move(Config)))};
}
static size_t DeclsSize(TranslationUnitDecl *PTUDecl) {
@@ -172,20 +166,19 @@ TEST_F(InterpreterTestBase, SanityWithRemoteExecution) {
if (!HostSupportsJIT())
GTEST_SKIP();
- std::string OrcRuntimePath = getOrcRuntimePath();
- std::string ExecutorPath = getExecutorPath();
-
- if (!llvm::sys::fs::exists(OrcRuntimePath) ||
- !llvm::sys::fs::exists(ExecutorPath))
- GTEST_SKIP();
-
auto io_ctx = std::make_shared<IOContext>();
ASSERT_TRUE(io_ctx->initializeTempFiles());
- std::unique_ptr<Interpreter> Interp =
+ OutOfProcessInterpreterInfo Info =
createInterpreterWithRemoteExecution(io_ctx);
+ Interpreter *Interp = Info.Interpreter.get();
ASSERT_TRUE(Interp);
+ std::string ExecutorPath = getExecutorPath();
+ if (!llvm::sys::fs::exists(Info.OrcRuntimePath) ||
+ !llvm::sys::fs::exists(ExecutorPath))
+ GTEST_SKIP();
+
using PTU = PartialTranslationUnit;
PTU &R1(cantFail(Interp->Parse("void g(); void g() {}")));
EXPECT_EQ(2U, DeclsSize(R1.TUPart));
@@ -196,8 +189,31 @@ TEST_F(InterpreterTestBase, SanityWithRemoteExecution) {
std::string captured_stdout = io_ctx->readStdoutContent();
std::string captured_stderr = io_ctx->readStderrContent();
- EXPECT_TRUE(captured_stdout.find("CustomizeFork executed") !=
- std::string::npos);
+ EXPECT_NE(std::string::npos, captured_stdout.find("CustomizeFork executed"));
+}
+
+TEST_F(InterpreterTestBase, FindRuntimeInterface) {
+ if (!HostSupportsJIT())
+ GTEST_SKIP();
+
+ // make a fresh io context for this test
+ auto io_ctx = std::make_shared<IOContext>();
+ ASSERT_TRUE(io_ctx->initializeTempFiles());
+
+ OutOfProcessInterpreterInfo I = createInterpreterWithRemoteExecution(io_ctx);
+ ASSERT_TRUE(I.Interpreter);
+
+ // FIXME: Not yet supported.
+ // cantFail(I->Parse("int a = 1; a"));
+ // cantFail(I->Parse("int b = 2; b"));
+ // cantFail(I->Parse("int c = 3; c"));
+
+ // // Make sure no clang::Value logic is attached by the Interpreter.
+ // Value V1;
+ // llvm::cantFail(I->ParseAndExecute("int x = 42;"));
+ // llvm::cantFail(I->ParseAndExecute("x", &V1));
+ // EXPECT_FALSE(V1.isValid());
+ // EXPECT_FALSE(V1.hasValue());
}
-} // end anonymous namespace
\ No newline at end of file
+} // end anonymous namespace
More information about the cfe-commits
mailing list