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 from 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/PassBuilder.h"
20 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
21 #include "llvm/Support/Debug.h"
22 #include "llvm/TargetParser/Host.h"
23 #include "gtest/gtest.h"
27 static bool didCallAllocateCodeSection
;
28 static bool didAllocateCompactUnwindSection
;
29 static bool didCallYield
;
31 static uint8_t *roundTripAllocateCodeSection(void *object
, uintptr_t size
,
34 const char *sectionName
) {
35 didCallAllocateCodeSection
= true;
36 return static_cast<SectionMemoryManager
*>(object
)->allocateCodeSection(
37 size
, alignment
, sectionID
, sectionName
);
40 static uint8_t *roundTripAllocateDataSection(void *object
, uintptr_t size
,
43 const char *sectionName
,
44 LLVMBool isReadOnly
) {
45 if (!strcmp(sectionName
, "__compact_unwind"))
46 didAllocateCompactUnwindSection
= true;
47 return static_cast<SectionMemoryManager
*>(object
)->allocateDataSection(
48 size
, alignment
, sectionID
, sectionName
, isReadOnly
);
51 static LLVMBool
roundTripFinalizeMemory(void *object
, char **errMsg
) {
52 std::string errMsgString
;
54 static_cast<SectionMemoryManager
*>(object
)->finalizeMemory(&errMsgString
);
56 *errMsg
= LLVMCreateMessage(errMsgString
.c_str());
62 static void roundTripDestroy(void *object
) {
63 delete static_cast<SectionMemoryManager
*>(object
);
66 static void yield(LLVMContextRef
, void *) {
72 // memory manager to test reserve allocation space callback
73 class TestReserveAllocationSpaceMemoryManager
: public SectionMemoryManager
{
75 uintptr_t ReservedCodeSize
;
76 uintptr_t UsedCodeSize
;
77 uintptr_t ReservedDataSizeRO
;
78 uintptr_t UsedDataSizeRO
;
79 uintptr_t ReservedDataSizeRW
;
80 uintptr_t UsedDataSizeRW
;
82 TestReserveAllocationSpaceMemoryManager() :
83 ReservedCodeSize(0), UsedCodeSize(0), ReservedDataSizeRO(0),
84 UsedDataSizeRO(0), ReservedDataSizeRW(0), UsedDataSizeRW(0) {
87 bool needsToReserveAllocationSpace() override
{ return true; }
89 void reserveAllocationSpace(uintptr_t CodeSize
, Align CodeAlign
,
90 uintptr_t DataSizeRO
, Align RODataAlign
,
92 Align RWDataAlign
) 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 LLVMTypeRef stackmapTy
=
191 LLVMFunctionType(LLVMVoidType(), stackmapParamTypes
, 2, 1);
192 LLVMValueRef stackmap
= LLVMAddFunction(
193 Module
, "llvm.experimental.stackmap", stackmapTy
);
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 LLVMBuildCall2(builder
, stackmapTy
, 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
=
234 LLVMBuildLoad2(Builder
, LLVMInt32Type(), 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 LLVMPassBuilderOptionsRef Options
= LLVMCreatePassBuilderOptions();
290 LLVMRunPasses(Module
, "instcombine", nullptr, Options
)) {
291 char *Msg
= LLVMGetErrorMessage(E
);
293 LLVMDisposePassBuilderOptions(Options
);
294 FAIL() << "Failed to run passes: " << Msg
;
297 LLVMDisposePassBuilderOptions(Options
);
300 void buildAndRunOptPasses() {
301 LLVMPassBuilderOptionsRef Options
= LLVMCreatePassBuilderOptions();
303 LLVMRunPasses(Module
, "default<O2>", nullptr, Options
)) {
304 char *Msg
= LLVMGetErrorMessage(E
);
306 LLVMDisposePassBuilderOptions(Options
);
307 FAIL() << "Failed to run passes: " << Msg
;
310 LLVMDisposePassBuilderOptions(Options
);
313 LLVMModuleRef Module
;
314 LLVMValueRef Function
;
315 LLVMValueRef Function2
;
316 LLVMMCJITCompilerOptions Options
;
317 LLVMExecutionEngineRef Engine
;
320 } // end anonymous namespace
322 TEST_F(MCJITCAPITest
, simple_function
) {
323 SKIP_UNSUPPORTED_PLATFORM
;
325 buildSimpleFunction();
330 auto *functionPointer
= reinterpret_cast<int (*)()>(
331 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine
, Function
)));
333 EXPECT_EQ(42, functionPointer());
336 TEST_F(MCJITCAPITest
, gva
) {
337 SKIP_UNSUPPORTED_PLATFORM
;
339 Module
= LLVMModuleCreateWithName("simple_module");
340 LLVMSetTarget(Module
, HostTriple
.c_str());
341 LLVMValueRef GlobalVar
= LLVMAddGlobal(Module
, LLVMInt32Type(), "simple_value");
342 LLVMSetInitializer(GlobalVar
, LLVMConstInt(LLVMInt32Type(), 42, 0));
348 uint64_t raw
= LLVMGetGlobalValueAddress(Engine
, "simple_value");
349 int32_t *usable
= (int32_t *) raw
;
351 EXPECT_EQ(42, *usable
);
354 TEST_F(MCJITCAPITest
, gfa
) {
355 SKIP_UNSUPPORTED_PLATFORM
;
357 buildSimpleFunction();
362 uint64_t raw
= LLVMGetFunctionAddress(Engine
, "simple_function");
363 int (*usable
)() = (int (*)()) raw
;
365 EXPECT_EQ(42, usable());
368 TEST_F(MCJITCAPITest
, custom_memory_manager
) {
369 SKIP_UNSUPPORTED_PLATFORM
;
371 buildSimpleFunction();
373 useRoundTripSectionMemoryManager();
377 auto *functionPointer
= reinterpret_cast<int (*)()>(
378 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine
, Function
)));
380 EXPECT_EQ(42, functionPointer());
381 EXPECT_TRUE(didCallAllocateCodeSection
);
384 TEST_F(MCJITCAPITest
, stackmap_creates_compact_unwind_on_darwin
) {
385 SKIP_UNSUPPORTED_PLATFORM
;
387 // This test is also not supported on non-x86 platforms.
388 if (Triple(HostTriple
).getArch() != Triple::x86_64
)
391 buildFunctionThatUsesStackmap();
393 useRoundTripSectionMemoryManager();
395 buildAndRunOptPasses();
397 auto *functionPointer
= reinterpret_cast<int (*)()>(
398 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine
, Function
)));
400 EXPECT_EQ(42, functionPointer());
401 EXPECT_TRUE(didCallAllocateCodeSection
);
403 // Up to this point, the test is specific only to X86-64. But this next
404 // expectation is only valid on Darwin because it assumes that unwind
405 // data is made available only through compact_unwind. It would be
406 // worthwhile to extend this to handle non-Darwin platforms, in which
407 // case you'd want to look for an eh_frame or something.
409 // FIXME: Currently, MCJIT relies on a configure-time check to determine which
410 // sections to emit. The JIT client should have runtime control over this.
412 Triple(HostTriple
).getOS() != Triple::Darwin
||
413 Triple(HostTriple
).isMacOSXVersionLT(10, 7) ||
414 didAllocateCompactUnwindSection
);
417 #if defined(__APPLE__) && defined(__aarch64__)
418 // FIXME: Figure out why this fails on mac/arm, PR46647
419 #define MAYBE_reserve_allocation_space DISABLED_reserve_allocation_space
421 #define MAYBE_reserve_allocation_space reserve_allocation_space
423 TEST_F(MCJITCAPITest
, MAYBE_reserve_allocation_space
) {
424 SKIP_UNSUPPORTED_PLATFORM
;
426 TestReserveAllocationSpaceMemoryManager
* MM
= new TestReserveAllocationSpaceMemoryManager();
428 buildModuleWithCodeAndData();
430 Options
.MCJMM
= wrap(MM
);
434 auto GetGlobalFct
= reinterpret_cast<int (*)()>(
435 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine
, Function
)));
437 auto SetGlobalFct
= reinterpret_cast<void (*)(int)>(
438 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine
, Function2
)));
441 EXPECT_EQ(789, GetGlobalFct());
442 EXPECT_LE(MM
->UsedCodeSize
, MM
->ReservedCodeSize
);
443 EXPECT_LE(MM
->UsedDataSizeRO
, MM
->ReservedDataSizeRO
);
444 EXPECT_LE(MM
->UsedDataSizeRW
, MM
->ReservedDataSizeRW
);
445 EXPECT_TRUE(MM
->UsedCodeSize
> 0);
446 EXPECT_TRUE(MM
->UsedDataSizeRW
> 0);
449 TEST_F(MCJITCAPITest
, yield
) {
450 SKIP_UNSUPPORTED_PLATFORM
;
452 buildSimpleFunction();
455 LLVMContextRef C
= LLVMGetGlobalContext();
456 LLVMContextSetYieldCallback(C
, yield
, nullptr);
459 auto *functionPointer
= reinterpret_cast<int (*)()>(
460 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine
, Function
)));
462 EXPECT_EQ(42, functionPointer());
463 EXPECT_TRUE(didCallYield
);
466 static int localTestFunc() {
470 TEST_F(MCJITCAPITest
, addGlobalMapping
) {
471 SKIP_UNSUPPORTED_PLATFORM
;
473 Module
= LLVMModuleCreateWithName("testModule");
474 LLVMSetTarget(Module
, HostTriple
.c_str());
475 LLVMTypeRef FunctionType
= LLVMFunctionType(LLVMInt32Type(), nullptr, 0, 0);
476 LLVMValueRef MappedFn
= LLVMAddFunction(Module
, "mapped_fn", FunctionType
);
478 Function
= LLVMAddFunction(Module
, "test_fn", FunctionType
);
479 LLVMBasicBlockRef Entry
= LLVMAppendBasicBlock(Function
, "");
480 LLVMBuilderRef Builder
= LLVMCreateBuilder();
481 LLVMPositionBuilderAtEnd(Builder
, Entry
);
482 LLVMValueRef RetVal
=
483 LLVMBuildCall2(Builder
, FunctionType
, MappedFn
, nullptr, 0, "");
484 LLVMBuildRet(Builder
, RetVal
);
485 LLVMDisposeBuilder(Builder
);
487 LLVMVerifyModule(Module
, LLVMAbortProcessAction
, &Error
);
488 LLVMDisposeMessage(Error
);
493 LLVMAddGlobalMapping(
495 reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(&localTestFunc
)));
499 uint64_t raw
= LLVMGetFunctionAddress(Engine
, "test_fn");
500 int (*usable
)() = (int (*)()) raw
;
502 EXPECT_EQ(42, usable());