|  | //===- unittests/Interpreter/InterpreterExtensionsTest.cpp ----------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // Unit tests for Clang's Interpreter library. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "InterpreterTestFixture.h" | 
|  |  | 
|  | #include "clang/Interpreter/Interpreter.h" | 
|  |  | 
|  | #include "clang/AST/Expr.h" | 
|  | #include "clang/Frontend/CompilerInstance.h" | 
|  | #include "clang/Sema/Lookup.h" | 
|  | #include "clang/Sema/Sema.h" | 
|  |  | 
|  | #include "llvm/ExecutionEngine/Orc/LLJIT.h" | 
|  | #include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h" | 
|  | #include "llvm/MC/TargetRegistry.h" | 
|  | #include "llvm/Support/Threading.h" | 
|  | #include "llvm/Testing/Support/Error.h" | 
|  |  | 
|  | #include "gmock/gmock.h" | 
|  | #include "gtest/gtest.h" | 
|  |  | 
|  | #include <system_error> | 
|  |  | 
|  | #if defined(_AIX) || defined(__MVS__) | 
|  | #define CLANG_INTERPRETER_PLATFORM_CANNOT_CREATE_LLJIT | 
|  | #endif | 
|  |  | 
|  | using namespace clang; | 
|  | namespace { | 
|  |  | 
|  | class InterpreterExtensionsTest : public InterpreterTestBase { | 
|  | protected: | 
|  | void SetUp() override { | 
|  | #ifdef CLANG_INTERPRETER_PLATFORM_CANNOT_CREATE_LLJIT | 
|  | GTEST_SKIP(); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | static void SetUpTestSuite() { | 
|  | llvm::InitializeAllTargets(); | 
|  | llvm::InitializeAllTargetInfos(); | 
|  | llvm::InitializeAllTargetMCs(); | 
|  | llvm::InitializeAllAsmPrinters(); | 
|  | } | 
|  |  | 
|  | public: | 
|  | // Some tests require a arm-registered-target | 
|  | static bool IsARMTargetRegistered() { | 
|  | llvm::Triple TT; | 
|  | TT.setArch(llvm::Triple::arm); | 
|  | TT.setVendor(llvm::Triple::UnknownVendor); | 
|  | TT.setOS(llvm::Triple::UnknownOS); | 
|  |  | 
|  | std::string UnusedErr; | 
|  | return llvm::TargetRegistry::lookupTarget(TT, UnusedErr); | 
|  | } | 
|  | }; | 
|  |  | 
|  | 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) { | 
|  | if (!HostSupportsJIT()) | 
|  | GTEST_SKIP(); | 
|  |  | 
|  | 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>>()>; | 
|  | CustomJITBuilderCreatorFunction JBCreator = nullptr; | 
|  |  | 
|  | public: | 
|  | 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(); | 
|  | } | 
|  |  | 
|  | llvm::Error CreateExecutor() { return Interpreter::CreateExecutor(); } | 
|  | }; | 
|  |  | 
|  | TEST_F(InterpreterExtensionsTest, DefaultCrossJIT) { | 
|  | if (!IsARMTargetRegistered()) | 
|  | GTEST_SKIP(); | 
|  |  | 
|  | IncrementalCompilerBuilder CB; | 
|  | CB.SetTargetTriple("armv6-none-eabi"); | 
|  | auto CI = cantFail(CB.CreateCpp()); | 
|  | llvm::Error ErrOut = llvm::Error::success(); | 
|  | CustomJBInterpreter Interp(std::move(CI), ErrOut, nullptr); | 
|  | cantFail(std::move(ErrOut)); | 
|  | } | 
|  |  | 
|  | TEST_F(InterpreterExtensionsTest, CustomCrossJIT) { | 
|  | if (!IsARMTargetRegistered()) | 
|  | GTEST_SKIP(); | 
|  |  | 
|  | std::string TargetTriple = "armv6-none-eabi"; | 
|  |  | 
|  | IncrementalCompilerBuilder CB; | 
|  | CB.SetTargetTriple(TargetTriple); | 
|  | auto CI = cantFail(CB.CreateCpp()); | 
|  |  | 
|  | using namespace llvm::orc; | 
|  | LLJIT *JIT = nullptr; | 
|  | std::vector<std::unique_ptr<llvm::MemoryBuffer>> Objs; | 
|  | 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.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()); | 
|  | } | 
|  |  | 
|  | } // end anonymous namespace |