1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
|
//===- 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.str(), 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
|