[interp] Fix interp logging (#17636)
[mono-project.git] / mono / mini / llvm-jit.cpp
blobe25ef707682cf9c54afb87b48d0e4dd0c5f1f227
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/IR/LegacyPassNameParser.h"
26 #include <llvm/ExecutionEngine/ExecutionEngine.h>
27 #include "llvm/ExecutionEngine/Orc/CompileUtils.h"
28 #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
29 #include "llvm/ExecutionEngine/Orc/LambdaResolver.h"
30 #include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
31 #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
32 #include "llvm/ExecutionEngine/JITSymbol.h"
33 #include "llvm/Transforms/Scalar.h"
34 #include "llvm/CodeGen/GCs.h"
36 #include <cstdlib>
38 #include <mono/utils/mono-dl.h>
40 using namespace llvm;
41 using namespace llvm::orc;
43 extern cl::opt<bool> EnableMonoEH;
44 extern cl::opt<std::string> MonoEHFrameSymbol;
46 void
47 mono_llvm_set_unhandled_exception_handler (void)
51 template <typename T>
52 static std::vector<T> singletonSet(T t) {
53 std::vector<T> Vec;
54 Vec.push_back(std::move(t));
55 return Vec;
58 #ifdef __MINGW32__
60 #include <stddef.h>
61 extern void *memset(void *, int, size_t);
62 void bzero (void *to, size_t count) { memset (to, 0, count); }
64 #endif
66 static AllocCodeMemoryCb *alloc_code_mem_cb;
68 class MonoJitMemoryManager : public RTDyldMemoryManager
70 public:
71 ~MonoJitMemoryManager() override;
73 uint8_t *allocateDataSection(uintptr_t Size,
74 unsigned Alignment,
75 unsigned SectionID,
76 StringRef SectionName,
77 bool IsReadOnly) override;
79 uint8_t *allocateCodeSection(uintptr_t Size,
80 unsigned Alignment,
81 unsigned SectionID,
82 StringRef SectionName) override;
84 bool finalizeMemory(std::string *ErrMsg = nullptr) override;
87 MonoJitMemoryManager::~MonoJitMemoryManager()
91 uint8_t *
92 MonoJitMemoryManager::allocateDataSection(uintptr_t Size,
93 unsigned Alignment,
94 unsigned SectionID,
95 StringRef SectionName,
96 bool IsReadOnly)
98 uint8_t *res;
100 // FIXME: Use a mempool
101 if (Alignment == 32) {
102 /* Used for SIMD */
103 res = (uint8_t*)malloc (Size + 32);
104 res += (GPOINTER_TO_UINT (res) % 32);
105 } else {
106 res = (uint8_t*)malloc (Size);
108 assert (res);
109 g_assert (GPOINTER_TO_UINT (res) % Alignment == 0);
110 memset (res, 0, Size);
111 return res;
114 uint8_t *
115 MonoJitMemoryManager::allocateCodeSection(uintptr_t Size,
116 unsigned Alignment,
117 unsigned SectionID,
118 StringRef SectionName)
120 return alloc_code_mem_cb (NULL, Size);
123 bool
124 MonoJitMemoryManager::finalizeMemory(std::string *ErrMsg)
126 return false;
129 #if LLVM_API_VERSION >= 900
131 struct MonoLLVMJIT {
132 std::shared_ptr<MonoJitMemoryManager> mmgr;
133 ExecutionSession execution_session;
134 std::map<VModuleKey, std::shared_ptr<SymbolResolver>> resolvers;
135 TargetMachine *target_machine;
136 LegacyRTDyldObjectLinkingLayer object_layer;
137 LegacyIRCompileLayer<decltype(object_layer), SimpleCompiler> compile_layer;
138 DataLayout data_layout;
140 MonoLLVMJIT (TargetMachine *tm)
141 : mmgr (std::make_shared<MonoJitMemoryManager>())
142 , target_machine (tm)
143 , object_layer (
144 AcknowledgeORCv1Deprecation, execution_session,
145 [this] (VModuleKey k) {
146 return LegacyRTDyldObjectLinkingLayer::Resources{
147 mmgr, resolvers[k] };
149 , compile_layer (
150 AcknowledgeORCv1Deprecation, object_layer,
151 SimpleCompiler{*target_machine})
152 , data_layout (target_machine->createDataLayout())
154 compile_layer.setNotifyCompiled ([] (VModuleKey, std::unique_ptr<Module> module) {
155 module.release ();
159 VModuleKey
160 add_module (std::unique_ptr<Module> m)
162 auto k = execution_session.allocateVModule();
163 auto lookup_name = [this] (const std::string &namestr) {
164 auto jit_sym = compile_layer.findSymbol(namestr, false);
165 if (jit_sym) {
166 return jit_sym;
168 auto namebuf = namestr.c_str();
169 JITSymbolFlags flags{};
170 if (!strcmp(namebuf, "___bzero")) {
171 return JITSymbol{(uint64_t)(gssize)(void*)bzero, flags};
173 auto current = mono_dl_open (NULL, 0, NULL);
174 g_assert (current);
175 auto name = namebuf[0] == '_' ? namebuf + 1 : namebuf;
176 void *sym = nullptr;
177 auto err = mono_dl_symbol (current, name, &sym);
178 if (!sym) {
179 outs () << "R: " << namestr << "\n";
181 assert (sym);
182 return JITSymbol{(uint64_t)(gssize)sym, flags};
184 auto on_error = [] (Error err) {
185 outs () << "R2: " << err << "\n";
186 assert (0);
188 auto resolver = createLegacyLookupResolver (execution_session,
189 lookup_name, on_error);
190 resolvers[k] = std::move (resolver);
191 auto err = compile_layer.addModule (k, std::move(m));
192 if (err) {
193 outs () << "addModule error: " << err << "\n";
194 assert (0);
196 return k;
199 std::string
200 mangle (const std::string &name)
202 std::string ret;
203 raw_string_ostream out{ret};
204 Mangler::getNameWithPrefix (out, name, data_layout);
205 return ret;
208 std::string
209 mangle (const GlobalValue *gv)
211 std::string ret;
212 raw_string_ostream out{ret};
213 Mangler{}.getNameWithPrefix (out, gv, false);
214 return ret;
217 gpointer
218 compile (
219 Function *func, int nvars, LLVMValueRef *callee_vars,
220 gpointer *callee_addrs, gpointer *eh_frame)
222 auto module = func->getParent ();
223 module->setDataLayout (data_layout);
224 // The lifetime of this module is managed by the C API, and the
225 // `unique_ptr` created here will be released in the
226 // NotifyCompiled callback.
227 auto k = add_module (std::unique_ptr<Module>(module));
228 auto bodysym = compile_layer.findSymbolIn (k, mangle (func), false);
229 auto bodyaddr = bodysym.getAddress ();
230 assert (bodyaddr);
231 for (int i = 0; i < nvars; ++i) {
232 auto var = unwrap<GlobalVariable> (callee_vars[i]);
233 auto sym = compile_layer.findSymbolIn (k, mangle (var->getName ()), true);
234 auto addr = sym.getAddress ();
235 g_assert ((bool)addr);
236 callee_addrs[i] = (gpointer)addr.get ();
238 auto ehsym = compile_layer.findSymbolIn (k, "mono_eh_frame", false);
239 auto ehaddr = ehsym.getAddress ();
240 g_assert ((bool)ehaddr);
241 *eh_frame = (gpointer)ehaddr.get ();
242 return (gpointer)bodyaddr.get ();
246 static void
247 init_mono_llvm_jit ()
251 static MonoLLVMJIT *
252 make_mono_llvm_jit (TargetMachine *target_machine)
254 return new MonoLLVMJIT{target_machine};
257 #elif LLVM_API_VERSION > 600
259 // The OptimizationList is automatically populated with registered Passes by the
260 // PassNameParser.
262 static cl::list<const PassInfo*, bool, PassNameParser>
263 PassList(cl::desc("Optimizations available:"));
265 class MonoLLVMJIT {
266 public:
267 /* We use our own trampoline infrastructure instead of the Orc one */
268 typedef RTDyldObjectLinkingLayer ObjLayerT;
269 typedef IRCompileLayer<ObjLayerT, SimpleCompiler> CompileLayerT;
270 typedef CompileLayerT::ModuleHandleT ModuleHandleT;
272 MonoLLVMJIT (TargetMachine *TM, MonoJitMemoryManager *mm)
273 : TM(TM), ObjectLayer([=] { return std::shared_ptr<RuntimeDyld::MemoryManager> (mm); }),
274 CompileLayer (ObjectLayer, SimpleCompiler (*TM)),
275 modules(),
276 fpm (NULL) {
277 initPassManager ();
280 void initPassManager () {
281 PassRegistry &registry = *PassRegistry::getPassRegistry();
282 initializeCore(registry);
283 initializeScalarOpts(registry);
284 initializeInstCombine(registry);
285 initializeTarget(registry);
286 linkCoreCLRGC(); // Mono uses built-in "coreclr" GCStrategy
288 // FIXME: find optimal mono specific order of passes
289 // see https://llvm.org/docs/Frontend/PerformanceTips.html#pass-ordering
290 // the following order is based on a stripped version of "OPT -O2"
291 const char *default_opts = " -simplifycfg -sroa -lower-expect -instcombine -licm -simplifycfg -lcssa -indvars -loop-deletion -gvn -memcpyopt -sccp -bdce -instcombine -dse -simplifycfg";
292 const char *opts = g_getenv ("MONO_LLVM_OPT");
293 if (opts == NULL)
294 opts = default_opts;
295 else if (opts[0] == '+') // Append passes to the default order if starts with '+', overwrite otherwise
296 opts = g_strdup_printf ("%s %s", default_opts, opts + 1);
297 else if (opts[0] != ' ') // pass order has to start with a leading whitespace
298 opts = g_strdup_printf (" %s", opts);
300 char **args = g_strsplit (opts, " ", -1);
301 llvm::cl::ParseCommandLineOptions (g_strv_length (args), args, "");
303 for (size_t i = 0; i < PassList.size(); i++) {
304 Pass *pass = PassList[i]->getNormalCtor()();
305 if (pass->getPassKind () == llvm::PT_Function || pass->getPassKind () == llvm::PT_Loop) {
306 fpm.add (pass);
307 } else {
308 printf("Opt pass is ignored: %s\n", args[i + 1]);
311 // -place-safepoints pass is mandatory
312 fpm.add (createPlaceSafepointsPass ());
314 g_strfreev (args);
315 fpm.doInitialization();
318 ModuleHandleT addModule(Function *F, std::shared_ptr<Module> M) {
319 auto Resolver = createLambdaResolver(
320 [&](const std::string &Name) {
321 const char *name = Name.c_str ();
322 JITSymbolFlags flags = JITSymbolFlags ();
323 if (!strcmp (name, "___bzero"))
324 return JITSymbol((uint64_t)(gssize)(void*)bzero, flags);
326 MonoDl *current;
327 char *err;
328 void *symbol;
329 current = mono_dl_open (NULL, 0, NULL);
330 g_assert (current);
331 if (name [0] == '_')
332 err = mono_dl_symbol (current, name + 1, &symbol);
333 else
334 err = mono_dl_symbol (current, name, &symbol);
335 mono_dl_close (current);
336 if (!symbol)
337 outs () << "R: " << Name << "\n";
338 assert (symbol);
339 return JITSymbol((uint64_t)(gssize)symbol, flags);
341 [](const std::string &S) {
342 outs () << "R2: " << S << "\n";
343 assert (0);
344 return nullptr;
345 } );
347 auto m = CompileLayer.addModule(M, std::move(Resolver));
348 g_assert (!!m);
349 return m.get ();
352 std::string mangle(const std::string &Name) {
353 std::string MangledName;
355 raw_string_ostream MangledNameStream(MangledName);
356 Mangler::getNameWithPrefix(MangledNameStream, Name,
357 TM->createDataLayout());
359 return MangledName;
362 std::string mangle(const GlobalValue *GV) {
363 std::string MangledName;
365 Mangler Mang;
367 raw_string_ostream MangledNameStream(MangledName);
368 Mang.getNameWithPrefix(MangledNameStream, GV, false);
370 return MangledName;
373 gpointer compile (Function *F, int nvars, LLVMValueRef *callee_vars, gpointer *callee_addrs, gpointer *eh_frame) {
374 F->getParent ()->setDataLayout (TM->createDataLayout ());
375 fpm.run(*F);
376 // TODO: run module wide optimizations, e.g. remove dead globals/functions
377 // Orc uses a shared_ptr to refer to modules so we have to save them ourselves to keep a ref
378 std::shared_ptr<Module> m (F->getParent ());
379 modules.push_back (m);
380 auto ModuleHandle = addModule (F, m);
381 auto BodySym = CompileLayer.findSymbolIn(ModuleHandle, mangle (F), false);
382 auto BodyAddr = BodySym.getAddress();
383 assert (BodyAddr);
385 for (int i = 0; i < nvars; ++i) {
386 GlobalVariable *var = unwrap<GlobalVariable>(callee_vars [i]);
388 auto sym = CompileLayer.findSymbolIn (ModuleHandle, mangle (var->getName ()), true);
389 auto addr = sym.getAddress ();
390 g_assert ((bool)addr);
391 callee_addrs [i] = (gpointer)addr.get ();
394 auto ehsym = CompileLayer.findSymbolIn(ModuleHandle, "mono_eh_frame", false);
395 auto ehaddr = ehsym.getAddress ();
396 g_assert ((bool)ehaddr);
397 *eh_frame = (gpointer)ehaddr.get ();
398 return (gpointer)BodyAddr.get ();
401 private:
402 TargetMachine *TM;
403 ObjLayerT ObjectLayer;
404 CompileLayerT CompileLayer;
405 std::vector<std::shared_ptr<Module>> modules;
406 legacy::FunctionPassManager fpm;
409 static MonoJitMemoryManager *mono_mm;
411 static void
412 init_mono_llvm_jit ()
414 mono_mm = new MonoJitMemoryManager ();
417 static MonoLLVMJIT *
418 make_mono_llvm_jit (TargetMachine *target_machine)
420 return new MonoLLVMJIT(target_machine, mono_mm);
423 #endif
425 static MonoLLVMJIT *jit;
427 MonoEERef
428 mono_llvm_create_ee (AllocCodeMemoryCb *alloc_cb, FunctionEmittedCb *emitted_cb, ExceptionTableCb *exception_cb, LLVMExecutionEngineRef *ee)
430 alloc_code_mem_cb = alloc_cb;
432 InitializeNativeTarget ();
433 InitializeNativeTargetAsmPrinter();
435 EnableMonoEH = true;
436 MonoEHFrameSymbol = "mono_eh_frame";
437 EngineBuilder EB;
439 if (mono_use_fast_math) {
440 TargetOptions opts;
441 opts.NoInfsFPMath = true;
442 opts.NoNaNsFPMath = true;
443 opts.NoSignedZerosFPMath = true;
444 opts.NoTrappingFPMath = true;
445 opts.UnsafeFPMath = true;
446 opts.AllowFPOpFusion = FPOpFusion::Fast;
447 EB.setTargetOptions (opts);
450 EB.setOptLevel(CodeGenOpt::Aggressive);
451 EB.setMCPU(sys::getHostCPUName());
452 auto TM = EB.selectTarget ();
453 assert (TM);
455 init_mono_llvm_jit ();
456 jit = make_mono_llvm_jit (TM);
458 return NULL;
462 * mono_llvm_compile_method:
464 * Compile METHOD to native code. Compute the addresses of the variables in CALLEE_VARS and store them into
465 * CALLEE_ADDRS. Return the EH frame address in EH_FRAME.
467 gpointer
468 mono_llvm_compile_method (MonoEERef mono_ee, LLVMValueRef method, int nvars, LLVMValueRef *callee_vars, gpointer *callee_addrs, gpointer *eh_frame)
470 return jit->compile (unwrap<Function> (method), nvars, callee_vars, callee_addrs, eh_frame);
473 void
474 mono_llvm_dispose_ee (MonoEERef *eeref)
478 #else /* MONO_CROSS_COMPILE or LLVM_API_VERSION < 600 */
480 void
481 mono_llvm_set_unhandled_exception_handler (void)
485 MonoEERef
486 mono_llvm_create_ee (AllocCodeMemoryCb *alloc_cb, FunctionEmittedCb *emitted_cb, ExceptionTableCb *exception_cb, LLVMExecutionEngineRef *ee)
488 g_error ("LLVM JIT not supported on this platform.");
489 return NULL;
492 gpointer
493 mono_llvm_compile_method (MonoEERef mono_ee, LLVMValueRef method, int nvars, LLVMValueRef *callee_vars, gpointer *callee_addrs, gpointer *eh_frame)
495 g_assert_not_reached ();
496 return NULL;
499 void
500 mono_llvm_dispose_ee (MonoEERef *eeref)
502 g_assert_not_reached ();
505 #endif /* !MONO_CROSS_COMPILE */