[llvm] [Codegen][NewPM] Explicitly Nest Passes in CodegenPassBuilder (PR #169867)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Nov 27 19:18:53 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-amdgpu
Author: Aiden Grossman (boomanaiden154)
<details>
<summary>Changes</summary>
This implements the major piece of
https://discourse.llvm.org/t/rfc-codegen-new-pass-manager-pipeline-construction-design/84659,
making it explicit when we break the function pipeline up.
We essentially get rid of the AddPass and AddMachinePass helpers and
replace them with explicit functions for the pass types. The user then
needs to explicitly call flushFPMstoMPM before breaking.
This is sort of a hybrid of the current construction and what the RFC
proposed. The alternative would be passing around FunctionPassManagers
and having the pipeline actually explicitly constructed. I think this
compromises ergonomics slightly (needing to pass a FPM in many more
places). It is also nice to assert that the function pass manager is
empty when adding a module pass, which is easier when CodegenPassBuilder
owns the FPM and MFPM.
---
Patch is 73.91 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/169867.diff
4 Files Affected:
- (modified) llvm/include/llvm/Passes/CodeGenPassBuilder.h (+291-344)
- (modified) llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp (+148-138)
- (modified) llvm/lib/Target/AMDGPU/R600TargetMachine.cpp (+6-6)
- (modified) llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp (+7-7)
``````````diff
diff --git a/llvm/include/llvm/Passes/CodeGenPassBuilder.h b/llvm/include/llvm/Passes/CodeGenPassBuilder.h
index 03777c7fcb45f..9e9a3d0104bfa 100644
--- a/llvm/include/llvm/Passes/CodeGenPassBuilder.h
+++ b/llvm/include/llvm/Passes/CodeGenPassBuilder.h
@@ -108,6 +108,7 @@
#include "llvm/IRPrinter/IRPrintingPasses.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCTargetOptions.h"
+#include "llvm/Pass.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Error.h"
@@ -189,6 +190,12 @@ template <typename DerivedT, typename TargetMachineT> class CodeGenPassBuilder {
Opt.OptimizeRegAlloc = getOptLevel() != CodeGenOptLevel::None;
}
+ ~CodeGenPassBuilder() {
+ assert(FPM.isEmpty() && MFPM.isEmpty() &&
+ "There are passes that have not been flushed from the function "
+ "pipelines.");
+ }
+
Error buildPipeline(ModulePassManager &MPM, raw_pwrite_stream &Out,
raw_pwrite_stream *DwoOut,
CodeGenFileType FileType) const;
@@ -211,147 +218,72 @@ template <typename DerivedT, typename TargetMachineT> class CodeGenPassBuilder {
std::declval<MachineFunction &>(),
std::declval<MachineFunctionAnalysisManager &>()));
- // Function object to maintain state while adding codegen IR passes.
- // TODO: add a Function -> MachineFunction adaptor and merge
- // AddIRPass/AddMachinePass so we can have a function pipeline that runs both
- // function passes and machine function passes.
- class AddIRPass {
- public:
- AddIRPass(ModulePassManager &MPM, const DerivedT &PB) : MPM(MPM), PB(PB) {}
- ~AddIRPass() { flushFPMToMPM(); }
-
- template <typename PassT>
- void operator()(PassT &&Pass, bool Force = false,
- StringRef Name = PassT::name()) {
- static_assert((is_detected<is_function_pass_t, PassT>::value ||
- is_detected<is_module_pass_t, PassT>::value) &&
- "Only module pass and function pass are supported.");
- if (!Force && !PB.runBeforeAdding(Name))
- return;
-
- // Add Function Pass
- if constexpr (is_detected<is_function_pass_t, PassT>::value) {
- FPM.addPass(std::forward<PassT>(Pass));
- } else {
- // Add Module Pass
- flushFPMToMPM();
- MPM.addPass(std::forward<PassT>(Pass));
- }
- }
-
- /// Setting this will add passes to the CGSCC pass manager.
- void requireCGSCCOrder() {
- if (PB.AddInCGSCCOrder)
- return;
- flushFPMToMPM();
- PB.AddInCGSCCOrder = true;
- }
-
- /// Stop adding passes to the CGSCC pass manager.
- /// Existing passes won't be removed.
- void stopAddingInCGSCCOrder() {
- if (!PB.AddInCGSCCOrder)
- return;
- flushFPMToMPM();
- PB.AddInCGSCCOrder = false;
- }
+ template <typename PassT>
+ void addFunctionPass(PassT &&Pass, bool Force = false,
+ StringRef Name = PassT::name()) const {
+ static_assert(is_detected<is_function_pass_t, PassT>::value &&
+ "Only function passes are supported.");
+ if (!Force && !runBeforeAdding(Name))
+ return;
+ FPM.addPass(std::forward<PassT>(Pass));
+ }
- private:
- void flushFPMToMPM() {
- if (FPM.isEmpty())
- return;
- if (PB.AddInCGSCCOrder) {
- MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(
- createCGSCCToFunctionPassAdaptor(std::move(FPM))));
- } else {
- MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
- }
- FPM = FunctionPassManager();
- }
- ModulePassManager &MPM;
- FunctionPassManager FPM;
- const DerivedT &PB;
- };
+ template <typename PassT>
+ void addModulePass(PassT &&Pass, ModulePassManager &MPM, bool Force = false,
+ StringRef Name = PassT::name()) const {
+ static_assert(is_detected<is_module_pass_t, PassT>::value &&
+ "Only module passes are suported.");
+ assert(FPM.isEmpty() && MFPM.isEmpty() &&
+ "You cannot insert a module pass without first flushing the current "
+ "function pipelines to the module pipeline.");
+ if (!Force && !runBeforeAdding(Name))
+ return;
+ MPM.addPass(std::forward<PassT>(Pass));
+ }
- // Function object to maintain state while adding codegen machine passes.
- class AddMachinePass {
- public:
- AddMachinePass(ModulePassManager &MPM, const DerivedT &PB)
- : MPM(MPM), PB(PB) {}
- ~AddMachinePass() {
- if (MFPM.isEmpty())
- return;
+ template <typename PassT>
+ void addMachineFunctionPass(PassT &&Pass, bool Force = false,
+ StringRef Name = PassT::name()) const {
+ static_assert(is_detected<is_machine_function_pass_t, PassT>::value &&
+ "Only machine function passes are supported.");
+
+ if (!Force && !runBeforeAdding(Name))
+ return;
+ MFPM.addPass(std::forward<PassT>(Pass));
+ for (auto &C : AfterCallbacks)
+ C(Name, MFPM);
+ }
- FunctionPassManager FPM;
+ void flushFPMsToMPM(ModulePassManager &MPM,
+ bool FreeMachineFunctions = false) const {
+ if (FPM.isEmpty() && MFPM.isEmpty())
+ return;
+ if (!MFPM.isEmpty()) {
FPM.addPass(createFunctionToMachineFunctionPassAdaptor(std::move(MFPM)));
- FPM.addPass(FreeMachineFunctionPass());
- if (this->PB.AddInCGSCCOrder) {
- MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(
- createCGSCCToFunctionPassAdaptor(std::move(FPM))));
- } else
- MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
- }
-
- template <typename PassT>
- void operator()(PassT &&Pass, bool Force = false,
- StringRef Name = PassT::name()) {
- static_assert((is_detected<is_machine_function_pass_t, PassT>::value ||
- is_detected<is_module_pass_t, PassT>::value) &&
- "Only module pass and function pass are supported.");
-
- if (!Force && !PB.runBeforeAdding(Name))
- return;
-
- // Add Function Pass
- if constexpr (is_detected<is_machine_function_pass_t, PassT>::value) {
- MFPM.addPass(std::forward<PassT>(Pass));
- } else {
- // Add Module Pass
- flushMFPMToMPM();
- MPM.addPass(std::forward<PassT>(Pass));
- }
-
- for (auto &C : PB.AfterCallbacks)
- C(Name, MFPM);
- }
-
- /// Setting this will add passes to the CGSCC pass manager.
- void requireCGSCCOrder() {
- if (PB.AddInCGSCCOrder)
- return;
- flushMFPMToMPM();
- PB.AddInCGSCCOrder = true;
+ MFPM = MachineFunctionPassManager();
}
-
- /// Stop adding passes to the CGSCC pass manager.
- /// Existing passes won't be removed.
- void stopAddingInCGSCCOrder() {
- if (!PB.AddInCGSCCOrder)
- return;
- flushMFPMToMPM();
- PB.AddInCGSCCOrder = false;
+ if (FreeMachineFunctions)
+ FPM.addPass(FreeMachineFunctionPass());
+ if (AddInCGSCCOrder) {
+ MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(
+ createCGSCCToFunctionPassAdaptor(std::move(FPM))));
+ } else {
+ MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
}
+ FPM = FunctionPassManager();
+ }
- private:
- void flushMFPMToMPM() {
- if (MFPM.isEmpty())
- return;
-
- if (PB.AddInCGSCCOrder) {
- MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(
- createCGSCCToFunctionPassAdaptor(
- createFunctionToMachineFunctionPassAdaptor(std::move(MFPM)))));
- } else {
- MPM.addPass(createModuleToFunctionPassAdaptor(
- createFunctionToMachineFunctionPassAdaptor(std::move(MFPM))));
- }
- MFPM = MachineFunctionPassManager();
- }
+ void requireCGSCCOrder(ModulePassManager &MPM) const {
+ assert(!AddInCGSCCOrder);
+ flushFPMsToMPM(MPM);
+ AddInCGSCCOrder = true;
+ }
- ModulePassManager &MPM;
- MachineFunctionPassManager MFPM;
- const DerivedT &PB;
- };
+ void stopAddingInCGSCCOrder(ModulePassManager &MPM) const {
+ assert(AddInCGSCCOrder);
+ flushFPMsToMPM(MPM);
+ AddInCGSCCOrder = false;
+ }
TargetMachineT &TM;
CGPassBuilderOption Opt;
@@ -376,13 +308,13 @@ template <typename DerivedT, typename TargetMachineT> class CodeGenPassBuilder {
/// addInstSelector - This method should install an instruction selector pass,
/// which converts from LLVM code to machine instructions.
- Error addInstSelector(AddMachinePass &) const {
+ Error addInstSelector(ModulePassManager &MPM) const {
return make_error<StringError>("addInstSelector is not overridden",
inconvertibleErrorCode());
}
/// Target can override this to add GlobalMergePass before all IR passes.
- void addGlobalMergePass(AddIRPass &) const {}
+ void addGlobalMergePass(ModulePassManager &MPM) const {}
/// Add passes that optimize instruction level parallelism for out-of-order
/// targets. These passes are run while the machine code is still in SSA
@@ -390,11 +322,11 @@ template <typename DerivedT, typename TargetMachineT> class CodeGenPassBuilder {
///
/// All passes added here should preserve the MachineDominatorTree,
/// MachineLoopInfo, and MachineTraceMetrics analyses.
- void addILPOpts(AddMachinePass &) const {}
+ void addILPOpts(ModulePassManager &MPM) const {}
/// This method may be implemented by targets that want to run passes
/// immediately before register allocation.
- void addPreRegAlloc(AddMachinePass &) const {}
+ void addPreRegAlloc(ModulePassManager &MPM) const {}
/// addPreRewrite - Add passes to the optimized register allocation pipeline
/// after register allocation is complete, but before virtual registers are
@@ -408,79 +340,79 @@ template <typename DerivedT, typename TargetMachineT> class CodeGenPassBuilder {
/// Note if the target overloads addRegAssignAndRewriteOptimized, this may not
/// be honored. This is also not generally used for the fast variant,
/// where the allocation and rewriting are done in one pass.
- void addPreRewrite(AddMachinePass &) const {}
+ void addPreRewrite(ModulePassManager &MPM) const {}
/// Add passes to be run immediately after virtual registers are rewritten
/// to physical registers.
- void addPostRewrite(AddMachinePass &) const {}
+ void addPostRewrite(ModulePassManager &MPM) const {}
/// This method may be implemented by targets that want to run passes after
/// register allocation pass pipeline but before prolog-epilog insertion.
- void addPostRegAlloc(AddMachinePass &) const {}
+ void addPostRegAlloc(ModulePassManager &MPM) const {}
/// This method may be implemented by targets that want to run passes after
/// prolog-epilog insertion and before the second instruction scheduling pass.
- void addPreSched2(AddMachinePass &) const {}
+ void addPreSched2(ModulePassManager &MPM) const {}
/// This pass may be implemented by targets that want to run passes
/// immediately before machine code is emitted.
- void addPreEmitPass(AddMachinePass &) const {}
+ void addPreEmitPass(ModulePassManager &MPM) const {}
/// Targets may add passes immediately before machine code is emitted in this
/// callback. This is called even later than `addPreEmitPass`.
// FIXME: Rename `addPreEmitPass` to something more sensible given its actual
// position and remove the `2` suffix here as this callback is what
// `addPreEmitPass` *should* be but in reality isn't.
- void addPreEmitPass2(AddMachinePass &) const {}
+ void addPreEmitPass2(ModulePassManager &MPM) const {}
/// {{@ For GlobalISel
///
/// addPreISel - This method should add any "last minute" LLVM->LLVM
/// passes (which are run just before instruction selector).
- void addPreISel(AddIRPass &) const {
+ void addPreISel(ModulePassManager &MPM) const {
llvm_unreachable("addPreISel is not overridden");
}
/// This method should install an IR translator pass, which converts from
/// LLVM code to machine instructions with possibly generic opcodes.
- Error addIRTranslator(AddMachinePass &) const {
+ Error addIRTranslator(ModulePassManager &MPM) const {
return make_error<StringError>("addIRTranslator is not overridden",
inconvertibleErrorCode());
}
/// This method may be implemented by targets that want to run passes
/// immediately before legalization.
- void addPreLegalizeMachineIR(AddMachinePass &) const {}
+ void addPreLegalizeMachineIR(ModulePassManager &MPM) const {}
/// This method should install a legalize pass, which converts the instruction
/// sequence into one that can be selected by the target.
- Error addLegalizeMachineIR(AddMachinePass &) const {
+ Error addLegalizeMachineIR(ModulePassManager &MPM) const {
return make_error<StringError>("addLegalizeMachineIR is not overridden",
inconvertibleErrorCode());
}
/// This method may be implemented by targets that want to run passes
/// immediately before the register bank selection.
- void addPreRegBankSelect(AddMachinePass &) const {}
+ void addPreRegBankSelect(ModulePassManager &MPM) const {}
/// This method should install a register bank selector pass, which
/// assigns register banks to virtual registers without a register
/// class or register banks.
- Error addRegBankSelect(AddMachinePass &) const {
+ Error addRegBankSelect(ModulePassManager &MPM) const {
return make_error<StringError>("addRegBankSelect is not overridden",
inconvertibleErrorCode());
}
/// This method may be implemented by targets that want to run passes
/// immediately before the (global) instruction selection.
- void addPreGlobalInstructionSelect(AddMachinePass &) const {}
+ void addPreGlobalInstructionSelect(ModulePassManager &MPM) const {}
/// This method should install a (global) instruction selector pass, which
/// converts possibly generic instructions to fully target-specific
/// instructions, thereby constraining all generic virtual registers to
/// register classes.
- Error addGlobalInstructionSelect(AddMachinePass &) const {
+ Error addGlobalInstructionSelect(ModulePassManager &MPM) const {
return make_error<StringError>(
"addGlobalInstructionSelect is not overridden",
inconvertibleErrorCode());
@@ -491,30 +423,30 @@ template <typename DerivedT, typename TargetMachineT> class CodeGenPassBuilder {
/// representation to the MI representation.
/// Adds IR based lowering and target specific optimization passes and finally
/// the core instruction selection passes.
- void addISelPasses(AddIRPass &) const;
+ void addISelPasses(ModulePassManager &MPM) const;
/// Add the actual instruction selection passes. This does not include
/// preparation passes on IR.
- Error addCoreISelPasses(AddMachinePass &) const;
+ Error addCoreISelPasses(ModulePassManager &MPM) const;
/// Add the complete, standard set of LLVM CodeGen passes.
/// Fully developed targets will not generally override this.
- Error addMachinePasses(AddMachinePass &) const;
+ Error addMachinePasses(ModulePassManager &MPM) const;
/// Add passes to lower exception handling for the code generator.
- void addPassesToHandleExceptions(AddIRPass &) const;
+ void addPassesToHandleExceptions(ModulePassManager &MPM) const;
/// Add common target configurable passes that perform LLVM IR to IR
/// transforms following machine independent optimization.
- void addIRPasses(AddIRPass &) const;
+ void addIRPasses(ModulePassManager &MPM) const;
/// Add pass to prepare the LLVM IR for code generation. This should be done
/// before exception handling preparation passes.
- void addCodeGenPrepare(AddIRPass &) const;
+ void addCodeGenPrepare(ModulePassManager &MPM) const;
/// Add common passes that perform LLVM IR to IR transforms in preparation for
/// instruction selection.
- void addISelPrepare(AddIRPass &) const;
+ void addISelPrepare(ModulePassManager &MPM) const;
/// Methods with trivial inline returns are convenient points in the common
/// codegen pass pipeline where targets may insert passes. Methods with
@@ -525,31 +457,31 @@ template <typename DerivedT, typename TargetMachineT> class CodeGenPassBuilder {
/// addMachineSSAOptimization - Add standard passes that optimize machine
/// instructions in SSA form.
- void addMachineSSAOptimization(AddMachinePass &) const;
+ void addMachineSSAOptimization(ModulePassManager &MPM) const;
/// addFastRegAlloc - Add the minimum set of target-independent passes that
/// are required for fast register allocation.
- Error addFastRegAlloc(AddMachinePass &) const;
+ Error addFastRegAlloc(ModulePassManager &MPM) const;
/// addOptimizedRegAlloc - Add passes related to register allocation.
/// CodeGenTargetMachineImpl provides standard regalloc passes for most
/// targets.
- void addOptimizedRegAlloc(AddMachinePass &) const;
+ void addOptimizedRegAlloc(ModulePassManager &MPM) const;
/// Add passes that optimize machine instructions after register allocation.
- void addMachineLateOptimization(AddMachinePass &) const;
+ void addMachineLateOptimization(ModulePassManager &MPM) const;
/// addGCPasses - Add late codegen passes that analyze code for garbage
/// collection. This should return true if GC info should be printed after
/// these passes.
- void addGCPasses(AddMachinePass &) const {}
+ void addGCPasses(ModulePassManager &MPM) const {}
/// Add standard basic block placement passes.
- void addBlockPlacement(AddMachinePass &) const;
+ void addBlockPlacement(ModulePassManager &MPM) const;
using CreateMCStreamer =
std::function<Expected<std::unique_ptr<MCStreamer>>(MCContext &)>;
- void addAsmPrinter(AddMachinePass &, CreateMCStreamer) const {
+ void addAsmPrinter(ModulePassManager &MPM, CreateMCStreamer) const {
llvm_unreachable("addAsmPrinter is not overridden");
}
@@ -558,16 +490,16 @@ template <typename DerivedT, typename TargetMachineT> class CodeGenPassBuilder {
/// createTargetRegisterAllocator - Create the register allocator pass for
/// this target at the current optimization level.
- void addTargetRegisterAllocator(AddMachinePass &, bool Optimized) const;
+ void addTargetRegisterAllocator(ModulePassManager &MPM, bool Optimized) const;
/// addMachinePasses helper to create the target-selected or overriden
/// regalloc pass.
- void addRegAllocPass(AddMachinePass &, bool Optimized) const;
+ void addRegAllocPass(ModulePassManager &MPM, bool Optimized) const;
/// Add core register alloator passes which do the actual register assignment
/// and rewriting. \returns true if any passes were added.
- Error addRegAssignmentFast(AddMachinePass &) const;
- Error addRegAssignmentOptimized(AddMachinePass &) const;
+ Error addRegAssignmentFast(ModulePassManager &MPM) const;
+ Error addRegAssignmentOptimized(ModulePassManager &MPM) const;
/// Allow the target to disable a specific pass by default.
/// Backend can declare unwanted passes in constructor.
@@ -616,6 +548,9 @@ template <typename DerivedT, typename TargetMachineT> class CodeGenPassBuilder {
mutable bool Started = true;
mutable bool Stopped = true;
mutable bool AddInCGSCCOrder = false;
+
+ mutable FunctionPassManager FPM;
+ mutable MachineFunctionPassManager MFPM;
};
template <typename Derived, typename TargetMachineT>
@@ -630,42 +565,40 @@ Error CodeGenPassBuilder<Derived, TargetMachineT>::buildPipeline(
bool PrintAsm = TargetPassConfig::willCompleteCodeGenPipeline();
bool PrintMIR = !PrintAsm && FileType != CodeGenFileType::Null;
- {
- AddIRPass addIRPass(MPM, derived());
- addIRPass(RequireAnalysisPass<MachineModuleAnalysis, Module>(),
- /*Force=*/true);
- addIRPass(RequireAnalysisPass<ProfileSummaryAnalysis, Module>(),
- /*Force=*/true);
- addIRPass(RequireAnalysisPass<CollectorMetadataAnalysis, Module>(),
- /*Force=*/true);
- addIRPass(RequireAnalysisPass<RuntimeLibraryAnalysis, Module>(),
- /*Force=*/true);
- addISelPasses(addIRPass);
- }
-
- AddMachinePass addPass...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/169867
More information about the llvm-commits
mailing list