diff options
| author | Min-Yih Hsu <minyihh@uci.edu> | 2021-04-05 13:26:15 -0700 |
|---|---|---|
| committer | Min-Yih Hsu <minyihh@uci.edu> | 2021-04-09 16:51:35 -0700 |
| commit | 6b3eaa62e86d2652cf0b0802d704ab16d148c2ce (patch) | |
| tree | 3e150f815fea01fc581b92aa9beb306d71d6b386 /src/zig_llvm.cpp | |
| parent | 000c0845b1ac30fe57690d71cb84847b42ad762a (diff) | |
| download | zig-6b3eaa62e86d2652cf0b0802d704ab16d148c2ce.tar.gz zig-6b3eaa62e86d2652cf0b0802d704ab16d148c2ce.zip | |
Revert "Revert back to the old LLVM PassManager"
This reverts commit 09008125e7944ae01bb907f2eb8dbff41d7a0715.
Diffstat (limited to 'src/zig_llvm.cpp')
| -rw-r--r-- | src/zig_llvm.cpp | 231 |
1 files changed, 135 insertions, 96 deletions
diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp index 12ae9de75e..0d60d7a4ac 100644 --- a/src/zig_llvm.cpp +++ b/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; } |
