Home | History | Annotate | Download | only in MCJIT
      1 //===- MCJITTest.cpp - Unit tests for the MCJIT -----------------*- C++ -*-===//
      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   bool needsToReserveAllocationSpace() override { return true; }
     90 
     91   void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign,
     92 			      uintptr_t DataSizeRO, uint32_t RODataAlign,
     93                               uintptr_t DataSizeRW, uint32_t RWDataAlign) override {
     94     ReservedCodeSize = CodeSize;
     95     ReservedDataSizeRO = DataSizeRO;
     96     ReservedDataSizeRW = DataSizeRW;
     97   }
     98 
     99   void useSpace(uintptr_t* UsedSize, uintptr_t Size, unsigned Alignment) {
    100     uintptr_t AlignedSize = (Size + Alignment - 1) / Alignment * Alignment;
    101     uintptr_t AlignedBegin = (*UsedSize + Alignment - 1) / Alignment * Alignment;
    102     *UsedSize = AlignedBegin + AlignedSize;
    103   }
    104 
    105   uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
    106                                unsigned SectionID, StringRef SectionName,
    107                                bool IsReadOnly) override {
    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,
    115                                StringRef SectionName) override {
    116     useSpace(&UsedCodeSize, Size, Alignment);
    117     return SectionMemoryManager::allocateCodeSection(Size, Alignment,
    118       SectionID, SectionName);
    119   }
    120 };
    121 
    122 class MCJITCAPITest : public testing::Test, public MCJITTestAPICommon {
    123 protected:
    124   MCJITCAPITest() {
    125     // The architectures below are known to be compatible with MCJIT as they
    126     // are copied from test/ExecutionEngine/MCJIT/lit.local.cfg and should be
    127     // kept in sync.
    128     SupportedArchs.push_back(Triple::aarch64);
    129     SupportedArchs.push_back(Triple::arm);
    130     SupportedArchs.push_back(Triple::mips);
    131     SupportedArchs.push_back(Triple::mips64);
    132     SupportedArchs.push_back(Triple::mips64el);
    133     SupportedArchs.push_back(Triple::x86);
    134     SupportedArchs.push_back(Triple::x86_64);
    135 
    136     // Some architectures have sub-architectures in which tests will fail, like
    137     // ARM. These two vectors will define if they do have sub-archs (to avoid
    138     // extra work for those who don't), and if so, if they are listed to work
    139     HasSubArchs.push_back(Triple::arm);
    140     SupportedSubArchs.push_back("armv6");
    141     SupportedSubArchs.push_back("armv7");
    142 
    143     // The operating systems below are known to be sufficiently incompatible
    144     // that they will fail the MCJIT C API tests.
    145     UnsupportedEnvironments.push_back(Triple::Cygnus);
    146   }
    147 
    148   void SetUp() override {
    149     didCallAllocateCodeSection = false;
    150     didAllocateCompactUnwindSection = false;
    151     didCallYield = false;
    152     Module = nullptr;
    153     Function = nullptr;
    154     Engine = nullptr;
    155     Error = nullptr;
    156   }
    157 
    158   void TearDown() override {
    159     if (Engine)
    160       LLVMDisposeExecutionEngine(Engine);
    161     else if (Module)
    162       LLVMDisposeModule(Module);
    163   }
    164 
    165   void buildSimpleFunction() {
    166     Module = LLVMModuleCreateWithName("simple_module");
    167 
    168     LLVMSetTarget(Module, HostTriple.c_str());
    169 
    170     Function = LLVMAddFunction(Module, "simple_function",
    171                                LLVMFunctionType(LLVMInt32Type(), nullptr,0, 0));
    172     LLVMSetFunctionCallConv(Function, LLVMCCallConv);
    173 
    174     LLVMBasicBlockRef entry = LLVMAppendBasicBlock(Function, "entry");
    175     LLVMBuilderRef builder = LLVMCreateBuilder();
    176     LLVMPositionBuilderAtEnd(builder, entry);
    177     LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0));
    178 
    179     LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
    180     LLVMDisposeMessage(Error);
    181 
    182     LLVMDisposeBuilder(builder);
    183   }
    184 
    185   void buildFunctionThatUsesStackmap() {
    186     Module = LLVMModuleCreateWithName("simple_module");
    187 
    188     LLVMSetTarget(Module, HostTriple.c_str());
    189 
    190     LLVMTypeRef stackmapParamTypes[] = { LLVMInt64Type(), LLVMInt32Type() };
    191     LLVMValueRef stackmap = LLVMAddFunction(
    192       Module, "llvm.experimental.stackmap",
    193       LLVMFunctionType(LLVMVoidType(), stackmapParamTypes, 2, 1));
    194     LLVMSetLinkage(stackmap, LLVMExternalLinkage);
    195 
    196     Function = LLVMAddFunction(Module, "simple_function",
    197                               LLVMFunctionType(LLVMInt32Type(), nullptr, 0, 0));
    198 
    199     LLVMBasicBlockRef entry = LLVMAppendBasicBlock(Function, "entry");
    200     LLVMBuilderRef builder = LLVMCreateBuilder();
    201     LLVMPositionBuilderAtEnd(builder, entry);
    202     LLVMValueRef stackmapArgs[] = {
    203       LLVMConstInt(LLVMInt64Type(), 0, 0), LLVMConstInt(LLVMInt32Type(), 5, 0),
    204       LLVMConstInt(LLVMInt32Type(), 42, 0)
    205     };
    206     LLVMBuildCall(builder, stackmap, stackmapArgs, 3, "");
    207     LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0));
    208 
    209     LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
    210     LLVMDisposeMessage(Error);
    211 
    212     LLVMDisposeBuilder(builder);
    213   }
    214 
    215   void buildModuleWithCodeAndData() {
    216     Module = LLVMModuleCreateWithName("simple_module");
    217 
    218     LLVMSetTarget(Module, HostTriple.c_str());
    219 
    220     // build a global int32 variable initialized to 42.
    221     LLVMValueRef GlobalVar = LLVMAddGlobal(Module, LLVMInt32Type(), "intVal");
    222     LLVMSetInitializer(GlobalVar, LLVMConstInt(LLVMInt32Type(), 42, 0));
    223 
    224     {
    225         Function = LLVMAddFunction(Module, "getGlobal",
    226                               LLVMFunctionType(LLVMInt32Type(), nullptr, 0, 0));
    227         LLVMSetFunctionCallConv(Function, LLVMCCallConv);
    228 
    229         LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function, "entry");
    230         LLVMBuilderRef Builder = LLVMCreateBuilder();
    231         LLVMPositionBuilderAtEnd(Builder, Entry);
    232 
    233         LLVMValueRef IntVal = LLVMBuildLoad(Builder, GlobalVar, "intVal");
    234         LLVMBuildRet(Builder, IntVal);
    235 
    236         LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
    237         LLVMDisposeMessage(Error);
    238 
    239         LLVMDisposeBuilder(Builder);
    240     }
    241 
    242     {
    243         LLVMTypeRef ParamTypes[] = { LLVMInt32Type() };
    244         Function2 = LLVMAddFunction(
    245           Module, "setGlobal", LLVMFunctionType(LLVMVoidType(), ParamTypes, 1, 0));
    246         LLVMSetFunctionCallConv(Function2, LLVMCCallConv);
    247 
    248         LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function2, "entry");
    249         LLVMBuilderRef Builder = LLVMCreateBuilder();
    250         LLVMPositionBuilderAtEnd(Builder, Entry);
    251 
    252         LLVMValueRef Arg = LLVMGetParam(Function2, 0);
    253         LLVMBuildStore(Builder, Arg, GlobalVar);
    254         LLVMBuildRetVoid(Builder);
    255 
    256         LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
    257         LLVMDisposeMessage(Error);
    258 
    259         LLVMDisposeBuilder(Builder);
    260     }
    261   }
    262 
    263   void buildMCJITOptions() {
    264     LLVMInitializeMCJITCompilerOptions(&Options, sizeof(Options));
    265     Options.OptLevel = 2;
    266 
    267     // Just ensure that this field still exists.
    268     Options.NoFramePointerElim = false;
    269   }
    270 
    271   void useRoundTripSectionMemoryManager() {
    272     Options.MCJMM = LLVMCreateSimpleMCJITMemoryManager(
    273       new SectionMemoryManager(),
    274       roundTripAllocateCodeSection,
    275       roundTripAllocateDataSection,
    276       roundTripFinalizeMemory,
    277       roundTripDestroy);
    278   }
    279 
    280   void buildMCJITEngine() {
    281     ASSERT_EQ(
    282       0, LLVMCreateMCJITCompilerForModule(&Engine, Module, &Options,
    283                                           sizeof(Options), &Error));
    284   }
    285 
    286   void buildAndRunPasses() {
    287     LLVMPassManagerRef pass = LLVMCreatePassManager();
    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     LLVMPassManagerBuilderPopulateFunctionPassManager(passBuilder,
    307                                                       functionPasses);
    308     LLVMPassManagerBuilderPopulateModulePassManager(passBuilder, modulePasses);
    309 
    310     LLVMPassManagerBuilderDispose(passBuilder);
    311 
    312     LLVMInitializeFunctionPassManager(functionPasses);
    313     for (LLVMValueRef value = LLVMGetFirstFunction(Module);
    314          value; value = LLVMGetNextFunction(value))
    315       LLVMRunFunctionPassManager(functionPasses, value);
    316     LLVMFinalizeFunctionPassManager(functionPasses);
    317 
    318     LLVMRunPassManager(modulePasses, Module);
    319 
    320     LLVMDisposePassManager(functionPasses);
    321     LLVMDisposePassManager(modulePasses);
    322   }
    323 
    324   LLVMModuleRef Module;
    325   LLVMValueRef Function;
    326   LLVMValueRef Function2;
    327   LLVMMCJITCompilerOptions Options;
    328   LLVMExecutionEngineRef Engine;
    329   char *Error;
    330 };
    331 } // end anonymous namespace
    332 
    333 TEST_F(MCJITCAPITest, simple_function) {
    334   SKIP_UNSUPPORTED_PLATFORM;
    335 
    336   buildSimpleFunction();
    337   buildMCJITOptions();
    338   buildMCJITEngine();
    339   buildAndRunPasses();
    340 
    341   auto *functionPointer = reinterpret_cast<int (*)()>(
    342       reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine, Function)));
    343 
    344   EXPECT_EQ(42, functionPointer());
    345 }
    346 
    347 TEST_F(MCJITCAPITest, gva) {
    348   SKIP_UNSUPPORTED_PLATFORM;
    349 
    350   Module = LLVMModuleCreateWithName("simple_module");
    351   LLVMSetTarget(Module, HostTriple.c_str());
    352   LLVMValueRef GlobalVar = LLVMAddGlobal(Module, LLVMInt32Type(), "simple_value");
    353   LLVMSetInitializer(GlobalVar, LLVMConstInt(LLVMInt32Type(), 42, 0));
    354 
    355   buildMCJITOptions();
    356   buildMCJITEngine();
    357   buildAndRunPasses();
    358 
    359   uint64_t raw = LLVMGetGlobalValueAddress(Engine, "simple_value");
    360   int32_t *usable  = (int32_t *) raw;
    361 
    362   EXPECT_EQ(42, *usable);
    363 }
    364 
    365 TEST_F(MCJITCAPITest, gfa) {
    366   SKIP_UNSUPPORTED_PLATFORM;
    367 
    368   buildSimpleFunction();
    369   buildMCJITOptions();
    370   buildMCJITEngine();
    371   buildAndRunPasses();
    372 
    373   uint64_t raw = LLVMGetFunctionAddress(Engine, "simple_function");
    374   int (*usable)() = (int (*)()) raw;
    375 
    376   EXPECT_EQ(42, usable());
    377 }
    378 
    379 TEST_F(MCJITCAPITest, custom_memory_manager) {
    380   SKIP_UNSUPPORTED_PLATFORM;
    381 
    382   buildSimpleFunction();
    383   buildMCJITOptions();
    384   useRoundTripSectionMemoryManager();
    385   buildMCJITEngine();
    386   buildAndRunPasses();
    387 
    388   auto *functionPointer = reinterpret_cast<int (*)()>(
    389       reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine, Function)));
    390 
    391   EXPECT_EQ(42, functionPointer());
    392   EXPECT_TRUE(didCallAllocateCodeSection);
    393 }
    394 
    395 TEST_F(MCJITCAPITest, stackmap_creates_compact_unwind_on_darwin) {
    396   SKIP_UNSUPPORTED_PLATFORM;
    397 
    398   // This test is also not supported on non-x86 platforms.
    399   if (Triple(HostTriple).getArch() != Triple::x86_64)
    400     return;
    401 
    402   buildFunctionThatUsesStackmap();
    403   buildMCJITOptions();
    404   useRoundTripSectionMemoryManager();
    405   buildMCJITEngine();
    406   buildAndRunOptPasses();
    407 
    408   auto *functionPointer = reinterpret_cast<int (*)()>(
    409       reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine, Function)));
    410 
    411   EXPECT_EQ(42, functionPointer());
    412   EXPECT_TRUE(didCallAllocateCodeSection);
    413 
    414   // Up to this point, the test is specific only to X86-64. But this next
    415   // expectation is only valid on Darwin because it assumes that unwind
    416   // data is made available only through compact_unwind. It would be
    417   // worthwhile to extend this to handle non-Darwin platforms, in which
    418   // case you'd want to look for an eh_frame or something.
    419   //
    420   // FIXME: Currently, MCJIT relies on a configure-time check to determine which
    421   // sections to emit. The JIT client should have runtime control over this.
    422   EXPECT_TRUE(
    423     Triple(HostTriple).getOS() != Triple::Darwin ||
    424     Triple(HostTriple).isMacOSXVersionLT(10, 7) ||
    425     didAllocateCompactUnwindSection);
    426 }
    427 
    428 TEST_F(MCJITCAPITest, reserve_allocation_space) {
    429   SKIP_UNSUPPORTED_PLATFORM;
    430 
    431   TestReserveAllocationSpaceMemoryManager* MM = new TestReserveAllocationSpaceMemoryManager();
    432 
    433   buildModuleWithCodeAndData();
    434   buildMCJITOptions();
    435   Options.MCJMM = wrap(MM);
    436   buildMCJITEngine();
    437   buildAndRunPasses();
    438 
    439   auto GetGlobalFct = reinterpret_cast<int (*)()>(
    440       reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine, Function)));
    441 
    442   auto SetGlobalFct = reinterpret_cast<void (*)(int)>(
    443       reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine, Function2)));
    444 
    445   SetGlobalFct(789);
    446   EXPECT_EQ(789, GetGlobalFct());
    447   EXPECT_LE(MM->UsedCodeSize, MM->ReservedCodeSize);
    448   EXPECT_LE(MM->UsedDataSizeRO, MM->ReservedDataSizeRO);
    449   EXPECT_LE(MM->UsedDataSizeRW, MM->ReservedDataSizeRW);
    450   EXPECT_TRUE(MM->UsedCodeSize > 0);
    451   EXPECT_TRUE(MM->UsedDataSizeRW > 0);
    452 }
    453 
    454 TEST_F(MCJITCAPITest, yield) {
    455   SKIP_UNSUPPORTED_PLATFORM;
    456 
    457   buildSimpleFunction();
    458   buildMCJITOptions();
    459   buildMCJITEngine();
    460   LLVMContextRef C = LLVMGetGlobalContext();
    461   LLVMContextSetYieldCallback(C, yield, nullptr);
    462   buildAndRunPasses();
    463 
    464   auto *functionPointer = reinterpret_cast<int (*)()>(
    465       reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine, Function)));
    466 
    467   EXPECT_EQ(42, functionPointer());
    468   EXPECT_TRUE(didCallYield);
    469 }
    470 
    471 static int localTestFunc() {
    472   return 42;
    473 }
    474 
    475 TEST_F(MCJITCAPITest, addGlobalMapping) {
    476   SKIP_UNSUPPORTED_PLATFORM;
    477 
    478   Module = LLVMModuleCreateWithName("testModule");
    479   LLVMSetTarget(Module, HostTriple.c_str());
    480   LLVMTypeRef FunctionType = LLVMFunctionType(LLVMInt32Type(), nullptr, 0, 0);
    481   LLVMValueRef MappedFn = LLVMAddFunction(Module, "mapped_fn", FunctionType);
    482 
    483   Function = LLVMAddFunction(Module, "test_fn", FunctionType);
    484   LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function, "");
    485   LLVMBuilderRef Builder = LLVMCreateBuilder();
    486   LLVMPositionBuilderAtEnd(Builder, Entry);
    487   LLVMValueRef RetVal = LLVMBuildCall(Builder, MappedFn, nullptr, 0, "");
    488   LLVMBuildRet(Builder, RetVal);
    489   LLVMDisposeBuilder(Builder);
    490 
    491   LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
    492   LLVMDisposeMessage(Error);
    493 
    494   buildMCJITOptions();
    495   buildMCJITEngine();
    496 
    497   LLVMAddGlobalMapping(
    498       Engine, MappedFn,
    499       reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(&localTestFunc)));
    500 
    501   buildAndRunPasses();
    502 
    503   uint64_t raw = LLVMGetFunctionAddress(Engine, "test_fn");
    504   int (*usable)() = (int (*)()) raw;
    505 
    506   EXPECT_EQ(42, usable());
    507 }
    508