[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