Merge pull request #3199 from lambdageek/dev/proxy-setter
[mono.git] / mono / mini / mini-llvm-cpp.cpp
1 //
2 // mini-llvm-cpp.cpp: C++ support classes for the mono LLVM integration
3 //
4 // (C) 2009-2011 Novell, Inc.
5 // Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
6 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
7 //
8
9 //
10 // We need to override some stuff in LLVM, but this cannot be done using the C
11 // interface, so we have to use some C++ code here.
12 // The things which we override are:
13 // - the default JIT code manager used by LLVM doesn't allocate memory using
14 //   MAP_32BIT, we require it.
15 // - add some callbacks so we can obtain the size of methods and their exception
16 //   tables.
17 //
18
19 //
20 // Mono's internal header files are not C++ clean, so avoid including them if 
21 // possible
22 //
23
24 #include "config.h"
25
26 #include <stdint.h>
27
28 #include <llvm/Support/raw_ostream.h>
29 #include <llvm/IR/Function.h>
30 #include <llvm/IR/IRBuilder.h>
31 #include <llvm/IR/Module.h>
32 #include <llvm/IR/DIBuilder.h>
33
34 #include "mini-llvm-cpp.h"
35
36 using namespace llvm;
37
38 void
39 mono_llvm_dump_value (LLVMValueRef value)
40 {
41         /* Same as LLVMDumpValue (), but print to stdout */
42         fflush (stdout);
43         outs () << (*unwrap<Value> (value));
44 }
45
46 /* Missing overload for building an alloca with an alignment */
47 LLVMValueRef
48 mono_llvm_build_alloca (LLVMBuilderRef builder, LLVMTypeRef Ty, 
49                                                 LLVMValueRef ArraySize,
50                                                 int alignment, const char *Name)
51 {
52         return wrap (unwrap (builder)->Insert (new AllocaInst (unwrap (Ty), unwrap (ArraySize), alignment), Name));
53 }
54
55 LLVMValueRef 
56 mono_llvm_build_load (LLVMBuilderRef builder, LLVMValueRef PointerVal,
57                                           const char *Name, gboolean is_volatile)
58 {
59         LoadInst *ins = unwrap(builder)->CreateLoad(unwrap(PointerVal), is_volatile, Name);
60
61         return wrap(ins);
62 }
63
64 LLVMValueRef
65 mono_llvm_build_atomic_load (LLVMBuilderRef builder, LLVMValueRef PointerVal,
66                                                          const char *Name, gboolean is_volatile, int alignment, BarrierKind barrier)
67 {
68         LoadInst *ins = unwrap(builder)->CreateLoad(unwrap(PointerVal), is_volatile, Name);
69
70         ins->setAlignment (alignment);
71         switch (barrier) {
72         case LLVM_BARRIER_NONE:
73                 break;
74         case LLVM_BARRIER_ACQ:
75                 ins->setOrdering(Acquire);
76                 break;
77         case LLVM_BARRIER_SEQ:
78                 ins->setOrdering(SequentiallyConsistent);
79                 break;
80         default:
81                 g_assert_not_reached ();
82                 break;
83         }
84
85         return wrap(ins);
86 }
87
88 LLVMValueRef 
89 mono_llvm_build_aligned_load (LLVMBuilderRef builder, LLVMValueRef PointerVal,
90                                                           const char *Name, gboolean is_volatile, int alignment)
91 {
92         LoadInst *ins;
93
94         ins = unwrap(builder)->CreateLoad(unwrap(PointerVal), is_volatile, Name);
95         ins->setAlignment (alignment);
96
97         return wrap(ins);
98 }
99
100 LLVMValueRef 
101 mono_llvm_build_store (LLVMBuilderRef builder, LLVMValueRef Val, LLVMValueRef PointerVal,
102                                           gboolean is_volatile, BarrierKind barrier)
103 {
104         StoreInst *ins = unwrap(builder)->CreateStore(unwrap(Val), unwrap(PointerVal), is_volatile);
105
106         switch (barrier) {
107         case LLVM_BARRIER_NONE:
108                 break;
109         case LLVM_BARRIER_REL:
110                 ins->setOrdering(Release);
111                 break;
112         case LLVM_BARRIER_SEQ:
113                 ins->setOrdering(SequentiallyConsistent);
114                 break;
115         default:
116                 g_assert_not_reached ();
117                 break;
118         }
119
120         return wrap(ins);
121 }
122
123 LLVMValueRef 
124 mono_llvm_build_aligned_store (LLVMBuilderRef builder, LLVMValueRef Val, LLVMValueRef PointerVal,
125                                                            gboolean is_volatile, int alignment)
126 {
127         StoreInst *ins;
128
129         ins = unwrap(builder)->CreateStore(unwrap(Val), unwrap(PointerVal), is_volatile);
130         ins->setAlignment (alignment);
131
132         return wrap (ins);
133 }
134
135 LLVMValueRef
136 mono_llvm_build_cmpxchg (LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp, LLVMValueRef val)
137 {
138         AtomicCmpXchgInst *ins;
139
140         ins = unwrap(builder)->CreateAtomicCmpXchg (unwrap(ptr), unwrap (cmp), unwrap (val), SequentiallyConsistent, SequentiallyConsistent);
141         return wrap (ins);
142 }
143
144 LLVMValueRef
145 mono_llvm_build_atomic_rmw (LLVMBuilderRef builder, AtomicRMWOp op, LLVMValueRef ptr, LLVMValueRef val)
146 {
147         AtomicRMWInst::BinOp aop = AtomicRMWInst::Xchg;
148         AtomicRMWInst *ins;
149
150         switch (op) {
151         case LLVM_ATOMICRMW_OP_XCHG:
152                 aop = AtomicRMWInst::Xchg;
153                 break;
154         case LLVM_ATOMICRMW_OP_ADD:
155                 aop = AtomicRMWInst::Add;
156                 break;
157         default:
158                 g_assert_not_reached ();
159                 break;
160         }
161
162         ins = unwrap (builder)->CreateAtomicRMW (aop, unwrap (ptr), unwrap (val), SequentiallyConsistent);
163         return wrap (ins);
164 }
165
166 LLVMValueRef
167 mono_llvm_build_fence (LLVMBuilderRef builder, BarrierKind kind)
168 {
169         FenceInst *ins;
170         AtomicOrdering ordering;
171
172         g_assert (kind != LLVM_BARRIER_NONE);
173
174         switch (kind) {
175         case LLVM_BARRIER_ACQ:
176                 ordering = Acquire;
177                 break;
178         case LLVM_BARRIER_REL:
179                 ordering = Release;
180                 break;
181         case LLVM_BARRIER_SEQ:
182                 ordering = SequentiallyConsistent;
183                 break;
184         default:
185                 g_assert_not_reached ();
186                 break;
187         }
188
189         ins = unwrap (builder)->CreateFence (ordering);
190         return wrap (ins);
191 }
192
193 void
194 mono_llvm_set_must_tail (LLVMValueRef call_ins)
195 {
196         CallInst *ins = (CallInst*)unwrap (call_ins);
197
198         ins->setTailCallKind (CallInst::TailCallKind::TCK_MustTail);
199 }
200
201 void
202 mono_llvm_replace_uses_of (LLVMValueRef var, LLVMValueRef v)
203 {
204         Value *V = ConstantExpr::getTruncOrBitCast (unwrap<Constant> (v), unwrap (var)->getType ());
205         unwrap (var)->replaceAllUsesWith (V);
206 }
207
208 LLVMValueRef
209 mono_llvm_create_constant_data_array (const uint8_t *data, int len)
210 {
211         return wrap(ConstantDataArray::get (*unwrap(LLVMGetGlobalContext ()), makeArrayRef(data, len)));
212 }
213
214 void
215 mono_llvm_set_is_constant (LLVMValueRef global_var)
216 {
217         unwrap<GlobalVariable>(global_var)->setConstant (true);
218 }
219
220 void
221 mono_llvm_set_preserveall_cc (LLVMValueRef func)
222 {
223         unwrap<Function>(func)->setCallingConv (CallingConv::PreserveAll);
224 }
225
226 void
227 mono_llvm_set_call_preserveall_cc (LLVMValueRef func)
228 {
229         unwrap<CallInst>(func)->setCallingConv (CallingConv::PreserveAll);
230 }
231
232 void
233 mono_llvm_set_call_notail (LLVMValueRef func)
234 {
235 #if LLVM_API_VERSION > 100
236         //unwrap<CallInst>(func)->setTailCallKind (CallInst::TailCallKind::TCK_NoTail);
237 #endif
238 }
239
240 #if LLVM_API_VERSION > 100
241
242 void*
243 mono_llvm_create_di_builder (LLVMModuleRef module)
244 {
245         return new DIBuilder (*unwrap(module));
246 }
247
248 void*
249 mono_llvm_di_create_compile_unit (void *di_builder, const char *cu_name, const char *dir, const char *producer)
250 {
251         DIBuilder *builder = (DIBuilder*)di_builder;
252
253         return builder->createCompileUnit (dwarf::DW_LANG_C99, cu_name, dir, producer, true, "", 0);
254 }
255
256 void*
257 mono_llvm_di_create_function (void *di_builder, void *cu, LLVMValueRef func, const char *name, const char *mangled_name, const char *dir, const char *file, int line)
258 {
259         DIBuilder *builder = (DIBuilder*)di_builder;
260         DIFile *di_file;
261         DISubroutineType *type;
262         DISubprogram *di_func;
263
264         // FIXME: Share DIFile
265         di_file = builder->createFile (file, dir);
266         type = builder->createSubroutineType (builder->getOrCreateTypeArray (ArrayRef<Metadata*> ()));
267         di_func = builder->createFunction (di_file, name, mangled_name, di_file, line, type, true, true, 0);
268
269         unwrap<Function>(func)->setMetadata ("dbg", di_func);
270
271         return di_func;
272 }
273
274 void*
275 mono_llvm_di_create_file (void *di_builder, const char *dir, const char *file)
276 {
277         DIBuilder *builder = (DIBuilder*)di_builder;
278
279         return builder->createFile (file, dir);
280 }
281
282 void*
283 mono_llvm_di_create_location (void *di_builder, void *scope, int row, int column)
284 {
285         return DILocation::get (*unwrap(LLVMGetGlobalContext ()), row, column, (Metadata*)scope);
286 }
287
288 void
289 mono_llvm_di_set_location (LLVMBuilderRef builder, void *loc_md)
290 {
291         unwrap(builder)->SetCurrentDebugLocation ((DILocation*)loc_md);
292 }
293
294 void
295 mono_llvm_di_builder_finalize (void *di_builder)
296 {
297         DIBuilder *builder = (DIBuilder*)di_builder;
298
299         builder->finalize ();
300 }
301
302 #endif /* #if LLVM_API_VERSION > 100 */