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
18using namespace llvm;
19
20namespace {
21
22class MCJITMultipleModuleTest : public testing::Test, public MCJITTestBase {};
23
24// FIXME: ExecutionEngine has no support empty modules
25/*
26TEST_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
44void 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
56void 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/*
69TEST_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
89TEST_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(M: std::move(A));
97 TheJIT->addModule(M: std::move(B));
98
99 uint64_t ptr = TheJIT->getFunctionAddress(Name: FA->getName().str());
100 checkAdd(ptr);
101
102 ptr = TheJIT->getFunctionAddress(Name: FB->getName().str());
103 checkAdd(ptr);
104}
105
106// Module A { Function FA },
107// Module B { Function FB },
108// execute FB then FA
109TEST_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(M: std::move(A));
117 TheJIT->addModule(M: std::move(B));
118
119 uint64_t ptr = TheJIT->getFunctionAddress(Name: FB->getName().str());
120 TheJIT->finalizeObject();
121 checkAdd(ptr);
122
123 ptr = TheJIT->getFunctionAddress(Name: 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
130TEST_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(M: std::move(A));
138 TheJIT->addModule(M: std::move(B));
139
140 uint64_t ptr = TheJIT->getFunctionAddress(Name: FB->getName().str());
141 TheJIT->finalizeObject();
142 checkAdd(ptr);
143
144 ptr = TheJIT->getFunctionAddress(Name: 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
151TEST_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(M: std::move(A));
159 TheJIT->addModule(M: std::move(B));
160
161 uint64_t ptr = TheJIT->getFunctionAddress(Name: FA->getName().str());
162 checkAdd(ptr);
163
164 ptr = TheJIT->getFunctionAddress(Name: 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
171TEST_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, FA&: FA1, B, FB);
177 FA2 = insertSimpleCallFunction(M: A.get(), Callee: FA1);
178
179 createJIT(M: std::move(A));
180 TheJIT->addModule(M: std::move(B));
181
182 uint64_t ptr = TheJIT->getFunctionAddress(Name: FB->getName().str());
183 TheJIT->finalizeObject();
184 checkAdd(ptr);
185
186 ptr = TheJIT->getFunctionAddress(Name: 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
199TEST_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(p: createEmptyModule(Name: "A"));
207 B.reset(p: createEmptyModule(Name: "B"));
208
209 int32_t initialNum = 7;
210 GVA = insertGlobalInt32(M: A.get(), name: "GVA", InitialValue: initialNum);
211 GVB = insertGlobalInt32(M: B.get(), name: "GVB", InitialValue: initialNum);
212 FA = startFunction(M: A.get(),
213 FT: FunctionType::get(Result: Builder.getInt32Ty(), Params: {}, isVarArg: false), Name: "FA");
214 endFunctionWithRet(Func: FA, RetValue: Builder.CreateLoad(Ty: Builder.getInt32Ty(), Ptr: GVA));
215 FB = startFunction(M: B.get(),
216 FT: FunctionType::get(Result: Builder.getInt32Ty(), Params: {}, isVarArg: false), Name: "FB");
217 endFunctionWithRet(Func: FB, RetValue: Builder.CreateLoad(Ty: Builder.getInt32Ty(), Ptr: GVB));
218
219 GVC = insertGlobalInt32(M: B.get(), name: "GVC", InitialValue: initialNum);
220 GVC->setLinkage(GlobalValue::InternalLinkage);
221
222 createJIT(M: std::move(A));
223 TheJIT->addModule(M: 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(Name: 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(Name: 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
248TEST_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(M: std::move(A));
256 TheJIT->addModule(M: std::move(B));
257 TheJIT->addModule(M: std::move(C));
258
259 uint64_t ptr = TheJIT->getFunctionAddress(Name: FC->getName().str());
260 checkAdd(ptr);
261
262 ptr = TheJIT->getFunctionAddress(Name: FB->getName().str());
263 checkAdd(ptr);
264
265 ptr = TheJIT->getFunctionAddress(Name: 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
273TEST_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(M: std::move(A));
281 TheJIT->addModule(M: std::move(B));
282 TheJIT->addModule(M: std::move(C));
283
284 uint64_t ptr = TheJIT->getFunctionAddress(Name: FA->getName().str());
285 checkAdd(ptr);
286
287 ptr = TheJIT->getFunctionAddress(Name: FB->getName().str());
288 checkAdd(ptr);
289
290 ptr = TheJIT->getFunctionAddress(Name: 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
298TEST_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(M: std::move(A));
306 TheJIT->addModule(M: std::move(B));
307 TheJIT->addModule(M: std::move(C));
308
309 uint64_t ptr = TheJIT->getFunctionAddress(Name: FC->getName().str());
310 checkAdd(ptr);
311
312 ptr = TheJIT->getFunctionAddress(Name: FB->getName().str());
313 checkAdd(ptr);
314
315 ptr = TheJIT->getFunctionAddress(Name: 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
323TEST_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(M: std::move(A));
331 TheJIT->addModule(M: std::move(B));
332 TheJIT->addModule(M: std::move(C));
333
334 uint64_t ptr = TheJIT->getFunctionAddress(Name: FA->getName().str());
335 checkAdd(ptr);
336
337 ptr = TheJIT->getFunctionAddress(Name: FB->getName().str());
338 checkAdd(ptr);
339
340 ptr = TheJIT->getFunctionAddress(Name: 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
348TEST_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(M: std::move(A));
356 TheJIT->addModule(M: std::move(B));
357
358 uint64_t ptr = TheJIT->getFunctionAddress(Name: FA->getName().str());
359 checkAccumulate(ptr);
360
361 ptr = TheJIT->getFunctionAddress(Name: 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
369TEST_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(M: std::move(A));
377 TheJIT->addModule(M: std::move(B));
378
379 uint64_t ptr = TheJIT->getFunctionAddress(Name: FB1->getName().str());
380 checkAccumulate(ptr);
381
382 ptr = TheJIT->getFunctionAddress(Name: 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
390TEST_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(M: std::move(A));
398 TheJIT->addModule(M: std::move(B));
399
400 uint64_t ptr = TheJIT->getFunctionAddress(Name: FB1->getName().str());
401 checkAccumulate(ptr);
402
403 ptr = TheJIT->getFunctionAddress(Name: 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.
411TEST_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(M: std::move(A));
419 TheJIT->addModule(M: 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

source code of llvm/unittests/ExecutionEngine/MCJIT/MCJITMultipleModuleTest.cpp