xref: /llvm-project/llvm/unittests/ExecutionEngine/MCJIT/MCJITMultipleModuleTest.cpp (revision c0044118c8ec4889ff1490179d5d70549cb7621c)
1 //===- MCJITMultipeModuleTest.cpp - Unit tests for the MCJIT ----*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This test suite verifies MCJIT for handling multiple modules in a single
11 // ExecutionEngine by building multiple modules, making function calls across
12 // modules, accessing global variables, etc.
13 //===----------------------------------------------------------------------===//
14 
15 #include "MCJITTestBase.h"
16 #include "llvm/ExecutionEngine/MCJIT.h"
17 #include "gtest/gtest.h"
18 
19 using namespace llvm;
20 
21 namespace {
22 
23 class MCJITMultipleModuleTest : public testing::Test, public MCJITTestBase {};
24 
25 // FIXME: ExecutionEngine has no support empty modules
26 /*
27 TEST_F(MCJITMultipleModuleTest, multiple_empty_modules) {
28   SKIP_UNSUPPORTED_PLATFORM;
29 
30   createJIT(M.take());
31   // JIT-compile
32   EXPECT_NE(0, TheJIT->getObjectImage())
33     << "Unable to generate executable loaded object image";
34 
35   TheJIT->addModule(createEmptyModule("<other module>"));
36   TheJIT->addModule(createEmptyModule("<other other module>"));
37 
38   // JIT again
39   EXPECT_NE(0, TheJIT->getObjectImage())
40     << "Unable to generate executable loaded object image";
41 }
42 */
43 
44 // Helper Function to test add operation
45 void checkAdd(uint64_t ptr) {
46   ASSERT_TRUE(ptr != 0) << "Unable to get pointer to function.";
47   int (*AddPtr)(int, int) = (int (*)(int, int))ptr;
48   EXPECT_EQ(0, AddPtr(0, 0));
49   EXPECT_EQ(1, AddPtr(1, 0));
50   EXPECT_EQ(3, AddPtr(1, 2));
51   EXPECT_EQ(-5, AddPtr(-2, -3));
52   EXPECT_EQ(30, AddPtr(10, 20));
53   EXPECT_EQ(-30, AddPtr(-10, -20));
54   EXPECT_EQ(-40, AddPtr(-10, -30));
55 }
56 
57 void checkAccumulate(uint64_t ptr) {
58   ASSERT_TRUE(ptr != 0) << "Unable to get pointer to function.";
59   int32_t (*FPtr)(int32_t) = (int32_t (*)(int32_t))(intptr_t)ptr;
60   EXPECT_EQ(0, FPtr(0));
61   EXPECT_EQ(1, FPtr(1));
62   EXPECT_EQ(3, FPtr(2));
63   EXPECT_EQ(6, FPtr(3));
64   EXPECT_EQ(10, FPtr(4));
65   EXPECT_EQ(15, FPtr(5));
66 }
67 
68 // FIXME: ExecutionEngine has no support empty modules
69 /*
70 TEST_F(MCJITMultipleModuleTest, multiple_empty_modules) {
71   SKIP_UNSUPPORTED_PLATFORM;
72 
73   createJIT(M.take());
74   // JIT-compile
75   EXPECT_NE(0, TheJIT->getObjectImage())
76     << "Unable to generate executable loaded object image";
77 
78   TheJIT->addModule(createEmptyModule("<other module>"));
79   TheJIT->addModule(createEmptyModule("<other other module>"));
80 
81   // JIT again
82   EXPECT_NE(0, TheJIT->getObjectImage())
83     << "Unable to generate executable loaded object image";
84 }
85 */
86 
87 // Module A { Function FA },
88 // Module B { Function FB },
89 // execute FA then FB
90 TEST_F(MCJITMultipleModuleTest, two_module_case) {
91   SKIP_UNSUPPORTED_PLATFORM;
92 
93   std::unique_ptr<Module> A, B;
94   Function *FA, *FB;
95   createTwoModuleCase(A, FA, B, FB);
96 
97   createJIT(std::move(A));
98   TheJIT->addModule(std::move(B));
99 
100   uint64_t ptr = TheJIT->getFunctionAddress(FA->getName().str());
101   checkAdd(ptr);
102 
103   ptr = TheJIT->getFunctionAddress(FB->getName().str());
104   checkAdd(ptr);
105 }
106 
107 // Module A { Function FA },
108 // Module B { Function FB },
109 // execute FB then FA
110 TEST_F(MCJITMultipleModuleTest, two_module_reverse_case) {
111   SKIP_UNSUPPORTED_PLATFORM;
112 
113   std::unique_ptr<Module> A, B;
114   Function *FA, *FB;
115   createTwoModuleCase(A, FA, B, FB);
116 
117   createJIT(std::move(A));
118   TheJIT->addModule(std::move(B));
119 
120   uint64_t ptr = TheJIT->getFunctionAddress(FB->getName().str());
121   TheJIT->finalizeObject();
122   checkAdd(ptr);
123 
124   ptr = TheJIT->getFunctionAddress(FA->getName().str());
125   checkAdd(ptr);
126 }
127 
128 // Module A { Function FA },
129 // Module B { Extern FA, Function FB which calls FA },
130 // execute FB then FA
131 TEST_F(MCJITMultipleModuleTest, two_module_extern_reverse_case) {
132   SKIP_UNSUPPORTED_PLATFORM;
133 
134   std::unique_ptr<Module> A, B;
135   Function *FA, *FB;
136   createTwoModuleExternCase(A, FA, B, FB);
137 
138   createJIT(std::move(A));
139   TheJIT->addModule(std::move(B));
140 
141   uint64_t ptr = TheJIT->getFunctionAddress(FB->getName().str());
142   TheJIT->finalizeObject();
143   checkAdd(ptr);
144 
145   ptr = TheJIT->getFunctionAddress(FA->getName().str());
146   checkAdd(ptr);
147 }
148 
149 // Module A { Function FA },
150 // Module B { Extern FA, Function FB which calls FA },
151 // execute FA then FB
152 TEST_F(MCJITMultipleModuleTest, two_module_extern_case) {
153   SKIP_UNSUPPORTED_PLATFORM;
154 
155   std::unique_ptr<Module> A, B;
156   Function *FA, *FB;
157   createTwoModuleExternCase(A, FA, B, FB);
158 
159   createJIT(std::move(A));
160   TheJIT->addModule(std::move(B));
161 
162   uint64_t ptr = TheJIT->getFunctionAddress(FA->getName().str());
163   checkAdd(ptr);
164 
165   ptr = TheJIT->getFunctionAddress(FB->getName().str());
166   checkAdd(ptr);
167 }
168 
169 // Module A { Function FA1, Function FA2 which calls FA1 },
170 // Module B { Extern FA1, Function FB which calls FA1 },
171 // execute FB then FA2
172 TEST_F(MCJITMultipleModuleTest, two_module_consecutive_call_case) {
173   SKIP_UNSUPPORTED_PLATFORM;
174 
175   std::unique_ptr<Module> A, B;
176   Function *FA1, *FA2, *FB;
177   createTwoModuleExternCase(A, FA1, B, FB);
178   FA2 = insertSimpleCallFunction(A.get(), FA1);
179 
180   createJIT(std::move(A));
181   TheJIT->addModule(std::move(B));
182 
183   uint64_t ptr = TheJIT->getFunctionAddress(FB->getName().str());
184   TheJIT->finalizeObject();
185   checkAdd(ptr);
186 
187   ptr = TheJIT->getFunctionAddress(FA2->getName().str());
188   checkAdd(ptr);
189 }
190 
191 // TODO:
192 // Module A { Extern Global GVB, Global Variable GVA, Function FA loads GVB },
193 // Module B { Extern Global GVA, Global Variable GVB, Function FB loads GVA },
194 
195 
196 // Module A { Global Variable GVA, Function FA loads GVA },
197 // Module B { Global Variable GVB, Internal Global GVC, Function FB loads GVB },
198 // execute FB then FA, also check that the global variables are properly accesible
199 // through the ExecutionEngine APIs
200 TEST_F(MCJITMultipleModuleTest, two_module_global_variables_case) {
201   SKIP_UNSUPPORTED_PLATFORM;
202 
203   std::unique_ptr<Module> A, B;
204   Function *FA, *FB;
205   GlobalVariable *GVA, *GVB, *GVC;
206 
207   A.reset(createEmptyModule("A"));
208   B.reset(createEmptyModule("B"));
209 
210   int32_t initialNum = 7;
211   GVA = insertGlobalInt32(A.get(), "GVA", initialNum);
212   GVB = insertGlobalInt32(B.get(), "GVB", initialNum);
213   FA = startFunction(A.get(),
214                      FunctionType::get(Builder.getInt32Ty(), {}, false), "FA");
215   endFunctionWithRet(FA, Builder.CreateLoad(GVA));
216   FB = startFunction(B.get(),
217                      FunctionType::get(Builder.getInt32Ty(), {}, false), "FB");
218   endFunctionWithRet(FB, Builder.CreateLoad(GVB));
219 
220   GVC = insertGlobalInt32(B.get(), "GVC", initialNum);
221   GVC->setLinkage(GlobalValue::InternalLinkage);
222 
223   createJIT(std::move(A));
224   TheJIT->addModule(std::move(B));
225 
226   EXPECT_EQ(GVA, TheJIT->FindGlobalVariableNamed("GVA"));
227   EXPECT_EQ(GVB, TheJIT->FindGlobalVariableNamed("GVB"));
228   EXPECT_EQ(GVC, TheJIT->FindGlobalVariableNamed("GVC",true));
229   EXPECT_EQ(nullptr, TheJIT->FindGlobalVariableNamed("GVC"));
230 
231   uint64_t FBPtr = TheJIT->getFunctionAddress(FB->getName().str());
232   TheJIT->finalizeObject();
233   EXPECT_TRUE(0 != FBPtr);
234   int32_t(*FuncPtr)() = (int32_t(*)())FBPtr;
235   EXPECT_EQ(initialNum, FuncPtr())
236     << "Invalid value for global returned from JITted function in module B";
237 
238   uint64_t FAPtr = TheJIT->getFunctionAddress(FA->getName().str());
239   EXPECT_TRUE(0 != FAPtr);
240   FuncPtr = (int32_t(*)())FAPtr;
241   EXPECT_EQ(initialNum, FuncPtr())
242     << "Invalid value for global returned from JITted function in module A";
243 }
244 
245 // Module A { Function FA },
246 // Module B { Extern FA, Function FB which calls FA },
247 // Module C { Extern FA, Function FC which calls FA },
248 // execute FC, FB, FA
249 TEST_F(MCJITMultipleModuleTest, three_module_case) {
250   SKIP_UNSUPPORTED_PLATFORM;
251 
252   std::unique_ptr<Module> A, B, C;
253   Function *FA, *FB, *FC;
254   createThreeModuleCase(A, FA, B, FB, C, FC);
255 
256   createJIT(std::move(A));
257   TheJIT->addModule(std::move(B));
258   TheJIT->addModule(std::move(C));
259 
260   uint64_t ptr = TheJIT->getFunctionAddress(FC->getName().str());
261   checkAdd(ptr);
262 
263   ptr = TheJIT->getFunctionAddress(FB->getName().str());
264   checkAdd(ptr);
265 
266   ptr = TheJIT->getFunctionAddress(FA->getName().str());
267   checkAdd(ptr);
268 }
269 
270 // Module A { Function FA },
271 // Module B { Extern FA, Function FB which calls FA },
272 // Module C { Extern FA, Function FC which calls FA },
273 // execute FA, FB, FC
274 TEST_F(MCJITMultipleModuleTest, three_module_case_reverse_order) {
275   SKIP_UNSUPPORTED_PLATFORM;
276 
277   std::unique_ptr<Module> A, B, C;
278   Function *FA, *FB, *FC;
279   createThreeModuleCase(A, FA, B, FB, C, FC);
280 
281   createJIT(std::move(A));
282   TheJIT->addModule(std::move(B));
283   TheJIT->addModule(std::move(C));
284 
285   uint64_t ptr = TheJIT->getFunctionAddress(FA->getName().str());
286   checkAdd(ptr);
287 
288   ptr = TheJIT->getFunctionAddress(FB->getName().str());
289   checkAdd(ptr);
290 
291   ptr = TheJIT->getFunctionAddress(FC->getName().str());
292   checkAdd(ptr);
293 }
294 
295 // Module A { Function FA },
296 // Module B { Extern FA, Function FB which calls FA },
297 // Module C { Extern FB, Function FC which calls FB },
298 // execute FC, FB, FA
299 TEST_F(MCJITMultipleModuleTest, three_module_chain_case) {
300   SKIP_UNSUPPORTED_PLATFORM;
301 
302   std::unique_ptr<Module> A, B, C;
303   Function *FA, *FB, *FC;
304   createThreeModuleChainedCallsCase(A, FA, B, FB, C, FC);
305 
306   createJIT(std::move(A));
307   TheJIT->addModule(std::move(B));
308   TheJIT->addModule(std::move(C));
309 
310   uint64_t ptr = TheJIT->getFunctionAddress(FC->getName().str());
311   checkAdd(ptr);
312 
313   ptr = TheJIT->getFunctionAddress(FB->getName().str());
314   checkAdd(ptr);
315 
316   ptr = TheJIT->getFunctionAddress(FA->getName().str());
317   checkAdd(ptr);
318 }
319 
320 // Module A { Function FA },
321 // Module B { Extern FA, Function FB which calls FA },
322 // Module C { Extern FB, Function FC which calls FB },
323 // execute FA, FB, FC
324 TEST_F(MCJITMultipleModuleTest, three_modules_chain_case_reverse_order) {
325   SKIP_UNSUPPORTED_PLATFORM;
326 
327   std::unique_ptr<Module> A, B, C;
328   Function *FA, *FB, *FC;
329   createThreeModuleChainedCallsCase(A, FA, B, FB, C, FC);
330 
331   createJIT(std::move(A));
332   TheJIT->addModule(std::move(B));
333   TheJIT->addModule(std::move(C));
334 
335   uint64_t ptr = TheJIT->getFunctionAddress(FA->getName().str());
336   checkAdd(ptr);
337 
338   ptr = TheJIT->getFunctionAddress(FB->getName().str());
339   checkAdd(ptr);
340 
341   ptr = TheJIT->getFunctionAddress(FC->getName().str());
342   checkAdd(ptr);
343 }
344 
345 // Module A { Extern FB, Function FA which calls FB1 },
346 // Module B { Extern FA, Function FB1, Function FB2 which calls FA },
347 // execute FA, then FB1
348 // FIXME: this test case is not supported by MCJIT
349 TEST_F(MCJITMultipleModuleTest, cross_module_dependency_case) {
350   SKIP_UNSUPPORTED_PLATFORM;
351 
352   std::unique_ptr<Module> A, B;
353   Function *FA, *FB1, *FB2;
354   createCrossModuleRecursiveCase(A, FA, B, FB1, FB2);
355 
356   createJIT(std::move(A));
357   TheJIT->addModule(std::move(B));
358 
359   uint64_t ptr = TheJIT->getFunctionAddress(FA->getName().str());
360   checkAccumulate(ptr);
361 
362   ptr = TheJIT->getFunctionAddress(FB1->getName().str());
363   checkAccumulate(ptr);
364 }
365 
366 // Module A { Extern FB, Function FA which calls FB1 },
367 // Module B { Extern FA, Function FB1, Function FB2 which calls FA },
368 // execute FB1 then FA
369 // FIXME: this test case is not supported by MCJIT
370 TEST_F(MCJITMultipleModuleTest, cross_module_dependency_case_reverse_order) {
371   SKIP_UNSUPPORTED_PLATFORM;
372 
373   std::unique_ptr<Module> A, B;
374   Function *FA, *FB1, *FB2;
375   createCrossModuleRecursiveCase(A, FA, B, FB1, FB2);
376 
377   createJIT(std::move(A));
378   TheJIT->addModule(std::move(B));
379 
380   uint64_t ptr = TheJIT->getFunctionAddress(FB1->getName().str());
381   checkAccumulate(ptr);
382 
383   ptr = TheJIT->getFunctionAddress(FA->getName().str());
384   checkAccumulate(ptr);
385 }
386 
387 // Module A { Extern FB1, Function FA which calls FB1 },
388 // Module B { Extern FA, Function FB1, Function FB2 which calls FA },
389 // execute FB1 then FB2
390 // FIXME: this test case is not supported by MCJIT
391 TEST_F(MCJITMultipleModuleTest, cross_module_dependency_case3) {
392   SKIP_UNSUPPORTED_PLATFORM;
393 
394   std::unique_ptr<Module> A, B;
395   Function *FA, *FB1, *FB2;
396   createCrossModuleRecursiveCase(A, FA, B, FB1, FB2);
397 
398   createJIT(std::move(A));
399   TheJIT->addModule(std::move(B));
400 
401   uint64_t ptr = TheJIT->getFunctionAddress(FB1->getName().str());
402   checkAccumulate(ptr);
403 
404   ptr = TheJIT->getFunctionAddress(FB2->getName().str());
405   checkAccumulate(ptr);
406 }
407 
408 // Test that FindFunctionNamed finds the definition of
409 // a function in the correct module. We check two functions
410 // in two different modules, to make sure that for at least
411 // one of them MCJIT had to ignore the extern declaration.
412 TEST_F(MCJITMultipleModuleTest, FindFunctionNamed_test) {
413   SKIP_UNSUPPORTED_PLATFORM;
414 
415   std::unique_ptr<Module> A, B;
416   Function *FA, *FB1, *FB2;
417   createCrossModuleRecursiveCase(A, FA, B, FB1, FB2);
418 
419   createJIT(std::move(A));
420   TheJIT->addModule(std::move(B));
421 
422   EXPECT_EQ(FA, TheJIT->FindFunctionNamed(FA->getName().data()));
423   EXPECT_EQ(FB1, TheJIT->FindFunctionNamed(FB1->getName().data()));
424 }
425 
426 } // end anonymous namespace
427