Commit 09008125e7

Andrew Kelley <andrew@ziglang.org>
2021-04-02 23:35:01
Revert back to the old LLVM PassManager
See #8418 This reverts commit ba1bea2fe87b73a53a3ecd729789853dcc56affe. This reverts commit 94383d14df77fa638dac14f4b2bda5a2e3f21c5c. This reverts commit 0d53a2bff01750f9220bcc861d662b2c5f304506.
1 parent ba1bea2
Changed files (1)
src/zig_llvm.cpp
@@ -20,7 +20,6 @@
 #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>
@@ -31,12 +30,9 @@
 #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>
@@ -58,9 +54,6 @@
 #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>
 
@@ -98,6 +91,14 @@ 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
@@ -187,16 +188,14 @@ 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_ptr = nullptr;
-    raw_fd_ostream *dest_bin_ptr = nullptr;
+    raw_fd_ostream *dest_asm = nullptr;
+    raw_fd_ostream *dest_bin = nullptr;
 
     if (asm_filename) {
         std::error_code EC;
-        dest_asm_ptr = new(std::nothrow) raw_fd_ostream(asm_filename, EC, sys::fs::F_None);
+        dest_asm = 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;
@@ -204,155 +203,117 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
     }
     if (bin_filename) {
         std::error_code EC;
-        dest_bin_ptr = new(std::nothrow) raw_fd_ostream(bin_filename, EC, sys::fs::F_None);
+        dest_bin = 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;
         }
     }
 
-    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());
-        });
+    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;
     }
+    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) {
-      // 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());
-        });
+        PMBuilder->Inliner = createAlwaysInlinerLegacyPass(false);
     } else {
-      pass_builder.registerPipelineStartEPCallback(
-        [](ModulePassManager &module_pm, OptimizationLevel OL) {
-          module_pm.addPass(
-            createModuleToFunctionPassAdaptor(AddDiscriminatorsPass()));
-        });
+        target_machine->adjustPassManager(*PMBuilder);
+
+        PMBuilder->addExtension(PassManagerBuilder::EP_EarlyAsPossible, addDiscriminatorsPass);
+        PMBuilder->Inliner = createFunctionInliningPass(PMBuilder->OptLevel, PMBuilder->SizeLevel, false);
     }
 
-    // Thread sanitizer
     if (tsan) {
-      pass_builder.registerOptimizerLastEPCallback(
-        [](ModulePassManager &module_pm, OptimizationLevel level) {
-          module_pm.addPass(ThreadSanitizerPass());
-        });
+        PMBuilder->addExtension(PassManagerBuilder::EP_OptimizerLast, addThreadSanitizerPass);
+        PMBuilder->addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0, addThreadSanitizerPass);
     }
 
-    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);
+    // 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());
     }
-
-    // Unfortunately we don't have new PM for code generation
-    legacy::PassManager codegen_pm;
-    codegen_pm.add(
-      createTargetTransformInfoWrapperPass(target_machine.getTargetIRAnalysis()));
-
-    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;
+    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(codegen_pm, *dest_asm, nullptr, CGFT_AssemblyFile)) {
-            *error_message = strdup("TargetMachine can't emit an assembly 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;
+            }
         }
-    }
 
-    // Optimization phase
-    module_pm.run(module, module_am);
+        // run per function optimization passes
+        FPM.doInitialization();
+        for (Function &F : *module)
+        if (!F.isDeclaration())
+            FPM.run(F);
+        FPM.doFinalization();
 
-    // Code generation phase
-    codegen_pm.run(module);
+        MPM.run(*module);
 
-    if (llvm_ir_filename) {
-        if (LLVMPrintModuleToFile(module_ref, llvm_ir_filename, error_message)) {
-            return true;
+        if (llvm_ir_filename) {
+            if (LLVMPrintModuleToFile(module_ref, llvm_ir_filename, error_message)) {
+                return true;
+            }
+        }
+        if (dest_bin && lto) {
+            WriteBitcodeToFile(*module, *dest_bin);
         }
-    }
 
-    if (dest_bin && lto) {
-        WriteBitcodeToFile(module, *dest_bin);
-    }
+        if (time_report) {
+            TimerGroup::printAll(errs());
+        }
 
-    if (time_report) {
-        TimerGroup::printAll(errs());
+        // MPM goes out of scope and writes to the out streams
     }
 
+    delete dest_asm;
+    delete dest_bin;
+
     return false;
 }