[llvm] [RISCV][NewPM] Add NewPM Codegen Pipeline Skeleton (PR #213129)

Sam Elliott via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 30 14:51:00 PDT 2026


https://github.com/lenary updated https://github.com/llvm/llvm-project/pull/213129

>From 35dfdc739489ee67ad907dbc061b64940b80c54d Mon Sep 17 00:00:00 2001
From: Sam Elliott <aelliott at qti.qualcomm.com>
Date: Thu, 30 Jul 2026 11:23:20 -0700
Subject: [PATCH 1/5] [RISCV][NewPM] Add NewPM Codegen Pipeline Skeleton

This follows what has been done for other targets. Follow-up commits
will port each pass and add them to this pipeline.

I intend to have many fewer `cl::opt`s in this pipeline, as I think lots
are left over from early work to enable specific passes.
---
 llvm/lib/Target/RISCV/CMakeLists.txt          |   3 +
 llvm/lib/Target/RISCV/RISCV.h                 |   6 +
 llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp     |  33 +++
 llvm/lib/Target/RISCV/RISCVAsmPrinter.h       |  39 +++
 .../Target/RISCV/RISCVCodeGenPassBuilder.cpp  | 238 ++++++++++++++++++
 llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp   |   4 +
 llvm/lib/Target/RISCV/RISCVPassRegistry.def   |   6 +
 llvm/lib/Target/RISCV/RISCVTargetMachine.cpp  |  13 -
 llvm/lib/Target/RISCV/RISCVTargetMachine.h    |   5 +
 llvm/test/CodeGen/RISCV/O1-newpm-pipeline.ll  | 107 ++++++++
 llvm/test/CodeGen/RISCV/O3-newpm-pipeline.ll  | 108 ++++++++
 11 files changed, 549 insertions(+), 13 deletions(-)
 create mode 100644 llvm/lib/Target/RISCV/RISCVAsmPrinter.h
 create mode 100644 llvm/lib/Target/RISCV/RISCVCodeGenPassBuilder.cpp
 create mode 100644 llvm/test/CodeGen/RISCV/O1-newpm-pipeline.ll
 create mode 100644 llvm/test/CodeGen/RISCV/O3-newpm-pipeline.ll

diff --git a/llvm/lib/Target/RISCV/CMakeLists.txt b/llvm/lib/Target/RISCV/CMakeLists.txt
index afab81b2cf7b0..27879c1dd1085 100644
--- a/llvm/lib/Target/RISCV/CMakeLists.txt
+++ b/llvm/lib/Target/RISCV/CMakeLists.txt
@@ -33,6 +33,7 @@ add_public_tablegen_target(RISCVCommonTableGen)
 add_llvm_target(RISCVCodeGen
   RISCVAsmPrinter.cpp
   RISCVCallingConv.cpp
+  RISCVCodeGenPassBuilder.cpp
   RISCVCodeGenPrepare.cpp
   RISCVConstantPoolValue.cpp
   RISCVDeadRegisterDefinitions.cpp
@@ -93,7 +94,9 @@ add_llvm_target(RISCVCodeGen
   Core
   GlobalISel
   IPO
+  IRPrinter
   MC
+  ObjCARC
   Passes
   RISCVDesc
   RISCVInfo
diff --git a/llvm/lib/Target/RISCV/RISCV.h b/llvm/lib/Target/RISCV/RISCV.h
index 8db90ee51c441..013cb57565d93 100644
--- a/llvm/lib/Target/RISCV/RISCV.h
+++ b/llvm/lib/Target/RISCV/RISCV.h
@@ -15,6 +15,7 @@
 #define LLVM_LIB_TARGET_RISCV_RISCV_H
 
 #include "MCTargetDesc/RISCVBaseInfo.h"
+#include "llvm/CodeGen/SelectionDAGISel.h"
 #include "llvm/Target/TargetMachine.h"
 
 namespace llvm {
@@ -50,6 +51,11 @@ void initializeRISCVLandingPadSetupPass(PassRegistry &);
 FunctionPass *createRISCVISelDag(RISCVTargetMachine &TM,
                                  CodeGenOptLevel OptLevel);
 
+class RISCVISelDAGToDAGPass : public SelectionDAGISelPass {
+public:
+  RISCVISelDAGToDAGPass(RISCVTargetMachine &TM, CodeGenOptLevel OptLevel);
+};
+
 FunctionPass *createRISCVLateBranchOptPass();
 void initializeRISCVLateBranchOptPass(PassRegistry &);
 
diff --git a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
index e37ea27364e6e..6dee7fb37ef4c 100644
--- a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
+++ b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
@@ -11,6 +11,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "RISCVAsmPrinter.h"
 #include "MCTargetDesc/RISCVBaseInfo.h"
 #include "MCTargetDesc/RISCVELFStreamer.h"
 #include "MCTargetDesc/RISCVInstPrinter.h"
@@ -26,7 +27,9 @@
 #include "llvm/ADT/Statistic.h"
 #include "llvm/BinaryFormat/ELF.h"
 #include "llvm/CodeGen/AsmPrinter.h"
+#include "llvm/CodeGen/AsmPrinterAnalysis.h"
 #include "llvm/CodeGen/MachineConstantPool.h"
+#include "llvm/CodeGen/MachineFunctionAnalysisManager.h"
 #include "llvm/CodeGen/MachineInstr.h"
 #include "llvm/CodeGen/MachineModuleInfo.h"
 #include "llvm/IR/Module.h"
@@ -1324,3 +1327,33 @@ char RISCVAsmPrinter::ID = 0;
 
 INITIALIZE_PASS(RISCVAsmPrinter, "riscv-asm-printer", "RISC-V Assembly Printer",
                 false, false)
+
+PreservedAnalyses RISCVAsmPrinterBeginPass::run(Module &M,
+                                                ModuleAnalysisManager &MAM) {
+  RISCVAsmPrinter &AsmPrinter = static_cast<RISCVAsmPrinter &>(
+      MAM.getResult<AsmPrinterAnalysis>(M).getPrinter());
+  setupModuleAsmPrinter(M, MAM, AsmPrinter);
+  AsmPrinter.doInitialization(M);
+  return PreservedAnalyses::all();
+}
+
+PreservedAnalyses
+RISCVAsmPrinterPass::run(MachineFunction &MF,
+                         MachineFunctionAnalysisManager &MFAM) {
+  RISCVAsmPrinter &AsmPrinter = static_cast<RISCVAsmPrinter &>(
+      MFAM.getResult<ModuleAnalysisManagerMachineFunctionProxy>(MF)
+          .getCachedResult<AsmPrinterAnalysis>(*MF.getFunction().getParent())
+          ->getPrinter());
+  setupMachineFunctionAsmPrinter(MFAM, MF, AsmPrinter);
+  AsmPrinter.runOnMachineFunction(MF);
+  return PreservedAnalyses::all();
+}
+
+PreservedAnalyses RISCVAsmPrinterEndPass::run(Module &M,
+                                              ModuleAnalysisManager &MAM) {
+  RISCVAsmPrinter &AsmPrinter = static_cast<RISCVAsmPrinter &>(
+      MAM.getResult<AsmPrinterAnalysis>(M).getPrinter());
+  setupModuleAsmPrinter(M, MAM, AsmPrinter);
+  AsmPrinter.doFinalization(M);
+  return PreservedAnalyses::all();
+}
diff --git a/llvm/lib/Target/RISCV/RISCVAsmPrinter.h b/llvm/lib/Target/RISCV/RISCVAsmPrinter.h
new file mode 100644
index 0000000000000..d4a3807fc62a7
--- /dev/null
+++ b/llvm/lib/Target/RISCV/RISCVAsmPrinter.h
@@ -0,0 +1,39 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_RISCV_RISCVASMPRINTER_H
+#define LLVM_LIB_TARGET_RISCV_RISCVASMPRINTER_H
+
+#include "llvm/CodeGen/MachineFunctionAnalysisManager.h"
+#include "llvm/IR/Analysis.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+
+class RISCVAsmPrinterBeginPass
+    : public RequiredPassInfoMixin<RISCVAsmPrinterBeginPass> {
+public:
+  PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
+};
+
+class RISCVAsmPrinterPass : public RequiredPassInfoMixin<RISCVAsmPrinterPass> {
+public:
+  PreservedAnalyses run(MachineFunction &MF,
+                        MachineFunctionAnalysisManager &MFAM);
+};
+
+class RISCVAsmPrinterEndPass
+    : public RequiredPassInfoMixin<RISCVAsmPrinterEndPass> {
+public:
+  PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
+};
+
+} // namespace llvm
+
+#endif // LLVM_LIB_TARGET_RISCV_RISCVASMPRINTER_H
diff --git a/llvm/lib/Target/RISCV/RISCVCodeGenPassBuilder.cpp b/llvm/lib/Target/RISCV/RISCVCodeGenPassBuilder.cpp
new file mode 100644
index 0000000000000..e7951918bf632
--- /dev/null
+++ b/llvm/lib/Target/RISCV/RISCVCodeGenPassBuilder.cpp
@@ -0,0 +1,238 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+/// This file contains the RISC-V CodeGen pipeline builder.
+/// TODO: Port the remaining RISC-V CodeGen passes to the new pass manager.
+//===----------------------------------------------------------------------===//
+
+#include "RISCV.h"
+#include "RISCVAsmPrinter.h"
+#include "RISCVTargetMachine.h"
+#include "llvm/CodeGen/AtomicExpand.h"
+#include "llvm/CodeGen/BranchRelaxation.h"
+#include "llvm/CodeGen/InterleavedAccess.h"
+#include "llvm/CodeGen/KCFI.h"
+#include "llvm/CodeGen/MachineCopyPropagation.h"
+#include "llvm/CodeGen/MachineInstrBundle.h"
+#include "llvm/CodeGen/MachineLICM.h"
+#include "llvm/CodeGen/TypePromotion.h"
+#include "llvm/IR/PassInstrumentation.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/Passes/CodeGenPassBuilder.h"
+#include "llvm/Passes/PassBuilder.h"
+#include "llvm/Support/CodeGen.h"
+#include "llvm/Target/CGPassBuilderOption.h"
+#include "llvm/Transforms/Vectorize/LoopIdiomVectorize.h"
+#include "llvm/Transforms/Scalar/LoopDataPrefetch.h"
+
+using namespace llvm;
+
+namespace {
+
+class RISCVCodeGenPassBuilder
+    : public CodeGenPassBuilder<RISCVCodeGenPassBuilder, RISCVTargetMachine> {
+  using Base = CodeGenPassBuilder<RISCVCodeGenPassBuilder, RISCVTargetMachine>;
+
+public:
+  explicit RISCVCodeGenPassBuilder(RISCVTargetMachine &TM,
+                                   const CGPassBuilderOption &Opts,
+                                   PassInstrumentationCallbacks *PIC)
+      : CodeGenPassBuilder(TM, Opts, PIC) {
+    // TODO: See the FIXME on RISCVPassConfig::setEnableSinkAndFold in the
+    // legacy pass manager pipeline. There is currently no way to plumb
+    // -riscv-enable-sink-fold through to CGPassBuilderOption::EnableSinkAndFold
+    // from a target-local CodeGenPassBuilder, so this NewPM pipeline always
+    // uses the base class default (disabled).
+  }
+
+  void addIRPasses(PassManagerWrapper &PMW) const;
+  void addCodeGenPrepare(PassManagerWrapper &PMW) const;
+  Error addInstSelector(PassManagerWrapper &PMW) const;
+  void addPreRegAlloc(PassManagerWrapper &PMW) const;
+  void addPostRegAlloc(PassManagerWrapper &PMW) const;
+  void addMachineSSAOptimization(PassManagerWrapper &PMW) const;
+  void addPreSched2(PassManagerWrapper &PMW) const;
+  void addPreEmitPass(PassManagerWrapper &PMW) const;
+  void addPreEmitPass2(PassManagerWrapper &PMW) const;
+  void addAsmPrinterBegin(PassManagerWrapper &PMW) const;
+  void addAsmPrinter(PassManagerWrapper &PMW) const;
+  void addAsmPrinterEnd(PassManagerWrapper &PMW) const;
+};
+
+void RISCVCodeGenPassBuilder::addIRPasses(PassManagerWrapper &PMW) const {
+  addFunctionPass(AtomicExpandPass(TM), PMW);
+  // TODO: RISCVZacasABIFixPass
+
+  if (getOptLevel() != CodeGenOptLevel::None) {
+    addFunctionPass(LoopDataPrefetchPass(), PMW);
+
+    // TODO: RISCVGatherScatterLoweringPass
+    addFunctionPass(InterleavedAccessPass(TM), PMW);
+    addFunctionPass(RISCVCodeGenPreparePass(&TM), PMW);
+  }
+
+  Base::addIRPasses(PMW);
+
+  // TODO: SelectOptimizePass is already added by the base class when
+  // !Opt.DisableSelectOptimize. The legacy pipeline additionally gates this
+  // on -riscv-select-opt and only runs it at -O3; that extra gating is not
+  // yet replicated here.
+}
+
+void RISCVCodeGenPassBuilder::addCodeGenPrepare(PassManagerWrapper &PMW) const {
+  if (getOptLevel() != CodeGenOptLevel::None)
+    addFunctionPass(TypePromotionPass(TM), PMW);
+  Base::addCodeGenPrepare(PMW);
+}
+
+Error RISCVCodeGenPassBuilder::addInstSelector(PassManagerWrapper &PMW) const {
+  addMachineFunctionPass(RISCVISelDAGToDAGPass(TM, getOptLevel()), PMW);
+  return Error::success();
+}
+
+void RISCVCodeGenPassBuilder::addPreRegAlloc(PassManagerWrapper &PMW) const {
+  // TODO: RISCVPreRAExpandPseudoPass
+  if (getOptLevel() != CodeGenOptLevel::None) {
+    // TODO: RISCVMergeBaseOffsetOptPass
+    // TODO: RISCVPreAllocZilsdOptPass
+  }
+
+  // TODO: RISCVInsertReadWriteCSRPass
+  // TODO: RISCVInsertWriteVXRMPass
+  // TODO: RISCVLandingPadSetupPass
+
+  // TODO: MachinePipelinerPass (no new pass manager port exists yet)
+
+  // TODO: RISCVVMV0EliminationPass
+}
+
+void RISCVCodeGenPassBuilder::addPostRegAlloc(PassManagerWrapper &PMW) const {
+  if (getOptLevel() != CodeGenOptLevel::None) {
+    // TODO: RISCVRedundantCopyEliminationPass
+  }
+}
+
+void RISCVCodeGenPassBuilder::addMachineSSAOptimization(
+    PassManagerWrapper &PMW) const {
+  // It's beneficial to reduce the VL to enable more
+  // Machine SSA optimizations.
+  if (getOptLevel() != CodeGenOptLevel::None) {
+    // RISCVVLOptimizer can make loop invariant instructions like vmv.v.i
+    // loop variant by propagating a VL defined inside the loop. Run LICM and
+    // hoist them early. Don't do this at -O0 to avoid the compile-time
+    // overhead. Not reducing the VL of loop invariant pseudos results in more
+    // vsetvli toggles, and still requires the MachineLoopInfo analysis to be
+    // run.
+    addMachineFunctionPass(EarlyMachineLICMPass(), PMW);
+    // TODO: RISCVVLOptimizerPass
+  }
+
+  // TODO: RISCVVectorPeepholePass
+  // TODO: RISCVFoldMemOffsetPass
+
+  Base::addMachineSSAOptimization(PMW);
+
+  if (TM.getTargetTriple().isRISCV64()) {
+    // TODO: RISCVOptWInstrsPass
+  }
+}
+
+void RISCVCodeGenPassBuilder::addPreSched2(PassManagerWrapper &PMW) const {
+  // TODO: RISCVPostRAExpandPseudoPass
+
+  addMachineFunctionPass(MachineKCFIPass(), PMW);
+  if (getOptLevel() != CodeGenOptLevel::None) {
+    // TODO: RISCVLoadStoreOptPass
+  }
+}
+
+void RISCVCodeGenPassBuilder::addPreEmitPass(PassManagerWrapper &PMW) const {
+  // TODO: It would potentially be better to schedule copy propagation after
+  // expanding pseudos (in addPreEmitPass2). However, performing copy
+  // propagation after the machine outliner (which runs after addPreEmitPass)
+  // currently leads to incorrect code-gen, where copies to registers within
+  // outlined functions are removed erroneously.
+  if (getOptLevel() >= CodeGenOptLevel::Default) {
+    addMachineFunctionPass(MachineCopyPropagationPass(true), PMW);
+    // TODO: RISCVLateBranchOptPass
+  }
+  // The IndirectBranchTrackingPass inserts lpad and could have changed the
+  // basic block alignment. It must be done before Branch Relaxation to
+  // prevent the adjusted offset exceeding the branch range.
+  // TODO: RISCVIndirectBranchTrackingPass
+  addMachineFunctionPass(BranchRelaxationPass(), PMW);
+  // TODO: RISCVMakeCompressibleOptPass
+}
+
+void RISCVCodeGenPassBuilder::addPreEmitPass2(PassManagerWrapper &PMW) const {
+  if (getOptLevel() != CodeGenOptLevel::None) {
+    // TODO: RISCVMoveMergePass
+    // TODO: RISCVPushPopOptimizationPass
+  }
+  // TODO: RISCVExpandPseudoPass
+
+  // Add QC Relaxation Markers as late as possible, and only for RV32
+  if (getOptLevel() != CodeGenOptLevel::None &&
+      TM.getTargetTriple().isRISCV32()) {
+    // TODO: RISCVQCRelaxMarkingPass
+  }
+
+  // TODO: RISCVExpandAtomicPseudoPass
+
+  // KCFI indirect call checks are lowered to a bundle.
+  addMachineFunctionPass(
+      UnpackMachineBundlesPass([&](const MachineFunction &MF) {
+        return MF.getFunction().getParent()->getModuleFlag("kcfi");
+      }),
+      PMW);
+
+  // TODO: CFIInstrInserterPass
+}
+
+void RISCVCodeGenPassBuilder::addAsmPrinterBegin(
+    PassManagerWrapper &PMW) const {
+  addModulePass(RISCVAsmPrinterBeginPass(), PMW, /*Force=*/true);
+}
+
+void RISCVCodeGenPassBuilder::addAsmPrinter(PassManagerWrapper &PMW) const {
+  addMachineFunctionPass(RISCVAsmPrinterPass(), PMW);
+}
+
+void RISCVCodeGenPassBuilder::addAsmPrinterEnd(PassManagerWrapper &PMW) const {
+  addModulePass(RISCVAsmPrinterEndPass(), PMW, /*Force=*/true);
+}
+
+} // namespace
+
+void RISCVTargetMachine::registerPassBuilderCallbacks(PassBuilder &PB) {
+#define GET_PASS_REGISTRY "RISCVPassRegistry.def"
+#include "llvm/Passes/TargetPassRegistry.inc"
+
+  PB.registerLateLoopOptimizationsEPCallback([=](LoopPassManager &LPM,
+                                                 OptimizationLevel Level) {
+    if (Level != OptimizationLevel::O0)
+      LPM.addPass(LoopIdiomVectorizePass(LoopIdiomVectorizeStyle::Predicated));
+  });
+
+  if (PIC) {
+    PIC->addClassToPassName(RISCVAsmPrinterBeginPass::name(),
+                            "riscv-asm-printer-begin");
+    PIC->addClassToPassName(RISCVAsmPrinterPass::name(), "riscv-asm-printer");
+    PIC->addClassToPassName(RISCVAsmPrinterEndPass::name(),
+                            "riscv-asm-printer-end");
+  }
+}
+
+Error RISCVTargetMachine::buildCodeGenPipeline(
+    ModulePassManager &MPM, ModuleAnalysisManager &MAM, raw_pwrite_stream &Out,
+    raw_pwrite_stream *DwoOut, CodeGenFileType FileType,
+    const CGPassBuilderOption &Opt, MCContext &Ctx,
+    PassInstrumentationCallbacks *PIC) {
+  auto CGPB = RISCVCodeGenPassBuilder(*this, Opt, PIC);
+  return CGPB.buildPipeline(MPM, MAM, Out, DwoOut, FileType, Ctx);
+}
diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index 611306b6ab7b3..680e2fd00de21 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -5099,6 +5099,10 @@ FunctionPass *llvm::createRISCVISelDag(RISCVTargetMachine &TM,
   return new RISCVDAGToDAGISelLegacy(TM, OptLevel);
 }
 
+RISCVISelDAGToDAGPass::RISCVISelDAGToDAGPass(RISCVTargetMachine &TM,
+                                             CodeGenOptLevel OptLevel)
+    : SelectionDAGISelPass(std::make_unique<RISCVDAGToDAGISel>(TM, OptLevel)) {}
+
 char RISCVDAGToDAGISelLegacy::ID = 0;
 
 RISCVDAGToDAGISelLegacy::RISCVDAGToDAGISelLegacy(RISCVTargetMachine &TM,
diff --git a/llvm/lib/Target/RISCV/RISCVPassRegistry.def b/llvm/lib/Target/RISCV/RISCVPassRegistry.def
index 29ccf2cff1ca5..b42e8ea5b9f35 100644
--- a/llvm/lib/Target/RISCV/RISCVPassRegistry.def
+++ b/llvm/lib/Target/RISCV/RISCVPassRegistry.def
@@ -18,3 +18,9 @@
 #endif
 FUNCTION_PASS("riscv-codegenprepare", RISCVCodeGenPreparePass(this))
 #undef FUNCTION_PASS
+
+#ifndef MACHINE_FUNCTION_PASS
+#define MACHINE_FUNCTION_PASS(NAME, CREATE_PASS)
+#endif
+MACHINE_FUNCTION_PASS("riscv-isel", RISCVISelDAGToDAGPass(*this, getOptLevel()))
+#undef MACHINE_FUNCTION_PASS
diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
index 8cf29ca900faa..517e48faa1043 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
+++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
@@ -34,12 +34,10 @@
 #include "llvm/CodeGen/TargetPassConfig.h"
 #include "llvm/InitializePasses.h"
 #include "llvm/MC/TargetRegistry.h"
-#include "llvm/Passes/PassBuilder.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Target/TargetOptions.h"
 #include "llvm/Transforms/IPO.h"
 #include "llvm/Transforms/Scalar.h"
-#include "llvm/Transforms/Vectorize/LoopIdiomVectorize.h"
 #include <optional>
 using namespace llvm;
 
@@ -681,17 +679,6 @@ bool RISCVPassConfig::addILPOpts() {
   return true;
 }
 
-void RISCVTargetMachine::registerPassBuilderCallbacks(PassBuilder &PB) {
-#define GET_PASS_REGISTRY "RISCVPassRegistry.def"
-#include "llvm/Passes/TargetPassRegistry.inc"
-
-  PB.registerLateLoopOptimizationsEPCallback([=](LoopPassManager &LPM,
-                                                 OptimizationLevel Level) {
-    if (Level != OptimizationLevel::O0)
-      LPM.addPass(LoopIdiomVectorizePass(LoopIdiomVectorizeStyle::Predicated));
-  });
-}
-
 yaml::MachineFunctionInfo *
 RISCVTargetMachine::createDefaultFuncInfoYAML() const {
   return new yaml::RISCVMachineFunctionInfo();
diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.h b/llvm/lib/Target/RISCV/RISCVTargetMachine.h
index c85c2b3d0e611..fdc76454b08d9 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetMachine.h
+++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.h
@@ -59,6 +59,11 @@ class RISCVTargetMachine : public CodeGenTargetMachineImpl {
                                 SMDiagnostic &Error,
                                 SMRange &SourceRange) const override;
   void registerPassBuilderCallbacks(PassBuilder &PB) override;
+  Error buildCodeGenPipeline(ModulePassManager &MPM, ModuleAnalysisManager &MAM,
+                             raw_pwrite_stream &Out, raw_pwrite_stream *DwoOut,
+                             CodeGenFileType FileType,
+                             const CGPassBuilderOption &Opt, MCContext &Ctx,
+                             PassInstrumentationCallbacks *PIC) override;
   ScheduleDAGInstrs *
   createMachineScheduler(MachineSchedContext *C) const override;
   ScheduleDAGInstrs *
diff --git a/llvm/test/CodeGen/RISCV/O1-newpm-pipeline.ll b/llvm/test/CodeGen/RISCV/O1-newpm-pipeline.ll
new file mode 100644
index 0000000000000..92d894d445447
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/O1-newpm-pipeline.ll
@@ -0,0 +1,107 @@
+; RUN: llc -enable-new-pm -mtriple=riscv32 -O1 -print-pipeline-passes=tree < %s 2>&1 \
+; RUN:   | FileCheck %s
+; RUN: llc -enable-new-pm -mtriple=riscv64 -O1 -print-pipeline-passes=tree < %s 2>&1 \
+; RUN:   | FileCheck %s
+
+; CHECK: require<MachineModuleAnalysis>
+; CHECK-NEXT: require<profile-summary>
+; CHECK-NEXT: require<collector-metadata>
+; CHECK-NEXT: require<runtime-libcall-info>
+; CHECK-NEXT: require<libcall-lowering-info>
+; CHECK-NEXT: function
+; CHECK-NEXT:   objc-arc-contract
+; CHECK-NEXT: pre-isel-intrinsic-lowering
+; CHECK-NEXT: function
+; CHECK-NEXT:   expand-ir-insts<O1>
+; CHECK-NEXT:   atomic-expand
+; CHECK-NEXT:   loop-data-prefetch
+; CHECK-NEXT:   interleaved-access
+; CHECK-NEXT:   riscv-codegenprepare
+; CHECK-NEXT:   verify
+; CHECK-NEXT:   loop
+; CHECK-NEXT:     canon-freeze
+; CHECK-NEXT:     loop-reduce
+; CHECK-NEXT:   gc-lowering
+; CHECK-NEXT: shadow-stack-gc-lowering
+; CHECK-NEXT: function
+; CHECK-NEXT:   unreachableblockelim
+; CHECK-NEXT:   consthoist
+; CHECK-NEXT:   replace-with-veclib
+; CHECK-NEXT:   partially-inline-libcalls
+; CHECK-NEXT:   ee-instrument<post-inline>
+; CHECK-NEXT:   scalarize-masked-mem-intrin
+; CHECK-NEXT:   expand-reductions
+; CHECK-NEXT:   typepromotion
+; CHECK-NEXT:   codegenprepare
+; CHECK-NEXT:   dwarf-eh-prepare
+; CHECK-NEXT:   inline-asm-prepare
+; CHECK-NEXT:   safe-stack
+; CHECK-NEXT:   stack-protector
+; CHECK-NEXT:   verify
+; CHECK-NEXT: riscv-asm-printer-begin
+; CHECK-NEXT: function
+; CHECK-NEXT:   machine-function
+; CHECK-NEXT:     riscv-isel
+; CHECK-NEXT:     finalize-isel
+; CHECK-NEXT:     early-machinelicm
+; CHECK-NEXT:     early-tailduplication
+; CHECK-NEXT:     opt-phis
+; CHECK-NEXT:     stack-coloring
+; CHECK-NEXT:     localstackalloc
+; CHECK-NEXT:     dead-mi-elimination
+; CHECK-NEXT:     early-machinelicm
+; CHECK-NEXT:     machine-cse
+; CHECK-NEXT:     machine-sink
+; CHECK-NEXT:     peephole-opt
+; CHECK-NEXT:     dead-mi-elimination
+; CHECK-NEXT:     detect-dead-lanes
+; CHECK-NEXT:     init-undef
+; CHECK-NEXT:     process-imp-defs
+; CHECK-NEXT:     unreachable-mbb-elimination
+; CHECK-NEXT:     require<live-vars>
+; CHECK-NEXT:     require<machine-loops>
+; CHECK-NEXT:     phi-node-elimination
+; CHECK-NEXT:     two-address-instruction
+; CHECK-NEXT:     register-coalescer
+; CHECK-NEXT:     rename-independent-subregs
+; CHECK-NEXT:     machine-scheduler
+; CHECK-NEXT:     greedy<all>
+; CHECK-NEXT:     virt-reg-rewriter
+; CHECK-NEXT:     stack-slot-coloring
+; CHECK-NEXT:     machine-cp
+; CHECK-NEXT:     machinelicm
+; CHECK-NEXT:     remove-redundant-debug-values
+; CHECK-NEXT:     fixup-statepoint-caller-saved
+; CHECK-NEXT:     postra-machine-sink
+; CHECK-NEXT:     shrink-wrap
+; CHECK-NEXT:     prolog-epilog
+; CHECK-NEXT:     machine-latecleanup
+; CHECK-NEXT:     branch-folder
+; CHECK-NEXT:     tailduplication
+; CHECK-NEXT:     machine-cp
+; CHECK-NEXT:     post-ra-pseudos
+; CHECK-NEXT:     kcfi
+; CHECK-NEXT:     post-RA-sched
+; CHECK-NEXT:     block-placement
+; CHECK-NEXT:     fentry-insert
+; CHECK-NEXT:     xray-instrumentation
+; CHECK-NEXT:     patchable-function
+; CHECK-NEXT:     branch-relaxation
+; CHECK-NEXT:     FuncletLayoutPass
+; CHECK-NEXT:     remove-loads-into-fake-uses
+; CHECK-NEXT:     StackMapLivenessPass
+; CHECK-NEXT:     live-debug-values<emit-debug-entry-values>
+; CHECK-NEXT:     machine-sanmd
+; CHECK-NEXT: MachineOutlinerPass
+; CHECK-NEXT: function
+; CHECK-NEXT:   machine-function
+; CHECK-NEXT:     stack-frame-layout
+; CHECK-NEXT:     unpack-mi-bundles
+; CHECK-NEXT:     verify
+; CHECK-NEXT:     riscv-asm-printer
+; CHECK-NEXT:   free-machine-function
+; CHECK-NEXT: riscv-asm-printer-end
+
+define void @f() {
+  ret void
+}
diff --git a/llvm/test/CodeGen/RISCV/O3-newpm-pipeline.ll b/llvm/test/CodeGen/RISCV/O3-newpm-pipeline.ll
new file mode 100644
index 0000000000000..8fc45d046384e
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/O3-newpm-pipeline.ll
@@ -0,0 +1,108 @@
+; RUN: llc -enable-new-pm -mtriple=riscv32 -O3 -print-pipeline-passes=tree < %s 2>&1 \
+; RUN:   | FileCheck %s
+; RUN: llc -enable-new-pm -mtriple=riscv64 -O3 -print-pipeline-passes=tree < %s 2>&1 \
+; RUN:   | FileCheck %s
+
+; CHECK: require<MachineModuleAnalysis>
+; CHECK-NEXT: require<profile-summary>
+; CHECK-NEXT: require<collector-metadata>
+; CHECK-NEXT: require<runtime-libcall-info>
+; CHECK-NEXT: require<libcall-lowering-info>
+; CHECK-NEXT: function
+; CHECK-NEXT:   objc-arc-contract
+; CHECK-NEXT: pre-isel-intrinsic-lowering
+; CHECK-NEXT: function
+; CHECK-NEXT:   expand-ir-insts<O3>
+; CHECK-NEXT:   atomic-expand
+; CHECK-NEXT:   loop-data-prefetch
+; CHECK-NEXT:   interleaved-access
+; CHECK-NEXT:   riscv-codegenprepare
+; CHECK-NEXT:   verify
+; CHECK-NEXT:   loop
+; CHECK-NEXT:     canon-freeze
+; CHECK-NEXT:     loop-reduce
+; CHECK-NEXT:   gc-lowering
+; CHECK-NEXT: shadow-stack-gc-lowering
+; CHECK-NEXT: function
+; CHECK-NEXT:   unreachableblockelim
+; CHECK-NEXT:   consthoist
+; CHECK-NEXT:   replace-with-veclib
+; CHECK-NEXT:   partially-inline-libcalls
+; CHECK-NEXT:   ee-instrument<post-inline>
+; CHECK-NEXT:   scalarize-masked-mem-intrin
+; CHECK-NEXT:   expand-reductions
+; CHECK-NEXT:   typepromotion
+; CHECK-NEXT:   codegenprepare
+; CHECK-NEXT:   dwarf-eh-prepare
+; CHECK-NEXT:   inline-asm-prepare
+; CHECK-NEXT:   safe-stack
+; CHECK-NEXT:   stack-protector
+; CHECK-NEXT:   verify
+; CHECK-NEXT: riscv-asm-printer-begin
+; CHECK-NEXT: function
+; CHECK-NEXT:   machine-function
+; CHECK-NEXT:     riscv-isel
+; CHECK-NEXT:     finalize-isel
+; CHECK-NEXT:     early-machinelicm
+; CHECK-NEXT:     early-tailduplication
+; CHECK-NEXT:     opt-phis
+; CHECK-NEXT:     stack-coloring
+; CHECK-NEXT:     localstackalloc
+; CHECK-NEXT:     dead-mi-elimination
+; CHECK-NEXT:     early-machinelicm
+; CHECK-NEXT:     machine-cse
+; CHECK-NEXT:     machine-sink
+; CHECK-NEXT:     peephole-opt
+; CHECK-NEXT:     dead-mi-elimination
+; CHECK-NEXT:     detect-dead-lanes
+; CHECK-NEXT:     init-undef
+; CHECK-NEXT:     process-imp-defs
+; CHECK-NEXT:     unreachable-mbb-elimination
+; CHECK-NEXT:     require<live-vars>
+; CHECK-NEXT:     require<machine-loops>
+; CHECK-NEXT:     phi-node-elimination
+; CHECK-NEXT:     two-address-instruction
+; CHECK-NEXT:     register-coalescer
+; CHECK-NEXT:     rename-independent-subregs
+; CHECK-NEXT:     machine-scheduler
+; CHECK-NEXT:     greedy<all>
+; CHECK-NEXT:     virt-reg-rewriter
+; CHECK-NEXT:     stack-slot-coloring
+; CHECK-NEXT:     machine-cp
+; CHECK-NEXT:     machinelicm
+; CHECK-NEXT:     remove-redundant-debug-values
+; CHECK-NEXT:     fixup-statepoint-caller-saved
+; CHECK-NEXT:     postra-machine-sink
+; CHECK-NEXT:     shrink-wrap
+; CHECK-NEXT:     prolog-epilog
+; CHECK-NEXT:     machine-latecleanup
+; CHECK-NEXT:     branch-folder
+; CHECK-NEXT:     tailduplication
+; CHECK-NEXT:     machine-cp
+; CHECK-NEXT:     post-ra-pseudos
+; CHECK-NEXT:     kcfi
+; CHECK-NEXT:     post-RA-sched
+; CHECK-NEXT:     block-placement
+; CHECK-NEXT:     fentry-insert
+; CHECK-NEXT:     xray-instrumentation
+; CHECK-NEXT:     patchable-function
+; CHECK-NEXT:     machine-cp
+; CHECK-NEXT:     branch-relaxation
+; CHECK-NEXT:     FuncletLayoutPass
+; CHECK-NEXT:     remove-loads-into-fake-uses
+; CHECK-NEXT:     StackMapLivenessPass
+; CHECK-NEXT:     live-debug-values<emit-debug-entry-values>
+; CHECK-NEXT:     machine-sanmd
+; CHECK-NEXT: MachineOutlinerPass
+; CHECK-NEXT: function
+; CHECK-NEXT:   machine-function
+; CHECK-NEXT:     stack-frame-layout
+; CHECK-NEXT:     unpack-mi-bundles
+; CHECK-NEXT:     verify
+; CHECK-NEXT:     riscv-asm-printer
+; CHECK-NEXT:   free-machine-function
+; CHECK-NEXT: riscv-asm-printer-end
+
+define void @f() {
+  ret void
+}

>From aecd6aa6206e396f2e96f0c65bb6ee03d792843d Mon Sep 17 00:00:00 2001
From: Sam Elliott <aelliott at qti.qualcomm.com>
Date: Thu, 30 Jul 2026 13:22:31 -0700
Subject: [PATCH 2/5] clang-format

---
 llvm/lib/Target/RISCV/RISCVCodeGenPassBuilder.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Target/RISCV/RISCVCodeGenPassBuilder.cpp b/llvm/lib/Target/RISCV/RISCVCodeGenPassBuilder.cpp
index e7951918bf632..4a8e865f1a977 100644
--- a/llvm/lib/Target/RISCV/RISCVCodeGenPassBuilder.cpp
+++ b/llvm/lib/Target/RISCV/RISCVCodeGenPassBuilder.cpp
@@ -27,8 +27,8 @@
 #include "llvm/Passes/PassBuilder.h"
 #include "llvm/Support/CodeGen.h"
 #include "llvm/Target/CGPassBuilderOption.h"
-#include "llvm/Transforms/Vectorize/LoopIdiomVectorize.h"
 #include "llvm/Transforms/Scalar/LoopDataPrefetch.h"
+#include "llvm/Transforms/Vectorize/LoopIdiomVectorize.h"
 
 using namespace llvm;
 

>From c9d404f4a8dcdf781253c5c3eb4d63c80d3f6b77 Mon Sep 17 00:00:00 2001
From: Sam Elliott <aelliott at qti.qualcomm.com>
Date: Thu, 30 Jul 2026 14:33:15 -0700
Subject: [PATCH 3/5] review feedback on RISC-V CGPB

---
 llvm/lib/Target/RISCV/RISCVCodeGenPassBuilder.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVCodeGenPassBuilder.cpp b/llvm/lib/Target/RISCV/RISCVCodeGenPassBuilder.cpp
index 4a8e865f1a977..2ca1d1f6b483f 100644
--- a/llvm/lib/Target/RISCV/RISCVCodeGenPassBuilder.cpp
+++ b/llvm/lib/Target/RISCV/RISCVCodeGenPassBuilder.cpp
@@ -7,7 +7,6 @@
 //===----------------------------------------------------------------------===//
 /// \file
 /// This file contains the RISC-V CodeGen pipeline builder.
-/// TODO: Port the remaining RISC-V CodeGen passes to the new pass manager.
 //===----------------------------------------------------------------------===//
 
 #include "RISCV.h"
@@ -53,9 +52,9 @@ class RISCVCodeGenPassBuilder
   void addIRPasses(PassManagerWrapper &PMW) const;
   void addCodeGenPrepare(PassManagerWrapper &PMW) const;
   Error addInstSelector(PassManagerWrapper &PMW) const;
+  void addMachineSSAOptimization(PassManagerWrapper &PMW) const;
   void addPreRegAlloc(PassManagerWrapper &PMW) const;
   void addPostRegAlloc(PassManagerWrapper &PMW) const;
-  void addMachineSSAOptimization(PassManagerWrapper &PMW) const;
   void addPreSched2(PassManagerWrapper &PMW) const;
   void addPreEmitPass(PassManagerWrapper &PMW) const;
   void addPreEmitPass2(PassManagerWrapper &PMW) const;

>From 05b9c12f390d4c9a16bd0bde57ca0eb655aa9fd9 Mon Sep 17 00:00:00 2001
From: Sam Elliott <aelliott at qti.qualcomm.com>
Date: Thu, 30 Jul 2026 14:47:38 -0700
Subject: [PATCH 4/5] Move function definition too

---
 .../Target/RISCV/RISCVCodeGenPassBuilder.cpp  | 46 ++++++++++---------
 1 file changed, 24 insertions(+), 22 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVCodeGenPassBuilder.cpp b/llvm/lib/Target/RISCV/RISCVCodeGenPassBuilder.cpp
index 2ca1d1f6b483f..7b0afc4561cec 100644
--- a/llvm/lib/Target/RISCV/RISCVCodeGenPassBuilder.cpp
+++ b/llvm/lib/Target/RISCV/RISCVCodeGenPassBuilder.cpp
@@ -94,28 +94,6 @@ Error RISCVCodeGenPassBuilder::addInstSelector(PassManagerWrapper &PMW) const {
   return Error::success();
 }
 
-void RISCVCodeGenPassBuilder::addPreRegAlloc(PassManagerWrapper &PMW) const {
-  // TODO: RISCVPreRAExpandPseudoPass
-  if (getOptLevel() != CodeGenOptLevel::None) {
-    // TODO: RISCVMergeBaseOffsetOptPass
-    // TODO: RISCVPreAllocZilsdOptPass
-  }
-
-  // TODO: RISCVInsertReadWriteCSRPass
-  // TODO: RISCVInsertWriteVXRMPass
-  // TODO: RISCVLandingPadSetupPass
-
-  // TODO: MachinePipelinerPass (no new pass manager port exists yet)
-
-  // TODO: RISCVVMV0EliminationPass
-}
-
-void RISCVCodeGenPassBuilder::addPostRegAlloc(PassManagerWrapper &PMW) const {
-  if (getOptLevel() != CodeGenOptLevel::None) {
-    // TODO: RISCVRedundantCopyEliminationPass
-  }
-}
-
 void RISCVCodeGenPassBuilder::addMachineSSAOptimization(
     PassManagerWrapper &PMW) const {
   // It's beneficial to reduce the VL to enable more
@@ -141,6 +119,30 @@ void RISCVCodeGenPassBuilder::addMachineSSAOptimization(
   }
 }
 
+void RISCVCodeGenPassBuilder::addPreRegAlloc(PassManagerWrapper &PMW) const {
+  // TODO: RISCVPreRAExpandPseudoPass
+  if (getOptLevel() != CodeGenOptLevel::None) {
+    // TODO: RISCVMergeBaseOffsetOptPass
+    // TODO: RISCVPreAllocZilsdOptPass
+  }
+
+  // TODO: RISCVInsertReadWriteCSRPass
+  // TODO: RISCVInsertWriteVXRMPass
+  // TODO: RISCVLandingPadSetupPass
+
+  // TODO: MachinePipelinerPass (no new pass manager port exists yet)
+
+  // TODO: RISCVVMV0EliminationPass
+}
+
+void RISCVCodeGenPassBuilder::addPostRegAlloc(PassManagerWrapper &PMW) const {
+  if (getOptLevel() != CodeGenOptLevel::None) {
+    // TODO: RISCVRedundantCopyEliminationPass
+  }
+}
+
+
+
 void RISCVCodeGenPassBuilder::addPreSched2(PassManagerWrapper &PMW) const {
   // TODO: RISCVPostRAExpandPseudoPass
 

>From 559339ee208f511db1a218b177daaea7a5172c07 Mon Sep 17 00:00:00 2001
From: Sam Elliott <aelliott at qti.qualcomm.com>
Date: Thu, 30 Jul 2026 14:50:46 -0700
Subject: [PATCH 5/5] clang-format

---
 llvm/lib/Target/RISCV/RISCVCodeGenPassBuilder.cpp | 2 --
 1 file changed, 2 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVCodeGenPassBuilder.cpp b/llvm/lib/Target/RISCV/RISCVCodeGenPassBuilder.cpp
index 7b0afc4561cec..8353ad3dfbd3e 100644
--- a/llvm/lib/Target/RISCV/RISCVCodeGenPassBuilder.cpp
+++ b/llvm/lib/Target/RISCV/RISCVCodeGenPassBuilder.cpp
@@ -141,8 +141,6 @@ void RISCVCodeGenPassBuilder::addPostRegAlloc(PassManagerWrapper &PMW) const {
   }
 }
 
-
-
 void RISCVCodeGenPassBuilder::addPreSched2(PassManagerWrapper &PMW) const {
   // TODO: RISCVPostRAExpandPseudoPass
 



More information about the llvm-commits mailing list