[sdb] Fix support for async debugging in optimized mode, roslyn generates valuetype...
[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 #if LLVM_API_VERSION > 100
39 // These are c++11 scoped enums in recent llvm versions
40 #define Acquire AtomicOrdering::Acquire
41 #define Release AtomicOrdering::Release
42 #define SequentiallyConsistent AtomicOrdering::SequentiallyConsistent
43 #endif
44
45 void
46 mono_llvm_dump_value (LLVMValueRef value)
47 {
48         /* Same as LLVMDumpValue (), but print to stdout */
49         fflush (stdout);
50         outs () << (*unwrap<Value> (value));
51 }
52
53 /* Missing overload for building an alloca with an alignment */
54 LLVMValueRef
55 mono_llvm_build_alloca (LLVMBuilderRef builder, LLVMTypeRef Ty, 
56                                                 LLVMValueRef ArraySize,
57                                                 int alignment, const char *Name)
58 {
59         return wrap (unwrap (builder)->Insert (new AllocaInst (unwrap (Ty), unwrap (ArraySize), alignment), Name));
60 }
61
62 LLVMValueRef 
63 mono_llvm_build_load (LLVMBuilderRef builder, LLVMValueRef PointerVal,
64                                           const char *Name, gboolean is_volatile)
65 {
66         LoadInst *ins = unwrap(builder)->CreateLoad(unwrap(PointerVal), is_volatile, Name);
67
68         return wrap(ins);
69 }
70
71 LLVMValueRef
72 mono_llvm_build_atomic_load (LLVMBuilderRef builder, LLVMValueRef PointerVal,
73                                                          const char *Name, gboolean is_volatile, int alignment, BarrierKind barrier)
74 {
75         LoadInst *ins = unwrap(builder)->CreateLoad(unwrap(PointerVal), is_volatile, Name);
76
77         ins->setAlignment (alignment);
78         switch (barrier) {
79         case LLVM_BARRIER_NONE:
80                 break;
81         case LLVM_BARRIER_ACQ:
82                 ins->setOrdering(Acquire);
83                 break;
84         case LLVM_BARRIER_SEQ:
85                 ins->setOrdering(SequentiallyConsistent);
86                 break;
87         default:
88                 g_assert_not_reached ();
89                 break;
90         }
91
92         return wrap(ins);
93 }
94
95 LLVMValueRef 
96 mono_llvm_build_aligned_load (LLVMBuilderRef builder, LLVMValueRef PointerVal,
97                                                           const char *Name, gboolean is_volatile, int alignment)
98 {
99         LoadInst *ins;
100
101         ins = unwrap(builder)->CreateLoad(unwrap(PointerVal), is_volatile, Name);
102         ins->setAlignment (alignment);
103
104         return wrap(ins);
105 }
106
107 LLVMValueRef 
108 mono_llvm_build_store (LLVMBuilderRef builder, LLVMValueRef Val, LLVMValueRef PointerVal,
109                                           gboolean is_volatile, BarrierKind barrier)
110 {
111         StoreInst *ins = unwrap(builder)->CreateStore(unwrap(Val), unwrap(PointerVal), is_volatile);
112
113         switch (barrier) {
114         case LLVM_BARRIER_NONE:
115                 break;
116         case LLVM_BARRIER_REL:
117                 ins->setOrdering(Release);
118                 break;
119         case LLVM_BARRIER_SEQ:
120                 ins->setOrdering(SequentiallyConsistent);
121                 break;
122         default:
123                 g_assert_not_reached ();
124                 break;
125         }
126
127         return wrap(ins);
128 }
129
130 LLVMValueRef 
131 mono_llvm_build_aligned_store (LLVMBuilderRef builder, LLVMValueRef Val, LLVMValueRef PointerVal,
132                                                            gboolean is_volatile, int alignment)
133 {
134         StoreInst *ins;
135
136         ins = unwrap(builder)->CreateStore(unwrap(Val), unwrap(PointerVal), is_volatile);
137         ins->setAlignment (alignment);
138
139         return wrap (ins);
140 }
141
142 LLVMValueRef
143 mono_llvm_build_cmpxchg (LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp, LLVMValueRef val)
144 {
145         AtomicCmpXchgInst *ins;
146
147         ins = unwrap(builder)->CreateAtomicCmpXchg (unwrap(ptr), unwrap (cmp), unwrap (val), SequentiallyConsistent, SequentiallyConsistent);
148         return wrap (ins);
149 }
150
151 LLVMValueRef
152 mono_llvm_build_atomic_rmw (LLVMBuilderRef builder, AtomicRMWOp op, LLVMValueRef ptr, LLVMValueRef val)
153 {
154         AtomicRMWInst::BinOp aop = AtomicRMWInst::Xchg;
155         AtomicRMWInst *ins;
156
157         switch (op) {
158         case LLVM_ATOMICRMW_OP_XCHG:
159                 aop = AtomicRMWInst::Xchg;
160                 break;
161         case LLVM_ATOMICRMW_OP_ADD:
162                 aop = AtomicRMWInst::Add;
163                 break;
164         default:
165                 g_assert_not_reached ();
166                 break;
167         }
168
169         ins = unwrap (builder)->CreateAtomicRMW (aop, unwrap (ptr), unwrap (val), SequentiallyConsistent);
170         return wrap (ins);
171 }
172
173 LLVMValueRef
174 mono_llvm_build_fence (LLVMBuilderRef builder, BarrierKind kind)
175 {
176         FenceInst *ins;
177         AtomicOrdering ordering;
178
179         g_assert (kind != LLVM_BARRIER_NONE);
180
181         switch (kind) {
182         case LLVM_BARRIER_ACQ:
183                 ordering = Acquire;
184                 break;
185         case LLVM_BARRIER_REL:
186                 ordering = Release;
187                 break;
188         case LLVM_BARRIER_SEQ:
189                 ordering = SequentiallyConsistent;
190                 break;
191         default:
192                 g_assert_not_reached ();
193                 break;
194         }
195
196         ins = unwrap (builder)->CreateFence (ordering);
197         return wrap (ins);
198 }
199
200 void
201 mono_llvm_set_must_tail (LLVMValueRef call_ins)
202 {
203         CallInst *ins = (CallInst*)unwrap (call_ins);
204
205         ins->setTailCallKind (CallInst::TailCallKind::TCK_MustTail);
206 }
207
208 void
209 mono_llvm_replace_uses_of (LLVMValueRef var, LLVMValueRef v)
210 {
211         Value *V = ConstantExpr::getTruncOrBitCast (unwrap<Constant> (v), unwrap (var)->getType ());
212         unwrap (var)->replaceAllUsesWith (V);
213 }
214
215 LLVMValueRef
216 mono_llvm_create_constant_data_array (const uint8_t *data, int len)
217 {
218         return wrap(ConstantDataArray::get (*unwrap(LLVMGetGlobalContext ()), makeArrayRef(data, len)));
219 }
220
221 void
222 mono_llvm_set_is_constant (LLVMValueRef global_var)
223 {
224         unwrap<GlobalVariable>(global_var)->setConstant (true);
225 }
226
227 void
228 mono_llvm_set_preserveall_cc (LLVMValueRef func)
229 {
230         unwrap<Function>(func)->setCallingConv (CallingConv::PreserveAll);
231 }
232
233 void
234 mono_llvm_set_call_preserveall_cc (LLVMValueRef func)
235 {
236         unwrap<CallInst>(func)->setCallingConv (CallingConv::PreserveAll);
237 }
238
239 void
240 mono_llvm_set_call_notail (LLVMValueRef func)
241 {
242 #if LLVM_API_VERSION > 100
243         unwrap<CallInst>(func)->setTailCallKind (CallInst::TailCallKind::TCK_NoTail);
244 #endif
245 }
246
247 #if LLVM_API_VERSION > 100
248
249 void*
250 mono_llvm_create_di_builder (LLVMModuleRef module)
251 {
252         return new DIBuilder (*unwrap(module));
253 }
254
255 void*
256 mono_llvm_di_create_compile_unit (void *di_builder, const char *cu_name, const char *dir, const char *producer)
257 {
258         DIBuilder *builder = (DIBuilder*)di_builder;
259
260         return builder->createCompileUnit (dwarf::DW_LANG_C99, cu_name, dir, producer, true, "", 0);
261 }
262
263 void*
264 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)
265 {
266         DIBuilder *builder = (DIBuilder*)di_builder;
267         DIFile *di_file;
268         DISubroutineType *type;
269         DISubprogram *di_func;
270
271         // FIXME: Share DIFile
272         di_file = builder->createFile (file, dir);
273         type = builder->createSubroutineType (builder->getOrCreateTypeArray (ArrayRef<Metadata*> ()));
274         di_func = builder->createFunction (di_file, name, mangled_name, di_file, line, type, true, true, 0);
275
276         unwrap<Function>(func)->setMetadata ("dbg", di_func);
277
278         return di_func;
279 }
280
281 void*
282 mono_llvm_di_create_file (void *di_builder, const char *dir, const char *file)
283 {
284         DIBuilder *builder = (DIBuilder*)di_builder;
285
286         return builder->createFile (file, dir);
287 }
288
289 void*
290 mono_llvm_di_create_location (void *di_builder, void *scope, int row, int column)
291 {
292         return DILocation::get (*unwrap(LLVMGetGlobalContext ()), row, column, (Metadata*)scope);
293 }
294
295 void
296 mono_llvm_di_set_location (LLVMBuilderRef builder, void *loc_md)
297 {
298         unwrap(builder)->SetCurrentDebugLocation ((DILocation*)loc_md);
299 }
300
301 void
302 mono_llvm_di_builder_finalize (void *di_builder)
303 {
304         DIBuilder *builder = (DIBuilder*)di_builder;
305
306         builder->finalize ();
307 }
308
309 #endif /* #if LLVM_API_VERSION > 100 */