1 //===- MCJITMultipeModuleTest.cpp - Unit tests for the MCJIT ----*- C++ -*-===//
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 // 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 //===----------------------------------------------------------------------===//
13 
14 #include "MCJITTestBase.h"
15 #include "llvm/ExecutionEngine/MCJIT.h"
16 #include "gtest/gtest.h"
17 
18 using namespace llvm;
19 
20 namespace {
21 
22 class MCJITMultipleModuleTest : public testing::Test, public MCJITTestBase {};
23 
24 // FIXME: ExecutionEngine has no support empty modules
25 /*
26 TEST_F(MCJITMultipleModuleTest, multiple_empty_modules) {
27   SKIP_UNSUPPORTED_PLATFORM;
28 
29   createJIT(M.take());
30   // JIT-compile
31   EXPECT_NE(0, TheJIT->getObjectImage())
32     << "Unable to generate executable loaded object image";
33 
34   TheJIT->addModule(createEmptyModule("<other module>"));
35   TheJIT->addModule(createEmptyModule("<other other module>"));
36 
37   // JIT again
38   EXPECT_NE(0, TheJIT->getObjectImage())
39     << "Unable to generate executable loaded object image";
40 }
41 */
42 
43 // Helper Function to test add operation
checkAdd(uint64_t ptr)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));
54 }
55 
checkAccumulate(uint64_t ptr)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));
65 }
66 
67 // FIXME: ExecutionEngine has no support empty modules
68 /*
69 TEST_F(MCJITMultipleModuleTest, multiple_empty_modules) {
70   SKIP_UNSUPPORTED_PLATFORM;
71 
72   createJIT(M.take());
73   // JIT-compile
74   EXPECT_NE(0, TheJIT->getObjectImage())
75     << "Unable to generate executable loaded object image";
76 
77   TheJIT->addModule(createEmptyModule("<other module>"));
78   TheJIT->addModule(createEmptyModule("<other other module>"));
79 
80   // JIT again
81   EXPECT_NE(0, TheJIT->getObjectImage())
82     << "Unable to generate executable loaded object image";
83 }
84 */
85 
86 // Module A { Function FA },
87 // Module B { Function FB },
88 // execute FA then FB
TEST_F(MCJITMultipleModuleTest,two_module_case)89 TEST_F(MCJITMultipleModuleTest, two_module_case) {
90   SKIP_UNSUPPORTED_PLATFORM;
91 
92   std::unique_ptr<Module> A, B;
93   Function *FA, *FB;
94   createTwoModuleCase(A, FA, B, FB);
95 
96   createJIT(std::move(A));
97   TheJIT->addModule(std::move(B));
98 
99   uint64_t ptr = TheJIT->getFunctionAddress(FA->getName().str());
100   checkAdd(ptr);
101 
102   ptr = TheJIT->getFunctionAddress(FB->getName().str());
103   checkAdd(ptr);
104 }
105 
106 // Module A { Function FA },
107 // Module B { Function FB },
108 // execute FB then FA
TEST_F(MCJITMultipleModuleTest,two_module_reverse_case)109 TEST_F(MCJITMultipleModuleTest, two_module_reverse_case) {
110   SKIP_UNSUPPORTED_PLATFORM;
111 
112   std::unique_ptr<Module> A, B;
113   Function *FA, *FB;
114   createTwoModuleCase(A, FA, B, FB);
115 
116   createJIT(std::move(A));
117   TheJIT->addModule(std::move(B));
118 
119   uint64_t ptr = TheJIT->getFunctionAddress(FB->getName().str());
120   TheJIT->finalizeObject();
121   checkAdd(ptr);
122 
123   ptr = TheJIT->getFunctionAddress(FA->getName().str());
124   checkAdd(ptr);
125 }
126 
127 // Module A { Function FA },
128 // Module B { Extern FA, Function FB which calls FA },
129 // execute FB then FA
TEST_F(MCJITMultipleModuleTest,two_module_extern_reverse_case)130 TEST_F(MCJITMultipleModuleTest, two_module_extern_reverse_case) {
131   SKIP_UNSUPPORTED_PLATFORM;
132 
133   std::unique_ptr<Module> A, B;
134   Function *FA, *FB;
135   createTwoModuleExternCase(A, FA, B, FB);
136 
137   createJIT(std::move(A));
138   TheJIT->addModule(std::move(B));
139 
140   uint64_t ptr = TheJIT->getFunctionAddress(FB->getName().str());
141   TheJIT->finalizeObject();
142   checkAdd(ptr);
143 
144   ptr = TheJIT->getFunctionAddress(FA->getName().str());
145   checkAdd(ptr);
146 }
147 
148 // Module A { Function FA },
149 // Module B { Extern FA, Function FB which calls FA },
150 // execute FA then FB
TEST_F(MCJITMultipleModuleTest,two_module_extern_case)151 TEST_F(MCJITMultipleModuleTest, two_module_extern_case) {
152   SKIP_UNSUPPORTED_PLATFORM;
153 
154   std::unique_ptr<Module> A, B;
155   Function *FA, *FB;
156   createTwoModuleExternCase(A, FA, B, FB);
157 
158   createJIT(std::move(A));
159   TheJIT->addModule(std::move(B));
160 
161   uint64_t ptr = TheJIT->getFunctionAddress(FA->getName().str());
162   checkAdd(ptr);
163 
164   ptr = TheJIT->getFunctionAddress(FB->getName().str());
165   checkAdd(ptr);
166 }
167 
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
TEST_F(MCJITMultipleModuleTest,two_module_consecutive_call_case)171 TEST_F(MCJITMultipleModuleTest, two_module_consecutive_call_case) {
172   SKIP_UNSUPPORTED_PLATFORM;
173 
174   std::unique_ptr<Module> A, B;
175   Function *FA1, *FA2, *FB;
176   createTwoModuleExternCase(A, FA1, B, FB);
177   FA2 = insertSimpleCallFunction(A.get(), FA1);
178 
179   createJIT(std::move(A));
180   TheJIT->addModule(std::move(B));
181 
182   uint64_t ptr = TheJIT->getFunctionAddress(FB->getName().str());
183   TheJIT->finalizeObject();
184   checkAdd(ptr);
185 
186   ptr = TheJIT->getFunctionAddress(FA2->getName().str());
187   checkAdd(ptr);
188 }
189 
190 // TODO:
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 },
193 
194 
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
TEST_F(MCJITMultipleModuleTest,two_module_global_variables_case)199 TEST_F(MCJITMultipleModuleTest, two_module_global_variables_case) {
200   SKIP_UNSUPPORTED_PLATFORM;
201 
202   std::unique_ptr<Module> A, B;
203   Function *FA, *FB;
204   GlobalVariable *GVA, *GVB, *GVC;
205 
206   A.reset(createEmptyModule("A"));
207   B.reset(createEmptyModule("B"));
208 
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));
218 
219   GVC = insertGlobalInt32(B.get(), "GVC", initialNum);
220   GVC->setLinkage(GlobalValue::InternalLinkage);
221 
222   createJIT(std::move(A));
223   TheJIT->addModule(std::move(B));
224 
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"));
229 
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";
236 
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";
242 }
243 
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
TEST_F(MCJITMultipleModuleTest,three_module_case)248 TEST_F(MCJITMultipleModuleTest, three_module_case) {
249   SKIP_UNSUPPORTED_PLATFORM;
250 
251   std::unique_ptr<Module> A, B, C;
252   Function *FA, *FB, *FC;
253   createThreeModuleCase(A, FA, B, FB, C, FC);
254 
255   createJIT(std::move(A));
256   TheJIT->addModule(std::move(B));
257   TheJIT->addModule(std::move(C));
258 
259   uint64_t ptr = TheJIT->getFunctionAddress(FC->getName().str());
260   checkAdd(ptr);
261 
262   ptr = TheJIT->getFunctionAddress(FB->getName().str());
263   checkAdd(ptr);
264 
265   ptr = TheJIT->getFunctionAddress(FA->getName().str());
266   checkAdd(ptr);
267 }
268 
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
TEST_F(MCJITMultipleModuleTest,three_module_case_reverse_order)273 TEST_F(MCJITMultipleModuleTest, three_module_case_reverse_order) {
274   SKIP_UNSUPPORTED_PLATFORM;
275 
276   std::unique_ptr<Module> A, B, C;
277   Function *FA, *FB, *FC;
278   createThreeModuleCase(A, FA, B, FB, C, FC);
279 
280   createJIT(std::move(A));
281   TheJIT->addModule(std::move(B));
282   TheJIT->addModule(std::move(C));
283 
284   uint64_t ptr = TheJIT->getFunctionAddress(FA->getName().str());
285   checkAdd(ptr);
286 
287   ptr = TheJIT->getFunctionAddress(FB->getName().str());
288   checkAdd(ptr);
289 
290   ptr = TheJIT->getFunctionAddress(FC->getName().str());
291   checkAdd(ptr);
292 }
293 
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
TEST_F(MCJITMultipleModuleTest,three_module_chain_case)298 TEST_F(MCJITMultipleModuleTest, three_module_chain_case) {
299   SKIP_UNSUPPORTED_PLATFORM;
300 
301   std::unique_ptr<Module> A, B, C;
302   Function *FA, *FB, *FC;
303   createThreeModuleChainedCallsCase(A, FA, B, FB, C, FC);
304 
305   createJIT(std::move(A));
306   TheJIT->addModule(std::move(B));
307   TheJIT->addModule(std::move(C));
308 
309   uint64_t ptr = TheJIT->getFunctionAddress(FC->getName().str());
310   checkAdd(ptr);
311 
312   ptr = TheJIT->getFunctionAddress(FB->getName().str());
313   checkAdd(ptr);
314 
315   ptr = TheJIT->getFunctionAddress(FA->getName().str());
316   checkAdd(ptr);
317 }
318 
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
TEST_F(MCJITMultipleModuleTest,three_modules_chain_case_reverse_order)323 TEST_F(MCJITMultipleModuleTest, three_modules_chain_case_reverse_order) {
324   SKIP_UNSUPPORTED_PLATFORM;
325 
326   std::unique_ptr<Module> A, B, C;
327   Function *FA, *FB, *FC;
328   createThreeModuleChainedCallsCase(A, FA, B, FB, C, FC);
329 
330   createJIT(std::move(A));
331   TheJIT->addModule(std::move(B));
332   TheJIT->addModule(std::move(C));
333 
334   uint64_t ptr = TheJIT->getFunctionAddress(FA->getName().str());
335   checkAdd(ptr);
336 
337   ptr = TheJIT->getFunctionAddress(FB->getName().str());
338   checkAdd(ptr);
339 
340   ptr = TheJIT->getFunctionAddress(FC->getName().str());
341   checkAdd(ptr);
342 }
343 
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
TEST_F(MCJITMultipleModuleTest,cross_module_dependency_case)348 TEST_F(MCJITMultipleModuleTest, cross_module_dependency_case) {
349   SKIP_UNSUPPORTED_PLATFORM;
350 
351   std::unique_ptr<Module> A, B;
352   Function *FA, *FB1, *FB2;
353   createCrossModuleRecursiveCase(A, FA, B, FB1, FB2);
354 
355   createJIT(std::move(A));
356   TheJIT->addModule(std::move(B));
357 
358   uint64_t ptr = TheJIT->getFunctionAddress(FA->getName().str());
359   checkAccumulate(ptr);
360 
361   ptr = TheJIT->getFunctionAddress(FB1->getName().str());
362   checkAccumulate(ptr);
363 }
364 
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
TEST_F(MCJITMultipleModuleTest,cross_module_dependency_case_reverse_order)369 TEST_F(MCJITMultipleModuleTest, cross_module_dependency_case_reverse_order) {
370   SKIP_UNSUPPORTED_PLATFORM;
371 
372   std::unique_ptr<Module> A, B;
373   Function *FA, *FB1, *FB2;
374   createCrossModuleRecursiveCase(A, FA, B, FB1, FB2);
375 
376   createJIT(std::move(A));
377   TheJIT->addModule(std::move(B));
378 
379   uint64_t ptr = TheJIT->getFunctionAddress(FB1->getName().str());
380   checkAccumulate(ptr);
381 
382   ptr = TheJIT->getFunctionAddress(FA->getName().str());
383   checkAccumulate(ptr);
384 }
385 
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
TEST_F(MCJITMultipleModuleTest,cross_module_dependency_case3)390 TEST_F(MCJITMultipleModuleTest, cross_module_dependency_case3) {
391   SKIP_UNSUPPORTED_PLATFORM;
392 
393   std::unique_ptr<Module> A, B;
394   Function *FA, *FB1, *FB2;
395   createCrossModuleRecursiveCase(A, FA, B, FB1, FB2);
396 
397   createJIT(std::move(A));
398   TheJIT->addModule(std::move(B));
399 
400   uint64_t ptr = TheJIT->getFunctionAddress(FB1->getName().str());
401   checkAccumulate(ptr);
402 
403   ptr = TheJIT->getFunctionAddress(FB2->getName().str());
404   checkAccumulate(ptr);
405 }
406 
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.
TEST_F(MCJITMultipleModuleTest,FindFunctionNamed_test)411 TEST_F(MCJITMultipleModuleTest, FindFunctionNamed_test) {
412   SKIP_UNSUPPORTED_PLATFORM;
413 
414   std::unique_ptr<Module> A, B;
415   Function *FA, *FB1, *FB2;
416   createCrossModuleRecursiveCase(A, FA, B, FB1, FB2);
417 
418   createJIT(std::move(A));
419   TheJIT->addModule(std::move(B));
420 
421   EXPECT_EQ(FA, TheJIT->FindFunctionNamed(FA->getName().data()));
422   EXPECT_EQ(FB1, TheJIT->FindFunctionNamed(FB1->getName().data()));
423 }
424 
425 } // end anonymous namespace
426