[llvm] Enable optimizations for LLVM 9 JIT. (#34555)
authormonojenkins <jo.shields+jenkins@xamarin.com>
Sun, 5 Apr 2020 19:09:04 +0000 (15:09 -0400)
committerGitHub <noreply@github.com>
Sun, 5 Apr 2020 19:09:04 +0000 (12:09 -0700)
Share more code between LLVM 6 and LLVM 9.

Mangler::getNameWithPrefix takes a Twine, not a std::string, so use a
StringRef to avoid an unnecessary allocation.

InstructionCombiningPass grew a dependency on
ProfileSummaryInfoWrapperPass in
https://github.com/dotnet/llvm-project/commit/09e539fcaebb6362795d352cdcf4a818cf4d0d6a,
which depends on the enclosing FunctionPassManager having a valid
reference to a module. This commit adds a dummy module to satisfy this,
instead of recreating a new FunctionPassManager on every compilation.
(See also
http://lists.llvm.org/pipermail/llvm-dev/2019-March/130690.html.)

Co-authored-by: imhameed <imhameed@users.noreply.github.com>
src/mono/mono/mini/llvm-jit.cpp

index d8c9bd5b9241265b851d660756ade85e9a3bc913..325e09c2cc3830c3a12e155597dad64a0b75d562 100644 (file)
@@ -24,6 +24,7 @@
 #include <llvm/Support/Memory.h>
 #include <llvm/Support/TargetSelect.h>
 #include <llvm/IR/Mangler.h>
+#include "llvm/IR/LegacyPassManager.h"
 #include "llvm/IR/LegacyPassNameParser.h"
 #include <llvm/ExecutionEngine/ExecutionEngine.h>
 #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<const PassInfo*, bool, PassNameParser>
+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<decltype(object_layer), SimpleCompiler> compile_layer;
        DataLayout data_layout;
+       legacy::FunctionPassManager fpm;
 
-       MonoLLVMJIT (TargetMachine *tm)
+       MonoLLVMJIT (TargetMachine *tm, Module *pgo_module)
                : mmgr (std::make_shared<MonoJitMemoryManager>())
                , 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) {
                        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>(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<const PassInfo*, bool, PassNameParser>
-PassList(cl::desc("Optimizations available:"));
-
 class MonoLLVMJIT {
 public:
        /* We use our own trampoline infrastructure instead of the Orc one */
@@ -309,46 +334,9 @@ public:
                : TM(TM), ObjectLayer([=] { return std::shared_ptr<RuntimeDyld::MemoryManager> (mm); }),
                  CompileLayer (ObjectLayer, SimpleCompiler (*TM)),
                  modules(),
-                 fpm (NULL) {
-               initPassManager ();
-       }
-
-       void initPassManager () {
-               PassRegistry &registry = *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<Module> M) {
@@ -445,7 +433,7 @@ private:
 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 &registry = *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