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