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;
31 static bool didCallPassRunListener;
33 static uint8_t *roundTripAllocateCodeSection(void *object, uintptr_t size,
36 const char *sectionName) {
37 didCallAllocateCodeSection = true;
38 return static_cast<SectionMemoryManager*>(object)->allocateCodeSection(
39 size, alignment, sectionID, sectionName);
42 static uint8_t *roundTripAllocateDataSection(void *object, uintptr_t size,
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);
53 static LLVMBool roundTripFinalizeMemory(void *object, char **errMsg) {
54 std::string errMsgString;
56 static_cast<SectionMemoryManager*>(object)->finalizeMemory(&errMsgString);
58 *errMsg = LLVMCreateMessage(errMsgString.c_str());
64 static void roundTripDestroy(void *object) {
65 delete static_cast<SectionMemoryManager*>(object);
68 static void passRunListenerCallback(LLVMContextRef C, LLVMPassRef P,
69 LLVMModuleRef M, LLVMValueRef F,
70 LLVMBasicBlockRef BB) {
71 didCallPassRunListener = true;
76 // memory manager to test reserve allocation space callback
77 class TestReserveAllocationSpaceMemoryManager: public SectionMemoryManager {
79 uintptr_t ReservedCodeSize;
80 uintptr_t UsedCodeSize;
81 uintptr_t ReservedDataSizeRO;
82 uintptr_t UsedDataSizeRO;
83 uintptr_t ReservedDataSizeRW;
84 uintptr_t UsedDataSizeRW;
86 TestReserveAllocationSpaceMemoryManager() :
87 ReservedCodeSize(0), UsedCodeSize(0), ReservedDataSizeRO(0),
88 UsedDataSizeRO(0), ReservedDataSizeRW(0), UsedDataSizeRW(0) {
91 virtual bool needsToReserveAllocationSpace() {
95 virtual void reserveAllocationSpace(
96 uintptr_t CodeSize, uintptr_t DataSizeRO, uintptr_t DataSizeRW) {
97 ReservedCodeSize = CodeSize;
98 ReservedDataSizeRO = DataSizeRO;
99 ReservedDataSizeRW = DataSizeRW;
102 void useSpace(uintptr_t* UsedSize, uintptr_t Size, unsigned Alignment) {
103 uintptr_t AlignedSize = (Size + Alignment - 1) / Alignment * Alignment;
104 uintptr_t AlignedBegin = (*UsedSize + Alignment - 1) / Alignment * Alignment;
105 *UsedSize = AlignedBegin + AlignedSize;
108 virtual uint8_t* allocateDataSection(uintptr_t Size, unsigned Alignment,
109 unsigned SectionID, StringRef SectionName, bool IsReadOnly) {
110 useSpace(IsReadOnly ? &UsedDataSizeRO : &UsedDataSizeRW, Size, Alignment);
111 return SectionMemoryManager::allocateDataSection(Size, Alignment,
112 SectionID, SectionName, IsReadOnly);
115 uint8_t* allocateCodeSection(uintptr_t Size, unsigned Alignment,
116 unsigned SectionID, StringRef SectionName) {
117 useSpace(&UsedCodeSize, Size, Alignment);
118 return SectionMemoryManager::allocateCodeSection(Size, Alignment,
119 SectionID, SectionName);
123 class MCJITCAPITest : public testing::Test, public MCJITTestAPICommon {
126 // The architectures below are known to be compatible with MCJIT as they
127 // are copied from test/ExecutionEngine/MCJIT/lit.local.cfg and should be
129 SupportedArchs.push_back(Triple::aarch64);
130 SupportedArchs.push_back(Triple::arm);
131 SupportedArchs.push_back(Triple::mips);
132 SupportedArchs.push_back(Triple::x86);
133 SupportedArchs.push_back(Triple::x86_64);
135 // Some architectures have sub-architectures in which tests will fail, like
136 // ARM. These two vectors will define if they do have sub-archs (to avoid
137 // extra work for those who don't), and if so, if they are listed to work
138 HasSubArchs.push_back(Triple::arm);
139 SupportedSubArchs.push_back("armv6");
140 SupportedSubArchs.push_back("armv7");
142 // The operating systems below are known to be sufficiently incompatible
143 // that they will fail the MCJIT C API tests.
144 UnsupportedOSs.push_back(Triple::Cygwin);
146 UnsupportedEnvironments.push_back(Triple::Cygnus);
149 virtual void SetUp() {
150 didCallAllocateCodeSection = false;
151 didAllocateCompactUnwindSection = false;
152 didCallPassRunListener = false;
159 virtual void TearDown() {
161 LLVMDisposeExecutionEngine(Engine);
163 LLVMDisposeModule(Module);
166 void buildSimpleFunction() {
167 Module = LLVMModuleCreateWithName("simple_module");
169 LLVMSetTarget(Module, HostTriple.c_str());
171 Function = LLVMAddFunction(
172 Module, "simple_function", LLVMFunctionType(LLVMInt32Type(), 0, 0, 0));
173 LLVMSetFunctionCallConv(Function, LLVMCCallConv);
175 LLVMBasicBlockRef entry = LLVMAppendBasicBlock(Function, "entry");
176 LLVMBuilderRef builder = LLVMCreateBuilder();
177 LLVMPositionBuilderAtEnd(builder, entry);
178 LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0));
180 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
181 LLVMDisposeMessage(Error);
183 LLVMDisposeBuilder(builder);
186 void buildFunctionThatUsesStackmap() {
187 Module = LLVMModuleCreateWithName("simple_module");
189 LLVMSetTarget(Module, HostTriple.c_str());
191 LLVMTypeRef stackmapParamTypes[] = { LLVMInt64Type(), LLVMInt32Type() };
192 LLVMValueRef stackmap = LLVMAddFunction(
193 Module, "llvm.experimental.stackmap",
194 LLVMFunctionType(LLVMVoidType(), stackmapParamTypes, 2, 1));
195 LLVMSetLinkage(stackmap, LLVMExternalLinkage);
197 Function = LLVMAddFunction(
198 Module, "simple_function", LLVMFunctionType(LLVMInt32Type(), 0, 0, 0));
200 LLVMBasicBlockRef entry = LLVMAppendBasicBlock(Function, "entry");
201 LLVMBuilderRef builder = LLVMCreateBuilder();
202 LLVMPositionBuilderAtEnd(builder, entry);
203 LLVMValueRef stackmapArgs[] = {
204 LLVMConstInt(LLVMInt64Type(), 0, 0), LLVMConstInt(LLVMInt32Type(), 5, 0),
205 LLVMConstInt(LLVMInt32Type(), 42, 0)
207 LLVMBuildCall(builder, stackmap, stackmapArgs, 3, "");
208 LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0));
210 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
211 LLVMDisposeMessage(Error);
213 LLVMDisposeBuilder(builder);
216 void buildModuleWithCodeAndData() {
217 Module = LLVMModuleCreateWithName("simple_module");
219 LLVMSetTarget(Module, HostTriple.c_str());
221 // build a global int32 variable initialized to 42.
222 LLVMValueRef GlobalVar = LLVMAddGlobal(Module, LLVMInt32Type(), "intVal");
223 LLVMSetInitializer(GlobalVar, LLVMConstInt(LLVMInt32Type(), 42, 0));
226 Function = LLVMAddFunction(
227 Module, "getGlobal", LLVMFunctionType(LLVMInt32Type(), 0, 0, 0));
228 LLVMSetFunctionCallConv(Function, LLVMCCallConv);
230 LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function, "entry");
231 LLVMBuilderRef Builder = LLVMCreateBuilder();
232 LLVMPositionBuilderAtEnd(Builder, Entry);
234 LLVMValueRef IntVal = LLVMBuildLoad(Builder, GlobalVar, "intVal");
235 LLVMBuildRet(Builder, IntVal);
237 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
238 LLVMDisposeMessage(Error);
240 LLVMDisposeBuilder(Builder);
244 LLVMTypeRef ParamTypes[] = { LLVMInt32Type() };
245 Function2 = LLVMAddFunction(
246 Module, "setGlobal", LLVMFunctionType(LLVMVoidType(), ParamTypes, 1, 0));
247 LLVMSetFunctionCallConv(Function2, LLVMCCallConv);
249 LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function2, "entry");
250 LLVMBuilderRef Builder = LLVMCreateBuilder();
251 LLVMPositionBuilderAtEnd(Builder, Entry);
253 LLVMValueRef Arg = LLVMGetParam(Function2, 0);
254 LLVMBuildStore(Builder, Arg, GlobalVar);
255 LLVMBuildRetVoid(Builder);
257 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
258 LLVMDisposeMessage(Error);
260 LLVMDisposeBuilder(Builder);
264 void buildMCJITOptions() {
265 LLVMInitializeMCJITCompilerOptions(&Options, sizeof(Options));
266 Options.OptLevel = 2;
268 // Just ensure that this field still exists.
269 Options.NoFramePointerElim = false;
272 void useRoundTripSectionMemoryManager() {
273 Options.MCJMM = LLVMCreateSimpleMCJITMemoryManager(
274 new SectionMemoryManager(),
275 roundTripAllocateCodeSection,
276 roundTripAllocateDataSection,
277 roundTripFinalizeMemory,
281 void buildMCJITEngine() {
283 0, LLVMCreateMCJITCompilerForModule(&Engine, Module, &Options,
284 sizeof(Options), &Error));
287 void buildAndRunPasses() {
288 LLVMPassManagerRef pass = LLVMCreatePassManager();
289 LLVMAddTargetData(LLVMGetExecutionEngineTargetData(Engine), pass);
290 LLVMAddConstantPropagationPass(pass);
291 LLVMAddInstructionCombiningPass(pass);
292 LLVMRunPassManager(pass, Module);
293 LLVMDisposePassManager(pass);
296 void buildAndRunOptPasses() {
297 LLVMPassManagerBuilderRef passBuilder;
299 passBuilder = LLVMPassManagerBuilderCreate();
300 LLVMPassManagerBuilderSetOptLevel(passBuilder, 2);
301 LLVMPassManagerBuilderSetSizeLevel(passBuilder, 0);
303 LLVMPassManagerRef functionPasses =
304 LLVMCreateFunctionPassManagerForModule(Module);
305 LLVMPassManagerRef modulePasses =
306 LLVMCreatePassManager();
308 LLVMAddTargetData(LLVMGetExecutionEngineTargetData(Engine), modulePasses);
310 LLVMPassManagerBuilderPopulateFunctionPassManager(passBuilder,
312 LLVMPassManagerBuilderPopulateModulePassManager(passBuilder, modulePasses);
314 LLVMPassManagerBuilderDispose(passBuilder);
316 LLVMInitializeFunctionPassManager(functionPasses);
317 for (LLVMValueRef value = LLVMGetFirstFunction(Module);
318 value; value = LLVMGetNextFunction(value))
319 LLVMRunFunctionPassManager(functionPasses, value);
320 LLVMFinalizeFunctionPassManager(functionPasses);
322 LLVMRunPassManager(modulePasses, Module);
324 LLVMDisposePassManager(functionPasses);
325 LLVMDisposePassManager(modulePasses);
328 LLVMModuleRef Module;
329 LLVMValueRef Function;
330 LLVMValueRef Function2;
331 LLVMMCJITCompilerOptions Options;
332 LLVMExecutionEngineRef Engine;
335 } // end anonymous namespace
337 TEST_F(MCJITCAPITest, simple_function) {
338 SKIP_UNSUPPORTED_PLATFORM;
340 buildSimpleFunction();
349 functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function);
351 EXPECT_EQ(42, functionPointer.usable());
354 TEST_F(MCJITCAPITest, custom_memory_manager) {
355 SKIP_UNSUPPORTED_PLATFORM;
357 buildSimpleFunction();
359 useRoundTripSectionMemoryManager();
367 functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function);
369 EXPECT_EQ(42, functionPointer.usable());
370 EXPECT_TRUE(didCallAllocateCodeSection);
373 TEST_F(MCJITCAPITest, stackmap_creates_compact_unwind_on_darwin) {
374 SKIP_UNSUPPORTED_PLATFORM;
376 // This test is also not supported on non-x86 platforms.
377 if (Triple(HostTriple).getArch() != Triple::x86_64)
380 buildFunctionThatUsesStackmap();
382 useRoundTripSectionMemoryManager();
384 buildAndRunOptPasses();
390 functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function);
392 EXPECT_EQ(42, functionPointer.usable());
393 EXPECT_TRUE(didCallAllocateCodeSection);
395 // Up to this point, the test is specific only to X86-64. But this next
396 // expectation is only valid on Darwin because it assumes that unwind
397 // data is made available only through compact_unwind. It would be
398 // worthwhile to extend this to handle non-Darwin platforms, in which
399 // case you'd want to look for an eh_frame or something.
401 // FIXME: Currently, MCJIT relies on a configure-time check to determine which
402 // sections to emit. The JIT client should have runtime control over this.
404 Triple(HostTriple).getOS() != Triple::Darwin ||
405 Triple(HostTriple).isMacOSXVersionLT(10, 7) ||
406 didAllocateCompactUnwindSection);
409 TEST_F(MCJITCAPITest, reserve_allocation_space) {
410 SKIP_UNSUPPORTED_PLATFORM;
412 TestReserveAllocationSpaceMemoryManager* MM = new TestReserveAllocationSpaceMemoryManager();
414 buildModuleWithCodeAndData();
416 Options.MCJMM = wrap(MM);
424 GetGlobalFct.raw = LLVMGetPointerToGlobal(Engine, Function);
430 SetGlobalFct.raw = LLVMGetPointerToGlobal(Engine, Function2);
432 SetGlobalFct.usable(789);
433 EXPECT_EQ(789, GetGlobalFct.usable());
434 EXPECT_LE(MM->UsedCodeSize, MM->ReservedCodeSize);
435 EXPECT_LE(MM->UsedDataSizeRO, MM->ReservedDataSizeRO);
436 EXPECT_LE(MM->UsedDataSizeRW, MM->ReservedDataSizeRW);
437 EXPECT_TRUE(MM->UsedCodeSize > 0);
438 EXPECT_TRUE(MM->UsedDataSizeRW > 0);
441 TEST_F(MCJITCAPITest, pass_run_listener) {
442 SKIP_UNSUPPORTED_PLATFORM;
444 buildSimpleFunction();
447 LLVMContextRef C = LLVMGetGlobalContext();
448 LLVMAddPassRunListener(C, passRunListenerCallback);
455 functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function);
457 EXPECT_EQ(42, functionPointer.usable());
458 EXPECT_TRUE(didCallPassRunListener);