• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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