Skip to content

[clang-repl] Set up executor implicitly to account for init PTUs #84758

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 5 additions & 10 deletions clang/include/clang/Interpreter/Interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,9 @@ class Interpreter {
RuntimeInterfaceBuilder::TransformExprFunction *AddPrintValueCall = nullptr;

protected:
// Derived classes can make use an extended interface of the Interpreter.
// That's useful for testing and out-of-tree clients.
Interpreter(std::unique_ptr<CompilerInstance> CI, llvm::Error &Err);
// Derived classes can use an extended interface of the Interpreter.
Interpreter(std::unique_ptr<CompilerInstance> CI, llvm::Error &Err,
std::unique_ptr<llvm::orc::LLJITBuilder> JITBuilder = nullptr);

// Create the internal IncrementalExecutor, or re-create it after calling
// ResetExecutor().
Expand All @@ -128,13 +128,6 @@ 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();

Expand Down Expand Up @@ -189,6 +182,8 @@ class Interpreter {
llvm::DenseMap<CXXRecordDecl *, llvm::orc::ExecutorAddr> Dtors;

llvm::SmallVector<Expr *, 4> ValuePrintingInfo;

std::unique_ptr<llvm::orc::LLJITBuilder> JITBuilder;
};
} // namespace clang

Expand Down
58 changes: 41 additions & 17 deletions clang/lib/Interpreter/Interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,12 +229,32 @@ IncrementalCompilerBuilder::CreateCudaHost() {
}

Interpreter::Interpreter(std::unique_ptr<CompilerInstance> CI,
llvm::Error &Err) {
llvm::ErrorAsOutParameter EAO(&Err);
llvm::Error &ErrOut,
std::unique_ptr<llvm::orc::LLJITBuilder> JITBuilder)
: JITBuilder(std::move(JITBuilder)) {
llvm::ErrorAsOutParameter EAO(&ErrOut);
auto LLVMCtx = std::make_unique<llvm::LLVMContext>();
TSCtx = std::make_unique<llvm::orc::ThreadSafeContext>(std::move(LLVMCtx));
IncrParser = std::make_unique<IncrementalParser>(*this, std::move(CI),
*TSCtx->getContext(), Err);
IncrParser = std::make_unique<IncrementalParser>(
*this, std::move(CI), *TSCtx->getContext(), ErrOut);
if (ErrOut)
return;

// Not all frontends support code-generation, e.g. ast-dump actions don't
if (IncrParser->getCodeGen()) {
if (llvm::Error Err = CreateExecutor()) {
ErrOut = joinErrors(std::move(ErrOut), std::move(Err));
return;
}

// Process the PTUs that came from initialization. For example -include will
// give us a header that's processed at initialization of the preprocessor.
for (PartialTranslationUnit &PTU : IncrParser->getPTUs())
if (llvm::Error Err = Execute(PTU)) {
ErrOut = joinErrors(std::move(ErrOut), std::move(Err));
return;
}
}
}

