Skip to content

Commit cc46034

Browse files
[clang-repl] Add CreateJITBuilder() for specialization in derived classes
The LLJITBuilder interface provides a very convenient wat to configure the JIT.
1 parent 1972f25 commit cc46034

File tree

5 files changed

+165
-22
lines changed

5 files changed

+165
-22
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: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -373,21 +373,32 @@ Interpreter::Parse(llvm::StringRef Code) {
373373
static llvm::Expected<llvm::orc::JITTargetMachineBuilder>
374374
createJITTargetMachineBuilder(const std::string &TT) {
375375
if (TT == llvm::sys::getProcessTriple())
376+
// This fails immediately if the target backend is not registered
376377
return llvm::orc::JITTargetMachineBuilder::detectHost();
377-
// FIXME: This can fail as well if the target is not registered! We just don't
378-
// catch it yet.
378+
379+
// If the target backend is not registered, LLJITBuilder::create() will fail
379380
return llvm::orc::JITTargetMachineBuilder(llvm::Triple(TT));
380381
}
381382

383+
llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>
384+
Interpreter::CreateJITBuilder(CompilerInstance &CI) {
385+
auto JTMB = createJITTargetMachineBuilder(CI.getTargetOpts().Triple);
386+
if (!JTMB)
387+
return JTMB.takeError();
388+
return IncrementalExecutor::createDefaultJITBuilder(std::move(*JTMB));
389+
}
390+
382391
llvm::Error Interpreter::CreateExecutor() {
383-
const clang::TargetInfo &TI =
384-
getCompilerInstance()->getASTContext().getTargetInfo();
385392
if (IncrExecutor)
386393
return llvm::make_error<llvm::StringError>("Operation failed. "
387394
"Execution engine exists",
388395
std::error_code());
396+
llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>> JB =
397+
CreateJITBuilder(*getCompilerInstance());
398+
if (!JB)
399+
return JB.takeError();
389400
llvm::Error Err = llvm::Error::success();
390-
auto Executor = std::make_unique<IncrementalExecutor>(*TSCtx, Err, TI);
401+
auto Executor = std::make_unique<IncrementalExecutor>(*TSCtx, **JB, Err);
391402
if (!Err)
392403
IncrExecutor = std::move(Executor);
393404

clang/unittests/Interpreter/InterpreterExtensionsTest.cpp

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@
1717
#include "clang/Sema/Lookup.h"
1818
#include "clang/Sema/Sema.h"
1919

20+
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
21+
#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
2022
#include "llvm/Support/Error.h"
23+
#include "llvm/Support/TargetSelect.h"
24+
#include "llvm/Support/Threading.h"
2125
#include "llvm/Testing/Support/Error.h"
2226

2327
#include "gmock/gmock.h"
@@ -33,18 +37,36 @@ class TestCreateResetExecutor : public Interpreter {
3337
llvm::Error &Err)
3438
: Interpreter(std::move(CI), Err) {}
3539

40+
llvm::Error testCreateJITBuilderError() {
41+
JB = nullptr;
42+
return Interpreter::CreateExecutor();
43+
}
44+
3645
llvm::Error testCreateExecutor() {
46+
JB = std::make_unique<llvm::orc::LLJITBuilder>();
3747
return Interpreter::CreateExecutor();
3848
}
3949

4050
void resetExecutor() { Interpreter::ResetExecutor(); }
51+
52+
private:
53+
llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>
54+
CreateJITBuilder(CompilerInstance &CI) override {
55+
if (JB)
56+
return std::move(JB);
57+
return llvm::make_error<llvm::StringError>("TestError", std::error_code());
58+
}
59+
60+
std::unique_ptr<llvm::orc::LLJITBuilder> JB;
4161
};
4262

4363
TEST(InterpreterExtensionsTest, ExecutorCreateReset) {
4464
clang::IncrementalCompilerBuilder CB;
4565
llvm::Error ErrOut = llvm::Error::success();
4666
TestCreateResetExecutor Interp(cantFail(CB.CreateCpp()), ErrOut);
4767
cantFail(std::move(ErrOut));
68+
EXPECT_THAT_ERROR(Interp.testCreateJITBuilderError(),
69+
llvm::FailedWithMessage("TestError"));
4870
cantFail(Interp.testCreateExecutor());
4971
Interp.resetExecutor();
5072
cantFail(Interp.testCreateExecutor());
@@ -102,4 +124,97 @@ TEST(InterpreterExtensionsTest, FindRuntimeInterface) {
102124
EXPECT_EQ(1U, Interp.RuntimeIBPtr->TransformerQueries);
103125
}
104126

127+
class CustomJBInterpreter : public Interpreter {
128+
using CustomJITBuilderCreatorFunction =
129+
std::function<llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>()>;
130+
CustomJITBuilderCreatorFunction JBCreator = nullptr;
131+
132+
public:
133+
CustomJBInterpreter(std::unique_ptr<CompilerInstance> CI, llvm::Error &ErrOut)
134+
: Interpreter(std::move(CI), ErrOut) {}
135+
136+
~CustomJBInterpreter() override {
137+
// Skip cleanUp() because it would trigger LLJIT default dtors
138+
Interpreter::ResetExecutor();
139+
}
140+
141+
void setCustomJITBuilderCreator(CustomJITBuilderCreatorFunction Fn) {
142+
JBCreator = std::move(Fn);
143+
}
144+
145+
llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>
146+
CreateJITBuilder(CompilerInstance &CI) override {
147+
if (JBCreator)
148+
return JBCreator();
149+
return Interpreter::CreateJITBuilder(CI);
150+
}
151+
152+
llvm::Error CreateExecutor() { return Interpreter::CreateExecutor(); }
153+
};
154+
155+
static void initArmTarget() {
156+
static llvm::once_flag F;
157+
llvm::call_once(F, [] {
158+
LLVMInitializeARMTarget();
159+
LLVMInitializeARMTargetInfo();
160+
LLVMInitializeARMTargetMC();
161+
LLVMInitializeARMAsmPrinter();
162+
});
163+
}
164+
165+
llvm::llvm_shutdown_obj Shutdown;
166+
167+
TEST(InterpreterExtensionsTest, DefaultCrossJIT) {
168+
IncrementalCompilerBuilder CB;
169+
CB.SetTargetTriple("armv6-none-eabi");
170+
auto CI = cantFail(CB.CreateCpp());
171+
llvm::Error ErrOut = llvm::Error::success();
172+
CustomJBInterpreter Interp(std::move(CI), ErrOut);
173+
cantFail(std::move(ErrOut));
174+
175+
initArmTarget();
176+
cantFail(Interp.CreateExecutor());
177+
}
178+
179+
TEST(InterpreterExtensionsTest, CustomCrossJIT) {
180+
std::string TargetTriple = "armv6-none-eabi";
181+
182+
IncrementalCompilerBuilder CB;
183+
CB.SetTargetTriple(TargetTriple);
184+
auto CI = cantFail(CB.CreateCpp());
185+
llvm::Error ErrOut = llvm::Error::success();
186+
CustomJBInterpreter Interp(std::move(CI), ErrOut);
187+
cantFail(std::move(ErrOut));
188+
189+
using namespace llvm::orc;
190+
LLJIT *JIT = nullptr;
191+
std::vector<std::unique_ptr<llvm::MemoryBuffer>> Objs;
192+
Interp.setCustomJITBuilderCreator([&]() {
193+
initArmTarget();
194+
auto JTMB = JITTargetMachineBuilder(llvm::Triple(TargetTriple));
195+
JTMB.setCPU("cortex-m0plus");
196+
auto JB = std::make_unique<LLJITBuilder>();
197+
JB->setJITTargetMachineBuilder(JTMB);
198+
JB->setPlatformSetUp(setUpInactivePlatform);
199+
JB->setNotifyCreatedCallback([&](LLJIT &J) {
200+
ObjectLayer &ObjLayer = J.getObjLinkingLayer();
201+
auto *JITLinkObjLayer = llvm::dyn_cast<ObjectLinkingLayer>(&ObjLayer);
202+
JITLinkObjLayer->setReturnObjectBuffer(
203+
[&Objs](std::unique_ptr<llvm::MemoryBuffer> MB) {
204+
Objs.push_back(std::move(MB));
205+
});
206+
JIT = &J;
207+
return llvm::Error::success();
208+
});
209+
return JB;
210+
});
211+
212+
EXPECT_EQ(0U, Objs.size());
213+
cantFail(Interp.CreateExecutor());
214+
cantFail(Interp.ParseAndExecute("int a = 1;"));
215+
ExecutorAddr Addr = cantFail(JIT->lookup("a"));
216+
EXPECT_NE(0U, Addr.getValue());
217+
EXPECT_EQ(1U, Objs.size());
218+
}
219+
105220
} // end anonymous namespace

0 commit comments

Comments
 (0)