[llvm] [NFC][CodeGen] Add helper function to check SubReg validity (PR #181489)

Rahul Joshi via llvm-commits llvm-commits at lists.llvm.org
Mon Feb 16 13:54:04 PST 2026


https://github.com/jurahul updated https://github.com/llvm/llvm-project/pull/181489

>From 4951019f7313601daf4fcd50d81f66d6e10d7e9b Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Sat, 14 Feb 2026 08:58:27 -0800
Subject: [PATCH 1/2] [NFC][CodeGen] Add helper function to check SubReg
 validity

---
 .../include/llvm/CodeGen/TargetRegisterInfo.h | 14 +++++++++++
 llvm/lib/CodeGen/MachineInstr.cpp             |  3 ++-
 llvm/lib/CodeGen/MachineVerifier.cpp          | 24 ++++++-------------
 llvm/lib/CodeGen/PeepholeOptimizer.cpp        |  8 ++-----
 llvm/lib/CodeGen/TargetRegisterInfo.cpp       |  2 +-
 .../AMDGPU/GCNRewritePartialRegUses.cpp       |  2 +-
 6 files changed, 27 insertions(+), 26 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
index b69a91651e300..09428c78292ba 100644
--- a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
@@ -735,6 +735,20 @@ class LLVM_ABI TargetRegisterInfo : public MCRegisterInfo {
     return nullptr;
   }
 
+  /// Returns true if sub-register \p Idx can be used with register class
+  /// \p RC.
+  bool isSubRegValidForRegClass(const TargetRegisterClass *RC,
+                                unsigned Idx) const {
+    // NoSubRegister is always valid.
+    if (!Idx)
+      return true;
+
+    // `Idx` is valid if the largest subclass of `RC` that supports
+    // sub-register index `Idx` is same as `RC`. That is, every physical
+    // register in `RC` support sub-register index `Idx`.
+    return getSubClassWithSubReg(RC, Idx) == RC;
+  }
+
   /// Return the subregister index you get from composing
   /// two subregister indices.
   ///
diff --git a/llvm/lib/CodeGen/MachineInstr.cpp b/llvm/lib/CodeGen/MachineInstr.cpp
index 20e448f1d1954..926c00336efbc 100644
--- a/llvm/lib/CodeGen/MachineInstr.cpp
+++ b/llvm/lib/CodeGen/MachineInstr.cpp
@@ -1078,8 +1078,9 @@ const TargetRegisterClass *MachineInstr::getRegClassConstraintEffect(
       CurRC = TRI->getMatchingSuperRegClass(CurRC, OpRC, SubIdx);
     else
       CurRC = TRI->getSubClassWithSubReg(CurRC, SubIdx);
-  } else if (OpRC)
+  } else if (OpRC) {
     CurRC = TRI->getCommonSubClass(CurRC, OpRC);
+  }
   return CurRC;
 }
 
diff --git a/llvm/lib/CodeGen/MachineVerifier.cpp b/llvm/lib/CodeGen/MachineVerifier.cpp
index 919d451e25e54..7f016267f9906 100644
--- a/llvm/lib/CodeGen/MachineVerifier.cpp
+++ b/llvm/lib/CodeGen/MachineVerifier.cpp
@@ -2800,23 +2800,13 @@ MachineVerifier::visitMachineOperand(const MachineOperand *MO, unsigned MONum) {
 
         break;
       }
