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