Home | History | Annotate | Download | only in JIT
      1 //===- MultiJITTest.cpp - Unit tests for instantiating multiple JITs ------===//
      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 #include "llvm/ExecutionEngine/JIT.h"
     11 #include "llvm/AsmParser/Parser.h"
     12 #include "llvm/ExecutionEngine/GenericValue.h"
     13 #include "llvm/IR/LLVMContext.h"
     14 #include "llvm/IR/Module.h"
     15 #include "llvm/Support/SourceMgr.h"
     16 #include "gtest/gtest.h"
     17 #include <vector>
     18 
     19 using namespace llvm;
     20 
     21 namespace {
     22 
     23 // ARM, PowerPC and SystemZ tests disabled pending fix for PR10783.
     24 #if !defined(__arm__) && !defined(__powerpc__) && !defined(__s390__) \
     25                       && !defined(__aarch64__)
     26 
     27 bool LoadAssemblyInto(Module *M, const char *assembly) {
     28   SMDiagnostic Error;
     29   bool success =
     30     nullptr != ParseAssemblyString(assembly, M, Error, M->getContext());
     31   std::string errMsg;
     32   raw_string_ostream os(errMsg);
     33   Error.print("", os);
     34   EXPECT_TRUE(success) << os.str();
     35   return success;
     36 }
     37 
     38 void createModule1(LLVMContext &Context1, Module *&M1, Function *&FooF1) {
     39   M1 = new Module("test1", Context1);
     40   LoadAssemblyInto(M1,
     41                    "define i32 @add1(i32 %ArgX1) { "
     42                    "entry: "
     43                    "  %addresult = add i32 1, %ArgX1 "
     44                    "  ret i32 %addresult "
     45                    "} "
     46                    " "
     47                    "define i32 @foo1() { "
     48                    "entry: "
     49                    "  %add1 = call i32 @add1(i32 10) "
     50                    "  ret i32 %add1 "
     51                    "} ");
     52   FooF1 = M1->getFunction("foo1");
     53 }
     54 
     55 void createModule2(LLVMContext &Context2, Module *&M2, Function *&FooF2) {
     56   M2 = new Module("test2", Context2);
     57   LoadAssemblyInto(M2,
     58                    "define i32 @add2(i32 %ArgX2) { "
     59                    "entry: "
     60                    "  %addresult = add i32 2, %ArgX2 "
     61                    "  ret i32 %addresult "
     62                    "} "
     63                    " "
     64                    "define i32 @foo2() { "
     65                    "entry: "
     66                    "  %add2 = call i32 @add2(i32 10) "
     67                    "  ret i32 %add2 "
     68                    "} ");
     69   FooF2 = M2->getFunction("foo2");
     70 }
     71 
     72 TEST(MultiJitTest, EagerMode) {
     73   LLVMContext Context1;
     74   Module *M1 = nullptr;
     75   Function *FooF1 = nullptr;
     76   createModule1(Context1, M1, FooF1);
     77 
     78   LLVMContext Context2;
     79   Module *M2 = nullptr;
     80   Function *FooF2 = nullptr;
     81   createModule2(Context2, M2, FooF2);
     82 
     83   // Now we create the JIT in eager mode
     84   std::unique_ptr<ExecutionEngine> EE1(EngineBuilder(M1).create());
     85   EE1->DisableLazyCompilation(true);
     86   std::unique_ptr<ExecutionEngine> EE2(EngineBuilder(M2).create());
     87   EE2->DisableLazyCompilation(true);
     88 
     89   // Call the `foo' function with no arguments:
     90   std::vector<GenericValue> noargs;
     91   GenericValue gv1 = EE1->runFunction(FooF1, noargs);
     92   GenericValue gv2 = EE2->runFunction(FooF2, noargs);
     93 
     94   // Import result of execution:
     95   EXPECT_EQ(gv1.IntVal, 11);
     96   EXPECT_EQ(gv2.IntVal, 12);
     97 
     98   EE1->freeMachineCodeForFunction(FooF1);
     99   EE2->freeMachineCodeForFunction(FooF2);
    100 }
    101 
    102 TEST(MultiJitTest, LazyMode) {
    103   LLVMContext Context1;
    104   Module *M1 = nullptr;
    105   Function *FooF1 = nullptr;
    106   createModule1(Context1, M1, FooF1);
    107 
    108   LLVMContext Context2;
    109   Module *M2 = nullptr;
    110   Function *FooF2 = nullptr;
    111   createModule2(Context2, M2, FooF2);
    112 
    113   // Now we create the JIT in lazy mode
    114   std::unique_ptr<ExecutionEngine> EE1(EngineBuilder(M1).create());
    115   EE1->DisableLazyCompilation(false);
    116   std::unique_ptr<ExecutionEngine> EE2(EngineBuilder(M2).create());
    117   EE2->DisableLazyCompilation(false);
    118 
    119   // Call the `foo' function with no arguments:
    120   std::vector<GenericValue> noargs;
    121   GenericValue gv1 = EE1->runFunction(FooF1, noargs);
    122   GenericValue gv2 = EE2->runFunction(FooF2, noargs);
    123 
    124   // Import result of execution:
    125   EXPECT_EQ(gv1.IntVal, 11);
    126   EXPECT_EQ(gv2.IntVal, 12);
    127 
    128   EE1->freeMachineCodeForFunction(FooF1);
    129   EE2->freeMachineCodeForFunction(FooF2);
    130 }
    131 
    132 extern "C" {
    133   extern void *getPointerToNamedFunction(const char *Name);
    134 }
    135 
    136 TEST(MultiJitTest, JitPool) {
    137   LLVMContext Context1;
    138   Module *M1 = nullptr;
    139   Function *FooF1 = nullptr;
    140   createModule1(Context1, M1, FooF1);
    141 
    142   LLVMContext Context2;
    143   Module *M2 = nullptr;
    144   Function *FooF2 = nullptr;
    145   createModule2(Context2, M2, FooF2);
    146 
    147   // Now we create two JITs
    148   std::unique_ptr<ExecutionEngine> EE1(EngineBuilder(M1).create());
    149   std::unique_ptr<ExecutionEngine> EE2(EngineBuilder(M2).create());
    150 
    151   Function *F1 = EE1->FindFunctionNamed("foo1");
    152   void *foo1 = EE1->getPointerToFunction(F1);
    153 
    154   Function *F2 = EE2->FindFunctionNamed("foo2");
    155   void *foo2 = EE2->getPointerToFunction(F2);
    156 
    157   // Function in M1
    158   EXPECT_EQ(getPointerToNamedFunction("foo1"), foo1);
    159 
    160   // Function in M2
    161   EXPECT_EQ(getPointerToNamedFunction("foo2"), foo2);
    162 
    163   // Symbol search
    164   intptr_t
    165     sa = (intptr_t)getPointerToNamedFunction("getPointerToNamedFunction");
    166   EXPECT_TRUE(sa != 0);
    167   intptr_t fa = (intptr_t)&getPointerToNamedFunction;
    168   EXPECT_TRUE(fa != 0);
    169 #ifdef __i386__
    170   // getPointerToNamedFunction might be indirect jump on Win32 --enable-shared.
    171   // FF 25 <disp32>: jmp *(pointer to IAT)
    172   if (sa != fa && memcmp((char *)fa, "\xFF\x25", 2) == 0) {
    173     fa = *(intptr_t *)(fa + 2); // Address to IAT
    174     EXPECT_TRUE(fa != 0);
    175     fa = *(intptr_t *)fa;       // Bound value of IAT
    176   }
    177 #elif defined(__x86_64__)
    178   // getPointerToNamedFunction might be indirect jump
    179   // on Win32 x64 --enable-shared.
    180   // FF 25 <pcrel32>: jmp *(RIP + pointer to IAT)
    181   if (sa != fa && memcmp((char *)fa, "\xFF\x25", 2) == 0) {
    182     fa += *(int32_t *)(fa + 2) + 6;     // Address to IAT(RIP)
    183     fa = *(intptr_t *)fa;               // Bound value of IAT
    184   }
    185 #endif
    186   EXPECT_TRUE(sa == fa);
    187 }
    188 #endif  // !defined(__arm__) && !defined(__powerpc__) && !defined(__s390__)
    189 
    190 }  // anonymous namespace
    191