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