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 when invoked form the C
     11 // API.
     12 //
     13 //===----------------------------------------------------------------------===//
     14 
     15 #include "llvm-c/Analysis.h"
     16 #include "MCJITTestAPICommon.h"
     17 #include "llvm-c/Core.h"
     18 #include "llvm-c/ExecutionEngine.h"
     19 #include "llvm-c/Target.h"
     20 #include "llvm-c/Transforms/PassManagerBuilder.h"
     21 #include "llvm-c/Transforms/Scalar.h"
     22 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
     23 #include "llvm/Support/Debug.h"
     24 #include "llvm/Support/Host.h"
     25 #include "gtest/gtest.h"
     26 
     27 using namespace llvm;
     28 
     29 static bool didCallAllocateCodeSection;
     30 static bool didAllocateCompactUnwindSection;
     31 static bool didCallYield;
     32 
     33 static uint8_t *roundTripAllocateCodeSection(void *object, uintptr_t size,
     34                                              unsigned alignment,
     35                                              unsigned sectionID,
     36                                              const char *sectionName) {
     37   didCallAllocateCodeSection = true;
     38   return static_cast<SectionMemoryManager*>(object)->allocateCodeSection(
     39     size, alignment, sectionID, sectionName);
     40 }
     41 
     42 static uint8_t *roundTripAllocateDataSection(void *object, uintptr_t size,
     43                                              unsigned alignment,
     44                                              unsigned sectionID,
     45                                              const char *sectionName,
     46                                              LLVMBool isReadOnly) {
     47   if (!strcmp(sectionName, "__compact_unwind"))
     48     didAllocateCompactUnwindSection = true;
     49   return static_cast<SectionMemoryManager*>(object)->allocateDataSection(
     50     size, alignment, sectionID, sectionName, isReadOnly);
     51 }
     52 
     53 static LLVMBool roundTripFinalizeMemory(void *object, char **errMsg) {
     54   std::string errMsgString;
     55   bool result =
     56     static_cast<SectionMemoryManager*>(object)->finalizeMemory(&errMsgString);
     57   if (result) {
     58     *errMsg = LLVMCreateMessage(errMsgString.c_str());
     59     return 1;
     60   }
     61   return 0;
     62 }
     63 
     64 static void roundTripDestroy(void *object) {
     65   delete static_cast<SectionMemoryManager*>(object);
     66 }
     67 
     68 static void yield(LLVMContextRef, void *) {
     69   didCallYield = true;
     70 }
     71 
     72 namespace {
     73 
     74 // memory manager to test reserve allocation space callback
     75 class TestReserveAllocationSpaceMemoryManager: public SectionMemoryManager {
     76 public:
     77   uintptr_t ReservedCodeSize;
     78   uintptr_t UsedCodeSize;
     79   uintptr_t ReservedDataSizeRO;
     80   uintptr_t UsedDataSizeRO;
     81   uintptr_t ReservedDataSizeRW;
     82   uintptr_t UsedDataSizeRW;
     83 
     84   TestReserveAllocationSpaceMemoryManager() :
     85     ReservedCodeSize(0), UsedCodeSize(0), ReservedDataSizeRO(0),
     86     UsedDataSizeRO(0), ReservedDataSizeRW(0), UsedDataSizeRW(0) {
     87   }
     88 
     89   virtual bool needsToReserveAllocationSpace() {
     90     return true;
     91   }
     92 
     93   virtual void reserveAllocationSpace(
     94       uintptr_t CodeSize, uintptr_t DataSizeRO, uintptr_t DataSizeRW) {
     95     ReservedCodeSize = CodeSize;
     96     ReservedDataSizeRO = DataSizeRO;
     97     ReservedDataSizeRW = DataSizeRW;
     98   }
     99 
    100   void useSpace(uintptr_t* UsedSize, uintptr_t Size, unsigned Alignment) {
    101     uintptr_t AlignedSize = (Size + Alignment - 1) / Alignment * Alignment;
    102     uintptr_t AlignedBegin = (*UsedSize + Alignment - 1) / Alignment * Alignment;
    103     *UsedSize = AlignedBegin + AlignedSize;
    104   }
    105 
    106   virtual uint8_t* allocateDataSection(uintptr_t Size, unsigned Alignment,
    107       unsigned SectionID, StringRef SectionName, bool IsReadOnly) {
    108     useSpace(IsReadOnly ? &UsedDataSizeRO : &UsedDataSizeRW, Size, Alignment);
    109     return SectionMemoryManager::allocateDataSection(Size, Alignment,
    110       SectionID, SectionName, IsReadOnly);
    111   }
    112 
    113   uint8_t* allocateCodeSection(uintptr_t Size, unsigned Alignment,
    114       unsigned SectionID, StringRef SectionName) {
    115     useSpace(&UsedCodeSize, Size, Alignment);
    116     return SectionMemoryManager::allocateCodeSection(Size, Alignment,
    117       SectionID, SectionName);
    118   }
    119 };
    120 
    121 class MCJITCAPITest : public testing::Test, public MCJITTestAPICommon {
    122 protected:
    123   MCJITCAPITest() {
    124     // The architectures below are known to be compatible with MCJIT as they
    125     // are copied from test/ExecutionEngine/MCJIT/lit.local.cfg and should be
    126     // kept in sync.
    127     SupportedArchs.push_back(Triple::aarch64);
    128     SupportedArchs.push_back(Triple::arm);
    129     SupportedArchs.push_back(Triple::mips);
    130     SupportedArchs.push_back(Triple::x86);
    131     SupportedArchs.push_back(Triple::x86_64);
    132 
    133     // Some architectures have sub-architectures in which tests will fail, like
    134     // ARM. These two vectors will define if they do have sub-archs (to avoid
    135     // extra work for those who don't), and if so, if they are listed to work
    136     HasSubArchs.push_back(Triple::arm);
    137     SupportedSubArchs.push_back("armv6");
    138     SupportedSubArchs.push_back("armv7");
    139 
    140     // The operating systems below are known to be sufficiently incompatible
    141     // that they will fail the MCJIT C API tests.
    142     UnsupportedOSs.push_back(Triple::Cygwin);
    143 
    144     UnsupportedEnvironments.push_back(Triple::Cygnus);
    145   }
    146 
    147   virtual void SetUp() {
    148     didCallAllocateCodeSection = false;
    149     didAllocateCompactUnwindSection = false;
    150     didCallYield = false;
    151     Module = nullptr;
    152     Function = nullptr;
    153     Engine = nullptr;
    154     Error = nullptr;
    155   }
    156 
    157   virtual void TearDown() {
    158     if (Engine)
    159       LLVMDisposeExecutionEngine(Engine);
    160     else if (Module)
    161       LLVMDisposeModule(Module);
    162   }
    163 
    164   void buildSimpleFunction() {
    165     Module = LLVMModuleCreateWithName("simple_module");
    166 
    167     LLVMSetTarget(Module, HostTriple.c_str());
    168 
    169     Function = LLVMAddFunction(Module, "simple_function",
    170                                LLVMFunctionType(LLVMInt32Type(), nullptr,0, 0));
    171     LLVMSetFunctionCallConv(Function, LLVMCCallConv);
    172 
    173     LLVMBasicBlockRef entry = LLVMAppendBasicBlock(Function, "entry");
    174     LLVMBuilderRef builder = LLVMCreateBuilder();
    175     LLVMPositionBuilderAtEnd(builder, entry);
    176     LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0));
    177 
    178     LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
    179     LLVMDisposeMessage(Error);
    180 
    181     LLVMDisposeBuilder(builder);
    182   }
    183 
    184   void buildFunctionThatUsesStackmap() {
    185     Module = LLVMModuleCreateWithName("simple_module");
    186 
    187     LLVMSetTarget(Module, HostTriple.c_str());
    188 
    189     LLVMTypeRef stackmapParamTypes[] = { LLVMInt64Type(), LLVMInt32Type() };
    190     LLVMValueRef stackmap = LLVMAddFunction(
    191       Module, "llvm.experimental.stackmap",
    192       LLVMFunctionType(LLVMVoidType(), stackmapParamTypes, 2, 1));
    193     LLVMSetLinkage(stackmap, LLVMExternalLinkage);
    194 
    195     Function = LLVMAddFunction(Module, "simple_function",
    196                               LLVMFunctionType(LLVMInt32Type(), nullptr, 0, 0));
    197 
    198     LLVMBasicBlockRef entry = LLVMAppendBasicBlock(Function, "entry");
    199     LLVMBuilderRef builder = LLVMCreateBuilder();
    200     LLVMPositionBuilderAtEnd(builder, entry);
    201     LLVMValueRef stackmapArgs[] = {
    202       LLVMConstInt(LLVMInt64Type(), 0, 0), LLVMConstInt(LLVMInt32Type(), 5, 0),
    203       LLVMConstInt(LLVMInt32Type(), 42, 0)
    204     };
    205     LLVMBuildCall(builder, stackmap, stackmapArgs, 3, "");
    206     LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0));
    207 
    208     LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
    209     LLVMDisposeMessage(Error);
    210 
    211     LLVMDisposeBuilder(builder);
    212   }
    213 
    214   void buildModuleWithCodeAndData() {
    215     Module = LLVMModuleCreateWithName("simple_module");
    216 
    217     LLVMSetTarget(Module, HostTriple.c_str());
    218 
    219     // build a global int32 variable initialized to 42.
    220     LLVMValueRef GlobalVar = LLVMAddGlobal(Module, LLVMInt32Type(), "intVal");
    221     LLVMSetInitializer(GlobalVar, LLVMConstInt(LLVMInt32Type(), 42, 0));
    222 
    223     {
    224         Function = LLVMAddFunction(Module, "getGlobal",
    225                               LLVMFunctionType(LLVMInt32Type(), nullptr, 0, 0));
    226         LLVMSetFunctionCallConv(Function, LLVMCCallConv);
    227 
    228         LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function, "entry");
    229         LLVMBuilderRef Builder = LLVMCreateBuilder();
    230         LLVMPositionBuilderAtEnd(Builder, Entry);
    231 
    232         LLVMValueRef IntVal = LLVMBuildLoad(Builder, GlobalVar, "intVal");
    233         LLVMBuildRet(Builder, IntVal);
    234 
    235         LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
    236         LLVMDisposeMessage(Error);
    237 
    238         LLVMDisposeBuilder(Builder);
    239     }
    240 
    241     {
    242         LLVMTypeRef ParamTypes[] = { LLVMInt32Type() };
    243         Function2 = LLVMAddFunction(
    244           Module, "setGlobal", LLVMFunctionType(LLVMVoidType(), ParamTypes, 1, 0));
    245         LLVMSetFunctionCallConv(Function2, LLVMCCallConv);
    246 
    247         LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function2, "entry");
    248         LLVMBuilderRef Builder = LLVMCreateBuilder();
    249         LLVMPositionBuilderAtEnd(Builder, Entry);
    250 
    251         LLVMValueRef Arg = LLVMGetParam(Function2, 0);
    252         LLVMBuildStore(Builder, Arg, GlobalVar);
    253         LLVMBuildRetVoid(Builder);
    254 
    255         LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
    256         LLVMDisposeMessage(Error);
    257 
    258         LLVMDisposeBuilder(Builder);
    259     }
    260   }
    261 
    262   void buildMCJITOptions() {
    263     LLVMInitializeMCJITCompilerOptions(&Options, sizeof(Options));
    264     Options.OptLevel = 2;
    265 
    266     // Just ensure that this field still exists.
    267     Options.NoFramePointerElim = false;
    268   }
    269 
    270   void useRoundTripSectionMemoryManager() {
    271     Options.MCJMM = LLVMCreateSimpleMCJITMemoryManager(
    272       new SectionMemoryManager(),
    273       roundTripAllocateCodeSection,
    274       roundTripAllocateDataSection,
    275       roundTripFinalizeMemory,
    276       roundTripDestroy);
    277   }
    278 
    279   void buildMCJITEngine() {
    280     ASSERT_EQ(
    281       0, LLVMCreateMCJITCompilerForModule(&Engine, Module, &Options,
    282                                           sizeof(Options), &Error));
    283   }
    284 
    285   void buildAndRunPasses() {
    286     LLVMPassManagerRef pass = LLVMCreatePassManager();
    287     LLVMAddTargetData(LLVMGetExecutionEngineTargetData(Engine), pass);
    288     LLVMAddConstantPropagationPass(pass);
    289     LLVMAddInstructionCombiningPass(pass);
    290     LLVMRunPassManager(pass, Module);
    291     LLVMDisposePassManager(pass);
    292   }
    293 
    294   void buildAndRunOptPasses() {
    295     LLVMPassManagerBuilderRef passBuilder;
    296 
    297     passBuilder = LLVMPassManagerBuilderCreate();
    298     LLVMPassManagerBuilderSetOptLevel(passBuilder, 2);
    299     LLVMPassManagerBuilderSetSizeLevel(passBuilder, 0);
    300 
    301     LLVMPassManagerRef functionPasses =
    302       LLVMCreateFunctionPassManagerForModule(Module);
    303     LLVMPassManagerRef modulePasses =
    304       LLVMCreatePassManager();
    305 
    306     LLVMAddTargetData(LLVMGetExecutionEngineTargetData(Engine), modulePasses);
    307 
    308     LLVMPassManagerBuilderPopulateFunctionPassManager(passBuilder,
    309                                                       functionPasses);
    310     LLVMPassManagerBuilderPopulateModulePassManager(passBuilder, modulePasses);
    311 
    312     LLVMPassManagerBuilderDispose(passBuilder);
    313 
    314     LLVMInitializeFunctionPassManager(functionPasses);
    315     for (LLVMValueRef value = LLVMGetFirstFunction(Module);
    316          value; value = LLVMGetNextFunction(value))
    317       LLVMRunFunctionPassManager(functionPasses, value);
    318     LLVMFinalizeFunctionPassManager(functionPasses);
    319 
    320     LLVMRunPassManager(modulePasses, Module);
    321 
    322     LLVMDisposePassManager(functionPasses);
    323     LLVMDisposePassManager(modulePasses);
    324   }
    325 
    326   LLVMModuleRef Module;
    327   LLVMValueRef Function;
    328   LLVMValueRef Function2;
    329   LLVMMCJITCompilerOptions Options;
    330   LLVMExecutionEngineRef Engine;
    331   char *Error;
    332 };
    333 } // end anonymous namespace
    334 
    335 TEST_F(MCJITCAPITest, simple_function) {
    336   SKIP_UNSUPPORTED_PLATFORM;
    337 
    338   buildSimpleFunction();
    339   buildMCJITOptions();
    340   buildMCJITEngine();
    341   buildAndRunPasses();
    342 
    343   union {
    344     void *raw;
    345     int (*usable)();
    346   } functionPointer;
    347   functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function);
    348 
    349   EXPECT_EQ(42, functionPointer.usable());
    350 }
    351 
    352 TEST_F(MCJITCAPITest, custom_memory_manager) {
    353   SKIP_UNSUPPORTED_PLATFORM;
    354 
    355   buildSimpleFunction();
    356   buildMCJITOptions();
    357   useRoundTripSectionMemoryManager();
    358   buildMCJITEngine();
    359   buildAndRunPasses();
    360 
    361   union {
    362     void *raw;
    363     int (*usable)();
    364   } functionPointer;
    365   functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function);
    366 
    367   EXPECT_EQ(42, functionPointer.usable());
    368   EXPECT_TRUE(didCallAllocateCodeSection);
    369 }
    370 
    371 TEST_F(MCJITCAPITest, stackmap_creates_compact_unwind_on_darwin) {
    372   SKIP_UNSUPPORTED_PLATFORM;
    373 
    374   // This test is also not supported on non-x86 platforms.
    375   if (Triple(HostTriple).getArch() != Triple::x86_64)
    376     return;
    377 
    378   buildFunctionThatUsesStackmap();
    379   buildMCJITOptions();
    380   useRoundTripSectionMemoryManager();
    381   buildMCJITEngine();
    382   buildAndRunOptPasses();
    383 
    384   union {
    385     void *raw;
    386     int (*usable)();
    387   } functionPointer;
    388   functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function);
    389 
    390   EXPECT_EQ(42, functionPointer.usable());
    391   EXPECT_TRUE(didCallAllocateCodeSection);
    392 
    393   // Up to this point, the test is specific only to X86-64. But this next
    394   // expectation is only valid on Darwin because it assumes that unwind
    395   // data is made available only through compact_unwind. It would be
    396   // worthwhile to extend this to handle non-Darwin platforms, in which
    397   // case you'd want to look for an eh_frame or something.
    398   //
    399   // FIXME: Currently, MCJIT relies on a configure-time check to determine which
    400   // sections to emit. The JIT client should have runtime control over this.
    401   EXPECT_TRUE(
    402     Triple(HostTriple).getOS() != Triple::Darwin ||
    403     Triple(HostTriple).isMacOSXVersionLT(10, 7) ||
    404     didAllocateCompactUnwindSection);
    405 }
    406 
    407 TEST_F(MCJITCAPITest, reserve_allocation_space) {
    408   SKIP_UNSUPPORTED_PLATFORM;
    409 
    410   TestReserveAllocationSpaceMemoryManager* MM = new TestReserveAllocationSpaceMemoryManager();
    411 
    412   buildModuleWithCodeAndData();
    413   buildMCJITOptions();
    414   Options.MCJMM = wrap(MM);
    415   buildMCJITEngine();
    416   buildAndRunPasses();
    417 
    418   union {
    419     void *raw;
    420     int (*usable)();
    421   } GetGlobalFct;
    422   GetGlobalFct.raw = LLVMGetPointerToGlobal(Engine, Function);
    423 
    424   union {
    425     void *raw;
    426     void (*usable)(int);
    427   } SetGlobalFct;
    428   SetGlobalFct.raw = LLVMGetPointerToGlobal(Engine, Function2);
    429 
    430   SetGlobalFct.usable(789);
    431   EXPECT_EQ(789, GetGlobalFct.usable());
    432   EXPECT_LE(MM->UsedCodeSize, MM->ReservedCodeSize);
    433   EXPECT_LE(MM->UsedDataSizeRO, MM->ReservedDataSizeRO);
    434   EXPECT_LE(MM->UsedDataSizeRW, MM->ReservedDataSizeRW);
    435   EXPECT_TRUE(MM->UsedCodeSize > 0);
    436   EXPECT_TRUE(MM->UsedDataSizeRW > 0);
    437 }
    438 
    439 TEST_F(MCJITCAPITest, yield) {
    440   SKIP_UNSUPPORTED_PLATFORM;
    441 
    442   buildSimpleFunction();
    443   buildMCJITOptions();
    444   buildMCJITEngine();
    445   LLVMContextRef C = LLVMGetGlobalContext();
    446   LLVMContextSetYieldCallback(C, yield, nullptr);
    447   buildAndRunPasses();
    448 
    449   union {
    450     void *raw;
    451     int (*usable)();
    452   } functionPointer;
    453   functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function);
    454 
    455   EXPECT_EQ(42, functionPointer.usable());
    456   EXPECT_TRUE(didCallYield);
    457 }
    458 
    459