[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