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
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, uintptr_t DataSizeRO,
92                              uintptr_t DataSizeRW) override {
93    ReservedCodeSize = CodeSize;
94    ReservedDataSizeRO = DataSizeRO;
95    ReservedDataSizeRW = DataSizeRW;
96  }
97
98  void useSpace(uintptr_t* UsedSize, uintptr_t Size, unsigned Alignment) {
99    uintptr_t AlignedSize = (Size + Alignment - 1) / Alignment * Alignment;
100    uintptr_t AlignedBegin = (*UsedSize + Alignment - 1) / Alignment * Alignment;
101    *UsedSize = AlignedBegin + AlignedSize;
102  }
103
104  uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
105                               unsigned SectionID, StringRef SectionName,
106                               bool IsReadOnly) override {
107    useSpace(IsReadOnly ? &UsedDataSizeRO : &UsedDataSizeRW, Size, Alignment);
108    return SectionMemoryManager::allocateDataSection(Size, Alignment,
109      SectionID, SectionName, IsReadOnly);
110  }
111
112  uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
113                               unsigned SectionID,
114                               StringRef SectionName) override {
115    useSpace(&UsedCodeSize, Size, Alignment);
116    return SectionMemoryManager::allocateCodeSection(Size, Alignment,
117      SectionID, SectionName);
118  }
119};
120
121class MCJITCAPITest : public testing::Test, public MCJITTestAPICommon {
122protected:
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
145  void SetUp() override {
146    didCallAllocateCodeSection = false;
147    didAllocateCompactUnwindSection = false;
148    didCallYield = false;
149    Module = nullptr;
150    Function = nullptr;
151    Engine = nullptr;
152    Error = nullptr;
153  }
154
155  void TearDown() override {
156    if (Engine)
157      LLVMDisposeExecutionEngine(Engine);
158    else if (Module)
159      LLVMDisposeModule(Module);
160  }
161
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
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
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
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
268  void useRoundTripSectionMemoryManager() {
269    Options.MCJMM = LLVMCreateSimpleMCJITMemoryManager(
270      new SectionMemoryManager(),
271      roundTripAllocateCodeSection,
272      roundTripAllocateDataSection,
273      roundTripFinalizeMemory,
274      roundTripDestroy);
275  }
276
277  void buildMCJITEngine() {
278    ASSERT_EQ(
279      0, LLVMCreateMCJITCompilerForModule(&Engine, Module, &Options,
280                                          sizeof(Options), &Error));
281  }
282
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
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
333TEST_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
350TEST_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
368TEST_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
382TEST_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
401TEST_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
437TEST_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
469TEST_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