1//===- unittests/Interpreter/InterpreterExtensionsTest.cpp ----------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Unit tests for Clang's Interpreter library.
10//
11//===----------------------------------------------------------------------===//
12
13#include "clang/Interpreter/Interpreter.h"
14
15#include "clang/AST/Expr.h"
16#include "clang/Frontend/CompilerInstance.h"
17#include "clang/Sema/Lookup.h"
18#include "clang/Sema/Sema.h"
19
20#include "llvm/ExecutionEngine/Orc/LLJIT.h"
21#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
22#include "llvm/MC/TargetRegistry.h"
23#include "llvm/Support/Error.h"
24#include "llvm/Support/TargetSelect.h"
25#include "llvm/Support/Threading.h"
26#include "llvm/Testing/Support/Error.h"
27
28#include "gmock/gmock.h"
29#include "gtest/gtest.h"
30
31#include <system_error>
32
33#if defined(_AIX) || defined(__MVS__)
34#define CLANG_INTERPRETER_PLATFORM_CANNOT_CREATE_LLJIT
35#endif
36
37using namespace clang;
38namespace {
39
40static bool HostSupportsJit() {
41 auto J = llvm::orc::LLJITBuilder().create();
42 if (J)
43 return true;
44 LLVMConsumeError(Err: llvm::wrap(Err: J.takeError()));
45 return false;
46}
47
48// Some tests require a arm-registered-target
49static bool IsARMTargetRegistered() {
50 llvm::Triple TT;
51 TT.setArch(Kind: llvm::Triple::arm);
52 TT.setVendor(llvm::Triple::UnknownVendor);
53 TT.setOS(llvm::Triple::UnknownOS);
54
55 std::string UnusedErr;
56 return llvm::TargetRegistry::lookupTarget(Triple: TT.str(), Error&: UnusedErr);
57}
58
59struct LLVMInitRAII {
60 LLVMInitRAII() {
61 llvm::InitializeAllTargets();
62 llvm::InitializeAllTargetInfos();
63 llvm::InitializeAllTargetMCs();
64 llvm::InitializeAllAsmPrinters();
65 }
66 ~LLVMInitRAII() { llvm::llvm_shutdown(); }
67} LLVMInit;
68
69class TestCreateResetExecutor : public Interpreter {
70public:
71 TestCreateResetExecutor(std::unique_ptr<CompilerInstance> CI,
72 llvm::Error &Err)
73 : Interpreter(std::move(CI), Err) {}
74
75 llvm::Error testCreateJITBuilderError() {
76 JB = nullptr;
77 return Interpreter::CreateExecutor();
78 }
79
80 llvm::Error testCreateExecutor() {
81 JB = std::make_unique<llvm::orc::LLJITBuilder>();
82 return Interpreter::CreateExecutor();
83 }
84
85 void resetExecutor() { Interpreter::ResetExecutor(); }
86
87private:
88 llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>
89 CreateJITBuilder(CompilerInstance &CI) override {
90 if (JB)
91 return std::move(JB);
92 return llvm::make_error<llvm::StringError>(Args: "TestError", Args: std::error_code());
93 }
94
95 std::unique_ptr<llvm::orc::LLJITBuilder> JB;
96};
97
98#ifdef CLANG_INTERPRETER_PLATFORM_CANNOT_CREATE_LLJIT
99TEST(InterpreterExtensionsTest, DISABLED_ExecutorCreateReset) {
100#else
101TEST(InterpreterExtensionsTest, ExecutorCreateReset) {
102#endif
103 // Make sure we can create the executer on the platform.
104 if (!HostSupportsJit())
105 GTEST_SKIP();
106
107 clang::IncrementalCompilerBuilder CB;
108 llvm::Error ErrOut = llvm::Error::success();
109 TestCreateResetExecutor Interp(cantFail(ValOrErr: CB.CreateCpp()), ErrOut);
110 cantFail(Err: std::move(ErrOut));
111 EXPECT_THAT_ERROR(Interp.testCreateJITBuilderError(),
112 llvm::FailedWithMessage("TestError"));
113 cantFail(Err: Interp.testCreateExecutor());
114 Interp.resetExecutor();
115 cantFail(Err: Interp.testCreateExecutor());
116 EXPECT_THAT_ERROR(Interp.testCreateExecutor(),
117 llvm::FailedWithMessage("Operation failed. "
118 "Execution engine exists"));
119}
120
121class RecordRuntimeIBMetrics : public Interpreter {
122 struct NoopRuntimeInterfaceBuilder : public RuntimeInterfaceBuilder {
123 NoopRuntimeInterfaceBuilder(Sema &S) : S(S) {}
124
125 TransformExprFunction *getPrintValueTransformer() override {
126 TransformerQueries += 1;
127 return &noop;
128 }
129
130 static ExprResult noop(RuntimeInterfaceBuilder *Builder, Expr *E,
131 ArrayRef<Expr *> FixedArgs) {
132 auto *B = static_cast<NoopRuntimeInterfaceBuilder *>(Builder);
133 B->TransformedExprs += 1;
134 return B->S.ActOnFinishFullExpr(Expr: E, /*DiscardedValue=*/false);
135 }
136
137 Sema &S;
138 size_t TransformedExprs = 0;
139 size_t TransformerQueries = 0;
140 };
141
142public:
143 // Inherit with using wouldn't make it public
144 RecordRuntimeIBMetrics(std::unique_ptr<CompilerInstance> CI, llvm::Error &Err)
145 : Interpreter(std::move(CI), Err) {}
146
147 std::unique_ptr<RuntimeInterfaceBuilder> FindRuntimeInterface() override {
148 assert(RuntimeIBPtr == nullptr && "We create the builder only once");
149 Sema &S = getCompilerInstance()->getSema();
150 auto RuntimeIB = std::make_unique<NoopRuntimeInterfaceBuilder>(args&: S);
151 RuntimeIBPtr = RuntimeIB.get();
152 return RuntimeIB;
153 }
154
155 NoopRuntimeInterfaceBuilder *RuntimeIBPtr = nullptr;
156};
157
158TEST(InterpreterExtensionsTest, FindRuntimeInterface) {
159 clang::IncrementalCompilerBuilder CB;
160 llvm::Error ErrOut = llvm::Error::success();
161 RecordRuntimeIBMetrics Interp(cantFail(ValOrErr: CB.CreateCpp()), ErrOut);
162 cantFail(Err: std::move(ErrOut));
163 cantFail(ValOrErr: Interp.Parse(Code: "int a = 1; a"));
164 cantFail(ValOrErr: Interp.Parse(Code: "int b = 2; b"));
165 cantFail(ValOrErr: Interp.Parse(Code: "int c = 3; c"));
166 EXPECT_EQ(3U, Interp.RuntimeIBPtr->TransformedExprs);
167 EXPECT_EQ(1U, Interp.RuntimeIBPtr->TransformerQueries);
168}
169
170class CustomJBInterpreter : public Interpreter {
171 using CustomJITBuilderCreatorFunction =
172 std::function<llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>()>;
173 CustomJITBuilderCreatorFunction JBCreator = nullptr;
174
175public:
176 CustomJBInterpreter(std::unique_ptr<CompilerInstance> CI, llvm::Error &ErrOut)
177 : Interpreter(std::move(CI), ErrOut) {}
178
179 ~CustomJBInterpreter() override {
180 // Skip cleanUp() because it would trigger LLJIT default dtors
181 Interpreter::ResetExecutor();
182 }
183
184 void setCustomJITBuilderCreator(CustomJITBuilderCreatorFunction Fn) {
185 JBCreator = std::move(Fn);
186 }
187
188 llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>
189 CreateJITBuilder(CompilerInstance &CI) override {
190 if (JBCreator)
191 return JBCreator();
192 return Interpreter::CreateJITBuilder(CI);
193 }
194
195 llvm::Error CreateExecutor() { return Interpreter::CreateExecutor(); }
196};
197
198#ifdef CLANG_INTERPRETER_PLATFORM_CANNOT_CREATE_LLJIT
199TEST(InterpreterExtensionsTest, DISABLED_DefaultCrossJIT) {
200#else
201TEST(InterpreterExtensionsTest, DefaultCrossJIT) {
202#endif
203 if (!IsARMTargetRegistered())
204 GTEST_SKIP();
205
206 IncrementalCompilerBuilder CB;
207 CB.SetTargetTriple("armv6-none-eabi");
208 auto CI = cantFail(ValOrErr: CB.CreateCpp());
209 llvm::Error ErrOut = llvm::Error::success();
210 CustomJBInterpreter Interp(std::move(CI), ErrOut);
211 cantFail(Err: std::move(ErrOut));
212 cantFail(Err: Interp.CreateExecutor());
213}
214
215#ifdef CLANG_INTERPRETER_PLATFORM_CANNOT_CREATE_LLJIT
216TEST(InterpreterExtensionsTest, DISABLED_CustomCrossJIT) {
217#else
218TEST(InterpreterExtensionsTest, CustomCrossJIT) {
219#endif
220 if (!IsARMTargetRegistered())
221 GTEST_SKIP();
222
223 std::string TargetTriple = "armv6-none-eabi";
224
225 IncrementalCompilerBuilder CB;
226 CB.SetTargetTriple(TargetTriple);
227 auto CI = cantFail(ValOrErr: CB.CreateCpp());
228 llvm::Error ErrOut = llvm::Error::success();
229 CustomJBInterpreter Interp(std::move(CI), ErrOut);
230 cantFail(Err: std::move(ErrOut));
231
232 using namespace llvm::orc;
233 LLJIT *JIT = nullptr;
234 std::vector<std::unique_ptr<llvm::MemoryBuffer>> Objs;
235 Interp.setCustomJITBuilderCreator([&]() {
236 auto JTMB = JITTargetMachineBuilder(llvm::Triple(TargetTriple));
237 JTMB.setCPU("cortex-m0plus");
238 auto JB = std::make_unique<LLJITBuilder>();
239 JB->setJITTargetMachineBuilder(JTMB);
240 JB->setPlatformSetUp(setUpInactivePlatform);
241 JB->setNotifyCreatedCallback([&](LLJIT &J) {
242 ObjectLayer &ObjLayer = J.getObjLinkingLayer();
243 auto *JITLinkObjLayer = llvm::dyn_cast<ObjectLinkingLayer>(Val: &ObjLayer);
244 JITLinkObjLayer->setReturnObjectBuffer(
245 [&Objs](std::unique_ptr<llvm::MemoryBuffer> MB) {
246 Objs.push_back(x: std::move(MB));
247 });
248 JIT = &J;
249 return llvm::Error::success();
250 });
251 return JB;
252 });
253
254 EXPECT_EQ(0U, Objs.size());
255 cantFail(Err: Interp.CreateExecutor());
256 cantFail(Err: Interp.ParseAndExecute(Code: "int a = 1;"));
257 ExecutorAddr Addr = cantFail(ValOrErr: JIT->lookup(UnmangledName: "a"));
258 EXPECT_NE(0U, Addr.getValue());
259 EXPECT_EQ(1U, Objs.size());
260}
261
262} // end anonymous namespace
263

source code of clang/unittests/Interpreter/InterpreterExtensionsTest.cpp