1 //===- MCJITTest.cpp - Unit tests for the MCJIT ---------------------------===// 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 basic MCJIT functionality such as making function 11 // calls, using global variables, and compiling multpile modules. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "llvm/ExecutionEngine/MCJIT.h" 16 #include "MCJITTestBase.h" 17 #include "gtest/gtest.h" 18 19 using namespace llvm; 20 21 class MCJITTest : public testing::Test, public MCJITTestBase { 22 protected: 23 24 virtual void SetUp() { 25 M.reset(createEmptyModule("<main>")); 26 } 27 }; 28 29 namespace { 30 31 // FIXME: In order to JIT an empty module, there needs to be 32 // an interface to ExecutionEngine that forces compilation but 33 // does require retrieval of a pointer to a function/global. 34 /* 35 TEST_F(MCJITTest, empty_module) { 36 createJIT(M.take()); 37 TheJIT->finalizeObject(); 38 //EXPECT_NE(0, TheJIT->getObjectImage()) 39 // << "Unable to generate executable loaded object image"; 40 } 41 */ 42 43 TEST_F(MCJITTest, global_variable) { 44 SKIP_UNSUPPORTED_PLATFORM; 45 46 int initialValue = 5; 47 GlobalValue *Global = insertGlobalInt32(M.get(), "test_global", initialValue); 48 createJIT(M.take()); 49 void *globalPtr = TheJIT->getPointerToGlobal(Global); 50 TheJIT->finalizeObject(); 51 EXPECT_TRUE(0 != globalPtr) 52 << "Unable to get pointer to global value from JIT"; 53 54 EXPECT_EQ(initialValue, *(int32_t*)globalPtr) 55 << "Unexpected initial value of global"; 56 } 57 58 TEST_F(MCJITTest, add_function) { 59 SKIP_UNSUPPORTED_PLATFORM; 60 61 Function *F = insertAddFunction(M.get()); 62 createJIT(M.take()); 63 void *addPtr = TheJIT->getPointerToFunction(F); 64 TheJIT->finalizeObject(); 65 EXPECT_TRUE(0 != addPtr) 66 << "Unable to get pointer to function from JIT"; 67 68 int (*AddPtrTy)(int, int) = (int(*)(int, int))(intptr_t)addPtr; 69 EXPECT_EQ(0, AddPtrTy(0, 0)); 70 EXPECT_EQ(3, AddPtrTy(1, 2)); 71 EXPECT_EQ(-5, AddPtrTy(-2, -3)); 72 } 73 74 TEST_F(MCJITTest, run_main) { 75 SKIP_UNSUPPORTED_PLATFORM; 76 77 int rc = 6; 78 Function *Main = insertMainFunction(M.get(), 6); 79 createJIT(M.take()); 80 void *vPtr = TheJIT->getPointerToFunction(Main); 81 TheJIT->finalizeObject(); 82 EXPECT_TRUE(0 != vPtr) 83 << "Unable to get pointer to main() from JIT"; 84 85 int (*FuncPtr)(void) = (int(*)(void))(intptr_t)vPtr; 86 int returnCode = FuncPtr(); 87 EXPECT_EQ(returnCode, rc); 88 } 89 90 TEST_F(MCJITTest, return_global) { 91 SKIP_UNSUPPORTED_PLATFORM; 92 93 int32_t initialNum = 7; 94 GlobalVariable *GV = insertGlobalInt32(M.get(), "myglob", initialNum); 95 96 Function *ReturnGlobal = startFunction<int32_t(void)>(M.get(), 97 "ReturnGlobal"); 98 Value *ReadGlobal = Builder.CreateLoad(GV); 99 endFunctionWithRet(ReturnGlobal, ReadGlobal); 100 101 createJIT(M.take()); 102 void *rgvPtr = TheJIT->getPointerToFunction(ReturnGlobal); 103 TheJIT->finalizeObject(); 104 EXPECT_TRUE(0 != rgvPtr); 105 106 int32_t(*FuncPtr)(void) = (int32_t(*)(void))(intptr_t)rgvPtr; 107 EXPECT_EQ(initialNum, FuncPtr()) 108 << "Invalid value for global returned from JITted function"; 109 } 110 111 // FIXME: This case fails due to a bug with getPointerToGlobal(). 112 // The bug is due to MCJIT not having an implementation of getPointerToGlobal() 113 // which results in falling back on the ExecutionEngine implementation that 114 // allocates a new memory block for the global instead of using the same 115 // global variable that is emitted by MCJIT. Hence, the pointer (gvPtr below) 116 // has the correct initial value, but updates to the real global (accessed by 117 // JITted code) are not propagated. Instead, getPointerToGlobal() should return 118 // a pointer into the loaded ObjectImage to reference the emitted global. 119 /* 120 TEST_F(MCJITTest, increment_global) { 121 SKIP_UNSUPPORTED_PLATFORM; 122 123 int32_t initialNum = 5; 124 Function *IncrementGlobal = startFunction<int32_t(void)>(M.get(), "IncrementGlobal"); 125 GlobalVariable *GV = insertGlobalInt32(M.get(), "my_global", initialNum); 126 Value *DerefGV = Builder.CreateLoad(GV); 127 Value *AddResult = Builder.CreateAdd(DerefGV, 128 ConstantInt::get(Context, APInt(32, 1))); 129 Builder.CreateStore(AddResult, GV); 130 endFunctionWithRet(IncrementGlobal, AddResult); 131 132 createJIT(M.take()); 133 void *gvPtr = TheJIT->getPointerToGlobal(GV); 134 TheJIT->finalizeObject(); 135 EXPECT_EQ(initialNum, *(int32_t*)gvPtr); 136 137 void *vPtr = TheJIT->getPointerToFunction(IncrementGlobal); 138 EXPECT_TRUE(0 != vPtr) 139 << "Unable to get pointer to main() from JIT"; 140 141 int32_t(*FuncPtr)(void) = (int32_t(*)(void))(intptr_t)vPtr; 142 143 for(int i = 1; i < 3; ++i) { 144 int32_t result = FuncPtr(); 145 EXPECT_EQ(initialNum + i, result); // OK 146 EXPECT_EQ(initialNum + i, *(int32_t*)gvPtr); // FAILS 147 } 148 } 149 */ 150 151 // PR16013: XFAIL this test on ARM, which currently can't handle multiple relocations. 152 #if !defined(__arm__) 153 154 TEST_F(MCJITTest, multiple_functions) { 155 SKIP_UNSUPPORTED_PLATFORM; 156 157 unsigned int numLevels = 23; 158 int32_t innerRetVal= 5; 159 160 Function *Inner = startFunction<int32_t(void)>(M.get(), "Inner"); 161 endFunctionWithRet(Inner, ConstantInt::get(Context, APInt(32, innerRetVal))); 162 163 Function *Outer; 164 for (unsigned int i = 0; i < numLevels; ++i) { 165 std::stringstream funcName; 166 funcName << "level_" << i; 167 Outer = startFunction<int32_t(void)>(M.get(), funcName.str()); 168 Value *innerResult = Builder.CreateCall(Inner); 169 endFunctionWithRet(Outer, innerResult); 170 171 Inner = Outer; 172 } 173 174 createJIT(M.take()); 175 void *vPtr = TheJIT->getPointerToFunction(Outer); 176 TheJIT->finalizeObject(); 177 EXPECT_TRUE(0 != vPtr) 178 << "Unable to get pointer to outer function from JIT"; 179 180 int32_t(*FuncPtr)(void) = (int32_t(*)(void))(intptr_t)vPtr; 181 EXPECT_EQ(innerRetVal, FuncPtr()) 182 << "Incorrect result returned from function"; 183 } 184 185 #endif /*!defined(__arm__)*/ 186 187 // FIXME: ExecutionEngine has no support empty modules 188 /* 189 TEST_F(MCJITTest, multiple_empty_modules) { 190 SKIP_UNSUPPORTED_PLATFORM; 191 192 createJIT(M.take()); 193 // JIT-compile 194 EXPECT_NE(0, TheJIT->getObjectImage()) 195 << "Unable to generate executable loaded object image"; 196 197 TheJIT->addModule(createEmptyModule("<other module>")); 198 TheJIT->addModule(createEmptyModule("<other other module>")); 199 200 // JIT again 201 EXPECT_NE(0, TheJIT->getObjectImage()) 202 << "Unable to generate executable loaded object image"; 203 } 204 */ 205 206 // FIXME: MCJIT must support multiple modules 207 /* 208 TEST_F(MCJITTest, multiple_modules) { 209 SKIP_UNSUPPORTED_PLATFORM; 210 211 Function *Callee = insertAddFunction(M.get()); 212 createJIT(M.take()); 213 214 // caller function is defined in a different module 215 M.reset(createEmptyModule("<caller module>")); 216 217 Function *CalleeRef = insertExternalReferenceToFunction(M.get(), Callee); 218 Function *Caller = insertSimpleCallFunction(M.get(), CalleeRef); 219 220 TheJIT->addModule(M.take()); 221 222 // get a function pointer in a module that was not used in EE construction 223 void *vPtr = TheJIT->getPointerToFunction(Caller); 224 TheJIT->finalizeObject(); 225 EXPECT_NE(0, vPtr) 226 << "Unable to get pointer to caller function from JIT"; 227 228 int(*FuncPtr)(int, int) = (int(*)(int, int))(intptr_t)vPtr; 229 EXPECT_EQ(0, FuncPtr(0, 0)); 230 EXPECT_EQ(30, FuncPtr(10, 20)); 231 EXPECT_EQ(-30, FuncPtr(-10, -20)); 232 233 // ensure caller is destroyed before callee (free use before def) 234 M.reset(); 235 } 236 */ 237 238 } 239