[llvm] [CodeGen][Pass] Add `TargetPassBuilder` (PR #137290)
Stefan Gränitz via llvm-commits
llvm-commits at lists.llvm.org
Wed Nov 5 01:44:17 PST 2025
================
@@ -0,0 +1,321 @@
+//===- Parsing, selection, and construction of pass pipelines --*- C++ -*--===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+///
+/// Interfaces for registering analysis passes, producing common pass manager
+/// configurations, and parsing of pass pipelines.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_PASSES_TARGETPASSBUILDER_H
+#define LLVM_PASSES_TARGETPASSBUILDER_H
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/ADT/identity.h"
+#include "llvm/Analysis/CGSCCPassManager.h"
+#include "llvm/CodeGen/MachinePassManager.h"
+#include "llvm/Target/CGPassBuilderOption.h"
+#include "llvm/Transforms/Scalar/LoopPassManager.h"
+#include <list>
+#include <type_traits>
+#include <unordered_set>
+#include <utility>
+#include <variant>
+#include <vector>
+
+namespace llvm {
+
+class PassBuilder;
+class TargetMachine;
+class SelectionDAGISel;
+
+/// @brief Build CodeGen pipeline
+///
+class TargetPassBuilder {
+public:
+ TargetPassBuilder(PassBuilder &PB);
+
+ virtual ~TargetPassBuilder() = default;
+
+ // TODO: Add necessary parameters once AsmPrinter is ported to new pass
+ // manager.
+ llvm::ModulePassManager buildPipeline(raw_pwrite_stream &Out,
+ raw_pwrite_stream *DwoOut,
+ CodeGenFileType FileType,
+ MCContext &Ctx);
+
+private:
+ struct PassWrapper {
+ StringRef Name;
+ std::variant<llvm::ModulePassManager, llvm::FunctionPassManager,
+ llvm::LoopPassManager, llvm::MachineFunctionPassManager>
+ InternalPass;
+ bool InCGSCC = false;
+
+ template <typename PassManagerT>
+ PassWrapper(StringRef Name, PassManagerT &&PM)
+ : Name(Name), InternalPass(std::forward<PassManagerT>(PM)) {}
+
+ template <typename PassT> PassWrapper(PassT &&P) : Name(PassT::name()) {
+ // FIXME: This can't handle the case when `run` is template.
+ if constexpr (isModulePass<PassT>) {
+ llvm::ModulePassManager MPM;
+ MPM.addPass(std::forward<PassT>(P));
+ InternalPass.emplace<llvm::ModulePassManager>(std::move(MPM));
+ } else if constexpr (isFunctionPass<PassT>) {
+ llvm::FunctionPassManager FPM;
+ FPM.addPass(std::forward<PassT>(P));
+ InternalPass.emplace<llvm::FunctionPassManager>(std::move(FPM));
+ } else {
+ static_assert(isMachineFunctionPass<PassT>, "Invalid pass type!");
+ llvm::MachineFunctionPassManager MFPM;
+ MFPM.addPass(std::forward<PassT>(P));
+ InternalPass.emplace<llvm::MachineFunctionPassManager>(std::move(MFPM));
+ }
+ }
+ };
+
+public:
+ using PassList = std::list<PassWrapper>;
+
+private:
+ template <typename InternalPassT> struct AdaptorWrapper : InternalPassT {
+ using InternalPassT::Passes;
+ };
+
+ template <typename PassManagerT, typename InternalPassT = void>
+ class PassManagerWrapper {
+ friend class TargetPassBuilder;
+
+ public:
+ bool isEmpty() const { return Passes.empty(); }
+
+ template <typename PassT> void addPass(PassT &&P) {
+ PassManagerT PM;
+ PM.addPass(std::forward<PassT>(P));
+ // Injection point doesn't add real pass.
+ if constexpr (std::is_base_of_v<InjectionPointMixin, PassT>)
+ PM = PassManagerT();
+ PassWrapper PW(PassT::name(), std::move(PM));
+ Passes.push_back(std::move(PW));
+ }
+
+ void addPass(PassManagerWrapper &&PM) {
+ for (auto &P : PM.Passes)
+ Passes.push_back(std::move(P));
+ }
+
+ void addPass(AdaptorWrapper<InternalPassT> &&Adaptor) {
+ for (auto &P : Adaptor.Passes)
+ Passes.push_back(std::move(P));
+ }
+
+ void addPass(llvm::ModulePassManager &&) = delete;
+ void addPass(llvm::FunctionPassManager &&) = delete;
+ void addPass(llvm::LoopPassManager &&) = delete;
+ void addPass(llvm::MachineFunctionPassManager &&) = delete;
+
+ private:
+ PassList Passes;
+ };
+
+ template <typename NestedPassManagerT, typename PassT>
+ AdaptorWrapper<NestedPassManagerT> createPassAdaptor(PassT &&P) {
+ AdaptorWrapper<NestedPassManagerT> Adaptor;
+ Adaptor.addPass(std::forward<PassT>(P));
+ return Adaptor;
+ }
+
+private:
+ template <typename PassT, typename IRUnitT>
+ using HasRunOnIRUnit = decltype(std::declval<PassT>().run(
+ std::declval<IRUnitT &>(), std::declval<AnalysisManager<IRUnitT> &>()));
+ template <typename PassT>
+ static constexpr bool isModulePass =
+ is_detected<HasRunOnIRUnit, PassT, Module>::value;
+ template <typename PassT>
+ static constexpr bool isFunctionPass =
+ is_detected<HasRunOnIRUnit, PassT, Function>::value;
+ template <typename PassT>
+ static constexpr bool isMachineFunctionPass =
+ is_detected<HasRunOnIRUnit, PassT, MachineFunction>::value;
+
+protected:
+ // Hijack real pass managers intentionally.
+ using MachineFunctionPassManager =
+ PassManagerWrapper<llvm::MachineFunctionPassManager>;
+ using FunctionPassManager =
+ PassManagerWrapper<llvm::FunctionPassManager, MachineFunctionPassManager>;
+ using ModulePassManager =
+ PassManagerWrapper<llvm::ModulePassManager, FunctionPassManager>;
+
+ struct CGSCCAdaptorWrapper : AdaptorWrapper<FunctionPassManager> {};
+
+protected:
+ template <typename FunctionPassT>
+ AdaptorWrapper<FunctionPassManager>
+ createModuleToFunctionPassAdaptor(FunctionPassT &&P) {
+ return createPassAdaptor<FunctionPassManager>(
+ std::forward<FunctionPassT>(P));
+ }
+
+ AdaptorWrapper<FunctionPassManager>
+ createModuleToPostOrderCGSCCPassAdaptor(CGSCCAdaptorWrapper &&PM) {
+ AdaptorWrapper<FunctionPassManager> AW;
+ AW.Passes = std::move(PM.Passes);
+ return AW;
+ }
+
+ template <typename FunctionPassT>
+ CGSCCAdaptorWrapper createCGSCCToFunctionPassAdaptor(FunctionPassT &&PM) {
+ for (auto &P : PM.Passes)
+ P.InCGSCC = true;
+ CGSCCAdaptorWrapper AW;
+ AW.Passes = std::move(PM.Passes);
+ return AW;
+ }
+
+ template <typename MachineFunctionPassT>
+ AdaptorWrapper<MachineFunctionPassManager>
+ createFunctionToMachineFunctionPassAdaptor(MachineFunctionPassT &&P) {
+ return createPassAdaptor<MachineFunctionPassManager>(
+ std::forward<MachineFunctionPassT>(P));
+ }
+
+ struct InjectionPointMixin {};
+ // When run is template, injectBefore can't recognize pass type correctly.
+ struct DummyFunctionPassBase : InjectionPointMixin {
+ PreservedAnalyses run(Function &, FunctionAnalysisManager &) {
+ return PreservedAnalyses();
+ }
+ };
+ struct DummyMachineFunctionPassBase : InjectionPointMixin {
+ PreservedAnalyses run(MachineFunction &, MachineFunctionAnalysisManager &) {
+ return PreservedAnalyses();
+ }
+ };
+ struct PreISel : PassInfoMixin<PreISel>, DummyFunctionPassBase {};
+ struct PostBBSections : PassInfoMixin<PostBBSections>,
+ DummyMachineFunctionPassBase {};
+ struct PreEmit : PassInfoMixin<PreEmit>, DummyMachineFunctionPassBase {};
+
+protected:
+ PassBuilder &PB;
+ TargetMachine *TM;
+ CodeGenOptLevel OptLevel;
+ CGPassBuilderOption CGPBO = getCGPassBuilderOption();
+
+ /// @brief The only method to extend pipeline
+ /// @tparam PassT The injection point
+ /// @tparam PassManagerT Returned pass manager, by default it depends on the
+ /// injection point.
+ /// @param F Callback to build the pipeline.
+ template <typename PassT,
+ typename PassManagerT = std::conditional_t<
+ isModulePass<PassT>, ModulePassManager,
+ std::conditional_t<isFunctionPass<PassT>, FunctionPassManager,
+ MachineFunctionPassManager>>>
+ void injectBefore(
+ typename llvm::identity<std::function<PassManagerT()>>::argument_type F) {
----------------
weliveindetail wrote:
And then.. maybe we could spell these out for the actual pass managers we have? This looks a lot simpler to me:
```
protected:
template <typename PassT>
void injectModulePassManagerBefore(std::function<ModulePassManager()> F) {
injectCallback(PassT::name(), std::move(F));
}
private:
template <typename PassManagerT>
void injectCallback(StringRef PassName, std::function<PassManagerT()> F) {
InjectionCallbacks.push_back(
...
```
And the interface still seems acceptable:
```
injectModulePassManagerBefore<ExpandFpPass>([] {
TargetModulePassManager MPM;
MPM.addPass(NoOpModulePass());
return MPM;
});
```
https://github.com/llvm/llvm-project/pull/137290
More information about the llvm-commits
mailing list