Commit 6b3eaa62e8

Min-Yih Hsu <minyihh@uci.edu>
2021-04-05 22:26:15
Revert "Revert back to the old LLVM PassManager"
This reverts commit 09008125e7944ae01bb907f2eb8dbff41d7a0715.
1 parent 000c084
Changed files (1)
src/zig_llvm.cpp
@@ -20,6 +20,7 @@
 #pragma GCC diagnostic ignored "-Winit-list-lifetime"
 #endif
 
+#include <llvm/Analysis/AliasAnalysis.h>
 #include <llvm/Analysis/TargetLibraryInfo.h>
 #include <llvm/Analysis/TargetTransformInfo.h>
 #include <llvm/Bitcode/BitcodeWriter.h>
@@ -30,9 +31,12 @@
 #include <llvm/IR/Instructions.h>
 #include <llvm/IR/LegacyPassManager.h>
 #include <llvm/IR/Module.h>
+#include <llvm/IR/PassManager.h>
 #include <llvm/IR/Verifier.h>
 #include <llvm/InitializePasses.h>
 #include <llvm/MC/SubtargetFeature.h>
+#include <llvm/Passes/PassBuilder.h>
+#include <llvm/Passes/StandardInstrumentations.h>
 #include <llvm/Object/Archive.h>
 #include <llvm/Object/ArchiveWriter.h>
 #include <llvm/Object/COFF.h>
@@ -54,6 +58,9 @@
 #include <llvm/Transforms/Instrumentation/ThreadSanitizer.h>
 #include <llvm/Transforms/Scalar.h>
 #include <llvm/Transforms/Utils.h>
+#include <llvm/Transforms/Utils/AddDiscriminators.h>
+#include <llvm/Transforms/Utils/CanonicalizeAliases.h>
+#include <llvm/Transforms/Utils/NameAnonGlobals.h>
 
 #include <lld/Common/Driver.h>
 
@@ -91,14 +98,6 @@ char *ZigLLVMGetNativeFeatures(void) {
     return strdup((const char *)StringRef(features.getString()).bytes_begin());
 }
 
-static void addDiscriminatorsPass(const PassManagerBuilder &Builder, legacy::PassManagerBase &PM) {
-    PM.add(createAddDiscriminatorsPass());
-}
-
-static void addThreadSanitizerPass(const PassManagerBuilder &Builder, legacy::PassManagerBase &PM) {
-    PM.add(createThreadSanitizerLegacyPassPass());
-}
-
 #ifndef NDEBUG
 static const bool assertions_on = true;
 #else