-      if (SubIdx) {
-        const TargetRegisterClass *SRC =
-          TRI->getSubClassWithSubReg(RC, SubIdx);
-        if (!SRC) {
-          report("Invalid subregister index for virtual register", MO, MONum);
-          OS << "Register class " << TRI->getRegClassName(RC)
-             << " does not support subreg index "
-             << TRI->getSubRegIndexName(SubIdx) << '\n';
-          return;
-        }
-        if (RC != SRC) {
-          report("Invalid register class for subregister index", MO, MONum);
-          OS << "Register class " << TRI->getRegClassName(RC)
-             << " does not fully support subreg index "
-             << TRI->getSubRegIndexName(SubIdx) << '\n';
-          return;
-        }
+      // Validate that SubIdx can be applied to the virtual register.
+      if (!TRI->isSubRegValidForRegClass(RC, SubIdx)) {
+        report("Invalid subregister index for virtual register", MO, MONum);
+        OS << "Register class " << TRI->getRegClassName(RC)
+           << " does not support subreg index "
+           << TRI->getSubRegIndexName(SubIdx) << '\n';
+        return;
       }
       if (MONum < MCID.getNumOperands()) {
         if (const TargetRegisterClass *DRC = TII->getRegClass(MCID, MONum)) {
diff --git a/llvm/lib/CodeGen/PeepholeOptimizer.cpp b/llvm/lib/CodeGen/PeepholeOptimizer.cpp
index 6cb59717c4997..73aecda4e522c 100644
--- a/llvm/lib/CodeGen/PeepholeOptimizer.cpp
+++ b/llvm/lib/CodeGen/PeepholeOptimizer.cpp
@@ -1930,9 +1930,7 @@ ValueTrackerResult ValueTracker::getNextSourceFromCopy() {
     if (SrcReg.isVirtual()) {
       // TODO: Try constraining on rewrite if we can
       const TargetRegisterClass *RegRC = MRI.getRegClass(SrcReg);
-      const TargetRegisterClass *SrcWithSubRC =
-          TRI->getSubClassWithSubReg(RegRC, SubReg);
-      if (RegRC != SrcWithSubRC)
+      if (!TRI->isSubRegValidForRegClass(RegRC, SubReg))
         return ValueTrackerResult();
     } else {
       if (!TRI->getSubReg(SrcReg, SubReg))
@@ -2040,9 +2038,7 @@ ValueTrackerResult ValueTracker::getNextSourceFromRegSequence() {
     //
     // TODO: Should we modify the register class to support the index?
     const TargetRegisterClass *SrcRC = MRI.getRegClass(RegSeqInput.Reg);
-    const TargetRegisterClass *SrcWithSubRC =
-        TRI->getSubClassWithSubReg(SrcRC, ComposedDefInSrcReg1);
-    if (SrcRC != SrcWithSubRC)
+    if (!TRI->isSubRegValidForRegClass(SrcRC, ComposedDefInSrcReg1))
       return ValueTrackerResult();
 
     return ValueTrackerResult(RegSeqInput.Reg, ComposedDefInSrcReg1);
diff --git a/llvm/lib/CodeGen/TargetRegisterInfo.cpp b/llvm/lib/CodeGen/TargetRegisterInfo.cpp
index a56285679929e..7edc94dedb658 100644
--- a/llvm/lib/CodeGen/TargetRegisterInfo.cpp
+++ b/llvm/lib/CodeGen/TargetRegisterInfo.cpp
@@ -555,7 +555,7 @@ bool TargetRegisterInfo::getCoveringSubRegIndexes(
 
   for (unsigned Idx = 1, E = getNumSubRegIndices(); Idx < E; ++Idx) {
     // Is this index even compatible with the given class?
-    if (getSubClassWithSubReg(RC, Idx) != RC)
+    if (!isSubRegValidForRegClass(RC, Idx))
       continue;
     LaneBitmask SubRegMask = getSubRegIndexLaneMask(Idx);
     // Early exit if we found a perfect match.
diff --git a/llvm/lib/Target/AMDGPU/GCNRewritePartialRegUses.cpp b/llvm/lib/Target/AMDGPU/GCNRewritePartialRegUses.cpp
index 237da2d64d4ee..94f82f2915cef 100644
--- a/llvm/lib/Target/AMDGPU/GCNRewritePartialRegUses.cpp
+++ b/llvm/lib/Target/AMDGPU/GCNRewritePartialRegUses.cpp
@@ -268,7 +268,7 @@ GCNRewritePartialRegUsesImpl::getRegClassWithShiftedSubregs(
     assert(MinRC->isAllocatable() && TRI->isRegClassAligned(MinRC, RCAlign));
     for (auto [OldSubReg, NewSubReg] : SubRegs)
       // Check that all registers in MinRC support NewSubReg subregister.
-      assert(MinRC == TRI->getSubClassWithSubReg(MinRC, NewSubReg));
+      assert(TRI->isSubRegValidForRegClass(MinRC, NewSubReg));
   }
 #endif
   // There might be zero RShift - in this case we just trying to find smaller

>From 3f86bda6735c61985133ba6f58f434d6cf617fff Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Sun, 15 Feb 2026 05:54:18 -0800
Subject: [PATCH 2/2] Add verifier helper for RC/DRC/SubIdx combination

---
 .../include/llvm/CodeGen/TargetRegisterInfo.h | 28 +++++++----------
 llvm/lib/CodeGen/MachineVerifier.cpp          | 26 ++++++----------
 llvm/lib/CodeGen/TargetRegisterInfo.cpp       | 31 +++++++++++++++++++
 ...ported-subreg-index-aligned-vgpr-check.mir | 11 +++++++
 4 files changed, 63 insertions(+), 33 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
index 09428c78292ba..d8a632558d29d 100644
--- a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
@@ -667,16 +667,16 @@ class LLVM_ABI TargetRegisterInfo : public MCRegisterInfo {
   /// remove pseudo-registers that should be ignored).
   virtual void adjustStackMapLiveOutMask(uint32_t *Mask) const {}
 
-  /// Return a super-register of the specified register
-  /// Reg so its sub-register of index SubIdx is Reg.
+  /// Return a super-register of the register \p Reg so its sub-register of
+  /// index \p SubIdx is \p Reg.
   MCRegister getMatchingSuperReg(MCRegister Reg, unsigned SubIdx,
                                  const TargetRegisterClass *RC) const {
     return MCRegisterInfo::getMatchingSuperReg(Reg, SubIdx, RC->MC);
   }
 
-  /// Return a subclass of the specified register
-  /// class A so that each register in it has a sub-register of the
-  /// specified sub-register index which is in the specified register class B.
+  /// Return a subclass of the register class \p A so that each register in it
+  /// has a sub-register of the sub-register index \p Idx which is in the
+  /// register class \p B.
   ///
   /// TableGen will synthesize missing A sub-classes.
   virtual const TargetRegisterClass *
@@ -735,19 +735,15 @@ class LLVM_ABI TargetRegisterInfo : public MCRegisterInfo {
     return nullptr;
   }
 
-  /// Returns true if sub-register \p Idx can be used with register class
-  /// \p RC.
+  /// Returns true if sub-register \p Idx can be used with register class \p RC.
   bool isSubRegValidForRegClass(const TargetRegisterClass *RC,
-                                unsigned Idx) const {
-    // NoSubRegister is always valid.
-    if (!Idx)
-      return true;
+                                unsigned Idx) const;
 
-    // `Idx` is valid if the largest subclass of `RC` that supports
-    // sub-register index `Idx` is same as `RC`. That is, every physical
-    // register in `RC` support sub-register index `Idx`.
-    return getSubClassWithSubReg(RC, Idx) == RC;
-  }
+  /// Returns true if sub-register \p Idx can be used with register class \p RC
+  /// and the resulting set of registers is a sub-class of \p DRC.
+  bool isSubRegValidForRegClass(const TargetRegisterClass *RC,
+                                const TargetRegisterClass *DRC,
+                                unsigned Idx) const;
 
   /// Return the subregister index you get from composing
   /// two subregister indices.
diff --git a/llvm/lib/CodeGen/MachineVerifier.cpp b/llvm/lib/CodeGen/MachineVerifier.cpp
index 7f016267f9906..bd33432ccdf82 100644
--- a/llvm/lib/CodeGen/MachineVerifier.cpp
+++ b/llvm/lib/CodeGen/MachineVerifier.cpp
@@ -2810,24 +2810,16 @@ MachineVerifier::visitMachineOperand(const MachineOperand *MO, unsigned MONum) {
       }
       if (MONum < MCID.getNumOperands()) {
         if (const TargetRegisterClass *DRC = TII->getRegClass(MCID, MONum)) {
-          if (SubIdx) {
-            const TargetRegisterClass *SuperRC =
-                TRI->getLargestLegalSuperClass(RC, *MF);
-            if (!SuperRC) {
-              report("No largest legal super class exists.", MO, MONum);
-              return;
-            }
-            DRC = TRI->getMatchingSuperRegClass(SuperRC, DRC, SubIdx);
-            if (!DRC) {
-              report("No matching super-reg register class.", MO, MONum);
-              return;
-            }
-          }
-          if (!RC->hasSuperClassEq(DRC)) {
+          if (!TRI->isSubRegValidForRegClass(RC, DRC, SubIdx)) {
             report("Illegal virtual register for instruction", MO, MONum);
-            OS << "Expected a " << TRI->getRegClassName(DRC)
-               << " register, but got a " << TRI->getRegClassName(RC)
-               << " register\n";
+            const char *DRCName = TRI->getRegClassName(DRC);
+            const char *RCName = TRI->getRegClassName(RC);
+            if (SubIdx)
+              OS << RCName << "." << TRI->getSubRegIndexName(SubIdx)
+                 << " cannot be used for " << DRCName << " operands.";
+            else
+              OS << "Expected a " << DRCName << " register, but got a "
+                 << RCName << " register\n";
           }
         }
       }
diff --git a/llvm/lib/CodeGen/TargetRegisterInfo.cpp b/llvm/lib/CodeGen/TargetRegisterInfo.cpp
index 7edc94dedb658..18933b724ef1d 100644
--- a/llvm/lib/CodeGen/TargetRegisterInfo.cpp
+++ b/llvm/lib/CodeGen/TargetRegisterInfo.cpp
@@ -442,6 +442,37 @@ const TargetRegisterClass *TargetRegisterInfo::findCommonRegClass(
   return getCommonSubClass(DefRC, SrcRC);
 }
 
+bool TargetRegisterInfo::isSubRegValidForRegClass(const TargetRegisterClass *RC,
+                                                  unsigned Idx) const {
+  // NoSubRegister is always valid.
+  if (!Idx)
+    return true;
+
+  // `Idx` is valid if the largest subclass of `RC` that supports
+  // sub-register index `Idx` is same as `RC`. That is, every physical
+  // register in `RC` support sub-register index `Idx`.
+  return getSubClassWithSubReg(RC, Idx) == RC;
+}
+
+bool TargetRegisterInfo::isSubRegValidForRegClass(
+    const TargetRegisterClass *RC, const TargetRegisterClass *DRC,
+    unsigned Idx) const {
+  // If no sub-register index is used, return true if `DRC` is a super-class
+  // of `RC`.
+  if (!Idx)
+    return RC->hasSuperClassEq(DRC);
+
+  // Other, find the largest sub-class of `RC` that can be used with
+  // sub-register `Idx` such that the resulting sub-registers are in register
+  // class `DRC`.
+  const TargetRegisterClass *SuperRC = getMatchingSuperRegClass(RC, DRC, Idx);
+
+  // Return true if this class is same as RC, that is, for all physical
+  // registers in RC, sub-register index `Idx` can be used and the resulting
+  // sub-register is in register class `DRC`.
+  return SuperRC == RC;
+}
+
 float TargetRegisterInfo::getSpillWeightScaleFactor(
     const TargetRegisterClass *RC) const {
   return 1.0;
diff --git a/llvm/test/MachineVerifier/AMDGPU/unsupported-subreg-index-aligned-vgpr-check.mir b/llvm/test/MachineVerifier/AMDGPU/unsupported-subreg-index-aligned-vgpr-check.mir
index be1311cb6b217..59d298056e8e8 100644
--- a/llvm/test/MachineVerifier/AMDGPU/unsupported-subreg-index-aligned-vgpr-check.mir
+++ b/llvm/test/MachineVerifier/AMDGPU/unsupported-subreg-index-aligned-vgpr-check.mir
@@ -36,6 +36,17 @@ body:             |
     ; CHECK-NEXT: Register class VReg_512 does not support subreg index sub16_sub17_sub18_sub19
     S_NOP 0, implicit-def %2:vreg_512
     GLOBAL_STORE_DWORDX4_SADDR %0, %2.sub16_sub17_sub18_sub19, undef $sgpr8_sgpr9, 80, 0, implicit $exec :: (store (s128), addrspace 1)
+
+    ; Test valid subregister index, but invalid effective register class.
+    ; CHECK: *** Bad machine code: Illegal virtual register for instruction ***
+    ; CHECK-NEXT: - function:    uses_invalid_subregister_for_regclass
+    ; CHECK-NEXT: - basic block: %bb.0
+    ; CHECK-NEXT: - instruction: GLOBAL_STORE_DWORDX4_SADDR %0:vgpr_32, %2.sub0:vreg_512, undef $sgpr8_sgpr9, 80, 0, implicit $exec :: (store (s128), addrspace 1)
+    ; CHECK-NEXT: - operand 1:   %2.sub0:vreg_512
+    ; CHECK-NEXT: VReg_512.sub0 cannot be used for AV_128_Align2 operands.
+    %3:sreg_32 = COPY %0
+    GLOBAL_STORE_DWORDX4_SADDR %0, %2.sub0, undef $sgpr8_sgpr9, 80, 0, implicit $exec :: (store (s128), addrspace 1)
+
     S_ENDPGM 0
 
 ...



More information about the llvm-commits mailing list