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 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 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 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 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 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 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 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 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(GVA)); 215 FB = startFunction(B.get(), 216 FunctionType::get(Builder.getInt32Ty(), {}, false), "FB"); 217 endFunctionWithRet(FB, Builder.CreateLoad(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 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 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 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 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 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 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 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. 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