Revert "[mono][debugger] First PR to implement iCorDebug on mono (#20757)"
[mono-project.git] / mono / mini / llvm-jit.cpp
blob192758699ef1e3552624e702cbe7ec07d7dadead
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/ADT/SmallVector.h>
22 #include <llvm/Support/raw_ostream.h>
23 #include <llvm/Support/Host.h>
24 #include <llvm/Support/Memory.h>
25 #include <llvm/Support/TargetSelect.h>
26 #include <llvm/IR/Mangler.h>
27 #include "llvm/IR/LegacyPassManager.h"
28 #include "llvm/IR/LegacyPassNameParser.h"
29 #include <llvm/ExecutionEngine/ExecutionEngine.h>
30 #include "llvm/ExecutionEngine/Orc/CompileUtils.h"
31 #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
32 #include "llvm/ExecutionEngine/Orc/LambdaResolver.h"
33 #include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
34 #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
35 #include "llvm/ExecutionEngine/JITSymbol.h"
36 #include "llvm/Transforms/Scalar.h"
38 #if LLVM_API_VERSION >= 800
39 #include "llvm/CodeGen/BuiltinGCs.h"
40 #else
41 #include "llvm/CodeGen/GCs.h"
42 #endif
44 #include <cstdlib>
46 #include <mono/utils/mono-dl.h>
48 using namespace llvm;
49 using namespace llvm::orc;
51 extern cl::opt<bool> EnableMonoEH;
52 extern cl::opt<std::string> MonoEHFrameSymbol;
54 void
55 mono_llvm_set_unhandled_exception_handler (void)
59 // noop function that merely ensures that certain symbols are not eliminated
60 // from the resulting binary.
61 static void
62 link_gc () {
63 #if LLVM_API_VERSION >= 800
64 llvm::linkAllBuiltinGCs();
65 #else
66 llvm::linkCoreCLRGC(); // Mono uses built-in "coreclr" GCStrategy
67 #endif
70 template <typename T>
71 static std::vector<T> singletonSet(T t) {
72 std::vector<T> Vec;
73 Vec.push_back(std::move(t));
74 return Vec;
77 #ifdef __MINGW32__
79 #include <stddef.h>
80 extern void *memset(void *, int, size_t);
81 void bzero (void *to, size_t count) { memset (to, 0, count); }
83 #endif
85 static MonoNativeTlsKey current_cfg_tls_id;
87 static unsigned char *
88 alloc_code (LLVMValueRef function, int size)
90 auto cfg = (MonoCompile *)mono_native_tls_get_value (current_cfg_tls_id);
91 g_assert (cfg);
92 return (unsigned char *)mono_mem_manager_code_reserve (cfg->mem_manager, size);
95 class MonoJitMemoryManager : public RTDyldMemoryManager
97 public:
98 ~MonoJitMemoryManager() override;
100 uint8_t *allocateDataSection(uintptr_t Size,
101 unsigned Alignment,
102 unsigned SectionID,
103 StringRef SectionName,
104 bool IsReadOnly) override;
106 uint8_t *allocateCodeSection(uintptr_t Size,
107 unsigned Alignment,
108 unsigned SectionID,
109 StringRef SectionName) override;
111 bool finalizeMemory(std::string *ErrMsg = nullptr) override;
112 private:
113 SmallVector<sys::MemoryBlock, 16> PendingCodeMem;
116 MonoJitMemoryManager::~MonoJitMemoryManager()
120 uint8_t *
121 MonoJitMemoryManager::allocateDataSection(uintptr_t Size,
122 unsigned Alignment,
123 unsigned SectionID,
124 StringRef SectionName,
125 bool IsReadOnly)
127 uint8_t *res;
129 // FIXME: Use a mempool
130 if (Alignment == 0)
131 Alignment = 16;
132 res = (uint8_t*)malloc (Size + Alignment);
133 res = (uint8_t*)ALIGN_PTR_TO(res, Alignment);
134 assert (res);
135 g_assert (GPOINTER_TO_UINT (res) % Alignment == 0);
136 memset (res, 0, Size);
137 return res;
140 uint8_t *
141 MonoJitMemoryManager::allocateCodeSection(uintptr_t Size,
142 unsigned Alignment,
143 unsigned SectionID,
144 StringRef SectionName)
146 uint8_t *mem = alloc_code (NULL, Size);
147 PendingCodeMem.push_back (sys::MemoryBlock ((void *)mem, Size));
148 return mem;
151 bool
152 MonoJitMemoryManager::finalizeMemory(std::string *ErrMsg)
154 for (sys::MemoryBlock &Block : PendingCodeMem) {
155 #if LLVM_API_VERSION >= 900
156 sys::Memory::InvalidateInstructionCache (Block.base (), Block.allocatedSize ());
157 #else
158 sys::Memory::InvalidateInstructionCache (Block.base (), Block.size ());
159 #endif
161 PendingCodeMem.clear ();
162 return false;
165 #if defined(TARGET_AMD64) || defined(TARGET_X86)
166 #define NO_CALL_FRAME_OPT " -no-x86-call-frame-opt"
167 #else
168 #define NO_CALL_FRAME_OPT ""
169 #endif
171 // The OptimizationList is automatically populated with registered Passes by the
172 // PassNameParser.
174 static cl::list<const PassInfo*, bool, PassNameParser>
175 PassList(cl::desc("Optimizations available:"));
177 static void
178 init_function_pass_manager (legacy::FunctionPassManager &fpm)
180 auto reg = PassRegistry::getPassRegistry ();
181 for (size_t i = 0; i < PassList.size(); i++) {
182 Pass *pass = PassList[i]->getNormalCtor()();
183 if (pass->getPassKind () == llvm::PT_Function || pass->getPassKind () == llvm::PT_Loop) {
184 fpm.add (pass);
185 } else {
186 auto info = reg->getPassInfo (pass->getPassID());
187 auto name = info->getPassArgument ();
188 printf("Opt pass is ignored: %.*s\n", (int) name.size(), name.data());
191 // -place-safepoints pass is mandatory
192 fpm.add (createPlaceSafepointsPass ());
194 fpm.doInitialization();
197 #if LLVM_API_VERSION >= 900
199 struct MonoLLVMJIT {
200 std::shared_ptr<MonoJitMemoryManager> mmgr;
201 ExecutionSession execution_session;
202 std::map<VModuleKey, std::shared_ptr<SymbolResolver>> resolvers;
203 TargetMachine *target_machine;
204 LegacyRTDyldObjectLinkingLayer object_layer;
205 LegacyIRCompileLayer<decltype(object_layer), SimpleCompiler> compile_layer;
206 DataLayout data_layout;
207 legacy::FunctionPassManager fpm;
209 MonoLLVMJIT (TargetMachine *tm, Module *pgo_module)
210 : mmgr (std::make_shared<MonoJitMemoryManager>())
211 , target_machine (tm)
212 , object_layer (
213 AcknowledgeORCv1Deprecation, execution_session,
214 [this] (VModuleKey k) {
215 return LegacyRTDyldObjectLinkingLayer::Resources{
216 mmgr, resolvers[k] };
218 , compile_layer (
219 AcknowledgeORCv1Deprecation, object_layer,
220 SimpleCompiler{*target_machine})
221 , data_layout (target_machine->createDataLayout())
222 , fpm (pgo_module)
224 compile_layer.setNotifyCompiled ([] (VModuleKey, std::unique_ptr<Module> module) {
225 module.release ();
227 init_function_pass_manager (fpm);
230 VModuleKey
231 add_module (std::unique_ptr<Module> m)
233 auto k = execution_session.allocateVModule();
234 auto lookup_name = [this] (const std::string &namestr) {
235 auto jit_sym = compile_layer.findSymbol(namestr, false);
236 if (jit_sym) {
237 return jit_sym;
239 auto namebuf = namestr.c_str();
240 JITSymbolFlags flags{};
241 if (!strcmp(namebuf, "___bzero")) {
242 return JITSymbol{(uint64_t)(gssize)(void*)bzero, flags};
244 auto current = mono_dl_open (NULL, 0, NULL);
245 g_assert (current);
246 auto name = namebuf[0] == '_' ? namebuf + 1 : namebuf;
247 void *sym = nullptr;
248 auto err = mono_dl_symbol (current, name, &sym);
249 if (!sym) {
250 outs () << "R: " << namestr << " " << err << "\n";
252 assert (sym);
253 return JITSymbol{(uint64_t)(gssize)sym, flags};
255 auto on_error = [] (Error err) {
256 outs () << "R2: " << err << "\n";
257 assert (0);
259 auto resolver = createLegacyLookupResolver (execution_session,
260 lookup_name, on_error);
261 resolvers[k] = std::move (resolver);
262 auto err = compile_layer.addModule (k, std::move(m));
263 if (err) {
264 outs () << "addModule error: " << err << "\n";
265 assert (0);
267 return k;
270 std::string
271 mangle (llvm::StringRef name)
273 std::string ret;
274 raw_string_ostream out{ret};
275 Mangler::getNameWithPrefix (out, name, data_layout);
276 return ret;
279 std::string
280 mangle (const GlobalValue *gv)
282 std::string ret;
283 raw_string_ostream out{ret};
284 Mangler{}.getNameWithPrefix (out, gv, false);
285 return ret;
288 gpointer
289 compile (
290 Function *func, int nvars, LLVMValueRef *callee_vars,
291 gpointer *callee_addrs, gpointer *eh_frame)
293 auto module = func->getParent ();
294 module->setDataLayout (data_layout);
295 fpm.run (*func);
296 // The lifetime of this module is managed by Mono, not LLVM, so
297 // the `unique_ptr` created here will be released in the
298 // NotifyCompiled callback.
299 auto k = add_module (std::unique_ptr<Module>(module));
300 auto bodysym = compile_layer.findSymbolIn (k, mangle (func), false);
301 auto bodyaddr = bodysym.getAddress ();
302 if (!bodyaddr)
303 g_assert_not_reached();
304 for (int i = 0; i < nvars; ++i) {
305 auto var = unwrap<GlobalVariable> (callee_vars[i]);
306 auto sym = compile_layer.findSymbolIn (k, mangle (var->getName ()), true);
307 auto addr = sym.getAddress ();
308 g_assert ((bool)addr);
309 callee_addrs[i] = (gpointer)addr.get ();
311 auto ehsym = compile_layer.findSymbolIn (k, "mono_eh_frame", false);
312 auto ehaddr = ehsym.getAddress ();
313 g_assert ((bool)ehaddr);
314 *eh_frame = (gpointer)ehaddr.get ();
315 return (gpointer)bodyaddr.get ();
319 static MonoLLVMJIT *
320 make_mono_llvm_jit (TargetMachine *target_machine, llvm::Module *pgo_module)
322 return new MonoLLVMJIT{target_machine, pgo_module};
325 #elif LLVM_API_VERSION > 600
327 class MonoLLVMJIT {
328 public:
329 /* We use our own trampoline infrastructure instead of the Orc one */
330 typedef RTDyldObjectLinkingLayer ObjLayerT;
331 typedef IRCompileLayer<ObjLayerT, SimpleCompiler> CompileLayerT;
332 typedef CompileLayerT::ModuleHandleT ModuleHandleT;
334 MonoLLVMJIT (TargetMachine *TM, MonoJitMemoryManager *mm)
335 : TM(TM), ObjectLayer([=] { return std::shared_ptr<RuntimeDyld::MemoryManager> (mm); }),
336 CompileLayer (ObjectLayer, SimpleCompiler (*TM)),
337 modules(),
338 fpm (nullptr)
340 init_function_pass_manager (fpm);
343 ModuleHandleT addModule(Function *F, std::shared_ptr<Module> M) {
344 auto Resolver = createLambdaResolver(
345 [&](const std::string &Name) {
346 const char *name = Name.c_str ();
347 JITSymbolFlags flags = JITSymbolFlags ();
348 if (!strcmp (name, "___bzero"))
349 return JITSymbol((uint64_t)(gssize)(void*)bzero, flags);
351 MonoDl *current;
352 char *err;
353 void *symbol;
354 current = mono_dl_open (NULL, 0, NULL);
355 g_assert (current);
356 if (name [0] == '_')
357 err = mono_dl_symbol (current, name + 1, &symbol);
358 else
359 err = mono_dl_symbol (current, name, &symbol);
360 mono_dl_close (current);
361 if (!symbol)
362 outs () << "R: " << Name << "\n";
363 assert (symbol);
364 return JITSymbol((uint64_t)(gssize)symbol, flags);
366 [](const std::string &S) {
367 outs () << "R2: " << S << "\n";
368 assert (0);
369 return nullptr;
370 } );
372 auto m = CompileLayer.addModule(M, std::move(Resolver));
373 g_assert (!!m);
374 return m.get ();
377 std::string mangle(const std::string &Name) {
378 std::string MangledName;
380 raw_string_ostream MangledNameStream(MangledName);
381 Mangler::getNameWithPrefix(MangledNameStream, Name,
382 TM->createDataLayout());
384 return MangledName;
387 std::string mangle(const GlobalValue *GV) {
388 std::string MangledName;
390 Mangler Mang;
392 raw_string_ostream MangledNameStream(MangledName);
393 Mang.getNameWithPrefix(MangledNameStream, GV, false);
395 return MangledName;
398 gpointer compile (Function *F, int nvars, LLVMValueRef *callee_vars, gpointer *callee_addrs, gpointer *eh_frame) {
399 F->getParent ()->setDataLayout (TM->createDataLayout ());
400 fpm.run(*F);
401 // TODO: run module wide optimizations, e.g. remove dead globals/functions
402 // Orc uses a shared_ptr to refer to modules so we have to save them ourselves to keep a ref
403 std::shared_ptr<Module> m (F->getParent ());
404 modules.push_back (m);
405 auto ModuleHandle = addModule (F, m);
406 auto BodySym = CompileLayer.findSymbolIn(ModuleHandle, mangle (F), false);
407 auto BodyAddr = BodySym.getAddress();
408 if (!BodyAddr)
409 g_assert_not_reached ();
411 for (int i = 0; i < nvars; ++i) {
412 GlobalVariable *var = unwrap<GlobalVariable>(callee_vars [i]);
414 auto sym = CompileLayer.findSymbolIn (ModuleHandle, mangle (var->getName ()), true);
415 auto addr = sym.getAddress ();
416 g_assert ((bool)addr);
417 callee_addrs [i] = (gpointer)addr.get ();
420 auto ehsym = CompileLayer.findSymbolIn(ModuleHandle, "mono_eh_frame", false);
421 auto ehaddr = ehsym.getAddress ();
422 g_assert ((bool)ehaddr);
423 *eh_frame = (gpointer)ehaddr.get ();
424 return (gpointer)BodyAddr.get ();
427 private:
428 TargetMachine *TM;
429 ObjLayerT ObjectLayer;
430 CompileLayerT CompileLayer;
431 std::vector<std::shared_ptr<Module>> modules;
432 legacy::FunctionPassManager fpm;
435 static MonoJitMemoryManager *mono_mm;
437 static MonoLLVMJIT *
438 make_mono_llvm_jit (TargetMachine *target_machine, llvm::Module *)
440 mono_mm = new MonoJitMemoryManager ();
441 return new MonoLLVMJIT(target_machine, mono_mm);
444 #endif
446 static llvm::Module *dummy_pgo_module = nullptr;
447 static MonoLLVMJIT *jit;
449 static void
450 init_passes_and_options ()
452 PassRegistry &registry = *PassRegistry::getPassRegistry();
453 initializeCore(registry);
454 initializeScalarOpts(registry);
455 initializeInstCombine(registry);
456 initializeTarget(registry);
457 initializeLoopIdiomRecognizeLegacyPassPass(registry);
459 // FIXME: find optimal mono specific order of passes
460 // see https://llvm.org/docs/Frontend/PerformanceTips.html#pass-ordering
461 // the following order is based on a stripped version of "OPT -O2"
462 const char *default_opts = " -simplifycfg -sroa -lower-expect -instcombine -sroa -jump-threading -loop-rotate -licm -simplifycfg -lcssa -loop-idiom -indvars -loop-deletion -gvn -memcpyopt -sccp -bdce -instcombine -dse -simplifycfg -enable-implicit-null-checks -sroa -instcombine" NO_CALL_FRAME_OPT;
463 const char *opts = g_getenv ("MONO_LLVM_OPT");
464 if (opts == NULL)
465 opts = default_opts;
466 else if (opts[0] == '+') // Append passes to the default order if starts with '+', overwrite otherwise
467 opts = g_strdup_printf ("%s %s", default_opts, opts + 1);
468 else if (opts[0] != ' ') // pass order has to start with a leading whitespace
469 opts = g_strdup_printf (" %s", opts);
471 char **args = g_strsplit (opts, " ", -1);
472 llvm::cl::ParseCommandLineOptions (g_strv_length (args), args, "");
473 g_strfreev (args);
476 void
477 mono_llvm_jit_init ()
479 if (jit != nullptr) return;
481 link_gc ();
483 mono_native_tls_alloc (&current_cfg_tls_id, NULL);
485 InitializeNativeTarget ();
486 InitializeNativeTargetAsmPrinter();
488 EnableMonoEH = true;
489 MonoEHFrameSymbol = "mono_eh_frame";
490 EngineBuilder EB;
492 if (mono_use_fast_math) {
493 TargetOptions opts;
494 opts.NoInfsFPMath = true;
495 opts.NoNaNsFPMath = true;
496 opts.NoSignedZerosFPMath = true;
497 opts.NoTrappingFPMath = true;
498 opts.UnsafeFPMath = true;
499 opts.AllowFPOpFusion = FPOpFusion::Fast;
500 EB.setTargetOptions (opts);
503 EB.setOptLevel (CodeGenOpt::Aggressive);
504 EB.setMCPU (sys::getHostCPUName ());
506 #ifdef TARGET_AMD64
507 EB.setMArch ("x86-64");
508 #elif TARGET_X86
509 EB.setMArch ("x86");
510 #elif TARGET_ARM64
511 EB.setMArch ("aarch64");
512 #elif TARGET_ARM
513 EB.setMArch ("arm");
514 #else
515 g_assert_not_reached ();
516 #endif
518 llvm::StringMap<bool> cpu_features;
519 // Why 76? LLVM 9 supports 76 different x86 feature strings. This
520 // requires around 1216 bytes of data in the local activation record.
521 // It'd be possible to stream entries to setMAttrs using
522 // llvm::map_range and llvm::make_filter_range, but llvm::map_range
523 // isn't available in LLVM 6, and it's not worth writing a small
524 // single-purpose one here.
525 llvm::SmallVector<llvm::StringRef, 76> supported_features;
526 if (llvm::sys::getHostCPUFeatures (cpu_features)) {
527 for (const auto &feature : cpu_features) {
528 if (feature.second)
529 supported_features.push_back (feature.first ());
531 EB.setMAttrs (supported_features);
534 auto TM = EB.selectTarget ();
535 assert (TM);
536 dummy_pgo_module = unwrap (LLVMModuleCreateWithName("dummy-pgo-module"));
537 init_passes_and_options ();
538 jit = make_mono_llvm_jit (TM, dummy_pgo_module);
541 MonoEERef
542 mono_llvm_create_ee (LLVMExecutionEngineRef *ee)
544 return NULL;
548 * mono_llvm_compile_method:
550 * Compile METHOD to native code. Compute the addresses of the variables in CALLEE_VARS and store them into
551 * CALLEE_ADDRS. Return the EH frame address in EH_FRAME.
553 gpointer
554 mono_llvm_compile_method (MonoEERef mono_ee, MonoCompile *cfg, LLVMValueRef method, int nvars, LLVMValueRef *callee_vars, gpointer *callee_addrs, gpointer *eh_frame)
556 mono_native_tls_set_value (current_cfg_tls_id, cfg);
557 auto ret = jit->compile (unwrap<Function> (method), nvars, callee_vars, callee_addrs, eh_frame);
558 mono_native_tls_set_value (current_cfg_tls_id, nullptr);
559 return ret;
562 void
563 mono_llvm_dispose_ee (MonoEERef *eeref)
567 #else /* MONO_CROSS_COMPILE or LLVM_API_VERSION < 600 */
569 void
570 mono_llvm_set_unhandled_exception_handler (void)
574 void
575 mono_llvm_jit_init ()
579 MonoEERef
580 mono_llvm_create_ee (LLVMExecutionEngineRef *ee)
582 g_error ("LLVM JIT not supported on this platform.");
583 return NULL;
586 gpointer
587 mono_llvm_compile_method (MonoEERef mono_ee, MonoCompile *cfg, LLVMValueRef method, int nvars, LLVMValueRef *callee_vars, gpointer *callee_addrs, gpointer *eh_frame)
589 g_assert_not_reached ();
590 return NULL;
593 void
594 mono_llvm_dispose_ee (MonoEERef *eeref)
596 g_assert_not_reached ();
599 #endif /* !MONO_CROSS_COMPILE */