426 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This test suite verifies MCJIT for handling multiple modules in a single10// ExecutionEngine by building multiple modules, making function calls across11// 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 modules25/*26TEST_F(MCJITMultipleModuleTest, multiple_empty_modules) {27 SKIP_UNSUPPORTED_PLATFORM;28 29 createJIT(M.take());30 // JIT-compile31 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 again38 EXPECT_NE(0, TheJIT->getObjectImage())39 << "Unable to generate executable loaded object image";40}41*/42 43// Helper Function to test add operation44void 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 modules68/*69TEST_F(MCJITMultipleModuleTest, multiple_empty_modules) {70 SKIP_UNSUPPORTED_PLATFORM;71 72 createJIT(M.take());73 // JIT-compile74 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 again81 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 FB89TEST_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 FA109TEST_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 FA130TEST_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 FB151TEST_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 FA2171TEST_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 accesible198// through the ExecutionEngine APIs199TEST_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(Builder.getInt32Ty(), GVA));215 FB = startFunction(B.get(),216 FunctionType::get(Builder.getInt32Ty(), {}, false), "FB");217 endFunctionWithRet(FB, Builder.CreateLoad(Builder.getInt32Ty(), 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, FA248TEST_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, FC273TEST_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, FA298TEST_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, FC323TEST_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 FB1347// FIXME: this test case is not supported by MCJIT348TEST_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 FA368// FIXME: this test case is not supported by MCJIT369TEST_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 FB2389// FIXME: this test case is not supported by MCJIT390TEST_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 of408// a function in the correct module. We check two functions409// in two different modules, to make sure that for at least410// 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(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 namespace426