diff --git a/src/mono/mono/mini/llvm-jit.cpp b/src/mono/mono/mini/llvm-jit.cpp index d8c9bd5b92412..325e09c2cc383 100644 --- a/src/mono/mono/mini/llvm-jit.cpp +++ b/src/mono/mono/mini/llvm-jit.cpp @@ -24,6 +24,7 @@ #include #include #include +#include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/LegacyPassNameParser.h" #include #include "llvm/ExecutionEngine/Orc/CompileUtils.h" @@ -161,6 +162,38 @@ MonoJitMemoryManager::finalizeMemory(std::string *ErrMsg) return false; } +#if defined(TARGET_AMD64) || defined(TARGET_X86) +#define NO_CALL_FRAME_OPT " -no-x86-call-frame-opt" +#else +#define NO_CALL_FRAME_OPT "" +#endif + +// The OptimizationList is automatically populated with registered Passes by the +// PassNameParser. +// +static cl::list +PassList(cl::desc("Optimizations available:")); + +static void +init_function_pass_manager (legacy::FunctionPassManager &fpm) +{ + auto reg = PassRegistry::getPassRegistry (); + for (size_t i = 0; i < PassList.size(); i++) { + Pass *pass = PassList[i]->getNormalCtor()(); + if (pass->getPassKind () == llvm::PT_Function || pass->getPassKind () == llvm::PT_Loop) { + fpm.add (pass); + } else { + auto info = reg->getPassInfo (pass->getPassID()); + auto name = info->getPassArgument (); + printf("Opt pass is ignored: %.*s\n", name.size(), name.data()); + } + } + // -place-safepoints pass is mandatory + fpm.add (createPlaceSafepointsPass ()); + + fpm.doInitialization(); +} + #if LLVM_API_VERSION >= 900 struct MonoLLVMJIT { @@ -171,8 +204,9 @@ struct MonoLLVMJIT { LegacyRTDyldObjectLinkingLayer object_layer; LegacyIRCompileLayer compile_layer; DataLayout data_layout; + legacy::FunctionPassManager fpm; - MonoLLVMJIT (TargetMachine *tm) + MonoLLVMJIT (TargetMachine *tm, Module *pgo_module) : mmgr (std::make_shared()) , target_machine (tm) , object_layer ( @@ -185,10 +219,12 @@ struct MonoLLVMJIT { AcknowledgeORCv1Deprecation, object_layer, SimpleCompiler{*target_machine}) , data_layout (target_machine->createDataLayout()) + , fpm (pgo_module) { compile_layer.setNotifyCompiled ([] (VModuleKey, std::unique_ptr module) { module.release (); }); + init_function_pass_manager (fpm); } VModuleKey @@ -232,7 +268,7 @@ struct MonoLLVMJIT { } std::string - mangle (const std::string &name) + mangle (llvm::StringRef name) { std::string ret; raw_string_ostream out{ret}; @@ -256,8 +292,9 @@ struct MonoLLVMJIT { { auto module = func->getParent (); module->setDataLayout (data_layout); - // The lifetime of this module is managed by the C API, and the - // `unique_ptr` created here will be released in the + fpm.run (*func); + // The lifetime of this module is managed by Mono, not LLVM, so + // the `unique_ptr` created here will be released in the // NotifyCompiled callback. auto k = add_module (std::unique_ptr(module)); auto bodysym = compile_layer.findSymbolIn (k, mangle (func), false); @@ -279,25 +316,13 @@ struct MonoLLVMJIT { }; static MonoLLVMJIT * -make_mono_llvm_jit (TargetMachine *target_machine) +make_mono_llvm_jit (TargetMachine *target_machine, llvm::Module *pgo_module) { - return new MonoLLVMJIT{target_machine}; + return new MonoLLVMJIT{target_machine, pgo_module}; } #elif LLVM_API_VERSION > 600 -#if defined(TARGET_AMD64) || defined(TARGET_X86) -#define NO_CALL_FRAME_OPT " -no-x86-call-frame-opt" -#else -#define NO_CALL_FRAME_OPT "" -#endif - -// The OptimizationList is automatically populated with registered Passes by the -// PassNameParser. -// -static cl::list -PassList(cl::desc("Optimizations available:")); - class MonoLLVMJIT { public: /* We use our own trampoline infrastructure instead of the Orc one */ @@ -309,46 +334,9 @@ class MonoLLVMJIT { : TM(TM), ObjectLayer([=] { return std::shared_ptr (mm); }), CompileLayer (ObjectLayer, SimpleCompiler (*TM)), modules(), - fpm (NULL) { - initPassManager (); - } - - void initPassManager () { - PassRegistry ®istry = *PassRegistry::getPassRegistry(); - initializeCore(registry); - initializeScalarOpts(registry); - initializeInstCombine(registry); - initializeTarget(registry); - initializeLoopIdiomRecognizeLegacyPassPass(registry); - - // FIXME: find optimal mono specific order of passes - // see https://llvm.org/docs/Frontend/PerformanceTips.html#pass-ordering - // the following order is based on a stripped version of "OPT -O2" - const char *default_opts = " -simplifycfg -sroa -lower-expect -instcombine -jump-threading -loop-rotate -licm -simplifycfg -lcssa -loop-idiom -indvars -loop-deletion -gvn -memcpyopt -sccp -bdce -instcombine -dse -simplifycfg -enable-implicit-null-checks" NO_CALL_FRAME_OPT; - const char *opts = g_getenv ("MONO_LLVM_OPT"); - if (opts == NULL) - opts = default_opts; - else if (opts[0] == '+') // Append passes to the default order if starts with '+', overwrite otherwise - opts = g_strdup_printf ("%s %s", default_opts, opts + 1); - else if (opts[0] != ' ') // pass order has to start with a leading whitespace - opts = g_strdup_printf (" %s", opts); - - char **args = g_strsplit (opts, " ", -1); - llvm::cl::ParseCommandLineOptions (g_strv_length (args), args, ""); - - for (size_t i = 0; i < PassList.size(); i++) { - Pass *pass = PassList[i]->getNormalCtor()(); - if (pass->getPassKind () == llvm::PT_Function || pass->getPassKind () == llvm::PT_Loop) { - fpm.add (pass); - } else { - printf("Opt pass is ignored: %s\n", args[i + 1]); - } - } - // -place-safepoints pass is mandatory - fpm.add (createPlaceSafepointsPass ()); - - g_strfreev (args); - fpm.doInitialization(); + fpm (nullptr) + { + init_function_pass_manager (fpm); } ModuleHandleT addModule(Function *F, std::shared_ptr M) { @@ -445,7 +433,7 @@ class MonoLLVMJIT { static MonoJitMemoryManager *mono_mm; static MonoLLVMJIT * -make_mono_llvm_jit (TargetMachine *target_machine) +make_mono_llvm_jit (TargetMachine *target_machine, llvm::Module *) { mono_mm = new MonoJitMemoryManager (); return new MonoLLVMJIT(target_machine, mono_mm); @@ -453,8 +441,36 @@ make_mono_llvm_jit (TargetMachine *target_machine) #endif +static llvm::Module *dummy_pgo_module = nullptr; static MonoLLVMJIT *jit; +static void +init_passes_and_options () +{ + PassRegistry ®istry = *PassRegistry::getPassRegistry(); + initializeCore(registry); + initializeScalarOpts(registry); + initializeInstCombine(registry); + initializeTarget(registry); + initializeLoopIdiomRecognizeLegacyPassPass(registry); + + // FIXME: find optimal mono specific order of passes + // see https://llvm.org/docs/Frontend/PerformanceTips.html#pass-ordering + // the following order is based on a stripped version of "OPT -O2" + const char *default_opts = " -simplifycfg -sroa -lower-expect -instcombine -jump-threading -loop-rotate -licm -simplifycfg -lcssa -loop-idiom -indvars -loop-deletion -gvn -memcpyopt -sccp -bdce -instcombine -dse -simplifycfg -enable-implicit-null-checks" NO_CALL_FRAME_OPT; + const char *opts = g_getenv ("MONO_LLVM_OPT"); + if (opts == NULL) + opts = default_opts; + else if (opts[0] == '+') // Append passes to the default order if starts with '+', overwrite otherwise + opts = g_strdup_printf ("%s %s", default_opts, opts + 1); + else if (opts[0] != ' ') // pass order has to start with a leading whitespace + opts = g_strdup_printf (" %s", opts); + + char **args = g_strsplit (opts, " ", -1); + llvm::cl::ParseCommandLineOptions (g_strv_length (args), args, ""); + g_strfreev (args); +} + void mono_llvm_jit_init () { @@ -499,8 +515,9 @@ mono_llvm_jit_init () auto TM = EB.selectTarget (); assert (TM); - - jit = make_mono_llvm_jit (TM); + dummy_pgo_module = unwrap (LLVMModuleCreateWithName("dummy-pgo-module")); + init_passes_and_options (); + jit = make_mono_llvm_jit (TM, dummy_pgo_module); } MonoEERef