Skip to content

Commit fae2f46

Browse files
[clang-repl] Add CreateJITBuilder() for specialization in derived classes
The LLJITBuilder interface provides a very convenient way to configure the JIT.
1 parent 857161c commit fae2f46

File tree

5 files changed

+173
-21
lines changed

5 files changed

+173
-21
lines changed

clang/include/clang/Interpreter/Interpreter.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@
2929

3030
namespace llvm {
3131
namespace orc {
32+
class JITTargetMachineBuilder;
3233
class LLJIT;
34+
class LLJITBuilder;
3335
class ThreadSafeContext;
3436
} // namespace orc
3537
} // namespace llvm
@@ -127,6 +129,13 @@ class Interpreter {
127129
// custom runtime.
128130
virtual std::unique_ptr<RuntimeInterfaceBuilder> FindRuntimeInterface();
129131

132+
// Lazily construct thev ORCv2 JITBuilder. This called when the internal
133+
// IncrementalExecutor is created. The default implementation populates an
134+
// in-process JIT with debugging support. Override this to configure the JIT
135+
// engine used for execution.
136+
virtual llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>
137+
CreateJITBuilder(CompilerInstance &CI);
138+
130139
public:
131140
virtual ~Interpreter();
132141

clang/lib/Interpreter/IncrementalExecutor.cpp

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "llvm/ExecutionEngine/Orc/Debugging/DebuggerSupport.h"
2121
#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
2222
#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
23+
#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
2324
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
2425
#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
2526
#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
@@ -36,26 +37,28 @@ LLVM_ATTRIBUTE_USED void linkComponents() {
3637

3738
namespace clang {
3839

40+
llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>
41+
IncrementalExecutor::createDefaultJITBuilder(
42+
llvm::orc::JITTargetMachineBuilder JTMB) {
43+
auto JITBuilder = std::make_unique<llvm::orc::LLJITBuilder>();
44+
JITBuilder->setJITTargetMachineBuilder(std::move(JTMB));
45+
JITBuilder->setPrePlatformSetup([](llvm::orc::LLJIT &J) {
46+
// Try to enable debugging of JIT'd code (only works with JITLink for
47+
// ELF and MachO).
48+
consumeError(llvm::orc::enableDebuggerSupport(J));
49+
return llvm::Error::success();
50+
});
51+
return std::move(JITBuilder);
52+
}
53+
3954
IncrementalExecutor::IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC,
40-
llvm::Error &Err,
41-
const clang::TargetInfo &TI)
55+
llvm::orc::LLJITBuilder &JITBuilder,
56+
llvm::Error &Err)
4257
: TSCtx(TSC) {
4358
using namespace llvm::orc;
4459
llvm::ErrorAsOutParameter EAO(&Err);
4560

46-
auto JTMB = JITTargetMachineBuilder(TI.getTriple());
47-
JTMB.addFeatures(TI.getTargetOpts().Features);
48-
LLJITBuilder Builder;
49-
Builder.setJITTargetMachineBuilder(JTMB);
50-
Builder.setPrePlatformSetup(
51-
[](LLJIT &J) {
52-
// Try to enable debugging of JIT'd code (only works with JITLink for
53-
// ELF and MachO).
54-
consumeError(enableDebuggerSupport(J));
55-
return llvm::Error::success();
56-
});
57-
58-
if (auto JitOrErr = Builder.create())
61+
if (auto JitOrErr = JITBuilder.create())
5962
Jit = std::move(*JitOrErr);
6063
else {
6164
Err = JitOrErr.takeError();

clang/lib/Interpreter/IncrementalExecutor.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
namespace llvm {
2424
class Error;
2525
namespace orc {
26+
class JITTargetMachineBuilder;
2627
class LLJIT;
28+
class LLJITBuilder;
2729
class ThreadSafeContext;
2830
} // namespace orc
2931
} // namespace llvm
@@ -44,8 +46,8 @@ class IncrementalExecutor {
4446
public:
4547
enum SymbolNameKind { IRName, LinkerName };
4648

47-
IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC, llvm::Error &Err,
48-
const clang::TargetInfo &TI);
49+
IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC,
50+
llvm::orc::LLJITBuilder &JITBuilder, llvm::Error &Err);
4951
~IncrementalExecutor();
5052

5153
llvm::Error addModule(PartialTranslationUnit &PTU);
@@ -56,6 +58,9 @@ class IncrementalExecutor {
5658
getSymbolAddress(llvm::StringRef Name, SymbolNameKind NameKind) const;
5759

5860
llvm::orc::LLJIT &GetExecutionEngine() { return *Jit; }
61+
62+
static llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>
63+
createDefaultJITBuilder(llvm::orc::JITTargetMachineBuilder JTMB);
5964
};
6065

6166
} // end namespace clang

clang/lib/Interpreter/Interpreter.cpp

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -372,15 +372,35 @@ Interpreter::Parse(llvm::StringRef Code) {
372372
return IncrParser->Parse(Code);
373373
}
374374

375+
static llvm::Expected<llvm::orc::JITTargetMachineBuilder>
376+
createJITTargetMachineBuilder(const std::string &TT) {
377+
if (TT == llvm::sys::getProcessTriple())
378+
// This fails immediately if the target backend is not registered
379+
return llvm::orc::JITTargetMachineBuilder::detectHost();
380+
381+
// If the target backend is not registered, LLJITBuilder::create() will fail
382+
return llvm::orc::JITTargetMachineBuilder(llvm::Triple(TT));
383+
}
384+
385+
llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>
386+
Interpreter::CreateJITBuilder(CompilerInstance &CI) {
387+
auto JTMB = createJITTargetMachineBuilder(CI.getTargetOpts().Triple);
388+
if (!JTMB)
389+
return JTMB.takeError();
390+
return IncrementalExecutor::createDefaultJITBuilder(std::move(*JTMB));
391+
}
392+
375393
llvm::Error Interpreter::CreateExecutor() {
376-
const clang::TargetInfo &TI =
377-
getCompilerInstance()->getASTContext().getTargetInfo();
378394
if (IncrExecutor)
379395
return llvm::make_error<llvm::StringError>("Operation failed. "
380396
"Execution engine exists",
381397
std::error_code());
398+
llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>> JB =
399+
CreateJITBuilder(*getCompilerInstance());
400+
if (!JB)
401+
return JB.takeError();
382402
llvm::Error Err = llvm::Error::success();
383-
auto Executor = std::make_unique<IncrementalExecutor>(*TSCtx, Err, TI);
403+
auto Executor = std::make_unique<IncrementalExecutor>(*TSCtx, **JB, Err);
384404
if (!Err)
385405
IncrExecutor = std::move(Executor);
386406

clang/unittests/Interpreter/InterpreterExtensionsTest.cpp

Lines changed: 116 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@
1818
#include "clang/Sema/Sema.h"
1919

2020
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
21+
#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
2122
#include "llvm/Support/Error.h"
2223
#include "llvm/Support/TargetSelect.h"
24+
#include "llvm/Support/Threading.h"
2325
#include "llvm/Testing/Support/Error.h"
2426

2527
#include "gmock/gmock.h"
@@ -51,9 +53,27 @@ class TestCreateResetExecutor : public Interpreter {
5153
llvm::Error &Err)
5254
: Interpreter(std::move(CI), Err) {}
5355

54-
llvm::Error testCreateExecutor() { return Interpreter::CreateExecutor(); }
56+
llvm::Error testCreateJITBuilderError() {
57+
JB = nullptr;
58+
return Interpreter::CreateExecutor();
59+
}
60+
61+
llvm::Error testCreateExecutor() {
62+
JB = std::make_unique<llvm::orc::LLJITBuilder>();
63+
return Interpreter::CreateExecutor();
64+
}
5565

5666
void resetExecutor() { Interpreter::ResetExecutor(); }
67+
68+
private:
69+
llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>
70+
CreateJITBuilder(CompilerInstance &CI) override {
71+
if (JB)
72+
return std::move(JB);
73+
return llvm::make_error<llvm::StringError>("TestError", std::error_code());
74+
}
75+
76+
std::unique_ptr<llvm::orc::LLJITBuilder> JB;
5777
};
5878

5979
#ifdef _AIX
@@ -69,6 +89,8 @@ TEST(InterpreterExtensionsTest, ExecutorCreateReset) {
6989
llvm::Error ErrOut = llvm::Error::success();
7090
TestCreateResetExecutor Interp(cantFail(CB.CreateCpp()), ErrOut);
7191
cantFail(std::move(ErrOut));
92+
EXPECT_THAT_ERROR(Interp.testCreateJITBuilderError(),
93+
llvm::FailedWithMessage("TestError"));
7294
cantFail(Interp.testCreateExecutor());
7395
Interp.resetExecutor();
7496
cantFail(Interp.testCreateExecutor());
@@ -126,4 +148,97 @@ TEST(InterpreterExtensionsTest, FindRuntimeInterface) {
126148
EXPECT_EQ(1U, Interp.RuntimeIBPtr->TransformerQueries);
127149
}
128150

151+
class CustomJBInterpreter : public Interpreter {
152+
using CustomJITBuilderCreatorFunction =
153+
std::function<llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>()>;
154+
CustomJITBuilderCreatorFunction JBCreator = nullptr;
155+
156+
public:
157+
CustomJBInterpreter(std::unique_ptr<CompilerInstance> CI, llvm::Error &ErrOut)
158+
: Interpreter(std::move(CI), ErrOut) {}
159+
160+
~CustomJBInterpreter() override {
161+
// Skip cleanUp() because it would trigger LLJIT default dtors
162+
Interpreter::ResetExecutor();
163+
}
164+
165+
void setCustomJITBuilderCreator(CustomJITBuilderCreatorFunction Fn) {
166+
JBCreator = std::move(Fn);
167+
}
168+
169+
llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>
170+
CreateJITBuilder(CompilerInstance &CI) override {
171+
if (JBCreator)
172+
return JBCreator();
173+
return Interpreter::CreateJITBuilder(CI);
174+
}
175+
176+
llvm::Error CreateExecutor() { return Interpreter::CreateExecutor(); }
177+
};
178+
179+
static void initArmTarget() {
180+
static llvm::once_flag F;
181+
llvm::call_once(F, [] {
182+
LLVMInitializeARMTarget();
183+
LLVMInitializeARMTargetInfo();
184+
LLVMInitializeARMTargetMC();
185+
LLVMInitializeARMAsmPrinter();
186+
});
187+
}
188+
189+
llvm::llvm_shutdown_obj Shutdown;
190+
191+
TEST(InterpreterExtensionsTest, DefaultCrossJIT) {
192+
IncrementalCompilerBuilder CB;
193+
CB.SetTargetTriple("armv6-none-eabi");
194+
auto CI = cantFail(CB.CreateCpp());
195+
llvm::Error ErrOut = llvm::Error::success();
196+
CustomJBInterpreter Interp(std::move(CI), ErrOut);
197+
cantFail(std::move(ErrOut));
198+
199+
initArmTarget();
200+
cantFail(Interp.CreateExecutor());
201+
}
202+
203+
TEST(InterpreterExtensionsTest, CustomCrossJIT) {
204+
std::string TargetTriple = "armv6-none-eabi";
205+
206+
IncrementalCompilerBuilder CB;
207+
CB.SetTargetTriple(TargetTriple);
208+
auto CI = cantFail(CB.CreateCpp());
209+
llvm::Error ErrOut = llvm::Error::success();
210+
CustomJBInterpreter Interp(std::move(CI), ErrOut);
211+
cantFail(std::move(ErrOut));
212+
213+
using namespace llvm::orc;
214+
LLJIT *JIT = nullptr;
215+
std::vector<std::unique_ptr<llvm::MemoryBuffer>> Objs;
216+
Interp.setCustomJITBuilderCreator([&]() {
217+
initArmTarget();
218+
auto JTMB = JITTargetMachineBuilder(llvm::Triple(TargetTriple));
219+
JTMB.setCPU("cortex-m0plus");
220+
auto JB = std::make_unique<LLJITBuilder>();
221+
JB->setJITTargetMachineBuilder(JTMB);
222+
JB->setPlatformSetUp(setUpInactivePlatform);
223+
JB->setNotifyCreatedCallback([&](LLJIT &J) {
224+
ObjectLayer &ObjLayer = J.getObjLinkingLayer();
225+
auto *JITLinkObjLayer = llvm::dyn_cast<ObjectLinkingLayer>(&ObjLayer);
226+
JITLinkObjLayer->setReturnObjectBuffer(
227+
[&Objs](std::unique_ptr<llvm::MemoryBuffer> MB) {
228+
Objs.push_back(std::move(MB));
229+
});
230+
JIT = &J;
231+
return llvm::Error::success();
232+
});
233+
return JB;
234+
});
235+
236+
EXPECT_EQ(0U, Objs.size());
237+
cantFail(Interp.CreateExecutor());
238+
cantFail(Interp.ParseAndExecute("int a = 1;"));
239+
ExecutorAddr Addr = cantFail(JIT->lookup("a"));
240+
EXPECT_NE(0U, Addr.getValue());
241+
EXPECT_EQ(1U, Objs.size());
242+
}
243+
129244
} // end anonymous namespace

0 commit comments

Comments
 (0)