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 didCallYield;
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 yield(LLVMContextRef, void *) {
74 // memory manager to test reserve allocation space callback
75 class TestReserveAllocationSpaceMemoryManager: public SectionMemoryManager {
77 uintptr_t ReservedCodeSize;
78 uintptr_t UsedCodeSize;
79 uintptr_t ReservedDataSizeRO;
80 uintptr_t UsedDataSizeRO;
81 uintptr_t ReservedDataSizeRW;
82 uintptr_t UsedDataSizeRW;
84 TestReserveAllocationSpaceMemoryManager() :
85 ReservedCodeSize(0), UsedCodeSize(0), ReservedDataSizeRO(0),
86 UsedDataSizeRO(0), ReservedDataSizeRW(0), UsedDataSizeRW(0) {
89 bool needsToReserveAllocationSpace() override { return true; }
91 void reserveAllocationSpace(uintptr_t CodeSize, uintptr_t DataSizeRO,
92 uintptr_t DataSizeRW) override {
93 ReservedCodeSize = CodeSize;
94 ReservedDataSizeRO = DataSizeRO;
95 ReservedDataSizeRW = DataSizeRW;
98 void useSpace(uintptr_t* UsedSize, uintptr_t Size, unsigned Alignment) {
99 uintptr_t AlignedSize = (Size + Alignment - 1) / Alignment * Alignment;
100 uintptr_t AlignedBegin = (*UsedSize + Alignment - 1) / Alignment * Alignment;
101 *UsedSize = AlignedBegin + AlignedSize;
104 uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
105 unsigned SectionID, StringRef SectionName,
106 bool IsReadOnly) override {
107 useSpace(IsReadOnly ? &UsedDataSizeRO : &UsedDataSizeRW, Size, Alignment);
108 return SectionMemoryManager::allocateDataSection(Size, Alignment,
109 SectionID, SectionName, IsReadOnly);
112 uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
114 StringRef SectionName) override {
115 useSpace(&UsedCodeSize, Size, Alignment);
116 return SectionMemoryManager::allocateCodeSection(Size, Alignment,
117 SectionID, SectionName);
121 class MCJITCAPITest : public testing::Test, public MCJITTestAPICommon {
124 // The architectures below are known to be compatible with MCJIT as they
125 // are copied from test/ExecutionEngine/MCJIT/lit.local.cfg and should be
127 SupportedArchs.push_back(Triple::aarch64);
128 SupportedArchs.push_back(Triple::arm);
129 SupportedArchs.push_back(Triple::mips);
130 SupportedArchs.push_back(Triple::mips64);
131 SupportedArchs.push_back(Triple::mips64el);
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 UnsupportedEnvironments.push_back(Triple::Cygnus);
147 void SetUp() override {
148 didCallAllocateCodeSection = false;
149 didAllocateCompactUnwindSection = false;
150 didCallYield = false;
157 void TearDown() override {
159 LLVMDisposeExecutionEngine(Engine);
161 LLVMDisposeModule(Module);
164 void buildSimpleFunction() {
165 Module = LLVMModuleCreateWithName("simple_module");
167 LLVMSetTarget(Module, HostTriple.c_str());
169 Function = LLVMAddFunction(Module, "simple_function",
170 LLVMFunctionType(LLVMInt32Type(), nullptr,0, 0));
171 LLVMSetFunctionCallConv(Function, LLVMCCallConv);
173 LLVMBasicBlockRef entry = LLVMAppendBasicBlock(Function, "entry");
174 LLVMBuilderRef builder = LLVMCreateBuilder();
175 LLVMPositionBuilderAtEnd(builder, entry);
176 LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0));
178 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
179 LLVMDisposeMessage(Error);
181 LLVMDisposeBuilder(builder);
184 void buildFunctionThatUsesStackmap() {
185 Module = LLVMModuleCreateWithName("simple_module");
187 LLVMSetTarget(Module, HostTriple.c_str());
189 LLVMTypeRef stackmapParamTypes[] = { LLVMInt64Type(), LLVMInt32Type() };
190 LLVMValueRef stackmap = LLVMAddFunction(
191 Module, "llvm.experimental.stackmap",
192 LLVMFunctionType(LLVMVoidType(), stackmapParamTypes, 2, 1));
193 LLVMSetLinkage(stackmap, LLVMExternalLinkage);
195 Function = LLVMAddFunction(Module, "simple_function",
196 LLVMFunctionType(LLVMInt32Type(), nullptr, 0, 0));
198 LLVMBasicBlockRef entry = LLVMAppendBasicBlock(Function, "entry");
199 LLVMBuilderRef builder = LLVMCreateBuilder();
200 LLVMPositionBuilderAtEnd(builder, entry);
201 LLVMValueRef stackmapArgs[] = {
202 LLVMConstInt(LLVMInt64Type(), 0, 0), LLVMConstInt(LLVMInt32Type(), 5, 0),
203 LLVMConstInt(LLVMInt32Type(), 42, 0)
205 LLVMBuildCall(builder, stackmap, stackmapArgs, 3, "");
206 LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0));
208 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
209 LLVMDisposeMessage(Error);
211 LLVMDisposeBuilder(builder);
214 void buildModuleWithCodeAndData() {
215 Module = LLVMModuleCreateWithName("simple_module");
217 LLVMSetTarget(Module, HostTriple.c_str());
219 // build a global int32 variable initialized to 42.
220 LLVMValueRef GlobalVar = LLVMAddGlobal(Module, LLVMInt32Type(), "intVal");
221 LLVMSetInitializer(GlobalVar, LLVMConstInt(LLVMInt32Type(), 42, 0));
224 Function = LLVMAddFunction(Module, "getGlobal",
225 LLVMFunctionType(LLVMInt32Type(), nullptr, 0, 0));
226 LLVMSetFunctionCallConv(Function, LLVMCCallConv);
228 LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function, "entry");
229 LLVMBuilderRef Builder = LLVMCreateBuilder();
230 LLVMPositionBuilderAtEnd(Builder, Entry);
232 LLVMValueRef IntVal = LLVMBuildLoad(Builder, GlobalVar, "intVal");
233 LLVMBuildRet(Builder, IntVal);
235 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
236 LLVMDisposeMessage(Error);
238 LLVMDisposeBuilder(Builder);
242 LLVMTypeRef ParamTypes[] = { LLVMInt32Type() };
243 Function2 = LLVMAddFunction(
244 Module, "setGlobal", LLVMFunctionType(LLVMVoidType(), ParamTypes, 1, 0));
245 LLVMSetFunctionCallConv(Function2, LLVMCCallConv);
247 LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function2, "entry");
248 LLVMBuilderRef Builder = LLVMCreateBuilder();
249 LLVMPositionBuilderAtEnd(Builder, Entry);
251 LLVMValueRef Arg = LLVMGetParam(Function2, 0);
252 LLVMBuildStore(Builder, Arg, GlobalVar);
253 LLVMBuildRetVoid(Builder);
255 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
256 LLVMDisposeMessage(Error);
258 LLVMDisposeBuilder(Builder);
262 void buildMCJITOptions() {
263 LLVMInitializeMCJITCompilerOptions(&Options, sizeof(Options));
264 Options.OptLevel = 2;
266 // Just ensure that this field still exists.
267 Options.NoFramePointerElim = false;
270 void useRoundTripSectionMemoryManager() {
271 Options.MCJMM = LLVMCreateSimpleMCJITMemoryManager(
272 new SectionMemoryManager(),
273 roundTripAllocateCodeSection,
274 roundTripAllocateDataSection,
275 roundTripFinalizeMemory,
279 void buildMCJITEngine() {
281 0, LLVMCreateMCJITCompilerForModule(&Engine, Module, &Options,
282 sizeof(Options), &Error));
285 void buildAndRunPasses() {
286 LLVMPassManagerRef pass = LLVMCreatePassManager();
287 LLVMAddTargetData(LLVMGetExecutionEngineTargetData(Engine), pass);
288 LLVMAddConstantPropagationPass(pass);
289 LLVMAddInstructionCombiningPass(pass);
290 LLVMRunPassManager(pass, Module);
291 LLVMDisposePassManager(pass);
294 void buildAndRunOptPasses() {
295 LLVMPassManagerBuilderRef passBuilder;
297 passBuilder = LLVMPassManagerBuilderCreate();
298 LLVMPassManagerBuilderSetOptLevel(passBuilder, 2);
299 LLVMPassManagerBuilderSetSizeLevel(passBuilder, 0);
301 LLVMPassManagerRef functionPasses =
302 LLVMCreateFunctionPassManagerForModule(Module);
303 LLVMPassManagerRef modulePasses =
304 LLVMCreatePassManager();
306 LLVMAddTargetData(LLVMGetExecutionEngineTargetData(Engine), modulePasses);
308 LLVMPassManagerBuilderPopulateFunctionPassManager(passBuilder,
310 LLVMPassManagerBuilderPopulateModulePassManager(passBuilder, modulePasses);
312 LLVMPassManagerBuilderDispose(passBuilder);
314 LLVMInitializeFunctionPassManager(functionPasses);
315 for (LLVMValueRef value = LLVMGetFirstFunction(Module);
316 value; value = LLVMGetNextFunction(value))
317 LLVMRunFunctionPassManager(functionPasses, value);
318 LLVMFinalizeFunctionPassManager(functionPasses);
320 LLVMRunPassManager(modulePasses, Module);
322 LLVMDisposePassManager(functionPasses);
323 LLVMDisposePassManager(modulePasses);
326 LLVMModuleRef Module;
327 LLVMValueRef Function;
328 LLVMValueRef Function2;
329 LLVMMCJITCompilerOptions Options;
330 LLVMExecutionEngineRef Engine;
333 } // end anonymous namespace
335 TEST_F(MCJITCAPITest, simple_function) {
336 SKIP_UNSUPPORTED_PLATFORM;
338 buildSimpleFunction();
343 auto *functionPointer = reinterpret_cast<int (*)()>(
344 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine, Function)));
346 EXPECT_EQ(42, functionPointer());
349 TEST_F(MCJITCAPITest, gva) {
350 SKIP_UNSUPPORTED_PLATFORM;
352 Module = LLVMModuleCreateWithName("simple_module");
353 LLVMSetTarget(Module, HostTriple.c_str());
354 LLVMValueRef GlobalVar = LLVMAddGlobal(Module, LLVMInt32Type(), "simple_value");
355 LLVMSetInitializer(GlobalVar, LLVMConstInt(LLVMInt32Type(), 42, 0));
361 uint64_t raw = LLVMGetGlobalValueAddress(Engine, "simple_value");
362 int32_t *usable = (int32_t *) raw;
364 EXPECT_EQ(42, *usable);
367 TEST_F(MCJITCAPITest, gfa) {
368 SKIP_UNSUPPORTED_PLATFORM;
370 buildSimpleFunction();
375 uint64_t raw = LLVMGetFunctionAddress(Engine, "simple_function");
376 int (*usable)() = (int (*)()) raw;
378 EXPECT_EQ(42, usable());
381 TEST_F(MCJITCAPITest, custom_memory_manager) {
382 SKIP_UNSUPPORTED_PLATFORM;
384 buildSimpleFunction();
386 useRoundTripSectionMemoryManager();
390 auto *functionPointer = reinterpret_cast<int (*)()>(
391 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine, Function)));
393 EXPECT_EQ(42, functionPointer());
394 EXPECT_TRUE(didCallAllocateCodeSection);
397 TEST_F(MCJITCAPITest, stackmap_creates_compact_unwind_on_darwin) {
398 SKIP_UNSUPPORTED_PLATFORM;
400 // This test is also not supported on non-x86 platforms.
401 if (Triple(HostTriple).getArch() != Triple::x86_64)
404 buildFunctionThatUsesStackmap();
406 useRoundTripSectionMemoryManager();
408 buildAndRunOptPasses();
410 auto *functionPointer = reinterpret_cast<int (*)()>(
411 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine, Function)));
413 EXPECT_EQ(42, functionPointer());
414 EXPECT_TRUE(didCallAllocateCodeSection);
416 // Up to this point, the test is specific only to X86-64. But this next
417 // expectation is only valid on Darwin because it assumes that unwind
418 // data is made available only through compact_unwind. It would be
419 // worthwhile to extend this to handle non-Darwin platforms, in which
420 // case you'd want to look for an eh_frame or something.
422 // FIXME: Currently, MCJIT relies on a configure-time check to determine which
423 // sections to emit. The JIT client should have runtime control over this.
425 Triple(HostTriple).getOS() != Triple::Darwin ||
426 Triple(HostTriple).isMacOSXVersionLT(10, 7) ||
427 didAllocateCompactUnwindSection);
430 TEST_F(MCJITCAPITest, reserve_allocation_space) {
431 SKIP_UNSUPPORTED_PLATFORM;
433 TestReserveAllocationSpaceMemoryManager* MM = new TestReserveAllocationSpaceMemoryManager();
435 buildModuleWithCodeAndData();
437 Options.MCJMM = wrap(MM);
441 auto GetGlobalFct = reinterpret_cast<int (*)()>(
442 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine, Function)));
444 auto SetGlobalFct = reinterpret_cast<void (*)(int)>(
445 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine, Function2)));
448 EXPECT_EQ(789, GetGlobalFct());
449 EXPECT_LE(MM->UsedCodeSize, MM->ReservedCodeSize);
450 EXPECT_LE(MM->UsedDataSizeRO, MM->ReservedDataSizeRO);
451 EXPECT_LE(MM->UsedDataSizeRW, MM->ReservedDataSizeRW);
452 EXPECT_TRUE(MM->UsedCodeSize > 0);
453 EXPECT_TRUE(MM->UsedDataSizeRW > 0);
456 TEST_F(MCJITCAPITest, yield) {
457 SKIP_UNSUPPORTED_PLATFORM;
459 buildSimpleFunction();
462 LLVMContextRef C = LLVMGetGlobalContext();
463 LLVMContextSetYieldCallback(C, yield, nullptr);
466 auto *functionPointer = reinterpret_cast<int (*)()>(
467 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine, Function)));
469 EXPECT_EQ(42, functionPointer());
470 EXPECT_TRUE(didCallYield);
473 static int localTestFunc() {
477 TEST_F(MCJITCAPITest, addGlobalMapping) {
478 SKIP_UNSUPPORTED_PLATFORM;
480 Module = LLVMModuleCreateWithName("testModule");
481 LLVMSetTarget(Module, HostTriple.c_str());
482 LLVMTypeRef FunctionType = LLVMFunctionType(LLVMInt32Type(), NULL, 0, 0);
483 LLVMValueRef MappedFn = LLVMAddFunction(Module, "mapped_fn", FunctionType);
485 Function = LLVMAddFunction(Module, "test_fn", FunctionType);
486 LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function, "");
487 LLVMBuilderRef Builder = LLVMCreateBuilder();
488 LLVMPositionBuilderAtEnd(Builder, Entry);
489 LLVMValueRef RetVal = LLVMBuildCall(Builder, MappedFn, NULL, 0, "");
490 LLVMBuildRet(Builder, RetVal);
491 LLVMDisposeBuilder(Builder);
493 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
494 LLVMDisposeMessage(Error);
499 LLVMAddGlobalMapping(
501 reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(&localTestFunc)));
505 uint64_t raw = LLVMGetFunctionAddress(Engine, "test_fn");
506 int (*usable)() = (int (*)()) raw;
508 EXPECT_EQ(42, usable());