Merge remote-tracking branch 'origin/master' into ffast-math
[mono-project.git] / mono / mini / llvm-jit.cpp
blobce289cc571fbda24c05dcd95eb61f4edb182c1d3
1 //
2 // jit-llvm.cpp: Support code for using LLVM as a JIT backend
3 //
4 // (C) 2009-2011 Novell, Inc.
5 // Copyright 2011-2015 Xamarin, Inc (http://www.xamarin.com)
6 //
7 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
8 //
10 #include "config.h"
12 #include <llvm-c/Core.h>
13 #include <llvm-c/ExecutionEngine.h>
15 #include "mini-llvm-cpp.h"
16 #include "mini-runtime.h"
17 #include "llvm-jit.h"
19 #if defined(MONO_ARCH_LLVM_JIT_SUPPORTED) && !defined(MONO_CROSS_COMPILE) && LLVM_API_VERSION > 600
21 #include <llvm/Support/raw_ostream.h>
22 #include <llvm/Support/Host.h>
23 #include <llvm/Support/TargetSelect.h>
24 #include <llvm/IR/Mangler.h>
25 #include <llvm/ExecutionEngine/ExecutionEngine.h>
26 #include "llvm/ExecutionEngine/Orc/CompileUtils.h"
27 #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
28 #include "llvm/ExecutionEngine/Orc/LambdaResolver.h"
29 #include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
30 #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
31 #include "llvm/ExecutionEngine/JITSymbol.h"
33 #include <cstdlib>
35 #include <mono/utils/mono-dl.h>
37 using namespace llvm;
38 using namespace llvm::orc;
40 extern cl::opt<bool> EnableMonoEH;
41 extern cl::opt<std::string> MonoEHFrameSymbol;
43 static MonoCPUFeatures cpu_features;
45 void
46 mono_llvm_set_unhandled_exception_handler (void)
50 template <typename T>
51 static std::vector<T> singletonSet(T t) {
52 std::vector<T> Vec;
53 Vec.push_back(std::move(t));
54 return Vec;
57 #ifdef __MINGW32__
59 #include <stddef.h>
60 extern void *memset(void *, int, size_t);
61 void bzero (void *to, size_t count) { memset (to, 0, count); }
63 #endif
65 static AllocCodeMemoryCb *alloc_code_mem_cb;
67 class MonoJitMemoryManager : public RTDyldMemoryManager
69 public:
70 ~MonoJitMemoryManager() override;
72 uint8_t *allocateDataSection(uintptr_t Size,
73 unsigned Alignment,
74 unsigned SectionID,
75 StringRef SectionName,
76 bool IsReadOnly) override;
78 uint8_t *allocateCodeSection(uintptr_t Size,
79 unsigned Alignment,
80 unsigned SectionID,
81 StringRef SectionName) override;
83 bool finalizeMemory(std::string *ErrMsg = nullptr) override;
86 MonoJitMemoryManager::~MonoJitMemoryManager()
90 uint8_t *
91 MonoJitMemoryManager::allocateDataSection(uintptr_t Size,
92 unsigned Alignment,
93 unsigned SectionID,
94 StringRef SectionName,
95 bool IsReadOnly)
97 uint8_t *res;
99 // FIXME: Use a mempool
100 if (Alignment == 32) {
101 /* Used for SIMD */
102 res = (uint8_t*)malloc (Size + 32);
103 res += (GPOINTER_TO_UINT (res) % 32);
104 } else {
105 res = (uint8_t*)malloc (Size);
107 assert (res);
108 g_assert (GPOINTER_TO_UINT (res) % Alignment == 0);
109 memset (res, 0, Size);
110 return res;
113 uint8_t *
114 MonoJitMemoryManager::allocateCodeSection(uintptr_t Size,
115 unsigned Alignment,
116 unsigned SectionID,
117 StringRef SectionName)
119 return alloc_code_mem_cb (NULL, Size);
122 bool
123 MonoJitMemoryManager::finalizeMemory(std::string *ErrMsg)
125 return false;
128 #if LLVM_API_VERSION >= 900
130 struct MonoLLVMJIT {
131 std::shared_ptr<MonoJitMemoryManager> mmgr;
132 ExecutionSession execution_session;
133 std::map<VModuleKey, std::shared_ptr<SymbolResolver>> resolvers;
134 TargetMachine *target_machine;
135 LegacyRTDyldObjectLinkingLayer object_layer;
136 LegacyIRCompileLayer<decltype(object_layer), SimpleCompiler> compile_layer;
137 DataLayout data_layout;
139 MonoLLVMJIT (TargetMachine *tm)
140 : mmgr (std::make_shared<MonoJitMemoryManager>())
141 , target_machine (tm)
142 , object_layer (
143 AcknowledgeORCv1Deprecation, execution_session,
144 [this] (VModuleKey k) {
145 return LegacyRTDyldObjectLinkingLayer::Resources{
146 mmgr, resolvers[k] };
148 , compile_layer (
149 AcknowledgeORCv1Deprecation, object_layer,
150 SimpleCompiler{*target_machine})
151 , data_layout (target_machine->createDataLayout())
153 compile_layer.setNotifyCompiled ([] (VModuleKey, std::unique_ptr<Module> module) {
154 module.release ();
158 VModuleKey
159 add_module (std::unique_ptr<Module> m)
161 auto k = execution_session.allocateVModule();
162 auto lookup_name = [this] (const std::string &namestr) {
163 auto jit_sym = compile_layer.findSymbol(namestr, false);
164 if (jit_sym) {
165 return jit_sym;
167 auto namebuf = namestr.c_str();
168 JITSymbolFlags flags{};
169 if (!strcmp(namebuf, "___bzero")) {
170 return JITSymbol{(uint64_t)(gssize)(void*)bzero, flags};
172 auto current = mono_dl_open (NULL, 0, NULL);
173 g_assert (current);
174 auto name = namebuf[0] == '_' ? namebuf + 1 : namebuf;
175 void *sym = nullptr;
176 auto err = mono_dl_symbol (current, name, &sym);
177 if (!sym) {
178 outs () << "R: " << namestr << "\n";
180 assert (sym);
181 return JITSymbol{(uint64_t)(gssize)sym, flags};
183 auto on_error = [] (Error err) {
184 outs () << "R2: " << err << "\n";
185 assert (0);
187 auto resolver = createLegacyLookupResolver (execution_session,
188 lookup_name, on_error);
189 resolvers[k] = std::move (resolver);
190 auto err = compile_layer.addModule (k, std::move(m));
191 if (err) {
192 outs () << "addModule error: " << err << "\n";
193 assert (0);
195 return k;
198 std::string
199 mangle (const std::string &name)
201 std::string ret;
202 raw_string_ostream out{ret};
203 Mangler::getNameWithPrefix (out, name, data_layout);
204 return ret;
207 std::string
208 mangle (const GlobalValue *gv)
210 std::string ret;
211 raw_string_ostream out{ret};
212 Mangler{}.getNameWithPrefix (out, gv, false);
213 return ret;
216 gpointer
217 compile (
218 Function *func, int nvars, LLVMValueRef *callee_vars,
219 gpointer *callee_addrs, gpointer *eh_frame)
221 auto module = func->getParent ();
222 module->setDataLayout (data_layout);
223 // The lifetime of this module is managed by the C API, and the
224 // `unique_ptr` created here will be released in the
225 // NotifyCompiled callback.
226 auto k = add_module (std::unique_ptr<Module>(module));
227 auto bodysym = compile_layer.findSymbolIn (k, mangle (func), false);
228 auto bodyaddr = bodysym.getAddress ();
229 assert (bodyaddr);
230 for (int i = 0; i < nvars; ++i) {
231 auto var = unwrap<GlobalVariable> (callee_vars[i]);
232 auto sym = compile_layer.findSymbolIn (k, mangle (var->getName ()), true);
233 auto addr = sym.getAddress ();
234 g_assert ((bool)addr);
235 callee_addrs[i] = (gpointer)addr.get ();
237 auto ehsym = compile_layer.findSymbolIn (k, "mono_eh_frame", false);
238 auto ehaddr = ehsym.getAddress ();
239 g_assert ((bool)ehaddr);
240 *eh_frame = (gpointer)ehaddr.get ();
241 return (gpointer)bodyaddr.get ();
245 static void
246 init_mono_llvm_jit ()
250 static MonoLLVMJIT *
251 make_mono_llvm_jit (TargetMachine *target_machine)
253 return new MonoLLVMJIT{target_machine};
256 #elif LLVM_API_VERSION > 600
258 class MonoLLVMJIT {
259 public:
260 /* We use our own trampoline infrastructure instead of the Orc one */
261 typedef RTDyldObjectLinkingLayer ObjLayerT;
262 typedef IRCompileLayer<ObjLayerT, SimpleCompiler> CompileLayerT;
263 typedef CompileLayerT::ModuleHandleT ModuleHandleT;
265 MonoLLVMJIT (TargetMachine *TM, MonoJitMemoryManager *mm)
266 : TM(TM), ObjectLayer([=] { return std::shared_ptr<RuntimeDyld::MemoryManager> (mm); }),
267 CompileLayer (ObjectLayer, SimpleCompiler (*TM)),
268 modules() {
271 ModuleHandleT addModule(Function *F, std::shared_ptr<Module> M) {
272 auto Resolver = createLambdaResolver(
273 [&](const std::string &Name) {
274 const char *name = Name.c_str ();
275 JITSymbolFlags flags = JITSymbolFlags ();
276 if (!strcmp (name, "___bzero"))
277 return JITSymbol((uint64_t)(gssize)(void*)bzero, flags);
279 MonoDl *current;
280 char *err;
281 void *symbol;
282 current = mono_dl_open (NULL, 0, NULL);
283 g_assert (current);
284 if (name [0] == '_')
285 err = mono_dl_symbol (current, name + 1, &symbol);
286 else
287 err = mono_dl_symbol (current, name, &symbol);
288 mono_dl_close (current);
289 if (!symbol)
290 outs () << "R: " << Name << "\n";
291 assert (symbol);
292 return JITSymbol((uint64_t)(gssize)symbol, flags);
294 [](const std::string &S) {
295 outs () << "R2: " << S << "\n";
296 assert (0);
297 return nullptr;
298 } );
300 auto m = CompileLayer.addModule(M, std::move(Resolver));
301 g_assert (!!m);
302 return m.get ();
305 std::string mangle(const std::string &Name) {
306 std::string MangledName;
308 raw_string_ostream MangledNameStream(MangledName);
309 Mangler::getNameWithPrefix(MangledNameStream, Name,
310 TM->createDataLayout());
312 return MangledName;
315 std::string mangle(const GlobalValue *GV) {
316 std::string MangledName;
318 Mangler Mang;
320 raw_string_ostream MangledNameStream(MangledName);
321 Mang.getNameWithPrefix(MangledNameStream, GV, false);
323 return MangledName;
326 gpointer compile (Function *F, int nvars, LLVMValueRef *callee_vars, gpointer *callee_addrs, gpointer *eh_frame) {
327 F->getParent ()->setDataLayout (TM->createDataLayout ());
328 // Orc uses a shared_ptr to refer to modules so we have to save them ourselves to keep a ref
329 std::shared_ptr<Module> m (F->getParent ());
330 modules.push_back (m);
331 auto ModuleHandle = addModule (F, m);
332 auto BodySym = CompileLayer.findSymbolIn(ModuleHandle, mangle (F), false);
333 auto BodyAddr = BodySym.getAddress();
334 assert (BodyAddr);
336 for (int i = 0; i < nvars; ++i) {
337 GlobalVariable *var = unwrap<GlobalVariable>(callee_vars [i]);
339 auto sym = CompileLayer.findSymbolIn (ModuleHandle, mangle (var->getName ()), true);
340 auto addr = sym.getAddress ();
341 g_assert ((bool)addr);
342 callee_addrs [i] = (gpointer)addr.get ();
345 auto ehsym = CompileLayer.findSymbolIn(ModuleHandle, "mono_eh_frame", false);
346 auto ehaddr = ehsym.getAddress ();
347 g_assert ((bool)ehaddr);
348 *eh_frame = (gpointer)ehaddr.get ();
349 return (gpointer)BodyAddr.get ();
352 private:
353 TargetMachine *TM;
354 ObjLayerT ObjectLayer;
355 CompileLayerT CompileLayer;
356 std::vector<std::shared_ptr<Module>> modules;
359 static MonoJitMemoryManager *mono_mm;
361 static void
362 init_mono_llvm_jit ()
364 mono_mm = new MonoJitMemoryManager ();
367 static MonoLLVMJIT *
368 make_mono_llvm_jit (TargetMachine *target_machine)
370 return new MonoLLVMJIT(target_machine, mono_mm);
373 #endif
375 static MonoLLVMJIT *jit;
377 MonoEERef
378 mono_llvm_create_ee (LLVMModuleProviderRef MP, AllocCodeMemoryCb *alloc_cb, FunctionEmittedCb *emitted_cb, ExceptionTableCb *exception_cb, LLVMExecutionEngineRef *ee)
380 alloc_code_mem_cb = alloc_cb;
382 InitializeNativeTarget ();
383 InitializeNativeTargetAsmPrinter();
385 EnableMonoEH = true;
386 MonoEHFrameSymbol = "mono_eh_frame";
388 EngineBuilder EB;
389 TargetOptions opts;
390 EB.setOptLevel(CodeGenOpt::Aggressive);
391 EB.setMCPU(sys::getHostCPUName());
393 if (mono_use_fast_math) {
394 opts.NoInfsFPMath = true;
395 opts.NoNaNsFPMath = true;
396 opts.NoSignedZerosFPMath = true;
397 opts.NoTrappingFPMath = true;
398 opts.UnsafeFPMath = true;
399 opts.AllowFPOpFusion = FPOpFusion::Fast;
402 EB.setTargetOptions (opts);
403 auto TM = EB.selectTarget ();
404 assert (TM);
406 init_mono_llvm_jit ();
407 jit = make_mono_llvm_jit (TM);
409 return NULL;
413 * mono_llvm_compile_method:
415 * Compile METHOD to native code. Compute the addresses of the variables in CALLEE_VARS and store them into
416 * CALLEE_ADDRS. Return the EH frame address in EH_FRAME.
418 gpointer
419 mono_llvm_compile_method (MonoEERef mono_ee, LLVMValueRef method, int nvars, LLVMValueRef *callee_vars, gpointer *callee_addrs, gpointer *eh_frame)
421 return jit->compile (unwrap<Function> (method), nvars, callee_vars, callee_addrs, eh_frame);
424 void
425 mono_llvm_dispose_ee (MonoEERef *eeref)
429 MonoCPUFeatures
430 mono_llvm_get_cpu_features (void)
432 #if defined(TARGET_AMD64) || defined(TARGET_X86)
433 if (cpu_features == 0) {
434 uint64_t f = 0;
435 llvm::StringMap<bool> HostFeatures;
436 if (llvm::sys::getHostCPUFeatures(HostFeatures)) {
437 if (HostFeatures ["popcnt"])
438 f |= MONO_CPU_X86_POPCNT;
439 if (HostFeatures ["avx"])
440 f |= MONO_CPU_X86_AVX;
441 if (HostFeatures ["bmi"])
442 f |= MONO_CPU_X86_BMI1;
443 if (HostFeatures ["bmi2"])
444 f |= MONO_CPU_X86_BMI2;
446 for (auto &F : HostFeatures)
447 if (F.second)
448 outs () << "X: " << F.first () << "\n";
451 f |= MONO_CPU_INITED;
452 mono_memory_barrier ();
453 cpu_features = (MonoCPUFeatures)f;
455 #endif
457 return cpu_features;
460 #else /* MONO_CROSS_COMPILE or LLVM_API_VERSION < 600 */
462 void
463 mono_llvm_set_unhandled_exception_handler (void)
467 MonoEERef
468 mono_llvm_create_ee (LLVMModuleProviderRef MP, AllocCodeMemoryCb *alloc_cb, FunctionEmittedCb *emitted_cb, ExceptionTableCb *exception_cb, LLVMExecutionEngineRef *ee)
470 g_error ("LLVM JIT not supported on this platform.");
471 return NULL;
474 gpointer
475 mono_llvm_compile_method (MonoEERef mono_ee, LLVMValueRef method, int nvars, LLVMValueRef *callee_vars, gpointer *callee_addrs, gpointer *eh_frame)
477 g_assert_not_reached ();
478 return NULL;
481 void
482 mono_llvm_dispose_ee (MonoEERef *eeref)
484 g_assert_not_reached ();
487 MonoCPUFeatures
488 mono_llvm_get_cpu_features (void)
490 return (MonoCPUFeatures)0;
493 #endif /* !MONO_CROSS_COMPILE */