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 "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
27using namespace llvm;
28
29static bool didCallAllocateCodeSection;
30static bool didAllocateCompactUnwindSection;
31static bool didCallYield;
32
33static 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
42static 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
53static 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
64static void roundTripDestroy(void *object) {
65  delete static_cast<SectionMemoryManager*>(object);
66}
67
68static void yield(LLVMContextRef, void *) {
69  didCallYield = true;
70}
71
72namespace {
73
74// memory manager to test reserve allocation space callback
75class TestReserveAllocationSpaceMemoryManager: public SectionMemoryManager {
76public:
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
84  TestReserveAllocationSpaceMemoryManager() :
85    ReservedCodeSize(0), UsedCodeSize(0), ReservedDataSizeRO(0),
86    UsedDataSizeRO(0), ReservedDataSizeRW(0), UsedDataSizeRW(0) {
87  }
88
89  bool needsToReserveAllocationSpace() override { return true; }
90
91  void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign,
92			      uintptr_t DataSizeRO, uint32_t RODataAlign,
93                              uintptr_t DataSizeRW, uint32_t RWDataAlign) override {
94    ReservedCodeSize = CodeSize;
95    ReservedDataSizeRO = DataSizeRO;
96    ReservedDataSizeRW = DataSizeRW;
97  }
98
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
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
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
122class MCJITCAPITest : public testing::Test, public MCJITTestAPICommon {
123protected:
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
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
158  void TearDown() override {
159    if (Engine)
160      LLVMDisposeExecutionEngine(Engine);
161    else if (Module)
162      LLVMDisposeModule(Module);
163  }
164
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
185  void buildFunctionThatUsesStackmap() {
186    Module = LLVMModuleCreateWithName("simple_module");
187
188    LLVMSetTarget(Module, HostTriple.c_str());
189
190    LLVMTypeRef stackmapParamTypes[] = { LLVMInt64Type(), LLVMInt32Type() };
191    LLVMValueRef stackmap = LLVMAddFunction(
192      Module, "llvm.experimental.stackmap",
193      LLVMFunctionType(LLVMVoidType(), stackmapParamTypes, 2, 1));
194    LLVMSetLinkage(stackmap, LLVMExternalLinkage);
195
196    Function = LLVMAddFunction(Module, "simple_function",
197                              LLVMFunctionType(LLVMInt32Type(), nullptr, 0, 0));
198
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)
205    };
206    LLVMBuildCall(builder, stackmap, stackmapArgs, 3, "");
207    LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0));
208
209    LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
210    LLVMDisposeMessage(Error);
211
212    LLVMDisposeBuilder(builder);
213  }
214
215  void buildModuleWithCodeAndData() {
216    Module = LLVMModuleCreateWithName("simple_module");
217
218    LLVMSetTarget(Module, HostTriple.c_str());
219
220    // build a global int32 variable initialized to 42.
221    LLVMValueRef GlobalVar = LLVMAddGlobal(Module, LLVMInt32Type(), "intVal");
222    LLVMSetInitializer(GlobalVar, LLVMConstInt(LLVMInt32Type(), 42, 0));
223
224    {
225        Function = LLVMAddFunction(Module, "getGlobal",
226                              LLVMFunctionType(LLVMInt32Type(), nullptr, 0, 0));
227        LLVMSetFunctionCallConv(Function, LLVMCCallConv);
228
229        LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function, "entry");
230        LLVMBuilderRef Builder = LLVMCreateBuilder();
231        LLVMPositionBuilderAtEnd(Builder, Entry);
232
233        LLVMValueRef IntVal = LLVMBuildLoad(Builder, GlobalVar, "intVal");
234        LLVMBuildRet(Builder, IntVal);
235
236        LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
237        LLVMDisposeMessage(Error);
238
239        LLVMDisposeBuilder(Builder);
240    }
241
242    {
243        LLVMTypeRef ParamTypes[] = { LLVMInt32Type() };
244        Function2 = LLVMAddFunction(
245          Module, "setGlobal", LLVMFunctionType(LLVMVoidType(), ParamTypes, 1, 0));
246        LLVMSetFunctionCallConv(Function2, LLVMCCallConv);
247
248        LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function2, "entry");
249        LLVMBuilderRef Builder = LLVMCreateBuilder();
250        LLVMPositionBuilderAtEnd(Builder, Entry);
251
252        LLVMValueRef Arg = LLVMGetParam(Function2, 0);
253        LLVMBuildStore(Builder, Arg, GlobalVar);
254        LLVMBuildRetVoid(Builder);
255
256        LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
257        LLVMDisposeMessage(Error);
258
259        LLVMDisposeBuilder(Builder);
260    }
261  }
262
263  void buildMCJITOptions() {
264    LLVMInitializeMCJITCompilerOptions(&Options, sizeof(Options));
265    Options.OptLevel = 2;
266
267    // Just ensure that this field still exists.
268    Options.NoFramePointerElim = false;
269  }
270
271  void useRoundTripSectionMemoryManager() {
272    Options.MCJMM = LLVMCreateSimpleMCJITMemoryManager(
273      new SectionMemoryManager(),
274      roundTripAllocateCodeSection,
275      roundTripAllocateDataSection,
276      roundTripFinalizeMemory,
277      roundTripDestroy);
278  }
279
280  void buildMCJITEngine() {
281    ASSERT_EQ(
282      0, LLVMCreateMCJITCompilerForModule(&Engine, Module, &Options,
283                                          sizeof(Options), &Error));
284  }
285
286  void buildAndRunPasses() {
287    LLVMPassManagerRef pass = LLVMCreatePassManager();
288    LLVMAddConstantPropagationPass(pass);
289    LLVMAddInstructionCombiningPass(pass);
290    LLVMRunPassManager(pass, Module);
291    LLVMDisposePassManager(pass);
292  }
293
294  void buildAndRunOptPasses() {
295    LLVMPassManagerBuilderRef passBuilder;
296
297    passBuilder = LLVMPassManagerBuilderCreate();
298    LLVMPassManagerBuilderSetOptLevel(passBuilder, 2);
299    LLVMPassManagerBuilderSetSizeLevel(passBuilder, 0);
300
301    LLVMPassManagerRef functionPasses =
302      LLVMCreateFunctionPassManagerForModule(Module);
303    LLVMPassManagerRef modulePasses =
304      LLVMCreatePassManager();
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
333TEST_F(MCJITCAPITest, simple_function) {
334  SKIP_UNSUPPORTED_PLATFORM;
335
336  buildSimpleFunction();
337  buildMCJITOptions();
338  buildMCJITEngine();
339  buildAndRunPasses();
340
341  auto *functionPointer = reinterpret_cast<int (*)()>(
342      reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine, Function)));
343
344  EXPECT_EQ(42, functionPointer());
345}
346
347TEST_F(MCJITCAPITest, gva) {
348  SKIP_UNSUPPORTED_PLATFORM;
349
350  Module = LLVMModuleCreateWithName("simple_module");
351  LLVMSetTarget(Module, HostTriple.c_str());
352  LLVMValueRef GlobalVar = LLVMAddGlobal(Module, LLVMInt32Type(), "simple_value");
353  LLVMSetInitializer(GlobalVar, LLVMConstInt(LLVMInt32Type(), 42, 0));
354
355  buildMCJITOptions();
356  buildMCJITEngine();
357  buildAndRunPasses();
358
359  uint64_t raw = LLVMGetGlobalValueAddress(Engine, "simple_value");
360  int32_t *usable  = (int32_t *) raw;
361
362  EXPECT_EQ(42, *usable);
363}
364
365TEST_F(MCJITCAPITest, gfa) {
366  SKIP_UNSUPPORTED_PLATFORM;
367
368  buildSimpleFunction();
369  buildMCJITOptions();
370  buildMCJITEngine();
371  buildAndRunPasses();
372
373  uint64_t raw = LLVMGetFunctionAddress(Engine, "simple_function");
374  int (*usable)() = (int (*)()) raw;
375
376  EXPECT_EQ(42, usable());
377}
378
379TEST_F(MCJITCAPITest, custom_memory_manager) {
380  SKIP_UNSUPPORTED_PLATFORM;
381
382  buildSimpleFunction();
383  buildMCJITOptions();
384  useRoundTripSectionMemoryManager();
385  buildMCJITEngine();
386  buildAndRunPasses();
387
388  auto *functionPointer = reinterpret_cast<int (*)()>(
389      reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine, Function)));
390
391  EXPECT_EQ(42, functionPointer());
392  EXPECT_TRUE(didCallAllocateCodeSection);
393}
394
395TEST_F(MCJITCAPITest, stackmap_creates_compact_unwind_on_darwin) {
396  SKIP_UNSUPPORTED_PLATFORM;
397
398  // This test is also not supported on non-x86 platforms.
399  if (Triple(HostTriple).getArch() != Triple::x86_64)
400    return;
401
402  buildFunctionThatUsesStackmap();
403  buildMCJITOptions();
404  useRoundTripSectionMemoryManager();
405  buildMCJITEngine();
406  buildAndRunOptPasses();
407
408  auto *functionPointer = reinterpret_cast<int (*)()>(
409      reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine, Function)));
410
411  EXPECT_EQ(42, functionPointer());
412  EXPECT_TRUE(didCallAllocateCodeSection);
413
414  // Up to this point, the test is specific only to X86-64. But this next
415  // expectation is only valid on Darwin because it assumes that unwind
416  // data is made available only through compact_unwind. It would be
417  // worthwhile to extend this to handle non-Darwin platforms, in which
418  // case you'd want to look for an eh_frame or something.
419  //
420  // FIXME: Currently, MCJIT relies on a configure-time check to determine which
421  // sections to emit. The JIT client should have runtime control over this.
422  EXPECT_TRUE(
423    Triple(HostTriple).getOS() != Triple::Darwin ||
424    Triple(HostTriple).isMacOSXVersionLT(10, 7) ||
425    didAllocateCompactUnwindSection);
426}
427
428TEST_F(MCJITCAPITest, reserve_allocation_space) {
429  SKIP_UNSUPPORTED_PLATFORM;
430
431  TestReserveAllocationSpaceMemoryManager* MM = new TestReserveAllocationSpaceMemoryManager();
432
433  buildModuleWithCodeAndData();
434  buildMCJITOptions();
435  Options.MCJMM = wrap(MM);
436  buildMCJITEngine();
437  buildAndRunPasses();
438
439  auto GetGlobalFct = reinterpret_cast<int (*)()>(
440      reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine, Function)));
441
442  auto SetGlobalFct = reinterpret_cast<void (*)(int)>(
443      reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine, Function2)));
444
445  SetGlobalFct(789);
446  EXPECT_EQ(789, GetGlobalFct());
447  EXPECT_LE(MM->UsedCodeSize, MM->ReservedCodeSize);
448  EXPECT_LE(MM->UsedDataSizeRO, MM->ReservedDataSizeRO);
449  EXPECT_LE(MM->UsedDataSizeRW, MM->ReservedDataSizeRW);
450  EXPECT_TRUE(MM->UsedCodeSize > 0);
451  EXPECT_TRUE(MM->UsedDataSizeRW > 0);
452}
453
454TEST_F(MCJITCAPITest, yield) {
455  SKIP_UNSUPPORTED_PLATFORM;
456
457  buildSimpleFunction();
458  buildMCJITOptions();
459  buildMCJITEngine();
460  LLVMContextRef C = LLVMGetGlobalContext();
461  LLVMContextSetYieldCallback(C, yield, nullptr);
462  buildAndRunPasses();
463
464  auto *functionPointer = reinterpret_cast<int (*)()>(
465      reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine, Function)));
466
467  EXPECT_EQ(42, functionPointer());
468  EXPECT_TRUE(didCallYield);
469}
470
471static int localTestFunc() {
472  return 42;
473}
474
475TEST_F(MCJITCAPITest, addGlobalMapping) {
476  SKIP_UNSUPPORTED_PLATFORM;
477
478  Module = LLVMModuleCreateWithName("testModule");
479  LLVMSetTarget(Module, HostTriple.c_str());
480  LLVMTypeRef FunctionType = LLVMFunctionType(LLVMInt32Type(), nullptr, 0, 0);
481  LLVMValueRef MappedFn = LLVMAddFunction(Module, "mapped_fn", FunctionType);
482
483  Function = LLVMAddFunction(Module, "test_fn", FunctionType);
484  LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function, "");
485  LLVMBuilderRef Builder = LLVMCreateBuilder();
486  LLVMPositionBuilderAtEnd(Builder, Entry);
487  LLVMValueRef RetVal = LLVMBuildCall(Builder, MappedFn, nullptr, 0, "");
488  LLVMBuildRet(Builder, RetVal);
489  LLVMDisposeBuilder(Builder);
490
491  LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
492  LLVMDisposeMessage(Error);
493
494  buildMCJITOptions();
495  buildMCJITEngine();
496
497  LLVMAddGlobalMapping(
498      Engine, MappedFn,
499      reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(&localTestFunc)));
500
501  buildAndRunPasses();
502
503  uint64_t raw = LLVMGetFunctionAddress(Engine, "test_fn");
504  int (*usable)() = (int (*)()) raw;
505
506  EXPECT_EQ(42, usable());
507}
508