aboutsummaryrefslogtreecommitdiff
path: root/src/zig_llvm.cpp
diff options
context:
space:
mode:
authorMin-Yih Hsu <minyihh@uci.edu>2021-04-05 13:26:15 -0700
committerMin-Yih Hsu <minyihh@uci.edu>2021-04-09 16:51:35 -0700
commit6b3eaa62e86d2652cf0b0802d704ab16d148c2ce (patch)
tree3e150f815fea01fc581b92aa9beb306d71d6b386 /src/zig_llvm.cpp
parent000c0845b1ac30fe57690d71cb84847b42ad762a (diff)
downloadzig-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.cpp231
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;
}