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 "llvm/ExecutionEngine/MCJIT.h"
16#include "MCJITTestBase.h"
17#include "gtest/gtest.h"
18
19using namespace llvm;
20
21namespace {
22
23class MCJITMultipleModuleTest : public testing::Test, public MCJITTestBase {};
24
25// FIXME: ExecutionEngine has no support empty modules
26/*
27TEST_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
45void 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
57void 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/*
70TEST_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
90TEST_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
110TEST_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
131TEST_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
152TEST_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
172TEST_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<int32_t(int32_t, int32_t)>(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
200TEST_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  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<int32_t(void)>(A.get(), "FA");
213  endFunctionWithRet(FA, Builder.CreateLoad(GVA));
214  FB = startFunction<int32_t(void)>(B.get(), "FB");
215  endFunctionWithRet(FB, Builder.CreateLoad(GVB));
216
217  GVC = insertGlobalInt32(B.get(), "GVC", initialNum);
218  GVC->setLinkage(GlobalValue::InternalLinkage);
219
220  createJIT(std::move(A));
221  TheJIT->addModule(std::move(B));
222
223  EXPECT_EQ(GVA, TheJIT->FindGlobalVariableNamed("GVA"));
224  EXPECT_EQ(GVB, TheJIT->FindGlobalVariableNamed("GVB"));
225  EXPECT_EQ(GVC, TheJIT->FindGlobalVariableNamed("GVC",true));
226  EXPECT_EQ(nullptr, TheJIT->FindGlobalVariableNamed("GVC"));
227
228  uint64_t FBPtr = TheJIT->getFunctionAddress(FB->getName().str());
229  TheJIT->finalizeObject();
230  EXPECT_TRUE(0 != FBPtr);
231  int32_t(*FuncPtr)() = (int32_t(*)())FBPtr;
232  EXPECT_EQ(initialNum, FuncPtr())
233    << "Invalid value for global returned from JITted function in module B";
234
235  uint64_t FAPtr = TheJIT->getFunctionAddress(FA->getName().str());
236  EXPECT_TRUE(0 != FAPtr);
237  FuncPtr = (int32_t(*)())FAPtr;
238  EXPECT_EQ(initialNum, FuncPtr())
239    << "Invalid value for global returned from JITted function in module A";
240}
241
242// Module A { Function FA },
243// Module B { Extern FA, Function FB which calls FA },
244// Module C { Extern FA, Function FC which calls FA },
245// execute FC, FB, FA
246TEST_F(MCJITMultipleModuleTest, three_module_case) {
247  SKIP_UNSUPPORTED_PLATFORM;
248
249  std::unique_ptr<Module> A, B, C;
250  Function *FA, *FB, *FC;
251  createThreeModuleCase(A, FA, B, FB, C, FC);
252
253  createJIT(std::move(A));
254  TheJIT->addModule(std::move(B));
255  TheJIT->addModule(std::move(C));
256
257  uint64_t ptr = TheJIT->getFunctionAddress(FC->getName().str());
258  checkAdd(ptr);
259
260  ptr = TheJIT->getFunctionAddress(FB->getName().str());
261  checkAdd(ptr);
262
263  ptr = TheJIT->getFunctionAddress(FA->getName().str());
264  checkAdd(ptr);
265}
266
267// Module A { Function FA },
268// Module B { Extern FA, Function FB which calls FA },
269// Module C { Extern FA, Function FC which calls FA },
270// execute FA, FB, FC
271TEST_F(MCJITMultipleModuleTest, three_module_case_reverse_order) {
272  SKIP_UNSUPPORTED_PLATFORM;
273
274  std::unique_ptr<Module> A, B, C;
275  Function *FA, *FB, *FC;
276  createThreeModuleCase(A, FA, B, FB, C, FC);
277
278  createJIT(std::move(A));
279  TheJIT->addModule(std::move(B));
280  TheJIT->addModule(std::move(C));
281
282  uint64_t ptr = TheJIT->getFunctionAddress(FA->getName().str());
283  checkAdd(ptr);
284
285  ptr = TheJIT->getFunctionAddress(FB->getName().str());
286  checkAdd(ptr);
287
288  ptr = TheJIT->getFunctionAddress(FC->getName().str());
289  checkAdd(ptr);
290}
291
292// Module A { Function FA },
293// Module B { Extern FA, Function FB which calls FA },
294// Module C { Extern FB, Function FC which calls FB },
295// execute FC, FB, FA
296TEST_F(MCJITMultipleModuleTest, three_module_chain_case) {
297  SKIP_UNSUPPORTED_PLATFORM;
298
299  std::unique_ptr<Module> A, B, C;
300  Function *FA, *FB, *FC;
301  createThreeModuleChainedCallsCase(A, FA, B, FB, C, FC);
302
303  createJIT(std::move(A));
304  TheJIT->addModule(std::move(B));
305  TheJIT->addModule(std::move(C));
306
307  uint64_t ptr = TheJIT->getFunctionAddress(FC->getName().str());
308  checkAdd(ptr);
309
310  ptr = TheJIT->getFunctionAddress(FB->getName().str());
311  checkAdd(ptr);
312
313  ptr = TheJIT->getFunctionAddress(FA->getName().str());
314  checkAdd(ptr);
315}
316
317// Module A { Function FA },
318// Module B { Extern FA, Function FB which calls FA },
319// Module C { Extern FB, Function FC which calls FB },
320// execute FA, FB, FC
321TEST_F(MCJITMultipleModuleTest, three_modules_chain_case_reverse_order) {
322  SKIP_UNSUPPORTED_PLATFORM;
323
324  std::unique_ptr<Module> A, B, C;
325  Function *FA, *FB, *FC;
326  createThreeModuleChainedCallsCase(A, FA, B, FB, C, FC);
327
328  createJIT(std::move(A));
329  TheJIT->addModule(std::move(B));
330  TheJIT->addModule(std::move(C));
331
332  uint64_t ptr = TheJIT->getFunctionAddress(FA->getName().str());
333  checkAdd(ptr);
334
335  ptr = TheJIT->getFunctionAddress(FB->getName().str());
336  checkAdd(ptr);
337
338  ptr = TheJIT->getFunctionAddress(FC->getName().str());
339  checkAdd(ptr);
340}
341
342// Module A { Extern FB, Function FA which calls FB1 },
343// Module B { Extern FA, Function FB1, Function FB2 which calls FA },
344// execute FA, then FB1
345// FIXME: this test case is not supported by MCJIT
346TEST_F(MCJITMultipleModuleTest, cross_module_dependency_case) {
347  SKIP_UNSUPPORTED_PLATFORM;
348
349  std::unique_ptr<Module> A, B;
350  Function *FA, *FB1, *FB2;
351  createCrossModuleRecursiveCase(A, FA, B, FB1, FB2);
352
353  createJIT(std::move(A));
354  TheJIT->addModule(std::move(B));
355
356  uint64_t ptr = TheJIT->getFunctionAddress(FA->getName().str());
357  checkAccumulate(ptr);
358
359  ptr = TheJIT->getFunctionAddress(FB1->getName().str());
360  checkAccumulate(ptr);
361}
362
363// Module A { Extern FB, Function FA which calls FB1 },
364// Module B { Extern FA, Function FB1, Function FB2 which calls FA },
365// execute FB1 then FA
366// FIXME: this test case is not supported by MCJIT
367TEST_F(MCJITMultipleModuleTest, cross_module_dependency_case_reverse_order) {
368  SKIP_UNSUPPORTED_PLATFORM;
369
370  std::unique_ptr<Module> A, B;
371  Function *FA, *FB1, *FB2;
372  createCrossModuleRecursiveCase(A, FA, B, FB1, FB2);
373
374  createJIT(std::move(A));
375  TheJIT->addModule(std::move(B));
376
377  uint64_t ptr = TheJIT->getFunctionAddress(FB1->getName().str());
378  checkAccumulate(ptr);
379
380  ptr = TheJIT->getFunctionAddress(FA->getName().str());
381  checkAccumulate(ptr);
382}
383
384// Module A { Extern FB1, Function FA which calls FB1 },
385// Module B { Extern FA, Function FB1, Function FB2 which calls FA },
386// execute FB1 then FB2
387// FIXME: this test case is not supported by MCJIT
388TEST_F(MCJITMultipleModuleTest, cross_module_dependency_case3) {
389  SKIP_UNSUPPORTED_PLATFORM;
390
391  std::unique_ptr<Module> A, B;
392  Function *FA, *FB1, *FB2;
393  createCrossModuleRecursiveCase(A, FA, B, FB1, FB2);
394
395  createJIT(std::move(A));
396  TheJIT->addModule(std::move(B));
397
398  uint64_t ptr = TheJIT->getFunctionAddress(FB1->getName().str());
399  checkAccumulate(ptr);
400
401  ptr = TheJIT->getFunctionAddress(FB2->getName().str());
402  checkAccumulate(ptr);
403}
404
405// Test that FindFunctionNamed finds the definition of
406// a function in the correct module. We check two functions
407// in two different modules, to make sure that for at least
408// one of them MCJIT had to ignore the extern declaration.
409TEST_F(MCJITMultipleModuleTest, FindFunctionNamed_test) {
410  SKIP_UNSUPPORTED_PLATFORM;
411
412  std::unique_ptr<Module> A, B;
413  Function *FA, *FB1, *FB2;
414  createCrossModuleRecursiveCase(A, FA, B, FB1, FB2);
415
416  createJIT(std::move(A));
417  TheJIT->addModule(std::move(B));
418
419  EXPECT_EQ(FA, TheJIT->FindFunctionNamed(FA->getName().data()));
420  EXPECT_EQ(FB1, TheJIT->FindFunctionNamed(FB1->getName().data()));
421}
422
423} // end anonymous namespace
424