1 //===- MCJITTest.cpp - Unit tests for the MCJIT -----------------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This test suite verifies basic MCJIT functionality when invoked form the C
11 // API.
12 //
13 //===----------------------------------------------------------------------===//
14
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"
26
27 using namespace llvm;
28
29 static bool didCallAllocateCodeSection;
30 static bool didAllocateCompactUnwindSection;
31 static bool didCallYield;
32
roundTripAllocateCodeSection(void * object,uintptr_t size,unsigned alignment,unsigned sectionID,const char * sectionName)33 static uint8_t *roundTripAllocateCodeSection(void *object, uintptr_t size,
34 unsigned alignment,
35 unsigned sectionID,
36 const char *sectionName) {
37 didCallAllocateCodeSection = true;
38 return static_cast<SectionMemoryManager*>(object)->allocateCodeSection(
39 size, alignment, sectionID, sectionName);
40 }
41
roundTripAllocateDataSection(void * object,uintptr_t size,unsigned alignment,unsigned sectionID,const char * sectionName,LLVMBool isReadOnly)42 static uint8_t *roundTripAllocateDataSection(void *object, uintptr_t size,
43 unsigned alignment,
44 unsigned sectionID,
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);
51 }
52
roundTripFinalizeMemory(void * object,char ** errMsg)53 static LLVMBool roundTripFinalizeMemory(void *object, char **errMsg) {
54 std::string errMsgString;
55 bool result =
56 static_cast<SectionMemoryManager*>(object)->finalizeMemory(&errMsgString);
57 if (result) {
58 *errMsg = LLVMCreateMessage(errMsgString.c_str());
59 return 1;
60 }
61 return 0;
62 }
63
roundTripDestroy(void * object)64 static void roundTripDestroy(void *object) {
65 delete static_cast<SectionMemoryManager*>(object);
66 }
67
yield(LLVMContextRef,void *)68 static void yield(LLVMContextRef, void *) {
69 didCallYield = true;
70 }
71
72 namespace {
73
74 // memory manager to test reserve allocation space callback
75 class TestReserveAllocationSpaceMemoryManager: public SectionMemoryManager {
76 public:
77 uintptr_t ReservedCodeSize;
78 uintptr_t UsedCodeSize;
79 uintptr_t ReservedDataSizeRO;
80 uintptr_t UsedDataSizeRO;
81 uintptr_t ReservedDataSizeRW;
82 uintptr_t UsedDataSizeRW;
83
TestReserveAllocationSpaceMemoryManager()84 TestReserveAllocationSpaceMemoryManager() :
85 ReservedCodeSize(0), UsedCodeSize(0), ReservedDataSizeRO(0),
86 UsedDataSizeRO(0), ReservedDataSizeRW(0), UsedDataSizeRW(0) {
87 }
88
needsToReserveAllocationSpace()89 bool needsToReserveAllocationSpace() override { return true; }
90
reserveAllocationSpace(uintptr_t CodeSize,uint32_t CodeAlign,uintptr_t DataSizeRO,uint32_t RODataAlign,uintptr_t DataSizeRW,uint32_t RWDataAlign)91 void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign,
92 uintptr_t DataSizeRO, uint32_t RODataAlign,
93 uintptr_t DataSizeRW,
94 uint32_t RWDataAlign) override {
95 ReservedCodeSize = CodeSize;
96 ReservedDataSizeRO = DataSizeRO;
97 ReservedDataSizeRW = DataSizeRW;
98 }
99
useSpace(uintptr_t * UsedSize,uintptr_t Size,unsigned Alignment)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;
104 }
105
allocateDataSection(uintptr_t Size,unsigned Alignment,unsigned SectionID,StringRef SectionName,bool IsReadOnly)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);
112 }
113
allocateCodeSection(uintptr_t Size,unsigned Alignment,unsigned SectionID,StringRef SectionName)114 uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
115 unsigned SectionID,
116 StringRef SectionName) override {
117 useSpace(&UsedCodeSize, Size, Alignment);
118 return SectionMemoryManager::allocateCodeSection(Size, Alignment,
119 SectionID, SectionName);
120 }
121 };
122
123 class MCJITCAPITest : public testing::Test, public MCJITTestAPICommon {
124 protected:
MCJITCAPITest()125 MCJITCAPITest() {
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
128 // kept in sync.
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);
136
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");
143
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);
147 }
148
SetUp()149 void SetUp() override {
150 didCallAllocateCodeSection = false;
151 didAllocateCompactUnwindSection = false;
152 didCallYield = false;
153 Module = nullptr;
154 Function = nullptr;
155 Engine = nullptr;
156 Error = nullptr;
157 }
158
TearDown()159 void TearDown() override {
160 if (Engine)
161 LLVMDisposeExecutionEngine(Engine);
162 else if (Module)
163 LLVMDisposeModule(Module);
164 }
165
buildSimpleFunction()166 void buildSimpleFunction() {
167 Module = LLVMModuleCreateWithName("simple_module");
168
169 LLVMSetTarget(Module, HostTriple.c_str());
170
171 Function = LLVMAddFunction(Module, "simple_function",
172 LLVMFunctionType(LLVMInt32Type(), nullptr,0, 0));
173 LLVMSetFunctionCallConv(Function, LLVMCCallConv);
174
175 LLVMBasicBlockRef entry = LLVMAppendBasicBlock(Function, "entry");
176 LLVMBuilderRef builder = LLVMCreateBuilder();
177 LLVMPositionBuilderAtEnd(builder, entry);
178 LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0));
179
180 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
181 LLVMDisposeMessage(Error);
182
183 LLVMDisposeBuilder(builder);
184 }
185
buildFunctionThatUsesStackmap()186 void buildFunctionThatUsesStackmap() {
187 Module = LLVMModuleCreateWithName("simple_module");
188
189 LLVMSetTarget(Module, HostTriple.c_str());
190
191 LLVMTypeRef stackmapParamTypes[] = { LLVMInt64Type(), LLVMInt32Type() };
192 LLVMValueRef stackmap = LLVMAddFunction(
193 Module, "llvm.experimental.stackmap",
194 LLVMFunctionType(LLVMVoidType(), stackmapParamTypes, 2, 1));
195 LLVMSetLinkage(stackmap, LLVMExternalLinkage);
196
197 Function = LLVMAddFunction(Module, "simple_function",
198 LLVMFunctionType(LLVMInt32Type(), nullptr, 0, 0));
199
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)
206 };
207 LLVMBuildCall(builder, stackmap, stackmapArgs, 3, "");
208 LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0));
209
210 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
211 LLVMDisposeMessage(Error);
212
213 LLVMDisposeBuilder(builder);
214 }
215
buildModuleWithCodeAndData()216 void buildModuleWithCodeAndData() {
217 Module = LLVMModuleCreateWithName("simple_module");
218
219 LLVMSetTarget(Module, HostTriple.c_str());
220
221 // build a global int32 variable initialized to 42.
222 LLVMValueRef GlobalVar = LLVMAddGlobal(Module, LLVMInt32Type(), "intVal");
223 LLVMSetInitializer(GlobalVar, LLVMConstInt(LLVMInt32Type(), 42, 0));
224
225 {
226 Function = LLVMAddFunction(Module, "getGlobal",
227 LLVMFunctionType(LLVMInt32Type(), nullptr, 0, 0));
228 LLVMSetFunctionCallConv(Function, LLVMCCallConv);
229
230 LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function, "entry");
231 LLVMBuilderRef Builder = LLVMCreateBuilder();
232 LLVMPositionBuilderAtEnd(Builder, Entry);
233
234 LLVMValueRef IntVal = LLVMBuildLoad(Builder, GlobalVar, "intVal");
235 LLVMBuildRet(Builder, IntVal);
236
237 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
238 LLVMDisposeMessage(Error);
239
240 LLVMDisposeBuilder(Builder);
241 }
242
243 {
244 LLVMTypeRef ParamTypes[] = { LLVMInt32Type() };
245 Function2 = LLVMAddFunction(
246 Module, "setGlobal", LLVMFunctionType(LLVMVoidType(), ParamTypes, 1, 0));
247 LLVMSetFunctionCallConv(Function2, LLVMCCallConv);
248
249 LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function2, "entry");
250 LLVMBuilderRef Builder = LLVMCreateBuilder();
251 LLVMPositionBuilderAtEnd(Builder, Entry);
252
253 LLVMValueRef Arg = LLVMGetParam(Function2, 0);
254 LLVMBuildStore(Builder, Arg, GlobalVar);
255 LLVMBuildRetVoid(Builder);
256
257 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
258 LLVMDisposeMessage(Error);
259
260 LLVMDisposeBuilder(Builder);
261 }
262 }
263
buildMCJITOptions()264 void buildMCJITOptions() {
265 LLVMInitializeMCJITCompilerOptions(&Options, sizeof(Options));
266 Options.OptLevel = 2;
267
268 // Just ensure that this field still exists.
269 Options.NoFramePointerElim = false;
270 }
271
useRoundTripSectionMemoryManager()272 void useRoundTripSectionMemoryManager() {
273 Options.MCJMM = LLVMCreateSimpleMCJITMemoryManager(
274 new SectionMemoryManager(),
275 roundTripAllocateCodeSection,
276 roundTripAllocateDataSection,
277 roundTripFinalizeMemory,
278 roundTripDestroy);
279 }
280
buildMCJITEngine()281 void buildMCJITEngine() {
282 ASSERT_EQ(
283 0, LLVMCreateMCJITCompilerForModule(&Engine, Module, &Options,
284 sizeof(Options), &Error));
285 }
286
buildAndRunPasses()287 void buildAndRunPasses() {
288 LLVMPassManagerRef pass = LLVMCreatePassManager();
289 LLVMAddConstantPropagationPass(pass);
290 LLVMAddInstructionCombiningPass(pass);
291 LLVMRunPassManager(pass, Module);
292 LLVMDisposePassManager(pass);
293 }
294
buildAndRunOptPasses()295 void buildAndRunOptPasses() {
296 LLVMPassManagerBuilderRef passBuilder;
297
298 passBuilder = LLVMPassManagerBuilderCreate();
299 LLVMPassManagerBuilderSetOptLevel(passBuilder, 2);
300 LLVMPassManagerBuilderSetSizeLevel(passBuilder, 0);
301
302 LLVMPassManagerRef functionPasses =
303 LLVMCreateFunctionPassManagerForModule(Module);
304 LLVMPassManagerRef modulePasses =
305 LLVMCreatePassManager();
306
307 LLVMPassManagerBuilderPopulateFunctionPassManager(passBuilder,
308 functionPasses);
309 LLVMPassManagerBuilderPopulateModulePassManager(passBuilder, modulePasses);
310
311 LLVMPassManagerBuilderDispose(passBuilder);
312
313 LLVMInitializeFunctionPassManager(functionPasses);
314 for (LLVMValueRef value = LLVMGetFirstFunction(Module);
315 value; value = LLVMGetNextFunction(value))
316 LLVMRunFunctionPassManager(functionPasses, value);
317 LLVMFinalizeFunctionPassManager(functionPasses);
318
319 LLVMRunPassManager(modulePasses, Module);
320
321 LLVMDisposePassManager(functionPasses);
322 LLVMDisposePassManager(modulePasses);
323 }
324
325 LLVMModuleRef Module;
326 LLVMValueRef Function;
327 LLVMValueRef Function2;
328 LLVMMCJITCompilerOptions Options;
329 LLVMExecutionEngineRef Engine;
330 char *Error;
331 };
332 } // end anonymous namespace
333
TEST_F(MCJITCAPITest,simple_function)334 TEST_F(MCJITCAPITest, simple_function) {
335 SKIP_UNSUPPORTED_PLATFORM;
336
337 buildSimpleFunction();
338 buildMCJITOptions();
339 buildMCJITEngine();
340 buildAndRunPasses();
341
342 auto *functionPointer = reinterpret_cast<int (*)()>(
343 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine, Function)));
344
345 EXPECT_EQ(42, functionPointer());
346 }
347
TEST_F(MCJITCAPITest,gva)348 TEST_F(MCJITCAPITest, gva) {
349 SKIP_UNSUPPORTED_PLATFORM;
350
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));
355
356 buildMCJITOptions();
357 buildMCJITEngine();
358 buildAndRunPasses();
359
360 uint64_t raw = LLVMGetGlobalValueAddress(Engine, "simple_value");
361 int32_t *usable = (int32_t *) raw;
362
363 EXPECT_EQ(42, *usable);
364 }
365
TEST_F(MCJITCAPITest,gfa)366 TEST_F(MCJITCAPITest, gfa) {
367 SKIP_UNSUPPORTED_PLATFORM;
368
369 buildSimpleFunction();
370 buildMCJITOptions();
371 buildMCJITEngine();
372 buildAndRunPasses();
373
374 uint64_t raw = LLVMGetFunctionAddress(Engine, "simple_function");
375 int (*usable)() = (int (*)()) raw;
376
377 EXPECT_EQ(42, usable());
378 }
379
TEST_F(MCJITCAPITest,custom_memory_manager)380 TEST_F(MCJITCAPITest, custom_memory_manager) {
381 SKIP_UNSUPPORTED_PLATFORM;
382
383 buildSimpleFunction();
384 buildMCJITOptions();
385 useRoundTripSectionMemoryManager();
386 buildMCJITEngine();
387 buildAndRunPasses();
388
389 auto *functionPointer = reinterpret_cast<int (*)()>(
390 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine, Function)));
391
392 EXPECT_EQ(42, functionPointer());
393 EXPECT_TRUE(didCallAllocateCodeSection);
394 }
395
TEST_F(MCJITCAPITest,stackmap_creates_compact_unwind_on_darwin)396 TEST_F(MCJITCAPITest, stackmap_creates_compact_unwind_on_darwin) {
397 SKIP_UNSUPPORTED_PLATFORM;
398
399 // This test is also not supported on non-x86 platforms.
400 if (Triple(HostTriple).getArch() != Triple::x86_64)
401 return;
402
403 buildFunctionThatUsesStackmap();
404 buildMCJITOptions();
405 useRoundTripSectionMemoryManager();
406 buildMCJITEngine();
407 buildAndRunOptPasses();
408
409 auto *functionPointer = reinterpret_cast<int (*)()>(
410 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine, Function)));
411
412 EXPECT_EQ(42, functionPointer());
413 EXPECT_TRUE(didCallAllocateCodeSection);
414
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.
420 //
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.
423 EXPECT_TRUE(
424 Triple(HostTriple).getOS() != Triple::Darwin ||
425 Triple(HostTriple).isMacOSXVersionLT(10, 7) ||
426 didAllocateCompactUnwindSection);
427 }
428
TEST_F(MCJITCAPITest,reserve_allocation_space)429 TEST_F(MCJITCAPITest, reserve_allocation_space) {
430 SKIP_UNSUPPORTED_PLATFORM;
431
432 TestReserveAllocationSpaceMemoryManager* MM = new TestReserveAllocationSpaceMemoryManager();
433
434 buildModuleWithCodeAndData();
435 buildMCJITOptions();
436 Options.MCJMM = wrap(MM);
437 buildMCJITEngine();
438 buildAndRunPasses();
439
440 auto GetGlobalFct = reinterpret_cast<int (*)()>(
441 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine, Function)));
442
443 auto SetGlobalFct = reinterpret_cast<void (*)(int)>(
444 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine, Function2)));
445
446 SetGlobalFct(789);
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);
453 }
454
TEST_F(MCJITCAPITest,yield)455 TEST_F(MCJITCAPITest, yield) {
456 SKIP_UNSUPPORTED_PLATFORM;
457
458 buildSimpleFunction();
459 buildMCJITOptions();
460 buildMCJITEngine();
461 LLVMContextRef C = LLVMGetGlobalContext();
462 LLVMContextSetYieldCallback(C, yield, nullptr);
463 buildAndRunPasses();
464
465 auto *functionPointer = reinterpret_cast<int (*)()>(
466 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine, Function)));
467
468 EXPECT_EQ(42, functionPointer());
469 EXPECT_TRUE(didCallYield);
470 }
471
localTestFunc()472 static int localTestFunc() {
473 return 42;
474 }
475
TEST_F(MCJITCAPITest,addGlobalMapping)476 TEST_F(MCJITCAPITest, addGlobalMapping) {
477 SKIP_UNSUPPORTED_PLATFORM;
478
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);
483
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);
491
492 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
493 LLVMDisposeMessage(Error);
494
495 buildMCJITOptions();
496 buildMCJITEngine();
497
498 LLVMAddGlobalMapping(
499 Engine, MappedFn,
500 reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(&localTestFunc)));
501
502 buildAndRunPasses();
503
504 uint64_t raw = LLVMGetFunctionAddress(Engine, "test_fn");
505 int (*usable)() = (int (*)()) raw;
506
507 EXPECT_EQ(42, usable());
508 }
509