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/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"
29 static bool didCallAllocateCodeSection;
30 static bool didAllocateCompactUnwindSection;
32 static uint8_t *roundTripAllocateCodeSection(void *object, uintptr_t size,
35 const char *sectionName) {
36 didCallAllocateCodeSection = true;
37 return static_cast<SectionMemoryManager*>(object)->allocateCodeSection(
38 size, alignment, sectionID, sectionName);
41 static uint8_t *roundTripAllocateDataSection(void *object, uintptr_t size,
44 const char *sectionName,
45 LLVMBool isReadOnly) {
46 if (!strcmp(sectionName, "__compact_unwind"))
47 didAllocateCompactUnwindSection = true;
48 return static_cast<SectionMemoryManager*>(object)->allocateDataSection(
49 size, alignment, sectionID, sectionName, isReadOnly);
52 static LLVMBool roundTripFinalizeMemory(void *object, char **errMsg) {
53 std::string errMsgString;
55 static_cast<SectionMemoryManager*>(object)->finalizeMemory(&errMsgString);
57 *errMsg = LLVMCreateMessage(errMsgString.c_str());
63 static void roundTripDestroy(void *object) {
64 delete static_cast<SectionMemoryManager*>(object);
69 // memory manager to test reserve allocation space callback
70 class TestReserveAllocationSpaceMemoryManager: public SectionMemoryManager {
72 uintptr_t ReservedCodeSize;
73 uintptr_t UsedCodeSize;
74 uintptr_t ReservedDataSizeRO;
75 uintptr_t UsedDataSizeRO;
76 uintptr_t ReservedDataSizeRW;
77 uintptr_t UsedDataSizeRW;
79 TestReserveAllocationSpaceMemoryManager() :
80 ReservedCodeSize(0), UsedCodeSize(0), ReservedDataSizeRO(0),
81 UsedDataSizeRO(0), ReservedDataSizeRW(0), UsedDataSizeRW(0) {
84 virtual bool needsToReserveAllocationSpace() {
88 virtual void reserveAllocationSpace(
89 uintptr_t CodeSize, uintptr_t DataSizeRO, uintptr_t DataSizeRW) {
90 ReservedCodeSize = CodeSize;
91 ReservedDataSizeRO = DataSizeRO;
92 ReservedDataSizeRW = DataSizeRW;
95 void useSpace(uintptr_t* UsedSize, uintptr_t Size, unsigned Alignment) {
96 uintptr_t AlignedSize = (Size + Alignment - 1) / Alignment * Alignment;
97 uintptr_t AlignedBegin = (*UsedSize + Alignment - 1) / Alignment * Alignment;
98 *UsedSize = AlignedBegin + AlignedSize;
101 virtual uint8_t* allocateDataSection(uintptr_t Size, unsigned Alignment,
102 unsigned SectionID, StringRef SectionName, bool IsReadOnly) {
103 useSpace(IsReadOnly ? &UsedDataSizeRO : &UsedDataSizeRW, Size, Alignment);
104 return SectionMemoryManager::allocateDataSection(Size, Alignment,
105 SectionID, SectionName, IsReadOnly);
108 uint8_t* allocateCodeSection(uintptr_t Size, unsigned Alignment,
109 unsigned SectionID, StringRef SectionName) {
110 useSpace(&UsedCodeSize, Size, Alignment);
111 return SectionMemoryManager::allocateCodeSection(Size, Alignment,
112 SectionID, SectionName);
116 class MCJITCAPITest : public testing::Test, public MCJITTestAPICommon {
119 // The architectures below are known to be compatible with MCJIT as they
120 // are copied from test/ExecutionEngine/MCJIT/lit.local.cfg and should be
122 SupportedArchs.push_back(Triple::aarch64);
123 SupportedArchs.push_back(Triple::arm);
124 SupportedArchs.push_back(Triple::mips);
125 SupportedArchs.push_back(Triple::x86);
126 SupportedArchs.push_back(Triple::x86_64);
128 // Some architectures have sub-architectures in which tests will fail, like
129 // ARM. These two vectors will define if they do have sub-archs (to avoid
130 // extra work for those who don't), and if so, if they are listed to work
131 HasSubArchs.push_back(Triple::arm);
132 SupportedSubArchs.push_back("armv6");
133 SupportedSubArchs.push_back("armv7");
135 // The operating systems below are known to be sufficiently incompatible
136 // that they will fail the MCJIT C API tests.
137 UnsupportedOSs.push_back(Triple::Cygwin);
139 UnsupportedEnvironments.push_back(Triple::Cygnus);
142 virtual void SetUp() {
143 didCallAllocateCodeSection = false;
144 didAllocateCompactUnwindSection = false;
151 virtual void TearDown() {
153 LLVMDisposeExecutionEngine(Engine);
155 LLVMDisposeModule(Module);
158 void buildSimpleFunction() {
159 Module = LLVMModuleCreateWithName("simple_module");
161 LLVMSetTarget(Module, HostTriple.c_str());
163 Function = LLVMAddFunction(
164 Module, "simple_function", LLVMFunctionType(LLVMInt32Type(), 0, 0, 0));
165 LLVMSetFunctionCallConv(Function, LLVMCCallConv);
167 LLVMBasicBlockRef entry = LLVMAppendBasicBlock(Function, "entry");
168 LLVMBuilderRef builder = LLVMCreateBuilder();
169 LLVMPositionBuilderAtEnd(builder, entry);
170 LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0));
172 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
173 LLVMDisposeMessage(Error);
175 LLVMDisposeBuilder(builder);
178 void buildFunctionThatUsesStackmap() {
179 Module = LLVMModuleCreateWithName("simple_module");
181 LLVMSetTarget(Module, HostTriple.c_str());
183 LLVMTypeRef stackmapParamTypes[] = { LLVMInt64Type(), LLVMInt32Type() };
184 LLVMValueRef stackmap = LLVMAddFunction(
185 Module, "llvm.experimental.stackmap",
186 LLVMFunctionType(LLVMVoidType(), stackmapParamTypes, 2, 1));
187 LLVMSetLinkage(stackmap, LLVMExternalLinkage);
189 Function = LLVMAddFunction(
190 Module, "simple_function", LLVMFunctionType(LLVMInt32Type(), 0, 0, 0));
192 LLVMBasicBlockRef entry = LLVMAppendBasicBlock(Function, "entry");
193 LLVMBuilderRef builder = LLVMCreateBuilder();
194 LLVMPositionBuilderAtEnd(builder, entry);
195 LLVMValueRef stackmapArgs[] = {
196 LLVMConstInt(LLVMInt64Type(), 0, 0), LLVMConstInt(LLVMInt32Type(), 5, 0),
197 LLVMConstInt(LLVMInt32Type(), 42, 0)
199 LLVMBuildCall(builder, stackmap, stackmapArgs, 3, "");
200 LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0));
202 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
203 LLVMDisposeMessage(Error);
205 LLVMDisposeBuilder(builder);
208 void buildModuleWithCodeAndData() {
209 Module = LLVMModuleCreateWithName("simple_module");
211 LLVMSetTarget(Module, HostTriple.c_str());
213 // build a global int32 variable initialized to 42.
214 LLVMValueRef GlobalVar = LLVMAddGlobal(Module, LLVMInt32Type(), "intVal");
215 LLVMSetInitializer(GlobalVar, LLVMConstInt(LLVMInt32Type(), 42, 0));
218 Function = LLVMAddFunction(
219 Module, "getGlobal", LLVMFunctionType(LLVMInt32Type(), 0, 0, 0));
220 LLVMSetFunctionCallConv(Function, LLVMCCallConv);
222 LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function, "entry");
223 LLVMBuilderRef Builder = LLVMCreateBuilder();
224 LLVMPositionBuilderAtEnd(Builder, Entry);
226 LLVMValueRef IntVal = LLVMBuildLoad(Builder, GlobalVar, "intVal");
227 LLVMBuildRet(Builder, IntVal);
229 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
230 LLVMDisposeMessage(Error);
232 LLVMDisposeBuilder(Builder);
236 LLVMTypeRef ParamTypes[] = { LLVMInt32Type() };
237 Function2 = LLVMAddFunction(
238 Module, "setGlobal", LLVMFunctionType(LLVMVoidType(), ParamTypes, 1, 0));
239 LLVMSetFunctionCallConv(Function2, LLVMCCallConv);
241 LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function2, "entry");
242 LLVMBuilderRef Builder = LLVMCreateBuilder();
243 LLVMPositionBuilderAtEnd(Builder, Entry);
245 LLVMValueRef Arg = LLVMGetParam(Function2, 0);
246 LLVMBuildStore(Builder, Arg, GlobalVar);
247 LLVMBuildRetVoid(Builder);
249 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
250 LLVMDisposeMessage(Error);
252 LLVMDisposeBuilder(Builder);
256 void buildMCJITOptions() {
257 LLVMInitializeMCJITCompilerOptions(&Options, sizeof(Options));
258 Options.OptLevel = 2;
260 // Just ensure that this field still exists.
261 Options.NoFramePointerElim = false;
264 void useRoundTripSectionMemoryManager() {
265 Options.MCJMM = LLVMCreateSimpleMCJITMemoryManager(
266 new SectionMemoryManager(),
267 roundTripAllocateCodeSection,
268 roundTripAllocateDataSection,
269 roundTripFinalizeMemory,
273 void buildMCJITEngine() {
275 0, LLVMCreateMCJITCompilerForModule(&Engine, Module, &Options,
276 sizeof(Options), &Error));
279 void buildAndRunPasses() {
280 LLVMPassManagerRef pass = LLVMCreatePassManager();
281 LLVMAddTargetData(LLVMGetExecutionEngineTargetData(Engine), pass);
282 LLVMAddConstantPropagationPass(pass);
283 LLVMAddInstructionCombiningPass(pass);
284 LLVMRunPassManager(pass, Module);
285 LLVMDisposePassManager(pass);
288 void buildAndRunOptPasses() {
289 LLVMPassManagerBuilderRef passBuilder;
291 passBuilder = LLVMPassManagerBuilderCreate();
292 LLVMPassManagerBuilderSetOptLevel(passBuilder, 2);
293 LLVMPassManagerBuilderSetSizeLevel(passBuilder, 0);
295 LLVMPassManagerRef functionPasses =
296 LLVMCreateFunctionPassManagerForModule(Module);
297 LLVMPassManagerRef modulePasses =
298 LLVMCreatePassManager();
300 LLVMAddTargetData(LLVMGetExecutionEngineTargetData(Engine), modulePasses);
302 LLVMPassManagerBuilderPopulateFunctionPassManager(passBuilder,
304 LLVMPassManagerBuilderPopulateModulePassManager(passBuilder, modulePasses);
306 LLVMPassManagerBuilderDispose(passBuilder);
308 LLVMInitializeFunctionPassManager(functionPasses);
309 for (LLVMValueRef value = LLVMGetFirstFunction(Module);
310 value; value = LLVMGetNextFunction(value))
311 LLVMRunFunctionPassManager(functionPasses, value);
312 LLVMFinalizeFunctionPassManager(functionPasses);
314 LLVMRunPassManager(modulePasses, Module);
316 LLVMDisposePassManager(functionPasses);
317 LLVMDisposePassManager(modulePasses);
320 LLVMModuleRef Module;
321 LLVMValueRef Function;
322 LLVMValueRef Function2;
323 LLVMMCJITCompilerOptions Options;
324 LLVMExecutionEngineRef Engine;
327 } // end anonymous namespace
329 TEST_F(MCJITCAPITest, simple_function) {
330 SKIP_UNSUPPORTED_PLATFORM;
332 buildSimpleFunction();
341 functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function);
343 EXPECT_EQ(42, functionPointer.usable());
346 TEST_F(MCJITCAPITest, custom_memory_manager) {
347 SKIP_UNSUPPORTED_PLATFORM;
349 buildSimpleFunction();
351 useRoundTripSectionMemoryManager();
359 functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function);
361 EXPECT_EQ(42, functionPointer.usable());
362 EXPECT_TRUE(didCallAllocateCodeSection);
365 TEST_F(MCJITCAPITest, stackmap_creates_compact_unwind_on_darwin) {
366 SKIP_UNSUPPORTED_PLATFORM;
368 // This test is also not supported on non-x86 platforms.
369 if (Triple(HostTriple).getArch() != Triple::x86_64)
372 buildFunctionThatUsesStackmap();
374 useRoundTripSectionMemoryManager();
376 buildAndRunOptPasses();
382 functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function);
384 EXPECT_EQ(42, functionPointer.usable());
385 EXPECT_TRUE(didCallAllocateCodeSection);
387 // Up to this point, the test is specific only to X86-64. But this next
388 // expectation is only valid on Darwin because it assumes that unwind
389 // data is made available only through compact_unwind. It would be
390 // worthwhile to extend this to handle non-Darwin platforms, in which
391 // case you'd want to look for an eh_frame or something.
393 // FIXME: Currently, MCJIT relies on a configure-time check to determine which
394 // sections to emit. The JIT client should have runtime control over this.
396 Triple(HostTriple).getOS() != Triple::Darwin ||
397 Triple(HostTriple).isMacOSXVersionLT(10, 7) ||
398 didAllocateCompactUnwindSection);
401 TEST_F(MCJITCAPITest, reserve_allocation_space) {
402 SKIP_UNSUPPORTED_PLATFORM;
404 TestReserveAllocationSpaceMemoryManager* MM = new TestReserveAllocationSpaceMemoryManager();
406 buildModuleWithCodeAndData();
408 Options.MCJMM = wrap(MM);
416 GetGlobalFct.raw = LLVMGetPointerToGlobal(Engine, Function);
422 SetGlobalFct.raw = LLVMGetPointerToGlobal(Engine, Function2);
424 SetGlobalFct.usable(789);
425 EXPECT_EQ(789, GetGlobalFct.usable());
426 EXPECT_LE(MM->UsedCodeSize, MM->ReservedCodeSize);
427 EXPECT_LE(MM->UsedDataSizeRO, MM->ReservedDataSizeRO);
428 EXPECT_LE(MM->UsedDataSizeRW, MM->ReservedDataSizeRW);
429 EXPECT_TRUE(MM->UsedCodeSize > 0);
430 EXPECT_TRUE(MM->UsedDataSizeRW > 0);