Interpreter::~Interpreter() {
Expand Down Expand Up @@ -382,25 +402,29 @@ createJITTargetMachineBuilder(const std::string &TT) {
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() {
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();
if (!IncrParser->getCodeGen())
return llvm::make_error<llvm::StringError>("Operation failed. "
"No code generator available",
std::error_code());
if (!JITBuilder) {
const std::string &TT = getCompilerInstance()->getTargetOpts().Triple;
auto JTMB = createJITTargetMachineBuilder(TT);
if (!JTMB)
return JTMB.takeError();
auto JB = IncrementalExecutor::createDefaultJITBuilder(std::move(*JTMB));
if (!JB)
return JB.takeError();
JITBuilder = std::move(*JB);
}

llvm::Error Err = llvm::Error::success();
auto Executor = std::make_unique<IncrementalExecutor>(*TSCtx, **JB, Err);
auto Executor =
std::make_unique<IncrementalExecutor>(*TSCtx, *JITBuilder, Err);
if (!Err)
IncrExecutor = std::move(Executor);

Expand Down
4 changes: 2 additions & 2 deletions clang/test/Interpreter/execute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

// RUN: cat %s | clang-repl | FileCheck %s
// RUN: cat %s | clang-repl -Xcc -O2 | FileCheck %s
// RUN: clang-repl -Xcc -include -Xcc %s | FileCheck %s
// RUN: clang-repl -Xcc -fsyntax-only -Xcc -include -Xcc %s
extern "C" int printf(const char *, ...);
int i = 42;
auto r1 = printf("i = %d\n", i);
Expand All @@ -19,5 +21,3 @@ auto r2 = printf("S[f=%f, m=0x%llx]\n", s.f, reinterpret_cast<unsigned long long

inline int foo() { return 42; }
int r3 = foo();

%quit
2 changes: 1 addition & 1 deletion clang/test/Interpreter/inline-virtual.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ struct A { int a; A(int a) : a(a) {} virtual ~A(); };
// PartialTranslationUnit.
inline A::~A() { printf("~A(%d)\n", a); }

// Create one instance with new and delete it.
// Create one instance with new and delete it. We crash here now:
A *a1 = new A(1);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With -O2 this test fails unexpectedly now. Minimal repro:

clang-repl> struct A { int a; A(int a) : a(a) {} virtual ~A() {} };
clang-repl> A *a1 = new A(1);
clang-repl: llvm/include/llvm/ADT/SmallVector.h:308: const_reference llvm::SmallVectorTemplateCommon<llvm::PointerAlignElem>::operator[](size_type) const [T = llvm::PointerAlignElem]: Assertion `idx < size()' failed.

The following still works and thus I assume it's related to c861d32:

clang-repl> struct A { int a; A(int a) : a(a) {} virtual ~A() {} }; A *a1 = new A(1);

@hahnjo Maybe we now process init code that clashes with your above fix. Do you think that's possible? Any idea how to handle it? If possible, I'd like to submit the patch as-is with the test XFAILed for later investigation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we even have initial PTUs in the default case? Also the minimal reproducer shows a more general version where the virtual destructor is actually defined inline (c861d32 addresses the case where it is out-of-line, which is special due to key virtual functions). So if that breaks entirely (which is critical for us), I'm personally not ok with just XFAILing it to land another change...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, probably is something worth fixing now. I could not see the stack trace on osx. Can you paste it here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we even have initial PTUs in the default case?

Well, this test passes, if I comment out the for loop in the ctor that executes initial PTUs:
https://github.com/llvm/llvm-project/pull/84758/files#diff-b8484f1fc5b057f146ed5d9b6e2cd47c3f6f5ae879c7a0eee44f0a272581a88cR250-R254

Also the minimal reproducer shows a more general version where the virtual destructor is actually defined inline (c861d32 addresses the case where it is out-of-line, which is special due to key virtual functions).

Oh that's a good note, I had not considered the difference yet and actually they have different backtraces. Eventually, they both reach the same VTablePtr code though.

I could not see the stack trace on osx. Can you paste it here?

Here is a diff (inline left, out-of-line right):
Screenshot 2024-03-12 at 11 12 36

So if that breaks entirely (which is critical for us), I'm personally not ok with just XFAILing it to land another change...

What breaks here is the parser and this patch doesn't even touch it. Not sure I am missing something, but it seems that it triggers a bug that always existed and just didn't show up so far.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me share some more observations.

We execute the initial PTU and not only parse it. It shouldn't make a difference for the parser right? Still, I wasn't sure, especially since we unusally only parse runtime PTUs. So I made some experiments:

    Init      Runtime      Dtor-def  |  New     Delete  Automatic
(1) Execute   Execute   Out-of-line  |  fails   -       fails
                             Inline  |  fails   -       once*

(2) Execute   Parse     Out-of-line  |  fails   -       fails
                             Inline  |  once*   fails   once

(3) Parse     Any       Out-of-line  |  works   works   works
                             Inline  |  works   works   works

Without -O2 everything works.
Automatic = A a1(1);
once = Works exactly once (including shutdown)
once* = Same, but only if dtor has side-effects e.g. printf call

(1) is the behavior with this patch. (3) was the status-quo before this patch.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, does valgrind say anything?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is a report from valgrind and we seem to have a problem:

==858864== Warning: set address range perms: large range [0x108000, 0x11f2c000) (defined)
==858864== Invalid read of size 8
==858864==    at 0x11E99BE: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::length() const (basic_string.h:927)
==858864==    by 0x11F1E3B: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_assign(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (basic_string.tcc:259)
==858864==    by 0x11EE135: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::assign(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (basic_string.h:1387)
==858864==    by 0x11EB15C: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::operator=(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (basic_string.h:681)
==858864==    by 0x16F1819: llvm::DataLayout::operator=(llvm::DataLayout const&) (DataLayout.h:206)
==858864==    by 0x1A552E9: llvm::DataLayout::init(llvm::Module const*) (DataLayout.cpp:557)
==858864==    by 0x1A552B3: llvm::DataLayout::DataLayout(llvm::Module const*) (DataLayout.cpp:554)
==858864==    by 0x33797CA: clang::CodeGen::CodeGenTBAA::getVTablePtrAccessInfo(llvm::Type*) (CodeGenTBAA.cpp:274)
==858864==    by 0x3221BC3: clang::CodeGen::CodeGenModule::getTBAAVTablePtrAccessInfo(llvm::Type*) (CodeGenModule.cpp:1424)
==858864==    by 0x2DCA94E: clang::CodeGen::CodeGenFunction::InitializeVTablePointer(clang::CodeGen::CodeGenFunction::VPtr const&) (CGClass.cpp:2592)
==858864==    by 0x2DCAFC8: clang::CodeGen::CodeGenFunction::InitializeVTablePointers(clang::CXXRecordDecl const*) (CGClass.cpp:2676)
==858864==    by 0x2DC519C: clang::CodeGen::CodeGenFunction::EmitDestructorBody(clang::CodeGen::FunctionArgList&) (CGClass.cpp:1525)
==858864==  Address 0x13599270 is 512 bytes inside a block of size 800 free'd
==858864==    at 0x12D50B6F: operator delete(void*, unsigned long) (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==858864==    by 0x1E5A922: std::default_delete<llvm::Module>::operator()(llvm::Module*) const (unique_ptr.h:85)
==858864==    by 0x1E5A867: std::__uniq_ptr_impl<llvm::Module, std::default_delete<llvm::Module> >::reset(llvm::Module*) (unique_ptr.h:182)
==858864==    by 0x1E5A800: std::unique_ptr<llvm::Module, std::default_delete<llvm::Module> >::reset(llvm::Module*) (unique_ptr.h:456)
==858864==    by 0x1E4F8B8: std::unique_ptr<llvm::Module, std::default_delete<llvm::Module> >::operator=(decltype(nullptr)) (unique_ptr.h:397)
==858864==    by 0x1E4B5DC: llvm::orc::ThreadSafeModule::~ThreadSafeModule() (ThreadSafeModule.h:116)
==858864==    by 0x1F4DF4F: llvm::orc::IRMaterializationUnit::~IRMaterializationUnit() (Layer.h:31)
==858864==    by 0x1FCE1D5: llvm::orc::BasicIRLayerMaterializationUnit::~BasicIRLayerMaterializationUnit() (Layer.h:120)
==858864==    by 0x1FCE1F5: llvm::orc::BasicIRLayerMaterializationUnit::~BasicIRLayerMaterializationUnit() (Layer.h:120)
==858864==    by 0x1FCE235: std::default_delete<llvm::orc::BasicIRLayerMaterializationUnit>::operator()(llvm::orc::BasicIRLayerMaterializationUnit*) const (unique_ptr.h:85)
==858864==    by 0x1FCCFFD: std::unique_ptr<llvm::orc::BasicIRLayerMaterializationUnit, std::default_delete<llvm::orc::BasicIRLayerMaterializationUnit> >::~unique_ptr() (unique_ptr.h:361)
==858864==    by 0x1FCA870: llvm::orc::IRLayer::add(llvm::IntrusiveRefCntPtr<llvm::orc::ResourceTracker>, llvm::orc::ThreadSafeModule) (Layer.cpp:27)
==858864==  Block was alloc'd at
==858864==    at 0x12D4E013: operator new(unsigned long) (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==858864==    by 0x2CC7B86: (anonymous namespace)::CodeGeneratorImpl::CodeGeneratorImpl(clang::DiagnosticsEngine&, llvm::StringRef, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>, clang::HeaderSearchOptions const&, clang::PreprocessorOptions const&, clang::CodeGenOptions const&, llvm::LLVMContext&, clang::CoverageSourceInfo*) (ModuleBuilder.cpp:87)
==858864==    by 0x2CC90C0: clang::CreateLLVMCodeGen(clang::DiagnosticsEngine&, llvm::StringRef, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>, clang::HeaderSearchOptions const&, clang::PreprocessorOptions const&, clang::CodeGenOptions const&, llvm::LLVMContext&, clang::CoverageSourceInfo*) (ModuleBuilder.cpp:372)
==858864==    by 0x2C8749E: clang::BackendConsumer::BackendConsumer(clang::BackendAction, clang::DiagnosticsEngine&, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>, clang::HeaderSearchOptions const&, clang::PreprocessorOptions const&, clang::CodeGenOptions const&, clang::TargetOptions const&, clang::LangOptions const&, clang::FileManager const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, llvm::SmallVector<clang::CodeGenAction::LinkModule, 4u>, std::unique_ptr<llvm::raw_pwrite_stream, std::default_delete<llvm::raw_pwrite_stream> >, llvm::LLVMContext&, clang::CoverageSourceInfo*) (CodeGenAction.cpp:127)
==858864==    by 0x2C8C2A0: clang::CodeGenAction::CreateASTConsumer(clang::CompilerInstance&, llvm::StringRef) (CodeGenAction.cpp:1051)
==858864==    by 0x22A1E64: clang::WrapperFrontendAction::CreateASTConsumer(clang::CompilerInstance&, llvm::StringRef) (FrontendAction.cpp:1207)
==858864==    by 0x229B7A5: clang::FrontendAction::CreateWrappedASTConsumer(clang::CompilerInstance&, llvm::StringRef) (FrontendAction.cpp:166)
==858864==    by 0x22A08F0: clang::FrontendAction::BeginSourceFile(clang::CompilerInstance&, clang::FrontendInputFile const&) (FrontendAction.cpp:955)
==858864==    by 0x2198EA6: clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) (CompilerInstance.cpp:1061)
==858864==    by 0x2573ECA: clang::IncrementalParser::IncrementalParser(clang::Interpreter&, std::unique_ptr<clang::CompilerInstance, std::default_delete<clang::CompilerInstance> >, llvm::LLVMContext&, llvm::Error&) (IncrementalParser.cpp:211)
==858864==    by 0x2562095: std::_MakeUniq<clang::IncrementalParser>::__single_object std::make_unique<clang::IncrementalParser, clang::Interpreter&, std::unique_ptr<clang::CompilerInstance, std::default_delete<clang::CompilerInstance> >, llvm::LLVMContext&, llvm::Error&>(clang::Interpreter&, std::unique_ptr<clang::CompilerInstance, std::default_delete<clang::CompilerInstance> >&&, llvm::LLVMContext&, llvm::Error&) (unique_ptr.h:962)
==858864==    by 0x25599FD: clang::Interpreter::Interpreter(std::unique_ptr<clang::CompilerInstance, std::default_delete<clang::CompilerInstance> >, llvm::Error&) (Interpreter.cpp:236)
==858864== 

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is with this patch or just current main?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, that's also the case with releases/16.x...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#89031 should unblock this PR.

delete a1;
// CHECK: ~A(1)
Expand Down
112 changes: 24 additions & 88 deletions clang/unittests/Interpreter/InterpreterExtensionsTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,58 +66,6 @@ struct LLVMInitRAII {
~LLVMInitRAII() { llvm::llvm_shutdown(); }
} LLVMInit;

class TestCreateResetExecutor : public Interpreter {
public:
TestCreateResetExecutor(std::unique_ptr<CompilerInstance> CI,
llvm::Error &Err)
: Interpreter(std::move(CI), Err) {}

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 CLANG_INTERPRETER_PLATFORM_CANNOT_CREATE_LLJIT
TEST(InterpreterExtensionsTest, DISABLED_ExecutorCreateReset) {
#else
TEST(InterpreterExtensionsTest, ExecutorCreateReset) {
#endif
// Make sure we can create the executer on the platform.
if (!HostSupportsJit())
GTEST_SKIP();

clang::IncrementalCompilerBuilder CB;
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());
EXPECT_THAT_ERROR(Interp.testCreateExecutor(),
llvm::FailedWithMessage("Operation failed. "
"Execution engine exists"));
}

class RecordRuntimeIBMetrics : public Interpreter {
struct NoopRuntimeInterfaceBuilder : public RuntimeInterfaceBuilder {
NoopRuntimeInterfaceBuilder(Sema &S) : S(S) {}
Expand Down Expand Up @@ -173,25 +121,15 @@ class CustomJBInterpreter : public Interpreter {
CustomJITBuilderCreatorFunction JBCreator = nullptr;

public:
CustomJBInterpreter(std::unique_ptr<CompilerInstance> CI, llvm::Error &ErrOut)
: Interpreter(std::move(CI), ErrOut) {}
CustomJBInterpreter(std::unique_ptr<CompilerInstance> CI, llvm::Error &ErrOut,
std::unique_ptr<llvm::orc::LLJITBuilder> JB)
: Interpreter(std::move(CI), ErrOut, std::move(JB)) {}

~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(); }
};

Expand All @@ -207,9 +145,8 @@ TEST(InterpreterExtensionsTest, DefaultCrossJIT) {
CB.SetTargetTriple("armv6-none-eabi");
auto CI = cantFail(CB.CreateCpp());
llvm::Error ErrOut = llvm::Error::success();
CustomJBInterpreter Interp(std::move(CI), ErrOut);
CustomJBInterpreter Interp(std::move(CI), ErrOut, nullptr);
cantFail(std::move(ErrOut));
cantFail(Interp.CreateExecutor());
}

#ifdef CLANG_INTERPRETER_PLATFORM_CANNOT_CREATE_LLJIT
Expand All @@ -225,35 +162,34 @@ TEST(InterpreterExtensionsTest, CustomCrossJIT) {
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([&]() {
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;
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();
});

llvm::Error ErrOut = llvm::Error::success();
CustomJBInterpreter Interp(std::move(CI), ErrOut, std::move(JB));
cantFail(std::move(ErrOut));

EXPECT_EQ(0U, Objs.size());
cantFail(Interp.CreateExecutor());
cantFail(Interp.ParseAndExecute("int a = 1;"));
ASSERT_NE(JIT, nullptr); // But it is, because JBCreator was never called
ExecutorAddr Addr = cantFail(JIT->lookup("a"));
EXPECT_NE(0U, Addr.getValue());
EXPECT_EQ(1U, Objs.size());
Expand Down
Loading