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 "InterpreterTestFixture.h" |
14 | |
15 | #include "clang/Interpreter/Interpreter.h" |
16 | |
17 | #include "clang/AST/Expr.h" |
18 | #include "clang/Frontend/CompilerInstance.h" |
19 | #include "clang/Sema/Lookup.h" |
20 | #include "clang/Sema/Sema.h" |
21 | |
22 | #include "llvm/ExecutionEngine/Orc/LLJIT.h" |
23 | #include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h" |
24 | #include "llvm/MC/TargetRegistry.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 | |
37 | using namespace clang; |
38 | namespace { |
39 | |
40 | class InterpreterExtensionsTest : public InterpreterTestBase { |
41 | protected: |
42 | void SetUp() override { |
43 | #ifdef CLANG_INTERPRETER_PLATFORM_CANNOT_CREATE_LLJIT |
44 | GTEST_SKIP(); |
45 | #endif |
46 | } |
47 | |
48 | static void SetUpTestSuite() { |
49 | llvm::InitializeAllTargets(); |
50 | llvm::InitializeAllTargetInfos(); |
51 | llvm::InitializeAllTargetMCs(); |
52 | llvm::InitializeAllAsmPrinters(); |
53 | } |
54 | |
55 | public: |
56 | // Some tests require a arm-registered-target |
57 | static bool IsARMTargetRegistered() { |
58 | llvm::Triple TT; |
59 | TT.setArch(Kind: llvm::Triple::arm); |
60 | TT.setVendor(llvm::Triple::UnknownVendor); |
61 | TT.setOS(llvm::Triple::UnknownOS); |
62 | |
63 | std::string UnusedErr; |
64 | return llvm::TargetRegistry::lookupTarget(TheTriple: TT, Error&: UnusedErr); |
65 | } |
66 | }; |
67 | |
68 | struct OutOfProcInterpreter : public Interpreter { |
69 | OutOfProcInterpreter( |
70 | std::unique_ptr<CompilerInstance> CI, llvm::Error &ErrOut, |
71 | std::unique_ptr<clang::ASTConsumer> Consumer, |
72 | std::unique_ptr<llvm::orc::LLJITBuilder> JITBuilder = nullptr) |
73 | : Interpreter(std::move(CI), ErrOut, std::move(JITBuilder), |
74 | std::move(Consumer)) {} |
75 | }; |
76 | |
77 | TEST_F(InterpreterExtensionsTest, FindRuntimeInterface) { |
78 | if (!HostSupportsJIT()) |
79 | GTEST_SKIP(); |
80 | |
81 | clang::IncrementalCompilerBuilder CB; |
82 | llvm::Error ErrOut = llvm::Error::success(); |
83 | auto CI = cantFail(ValOrErr: CB.CreateCpp()); |
84 | // Do not attach the default consumer which is specialized for in-process. |
85 | class NoopConsumer : public ASTConsumer {}; |
86 | std::unique_ptr<ASTConsumer> C = std::make_unique<NoopConsumer>(); |
87 | OutOfProcInterpreter I(std::move(CI), ErrOut, std::move(C), |
88 | /*JITBuilder=*/nullptr); |
89 | cantFail(Err: std::move(ErrOut)); |
90 | cantFail(ValOrErr: I.Parse(Code: "int a = 1; a" )); |
91 | cantFail(ValOrErr: I.Parse(Code: "int b = 2; b" )); |
92 | cantFail(ValOrErr: I.Parse(Code: "int c = 3; c" )); |
93 | |
94 | // Make sure no clang::Value logic is attached by the Interpreter. |
95 | Value V1; |
96 | llvm::cantFail(Err: I.ParseAndExecute(Code: "int x = 42;" )); |
97 | llvm::cantFail(Err: I.ParseAndExecute(Code: "x" , V: &V1)); |
98 | EXPECT_FALSE(V1.isValid()); |
99 | EXPECT_FALSE(V1.hasValue()); |
100 | } |
101 | |
102 | class CustomJBInterpreter : public Interpreter { |
103 | using CustomJITBuilderCreatorFunction = |
104 | std::function<llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>()>; |
105 | CustomJITBuilderCreatorFunction JBCreator = nullptr; |
106 | |
107 | public: |
108 | CustomJBInterpreter(std::unique_ptr<CompilerInstance> CI, llvm::Error &ErrOut, |
109 | std::unique_ptr<llvm::orc::LLJITBuilder> JB) |
110 | : Interpreter(std::move(CI), ErrOut, std::move(JB)) {} |
111 | |
112 | ~CustomJBInterpreter() override { |
113 | // Skip cleanUp() because it would trigger LLJIT default dtors |
114 | Interpreter::ResetExecutor(); |
115 | } |
116 | |
117 | llvm::Error CreateExecutor() { return Interpreter::CreateExecutor(); } |
118 | }; |
119 | |
120 | TEST_F(InterpreterExtensionsTest, DefaultCrossJIT) { |
121 | if (!IsARMTargetRegistered()) |
122 | GTEST_SKIP(); |
123 | |
124 | IncrementalCompilerBuilder CB; |
125 | CB.SetTargetTriple("armv6-none-eabi" ); |
126 | auto CI = cantFail(ValOrErr: CB.CreateCpp()); |
127 | llvm::Error ErrOut = llvm::Error::success(); |
128 | CustomJBInterpreter Interp(std::move(CI), ErrOut, nullptr); |
129 | cantFail(Err: std::move(ErrOut)); |
130 | } |
131 | |
132 | TEST_F(InterpreterExtensionsTest, CustomCrossJIT) { |
133 | if (!IsARMTargetRegistered()) |
134 | GTEST_SKIP(); |
135 | |
136 | std::string TargetTriple = "armv6-none-eabi" ; |
137 | |
138 | IncrementalCompilerBuilder CB; |
139 | CB.SetTargetTriple(TargetTriple); |
140 | auto CI = cantFail(ValOrErr: CB.CreateCpp()); |
141 | |
142 | using namespace llvm::orc; |
143 | LLJIT *JIT = nullptr; |
144 | std::vector<std::unique_ptr<llvm::MemoryBuffer>> Objs; |
145 | auto JTMB = JITTargetMachineBuilder(llvm::Triple(TargetTriple)); |
146 | JTMB.setCPU("cortex-m0plus" ); |
147 | |
148 | auto JB = std::make_unique<LLJITBuilder>(); |
149 | JB->setJITTargetMachineBuilder(JTMB); |
150 | JB->setPlatformSetUp(setUpInactivePlatform); |
151 | JB->setNotifyCreatedCallback([&](LLJIT &J) { |
152 | ObjectLayer &ObjLayer = J.getObjLinkingLayer(); |
153 | auto *JITLinkObjLayer = llvm::dyn_cast<ObjectLinkingLayer>(Val: &ObjLayer); |
154 | JITLinkObjLayer->setReturnObjectBuffer( |
155 | [&Objs](std::unique_ptr<llvm::MemoryBuffer> MB) { |
156 | Objs.push_back(x: std::move(MB)); |
157 | }); |
158 | JIT = &J; |
159 | return llvm::Error::success(); |
160 | }); |
161 | |
162 | llvm::Error ErrOut = llvm::Error::success(); |
163 | CustomJBInterpreter Interp(std::move(CI), ErrOut, std::move(JB)); |
164 | cantFail(Err: std::move(ErrOut)); |
165 | |
166 | EXPECT_EQ(0U, Objs.size()); |
167 | cantFail(Err: Interp.ParseAndExecute(Code: "int a = 1;" )); |
168 | ASSERT_NE(JIT, nullptr); // But it is, because JBCreator was never called |
169 | ExecutorAddr Addr = cantFail(ValOrErr: JIT->lookup(UnmangledName: "a" )); |
170 | EXPECT_NE(0U, Addr.getValue()); |
171 | EXPECT_EQ(1U, Objs.size()); |
172 | } |
173 | |
174 | } // end anonymous namespace |
175 | |