1 //===- MCJITTest.cpp - Unit tests for the MCJIT -----------------*- C++ -*-===//
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 "MCJITTestAPICommon.h"
16 #include "llvm-c/Analysis.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
, uint32_t CodeAlign
,
92 uintptr_t DataSizeRO
, uint32_t RODataAlign
,
94 uint32_t RWDataAlign
) override
{
95 ReservedCodeSize
= CodeSize
;
96 ReservedDataSizeRO
= DataSizeRO
;
97 ReservedDataSizeRW
= DataSizeRW
;
100 void useSpace(uintptr_t* UsedSize
, uintptr_t Size
, unsigned Alignment
) {
101 uintptr_t AlignedSize
= (Size
+ Alignment
- 1) / Alignment
* Alignment
;
102 uintptr_t AlignedBegin
= (*UsedSize
+ Alignment
- 1) / Alignment
* Alignment
;
103 *UsedSize
= AlignedBegin
+ AlignedSize
;
106 uint8_t *allocateDataSection(uintptr_t Size
, unsigned Alignment
,
107 unsigned SectionID
, StringRef SectionName
,
108 bool IsReadOnly
) override
{
109 useSpace(IsReadOnly
? &UsedDataSizeRO
: &UsedDataSizeRW
, Size
, Alignment
);
110 return SectionMemoryManager::allocateDataSection(Size
, Alignment
,
111 SectionID
, SectionName
, IsReadOnly
);
114 uint8_t *allocateCodeSection(uintptr_t Size
, unsigned Alignment
,
116 StringRef SectionName
) override
{
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::mips64
);
133 SupportedArchs
.push_back(Triple::mips64el
);
134 SupportedArchs
.push_back(Triple::x86
);
135 SupportedArchs
.push_back(Triple::x86_64
);
137 // Some architectures have sub-architectures in which tests will fail, like
138 // ARM. These two vectors will define if they do have sub-archs (to avoid
139 // extra work for those who don't), and if so, if they are listed to work
140 HasSubArchs
.push_back(Triple::arm
);
141 SupportedSubArchs
.push_back("armv6");
142 SupportedSubArchs
.push_back("armv7");
144 // The operating systems below are known to be sufficiently incompatible
145 // that they will fail the MCJIT C API tests.
146 UnsupportedEnvironments
.push_back(Triple::Cygnus
);
149 void SetUp() override
{
150 didCallAllocateCodeSection
= false;
151 didAllocateCompactUnwindSection
= false;
152 didCallYield
= false;
159 void TearDown() override
{
161 LLVMDisposeExecutionEngine(Engine
);
163 LLVMDisposeModule(Module
);
166 void buildSimpleFunction() {
167 Module
= LLVMModuleCreateWithName("simple_module");
169 LLVMSetTarget(Module
, HostTriple
.c_str());
171 Function
= LLVMAddFunction(Module
, "simple_function",
172 LLVMFunctionType(LLVMInt32Type(), nullptr,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(Module
, "simple_function",
198 LLVMFunctionType(LLVMInt32Type(), nullptr, 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(Module
, "getGlobal",
227 LLVMFunctionType(LLVMInt32Type(), nullptr, 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 LLVMAddConstantPropagationPass(pass
);
290 LLVMAddInstructionCombiningPass(pass
);
291 LLVMRunPassManager(pass
, Module
);
292 LLVMDisposePassManager(pass
);
295 void buildAndRunOptPasses() {
296 LLVMPassManagerBuilderRef passBuilder
;
298 passBuilder
= LLVMPassManagerBuilderCreate();
299 LLVMPassManagerBuilderSetOptLevel(passBuilder
, 2);
300 LLVMPassManagerBuilderSetSizeLevel(passBuilder
, 0);
302 LLVMPassManagerRef functionPasses
=
303 LLVMCreateFunctionPassManagerForModule(Module
);
304 LLVMPassManagerRef modulePasses
=
305 LLVMCreatePassManager();
307 LLVMPassManagerBuilderPopulateFunctionPassManager(passBuilder
,
309 LLVMPassManagerBuilderPopulateModulePassManager(passBuilder
, modulePasses
);
311 LLVMPassManagerBuilderDispose(passBuilder
);
313 LLVMInitializeFunctionPassManager(functionPasses
);
314 for (LLVMValueRef value
= LLVMGetFirstFunction(Module
);
315 value
; value
= LLVMGetNextFunction(value
))
316 LLVMRunFunctionPassManager(functionPasses
, value
);
317 LLVMFinalizeFunctionPassManager(functionPasses
);
319 LLVMRunPassManager(modulePasses
, Module
);
321 LLVMDisposePassManager(functionPasses
);
322 LLVMDisposePassManager(modulePasses
);
325 LLVMModuleRef Module
;
326 LLVMValueRef Function
;
327 LLVMValueRef Function2
;
328 LLVMMCJITCompilerOptions Options
;
329 LLVMExecutionEngineRef Engine
;
332 } // end anonymous namespace
334 TEST_F(MCJITCAPITest
, simple_function
) {
335 SKIP_UNSUPPORTED_PLATFORM
;
337 buildSimpleFunction();
342 auto *functionPointer
= reinterpret_cast<int (*)()>(
343 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine
, Function
)));
345 EXPECT_EQ(42, functionPointer());
348 TEST_F(MCJITCAPITest
, gva
) {
349 SKIP_UNSUPPORTED_PLATFORM
;
351 Module
= LLVMModuleCreateWithName("simple_module");
352 LLVMSetTarget(Module
, HostTriple
.c_str());
353 LLVMValueRef GlobalVar
= LLVMAddGlobal(Module
, LLVMInt32Type(), "simple_value");
354 LLVMSetInitializer(GlobalVar
, LLVMConstInt(LLVMInt32Type(), 42, 0));
360 uint64_t raw
= LLVMGetGlobalValueAddress(Engine
, "simple_value");
361 int32_t *usable
= (int32_t *) raw
;
363 EXPECT_EQ(42, *usable
);
366 TEST_F(MCJITCAPITest
, gfa
) {
367 SKIP_UNSUPPORTED_PLATFORM
;
369 buildSimpleFunction();
374 uint64_t raw
= LLVMGetFunctionAddress(Engine
, "simple_function");
375 int (*usable
)() = (int (*)()) raw
;
377 EXPECT_EQ(42, usable());
380 TEST_F(MCJITCAPITest
, custom_memory_manager
) {
381 SKIP_UNSUPPORTED_PLATFORM
;
383 buildSimpleFunction();
385 useRoundTripSectionMemoryManager();
389 auto *functionPointer
= reinterpret_cast<int (*)()>(
390 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine
, Function
)));
392 EXPECT_EQ(42, functionPointer());
393 EXPECT_TRUE(didCallAllocateCodeSection
);
396 TEST_F(MCJITCAPITest
, stackmap_creates_compact_unwind_on_darwin
) {
397 SKIP_UNSUPPORTED_PLATFORM
;
399 // This test is also not supported on non-x86 platforms.
400 if (Triple(HostTriple
).getArch() != Triple::x86_64
)
403 buildFunctionThatUsesStackmap();
405 useRoundTripSectionMemoryManager();
407 buildAndRunOptPasses();
409 auto *functionPointer
= reinterpret_cast<int (*)()>(
410 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine
, Function
)));
412 EXPECT_EQ(42, functionPointer());
413 EXPECT_TRUE(didCallAllocateCodeSection
);
415 // Up to this point, the test is specific only to X86-64. But this next
416 // expectation is only valid on Darwin because it assumes that unwind
417 // data is made available only through compact_unwind. It would be
418 // worthwhile to extend this to handle non-Darwin platforms, in which
419 // case you'd want to look for an eh_frame or something.
421 // FIXME: Currently, MCJIT relies on a configure-time check to determine which
422 // sections to emit. The JIT client should have runtime control over this.
424 Triple(HostTriple
).getOS() != Triple::Darwin
||
425 Triple(HostTriple
).isMacOSXVersionLT(10, 7) ||
426 didAllocateCompactUnwindSection
);
429 TEST_F(MCJITCAPITest
, reserve_allocation_space
) {
430 SKIP_UNSUPPORTED_PLATFORM
;
432 TestReserveAllocationSpaceMemoryManager
* MM
= new TestReserveAllocationSpaceMemoryManager();
434 buildModuleWithCodeAndData();
436 Options
.MCJMM
= wrap(MM
);
440 auto GetGlobalFct
= reinterpret_cast<int (*)()>(
441 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine
, Function
)));
443 auto SetGlobalFct
= reinterpret_cast<void (*)(int)>(
444 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine
, Function2
)));
447 EXPECT_EQ(789, GetGlobalFct());
448 EXPECT_LE(MM
->UsedCodeSize
, MM
->ReservedCodeSize
);
449 EXPECT_LE(MM
->UsedDataSizeRO
, MM
->ReservedDataSizeRO
);
450 EXPECT_LE(MM
->UsedDataSizeRW
, MM
->ReservedDataSizeRW
);
451 EXPECT_TRUE(MM
->UsedCodeSize
> 0);
452 EXPECT_TRUE(MM
->UsedDataSizeRW
> 0);
455 TEST_F(MCJITCAPITest
, yield
) {
456 SKIP_UNSUPPORTED_PLATFORM
;
458 buildSimpleFunction();
461 LLVMContextRef C
= LLVMGetGlobalContext();
462 LLVMContextSetYieldCallback(C
, yield
, nullptr);
465 auto *functionPointer
= reinterpret_cast<int (*)()>(
466 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine
, Function
)));
468 EXPECT_EQ(42, functionPointer());
469 EXPECT_TRUE(didCallYield
);
472 static int localTestFunc() {
476 TEST_F(MCJITCAPITest
, addGlobalMapping
) {
477 SKIP_UNSUPPORTED_PLATFORM
;
479 Module
= LLVMModuleCreateWithName("testModule");
480 LLVMSetTarget(Module
, HostTriple
.c_str());
481 LLVMTypeRef FunctionType
= LLVMFunctionType(LLVMInt32Type(), nullptr, 0, 0);
482 LLVMValueRef MappedFn
= LLVMAddFunction(Module
, "mapped_fn", FunctionType
);
484 Function
= LLVMAddFunction(Module
, "test_fn", FunctionType
);
485 LLVMBasicBlockRef Entry
= LLVMAppendBasicBlock(Function
, "");
486 LLVMBuilderRef Builder
= LLVMCreateBuilder();
487 LLVMPositionBuilderAtEnd(Builder
, Entry
);
488 LLVMValueRef RetVal
= LLVMBuildCall(Builder
, MappedFn
, nullptr, 0, "");
489 LLVMBuildRet(Builder
, RetVal
);
490 LLVMDisposeBuilder(Builder
);
492 LLVMVerifyModule(Module
, LLVMAbortProcessAction
, &Error
);
493 LLVMDisposeMessage(Error
);
498 LLVMAddGlobalMapping(
500 reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(&localTestFunc
)));
504 uint64_t raw
= LLVMGetFunctionAddress(Engine
, "test_fn");
505 int (*usable
)() = (int (*)()) raw
;
507 EXPECT_EQ(42, usable());