[llvm-branch-commits] [llvm] [RISCV][NFC] Add RISCVVSETVLIInfoAnalysis (PR #172615)

Pengcheng Wang via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Sun Jan 11 20:00:58 PST 2026


https://github.com/wangpc-pp updated https://github.com/llvm/llvm-project/pull/172615

>From 150bd672c20f199600cb9f1615cfc659e5f0f619 Mon Sep 17 00:00:00 2001
From: Pengcheng Wang <wangpengcheng.pp at bytedance.com>
Date: Wed, 17 Dec 2025 17:02:48 +0800
Subject: [PATCH 1/2] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20ch?=
 =?UTF-8?q?anges=20to=20main=20this=20commit=20is=20based=20on?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Created using spr 1.3.6-beta.1

[skip ci]
---
 llvm/lib/Target/RISCV/CMakeLists.txt          |   1 +
 .../Target/RISCV/RISCVMachineScheduler.cpp    | 122 ++++++++++++++++++
 llvm/lib/Target/RISCV/RISCVMachineScheduler.h |  33 +++++
 llvm/lib/Target/RISCV/RISCVTargetMachine.cpp  |   3 +-
 4 files changed, 158 insertions(+), 1 deletion(-)
 create mode 100644 llvm/lib/Target/RISCV/RISCVMachineScheduler.cpp
 create mode 100644 llvm/lib/Target/RISCV/RISCVMachineScheduler.h

diff --git a/llvm/lib/Target/RISCV/CMakeLists.txt b/llvm/lib/Target/RISCV/CMakeLists.txt
index f8cf71ea077d6..768c6c4ae3171 100644
--- a/llvm/lib/Target/RISCV/CMakeLists.txt
+++ b/llvm/lib/Target/RISCV/CMakeLists.txt
@@ -54,6 +54,7 @@ add_llvm_target(RISCVCodeGen
   RISCVLoadStoreOptimizer.cpp
   RISCVMachineFunctionInfo.cpp
   RISCVMakeCompressible.cpp
+  RISCVMachineScheduler.cpp
   RISCVMergeBaseOffset.cpp
   RISCVMoveMerger.cpp
   RISCVOptWInstrs.cpp
diff --git a/llvm/lib/Target/RISCV/RISCVMachineScheduler.cpp b/llvm/lib/Target/RISCV/RISCVMachineScheduler.cpp
new file mode 100644
index 0000000000000..0899d66c6e184
--- /dev/null
+++ b/llvm/lib/Target/RISCV/RISCVMachineScheduler.cpp
@@ -0,0 +1,122 @@
+//===- RISCVMachineScheduler.cpp - MI Scheduler for RISC-V ----------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "RISCVMachineScheduler.h"
+#include "llvm/CodeGen/ScheduleDAG.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "riscv-prera-sched-strategy"
+
+bool RISCVPreRAMachineSchedStrategy::tryCandidate(SchedCandidate &Cand,
+                                                  SchedCandidate &TryCand,
+                                                  SchedBoundary *Zone) const {
+  //-------------------------------------------------------------------------//
+  // Below is copied from `GenericScheduler::tryCandidate`.
+  // FIXME: Is there a way to not replicate this?
+  //-------------------------------------------------------------------------//
+  // Initialize the candidate if needed.
+  if (!Cand.isValid()) {
+    TryCand.Reason = FirstValid;
+    return true;
+  }
+
+  // Bias PhysReg Defs and copies to their uses and defined respectively.
+  if (tryGreater(biasPhysReg(TryCand.SU, TryCand.AtTop),
+                 biasPhysReg(Cand.SU, Cand.AtTop), TryCand, Cand, PhysReg))
+    return TryCand.Reason != NoCand;
+
+  // Avoid exceeding the target's limit.
+  if (DAG->isTrackingPressure() &&
+      tryPressure(TryCand.RPDelta.Excess, Cand.RPDelta.Excess, TryCand, Cand,
+                  RegExcess, TRI, DAG->MF))
+    return TryCand.Reason != NoCand;
+
+  // Avoid increasing the max critical pressure in the scheduled region.
+  if (DAG->isTrackingPressure() &&
+      tryPressure(TryCand.RPDelta.CriticalMax, Cand.RPDelta.CriticalMax,
+                  TryCand, Cand, RegCritical, TRI, DAG->MF))
+    return TryCand.Reason != NoCand;
+
+  // We only compare a subset of features when comparing nodes between
+  // Top and Bottom boundary. Some properties are simply incomparable, in many
+  // other instances we should only override the other boundary if something
+  // is a clear good pick on one boundary. Skip heuristics that are more
+  // "tie-breaking" in nature.
+  bool SameBoundary = Zone != nullptr;
+  if (SameBoundary) {
+    // For loops that are acyclic path limited, aggressively schedule for
+    // latency. Within an single cycle, whenever CurrMOps > 0, allow normal
+    // heuristics to take precedence.
+    if (Rem.IsAcyclicLatencyLimited && !Zone->getCurrMOps() &&
+        tryLatency(TryCand, Cand, *Zone))
+      return TryCand.Reason != NoCand;
+
+    // Prioritize instructions that read unbuffered resources by stall cycles.
+    if (tryLess(Zone->getLatencyStallCycles(TryCand.SU),
+                Zone->getLatencyStallCycles(Cand.SU), TryCand, Cand, Stall))
+      return TryCand.Reason != NoCand;
+  }
+
+  // Keep clustered nodes together to encourage downstream peephole
+  // optimizations which may reduce resource requirements.
+  //
+  // This is a best effort to set things up for a post-RA pass. Optimizations
+  // like generating loads of multiple registers should ideally be done within
+  // the scheduler pass by combining the loads during DAG postprocessing.
+  unsigned CandZoneCluster = Cand.AtTop ? TopClusterID : BotClusterID;
+  unsigned TryCandZoneCluster = TryCand.AtTop ? TopClusterID : BotClusterID;
+  bool CandIsClusterSucc =
+      isTheSameCluster(CandZoneCluster, Cand.SU->ParentClusterIdx);
+  bool TryCandIsClusterSucc =
+      isTheSameCluster(TryCandZoneCluster, TryCand.SU->ParentClusterIdx);
+
+  if (tryGreater(TryCandIsClusterSucc, CandIsClusterSucc, TryCand, Cand,
+                 Cluster))
+    return TryCand.Reason != NoCand;
+
+  if (SameBoundary) {
+    // Weak edges are for clustering and other constraints.
+    if (tryLess(getWeakLeft(TryCand.SU, TryCand.AtTop),
+                getWeakLeft(Cand.SU, Cand.AtTop), TryCand, Cand, Weak))
+      return TryCand.Reason != NoCand;
+  }
+
+  // Avoid increasing the max pressure of the entire region.
+  if (DAG->isTrackingPressure() &&
+      tryPressure(TryCand.RPDelta.CurrentMax, Cand.RPDelta.CurrentMax, TryCand,
+                  Cand, RegMax, TRI, DAG->MF))
+    return TryCand.Reason != NoCand;
+
+  if (SameBoundary) {
+    // Avoid critical resource consumption and balance the schedule.
+    TryCand.initResourceDelta(DAG, SchedModel);
+    if (tryLess(TryCand.ResDelta.CritResources, Cand.ResDelta.CritResources,
+                TryCand, Cand, ResourceReduce))
+      return TryCand.Reason != NoCand;
+    if (tryGreater(TryCand.ResDelta.DemandedResources,
+                   Cand.ResDelta.DemandedResources, TryCand, Cand,
+                   ResourceDemand))
+      return TryCand.Reason != NoCand;
+
+    // Avoid serializing long latency dependence chains.
+    // For acyclic path limited loops, latency was already checked above.
+    if (!RegionPolicy.DisableLatencyHeuristic && TryCand.Policy.ReduceLatency &&
+        !Rem.IsAcyclicLatencyLimited && tryLatency(TryCand, Cand, *Zone))
+      return TryCand.Reason != NoCand;
+
+    // Fall through to original instruction order.
+    if ((Zone->isTop() && TryCand.SU->NodeNum < Cand.SU->NodeNum) ||
+        (!Zone->isTop() && TryCand.SU->NodeNum > Cand.SU->NodeNum)) {
+      TryCand.Reason = NodeOrder;
+      return true;
+    }
+  }
+
+  return false;
+}
diff --git a/llvm/lib/Target/RISCV/RISCVMachineScheduler.h b/llvm/lib/Target/RISCV/RISCVMachineScheduler.h
new file mode 100644
index 0000000000000..1807f6b3d2cb4
--- /dev/null
+++ b/llvm/lib/Target/RISCV/RISCVMachineScheduler.h
@@ -0,0 +1,33 @@
+//===--- RISCVMachineScheduler.h - Custom RISC-V MI scheduler ---*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Custom RISC-V MI scheduler.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_RISCV_RISCVMACHINESCHEDULER_H
+#define LLVM_LIB_TARGET_RISCV_RISCVMACHINESCHEDULER_H
+
+#include "llvm/CodeGen/MachineScheduler.h"
+
+namespace llvm {
+
+/// A GenericScheduler implementation for RISCV pre RA scheduling.
+class RISCVPreRAMachineSchedStrategy : public GenericScheduler {
+public:
+  RISCVPreRAMachineSchedStrategy(const MachineSchedContext *C)
+      : GenericScheduler(C) {}
+
+protected:
+  bool tryCandidate(SchedCandidate &Cand, SchedCandidate &TryCand,
+                    SchedBoundary *Zone) const override;
+};
+
+} // end namespace llvm
+
+#endif
diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
index 52dc38564059c..971882053ac79 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
+++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
@@ -14,6 +14,7 @@
 #include "MCTargetDesc/RISCVBaseInfo.h"
 #include "RISCV.h"
 #include "RISCVMachineFunctionInfo.h"
+#include "RISCVMachineScheduler.h"
 #include "RISCVTargetObjectFile.h"
 #include "RISCVTargetTransformInfo.h"
 #include "TargetInfo/RISCVTargetInfo.h"
@@ -279,7 +280,7 @@ bool RISCVTargetMachine::isNoopAddrSpaceCast(unsigned SrcAS,
 ScheduleDAGInstrs *
 RISCVTargetMachine::createMachineScheduler(MachineSchedContext *C) const {
   const RISCVSubtarget &ST = C->MF->getSubtarget<RISCVSubtarget>();
-  ScheduleDAGMILive *DAG = createSchedLive(C);
+  ScheduleDAGMILive *DAG = createSchedLive<RISCVPreRAMachineSchedStrategy>(C);
 
   if (ST.enableMISchedLoadClustering())
     DAG->addMutation(createLoadClusterDAGMutation(

>From b85f43932660cd181d7358a8ed0f4877640210f6 Mon Sep 17 00:00:00 2001
From: Pengcheng Wang <wangpengcheng.pp at bytedance.com>
Date: Thu, 18 Dec 2025 15:24:52 +0800
Subject: [PATCH 2/2] Address comments

Created using spr 1.3.6-beta.1
---
 llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp  | 39 ++++++++++++++-----
 .../Target/RISCV/RISCVVSETVLIInfoAnalysis.cpp | 21 ++--------
 .../Target/RISCV/RISCVVSETVLIInfoAnalysis.h   | 26 +++----------
 3 files changed, 37 insertions(+), 49 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp b/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp
index e5c3dc66cb18b..8ba00c815fa0e 100644
--- a/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp
+++ b/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp
@@ -68,13 +68,33 @@ static unsigned getVLOpNum(const MachineInstr &MI) {
   return RISCVII::getVLOpNum(MI.getDesc());
 }
 
+struct BlockData {
+  // The VSETVLIInfo that represents the VL/VTYPE settings on exit from this
+  // block. Calculated in Phase 2.
+  VSETVLIInfo Exit;
+
+  // The VSETVLIInfo that represents the VL/VTYPE settings from all predecessor
+  // blocks. Calculated in Phase 2, and used by Phase 3.
+  VSETVLIInfo Pred;
+
+  // Keeps track of whether the block is already in the queue.
+  bool InQueue = false;
+
+  BlockData() = default;
+};
+
+enum TKTMMode {
+  VSETTK = 0,
+  VSETTM = 1,
+};
+
 class RISCVInsertVSETVLI : public MachineFunctionPass {
   const RISCVSubtarget *ST;
   const TargetInstrInfo *TII;
   MachineRegisterInfo *MRI;
   // Possibly null!
   LiveIntervals *LIS;
-  RISCVVSETVLIInfoAnalysis *VIA;
+  RISCVVSETVLIInfoAnalysis VIA;
 
   std::vector<BlockData> BlockInfo;
   std::queue<const MachineBasicBlock *> WorkList;
@@ -179,7 +199,7 @@ void RISCVInsertVSETVLI::insertVSETVLI(MachineBasicBlock &MBB,
     if (Info.hasSameVLMAX(PrevInfo) && Info.hasAVLReg()) {
       if (const MachineInstr *DefMI = Info.getAVLDefMI(LIS);
           DefMI && RISCVInstrInfo::isVectorConfigInstr(*DefMI)) {
-        VSETVLIInfo DefInfo = VIA->getInfoForVSETVLI(*DefMI);
+        VSETVLIInfo DefInfo = VIA.getInfoForVSETVLI(*DefMI);
         if (DefInfo.hasSameAVL(PrevInfo) && DefInfo.hasSameVLMAX(PrevInfo)) {
           auto MI =
               BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLIX0X0))
@@ -311,7 +331,7 @@ void RISCVInsertVSETVLI::transferBefore(VSETVLIInfo &Info,
 
   DemandedFields Demanded = getDemanded(MI, ST);
 
-  const VSETVLIInfo NewInfo = VIA->computeInfoForInstr(MI);
+  const VSETVLIInfo NewInfo = VIA.computeInfoForInstr(MI);
   assert(NewInfo.isValid() && !NewInfo.isUnknown());
   if (Info.isValid() && !needVSETVLI(Demanded, NewInfo, Info))
     return;
@@ -362,7 +382,7 @@ void RISCVInsertVSETVLI::transferBefore(VSETVLIInfo &Info,
 void RISCVInsertVSETVLI::transferAfter(VSETVLIInfo &Info,
                                        const MachineInstr &MI) const {
   if (RISCVInstrInfo::isVectorConfigInstr(MI)) {
-    Info = VIA->getInfoForVSETVLI(MI);
+    Info = VIA.getInfoForVSETVLI(MI);
     return;
   }
 
@@ -493,7 +513,7 @@ bool RISCVInsertVSETVLI::needVSETVLIPHI(const VSETVLIInfo &Require,
 
     // We found a VSET(I)VLI make sure it matches the output of the
     // predecessor block.
-    VSETVLIInfo DefInfo = VIA->getInfoForVSETVLI(*DefMI);
+    VSETVLIInfo DefInfo = VIA.getInfoForVSETVLI(*DefMI);
     if (DefInfo != PBBExit)
       return true;
 
@@ -736,8 +756,8 @@ bool RISCVInsertVSETVLI::canMutatePriorConfig(
     if (Used.VLZeroness) {
       if (RISCVInstrInfo::isVLPreservingConfig(PrevMI))
         return false;
-      if (!VIA->getInfoForVSETVLI(PrevMI).hasEquallyZeroAVL(
-              VIA->getInfoForVSETVLI(MI), LIS))
+      if (!VIA.getInfoForVSETVLI(PrevMI).hasEquallyZeroAVL(
+              VIA.getInfoForVSETVLI(MI), LIS))
         return false;
     }
 
@@ -925,7 +945,7 @@ bool RISCVInsertVSETVLI::insertVSETMTK(MachineBasicBlock &MBB,
         !RISCVII::hasSEWOp(TSFlags) || !RISCVII::hasTWidenOp(TSFlags))
       continue;
 
-    VSETVLIInfo CurrInfo = VIA->computeInfoForInstr(MI);
+    VSETVLIInfo CurrInfo = VIA.computeInfoForInstr(MI);
 
     if (Mode == VSETTK && !RISCVII::hasTKOp(TSFlags))
       continue;
@@ -986,8 +1006,7 @@ bool RISCVInsertVSETVLI::runOnMachineFunction(MachineFunction &MF) {
   MRI = &MF.getRegInfo();
   auto *LISWrapper = getAnalysisIfAvailable<LiveIntervalsWrapperPass>();
   LIS = LISWrapper ? &LISWrapper->getLIS() : nullptr;
-  RISCVVSETVLIInfoAnalysis SETVLIInfoAnalysis(ST, LIS);
-  VIA = &SETVLIInfoAnalysis;
+  VIA = RISCVVSETVLIInfoAnalysis(ST, LIS);
 
   assert(BlockInfo.empty() && "Expect empty block infos");
   BlockInfo.resize(MF.getNumBlockIDs());
diff --git a/llvm/lib/Target/RISCV/RISCVVSETVLIInfoAnalysis.cpp b/llvm/lib/Target/RISCV/RISCVVSETVLIInfoAnalysis.cpp
index 4d586c0455d96..3fa9baea6de14 100644
--- a/llvm/lib/Target/RISCV/RISCVVSETVLIInfoAnalysis.cpp
+++ b/llvm/lib/Target/RISCV/RISCVVSETVLIInfoAnalysis.cpp
@@ -1,4 +1,4 @@
-//===- RISCVInsertVSETVLI.cpp - Insert VSETVLI instructions ---------------===//
+//===- RISCVVSETVLIInfoAnalysis.cpp - VSETVLI Info Analysis ---------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -6,21 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// This file implements a function pass that inserts VSETVLI instructions where
-// needed and expands the vl outputs of VLEFF/VLSEGFF to PseudoReadVL
-// instructions.
-//
-// This pass consists of 3 phases:
-//
-// Phase 1 collects how each basic block affects VL/VTYPE.
-//
-// Phase 2 uses the information from phase 1 to do a data flow analysis to
-// propagate the VL/VTYPE changes through the function. This gives us the
-// VL/VTYPE at the start of each basic block.
-//
-// Phase 3 inserts VSETVLI instructions in each basic block. Information from
-// phase 2 is used to prevent inserting a VSETVLI before the first vector
-// instruction in the block if possible.
+// This file implements an analysis of the vtype/vl information that is needed
+// by RISCVInsertVSETVLI pass and others.
 //
 //===----------------------------------------------------------------------===//
 
@@ -28,8 +15,6 @@
 #include "RISCVSubtarget.h"
 #include "llvm/CodeGen/LiveIntervals.h"
 
-#define DEBUG_TYPE "riscv-vsetvli-info"
-
 namespace llvm {
 namespace RISCV {
 
diff --git a/llvm/lib/Target/RISCV/RISCVVSETVLIInfoAnalysis.h b/llvm/lib/Target/RISCV/RISCVVSETVLIInfoAnalysis.h
index 84700375d2f07..ec8b8c3fc9812 100644
--- a/llvm/lib/Target/RISCV/RISCVVSETVLIInfoAnalysis.h
+++ b/llvm/lib/Target/RISCV/RISCVVSETVLIInfoAnalysis.h
@@ -1,4 +1,4 @@
-//===- RISCVInsertVSETVLI.cpp - Insert VSETVLI instructions ---------------===//
+//===- RISCVVSETVLIInfoAnalysis.h - VSETVLI Info Analysis -----------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -6,6 +6,9 @@
 //
 //===----------------------------------------------------------------------===//
 //
+// This file implements an analysis of the vtype/vl information that is needed
+// by RISCVInsertVSETVLI pass and others.
+//
 //===----------------------------------------------------------------------===//
 
 #include "RISCV.h"
@@ -565,32 +568,13 @@ inline raw_ostream &operator<<(raw_ostream &OS, const VSETVLIInfo &V) {
 }
 #endif
 
-struct BlockData {
-  // The VSETVLIInfo that represents the VL/VTYPE settings on exit from this
-  // block. Calculated in Phase 2.
-  VSETVLIInfo Exit;
-
-  // The VSETVLIInfo that represents the VL/VTYPE settings from all predecessor
-  // blocks. Calculated in Phase 2, and used by Phase 3.
-  VSETVLIInfo Pred;
-
-  // Keeps track of whether the block is already in the queue.
-  bool InQueue = false;
-
-  BlockData() = default;
-};
-
-enum TKTMMode {
-  VSETTK = 0,
-  VSETTM = 1,
-};
-
 class RISCVVSETVLIInfoAnalysis {
   const RISCVSubtarget *ST;
   // Possibly null!
   LiveIntervals *LIS;
 
 public:
+  RISCVVSETVLIInfoAnalysis() = default;
   RISCVVSETVLIInfoAnalysis(const RISCVSubtarget *ST, LiveIntervals *LIS)
       : ST(ST), LIS(LIS) {}
 



More information about the llvm-branch-commits mailing list