Home | History | Annotate | Download | only in MCJIT
      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 namespace {
     22 
     23 class MCJITTest : public testing::Test, public MCJITTestBase {
     24 protected:
     25   virtual void SetUp() { M.reset(createEmptyModule("<main>")); }
     26 };
     27 
     28 // FIXME: Ensure creating an execution engine does not crash when constructed
     29 //        with a null module.
     30 /*
     31 TEST_F(MCJITTest, null_module) {
     32   createJIT(0);
     33 }
     34 */
     35 
     36 // FIXME: In order to JIT an empty module, there needs to be
     37 // an interface to ExecutionEngine that forces compilation but
     38 // does not require retrieval of a pointer to a function/global.
     39 /*
     40 TEST_F(MCJITTest, empty_module) {
     41   createJIT(M.take());
     42   //EXPECT_NE(0, TheJIT->getObjectImage())
     43   //  << "Unable to generate executable loaded object image";
     44 }
     45 */
     46 
     47 TEST_F(MCJITTest, global_variable) {
     48   SKIP_UNSUPPORTED_PLATFORM;
     49 
     50   int initialValue = 5;
     51   GlobalValue *Global = insertGlobalInt32(M.get(), "test_global", initialValue);
     52   createJIT(M.release());
     53   void *globalPtr =  TheJIT->getPointerToGlobal(Global);
     54   EXPECT_TRUE(nullptr != globalPtr)
     55     << "Unable to get pointer to global value from JIT";
     56 
     57   EXPECT_EQ(initialValue, *(int32_t*)globalPtr)
     58     << "Unexpected initial value of global";
     59 }
     60 
     61 TEST_F(MCJITTest, add_function) {
     62   SKIP_UNSUPPORTED_PLATFORM;
     63 
     64   Function *F = insertAddFunction(M.get());
     65   createJIT(M.release());
     66   uint64_t addPtr = TheJIT->getFunctionAddress(F->getName().str());
     67   EXPECT_TRUE(0 != addPtr)
     68     << "Unable to get pointer to function from JIT";
     69 
     70   ASSERT_TRUE(addPtr != 0) << "Unable to get pointer to function .";
     71   int (*AddPtr)(int, int) = (int(*)(int, int))addPtr ;
     72   EXPECT_EQ(0,   AddPtr(0, 0));
     73   EXPECT_EQ(1,   AddPtr(1, 0));
     74   EXPECT_EQ(3,   AddPtr(1, 2));
     75   EXPECT_EQ(-5,  AddPtr(-2, -3));
     76   EXPECT_EQ(30,  AddPtr(10, 20));
     77   EXPECT_EQ(-30, AddPtr(-10, -20));
     78   EXPECT_EQ(-40, AddPtr(-10, -30));
     79 }
     80 
     81 TEST_F(MCJITTest, run_main) {
     82   SKIP_UNSUPPORTED_PLATFORM;
     83 
     84   int rc = 6;
     85   Function *Main = insertMainFunction(M.get(), 6);
     86   createJIT(M.release());
     87   uint64_t ptr = TheJIT->getFunctionAddress(Main->getName().str());
     88   EXPECT_TRUE(0 != ptr)
     89     << "Unable to get pointer to main() from JIT";
     90 
     91   int (*FuncPtr)(void) = (int(*)(void))ptr;
     92   int returnCode = FuncPtr();
     93   EXPECT_EQ(returnCode, rc);
     94 }
     95 
     96 TEST_F(MCJITTest, return_global) {
     97   SKIP_UNSUPPORTED_PLATFORM;
     98 
     99   int32_t initialNum = 7;
    100   GlobalVariable *GV = insertGlobalInt32(M.get(), "myglob", initialNum);
    101 
    102   Function *ReturnGlobal = startFunction<int32_t(void)>(M.get(),
    103                                                         "ReturnGlobal");
    104   Value *ReadGlobal = Builder.CreateLoad(GV);
    105   endFunctionWithRet(ReturnGlobal, ReadGlobal);
    106 
    107   createJIT(M.release());
    108   uint64_t rgvPtr = TheJIT->getFunctionAddress(ReturnGlobal->getName().str());
    109   EXPECT_TRUE(0 != rgvPtr);
    110 
    111   int32_t(*FuncPtr)(void) = (int32_t(*)(void))rgvPtr;
    112   EXPECT_EQ(initialNum, FuncPtr())
    113     << "Invalid value for global returned from JITted function";
    114 }
    115 
    116 // FIXME: This case fails due to a bug with getPointerToGlobal().
    117 // The bug is due to MCJIT not having an implementation of getPointerToGlobal()
    118 // which results in falling back on the ExecutionEngine implementation that
    119 // allocates a new memory block for the global instead of using the same
    120 // global variable that is emitted by MCJIT. Hence, the pointer (gvPtr below)
    121 // has the correct initial value, but updates to the real global (accessed by
    122 // JITted code) are not propagated. Instead, getPointerToGlobal() should return
    123 // a pointer into the loaded ObjectImage to reference the emitted global.
    124 /*
    125 TEST_F(MCJITTest, increment_global) {
    126   SKIP_UNSUPPORTED_PLATFORM;
    127 
    128   int32_t initialNum = 5;
    129   Function *IncrementGlobal = startFunction<int32_t(void)>(M.get(), "IncrementGlobal");
    130   GlobalVariable *GV = insertGlobalInt32(M.get(), "my_global", initialNum);
    131   Value *DerefGV = Builder.CreateLoad(GV);
    132   Value *AddResult = Builder.CreateAdd(DerefGV,
    133                                        ConstantInt::get(Context, APInt(32, 1)));
    134   Builder.CreateStore(AddResult, GV);
    135   endFunctionWithRet(IncrementGlobal, AddResult);
    136 
    137   createJIT(M.take());
    138   void *gvPtr = TheJIT->getPointerToGlobal(GV);
    139   EXPECT_EQ(initialNum, *(int32_t*)gvPtr);
    140 
    141   void *vPtr = TheJIT->getFunctionAddress(IncrementGlobal->getName().str());
    142   EXPECT_TRUE(0 != vPtr)
    143     << "Unable to get pointer to main() from JIT";
    144 
    145   int32_t(*FuncPtr)(void) = (int32_t(*)(void))(intptr_t)vPtr;
    146 
    147   for(int i = 1; i < 3; ++i) {
    148     int32_t result = FuncPtr();
    149     EXPECT_EQ(initialNum + i, result);            // OK
    150     EXPECT_EQ(initialNum + i, *(int32_t*)gvPtr);  // FAILS
    151   }
    152 }
    153 */
    154 
    155 // PR16013: XFAIL this test on ARM, which currently can't handle multiple relocations.
    156 #if !defined(__arm__)
    157 
    158 TEST_F(MCJITTest, multiple_functions) {
    159   SKIP_UNSUPPORTED_PLATFORM;
    160 
    161   unsigned int numLevels = 23;
    162   int32_t innerRetVal= 5;
    163 
    164   Function *Inner = startFunction<int32_t(void)>(M.get(), "Inner");
    165   endFunctionWithRet(Inner, ConstantInt::get(Context, APInt(32, innerRetVal)));
    166 
    167   Function *Outer;
    168   for (unsigned int i = 0; i < numLevels; ++i) {
    169     std::stringstream funcName;
    170     funcName << "level_" << i;
    171     Outer = startFunction<int32_t(void)>(M.get(), funcName.str());
    172     Value *innerResult = Builder.CreateCall(Inner);
    173     endFunctionWithRet(Outer, innerResult);
    174 
    175     Inner = Outer;
    176   }
    177 
    178   createJIT(M.release());
    179   uint64_t ptr = TheJIT->getFunctionAddress(Outer->getName().str());
    180   EXPECT_TRUE(0 != ptr)
    181     << "Unable to get pointer to outer function from JIT";
    182 
    183   int32_t(*FuncPtr)(void) = (int32_t(*)(void))ptr;
    184   EXPECT_EQ(innerRetVal, FuncPtr())
    185     << "Incorrect result returned from function";
    186 }
    187 
    188 #endif /*!defined(__arm__)*/
    189 
    190 }
    191