@@ -193,14 +192,16 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
         bool is_small, bool time_report, bool tsan, bool lto,
         const char *asm_filename, const char *bin_filename, const char *llvm_ir_filename)
 {
+    // TODO: Maybe we should collect time trace rather than using timer
+    // to get a more hierarchical timeline view
     TimePassesIsEnabled = time_report;
 
-    raw_fd_ostream *dest_asm = nullptr;
-    raw_fd_ostream *dest_bin = nullptr;
+    raw_fd_ostream *dest_asm_ptr = nullptr;
+    raw_fd_ostream *dest_bin_ptr = nullptr;
 
     if (asm_filename) {
         std::error_code EC;
-        dest_asm = new(std::nothrow) raw_fd_ostream(asm_filename, EC, sys::fs::F_None);
+        dest_asm_ptr = new(std::nothrow) raw_fd_ostream(asm_filename, EC, sys::fs::F_None);
         if (EC) {
             *error_message = strdup((const char *)StringRef(EC.message()).bytes_begin());
             return true;
@@ -208,116 +209,154 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
     }
     if (bin_filename) {
         std::error_code EC;
-        dest_bin = new(std::nothrow) raw_fd_ostream(bin_filename, EC, sys::fs::F_None);
+        dest_bin_ptr = new(std::nothrow) raw_fd_ostream(bin_filename, EC, sys::fs::F_None);
         if (EC) {
             *error_message = strdup((const char *)StringRef(EC.message()).bytes_begin());
             return true;
         }
     }
 
-    TargetMachine* target_machine = reinterpret_cast<TargetMachine*>(targ_machine_ref);
-    target_machine->setO0WantsFastISel(true);
-
-    Module* module = unwrap(module_ref);
-
-    PassManagerBuilder *PMBuilder = new(std::nothrow) PassManagerBuilder();
-    if (PMBuilder == nullptr) {
-        *error_message = strdup("memory allocation failure");
-        return true;
+    std::unique_ptr<raw_fd_ostream> dest_asm(dest_asm_ptr),
+                                    dest_bin(dest_bin_ptr);
+
+    TargetMachine &target_machine = *reinterpret_cast<TargetMachine*>(targ_machine_ref);
+    target_machine.setO0WantsFastISel(true);
+
+    Module &module = *unwrap(module_ref);
+
+    // Pipeline configurations
+    PipelineTuningOptions pipeline_opts;
+    pipeline_opts.LoopUnrolling = !is_debug;
+    pipeline_opts.SLPVectorization = !is_debug;
+    pipeline_opts.LoopVectorization = !is_debug;
+    pipeline_opts.LoopInterleaving = !is_debug;
+    pipeline_opts.MergeFunctions = !is_debug;
+
+    // Instrumentations
+    PassInstrumentationCallbacks instr_callbacks;
+    StandardInstrumentations std_instrumentations(false);
+    std_instrumentations.registerCallbacks(instr_callbacks);
+
+    PassBuilder pass_builder(false, &target_machine, pipeline_opts,
+                             None, &instr_callbacks);
+    using OptimizationLevel = typename PassBuilder::OptimizationLevel;
+
+    LoopAnalysisManager loop_am;
+    FunctionAnalysisManager function_am;
+    CGSCCAnalysisManager cgscc_am;
+    ModuleAnalysisManager module_am;
+
+    // Register the AA manager first so that our version is the one used
+    function_am.registerPass([&] {
+      return pass_builder.buildDefaultAAPipeline();
+    });
+
+    Triple target_triple(module.getTargetTriple());
+    auto tlii = std::make_unique<TargetLibraryInfoImpl>(target_triple);
+    function_am.registerPass([&] { return TargetLibraryAnalysis(*tlii); });
+
+    // Initialize the AnalysisManagers
+    pass_builder.registerModuleAnalyses(module_am);
+    pass_builder.registerCGSCCAnalyses(cgscc_am);
+    pass_builder.registerFunctionAnalyses(function_am);
+    pass_builder.registerLoopAnalyses(loop_am);
+    pass_builder.crossRegisterProxies(loop_am, function_am,
+                                      cgscc_am, module_am);
+
+    // IR verification
+    if (assertions_on) {
+      // Verify the input
+      pass_builder.registerPipelineStartEPCallback(
+        [](ModulePassManager &module_pm, OptimizationLevel OL) {
+          module_pm.addPass(VerifierPass());
+        });
+      // Verify the output
+      pass_builder.registerOptimizerLastEPCallback(
+        [](ModulePassManager &module_pm, OptimizationLevel OL) {
+          module_pm.addPass(VerifierPass());
+        });
     }
-    PMBuilder->OptLevel = target_machine->getOptLevel();
-    PMBuilder->SizeLevel = is_small ? 2 : 0;
-
-    PMBuilder->DisableTailCalls = is_debug;
-    PMBuilder->DisableUnrollLoops = is_debug;
-    PMBuilder->SLPVectorize = !is_debug;
-    PMBuilder->LoopVectorize = !is_debug;
-    PMBuilder->LoopsInterleaved = !PMBuilder->DisableUnrollLoops;
-    PMBuilder->RerollLoops = !is_debug;
-    // Leaving NewGVN as default (off) because when on it caused issue #673
-    //PMBuilder->NewGVN = !is_debug;
-    PMBuilder->DisableGVNLoadPRE = is_debug;
-    PMBuilder->VerifyInput = assertions_on;
-    PMBuilder->VerifyOutput = assertions_on;
-    PMBuilder->MergeFunctions = !is_debug;
-    PMBuilder->PrepareForLTO = lto;
-    PMBuilder->PrepareForThinLTO = false;
-    PMBuilder->PerformThinLTO = false;
-
-    TargetLibraryInfoImpl tlii(Triple(module->getTargetTriple()));
-    PMBuilder->LibraryInfo = &tlii;
 
+    // Passes for either debug or release build
     if (is_debug) {
-        PMBuilder->Inliner = createAlwaysInlinerLegacyPass(false);
+      // NOTE: Always inliner will go away (in debug build)
+      // when the self-hosted compiler becomes mature.
+      pass_builder.registerPipelineStartEPCallback(
+        [](ModulePassManager &module_pm, OptimizationLevel OL) {
+          module_pm.addPass(AlwaysInlinerPass());
+        });
     } else {
-        target_machine->adjustPassManager(*PMBuilder);
-
-        PMBuilder->addExtension(PassManagerBuilder::EP_EarlyAsPossible, addDiscriminatorsPass);
-        PMBuilder->Inliner = createFunctionInliningPass(PMBuilder->OptLevel, PMBuilder->SizeLevel, false);
+      pass_builder.registerPipelineStartEPCallback(
+        [](ModulePassManager &module_pm, OptimizationLevel OL) {
+          module_pm.addPass(
+            createModuleToFunctionPassAdaptor(AddDiscriminatorsPass()));
+        });
     }
 
+    // Thread sanitizer
     if (tsan) {
-        PMBuilder->addExtension(PassManagerBuilder::EP_OptimizerLast, addThreadSanitizerPass);
-        PMBuilder->addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0, addThreadSanitizerPass);
+      pass_builder.registerOptimizerLastEPCallback(
+        [](ModulePassManager &module_pm, OptimizationLevel level) {
+          module_pm.addPass(ThreadSanitizerPass());
+        });
     }
 
-    // Set up the per-function pass manager.
-    legacy::FunctionPassManager FPM = legacy::FunctionPassManager(module);
-    auto tliwp = new(std::nothrow) TargetLibraryInfoWrapperPass(tlii);
-    FPM.add(tliwp);
-    FPM.add(createTargetTransformInfoWrapperPass(target_machine->getTargetIRAnalysis()));
-    if (assertions_on) {
-        FPM.add(createVerifierPass());
+    ModulePassManager module_pm;
+    OptimizationLevel opt_level;
+    // Setting up the optimization level
+    if (is_debug)
+      opt_level = OptimizationLevel::O0;
+    else if (is_small)
+      opt_level = OptimizationLevel::Oz;
+    else
+      opt_level = OptimizationLevel::O3;
+
+    // Initialize the PassManager
+    if (lto) {
+      module_pm = pass_builder.buildLTOPreLinkDefaultPipeline(opt_level);
+      module_pm.addPass(CanonicalizeAliasesPass());
+      module_pm.addPass(NameAnonGlobalPass());
+    } else {
+      module_pm = pass_builder.buildPerModuleDefaultPipeline(opt_level);
     }
-    PMBuilder->populateFunctionPassManager(FPM);
-
-    {
-        // Set up the per-module pass manager.
-        legacy::PassManager MPM;
-        MPM.add(createTargetTransformInfoWrapperPass(target_machine->getTargetIRAnalysis()));
-        PMBuilder->populateModulePassManager(MPM);
-
-        // Set output passes.
-        if (dest_bin && !lto) {
-            if (target_machine->addPassesToEmitFile(MPM, *dest_bin, nullptr, CGFT_ObjectFile)) {
-                *error_message = strdup("TargetMachine can't emit an object file");
-                return true;
-            }
-        }
-        if (dest_asm) {
-            if (target_machine->addPassesToEmitFile(MPM, *dest_asm, nullptr, CGFT_AssemblyFile)) {
-                *error_message = strdup("TargetMachine can't emit an assembly file");
-                return true;
-            }
-        }
-
-        // run per function optimization passes
-        FPM.doInitialization();
-        for (Function &F : *module)
-        if (!F.isDeclaration())
-            FPM.run(F);
-        FPM.doFinalization();
 
-        MPM.run(*module);
+    // Unfortunately we don't have new PM for code generation
+    legacy::PassManager codegen_pm;
+    codegen_pm.add(
+      createTargetTransformInfoWrapperPass(target_machine.getTargetIRAnalysis()));
 
-        if (llvm_ir_filename) {
-            if (LLVMPrintModuleToFile(module_ref, llvm_ir_filename, error_message)) {
-                return true;
-            }
+    if (dest_bin && !lto) {
+        if (target_machine.addPassesToEmitFile(codegen_pm, *dest_bin, nullptr, CGFT_ObjectFile)) {
+            *error_message = strdup("TargetMachine can't emit an object file");
+            return true;
         }
-        if (dest_bin && lto) {
-            WriteBitcodeToFile(*module, *dest_bin);
+    }
+    if (dest_asm) {
+        if (target_machine.addPassesToEmitFile(codegen_pm, *dest_asm, nullptr, CGFT_AssemblyFile)) {
+            *error_message = strdup("TargetMachine can't emit an assembly file");
+            return true;
         }
+    }
 
-        if (time_report) {
-            TimerGroup::printAll(errs());
+    // Optimization phase
+    module_pm.run(module, module_am);
+
+    // Code generation phase
+    codegen_pm.run(module);
+
+    if (llvm_ir_filename) {
+        if (LLVMPrintModuleToFile(module_ref, llvm_ir_filename, error_message)) {
+            return true;
         }
+    }
 
-        // MPM goes out of scope and writes to the out streams
+    if (dest_bin && lto) {
+        WriteBitcodeToFile(module, *dest_bin);
     }
 
-    delete dest_asm;
-    delete dest_bin;
+    if (time_report) {
+        TimerGroup::printAll(errs());
+    }
 
     return false;
 }