1 //===- MCJITMultipeModuleTest.cpp - Unit tests for the MCJIT ----*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // This test suite verifies MCJIT for handling multiple modules in a single
10 // ExecutionEngine by building multiple modules, making function calls across
11 // modules, accessing global variables, etc.
12 //===----------------------------------------------------------------------===//
14 #include "MCJITTestBase.h"
15 #include "llvm/ExecutionEngine/MCJIT.h"
16 #include "gtest/gtest.h"
22 class MCJITMultipleModuleTest
: public testing::Test
, public MCJITTestBase
{};
24 // FIXME: ExecutionEngine has no support empty modules
26 TEST_F(MCJITMultipleModuleTest, multiple_empty_modules) {
27 SKIP_UNSUPPORTED_PLATFORM;
31 EXPECT_NE(0, TheJIT->getObjectImage())
32 << "Unable to generate executable loaded object image";
34 TheJIT->addModule(createEmptyModule("<other module>"));
35 TheJIT->addModule(createEmptyModule("<other other module>"));
38 EXPECT_NE(0, TheJIT->getObjectImage())
39 << "Unable to generate executable loaded object image";
43 // Helper Function to test add operation
44 void checkAdd(uint64_t ptr
) {
45 ASSERT_TRUE(ptr
!= 0) << "Unable to get pointer to function.";
46 int (*AddPtr
)(int, int) = (int (*)(int, int))ptr
;
47 EXPECT_EQ(0, AddPtr(0, 0));
48 EXPECT_EQ(1, AddPtr(1, 0));
49 EXPECT_EQ(3, AddPtr(1, 2));
50 EXPECT_EQ(-5, AddPtr(-2, -3));
51 EXPECT_EQ(30, AddPtr(10, 20));
52 EXPECT_EQ(-30, AddPtr(-10, -20));
53 EXPECT_EQ(-40, AddPtr(-10, -30));
56 void checkAccumulate(uint64_t ptr
) {
57 ASSERT_TRUE(ptr
!= 0) << "Unable to get pointer to function.";
58 int32_t (*FPtr
)(int32_t) = (int32_t (*)(int32_t))(intptr_t)ptr
;
59 EXPECT_EQ(0, FPtr(0));
60 EXPECT_EQ(1, FPtr(1));
61 EXPECT_EQ(3, FPtr(2));
62 EXPECT_EQ(6, FPtr(3));
63 EXPECT_EQ(10, FPtr(4));
64 EXPECT_EQ(15, FPtr(5));
67 // FIXME: ExecutionEngine has no support empty modules
69 TEST_F(MCJITMultipleModuleTest, multiple_empty_modules) {
70 SKIP_UNSUPPORTED_PLATFORM;
74 EXPECT_NE(0, TheJIT->getObjectImage())
75 << "Unable to generate executable loaded object image";
77 TheJIT->addModule(createEmptyModule("<other module>"));
78 TheJIT->addModule(createEmptyModule("<other other module>"));
81 EXPECT_NE(0, TheJIT->getObjectImage())
82 << "Unable to generate executable loaded object image";
86 // Module A { Function FA },
87 // Module B { Function FB },
89 TEST_F(MCJITMultipleModuleTest
, two_module_case
) {
90 SKIP_UNSUPPORTED_PLATFORM
;
92 std::unique_ptr
<Module
> A
, B
;
94 createTwoModuleCase(A
, FA
, B
, FB
);
96 createJIT(std::move(A
));
97 TheJIT
->addModule(std::move(B
));
99 uint64_t ptr
= TheJIT
->getFunctionAddress(FA
->getName().str());
102 ptr
= TheJIT
->getFunctionAddress(FB
->getName().str());
106 // Module A { Function FA },
107 // Module B { Function FB },
108 // execute FB then FA
109 TEST_F(MCJITMultipleModuleTest
, two_module_reverse_case
) {
110 SKIP_UNSUPPORTED_PLATFORM
;
112 std::unique_ptr
<Module
> A
, B
;
114 createTwoModuleCase(A
, FA
, B
, FB
);
116 createJIT(std::move(A
));
117 TheJIT
->addModule(std::move(B
));
119 uint64_t ptr
= TheJIT
->getFunctionAddress(FB
->getName().str());
120 TheJIT
->finalizeObject();
123 ptr
= TheJIT
->getFunctionAddress(FA
->getName().str());
127 // Module A { Function FA },
128 // Module B { Extern FA, Function FB which calls FA },
129 // execute FB then FA
130 TEST_F(MCJITMultipleModuleTest
, two_module_extern_reverse_case
) {
131 SKIP_UNSUPPORTED_PLATFORM
;
133 std::unique_ptr
<Module
> A
, B
;
135 createTwoModuleExternCase(A
, FA
, B
, FB
);
137 createJIT(std::move(A
));
138 TheJIT
->addModule(std::move(B
));
140 uint64_t ptr
= TheJIT
->getFunctionAddress(FB
->getName().str());
141 TheJIT
->finalizeObject();
144 ptr
= TheJIT
->getFunctionAddress(FA
->getName().str());
148 // Module A { Function FA },
149 // Module B { Extern FA, Function FB which calls FA },
150 // execute FA then FB
151 TEST_F(MCJITMultipleModuleTest
, two_module_extern_case
) {
152 SKIP_UNSUPPORTED_PLATFORM
;
154 std::unique_ptr
<Module
> A
, B
;
156 createTwoModuleExternCase(A
, FA
, B
, FB
);
158 createJIT(std::move(A
));
159 TheJIT
->addModule(std::move(B
));
161 uint64_t ptr
= TheJIT
->getFunctionAddress(FA
->getName().str());
164 ptr
= TheJIT
->getFunctionAddress(FB
->getName().str());
168 // Module A { Function FA1, Function FA2 which calls FA1 },
169 // Module B { Extern FA1, Function FB which calls FA1 },
170 // execute FB then FA2
171 TEST_F(MCJITMultipleModuleTest
, two_module_consecutive_call_case
) {
172 SKIP_UNSUPPORTED_PLATFORM
;
174 std::unique_ptr
<Module
> A
, B
;
175 Function
*FA1
, *FA2
, *FB
;
176 createTwoModuleExternCase(A
, FA1
, B
, FB
);
177 FA2
= insertSimpleCallFunction(A
.get(), FA1
);
179 createJIT(std::move(A
));
180 TheJIT
->addModule(std::move(B
));
182 uint64_t ptr
= TheJIT
->getFunctionAddress(FB
->getName().str());
183 TheJIT
->finalizeObject();
186 ptr
= TheJIT
->getFunctionAddress(FA2
->getName().str());
191 // Module A { Extern Global GVB, Global Variable GVA, Function FA loads GVB },
192 // Module B { Extern Global GVA, Global Variable GVB, Function FB loads GVA },
195 // Module A { Global Variable GVA, Function FA loads GVA },
196 // Module B { Global Variable GVB, Internal Global GVC, Function FB loads GVB },
197 // execute FB then FA, also check that the global variables are properly accesible
198 // through the ExecutionEngine APIs
199 TEST_F(MCJITMultipleModuleTest
, two_module_global_variables_case
) {
200 SKIP_UNSUPPORTED_PLATFORM
;
202 std::unique_ptr
<Module
> A
, B
;
204 GlobalVariable
*GVA
, *GVB
, *GVC
;
206 A
.reset(createEmptyModule("A"));
207 B
.reset(createEmptyModule("B"));
209 int32_t initialNum
= 7;
210 GVA
= insertGlobalInt32(A
.get(), "GVA", initialNum
);
211 GVB
= insertGlobalInt32(B
.get(), "GVB", initialNum
);
212 FA
= startFunction(A
.get(),
213 FunctionType::get(Builder
.getInt32Ty(), {}, false), "FA");
214 endFunctionWithRet(FA
, Builder
.CreateLoad(Builder
.getInt32Ty(), GVA
));
215 FB
= startFunction(B
.get(),
216 FunctionType::get(Builder
.getInt32Ty(), {}, false), "FB");
217 endFunctionWithRet(FB
, Builder
.CreateLoad(Builder
.getInt32Ty(), GVB
));
219 GVC
= insertGlobalInt32(B
.get(), "GVC", initialNum
);
220 GVC
->setLinkage(GlobalValue::InternalLinkage
);
222 createJIT(std::move(A
));
223 TheJIT
->addModule(std::move(B
));
225 EXPECT_EQ(GVA
, TheJIT
->FindGlobalVariableNamed("GVA"));
226 EXPECT_EQ(GVB
, TheJIT
->FindGlobalVariableNamed("GVB"));
227 EXPECT_EQ(GVC
, TheJIT
->FindGlobalVariableNamed("GVC",true));
228 EXPECT_EQ(nullptr, TheJIT
->FindGlobalVariableNamed("GVC"));
230 uint64_t FBPtr
= TheJIT
->getFunctionAddress(FB
->getName().str());
231 TheJIT
->finalizeObject();
232 EXPECT_TRUE(0 != FBPtr
);
233 int32_t(*FuncPtr
)() = (int32_t(*)())FBPtr
;
234 EXPECT_EQ(initialNum
, FuncPtr())
235 << "Invalid value for global returned from JITted function in module B";
237 uint64_t FAPtr
= TheJIT
->getFunctionAddress(FA
->getName().str());
238 EXPECT_TRUE(0 != FAPtr
);
239 FuncPtr
= (int32_t(*)())FAPtr
;
240 EXPECT_EQ(initialNum
, FuncPtr())
241 << "Invalid value for global returned from JITted function in module A";
244 // Module A { Function FA },
245 // Module B { Extern FA, Function FB which calls FA },
246 // Module C { Extern FA, Function FC which calls FA },
247 // execute FC, FB, FA
248 TEST_F(MCJITMultipleModuleTest
, three_module_case
) {
249 SKIP_UNSUPPORTED_PLATFORM
;
251 std::unique_ptr
<Module
> A
, B
, C
;
252 Function
*FA
, *FB
, *FC
;
253 createThreeModuleCase(A
, FA
, B
, FB
, C
, FC
);
255 createJIT(std::move(A
));
256 TheJIT
->addModule(std::move(B
));
257 TheJIT
->addModule(std::move(C
));
259 uint64_t ptr
= TheJIT
->getFunctionAddress(FC
->getName().str());
262 ptr
= TheJIT
->getFunctionAddress(FB
->getName().str());
265 ptr
= TheJIT
->getFunctionAddress(FA
->getName().str());
269 // Module A { Function FA },
270 // Module B { Extern FA, Function FB which calls FA },
271 // Module C { Extern FA, Function FC which calls FA },
272 // execute FA, FB, FC
273 TEST_F(MCJITMultipleModuleTest
, three_module_case_reverse_order
) {
274 SKIP_UNSUPPORTED_PLATFORM
;
276 std::unique_ptr
<Module
> A
, B
, C
;
277 Function
*FA
, *FB
, *FC
;
278 createThreeModuleCase(A
, FA
, B
, FB
, C
, FC
);
280 createJIT(std::move(A
));
281 TheJIT
->addModule(std::move(B
));
282 TheJIT
->addModule(std::move(C
));
284 uint64_t ptr
= TheJIT
->getFunctionAddress(FA
->getName().str());
287 ptr
= TheJIT
->getFunctionAddress(FB
->getName().str());
290 ptr
= TheJIT
->getFunctionAddress(FC
->getName().str());
294 // Module A { Function FA },
295 // Module B { Extern FA, Function FB which calls FA },
296 // Module C { Extern FB, Function FC which calls FB },
297 // execute FC, FB, FA
298 TEST_F(MCJITMultipleModuleTest
, three_module_chain_case
) {
299 SKIP_UNSUPPORTED_PLATFORM
;
301 std::unique_ptr
<Module
> A
, B
, C
;
302 Function
*FA
, *FB
, *FC
;
303 createThreeModuleChainedCallsCase(A
, FA
, B
, FB
, C
, FC
);
305 createJIT(std::move(A
));
306 TheJIT
->addModule(std::move(B
));
307 TheJIT
->addModule(std::move(C
));
309 uint64_t ptr
= TheJIT
->getFunctionAddress(FC
->getName().str());
312 ptr
= TheJIT
->getFunctionAddress(FB
->getName().str());
315 ptr
= TheJIT
->getFunctionAddress(FA
->getName().str());
319 // Module A { Function FA },
320 // Module B { Extern FA, Function FB which calls FA },
321 // Module C { Extern FB, Function FC which calls FB },
322 // execute FA, FB, FC
323 TEST_F(MCJITMultipleModuleTest
, three_modules_chain_case_reverse_order
) {
324 SKIP_UNSUPPORTED_PLATFORM
;
326 std::unique_ptr
<Module
> A
, B
, C
;
327 Function
*FA
, *FB
, *FC
;
328 createThreeModuleChainedCallsCase(A
, FA
, B
, FB
, C
, FC
);
330 createJIT(std::move(A
));
331 TheJIT
->addModule(std::move(B
));
332 TheJIT
->addModule(std::move(C
));
334 uint64_t ptr
= TheJIT
->getFunctionAddress(FA
->getName().str());
337 ptr
= TheJIT
->getFunctionAddress(FB
->getName().str());
340 ptr
= TheJIT
->getFunctionAddress(FC
->getName().str());
344 // Module A { Extern FB, Function FA which calls FB1 },
345 // Module B { Extern FA, Function FB1, Function FB2 which calls FA },
346 // execute FA, then FB1
347 // FIXME: this test case is not supported by MCJIT
348 TEST_F(MCJITMultipleModuleTest
, cross_module_dependency_case
) {
349 SKIP_UNSUPPORTED_PLATFORM
;
351 std::unique_ptr
<Module
> A
, B
;
352 Function
*FA
, *FB1
, *FB2
;
353 createCrossModuleRecursiveCase(A
, FA
, B
, FB1
, FB2
);
355 createJIT(std::move(A
));
356 TheJIT
->addModule(std::move(B
));
358 uint64_t ptr
= TheJIT
->getFunctionAddress(FA
->getName().str());
359 checkAccumulate(ptr
);
361 ptr
= TheJIT
->getFunctionAddress(FB1
->getName().str());
362 checkAccumulate(ptr
);
365 // Module A { Extern FB, Function FA which calls FB1 },
366 // Module B { Extern FA, Function FB1, Function FB2 which calls FA },
367 // execute FB1 then FA
368 // FIXME: this test case is not supported by MCJIT
369 TEST_F(MCJITMultipleModuleTest
, cross_module_dependency_case_reverse_order
) {
370 SKIP_UNSUPPORTED_PLATFORM
;
372 std::unique_ptr
<Module
> A
, B
;
373 Function
*FA
, *FB1
, *FB2
;
374 createCrossModuleRecursiveCase(A
, FA
, B
, FB1
, FB2
);
376 createJIT(std::move(A
));
377 TheJIT
->addModule(std::move(B
));
379 uint64_t ptr
= TheJIT
->getFunctionAddress(FB1
->getName().str());
380 checkAccumulate(ptr
);
382 ptr
= TheJIT
->getFunctionAddress(FA
->getName().str());
383 checkAccumulate(ptr
);
386 // Module A { Extern FB1, Function FA which calls FB1 },
387 // Module B { Extern FA, Function FB1, Function FB2 which calls FA },
388 // execute FB1 then FB2
389 // FIXME: this test case is not supported by MCJIT
390 TEST_F(MCJITMultipleModuleTest
, cross_module_dependency_case3
) {
391 SKIP_UNSUPPORTED_PLATFORM
;
393 std::unique_ptr
<Module
> A
, B
;
394 Function
*FA
, *FB1
, *FB2
;
395 createCrossModuleRecursiveCase(A
, FA
, B
, FB1
, FB2
);
397 createJIT(std::move(A
));
398 TheJIT
->addModule(std::move(B
));
400 uint64_t ptr
= TheJIT
->getFunctionAddress(FB1
->getName().str());
401 checkAccumulate(ptr
);
403 ptr
= TheJIT
->getFunctionAddress(FB2
->getName().str());
404 checkAccumulate(ptr
);
407 // Test that FindFunctionNamed finds the definition of
408 // a function in the correct module. We check two functions
409 // in two different modules, to make sure that for at least
410 // one of them MCJIT had to ignore the extern declaration.
411 TEST_F(MCJITMultipleModuleTest
, FindFunctionNamed_test
) {
412 SKIP_UNSUPPORTED_PLATFORM
;
414 std::unique_ptr
<Module
> A
, B
;
415 Function
*FA
, *FB1
, *FB2
;
416 createCrossModuleRecursiveCase(A
, FA
, B
, FB1
, FB2
);
418 createJIT(std::move(A
));
419 TheJIT
->addModule(std::move(B
));
421 EXPECT_EQ(FA
, TheJIT
->FindFunctionNamed(FA
->getName().data()));
422 EXPECT_EQ(FB1
, TheJIT
->FindFunctionNamed(FB1
->getName().data()));
425 } // end anonymous namespace