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 form the C
10 // API.
11 //
12 //===----------------------------------------------------------------------===//
13 
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/PassManagerBuilder.h"
20 #include "llvm-c/Transforms/Scalar.h"
21 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
22 #include "llvm/Support/Debug.h"
23 #include "llvm/Support/Host.h"
24 #include "gtest/gtest.h"
25 
26 using namespace llvm;
27 
28 static bool didCallAllocateCodeSection;
29 static bool didAllocateCompactUnwindSection;
30 static bool didCallYield;
31 
roundTripAllocateCodeSection(void * object,uintptr_t size,unsigned alignment,unsigned sectionID,const char * sectionName)32 static uint8_t *roundTripAllocateCodeSection(void *object, uintptr_t size,
33                                              unsigned alignment,
34                                              unsigned sectionID,
35                                              const char *sectionName) {
36   didCallAllocateCodeSection = true;
37   return static_cast<SectionMemoryManager*>(object)->allocateCodeSection(
38     size, alignment, sectionID, sectionName);
39 }
40 
roundTripAllocateDataSection(void * object,uintptr_t size,unsigned alignment,unsigned sectionID,const char * sectionName,LLVMBool isReadOnly)41 static uint8_t *roundTripAllocateDataSection(void *object, uintptr_t size,
42                                              unsigned alignment,
43                                              unsigned sectionID,
44                                              const char *sectionName,
45                                              LLVMBool isReadOnly) {
46   if (!strcmp(sectionName, "__compact_unwind"))
47     didAllocateCompactUnwindSection = true;
48   return static_cast<SectionMemoryManager*>(object)->allocateDataSection(
49     size, alignment, sectionID, sectionName, isReadOnly);
50 }
51 
roundTripFinalizeMemory(void * object,char ** errMsg)52 static LLVMBool roundTripFinalizeMemory(void *object, char **errMsg) {
53   std::string errMsgString;
54   bool result =
55     static_cast<SectionMemoryManager*>(object)->finalizeMemory(&errMsgString);
56   if (result) {
57     *errMsg = LLVMCreateMessage(errMsgString.c_str());
58     return 1;
59   }
60   return 0;
61 }
62 
roundTripDestroy(void * object)63 static void roundTripDestroy(void *object) {
64   delete static_cast<SectionMemoryManager*>(object);
65 }
66 
yield(LLVMContextRef,void *)67 static void yield(LLVMContextRef, void *) {
68   didCallYield = true;
69 }
70 
71 namespace {
72 
73 // memory manager to test reserve allocation space callback
74 class TestReserveAllocationSpaceMemoryManager: public SectionMemoryManager {
75 public:
76   uintptr_t ReservedCodeSize;
77   uintptr_t UsedCodeSize;
78   uintptr_t ReservedDataSizeRO;
79   uintptr_t UsedDataSizeRO;
80   uintptr_t ReservedDataSizeRW;
81   uintptr_t UsedDataSizeRW;
82 
TestReserveAllocationSpaceMemoryManager()83   TestReserveAllocationSpaceMemoryManager() :
84     ReservedCodeSize(0), UsedCodeSize(0), ReservedDataSizeRO(0),
85     UsedDataSizeRO(0), ReservedDataSizeRW(0), UsedDataSizeRW(0) {
86   }
87 
needsToReserveAllocationSpace()88   bool needsToReserveAllocationSpace() override { return true; }
89 
reserveAllocationSpace(uintptr_t CodeSize,uint32_t CodeAlign,uintptr_t DataSizeRO,uint32_t RODataAlign,uintptr_t DataSizeRW,uint32_t RWDataAlign)90   void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign,
91                               uintptr_t DataSizeRO, uint32_t RODataAlign,
92                               uintptr_t DataSizeRW,
93                               uint32_t RWDataAlign) override {
94     ReservedCodeSize = CodeSize;
95     ReservedDataSizeRO = DataSizeRO;
96     ReservedDataSizeRW = DataSizeRW;
97   }
98 
useSpace(uintptr_t * UsedSize,uintptr_t Size,unsigned Alignment)99   void useSpace(uintptr_t* UsedSize, uintptr_t Size, unsigned Alignment) {
100     uintptr_t AlignedSize = (Size + Alignment - 1) / Alignment * Alignment;
101     uintptr_t AlignedBegin = (*UsedSize + Alignment - 1) / Alignment * Alignment;
102     *UsedSize = AlignedBegin + AlignedSize;
103   }
104 
allocateDataSection(uintptr_t Size,unsigned Alignment,unsigned SectionID,StringRef SectionName,bool IsReadOnly)105   uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
106                                unsigned SectionID, StringRef SectionName,
107                                bool IsReadOnly) override {
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,
115                                StringRef SectionName) override {
116     useSpace(&UsedCodeSize, Size, Alignment);
117     return SectionMemoryManager::allocateCodeSection(Size, Alignment,
118       SectionID, SectionName);
119   }
120 };
121 
122 class MCJITCAPITest : public testing::Test, public MCJITTestAPICommon {
123 protected:
MCJITCAPITest()124   MCJITCAPITest() {
125     // The architectures below are known to be compatible with MCJIT as they
126     // are copied from test/ExecutionEngine/MCJIT/lit.local.cfg and should be
127     // kept in sync.
128     SupportedArchs.push_back(Triple::aarch64);
129     SupportedArchs.push_back(Triple::arm);
130     SupportedArchs.push_back(Triple::mips);
131     SupportedArchs.push_back(Triple::mips64);
132     SupportedArchs.push_back(Triple::mips64el);
133     SupportedArchs.push_back(Triple::x86);
134     SupportedArchs.push_back(Triple::x86_64);
135 
136     // Some architectures have sub-architectures in which tests will fail, like
137     // ARM. These two vectors will define if they do have sub-archs (to avoid
138     // extra work for those who don't), and if so, if they are listed to work
139     HasSubArchs.push_back(Triple::arm);
140     SupportedSubArchs.push_back("armv6");
141     SupportedSubArchs.push_back("armv7");
142 
143     // The operating systems below are known to be sufficiently incompatible
144     // that they will fail the MCJIT C API tests.
145     UnsupportedEnvironments.push_back(Triple::Cygnus);
146   }
147 
SetUp()148   void SetUp() override {
149     didCallAllocateCodeSection = false;
150     didAllocateCompactUnwindSection = false;
151     didCallYield = false;
152     Module = nullptr;
153     Function = nullptr;
154     Engine = nullptr;
155     Error = nullptr;
156   }
157 
TearDown()158   void TearDown() override {
159     if (Engine)
160       LLVMDisposeExecutionEngine(Engine);
161     else if (Module)
162       LLVMDisposeModule(Module);
163   }
164 
buildSimpleFunction()165   void buildSimpleFunction() {
166     Module = LLVMModuleCreateWithName("simple_module");
167 
168     LLVMSetTarget(Module, HostTriple.c_str());
169 
170     Function = LLVMAddFunction(Module, "simple_function",
171                                LLVMFunctionType(LLVMInt32Type(), nullptr,0, 0));
172     LLVMSetFunctionCallConv(Function, LLVMCCallConv);
173 
174     LLVMBasicBlockRef entry = LLVMAppendBasicBlock(Function, "entry");
175     LLVMBuilderRef builder = LLVMCreateBuilder();
176     LLVMPositionBuilderAtEnd(builder, entry);
177     LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0));
178 
179     LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
180     LLVMDisposeMessage(Error);
181 
182     LLVMDisposeBuilder(builder);
183   }
184 
buildFunctionThatUsesStackmap()185   void buildFunctionThatUsesStackmap() {
186     Module = LLVMModuleCreateWithName("simple_module");
187 
188     LLVMSetTarget(Module, HostTriple.c_str());
189 
190     LLVMTypeRef stackmapParamTypes[] = { LLVMInt64Type(), LLVMInt32Type() };
191     LLVMTypeRef stackmapTy =
192         LLVMFunctionType(LLVMVoidType(), stackmapParamTypes, 2, 1);
193     LLVMValueRef stackmap = LLVMAddFunction(
194       Module, "llvm.experimental.stackmap", stackmapTy);
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     LLVMBuildCall2(builder, stackmapTy, 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 =
235             LLVMBuildLoad2(Builder, LLVMInt32Type(), GlobalVar, "intVal");
236         LLVMBuildRet(Builder, IntVal);
237 
238         LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
239         LLVMDisposeMessage(Error);
240 
241         LLVMDisposeBuilder(Builder);
242     }
243 
244     {
245         LLVMTypeRef ParamTypes[] = { LLVMInt32Type() };
246         Function2 = LLVMAddFunction(
247           Module, "setGlobal", LLVMFunctionType(LLVMVoidType(), ParamTypes, 1, 0));
248         LLVMSetFunctionCallConv(Function2, LLVMCCallConv);
249 
250         LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function2, "entry");
251         LLVMBuilderRef Builder = LLVMCreateBuilder();
252         LLVMPositionBuilderAtEnd(Builder, Entry);
253 
254         LLVMValueRef Arg = LLVMGetParam(Function2, 0);
255         LLVMBuildStore(Builder, Arg, GlobalVar);
256         LLVMBuildRetVoid(Builder);
257 
258         LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
259         LLVMDisposeMessage(Error);
260 
261         LLVMDisposeBuilder(Builder);
262     }
263   }
264 
buildMCJITOptions()265   void buildMCJITOptions() {
266     LLVMInitializeMCJITCompilerOptions(&Options, sizeof(Options));
267     Options.OptLevel = 2;
268 
269     // Just ensure that this field still exists.
270     Options.NoFramePointerElim = false;
271   }
272 
useRoundTripSectionMemoryManager()273   void useRoundTripSectionMemoryManager() {
274     Options.MCJMM = LLVMCreateSimpleMCJITMemoryManager(
275       new SectionMemoryManager(),
276       roundTripAllocateCodeSection,
277       roundTripAllocateDataSection,
278       roundTripFinalizeMemory,
279       roundTripDestroy);
280   }
281 
buildMCJITEngine()282   void buildMCJITEngine() {
283     ASSERT_EQ(
284       0, LLVMCreateMCJITCompilerForModule(&Engine, Module, &Options,
285                                           sizeof(Options), &Error));
286   }
287 
buildAndRunPasses()288   void buildAndRunPasses() {
289     LLVMPassManagerRef pass = LLVMCreatePassManager();
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 
429 #if defined(__APPLE__) && defined(__aarch64__)
430 // FIXME: Figure out why this fails on mac/arm, PR46647
431 #define MAYBE_reserve_allocation_space DISABLED_reserve_allocation_space
432 #else
433 #define MAYBE_reserve_allocation_space reserve_allocation_space
434 #endif
TEST_F(MCJITCAPITest,MAYBE_reserve_allocation_space)435 TEST_F(MCJITCAPITest, MAYBE_reserve_allocation_space) {
436   SKIP_UNSUPPORTED_PLATFORM;
437 
438   TestReserveAllocationSpaceMemoryManager* MM = new TestReserveAllocationSpaceMemoryManager();
439 
440   buildModuleWithCodeAndData();
441   buildMCJITOptions();
442   Options.MCJMM = wrap(MM);
443   buildMCJITEngine();
444   buildAndRunPasses();
445 
446   auto GetGlobalFct = reinterpret_cast<int (*)()>(
447       reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine, Function)));
448 
449   auto SetGlobalFct = reinterpret_cast<void (*)(int)>(
450       reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine, Function2)));
451 
452   SetGlobalFct(789);
453   EXPECT_EQ(789, GetGlobalFct());
454   EXPECT_LE(MM->UsedCodeSize, MM->ReservedCodeSize);
455   EXPECT_LE(MM->UsedDataSizeRO, MM->ReservedDataSizeRO);
456   EXPECT_LE(MM->UsedDataSizeRW, MM->ReservedDataSizeRW);
457   EXPECT_TRUE(MM->UsedCodeSize > 0);
458   EXPECT_TRUE(MM->UsedDataSizeRW > 0);
459 }
460 
TEST_F(MCJITCAPITest,yield)461 TEST_F(MCJITCAPITest, yield) {
462   SKIP_UNSUPPORTED_PLATFORM;
463 
464   buildSimpleFunction();
465   buildMCJITOptions();
466   buildMCJITEngine();
467   LLVMContextRef C = LLVMGetGlobalContext();
468   LLVMContextSetYieldCallback(C, yield, nullptr);
469   buildAndRunPasses();
470 
471   auto *functionPointer = reinterpret_cast<int (*)()>(
472       reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine, Function)));
473 
474   EXPECT_EQ(42, functionPointer());
475   EXPECT_TRUE(didCallYield);
476 }
477 
localTestFunc()478 static int localTestFunc() {
479   return 42;
480 }
481 
TEST_F(MCJITCAPITest,addGlobalMapping)482 TEST_F(MCJITCAPITest, addGlobalMapping) {
483   SKIP_UNSUPPORTED_PLATFORM;
484 
485   Module = LLVMModuleCreateWithName("testModule");
486   LLVMSetTarget(Module, HostTriple.c_str());
487   LLVMTypeRef FunctionType = LLVMFunctionType(LLVMInt32Type(), nullptr, 0, 0);
488   LLVMValueRef MappedFn = LLVMAddFunction(Module, "mapped_fn", FunctionType);
489 
490   Function = LLVMAddFunction(Module, "test_fn", FunctionType);
491   LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function, "");
492   LLVMBuilderRef Builder = LLVMCreateBuilder();
493   LLVMPositionBuilderAtEnd(Builder, Entry);
494   LLVMValueRef RetVal =
495       LLVMBuildCall2(Builder, FunctionType, MappedFn, nullptr, 0, "");
496   LLVMBuildRet(Builder, RetVal);
497   LLVMDisposeBuilder(Builder);
498 
499   LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
500   LLVMDisposeMessage(Error);
501 
502   buildMCJITOptions();
503   buildMCJITEngine();
504 
505   LLVMAddGlobalMapping(
506       Engine, MappedFn,
507       reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(&localTestFunc)));
508 
509   buildAndRunPasses();
510 
511   uint64_t raw = LLVMGetFunctionAddress(Engine, "test_fn");
512   int (*usable)() = (int (*)()) raw;
513 
514   EXPECT_EQ(42, usable());
515 }
516