1 //===- MCJITTest.cpp - Unit tests for the MCJIT ---------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This test suite verifies basic MCJIT functionality when invoked form the C
13 //===----------------------------------------------------------------------===//
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/Scalar.h"
21 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
22 #include "llvm/Support/Host.h"
23 #include "gtest/gtest.h"
24 #include "llvm/Support/Debug.h"
28 static bool didCallAllocateCodeSection;
30 static uint8_t *roundTripAllocateCodeSection(void *object, uintptr_t size,
33 const char *sectionName) {
34 didCallAllocateCodeSection = true;
35 return static_cast<SectionMemoryManager*>(object)->allocateCodeSection(
36 size, alignment, sectionID, sectionName);
39 static uint8_t *roundTripAllocateDataSection(void *object, uintptr_t size,
42 const char *sectionName,
43 LLVMBool isReadOnly) {
44 return static_cast<SectionMemoryManager*>(object)->allocateDataSection(
45 size, alignment, sectionID, sectionName, isReadOnly);
48 static LLVMBool roundTripFinalizeMemory(void *object, char **errMsg) {
49 std::string errMsgString;
51 static_cast<SectionMemoryManager*>(object)->finalizeMemory(&errMsgString);
53 *errMsg = LLVMCreateMessage(errMsgString.c_str());
59 static void roundTripDestroy(void *object) {
60 delete static_cast<SectionMemoryManager*>(object);
65 // memory manager to test reserve allocation space callback
66 class TestReserveAllocationSpaceMemoryManager: public SectionMemoryManager {
68 uintptr_t ReservedCodeSize;
69 uintptr_t UsedCodeSize;
70 uintptr_t ReservedDataSizeRO;
71 uintptr_t UsedDataSizeRO;
72 uintptr_t ReservedDataSizeRW;
73 uintptr_t UsedDataSizeRW;
75 TestReserveAllocationSpaceMemoryManager() :
76 ReservedCodeSize(0), UsedCodeSize(0), ReservedDataSizeRO(0),
77 UsedDataSizeRO(0), ReservedDataSizeRW(0), UsedDataSizeRW(0) {
80 virtual bool needsToReserveAllocationSpace() {
84 virtual void reserveAllocationSpace(
85 uintptr_t CodeSize, uintptr_t DataSizeRO, uintptr_t DataSizeRW) {
86 ReservedCodeSize = CodeSize;
87 ReservedDataSizeRO = DataSizeRO;
88 ReservedDataSizeRW = DataSizeRW;
91 void useSpace(uintptr_t* UsedSize, uintptr_t Size, unsigned Alignment) {
92 uintptr_t AlignedSize = (Size + Alignment - 1) / Alignment * Alignment;
93 uintptr_t AlignedBegin = (*UsedSize + Alignment - 1) / Alignment * Alignment;
94 *UsedSize = AlignedBegin + AlignedSize;
97 virtual uint8_t* allocateDataSection(uintptr_t Size, unsigned Alignment,
98 unsigned SectionID, StringRef SectionName, bool IsReadOnly) {
99 useSpace(IsReadOnly ? &UsedDataSizeRO : &UsedDataSizeRW, Size, Alignment);
100 return SectionMemoryManager::allocateDataSection(Size, Alignment,
101 SectionID, SectionName, IsReadOnly);
104 uint8_t* allocateCodeSection(uintptr_t Size, unsigned Alignment,
105 unsigned SectionID, StringRef SectionName) {
106 useSpace(&UsedCodeSize, Size, Alignment);
107 return SectionMemoryManager::allocateCodeSection(Size, Alignment,
108 SectionID, SectionName);
112 class MCJITCAPITest : public testing::Test, public MCJITTestAPICommon {
115 // The architectures below are known to be compatible with MCJIT as they
116 // are copied from test/ExecutionEngine/MCJIT/lit.local.cfg and should be
118 SupportedArchs.push_back(Triple::aarch64);
119 SupportedArchs.push_back(Triple::arm);
120 SupportedArchs.push_back(Triple::mips);
121 SupportedArchs.push_back(Triple::x86);
122 SupportedArchs.push_back(Triple::x86_64);
124 // Some architectures have sub-architectures in which tests will fail, like
125 // ARM. These two vectors will define if they do have sub-archs (to avoid
126 // extra work for those who don't), and if so, if they are listed to work
127 HasSubArchs.push_back(Triple::arm);
128 SupportedSubArchs.push_back("armv6");
129 SupportedSubArchs.push_back("armv7");
131 // The operating systems below are known to be sufficiently incompatible
132 // that they will fail the MCJIT C API tests.
133 UnsupportedOSs.push_back(Triple::Cygwin);
136 virtual void SetUp() {
137 didCallAllocateCodeSection = false;
144 virtual void TearDown() {
146 LLVMDisposeExecutionEngine(Engine);
148 LLVMDisposeModule(Module);
151 void buildSimpleFunction() {
152 Module = LLVMModuleCreateWithName("simple_module");
154 LLVMSetTarget(Module, HostTriple.c_str());
156 Function = LLVMAddFunction(
157 Module, "simple_function", LLVMFunctionType(LLVMInt32Type(), 0, 0, 0));
158 LLVMSetFunctionCallConv(Function, LLVMCCallConv);
160 LLVMBasicBlockRef entry = LLVMAppendBasicBlock(Function, "entry");
161 LLVMBuilderRef builder = LLVMCreateBuilder();
162 LLVMPositionBuilderAtEnd(builder, entry);
163 LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0));
165 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
166 LLVMDisposeMessage(Error);
168 LLVMDisposeBuilder(builder);
171 void buildModuleWithCodeAndData() {
172 Module = LLVMModuleCreateWithName("simple_module");
174 LLVMSetTarget(Module, HostTriple.c_str());
176 // build a global variable initialized to "Hello World!"
177 LLVMValueRef GlobalVar = LLVMAddGlobal(Module, LLVMInt32Type(), "intVal");
178 LLVMSetInitializer(GlobalVar, LLVMConstInt(LLVMInt32Type(), 42, 0));
181 Function = LLVMAddFunction(
182 Module, "getGlobal", LLVMFunctionType(LLVMInt32Type(), 0, 0, 0));
183 LLVMSetFunctionCallConv(Function, LLVMCCallConv);
185 LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function, "entry");
186 LLVMBuilderRef Builder = LLVMCreateBuilder();
187 LLVMPositionBuilderAtEnd(Builder, Entry);
189 LLVMValueRef IntVal = LLVMBuildLoad(Builder, GlobalVar, "intVal");
190 LLVMBuildRet(Builder, IntVal);
192 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
193 LLVMDisposeMessage(Error);
195 LLVMDisposeBuilder(Builder);
199 LLVMTypeRef ParamTypes[] = { LLVMInt32Type() };
200 Function2 = LLVMAddFunction(
201 Module, "setGlobal", LLVMFunctionType(LLVMVoidType(), ParamTypes, 1, 0));
202 LLVMSetFunctionCallConv(Function2, LLVMCCallConv);
204 LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function2, "entry");
205 LLVMBuilderRef Builder = LLVMCreateBuilder();
206 LLVMPositionBuilderAtEnd(Builder, Entry);
208 LLVMValueRef Arg = LLVMGetParam(Function2, 0);
209 LLVMBuildStore(Builder, Arg, GlobalVar);
210 LLVMBuildRetVoid(Builder);
212 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
213 LLVMDisposeMessage(Error);
215 LLVMDisposeBuilder(Builder);
219 void buildMCJITOptions() {
220 LLVMInitializeMCJITCompilerOptions(&Options, sizeof(Options));
221 Options.OptLevel = 2;
223 // Just ensure that this field still exists.
224 Options.NoFramePointerElim = false;
227 void useRoundTripSectionMemoryManager() {
228 Options.MCJMM = LLVMCreateSimpleMCJITMemoryManager(
229 new SectionMemoryManager(),
230 roundTripAllocateCodeSection,
231 roundTripAllocateDataSection,
232 roundTripFinalizeMemory,
236 void buildMCJITEngine() {
238 0, LLVMCreateMCJITCompilerForModule(&Engine, Module, &Options,
239 sizeof(Options), &Error));
242 void buildAndRunPasses() {
243 LLVMPassManagerRef pass = LLVMCreatePassManager();
244 LLVMAddTargetData(LLVMGetExecutionEngineTargetData(Engine), pass);
245 LLVMAddConstantPropagationPass(pass);
246 LLVMAddInstructionCombiningPass(pass);
247 LLVMRunPassManager(pass, Module);
248 LLVMDisposePassManager(pass);
251 LLVMModuleRef Module;
252 LLVMValueRef Function;
253 LLVMValueRef Function2;
254 LLVMMCJITCompilerOptions Options;
255 LLVMExecutionEngineRef Engine;
258 } // end anonymous namespace
260 TEST_F(MCJITCAPITest, simple_function) {
261 SKIP_UNSUPPORTED_PLATFORM;
263 buildSimpleFunction();
272 functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function);
274 EXPECT_EQ(42, functionPointer.usable());
277 TEST_F(MCJITCAPITest, custom_memory_manager) {
278 SKIP_UNSUPPORTED_PLATFORM;
280 buildSimpleFunction();
282 useRoundTripSectionMemoryManager();
290 functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function);
292 EXPECT_EQ(42, functionPointer.usable());
293 EXPECT_TRUE(didCallAllocateCodeSection);
296 TEST_F(MCJITCAPITest, reserve_allocation_space) {
297 SKIP_UNSUPPORTED_PLATFORM;
299 TestReserveAllocationSpaceMemoryManager* MM = new TestReserveAllocationSpaceMemoryManager();
301 buildModuleWithCodeAndData();
303 Options.MCJMM = wrap(MM);
311 GetGlobalFct.raw = LLVMGetPointerToGlobal(Engine, Function);
317 SetGlobalFct.raw = LLVMGetPointerToGlobal(Engine, Function2);
319 SetGlobalFct.usable(789);
320 EXPECT_EQ(789, GetGlobalFct.usable());
321 EXPECT_LE(MM->UsedCodeSize, MM->ReservedCodeSize);
322 EXPECT_LE(MM->UsedDataSizeRO, MM->ReservedDataSizeRO);
323 EXPECT_LE(MM->UsedDataSizeRW, MM->ReservedDataSizeRW);
324 EXPECT_TRUE(MM->UsedCodeSize > 0);
325 EXPECT_TRUE(MM->UsedDataSizeRO >= 0);
326 EXPECT_TRUE(MM->UsedDataSizeRW > 0);