Extend RTDyld API to enable optionally precomputing the total amount of memory
[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/Scalar.h"
21 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
22 #include "llvm/Support/Host.h"
23 #include "gtest/gtest.h"
24 #include "llvm/Support/Debug.h"
25
26 using namespace llvm;
27
28 static bool didCallAllocateCodeSection;
29
30 static uint8_t *roundTripAllocateCodeSection(void *object, uintptr_t size,
31                                              unsigned alignment,
32                                              unsigned sectionID,
33                                              const char *sectionName) {
34   didCallAllocateCodeSection = true;
35   return static_cast<SectionMemoryManager*>(object)->allocateCodeSection(
36     size, alignment, sectionID, sectionName);
37 }
38
39 static uint8_t *roundTripAllocateDataSection(void *object, uintptr_t size,
40                                              unsigned alignment,
41                                              unsigned sectionID,
42                                              const char *sectionName,
43                                              LLVMBool isReadOnly) {
44   return static_cast<SectionMemoryManager*>(object)->allocateDataSection(
45     size, alignment, sectionID, sectionName, isReadOnly);
46 }
47
48 static LLVMBool roundTripFinalizeMemory(void *object, char **errMsg) {
49   std::string errMsgString;
50   bool result =
51     static_cast<SectionMemoryManager*>(object)->finalizeMemory(&errMsgString);
52   if (result) {
53     *errMsg = LLVMCreateMessage(errMsgString.c_str());
54     return 1;
55   }
56   return 0;
57 }
58
59 static void roundTripDestroy(void *object) {
60   delete static_cast<SectionMemoryManager*>(object);
61 }
62
63 namespace {
64
65 // memory manager to test reserve allocation space callback
66 class TestReserveAllocationSpaceMemoryManager: public SectionMemoryManager {
67 public:
68   uintptr_t ReservedCodeSize;
69   uintptr_t UsedCodeSize;
70   uintptr_t ReservedDataSizeRO;
71   uintptr_t UsedDataSizeRO;
72   uintptr_t ReservedDataSizeRW;
73   uintptr_t UsedDataSizeRW;
74   
75   TestReserveAllocationSpaceMemoryManager() : 
76     ReservedCodeSize(0), UsedCodeSize(0), ReservedDataSizeRO(0), 
77     UsedDataSizeRO(0), ReservedDataSizeRW(0), UsedDataSizeRW(0) {    
78   }
79   
80   virtual bool needsToReserveAllocationSpace() {
81     return true;
82   }
83
84   virtual void reserveAllocationSpace(
85       uintptr_t CodeSize, uintptr_t DataSizeRO, uintptr_t DataSizeRW) {
86     ReservedCodeSize = CodeSize;
87     ReservedDataSizeRO = DataSizeRO;
88     ReservedDataSizeRW = DataSizeRW;
89   }
90
91   void useSpace(uintptr_t* UsedSize, uintptr_t Size, unsigned Alignment) {
92     uintptr_t AlignedSize = (Size + Alignment - 1) / Alignment * Alignment;
93     uintptr_t AlignedBegin = (*UsedSize + Alignment - 1) / Alignment * Alignment;
94     *UsedSize = AlignedBegin + AlignedSize;
95   }
96
97   virtual uint8_t* allocateDataSection(uintptr_t Size, unsigned Alignment,
98       unsigned SectionID, StringRef SectionName, bool IsReadOnly) {
99     useSpace(IsReadOnly ? &UsedDataSizeRO : &UsedDataSizeRW, Size, Alignment);
100     return SectionMemoryManager::allocateDataSection(Size, Alignment, 
101       SectionID, SectionName, IsReadOnly);
102   }
103
104   uint8_t* allocateCodeSection(uintptr_t Size, unsigned Alignment, 
105       unsigned SectionID, StringRef SectionName) {
106     useSpace(&UsedCodeSize, Size, Alignment);
107     return SectionMemoryManager::allocateCodeSection(Size, Alignment, 
108       SectionID, SectionName);
109   }
110 };
111
112 class MCJITCAPITest : public testing::Test, public MCJITTestAPICommon {
113 protected:
114   MCJITCAPITest() {
115     // The architectures below are known to be compatible with MCJIT as they
116     // are copied from test/ExecutionEngine/MCJIT/lit.local.cfg and should be
117     // kept in sync.
118     SupportedArchs.push_back(Triple::aarch64);
119     SupportedArchs.push_back(Triple::arm);
120     SupportedArchs.push_back(Triple::mips);
121     SupportedArchs.push_back(Triple::x86);
122     SupportedArchs.push_back(Triple::x86_64);
123
124     // Some architectures have sub-architectures in which tests will fail, like
125     // ARM. These two vectors will define if they do have sub-archs (to avoid
126     // extra work for those who don't), and if so, if they are listed to work
127     HasSubArchs.push_back(Triple::arm);
128     SupportedSubArchs.push_back("armv6");
129     SupportedSubArchs.push_back("armv7");
130
131     // The operating systems below are known to be sufficiently incompatible
132     // that they will fail the MCJIT C API tests.
133     UnsupportedOSs.push_back(Triple::Cygwin);
134   }
135   
136   virtual void SetUp() {
137     didCallAllocateCodeSection = false;
138     Module = 0;
139     Function = 0;
140     Engine = 0;
141     Error = 0;
142   }
143   
144   virtual void TearDown() {
145     if (Engine)
146       LLVMDisposeExecutionEngine(Engine);
147     else if (Module)
148       LLVMDisposeModule(Module);
149   }
150   
151   void buildSimpleFunction() {
152     Module = LLVMModuleCreateWithName("simple_module");
153     
154     LLVMSetTarget(Module, HostTriple.c_str());
155     
156     Function = LLVMAddFunction(
157       Module, "simple_function", LLVMFunctionType(LLVMInt32Type(), 0, 0, 0));
158     LLVMSetFunctionCallConv(Function, LLVMCCallConv);
159     
160     LLVMBasicBlockRef entry = LLVMAppendBasicBlock(Function, "entry");
161     LLVMBuilderRef builder = LLVMCreateBuilder();
162     LLVMPositionBuilderAtEnd(builder, entry);
163     LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0));
164     
165     LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
166     LLVMDisposeMessage(Error);
167     
168     LLVMDisposeBuilder(builder);
169   }
170   
171   void buildModuleWithCodeAndData() {
172     Module = LLVMModuleCreateWithName("simple_module");
173     
174     LLVMSetTarget(Module, HostTriple.c_str());
175     
176     // build a global variable initialized to "Hello World!"
177     LLVMValueRef GlobalVar = LLVMAddGlobal(Module, LLVMInt32Type(), "intVal");    
178     LLVMSetInitializer(GlobalVar, LLVMConstInt(LLVMInt32Type(), 42, 0));
179     
180     {
181         Function = LLVMAddFunction(
182           Module, "getGlobal", LLVMFunctionType(LLVMInt32Type(), 0, 0, 0));
183         LLVMSetFunctionCallConv(Function, LLVMCCallConv);
184         
185         LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function, "entry");
186         LLVMBuilderRef Builder = LLVMCreateBuilder();
187         LLVMPositionBuilderAtEnd(Builder, Entry);
188         
189         LLVMValueRef IntVal = LLVMBuildLoad(Builder, GlobalVar, "intVal");
190         LLVMBuildRet(Builder, IntVal);
191         
192         LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
193         LLVMDisposeMessage(Error);
194         
195         LLVMDisposeBuilder(Builder);
196     }
197     
198     {
199         LLVMTypeRef ParamTypes[] = { LLVMInt32Type() };
200         Function2 = LLVMAddFunction(
201           Module, "setGlobal", LLVMFunctionType(LLVMVoidType(), ParamTypes, 1, 0));
202         LLVMSetFunctionCallConv(Function2, LLVMCCallConv);
203         
204         LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function2, "entry");
205         LLVMBuilderRef Builder = LLVMCreateBuilder();
206         LLVMPositionBuilderAtEnd(Builder, Entry);
207         
208         LLVMValueRef Arg = LLVMGetParam(Function2, 0);
209         LLVMBuildStore(Builder, Arg, GlobalVar);
210         LLVMBuildRetVoid(Builder);
211         
212         LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
213         LLVMDisposeMessage(Error);
214         
215         LLVMDisposeBuilder(Builder);
216     }
217   }
218   
219   void buildMCJITOptions() {
220     LLVMInitializeMCJITCompilerOptions(&Options, sizeof(Options));
221     Options.OptLevel = 2;
222     
223     // Just ensure that this field still exists.
224     Options.NoFramePointerElim = false;
225   }
226   
227   void useRoundTripSectionMemoryManager() {
228     Options.MCJMM = LLVMCreateSimpleMCJITMemoryManager(
229       new SectionMemoryManager(),
230       roundTripAllocateCodeSection,
231       roundTripAllocateDataSection,
232       roundTripFinalizeMemory,
233       roundTripDestroy);
234   }
235
236   void buildMCJITEngine() {
237     ASSERT_EQ(
238       0, LLVMCreateMCJITCompilerForModule(&Engine, Module, &Options,
239                                           sizeof(Options), &Error));
240   }
241   
242   void buildAndRunPasses() {
243     LLVMPassManagerRef pass = LLVMCreatePassManager();
244     LLVMAddTargetData(LLVMGetExecutionEngineTargetData(Engine), pass);
245     LLVMAddConstantPropagationPass(pass);
246     LLVMAddInstructionCombiningPass(pass);
247     LLVMRunPassManager(pass, Module);
248     LLVMDisposePassManager(pass);
249   }
250   
251   LLVMModuleRef Module;
252   LLVMValueRef Function;
253   LLVMValueRef Function2;
254   LLVMMCJITCompilerOptions Options;
255   LLVMExecutionEngineRef Engine;
256   char *Error;
257 };
258 } // end anonymous namespace
259
260 TEST_F(MCJITCAPITest, simple_function) {
261   SKIP_UNSUPPORTED_PLATFORM;
262   
263   buildSimpleFunction();
264   buildMCJITOptions();
265   buildMCJITEngine();
266   buildAndRunPasses();
267   
268   union {
269     void *raw;
270     int (*usable)();
271   } functionPointer;
272   functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function);
273   
274   EXPECT_EQ(42, functionPointer.usable());
275 }
276
277 TEST_F(MCJITCAPITest, custom_memory_manager) {
278   SKIP_UNSUPPORTED_PLATFORM;
279   
280   buildSimpleFunction();
281   buildMCJITOptions();
282   useRoundTripSectionMemoryManager();
283   buildMCJITEngine();
284   buildAndRunPasses();
285   
286   union {
287     void *raw;
288     int (*usable)();
289   } functionPointer;
290   functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function);
291   
292   EXPECT_EQ(42, functionPointer.usable());
293   EXPECT_TRUE(didCallAllocateCodeSection);
294 }
295
296 TEST_F(MCJITCAPITest, reserve_allocation_space) {
297   SKIP_UNSUPPORTED_PLATFORM;
298   
299   TestReserveAllocationSpaceMemoryManager* MM = new TestReserveAllocationSpaceMemoryManager();
300   
301   buildModuleWithCodeAndData();
302   buildMCJITOptions();
303   Options.MCJMM = wrap(MM);
304   buildMCJITEngine();
305   buildAndRunPasses();
306   
307   union {
308     void *raw;
309     int (*usable)();
310   } GetGlobalFct;
311   GetGlobalFct.raw = LLVMGetPointerToGlobal(Engine, Function);
312   
313   union {
314     void *raw;
315     void (*usable)(int);
316   } SetGlobalFct;
317   SetGlobalFct.raw = LLVMGetPointerToGlobal(Engine, Function2);
318   
319   SetGlobalFct.usable(789);
320   EXPECT_EQ(789, GetGlobalFct.usable());
321   EXPECT_LE(MM->UsedCodeSize, MM->ReservedCodeSize);
322   EXPECT_LE(MM->UsedDataSizeRO, MM->ReservedDataSizeRO);
323   EXPECT_LE(MM->UsedDataSizeRW, MM->ReservedDataSizeRW);
324   EXPECT_TRUE(MM->UsedCodeSize > 0); 
325   EXPECT_TRUE(MM->UsedDataSizeRO > 0);
326   EXPECT_TRUE(MM->UsedDataSizeRW > 0);
327 }