1 //===- MCJITTest.cpp - Unit tests for the MCJIT -----------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This test suite verifies basic MCJIT functionality when invoked form the C
12 //===----------------------------------------------------------------------===//
14 #include "MCJITTestAPICommon.h"
15 #include "llvm-c/Analysis.h"
16 #include "llvm-c/Core.h"
17 #include "llvm-c/ExecutionEngine.h"
18 #include "llvm-c/Target.h"
19 #include "llvm-c/Transforms/PassManagerBuilder.h"
20 #include "llvm-c/Transforms/Scalar.h"
21 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
22 #include "llvm/Support/Debug.h"
23 #include "llvm/Support/Host.h"
24 #include "gtest/gtest.h"
28 static bool didCallAllocateCodeSection
;
29 static bool didAllocateCompactUnwindSection
;
30 static bool didCallYield
;
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
);
67 static void yield(LLVMContextRef
, void *) {
73 // memory manager to test reserve allocation space callback
74 class TestReserveAllocationSpaceMemoryManager
: public SectionMemoryManager
{
76 uintptr_t ReservedCodeSize
;
77 uintptr_t UsedCodeSize
;
78 uintptr_t ReservedDataSizeRO
;
79 uintptr_t UsedDataSizeRO
;
80 uintptr_t ReservedDataSizeRW
;
81 uintptr_t UsedDataSizeRW
;
83 TestReserveAllocationSpaceMemoryManager() :
84 ReservedCodeSize(0), UsedCodeSize(0), ReservedDataSizeRO(0),
85 UsedDataSizeRO(0), ReservedDataSizeRW(0), UsedDataSizeRW(0) {
88 bool needsToReserveAllocationSpace() override
{ return true; }
90 void reserveAllocationSpace(uintptr_t CodeSize
, uint32_t CodeAlign
,
91 uintptr_t DataSizeRO
, uint32_t RODataAlign
,
93 uint32_t RWDataAlign
) override
{
94 ReservedCodeSize
= CodeSize
;
95 ReservedDataSizeRO
= DataSizeRO
;
96 ReservedDataSizeRW
= DataSizeRW
;
99 void useSpace(uintptr_t* UsedSize
, uintptr_t Size
, unsigned Alignment
) {
100 uintptr_t AlignedSize
= (Size
+ Alignment
- 1) / Alignment
* Alignment
;
101 uintptr_t AlignedBegin
= (*UsedSize
+ Alignment
- 1) / Alignment
* Alignment
;
102 *UsedSize
= AlignedBegin
+ AlignedSize
;
105 uint8_t *allocateDataSection(uintptr_t Size
, unsigned Alignment
,
106 unsigned SectionID
, StringRef SectionName
,
107 bool IsReadOnly
) override
{
108 useSpace(IsReadOnly
? &UsedDataSizeRO
: &UsedDataSizeRW
, Size
, Alignment
);
109 return SectionMemoryManager::allocateDataSection(Size
, Alignment
,
110 SectionID
, SectionName
, IsReadOnly
);
113 uint8_t *allocateCodeSection(uintptr_t Size
, unsigned Alignment
,
115 StringRef SectionName
) override
{
116 useSpace(&UsedCodeSize
, Size
, Alignment
);
117 return SectionMemoryManager::allocateCodeSection(Size
, Alignment
,
118 SectionID
, SectionName
);
122 class MCJITCAPITest
: public testing::Test
, public MCJITTestAPICommon
{
125 // The architectures below are known to be compatible with MCJIT as they
126 // are copied from test/ExecutionEngine/MCJIT/lit.local.cfg and should be
128 SupportedArchs
.push_back(Triple::aarch64
);
129 SupportedArchs
.push_back(Triple::arm
);
130 SupportedArchs
.push_back(Triple::mips
);
131 SupportedArchs
.push_back(Triple::mips64
);
132 SupportedArchs
.push_back(Triple::mips64el
);
133 SupportedArchs
.push_back(Triple::x86
);
134 SupportedArchs
.push_back(Triple::x86_64
);
136 // Some architectures have sub-architectures in which tests will fail, like
137 // ARM. These two vectors will define if they do have sub-archs (to avoid
138 // extra work for those who don't), and if so, if they are listed to work
139 HasSubArchs
.push_back(Triple::arm
);
140 SupportedSubArchs
.push_back("armv6");
141 SupportedSubArchs
.push_back("armv7");
143 // The operating systems below are known to be sufficiently incompatible
144 // that they will fail the MCJIT C API tests.
145 UnsupportedEnvironments
.push_back(Triple::Cygnus
);
148 void SetUp() override
{
149 didCallAllocateCodeSection
= false;
150 didAllocateCompactUnwindSection
= false;
151 didCallYield
= false;
158 void TearDown() override
{
160 LLVMDisposeExecutionEngine(Engine
);
162 LLVMDisposeModule(Module
);
165 void buildSimpleFunction() {
166 Module
= LLVMModuleCreateWithName("simple_module");
168 LLVMSetTarget(Module
, HostTriple
.c_str());
170 Function
= LLVMAddFunction(Module
, "simple_function",
171 LLVMFunctionType(LLVMInt32Type(), nullptr,0, 0));
172 LLVMSetFunctionCallConv(Function
, LLVMCCallConv
);
174 LLVMBasicBlockRef entry
= LLVMAppendBasicBlock(Function
, "entry");
175 LLVMBuilderRef builder
= LLVMCreateBuilder();
176 LLVMPositionBuilderAtEnd(builder
, entry
);
177 LLVMBuildRet(builder
, LLVMConstInt(LLVMInt32Type(), 42, 0));
179 LLVMVerifyModule(Module
, LLVMAbortProcessAction
, &Error
);
180 LLVMDisposeMessage(Error
);
182 LLVMDisposeBuilder(builder
);
185 void buildFunctionThatUsesStackmap() {
186 Module
= LLVMModuleCreateWithName("simple_module");
188 LLVMSetTarget(Module
, HostTriple
.c_str());
190 LLVMTypeRef stackmapParamTypes
[] = { LLVMInt64Type(), LLVMInt32Type() };
191 LLVMValueRef stackmap
= LLVMAddFunction(
192 Module
, "llvm.experimental.stackmap",
193 LLVMFunctionType(LLVMVoidType(), stackmapParamTypes
, 2, 1));
194 LLVMSetLinkage(stackmap
, LLVMExternalLinkage
);
196 Function
= LLVMAddFunction(Module
, "simple_function",
197 LLVMFunctionType(LLVMInt32Type(), nullptr, 0, 0));
199 LLVMBasicBlockRef entry
= LLVMAppendBasicBlock(Function
, "entry");
200 LLVMBuilderRef builder
= LLVMCreateBuilder();
201 LLVMPositionBuilderAtEnd(builder
, entry
);
202 LLVMValueRef stackmapArgs
[] = {
203 LLVMConstInt(LLVMInt64Type(), 0, 0), LLVMConstInt(LLVMInt32Type(), 5, 0),
204 LLVMConstInt(LLVMInt32Type(), 42, 0)
206 LLVMBuildCall(builder
, stackmap
, stackmapArgs
, 3, "");
207 LLVMBuildRet(builder
, LLVMConstInt(LLVMInt32Type(), 42, 0));
209 LLVMVerifyModule(Module
, LLVMAbortProcessAction
, &Error
);
210 LLVMDisposeMessage(Error
);
212 LLVMDisposeBuilder(builder
);
215 void buildModuleWithCodeAndData() {
216 Module
= LLVMModuleCreateWithName("simple_module");
218 LLVMSetTarget(Module
, HostTriple
.c_str());
220 // build a global int32 variable initialized to 42.
221 LLVMValueRef GlobalVar
= LLVMAddGlobal(Module
, LLVMInt32Type(), "intVal");
222 LLVMSetInitializer(GlobalVar
, LLVMConstInt(LLVMInt32Type(), 42, 0));
225 Function
= LLVMAddFunction(Module
, "getGlobal",
226 LLVMFunctionType(LLVMInt32Type(), nullptr, 0, 0));
227 LLVMSetFunctionCallConv(Function
, LLVMCCallConv
);
229 LLVMBasicBlockRef Entry
= LLVMAppendBasicBlock(Function
, "entry");
230 LLVMBuilderRef Builder
= LLVMCreateBuilder();
231 LLVMPositionBuilderAtEnd(Builder
, Entry
);
233 LLVMValueRef IntVal
= LLVMBuildLoad(Builder
, GlobalVar
, "intVal");
234 LLVMBuildRet(Builder
, IntVal
);
236 LLVMVerifyModule(Module
, LLVMAbortProcessAction
, &Error
);
237 LLVMDisposeMessage(Error
);
239 LLVMDisposeBuilder(Builder
);
243 LLVMTypeRef ParamTypes
[] = { LLVMInt32Type() };
244 Function2
= LLVMAddFunction(
245 Module
, "setGlobal", LLVMFunctionType(LLVMVoidType(), ParamTypes
, 1, 0));
246 LLVMSetFunctionCallConv(Function2
, LLVMCCallConv
);
248 LLVMBasicBlockRef Entry
= LLVMAppendBasicBlock(Function2
, "entry");
249 LLVMBuilderRef Builder
= LLVMCreateBuilder();
250 LLVMPositionBuilderAtEnd(Builder
, Entry
);
252 LLVMValueRef Arg
= LLVMGetParam(Function2
, 0);
253 LLVMBuildStore(Builder
, Arg
, GlobalVar
);
254 LLVMBuildRetVoid(Builder
);
256 LLVMVerifyModule(Module
, LLVMAbortProcessAction
, &Error
);
257 LLVMDisposeMessage(Error
);
259 LLVMDisposeBuilder(Builder
);
263 void buildMCJITOptions() {
264 LLVMInitializeMCJITCompilerOptions(&Options
, sizeof(Options
));
265 Options
.OptLevel
= 2;
267 // Just ensure that this field still exists.
268 Options
.NoFramePointerElim
= false;
271 void useRoundTripSectionMemoryManager() {
272 Options
.MCJMM
= LLVMCreateSimpleMCJITMemoryManager(
273 new SectionMemoryManager(),
274 roundTripAllocateCodeSection
,
275 roundTripAllocateDataSection
,
276 roundTripFinalizeMemory
,
280 void buildMCJITEngine() {
282 0, LLVMCreateMCJITCompilerForModule(&Engine
, Module
, &Options
,
283 sizeof(Options
), &Error
));
286 void buildAndRunPasses() {
287 LLVMPassManagerRef pass
= LLVMCreatePassManager();
288 LLVMAddInstructionCombiningPass(pass
);
289 LLVMRunPassManager(pass
, Module
);
290 LLVMDisposePassManager(pass
);
293 void buildAndRunOptPasses() {
294 LLVMPassManagerBuilderRef passBuilder
;
296 passBuilder
= LLVMPassManagerBuilderCreate();
297 LLVMPassManagerBuilderSetOptLevel(passBuilder
, 2);
298 LLVMPassManagerBuilderSetSizeLevel(passBuilder
, 0);
300 LLVMPassManagerRef functionPasses
=
301 LLVMCreateFunctionPassManagerForModule(Module
);
302 LLVMPassManagerRef modulePasses
=
303 LLVMCreatePassManager();
305 LLVMPassManagerBuilderPopulateFunctionPassManager(passBuilder
,
307 LLVMPassManagerBuilderPopulateModulePassManager(passBuilder
, modulePasses
);
309 LLVMPassManagerBuilderDispose(passBuilder
);
311 LLVMInitializeFunctionPassManager(functionPasses
);
312 for (LLVMValueRef value
= LLVMGetFirstFunction(Module
);
313 value
; value
= LLVMGetNextFunction(value
))
314 LLVMRunFunctionPassManager(functionPasses
, value
);
315 LLVMFinalizeFunctionPassManager(functionPasses
);
317 LLVMRunPassManager(modulePasses
, Module
);
319 LLVMDisposePassManager(functionPasses
);
320 LLVMDisposePassManager(modulePasses
);
323 LLVMModuleRef Module
;
324 LLVMValueRef Function
;
325 LLVMValueRef Function2
;
326 LLVMMCJITCompilerOptions Options
;
327 LLVMExecutionEngineRef Engine
;
330 } // end anonymous namespace
332 TEST_F(MCJITCAPITest
, simple_function
) {
333 SKIP_UNSUPPORTED_PLATFORM
;
335 buildSimpleFunction();
340 auto *functionPointer
= reinterpret_cast<int (*)()>(
341 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine
, Function
)));
343 EXPECT_EQ(42, functionPointer());
346 TEST_F(MCJITCAPITest
, gva
) {
347 SKIP_UNSUPPORTED_PLATFORM
;
349 Module
= LLVMModuleCreateWithName("simple_module");
350 LLVMSetTarget(Module
, HostTriple
.c_str());
351 LLVMValueRef GlobalVar
= LLVMAddGlobal(Module
, LLVMInt32Type(), "simple_value");
352 LLVMSetInitializer(GlobalVar
, LLVMConstInt(LLVMInt32Type(), 42, 0));
358 uint64_t raw
= LLVMGetGlobalValueAddress(Engine
, "simple_value");
359 int32_t *usable
= (int32_t *) raw
;
361 EXPECT_EQ(42, *usable
);
364 TEST_F(MCJITCAPITest
, gfa
) {
365 SKIP_UNSUPPORTED_PLATFORM
;
367 buildSimpleFunction();
372 uint64_t raw
= LLVMGetFunctionAddress(Engine
, "simple_function");
373 int (*usable
)() = (int (*)()) raw
;
375 EXPECT_EQ(42, usable());
378 TEST_F(MCJITCAPITest
, custom_memory_manager
) {
379 SKIP_UNSUPPORTED_PLATFORM
;
381 buildSimpleFunction();
383 useRoundTripSectionMemoryManager();
387 auto *functionPointer
= reinterpret_cast<int (*)()>(
388 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine
, Function
)));
390 EXPECT_EQ(42, functionPointer());
391 EXPECT_TRUE(didCallAllocateCodeSection
);
394 TEST_F(MCJITCAPITest
, stackmap_creates_compact_unwind_on_darwin
) {
395 SKIP_UNSUPPORTED_PLATFORM
;
397 // This test is also not supported on non-x86 platforms.
398 if (Triple(HostTriple
).getArch() != Triple::x86_64
)
401 buildFunctionThatUsesStackmap();
403 useRoundTripSectionMemoryManager();
405 buildAndRunOptPasses();
407 auto *functionPointer
= reinterpret_cast<int (*)()>(
408 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine
, Function
)));
410 EXPECT_EQ(42, functionPointer());
411 EXPECT_TRUE(didCallAllocateCodeSection
);
413 // Up to this point, the test is specific only to X86-64. But this next
414 // expectation is only valid on Darwin because it assumes that unwind
415 // data is made available only through compact_unwind. It would be
416 // worthwhile to extend this to handle non-Darwin platforms, in which
417 // case you'd want to look for an eh_frame or something.
419 // FIXME: Currently, MCJIT relies on a configure-time check to determine which
420 // sections to emit. The JIT client should have runtime control over this.
422 Triple(HostTriple
).getOS() != Triple::Darwin
||
423 Triple(HostTriple
).isMacOSXVersionLT(10, 7) ||
424 didAllocateCompactUnwindSection
);
427 #if defined(__APPLE__) && defined(__aarch64__)
428 // FIXME: Figure out why this fails on mac/arm, PR46647
429 #define MAYBE_reserve_allocation_space DISABLED_reserve_allocation_space
431 #define MAYBE_reserve_allocation_space reserve_allocation_space
433 TEST_F(MCJITCAPITest
, MAYBE_reserve_allocation_space
) {
434 SKIP_UNSUPPORTED_PLATFORM
;
436 TestReserveAllocationSpaceMemoryManager
* MM
= new TestReserveAllocationSpaceMemoryManager();
438 buildModuleWithCodeAndData();
440 Options
.MCJMM
= wrap(MM
);
444 auto GetGlobalFct
= reinterpret_cast<int (*)()>(
445 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine
, Function
)));
447 auto SetGlobalFct
= reinterpret_cast<void (*)(int)>(
448 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine
, Function2
)));
451 EXPECT_EQ(789, GetGlobalFct());
452 EXPECT_LE(MM
->UsedCodeSize
, MM
->ReservedCodeSize
);
453 EXPECT_LE(MM
->UsedDataSizeRO
, MM
->ReservedDataSizeRO
);
454 EXPECT_LE(MM
->UsedDataSizeRW
, MM
->ReservedDataSizeRW
);
455 EXPECT_TRUE(MM
->UsedCodeSize
> 0);
456 EXPECT_TRUE(MM
->UsedDataSizeRW
> 0);
459 TEST_F(MCJITCAPITest
, yield
) {
460 SKIP_UNSUPPORTED_PLATFORM
;
462 buildSimpleFunction();
465 LLVMContextRef C
= LLVMGetGlobalContext();
466 LLVMContextSetYieldCallback(C
, yield
, nullptr);
469 auto *functionPointer
= reinterpret_cast<int (*)()>(
470 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine
, Function
)));
472 EXPECT_EQ(42, functionPointer());
473 EXPECT_TRUE(didCallYield
);
476 static int localTestFunc() {
480 TEST_F(MCJITCAPITest
, addGlobalMapping
) {
481 SKIP_UNSUPPORTED_PLATFORM
;
483 Module
= LLVMModuleCreateWithName("testModule");
484 LLVMSetTarget(Module
, HostTriple
.c_str());
485 LLVMTypeRef FunctionType
= LLVMFunctionType(LLVMInt32Type(), nullptr, 0, 0);
486 LLVMValueRef MappedFn
= LLVMAddFunction(Module
, "mapped_fn", FunctionType
);
488 Function
= LLVMAddFunction(Module
, "test_fn", FunctionType
);
489 LLVMBasicBlockRef Entry
= LLVMAppendBasicBlock(Function
, "");
490 LLVMBuilderRef Builder
= LLVMCreateBuilder();
491 LLVMPositionBuilderAtEnd(Builder
, Entry
);
492 LLVMValueRef RetVal
= LLVMBuildCall(Builder
, MappedFn
, nullptr, 0, "");
493 LLVMBuildRet(Builder
, RetVal
);
494 LLVMDisposeBuilder(Builder
);
496 LLVMVerifyModule(Module
, LLVMAbortProcessAction
, &Error
);
497 LLVMDisposeMessage(Error
);
502 LLVMAddGlobalMapping(
504 reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(&localTestFunc
)));
508 uint64_t raw
= LLVMGetFunctionAddress(Engine
, "test_fn");
509 int (*usable
)() = (int (*)()) raw
;
511 EXPECT_EQ(42, usable());