[llvm] [RISCV] Remove unnecessary dependencies on vtype register. (PR #146971)

Mikhail Gudim via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 3 16:18:33 PDT 2025


https://github.com/mgudim created https://github.com/llvm/llvm-project/pull/146971

None

>From 393dfe41c4a045b904383c32489e91445e6fdfac Mon Sep 17 00:00:00 2001
From: Mikhail Gudim <mgudim at ventanamicro.com>
Date: Thu, 3 Jul 2025 16:12:56 -0700
Subject: [PATCH] [RISCV] Remove unnecessary dependencies on vtype register.

---
 llvm/lib/Target/RISCV/CMakeLists.txt          |   1 +
 llvm/lib/Target/RISCV/RISCVTargetMachine.cpp  |   7 +
 llvm/lib/Target/RISCV/RISCVTargetMachine.h    |   2 +
 .../Target/RISCV/RISCVVTypeRegDepMutation.cpp | 170 ++++++++++++++++++
 4 files changed, 180 insertions(+)
 create mode 100644 llvm/lib/Target/RISCV/RISCVVTypeRegDepMutation.cpp

diff --git a/llvm/lib/Target/RISCV/CMakeLists.txt b/llvm/lib/Target/RISCV/CMakeLists.txt
index e32d6eab3b977..929868585eca5 100644
--- a/llvm/lib/Target/RISCV/CMakeLists.txt
+++ b/llvm/lib/Target/RISCV/CMakeLists.txt
@@ -67,6 +67,7 @@ add_llvm_target(RISCVCodeGen
   RISCVVectorMaskDAGMutation.cpp
   RISCVVectorPeephole.cpp
   RISCVVLOptimizer.cpp
+  RISCVVTypeRegDepMutation.cpp
   RISCVVMV0Elimination.cpp
   RISCVZacasABIFix.cpp
   GISel/RISCVCallLowering.cpp
diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
index b43b915d0ad4f..87a3ef1cd9231 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
+++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
@@ -104,6 +104,11 @@ static cl::opt<bool> EnablePostMISchedLoadStoreClustering(
     cl::desc("Enable PostRA load and store clustering in the machine scheduler"),
     cl::init(true));
 
+static cl::opt<bool> EnableVTypeRegDepMutation(
+    "riscv-postmisched-vtype-reg-dep-mutation", cl::Hidden,
+    cl::desc("Remove unnecessary dependencies on vtype register"),
+    cl::init(false));
+
 static cl::opt<bool>
     EnableVLOptimizer("riscv-enable-vl-optimizer",
                       cl::desc("Enable the RISC-V VL Optimizer pass"),
@@ -323,6 +328,8 @@ RISCVTargetMachine::createPostMachineScheduler(MachineSchedContext *C) const {
     DAG->addMutation(createStoreClusterDAGMutation(
         DAG->TII, DAG->TRI, /*ReorderWhileClustering=*/true));
   }
+  if (EnableVTypeRegDepMutation)
+    DAG->addMutation(createRISCVVTypeRegDepMutation(DAG->TRI));
 
   return DAG;
 }
diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.h b/llvm/lib/Target/RISCV/RISCVTargetMachine.h
index c85c2b3d0e611..266d77228baf8 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetMachine.h
+++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.h
@@ -68,6 +68,8 @@ class RISCVTargetMachine : public CodeGenTargetMachineImpl {
 std::unique_ptr<ScheduleDAGMutation>
 createRISCVVectorMaskDAGMutation(const TargetRegisterInfo *TRI);
 
+std::unique_ptr<ScheduleDAGMutation>
+createRISCVVTypeRegDepMutation(const TargetRegisterInfo *TRI);
 } // namespace llvm
 
 #endif
diff --git a/llvm/lib/Target/RISCV/RISCVVTypeRegDepMutation.cpp b/llvm/lib/Target/RISCV/RISCVVTypeRegDepMutation.cpp
new file mode 100644
index 0000000000000..7c209cb22e4e7
--- /dev/null
+++ b/llvm/lib/Target/RISCV/RISCVVTypeRegDepMutation.cpp
@@ -0,0 +1,170 @@
+//===- RISCVVTypeRegDepMutation.cpp - RISC-V Vector Mask DAGMutation ----===//
+//
+// 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 "MCTargetDesc/RISCVBaseInfo.h"
+#include "MCTargetDesc/RISCVMCTargetDesc.h"
+#include "RISCVRegisterInfo.h"
+#include "RISCVTargetMachine.h"
+#include "llvm/CodeGen/LiveIntervals.h"
+#include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/CodeGen/ScheduleDAGInstrs.h"
+#include "llvm/CodeGen/ScheduleDAGMutation.h"
+#include "llvm/TargetParser/RISCVTargetParser.h"
+
+#define DEBUG_TYPE "machine-scheduler"
+
+namespace llvm {
+
+static void collectPossibleVSetsForMI(
+    MachineInstr *MI, int RequiredVL, unsigned PossibleVType,
+    SmallVector<std::tuple<MachineInstr *, int>> &VSetInstrVLs,
+    SmallVector<MachineInstr *> &PossibleVSets) {
+  unsigned VTypeMask = unsigned(-1);
+  if (MI->getOpcode() == RISCV::PseudoVLE8_V_MF4 ||
+      MI->getOpcode() == RISCV::PseudoVLE8_V_MF8) {
+    // TODO: actually, we care about the ratio lmul / sew
+    VTypeMask = ~((0x7 << 3) | 0x7);
+  }
+  unsigned RequiredMaskedVType = PossibleVType & VTypeMask;
+  for (auto &VSetInstrVL : VSetInstrVLs) {
+    MachineInstr *VSetInstr = std::get<0>(VSetInstrVL);
+    if ((std::get<1>(VSetInstrVL) == RequiredVL) &&
+        ((VSetInstr->getOperand(2).getImm() & VTypeMask) ==
+         RequiredMaskedVType)) {
+      PossibleVSets.push_back(VSetInstr);
+    }
+  }
+  return;
+}
+
+class RISCVVTypeRegDepMutation : public ScheduleDAGMutation {
+private:
+  const TargetRegisterInfo *TRI;
+
+public:
+  RISCVVTypeRegDepMutation(const TargetRegisterInfo *TRI) : TRI(TRI) {}
+  void apply(ScheduleDAGInstrs *DAG) override;
+};
+
+// For each instruction I that reads vtype register:
+//  (1) compute reaching definitions of vtype register.
+//  (2) From all vtype reg definitions in the basic block collect the ones
+//  compatible with those found in (1) (call this set Comp(I)).
+//  (3) for each instruction vset in Comp(I) if there is data dependence on
+//  vtype reg vset->I, remove it, also, remove all anti-depencies I->vset (4)
+//  Choose by some heuristic an instruction best_vset from Comp(I) and insert
+//  data  dependence on vtype: best_vset->I. NOTE: code below is not correct,
+//  but by luck it doesn't cause any issues on SPEC.
+void RISCVVTypeRegDepMutation::apply(ScheduleDAGInstrs *DAG) {
+  SmallVector<std::tuple<MachineInstr *, int>> VSetInstrVLs;
+  SmallVector<std::tuple<MachineInstr *, int, MachineInstr *>> MIVLVSetInstrs;
+  int CurrentVL = -1;
+  for (auto MBBI = DAG->begin(); MBBI != DAG->end(); ++MBBI) {
+    switch (MBBI->getOpcode()) {
+    default:
+      continue;
+    case RISCV::PseudoVSETIVLI: {
+      CurrentVL = MBBI->getOperand(1).getImm();
+      VSetInstrVLs.push_back({&*MBBI, CurrentVL});
+      continue;
+    }
+    case RISCV::PseudoVSETVLI: {
+      continue;
+    }
+    case RISCV::PseudoVSETVLIX0X0: {
+      // TODO: the case when we're setting to VLMax
+      // if (MBBI->getOperand(0).getReg() != RISCV::X0) {
+      //   continue;
+      // }
+      VSetInstrVLs.push_back(std::make_pair(&*MBBI, CurrentVL));
+      continue;
+    }
+    case RISCV::PseudoVLE8_V_MF8:
+    case RISCV::PseudoVLE8_V_MF4: {
+      if (!VSetInstrVLs.empty())
+        MIVLVSetInstrs.push_back(
+            {&*MBBI, CurrentVL, std::get<0>(VSetInstrVLs.back())});
+      continue;
+    }
+    }
+  }
+
+  DenseMap<MachineInstr *,
+           std::tuple<SmallVector<MachineInstr *>, MachineInstr *>>
+      MIToPossibleVSetsMap;
+  for (auto &MIVLVSetInstr : MIVLVSetInstrs) {
+    MachineInstr *OrigVSetInstr = std::get<2>(MIVLVSetInstr);
+    int RequiredVL = std::get<1>(MIVLVSetInstr);
+    int PossibleVType = OrigVSetInstr->getOperand(2).getImm();
+    SmallVector<MachineInstr *> PossibleVSets;
+    MachineInstr *MI = std::get<0>(MIVLVSetInstr);
+    collectPossibleVSetsForMI(MI, RequiredVL, PossibleVType, VSetInstrVLs,
+                              PossibleVSets);
+    MIToPossibleVSetsMap[MI] = {PossibleVSets, OrigVSetInstr};
+  }
+
+  DenseMap<MachineInstr *, SUnit *> VSetToSUMap;
+  for (SUnit &SU : DAG->SUnits) {
+    if (!SU.isInstr())
+      continue;
+    MachineInstr *MI = SU.getInstr();
+    unsigned Opc = MI->getOpcode();
+    if ((Opc == RISCV::PseudoVSETIVLI) || (Opc == RISCV::PseudoVSETVLI) ||
+        (Opc == RISCV::PseudoVSETVLIX0))
+      VSetToSUMap[MI] = &SU;
+  }
+
+  for (SUnit &SU : DAG->SUnits) {
+    if (!SU.isInstr())
+      continue;
+    MachineInstr *MI = SU.getInstr();
+    SmallVector<MachineInstr *> &PossibleVSets =
+        std::get<0>(MIToPossibleVSetsMap[MI]);
+    if (PossibleVSets.size() < 2)
+      continue;
+    // Choose the earliest (in the original program order) VSET insruction
+    // satisfying the vtype requirements of MI.
+    SUnit *NewVSetSU = VSetToSUMap[PossibleVSets[0]];
+    SUnit *OldVSetSU = VSetToSUMap[std::get<1>(MIToPossibleVSetsMap[MI])];
+    for (auto &D : SU.Succs) {
+      if (D.getKind() != SDep::Kind::Anti)
+        continue;
+      unsigned Reg = D.getReg();
+      if (Reg != RISCV::VL && Reg != RISCV::VTYPE)
+        continue;
+      SUnit &AntiDepSucc = *D.getSUnit();
+      // TODO: we can only remove anti-depence to compatible vsets.
+      for (auto &P : AntiDepSucc.Preds) {
+        if (P.getSUnit() == &SU) {
+          AntiDepSucc.removePred(P);
+        }
+      }
+    }
+    for (auto &D : SU.Preds) {
+      if (D.getSUnit() != OldVSetSU)
+        continue;
+      if (D.getKind() != SDep::Kind::Data)
+        continue;
+      unsigned Reg = D.getReg();
+      if (Reg != RISCV::VL && Reg != RISCV::VTYPE)
+        continue;
+      unsigned Latency = D.getLatency();
+      SU.removePred(D);
+      SDep NewSDep(NewVSetSU, SDep::Kind::Data, Reg);
+      NewSDep.setLatency(Latency);
+      SU.addPred(NewSDep);
+    }
+  }
+  return;
+}
+
+std::unique_ptr<ScheduleDAGMutation>
+createRISCVVTypeRegDepMutation(const TargetRegisterInfo *TRI) {
+  return std::make_unique<RISCVVTypeRegDepMutation>(TRI);
+}
+} // namespace llvm



More information about the llvm-commits mailing list