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 "llvm-c/Core.h" 17 #include "llvm-c/ExecutionEngine.h" 18 #include "llvm-c/Target.h" 19 #include "llvm-c/Transforms/Scalar.h" 20 #include "llvm/ExecutionEngine/SectionMemoryManager.h" 21 #include "llvm/Support/Host.h" 22 #include "MCJITTestAPICommon.h" 23 #include "gtest/gtest.h" 24 25 using namespace llvm; 26 27 static bool didCallAllocateCodeSection; 28 29 static uint8_t *roundTripAllocateCodeSection(void *object, uintptr_t size, 30 unsigned alignment, 31 unsigned sectionID) { 32 didCallAllocateCodeSection = true; 33 return static_cast<SectionMemoryManager*>(object)->allocateCodeSection( 34 size, alignment, sectionID); 35 } 36 37 static uint8_t *roundTripAllocateDataSection(void *object, uintptr_t size, 38 unsigned alignment, 39 unsigned sectionID, 40 LLVMBool isReadOnly) { 41 return static_cast<SectionMemoryManager*>(object)->allocateDataSection( 42 size, alignment, sectionID, isReadOnly); 43 } 44 45 static LLVMBool roundTripFinalizeMemory(void *object, char **errMsg) { 46 std::string errMsgString; 47 bool result = 48 static_cast<SectionMemoryManager*>(object)->finalizeMemory(&errMsgString); 49 if (result) { 50 *errMsg = LLVMCreateMessage(errMsgString.c_str()); 51 return 1; 52 } 53 return 0; 54 } 55 56 static void roundTripDestroy(void *object) { 57 delete static_cast<SectionMemoryManager*>(object); 58 } 59 60 class MCJITCAPITest : public testing::Test, public MCJITTestAPICommon { 61 protected: 62 MCJITCAPITest() { 63 // The architectures below are known to be compatible with MCJIT as they 64 // are copied from test/ExecutionEngine/MCJIT/lit.local.cfg and should be 65 // kept in sync. 66 SupportedArchs.push_back(Triple::aarch64); 67 SupportedArchs.push_back(Triple::arm); 68 SupportedArchs.push_back(Triple::mips); 69 SupportedArchs.push_back(Triple::x86); 70 SupportedArchs.push_back(Triple::x86_64); 71 72 // Some architectures have sub-architectures in which tests will fail, like 73 // ARM. These two vectors will define if they do have sub-archs (to avoid 74 // extra work for those who don't), and if so, if they are listed to work 75 HasSubArchs.push_back(Triple::arm); 76 SupportedSubArchs.push_back("armv6"); 77 SupportedSubArchs.push_back("armv7"); 78 79 // The operating systems below are known to be sufficiently incompatible 80 // that they will fail the MCJIT C API tests. 81 UnsupportedOSs.push_back(Triple::Cygwin); 82 } 83 84 virtual void SetUp() { 85 didCallAllocateCodeSection = false; 86 Module = 0; 87 Function = 0; 88 Engine = 0; 89 Error = 0; 90 } 91 92 virtual void TearDown() { 93 if (Engine) 94 LLVMDisposeExecutionEngine(Engine); 95 else if (Module) 96 LLVMDisposeModule(Module); 97 } 98 99 void buildSimpleFunction() { 100 Module = LLVMModuleCreateWithName("simple_module"); 101 102 LLVMSetTarget(Module, HostTriple.c_str()); 103 104 Function = LLVMAddFunction( 105 Module, "simple_function", LLVMFunctionType(LLVMInt32Type(), 0, 0, 0)); 106 LLVMSetFunctionCallConv(Function, LLVMCCallConv); 107 108 LLVMBasicBlockRef entry = LLVMAppendBasicBlock(Function, "entry"); 109 LLVMBuilderRef builder = LLVMCreateBuilder(); 110 LLVMPositionBuilderAtEnd(builder, entry); 111 LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0)); 112 113 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error); 114 LLVMDisposeMessage(Error); 115 116 LLVMDisposeBuilder(builder); 117 } 118 119 void buildMCJITOptions() { 120 LLVMInitializeMCJITCompilerOptions(&Options, sizeof(Options)); 121 Options.OptLevel = 2; 122 123 // Just ensure that this field still exists. 124 Options.NoFramePointerElim = false; 125 } 126 127 void useRoundTripSectionMemoryManager() { 128 Options.MCJMM = LLVMCreateSimpleMCJITMemoryManager( 129 new SectionMemoryManager(), 130 roundTripAllocateCodeSection, 131 roundTripAllocateDataSection, 132 roundTripFinalizeMemory, 133 roundTripDestroy); 134 } 135 136 void buildMCJITEngine() { 137 ASSERT_EQ( 138 0, LLVMCreateMCJITCompilerForModule(&Engine, Module, &Options, 139 sizeof(Options), &Error)); 140 } 141 142 void buildAndRunPasses() { 143 LLVMPassManagerRef pass = LLVMCreatePassManager(); 144 LLVMAddTargetData(LLVMGetExecutionEngineTargetData(Engine), pass); 145 LLVMAddConstantPropagationPass(pass); 146 LLVMAddInstructionCombiningPass(pass); 147 LLVMRunPassManager(pass, Module); 148 LLVMDisposePassManager(pass); 149 } 150 151 LLVMModuleRef Module; 152 LLVMValueRef Function; 153 LLVMMCJITCompilerOptions Options; 154 LLVMExecutionEngineRef Engine; 155 char *Error; 156 }; 157 158 TEST_F(MCJITCAPITest, simple_function) { 159 SKIP_UNSUPPORTED_PLATFORM; 160 161 buildSimpleFunction(); 162 buildMCJITOptions(); 163 buildMCJITEngine(); 164 buildAndRunPasses(); 165 166 union { 167 void *raw; 168 int (*usable)(); 169 } functionPointer; 170 functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function); 171 172 EXPECT_EQ(42, functionPointer.usable()); 173 } 174 175 TEST_F(MCJITCAPITest, custom_memory_manager) { 176 SKIP_UNSUPPORTED_PLATFORM; 177 178 buildSimpleFunction(); 179 buildMCJITOptions(); 180 useRoundTripSectionMemoryManager(); 181 buildMCJITEngine(); 182 buildAndRunPasses(); 183 184 union { 185 void *raw; 186 int (*usable)(); 187 } functionPointer; 188 functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function); 189 190 EXPECT_EQ(42, functionPointer.usable()); 191 EXPECT_TRUE(didCallAllocateCodeSection); 192 } 193