1 //===- MCJITTest.cpp - Unit tests for the MCJIT ---------------------------===//
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 "llvm-c/Analysis.h"
16 #include "MCJITTestAPICommon.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 virtual bool needsToReserveAllocationSpace() {
90 return true;
91 }
92
reserveAllocationSpace(uintptr_t CodeSize,uintptr_t DataSizeRO,uintptr_t DataSizeRW)93 virtual void reserveAllocationSpace(
94 uintptr_t CodeSize, uintptr_t DataSizeRO, uintptr_t DataSizeRW) {
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 virtual uint8_t* allocateDataSection(uintptr_t Size, unsigned Alignment,
107 unsigned SectionID, StringRef SectionName, bool IsReadOnly) {
108 useSpace(IsReadOnly ? &UsedDataSizeRO : &UsedDataSizeRW, Size, Alignment);
109 return SectionMemoryManager::allocateDataSection(Size, Alignment,
110 SectionID, SectionName, IsReadOnly);
111 }
112
allocateCodeSection(uintptr_t Size,unsigned Alignment,unsigned SectionID,StringRef SectionName)113 uint8_t* allocateCodeSection(uintptr_t Size, unsigned Alignment,
114 unsigned SectionID, StringRef SectionName) {
115 useSpace(&UsedCodeSize, Size, Alignment);
116 return SectionMemoryManager::allocateCodeSection(Size, Alignment,
117 SectionID, SectionName);
118 }
119 };
120
121 class MCJITCAPITest : public testing::Test, public MCJITTestAPICommon {
122 protected:
MCJITCAPITest()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::x86);
131 SupportedArchs.push_back(Triple::x86_64);
132
133 // Some architectures have sub-architectures in which tests will fail, like
134 // ARM. These two vectors will define if they do have sub-archs (to avoid
135 // extra work for those who don't), and if so, if they are listed to work
136 HasSubArchs.push_back(Triple::arm);
137 SupportedSubArchs.push_back("armv6");
138 SupportedSubArchs.push_back("armv7");
139
140 // The operating systems below are known to be sufficiently incompatible
141 // that they will fail the MCJIT C API tests.
142 UnsupportedEnvironments.push_back(Triple::Cygnus);
143 }
144
SetUp()145 virtual void SetUp() {
146 didCallAllocateCodeSection = false;
147 didAllocateCompactUnwindSection = false;
148 didCallYield = false;
149 Module = nullptr;
150 Function = nullptr;
151 Engine = nullptr;
152 Error = nullptr;
153 }
154
TearDown()155 virtual void TearDown() {
156 if (Engine)
157 LLVMDisposeExecutionEngine(Engine);
158 else if (Module)
159 LLVMDisposeModule(Module);
160 }
161
buildSimpleFunction()162 void buildSimpleFunction() {
163 Module = LLVMModuleCreateWithName("simple_module");
164
165 LLVMSetTarget(Module, HostTriple.c_str());
166
167 Function = LLVMAddFunction(Module, "simple_function",
168 LLVMFunctionType(LLVMInt32Type(), nullptr,0, 0));
169 LLVMSetFunctionCallConv(Function, LLVMCCallConv);
170
171 LLVMBasicBlockRef entry = LLVMAppendBasicBlock(Function, "entry");
172 LLVMBuilderRef builder = LLVMCreateBuilder();
173 LLVMPositionBuilderAtEnd(builder, entry);
174 LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0));
175
176 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
177 LLVMDisposeMessage(Error);
178
179 LLVMDisposeBuilder(builder);
180 }
181
buildFunctionThatUsesStackmap()182 void buildFunctionThatUsesStackmap() {
183 Module = LLVMModuleCreateWithName("simple_module");
184
185 LLVMSetTarget(Module, HostTriple.c_str());
186
187 LLVMTypeRef stackmapParamTypes[] = { LLVMInt64Type(), LLVMInt32Type() };
188 LLVMValueRef stackmap = LLVMAddFunction(
189 Module, "llvm.experimental.stackmap",
190 LLVMFunctionType(LLVMVoidType(), stackmapParamTypes, 2, 1));
191 LLVMSetLinkage(stackmap, LLVMExternalLinkage);
192
193 Function = LLVMAddFunction(Module, "simple_function",
194 LLVMFunctionType(LLVMInt32Type(), nullptr, 0, 0));
195
196 LLVMBasicBlockRef entry = LLVMAppendBasicBlock(Function, "entry");
197 LLVMBuilderRef builder = LLVMCreateBuilder();
198 LLVMPositionBuilderAtEnd(builder, entry);
199 LLVMValueRef stackmapArgs[] = {
200 LLVMConstInt(LLVMInt64Type(), 0, 0), LLVMConstInt(LLVMInt32Type(), 5, 0),
201 LLVMConstInt(LLVMInt32Type(), 42, 0)
202 };
203 LLVMBuildCall(builder, stackmap, stackmapArgs, 3, "");
204 LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0));
205
206 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
207 LLVMDisposeMessage(Error);
208
209 LLVMDisposeBuilder(builder);
210 }
211
buildModuleWithCodeAndData()212 void buildModuleWithCodeAndData() {
213 Module = LLVMModuleCreateWithName("simple_module");
214
215 LLVMSetTarget(Module, HostTriple.c_str());
216
217 // build a global int32 variable initialized to 42.
218 LLVMValueRef GlobalVar = LLVMAddGlobal(Module, LLVMInt32Type(), "intVal");
219 LLVMSetInitializer(GlobalVar, LLVMConstInt(LLVMInt32Type(), 42, 0));
220
221 {
222 Function = LLVMAddFunction(Module, "getGlobal",
223 LLVMFunctionType(LLVMInt32Type(), nullptr, 0, 0));
224 LLVMSetFunctionCallConv(Function, LLVMCCallConv);
225
226 LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function, "entry");
227 LLVMBuilderRef Builder = LLVMCreateBuilder();
228 LLVMPositionBuilderAtEnd(Builder, Entry);
229
230 LLVMValueRef IntVal = LLVMBuildLoad(Builder, GlobalVar, "intVal");
231 LLVMBuildRet(Builder, IntVal);
232
233 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
234 LLVMDisposeMessage(Error);
235
236 LLVMDisposeBuilder(Builder);
237 }
238
239 {
240 LLVMTypeRef ParamTypes[] = { LLVMInt32Type() };
241 Function2 = LLVMAddFunction(
242 Module, "setGlobal", LLVMFunctionType(LLVMVoidType(), ParamTypes, 1, 0));
243 LLVMSetFunctionCallConv(Function2, LLVMCCallConv);
244
245 LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function2, "entry");
246 LLVMBuilderRef Builder = LLVMCreateBuilder();
247 LLVMPositionBuilderAtEnd(Builder, Entry);
248
249 LLVMValueRef Arg = LLVMGetParam(Function2, 0);
250 LLVMBuildStore(Builder, Arg, GlobalVar);
251 LLVMBuildRetVoid(Builder);
252
253 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
254 LLVMDisposeMessage(Error);
255
256 LLVMDisposeBuilder(Builder);
257 }
258 }
259
buildMCJITOptions()260 void buildMCJITOptions() {
261 LLVMInitializeMCJITCompilerOptions(&Options, sizeof(Options));
262 Options.OptLevel = 2;
263
264 // Just ensure that this field still exists.
265 Options.NoFramePointerElim = false;
266 }
267
useRoundTripSectionMemoryManager()268 void useRoundTripSectionMemoryManager() {
269 Options.MCJMM = LLVMCreateSimpleMCJITMemoryManager(
270 new SectionMemoryManager(),
271 roundTripAllocateCodeSection,
272 roundTripAllocateDataSection,
273 roundTripFinalizeMemory,
274 roundTripDestroy);
275 }
276
buildMCJITEngine()277 void buildMCJITEngine() {
278 ASSERT_EQ(
279 0, LLVMCreateMCJITCompilerForModule(&Engine, Module, &Options,
280 sizeof(Options), &Error));
281 }
282
buildAndRunPasses()283 void buildAndRunPasses() {
284 LLVMPassManagerRef pass = LLVMCreatePassManager();
285 LLVMAddTargetData(LLVMGetExecutionEngineTargetData(Engine), pass);
286 LLVMAddConstantPropagationPass(pass);
287 LLVMAddInstructionCombiningPass(pass);
288 LLVMRunPassManager(pass, Module);
289 LLVMDisposePassManager(pass);
290 }
291
buildAndRunOptPasses()292 void buildAndRunOptPasses() {
293 LLVMPassManagerBuilderRef passBuilder;
294
295 passBuilder = LLVMPassManagerBuilderCreate();
296 LLVMPassManagerBuilderSetOptLevel(passBuilder, 2);
297 LLVMPassManagerBuilderSetSizeLevel(passBuilder, 0);
298
299 LLVMPassManagerRef functionPasses =
300 LLVMCreateFunctionPassManagerForModule(Module);
301 LLVMPassManagerRef modulePasses =
302 LLVMCreatePassManager();
303
304 LLVMAddTargetData(LLVMGetExecutionEngineTargetData(Engine), modulePasses);
305
306 LLVMPassManagerBuilderPopulateFunctionPassManager(passBuilder,
307 functionPasses);
308 LLVMPassManagerBuilderPopulateModulePassManager(passBuilder, modulePasses);
309
310 LLVMPassManagerBuilderDispose(passBuilder);
311
312 LLVMInitializeFunctionPassManager(functionPasses);
313 for (LLVMValueRef value = LLVMGetFirstFunction(Module);
314 value; value = LLVMGetNextFunction(value))
315 LLVMRunFunctionPassManager(functionPasses, value);
316 LLVMFinalizeFunctionPassManager(functionPasses);
317
318 LLVMRunPassManager(modulePasses, Module);
319
320 LLVMDisposePassManager(functionPasses);
321 LLVMDisposePassManager(modulePasses);
322 }
323
324 LLVMModuleRef Module;
325 LLVMValueRef Function;
326 LLVMValueRef Function2;
327 LLVMMCJITCompilerOptions Options;
328 LLVMExecutionEngineRef Engine;
329 char *Error;
330 };
331 } // end anonymous namespace
332
TEST_F(MCJITCAPITest,simple_function)333 TEST_F(MCJITCAPITest, simple_function) {
334 SKIP_UNSUPPORTED_PLATFORM;
335
336 buildSimpleFunction();
337 buildMCJITOptions();
338 buildMCJITEngine();
339 buildAndRunPasses();
340
341 union {
342 void *raw;
343 int (*usable)();
344 } functionPointer;
345 functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function);
346
347 EXPECT_EQ(42, functionPointer.usable());
348 }
349
TEST_F(MCJITCAPITest,gva)350 TEST_F(MCJITCAPITest, gva) {
351 SKIP_UNSUPPORTED_PLATFORM;
352
353 Module = LLVMModuleCreateWithName("simple_module");
354 LLVMSetTarget(Module, HostTriple.c_str());
355 LLVMValueRef GlobalVar = LLVMAddGlobal(Module, LLVMInt32Type(), "simple_value");
356 LLVMSetInitializer(GlobalVar, LLVMConstInt(LLVMInt32Type(), 42, 0));
357
358 buildMCJITOptions();
359 buildMCJITEngine();
360 buildAndRunPasses();
361
362 uint64_t raw = LLVMGetGlobalValueAddress(Engine, "simple_value");
363 int32_t *usable = (int32_t *) raw;
364
365 EXPECT_EQ(42, *usable);
366 }
367
TEST_F(MCJITCAPITest,gfa)368 TEST_F(MCJITCAPITest, gfa) {
369 SKIP_UNSUPPORTED_PLATFORM;
370
371 buildSimpleFunction();
372 buildMCJITOptions();
373 buildMCJITEngine();
374 buildAndRunPasses();
375
376 uint64_t raw = LLVMGetFunctionAddress(Engine, "simple_function");
377 int (*usable)() = (int (*)()) raw;
378
379 EXPECT_EQ(42, usable());
380 }
381
TEST_F(MCJITCAPITest,custom_memory_manager)382 TEST_F(MCJITCAPITest, custom_memory_manager) {
383 SKIP_UNSUPPORTED_PLATFORM;
384
385 buildSimpleFunction();
386 buildMCJITOptions();
387 useRoundTripSectionMemoryManager();
388 buildMCJITEngine();
389 buildAndRunPasses();
390
391 union {
392 void *raw;
393 int (*usable)();
394 } functionPointer;
395 functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function);
396
397 EXPECT_EQ(42, functionPointer.usable());
398 EXPECT_TRUE(didCallAllocateCodeSection);
399 }
400
TEST_F(MCJITCAPITest,stackmap_creates_compact_unwind_on_darwin)401 TEST_F(MCJITCAPITest, stackmap_creates_compact_unwind_on_darwin) {
402 SKIP_UNSUPPORTED_PLATFORM;
403
404 // This test is also not supported on non-x86 platforms.
405 if (Triple(HostTriple).getArch() != Triple::x86_64)
406 return;
407
408 buildFunctionThatUsesStackmap();
409 buildMCJITOptions();
410 useRoundTripSectionMemoryManager();
411 buildMCJITEngine();
412 buildAndRunOptPasses();
413
414 union {
415 void *raw;
416 int (*usable)();
417 } functionPointer;
418 functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function);
419
420 EXPECT_EQ(42, functionPointer.usable());
421 EXPECT_TRUE(didCallAllocateCodeSection);
422
423 // Up to this point, the test is specific only to X86-64. But this next
424 // expectation is only valid on Darwin because it assumes that unwind
425 // data is made available only through compact_unwind. It would be
426 // worthwhile to extend this to handle non-Darwin platforms, in which
427 // case you'd want to look for an eh_frame or something.
428 //
429 // FIXME: Currently, MCJIT relies on a configure-time check to determine which
430 // sections to emit. The JIT client should have runtime control over this.
431 EXPECT_TRUE(
432 Triple(HostTriple).getOS() != Triple::Darwin ||
433 Triple(HostTriple).isMacOSXVersionLT(10, 7) ||
434 didAllocateCompactUnwindSection);
435 }
436
TEST_F(MCJITCAPITest,reserve_allocation_space)437 TEST_F(MCJITCAPITest, reserve_allocation_space) {
438 SKIP_UNSUPPORTED_PLATFORM;
439
440 TestReserveAllocationSpaceMemoryManager* MM = new TestReserveAllocationSpaceMemoryManager();
441
442 buildModuleWithCodeAndData();
443 buildMCJITOptions();
444 Options.MCJMM = wrap(MM);
445 buildMCJITEngine();
446 buildAndRunPasses();
447
448 union {
449 void *raw;
450 int (*usable)();
451 } GetGlobalFct;
452 GetGlobalFct.raw = LLVMGetPointerToGlobal(Engine, Function);
453
454 union {
455 void *raw;
456 void (*usable)(int);
457 } SetGlobalFct;
458 SetGlobalFct.raw = LLVMGetPointerToGlobal(Engine, Function2);
459
460 SetGlobalFct.usable(789);
461 EXPECT_EQ(789, GetGlobalFct.usable());
462 EXPECT_LE(MM->UsedCodeSize, MM->ReservedCodeSize);
463 EXPECT_LE(MM->UsedDataSizeRO, MM->ReservedDataSizeRO);
464 EXPECT_LE(MM->UsedDataSizeRW, MM->ReservedDataSizeRW);
465 EXPECT_TRUE(MM->UsedCodeSize > 0);
466 EXPECT_TRUE(MM->UsedDataSizeRW > 0);
467 }
468
TEST_F(MCJITCAPITest,yield)469 TEST_F(MCJITCAPITest, yield) {
470 SKIP_UNSUPPORTED_PLATFORM;
471
472 buildSimpleFunction();
473 buildMCJITOptions();
474 buildMCJITEngine();
475 LLVMContextRef C = LLVMGetGlobalContext();
476 LLVMContextSetYieldCallback(C, yield, nullptr);
477 buildAndRunPasses();
478
479 union {
480 void *raw;
481 int (*usable)();
482 } functionPointer;
483 functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function);
484
485 EXPECT_EQ(42, functionPointer.usable());
486 EXPECT_TRUE(didCallYield);
487 }
488
489