1083ca9bbSHans Wennborg //===- MCJITTest.cpp - Unit tests for the MCJIT -----------------*- C++ -*-===//
25e7d7926SAndrew Kaylor //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65e7d7926SAndrew Kaylor //
75e7d7926SAndrew Kaylor //===----------------------------------------------------------------------===//
85e7d7926SAndrew Kaylor //
95e7d7926SAndrew Kaylor // This test suite verifies basic MCJIT functionality such as making function
105e7d7926SAndrew Kaylor // calls, using global variables, and compiling multpile modules.
115e7d7926SAndrew Kaylor //
125e7d7926SAndrew Kaylor //===----------------------------------------------------------------------===//
135e7d7926SAndrew Kaylor
145e7d7926SAndrew Kaylor #include "MCJITTestBase.h"
159a67b073SChandler Carruth #include "llvm/Support/DynamicLibrary.h"
16130cec21SChandler Carruth #include "gtest/gtest.h"
175e7d7926SAndrew Kaylor
185e7d7926SAndrew Kaylor using namespace llvm;
195e7d7926SAndrew Kaylor
2005c5a932SJuergen Ributzka namespace {
2105c5a932SJuergen Ributzka
225e7d7926SAndrew Kaylor class MCJITTest : public testing::Test, public MCJITTestBase {
235e7d7926SAndrew Kaylor protected:
SetUp()24f817c1cbSAlexander Kornienko void SetUp() override { M.reset(createEmptyModule("<main>")); }
25d12ccbd3SJuergen Ributzka };
26d12ccbd3SJuergen Ributzka
276bbb2c9fSAndrew Kaylor // FIXME: Ensure creating an execution engine does not crash when constructed
286bbb2c9fSAndrew Kaylor // with a null module.
296bbb2c9fSAndrew Kaylor /*
306bbb2c9fSAndrew Kaylor TEST_F(MCJITTest, null_module) {
316bbb2c9fSAndrew Kaylor createJIT(0);
326bbb2c9fSAndrew Kaylor }
336bbb2c9fSAndrew Kaylor */
346bbb2c9fSAndrew Kaylor
355e7d7926SAndrew Kaylor // FIXME: In order to JIT an empty module, there needs to be
365e7d7926SAndrew Kaylor // an interface to ExecutionEngine that forces compilation but
376bbb2c9fSAndrew Kaylor // does not require retrieval of a pointer to a function/global.
385e7d7926SAndrew Kaylor /*
395e7d7926SAndrew Kaylor TEST_F(MCJITTest, empty_module) {
405e7d7926SAndrew Kaylor createJIT(M.take());
415e7d7926SAndrew Kaylor //EXPECT_NE(0, TheJIT->getObjectImage())
425e7d7926SAndrew Kaylor // << "Unable to generate executable loaded object image";
435e7d7926SAndrew Kaylor }
445e7d7926SAndrew Kaylor */
455e7d7926SAndrew Kaylor
TEST_F(MCJITTest,global_variable)465e7d7926SAndrew Kaylor TEST_F(MCJITTest, global_variable) {
475e7d7926SAndrew Kaylor SKIP_UNSUPPORTED_PLATFORM;
485e7d7926SAndrew Kaylor
495e7d7926SAndrew Kaylor int initialValue = 5;
505e7d7926SAndrew Kaylor GlobalValue *Global = insertGlobalInt32(M.get(), "test_global", initialValue);
512a8a2795SRafael Espindola createJIT(std::move(M));
525e7d7926SAndrew Kaylor void *globalPtr = TheJIT->getPointerToGlobal(Global);
5366f09ad0SCraig Topper EXPECT_TRUE(nullptr != globalPtr)
545e7d7926SAndrew Kaylor << "Unable to get pointer to global value from JIT";
555e7d7926SAndrew Kaylor
565e7d7926SAndrew Kaylor EXPECT_EQ(initialValue, *(int32_t*)globalPtr)
575e7d7926SAndrew Kaylor << "Unexpected initial value of global";
585e7d7926SAndrew Kaylor }
595e7d7926SAndrew Kaylor
TEST_F(MCJITTest,add_function)605e7d7926SAndrew Kaylor TEST_F(MCJITTest, add_function) {
615e7d7926SAndrew Kaylor SKIP_UNSUPPORTED_PLATFORM;
625e7d7926SAndrew Kaylor
635e7d7926SAndrew Kaylor Function *F = insertAddFunction(M.get());
642a8a2795SRafael Espindola createJIT(std::move(M));
656bbb2c9fSAndrew Kaylor uint64_t addPtr = TheJIT->getFunctionAddress(F->getName().str());
665e7d7926SAndrew Kaylor EXPECT_TRUE(0 != addPtr)
675e7d7926SAndrew Kaylor << "Unable to get pointer to function from JIT";
685e7d7926SAndrew Kaylor
696bbb2c9fSAndrew Kaylor ASSERT_TRUE(addPtr != 0) << "Unable to get pointer to function .";
706bbb2c9fSAndrew Kaylor int (*AddPtr)(int, int) = (int(*)(int, int))addPtr ;
716bbb2c9fSAndrew Kaylor EXPECT_EQ(0, AddPtr(0, 0));
726bbb2c9fSAndrew Kaylor EXPECT_EQ(1, AddPtr(1, 0));
736bbb2c9fSAndrew Kaylor EXPECT_EQ(3, AddPtr(1, 2));
746bbb2c9fSAndrew Kaylor EXPECT_EQ(-5, AddPtr(-2, -3));
756bbb2c9fSAndrew Kaylor EXPECT_EQ(30, AddPtr(10, 20));
766bbb2c9fSAndrew Kaylor EXPECT_EQ(-30, AddPtr(-10, -20));
776bbb2c9fSAndrew Kaylor EXPECT_EQ(-40, AddPtr(-10, -30));
785e7d7926SAndrew Kaylor }
795e7d7926SAndrew Kaylor
TEST_F(MCJITTest,run_main)805e7d7926SAndrew Kaylor TEST_F(MCJITTest, run_main) {
815e7d7926SAndrew Kaylor SKIP_UNSUPPORTED_PLATFORM;
825e7d7926SAndrew Kaylor
835e7d7926SAndrew Kaylor int rc = 6;
845e7d7926SAndrew Kaylor Function *Main = insertMainFunction(M.get(), 6);
852a8a2795SRafael Espindola createJIT(std::move(M));
866bbb2c9fSAndrew Kaylor uint64_t ptr = TheJIT->getFunctionAddress(Main->getName().str());
876bbb2c9fSAndrew Kaylor EXPECT_TRUE(0 != ptr)
885e7d7926SAndrew Kaylor << "Unable to get pointer to main() from JIT";
895e7d7926SAndrew Kaylor
90ffec81caSEugene Zelenko int (*FuncPtr)() = (int(*)())ptr;
915e7d7926SAndrew Kaylor int returnCode = FuncPtr();
925e7d7926SAndrew Kaylor EXPECT_EQ(returnCode, rc);
935e7d7926SAndrew Kaylor }
945e7d7926SAndrew Kaylor
TEST_F(MCJITTest,return_global)955e7d7926SAndrew Kaylor TEST_F(MCJITTest, return_global) {
965e7d7926SAndrew Kaylor SKIP_UNSUPPORTED_PLATFORM;
975e7d7926SAndrew Kaylor
985e7d7926SAndrew Kaylor int32_t initialNum = 7;
995e7d7926SAndrew Kaylor GlobalVariable *GV = insertGlobalInt32(M.get(), "myglob", initialNum);
1005e7d7926SAndrew Kaylor
101c0044118SJames Y Knight Function *ReturnGlobal =
102c0044118SJames Y Knight startFunction(M.get(), FunctionType::get(Builder.getInt32Ty(), {}, false),
1035e7d7926SAndrew Kaylor "ReturnGlobal");
104*14359ef1SJames Y Knight Value *ReadGlobal = Builder.CreateLoad(Builder.getInt32Ty(), GV);
1055e7d7926SAndrew Kaylor endFunctionWithRet(ReturnGlobal, ReadGlobal);
1065e7d7926SAndrew Kaylor
1072a8a2795SRafael Espindola createJIT(std::move(M));
1086bbb2c9fSAndrew Kaylor uint64_t rgvPtr = TheJIT->getFunctionAddress(ReturnGlobal->getName().str());
1095e7d7926SAndrew Kaylor EXPECT_TRUE(0 != rgvPtr);
1105e7d7926SAndrew Kaylor
111ffec81caSEugene Zelenko int32_t(*FuncPtr)() = (int32_t(*)())rgvPtr;
1125e7d7926SAndrew Kaylor EXPECT_EQ(initialNum, FuncPtr())
1135e7d7926SAndrew Kaylor << "Invalid value for global returned from JITted function";
1145e7d7926SAndrew Kaylor }
1155e7d7926SAndrew Kaylor
1165e7d7926SAndrew Kaylor // FIXME: This case fails due to a bug with getPointerToGlobal().
1175e7d7926SAndrew Kaylor // The bug is due to MCJIT not having an implementation of getPointerToGlobal()
1185e7d7926SAndrew Kaylor // which results in falling back on the ExecutionEngine implementation that
1195e7d7926SAndrew Kaylor // allocates a new memory block for the global instead of using the same
1205e7d7926SAndrew Kaylor // global variable that is emitted by MCJIT. Hence, the pointer (gvPtr below)
1215e7d7926SAndrew Kaylor // has the correct initial value, but updates to the real global (accessed by
1225e7d7926SAndrew Kaylor // JITted code) are not propagated. Instead, getPointerToGlobal() should return
1235e7d7926SAndrew Kaylor // a pointer into the loaded ObjectImage to reference the emitted global.
1245e7d7926SAndrew Kaylor /*
1255e7d7926SAndrew Kaylor TEST_F(MCJITTest, increment_global) {
1265e7d7926SAndrew Kaylor SKIP_UNSUPPORTED_PLATFORM;
1275e7d7926SAndrew Kaylor
1285e7d7926SAndrew Kaylor int32_t initialNum = 5;
129c0044118SJames Y Knight Function *IncrementGlobal = startFunction(
130c0044118SJames Y Knight M.get(),
131c0044118SJames Y Knight FunctionType::get(Builder.getInt32Ty(), {}, false),
132c0044118SJames Y Knight "IncrementGlobal");
1335e7d7926SAndrew Kaylor GlobalVariable *GV = insertGlobalInt32(M.get(), "my_global", initialNum);
1345e7d7926SAndrew Kaylor Value *DerefGV = Builder.CreateLoad(GV);
1355e7d7926SAndrew Kaylor Value *AddResult = Builder.CreateAdd(DerefGV,
1365e7d7926SAndrew Kaylor ConstantInt::get(Context, APInt(32, 1)));
1375e7d7926SAndrew Kaylor Builder.CreateStore(AddResult, GV);
1385e7d7926SAndrew Kaylor endFunctionWithRet(IncrementGlobal, AddResult);
1395e7d7926SAndrew Kaylor
1405e7d7926SAndrew Kaylor createJIT(M.take());
1415e7d7926SAndrew Kaylor void *gvPtr = TheJIT->getPointerToGlobal(GV);
1425e7d7926SAndrew Kaylor EXPECT_EQ(initialNum, *(int32_t*)gvPtr);
1435e7d7926SAndrew Kaylor
1446bbb2c9fSAndrew Kaylor void *vPtr = TheJIT->getFunctionAddress(IncrementGlobal->getName().str());
1455e7d7926SAndrew Kaylor EXPECT_TRUE(0 != vPtr)
1465e7d7926SAndrew Kaylor << "Unable to get pointer to main() from JIT";
1475e7d7926SAndrew Kaylor
1485e7d7926SAndrew Kaylor int32_t(*FuncPtr)(void) = (int32_t(*)(void))(intptr_t)vPtr;
1495e7d7926SAndrew Kaylor
1505e7d7926SAndrew Kaylor for(int i = 1; i < 3; ++i) {
1515e7d7926SAndrew Kaylor int32_t result = FuncPtr();
1525e7d7926SAndrew Kaylor EXPECT_EQ(initialNum + i, result); // OK
1535e7d7926SAndrew Kaylor EXPECT_EQ(initialNum + i, *(int32_t*)gvPtr); // FAILS
1545e7d7926SAndrew Kaylor }
1555e7d7926SAndrew Kaylor }
1565e7d7926SAndrew Kaylor */
1575e7d7926SAndrew Kaylor
1582e7efeddSDavid Tweed // PR16013: XFAIL this test on ARM, which currently can't handle multiple relocations.
1592e7efeddSDavid Tweed #if !defined(__arm__)
1602e7efeddSDavid Tweed
TEST_F(MCJITTest,multiple_functions)1615e7d7926SAndrew Kaylor TEST_F(MCJITTest, multiple_functions) {
1625e7d7926SAndrew Kaylor SKIP_UNSUPPORTED_PLATFORM;
1635e7d7926SAndrew Kaylor
1645e7d7926SAndrew Kaylor unsigned int numLevels = 23;
1655e7d7926SAndrew Kaylor int32_t innerRetVal= 5;
1665e7d7926SAndrew Kaylor
167c0044118SJames Y Knight Function *Inner = startFunction(
168c0044118SJames Y Knight M.get(), FunctionType::get(Builder.getInt32Ty(), {}, false), "Inner");
1695e7d7926SAndrew Kaylor endFunctionWithRet(Inner, ConstantInt::get(Context, APInt(32, innerRetVal)));
1705e7d7926SAndrew Kaylor
1715e7d7926SAndrew Kaylor Function *Outer;
1725e7d7926SAndrew Kaylor for (unsigned int i = 0; i < numLevels; ++i) {
1735e7d7926SAndrew Kaylor std::stringstream funcName;
1745e7d7926SAndrew Kaylor funcName << "level_" << i;
175c0044118SJames Y Knight Outer = startFunction(M.get(),
176c0044118SJames Y Knight FunctionType::get(Builder.getInt32Ty(), {}, false),
177c0044118SJames Y Knight funcName.str());
178ff6409d0SDavid Blaikie Value *innerResult = Builder.CreateCall(Inner, {});
1795e7d7926SAndrew Kaylor endFunctionWithRet(Outer, innerResult);
1805e7d7926SAndrew Kaylor
1815e7d7926SAndrew Kaylor Inner = Outer;
1825e7d7926SAndrew Kaylor }
1835e7d7926SAndrew Kaylor
1842a8a2795SRafael Espindola createJIT(std::move(M));
1856bbb2c9fSAndrew Kaylor uint64_t ptr = TheJIT->getFunctionAddress(Outer->getName().str());
1866bbb2c9fSAndrew Kaylor EXPECT_TRUE(0 != ptr)
1875e7d7926SAndrew Kaylor << "Unable to get pointer to outer function from JIT";
1885e7d7926SAndrew Kaylor
189ffec81caSEugene Zelenko int32_t(*FuncPtr)() = (int32_t(*)())ptr;
1905e7d7926SAndrew Kaylor EXPECT_EQ(innerRetVal, FuncPtr())
1915e7d7926SAndrew Kaylor << "Incorrect result returned from function";
1925e7d7926SAndrew Kaylor }
1935e7d7926SAndrew Kaylor
1942e7efeddSDavid Tweed #endif /*!defined(__arm__)*/
1952e7efeddSDavid Tweed
TEST_F(MCJITTest,multiple_decl_lookups)196efe7e226SLang Hames TEST_F(MCJITTest, multiple_decl_lookups) {
197efe7e226SLang Hames SKIP_UNSUPPORTED_PLATFORM;
198efe7e226SLang Hames
199c0044118SJames Y Knight Function *Foo = insertExternalReferenceToFunction(
200c0044118SJames Y Knight M.get(), FunctionType::get(Builder.getVoidTy(), {}, false), "_exit");
201efe7e226SLang Hames createJIT(std::move(M));
202efe7e226SLang Hames void *A = TheJIT->getPointerToFunction(Foo);
203efe7e226SLang Hames void *B = TheJIT->getPointerToFunction(Foo);
204efe7e226SLang Hames
205083ca9bbSHans Wennborg EXPECT_TRUE(A != nullptr) << "Failed lookup - test not correctly configured.";
206efe7e226SLang Hames EXPECT_EQ(A, B) << "Repeat calls to getPointerToFunction fail.";
207efe7e226SLang Hames }
208efe7e226SLang Hames
2096f7012c2SLang Hames typedef void * (*FunctionHandlerPtr)(const std::string &str);
2106f7012c2SLang Hames
TEST_F(MCJITTest,lazy_function_creator_pointer)2116f7012c2SLang Hames TEST_F(MCJITTest, lazy_function_creator_pointer) {
2126f7012c2SLang Hames SKIP_UNSUPPORTED_PLATFORM;
2136f7012c2SLang Hames
214c0044118SJames Y Knight Function *Foo = insertExternalReferenceToFunction(
215c0044118SJames Y Knight M.get(), FunctionType::get(Builder.getInt32Ty(), {}, false),
2166f7012c2SLang Hames "\1Foo");
217c0044118SJames Y Knight startFunction(M.get(), FunctionType::get(Builder.getInt32Ty(), {}, false),
218c0044118SJames Y Knight "Parent");
2196f7012c2SLang Hames CallInst *Call = Builder.CreateCall(Foo, {});
2206f7012c2SLang Hames Builder.CreateRet(Call);
2216f7012c2SLang Hames
2226f7012c2SLang Hames createJIT(std::move(M));
2236f7012c2SLang Hames
2246f7012c2SLang Hames // Set up the lazy function creator that records the name of the last
2256f7012c2SLang Hames // unresolved external function found in the module. Using a function pointer
2266f7012c2SLang Hames // prevents us from capturing local variables, which is why this is static.
2276f7012c2SLang Hames static std::string UnresolvedExternal;
2286f7012c2SLang Hames FunctionHandlerPtr UnresolvedHandler = [] (const std::string &str) {
2296f7012c2SLang Hames // Try to resolve the function in the current process before marking it as
2306f7012c2SLang Hames // unresolved. This solves an issue on ARM where '__aeabi_*' function names
2316f7012c2SLang Hames // are passed to this handler.
2326f7012c2SLang Hames void *symbol =
2336f7012c2SLang Hames llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(str.c_str());
2346f7012c2SLang Hames if (symbol) {
2356f7012c2SLang Hames return symbol;
2366f7012c2SLang Hames }
2376f7012c2SLang Hames
2386f7012c2SLang Hames UnresolvedExternal = str;
2396f7012c2SLang Hames return (void *)(uintptr_t)-1;
2406f7012c2SLang Hames };
2416f7012c2SLang Hames TheJIT->InstallLazyFunctionCreator(UnresolvedHandler);
2426f7012c2SLang Hames
2436f7012c2SLang Hames // JIT the module.
2446f7012c2SLang Hames TheJIT->finalizeObject();
2456f7012c2SLang Hames
2466f7012c2SLang Hames // Verify that our handler was called.
2476f7012c2SLang Hames EXPECT_EQ(UnresolvedExternal, "Foo");
2486f7012c2SLang Hames }
2496f7012c2SLang Hames
TEST_F(MCJITTest,lazy_function_creator_lambda)2506f7012c2SLang Hames TEST_F(MCJITTest, lazy_function_creator_lambda) {
2516f7012c2SLang Hames SKIP_UNSUPPORTED_PLATFORM;
2526f7012c2SLang Hames
253c0044118SJames Y Knight FunctionType *Int32VoidFnTy =
254c0044118SJames Y Knight FunctionType::get(Builder.getInt32Ty(), {}, false);
255c0044118SJames Y Knight Function *Foo1 =
256c0044118SJames Y Knight insertExternalReferenceToFunction(M.get(), Int32VoidFnTy, "\1Foo1");
257c0044118SJames Y Knight Function *Foo2 =
258c0044118SJames Y Knight insertExternalReferenceToFunction(M.get(), Int32VoidFnTy, "\1Foo2");
259c0044118SJames Y Knight startFunction(M.get(), Int32VoidFnTy, "Parent");
2606f7012c2SLang Hames CallInst *Call1 = Builder.CreateCall(Foo1, {});
2616f7012c2SLang Hames CallInst *Call2 = Builder.CreateCall(Foo2, {});
2626f7012c2SLang Hames Value *Result = Builder.CreateAdd(Call1, Call2);
2636f7012c2SLang Hames Builder.CreateRet(Result);
2646f7012c2SLang Hames
2656f7012c2SLang Hames createJIT(std::move(M));
2666f7012c2SLang Hames
2676f7012c2SLang Hames // Set up the lazy function creator that records the name of unresolved
2686f7012c2SLang Hames // external functions in the module.
2696f7012c2SLang Hames std::vector<std::string> UnresolvedExternals;
2706f7012c2SLang Hames auto UnresolvedHandler = [&UnresolvedExternals] (const std::string &str) {
2716f7012c2SLang Hames // Try to resolve the function in the current process before marking it as
2726f7012c2SLang Hames // unresolved. This solves an issue on ARM where '__aeabi_*' function names
2736f7012c2SLang Hames // are passed to this handler.
2746f7012c2SLang Hames void *symbol =
2756f7012c2SLang Hames llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(str.c_str());
2766f7012c2SLang Hames if (symbol) {
2776f7012c2SLang Hames return symbol;
2786f7012c2SLang Hames }
2796f7012c2SLang Hames UnresolvedExternals.push_back(str);
2806f7012c2SLang Hames return (void *)(uintptr_t)-1;
2816f7012c2SLang Hames };
2826f7012c2SLang Hames TheJIT->InstallLazyFunctionCreator(UnresolvedHandler);
2836f7012c2SLang Hames
2846f7012c2SLang Hames // JIT the module.
2856f7012c2SLang Hames TheJIT->finalizeObject();
2866f7012c2SLang Hames
2876f7012c2SLang Hames // Verify that our handler was called for each unresolved function.
2886f7012c2SLang Hames auto I = UnresolvedExternals.begin(), E = UnresolvedExternals.end();
2896f7012c2SLang Hames EXPECT_EQ(UnresolvedExternals.size(), 2u);
2906f7012c2SLang Hames EXPECT_FALSE(std::find(I, E, "Foo1") == E);
2916f7012c2SLang Hames EXPECT_FALSE(std::find(I, E, "Foo2") == E);
2926f7012c2SLang Hames }
2936f7012c2SLang Hames
294083ca9bbSHans Wennborg } // end anonymous namespace
295