[clangd] Fix warnings
[llvm-project.git] / llvm / unittests / ExecutionEngine / MCJIT / MCJITCAPITest.cpp
blob8a4924fa92723f4b97a1e346516e901be55c6ba5
1 //===- MCJITTest.cpp - Unit tests for the MCJIT -----------------*- C++ -*-===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This test suite verifies basic MCJIT functionality when invoked from the C
10 // API.
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"
25 using namespace llvm;
27 static bool didCallAllocateCodeSection;
28 static bool didAllocateCompactUnwindSection;
29 static bool didCallYield;
31 static uint8_t *roundTripAllocateCodeSection(void *object, uintptr_t size,
32 unsigned alignment,
33 unsigned sectionID,
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,
41 unsigned alignment,
42 unsigned sectionID,
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;
53 bool result =
54 static_cast<SectionMemoryManager*>(object)->finalizeMemory(&errMsgString);
55 if (result) {
56 *errMsg = LLVMCreateMessage(errMsgString.c_str());
57 return 1;
59 return 0;
62 static void roundTripDestroy(void *object) {
63 delete static_cast<SectionMemoryManager*>(object);
66 static void yield(LLVMContextRef, void *) {
67 didCallYield = true;
70 namespace {
72 // memory manager to test reserve allocation space callback
73 class TestReserveAllocationSpaceMemoryManager: public SectionMemoryManager {
74 public:
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,
91 uintptr_t DataSizeRW,
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,
113 unsigned SectionID,
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 {
122 protected:
123 MCJITCAPITest() {
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
126 // kept in sync.
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;
151 Module = nullptr;
152 Function = nullptr;
153 Engine = nullptr;
154 Error = nullptr;
157 void TearDown() override {
158 if (Engine)
159 LLVMDisposeExecutionEngine(Engine);
160 else if (Module)
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,
278 roundTripDestroy);
281 void buildMCJITEngine() {
282 ASSERT_EQ(
283 0, LLVMCreateMCJITCompilerForModule(&Engine, Module, &Options,
284 sizeof(Options), &Error));
287 void buildAndRunPasses() {
288 LLVMPassBuilderOptionsRef Options = LLVMCreatePassBuilderOptions();
289 if (LLVMErrorRef E =
290 LLVMRunPasses(Module, "instcombine", nullptr, Options)) {
291 char *Msg = LLVMGetErrorMessage(E);
292 LLVMConsumeError(E);
293 LLVMDisposePassBuilderOptions(Options);
294 FAIL() << "Failed to run passes: " << Msg;
297 LLVMDisposePassBuilderOptions(Options);
300 void buildAndRunOptPasses() {
301 LLVMPassBuilderOptionsRef Options = LLVMCreatePassBuilderOptions();
302 if (LLVMErrorRef E =
303 LLVMRunPasses(Module, "default<O2>", nullptr, Options)) {
304 char *Msg = LLVMGetErrorMessage(E);
305 LLVMConsumeError(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;
318 char *Error;
320 } // end anonymous namespace
322 TEST_F(MCJITCAPITest, simple_function) {
323 SKIP_UNSUPPORTED_PLATFORM;
325 buildSimpleFunction();
326 buildMCJITOptions();
327 buildMCJITEngine();
328 buildAndRunPasses();
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));
344 buildMCJITOptions();
345 buildMCJITEngine();
346 buildAndRunPasses();
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();
358 buildMCJITOptions();
359 buildMCJITEngine();
360 buildAndRunPasses();
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();
372 buildMCJITOptions();
373 useRoundTripSectionMemoryManager();
374 buildMCJITEngine();
375 buildAndRunPasses();
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)
389 GTEST_SKIP();
391 buildFunctionThatUsesStackmap();
392 buildMCJITOptions();
393 useRoundTripSectionMemoryManager();
394 buildMCJITEngine();
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.
411 EXPECT_TRUE(
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
420 #else
421 #define MAYBE_reserve_allocation_space reserve_allocation_space
422 #endif
423 TEST_F(MCJITCAPITest, MAYBE_reserve_allocation_space) {
424 SKIP_UNSUPPORTED_PLATFORM;
426 TestReserveAllocationSpaceMemoryManager* MM = new TestReserveAllocationSpaceMemoryManager();
428 buildModuleWithCodeAndData();
429 buildMCJITOptions();
430 Options.MCJMM = wrap(MM);
431 buildMCJITEngine();
432 buildAndRunPasses();
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)));
440 SetGlobalFct(789);
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();
453 buildMCJITOptions();
454 buildMCJITEngine();
455 LLVMContextRef C = LLVMGetGlobalContext();
456 LLVMContextSetYieldCallback(C, yield, nullptr);
457 buildAndRunPasses();
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() {
467 return 42;
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);
490 buildMCJITOptions();
491 buildMCJITEngine();
493 LLVMAddGlobalMapping(
494 Engine, MappedFn,
495 reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(&localTestFunc)));
497 buildAndRunPasses();
499 uint64_t raw = LLVMGetFunctionAddress(Engine, "test_fn");
500 int (*usable)() = (int (*)()) raw;
502 EXPECT_EQ(42, usable());