[clang] [clang-repl] Factor out CreateJITBuilder() and allow specialization in derived classes (PR #84461)
Stefan Gränitz via cfe-commits
cfe-commits at lists.llvm.org
Fri Mar 22 03:56:51 PDT 2024
https://github.com/weliveindetail updated https://github.com/llvm/llvm-project/pull/84461
>From fae2f46d25650b8480f9d3135f33a0d6532f43ca Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20Gr=C3=A4nitz?= <stefan.graenitz at gmail.com>
Date: Thu, 7 Mar 2024 23:04:22 +0100
Subject: [PATCH 1/2] [clang-repl] Add CreateJITBuilder() for specialization in
derived classes
The LLJITBuilder interface provides a very convenient way to configure the JIT.
---
clang/include/clang/Interpreter/Interpreter.h | 9 ++
clang/lib/Interpreter/IncrementalExecutor.cpp | 33 ++---
clang/lib/Interpreter/IncrementalExecutor.h | 9 +-
clang/lib/Interpreter/Interpreter.cpp | 26 +++-
.../Interpreter/InterpreterExtensionsTest.cpp | 117 +++++++++++++++++-
5 files changed, 173 insertions(+), 21 deletions(-)
diff --git a/clang/include/clang/Interpreter/Interpreter.h b/clang/include/clang/Interpreter/Interpreter.h
index 1dcba1ef967980..33ce4bbf5bea10 100644
--- a/clang/include/clang/Interpreter/Interpreter.h
+++ b/clang/include/clang/Interpreter/Interpreter.h
@@ -29,7 +29,9 @@
namespace llvm {
namespace orc {
+class JITTargetMachineBuilder;
class LLJIT;
+class LLJITBuilder;
class ThreadSafeContext;
} // namespace orc
} // namespace llvm
@@ -127,6 +129,13 @@ class Interpreter {
// custom runtime.
virtual std::unique_ptr<RuntimeInterfaceBuilder> FindRuntimeInterface();
+ // Lazily construct thev ORCv2 JITBuilder. This called when the internal
+ // IncrementalExecutor is created. The default implementation populates an
+ // in-process JIT with debugging support. Override this to configure the JIT
+ // engine used for execution.
+ virtual llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>
+ CreateJITBuilder(CompilerInstance &CI);
+
public:
virtual ~Interpreter();
diff --git a/clang/lib/Interpreter/IncrementalExecutor.cpp b/clang/lib/Interpreter/IncrementalExecutor.cpp
index 40bcef94797d43..6f036107c14a9c 100644
--- a/clang/lib/Interpreter/IncrementalExecutor.cpp
+++ b/clang/lib/Interpreter/IncrementalExecutor.cpp
@@ -20,6 +20,7 @@
#include "llvm/ExecutionEngine/Orc/Debugging/DebuggerSupport.h"
#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
+#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
@@ -36,26 +37,28 @@ LLVM_ATTRIBUTE_USED void linkComponents() {
namespace clang {
+llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>
+IncrementalExecutor::createDefaultJITBuilder(
+ llvm::orc::JITTargetMachineBuilder JTMB) {
+ auto JITBuilder = std::make_unique<llvm::orc::LLJITBuilder>();
+ JITBuilder->setJITTargetMachineBuilder(std::move(JTMB));
+ JITBuilder->setPrePlatformSetup([](llvm::orc::LLJIT &J) {
+ // Try to enable debugging of JIT'd code (only works with JITLink for
+ // ELF and MachO).
+ consumeError(llvm::orc::enableDebuggerSupport(J));
+ return llvm::Error::success();
+ });
+ return std::move(JITBuilder);
+}
+
IncrementalExecutor::IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC,
- llvm::Error &Err,
- const clang::TargetInfo &TI)
+ llvm::orc::LLJITBuilder &JITBuilder,
+ llvm::Error &Err)
: 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();
- });
-
- if (auto JitOrErr = Builder.create())
+ if (auto JitOrErr = JITBuilder.create())
Jit = std::move(*JitOrErr);
else {
Err = JitOrErr.takeError();
diff --git a/clang/lib/Interpreter/IncrementalExecutor.h b/clang/lib/Interpreter/IncrementalExecutor.h
index dd0a210a061415..b4347209e14fe3 100644
--- a/clang/lib/Interpreter/IncrementalExecutor.h
+++ b/clang/lib/Interpreter/IncrementalExecutor.h
@@ -23,7 +23,9 @@
namespace llvm {
class Error;
namespace orc {
+class JITTargetMachineBuilder;
class LLJIT;
+class LLJITBuilder;
class ThreadSafeContext;
} // namespace orc
} // namespace llvm
@@ -44,8 +46,8 @@ class IncrementalExecutor {
public:
enum SymbolNameKind { IRName, LinkerName };
- IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC, llvm::Error &Err,
- const clang::TargetInfo &TI);
+ IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC,
+ llvm::orc::LLJITBuilder &JITBuilder, llvm::Error &Err);
~IncrementalExecutor();
llvm::Error addModule(PartialTranslationUnit &PTU);
@@ -56,6 +58,9 @@ class IncrementalExecutor {
getSymbolAddress(llvm::StringRef Name, SymbolNameKind NameKind) const;
llvm::orc::LLJIT &GetExecutionEngine() { return *Jit; }
+
+ static llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>
+ createDefaultJITBuilder(llvm::orc::JITTargetMachineBuilder JTMB);
};
} // end namespace clang
diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp
index 7fa52f2f15fc49..cf31456b6950ac 100644
--- a/clang/lib/Interpreter/Interpreter.cpp
+++ b/clang/lib/Interpreter/Interpreter.cpp
@@ -372,15 +372,35 @@ Interpreter::Parse(llvm::StringRef Code) {
return IncrParser->Parse(Code);
}
+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::CreateJITBuilder(CompilerInstance &CI) {
+ auto JTMB = createJITTargetMachineBuilder(CI.getTargetOpts().Triple);
+ if (!JTMB)
+ return JTMB.takeError();
+ return IncrementalExecutor::createDefaultJITBuilder(std::move(*JTMB));
+}
+
llvm::Error Interpreter::CreateExecutor() {
- const clang::TargetInfo &TI =
- getCompilerInstance()->getASTContext().getTargetInfo();
if (IncrExecutor)
return llvm::make_error<llvm::StringError>("Operation failed. "
"Execution engine exists",
std::error_code());
+ llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>> JB =
+ CreateJITBuilder(*getCompilerInstance());
+ if (!JB)
+ return JB.takeError();
llvm::Error Err = llvm::Error::success();
- auto Executor = std::make_unique<IncrementalExecutor>(*TSCtx, Err, TI);
+ auto Executor = std::make_unique<IncrementalExecutor>(*TSCtx, **JB, Err);
if (!Err)
IncrExecutor = std::move(Executor);
diff --git a/clang/unittests/Interpreter/InterpreterExtensionsTest.cpp b/clang/unittests/Interpreter/InterpreterExtensionsTest.cpp
index b7708616fd24d3..85ab169517fa4c 100644
--- a/clang/unittests/Interpreter/InterpreterExtensionsTest.cpp
+++ b/clang/unittests/Interpreter/InterpreterExtensionsTest.cpp
@@ -18,8 +18,10 @@
#include "clang/Sema/Sema.h"
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
+#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/Threading.h"
#include "llvm/Testing/Support/Error.h"
#include "gmock/gmock.h"
@@ -51,9 +53,27 @@ class TestCreateResetExecutor : public Interpreter {
llvm::Error &Err)
: Interpreter(std::move(CI), Err) {}
- llvm::Error testCreateExecutor() { return Interpreter::CreateExecutor(); }
+ llvm::Error testCreateJITBuilderError() {
+ JB = nullptr;
+ return Interpreter::CreateExecutor();
+ }
+
+ llvm::Error testCreateExecutor() {
+ JB = std::make_unique<llvm::orc::LLJITBuilder>();
+ return Interpreter::CreateExecutor();
+ }
void resetExecutor() { Interpreter::ResetExecutor(); }
+
+private:
+ llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>
+ CreateJITBuilder(CompilerInstance &CI) override {
+ if (JB)
+ return std::move(JB);
+ return llvm::make_error<llvm::StringError>("TestError", std::error_code());
+ }
+
+ std::unique_ptr<llvm::orc::LLJITBuilder> JB;
};
#ifdef _AIX
@@ -69,6 +89,8 @@ TEST(InterpreterExtensionsTest, ExecutorCreateReset) {
llvm::Error ErrOut = llvm::Error::success();
TestCreateResetExecutor Interp(cantFail(CB.CreateCpp()), ErrOut);
cantFail(std::move(ErrOut));
+ EXPECT_THAT_ERROR(Interp.testCreateJITBuilderError(),
+ llvm::FailedWithMessage("TestError"));
cantFail(Interp.testCreateExecutor());
Interp.resetExecutor();
cantFail(Interp.testCreateExecutor());
@@ -126,4 +148,97 @@ TEST(InterpreterExtensionsTest, FindRuntimeInterface) {
EXPECT_EQ(1U, Interp.RuntimeIBPtr->TransformerQueries);
}
+class CustomJBInterpreter : public Interpreter {
+ using CustomJITBuilderCreatorFunction =
+ std::function<llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>()>;
+ CustomJITBuilderCreatorFunction JBCreator = nullptr;
+
+public:
+ CustomJBInterpreter(std::unique_ptr<CompilerInstance> CI, llvm::Error &ErrOut)
+ : Interpreter(std::move(CI), ErrOut) {}
+
+ ~CustomJBInterpreter() override {
+ // Skip cleanUp() because it would trigger LLJIT default dtors
+ Interpreter::ResetExecutor();
+ }
+
+ void setCustomJITBuilderCreator(CustomJITBuilderCreatorFunction Fn) {
+ JBCreator = std::move(Fn);
+ }
+
+ llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>
+ CreateJITBuilder(CompilerInstance &CI) override {
+ if (JBCreator)
+ return JBCreator();
+ return Interpreter::CreateJITBuilder(CI);
+ }
+
+ llvm::Error CreateExecutor() { return Interpreter::CreateExecutor(); }
+};
+
+static void initArmTarget() {
+ static llvm::once_flag F;
+ llvm::call_once(F, [] {
+ LLVMInitializeARMTarget();
+ LLVMInitializeARMTargetInfo();
+ LLVMInitializeARMTargetMC();
+ LLVMInitializeARMAsmPrinter();
+ });
+}
+
+llvm::llvm_shutdown_obj Shutdown;
+
+TEST(InterpreterExtensionsTest, DefaultCrossJIT) {
+ IncrementalCompilerBuilder CB;
+ CB.SetTargetTriple("armv6-none-eabi");
+ auto CI = cantFail(CB.CreateCpp());
+ llvm::Error ErrOut = llvm::Error::success();
+ CustomJBInterpreter Interp(std::move(CI), ErrOut);
+ cantFail(std::move(ErrOut));
+
+ initArmTarget();
+ cantFail(Interp.CreateExecutor());
+}
+
+TEST(InterpreterExtensionsTest, CustomCrossJIT) {
+ std::string TargetTriple = "armv6-none-eabi";
+
+ IncrementalCompilerBuilder CB;
+ CB.SetTargetTriple(TargetTriple);
+ auto CI = cantFail(CB.CreateCpp());
+ llvm::Error ErrOut = llvm::Error::success();
+ CustomJBInterpreter Interp(std::move(CI), ErrOut);
+ cantFail(std::move(ErrOut));
+
+ using namespace llvm::orc;
+ LLJIT *JIT = nullptr;
+ std::vector<std::unique_ptr<llvm::MemoryBuffer>> Objs;
+ Interp.setCustomJITBuilderCreator([&]() {
+ initArmTarget();
+ auto JTMB = JITTargetMachineBuilder(llvm::Triple(TargetTriple));
+ JTMB.setCPU("cortex-m0plus");
+ auto JB = std::make_unique<LLJITBuilder>();
+ JB->setJITTargetMachineBuilder(JTMB);
+ JB->setPlatformSetUp(setUpInactivePlatform);
+ JB->setNotifyCreatedCallback([&](LLJIT &J) {
+ ObjectLayer &ObjLayer = J.getObjLinkingLayer();
+ auto *JITLinkObjLayer = llvm::dyn_cast<ObjectLinkingLayer>(&ObjLayer);
+ JITLinkObjLayer->setReturnObjectBuffer(
+ [&Objs](std::unique_ptr<llvm::MemoryBuffer> MB) {
+ Objs.push_back(std::move(MB));
+ });
+ JIT = &J;
+ return llvm::Error::success();
+ });
+ return JB;
+ });
+
+ EXPECT_EQ(0U, Objs.size());
+ cantFail(Interp.CreateExecutor());
+ cantFail(Interp.ParseAndExecute("int a = 1;"));
+ ExecutorAddr Addr = cantFail(JIT->lookup("a"));
+ EXPECT_NE(0U, Addr.getValue());
+ EXPECT_EQ(1U, Objs.size());
+}
+
} // end anonymous namespace
>From 93ff657d46653e82b78ef58d4585db2b7530c647 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20Gr=C3=A4nitz?= <stefan.graenitz at gmail.com>
Date: Fri, 22 Mar 2024 11:55:09 +0100
Subject: [PATCH 2/2] Disable tests on AIX and deduplicate LLVM target init
---
clang/include/clang/Interpreter/Interpreter.h | 1 -
.../Interpreter/InterpreterExtensionsTest.cpp | 34 ++++++++++---------
2 files changed, 18 insertions(+), 17 deletions(-)
diff --git a/clang/include/clang/Interpreter/Interpreter.h b/clang/include/clang/Interpreter/Interpreter.h
index 33ce4bbf5bea10..970e0245417b51 100644
--- a/clang/include/clang/Interpreter/Interpreter.h
+++ b/clang/include/clang/Interpreter/Interpreter.h
@@ -29,7 +29,6 @@
namespace llvm {
namespace orc {
-class JITTargetMachineBuilder;
class LLJIT;
class LLJITBuilder;
class ThreadSafeContext;
diff --git a/clang/unittests/Interpreter/InterpreterExtensionsTest.cpp b/clang/unittests/Interpreter/InterpreterExtensionsTest.cpp
index 85ab169517fa4c..8bc429d9ec2d7d 100644
--- a/clang/unittests/Interpreter/InterpreterExtensionsTest.cpp
+++ b/clang/unittests/Interpreter/InterpreterExtensionsTest.cpp
@@ -26,8 +26,13 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+
#include <system_error>
+#if defined(_AIX)
+#define CLANG_INTERPRETER_PLATFORM_CANNOT_CREATE_LLJIT
+#endif
+
using namespace clang;
namespace {
@@ -43,6 +48,10 @@ struct LLVMInitRAII {
LLVMInitRAII() {
llvm::InitializeNativeTarget();
llvm::InitializeNativeTargetAsmPrinter();
+ LLVMInitializeARMTarget();
+ LLVMInitializeARMTargetInfo();
+ LLVMInitializeARMTargetMC();
+ LLVMInitializeARMAsmPrinter();
}
~LLVMInitRAII() { llvm::llvm_shutdown(); }
} LLVMInit;
@@ -76,7 +85,7 @@ class TestCreateResetExecutor : public Interpreter {
std::unique_ptr<llvm::orc::LLJITBuilder> JB;
};
-#ifdef _AIX
+#ifdef CLANG_INTERPRETER_PLATFORM_CANNOT_CREATE_LLJIT
TEST(InterpreterExtensionsTest, DISABLED_ExecutorCreateReset) {
#else
TEST(InterpreterExtensionsTest, ExecutorCreateReset) {
@@ -176,31 +185,25 @@ class CustomJBInterpreter : public Interpreter {
llvm::Error CreateExecutor() { return Interpreter::CreateExecutor(); }
};
-static void initArmTarget() {
- static llvm::once_flag F;
- llvm::call_once(F, [] {
- LLVMInitializeARMTarget();
- LLVMInitializeARMTargetInfo();
- LLVMInitializeARMTargetMC();
- LLVMInitializeARMAsmPrinter();
- });
-}
-
-llvm::llvm_shutdown_obj Shutdown;
-
+#ifdef CLANG_INTERPRETER_PLATFORM_CANNOT_CREATE_LLJIT
+TEST(InterpreterExtensionsTest, DISABLED_DefaultCrossJIT) {
+#else
TEST(InterpreterExtensionsTest, DefaultCrossJIT) {
+#endif
IncrementalCompilerBuilder CB;
CB.SetTargetTriple("armv6-none-eabi");
auto CI = cantFail(CB.CreateCpp());
llvm::Error ErrOut = llvm::Error::success();
CustomJBInterpreter Interp(std::move(CI), ErrOut);
cantFail(std::move(ErrOut));
-
- initArmTarget();
cantFail(Interp.CreateExecutor());
}
+#ifdef CLANG_INTERPRETER_PLATFORM_CANNOT_CREATE_LLJIT
+TEST(InterpreterExtensionsTest, DISABLED_CustomCrossJIT) {
+#else
TEST(InterpreterExtensionsTest, CustomCrossJIT) {
+#endif
std::string TargetTriple = "armv6-none-eabi";
IncrementalCompilerBuilder CB;
@@ -214,7 +217,6 @@ TEST(InterpreterExtensionsTest, CustomCrossJIT) {
LLJIT *JIT = nullptr;
std::vector<std::unique_ptr<llvm::MemoryBuffer>> Objs;
Interp.setCustomJITBuilderCreator([&]() {
- initArmTarget();
auto JTMB = JITTargetMachineBuilder(llvm::Triple(TargetTriple));
JTMB.setCPU("cortex-m0plus");
auto JB = std::make_unique<LLJITBuilder>();
More information about the cfe-commits
mailing list