[llvm] [AArch64][llvm][tablegen] Restrict luti6 assembly (4 regs, 8-bit) to 0 <= Zn <= 7 (PR #200751)

Jonathan Thackray via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 10 06:02:00 PDT 2026


https://github.com/jthackray updated https://github.com/llvm/llvm-project/pull/200751

>From 3226a44617ef446529a4739cf210d98be024eeb0 Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <jonathan.thackray at arm.com>
Date: Mon, 1 Jun 2026 09:23:59 +0100
Subject: [PATCH 1/6] [AArch64][llvm] Restrict luti6 (4 regs, 8-bit) to 0 <= Zn
 <= 7

The `luti6` instruction (table, four registers, 8-bit) should only
allow `0 <= Zn <= 7`, since there's only 3 bits. It actually allows:
```
   luti6 { z0.b - z3.b }, zt0, { z8 - z10 }
```
which produces a duplicate encoding to the following:
```
   luti6 { z0.b - z3.b }, zt0, { z0 - z2 }
```

Fix tablegen to ensure Zn is only allowed in correct range of 0 to 7.
---
 llvm/lib/Target/AArch64/AArch64RegisterInfo.td    | 15 +++++++++++++++
 .../Target/AArch64/AsmParser/AArch64AsmParser.cpp |  4 ++++
 llvm/lib/Target/AArch64/SMEInstrFormats.td        |  2 +-
 llvm/test/MC/AArch64/SME2p3/luti6-diagnostics.s   |  5 +++++
 4 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
index cd94a2590c6d2..700f798f271d5 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
@@ -1321,6 +1321,17 @@ class ZPRVectorList<int ElementWidth, int NumRegs> : AsmOperandClass {
   let RenderMethod = "addVectorListOperands<AArch64Operand::VecListIdx_ZReg, " # NumRegs # ">";
 }
 
+class ZPRVectorListZ0Z7<int ElementWidth, int NumRegs>
+  : ZPRVectorList<ElementWidth, NumRegs> {
+  let Name = "SVEVectorList" # NumRegs # "x" # ElementWidth # "Z0Z7";
+  let DiagnosticType = "Invalid" # Name;
+  let PredicateMethod =
+      "isTypedVectorListMultiple<RegKind::SVEDataVector, "
+                                 # NumRegs # ", 0, "
+                                 # ElementWidth #  ", "
+                                 # "AArch64::ZPR_3bRegClassID" # ">";
+}
+
 def Z_b  : RegisterOperand<ZPR,  "printTypedVectorList<0,'b'>"> {
   let ParserMatchClass = ZPRVectorList<8, 1>;
 }
@@ -1369,6 +1380,10 @@ def ZZZ_Any  : RegisterOperand<ZPR3, "printTypedVectorList<0,0>"> {
   let ParserMatchClass = ZPRVectorList<0, 3>;
 }
 
+def ZZZ_Any_Z0Z7  : RegisterOperand<ZPR3, "printTypedVectorList<0,0>"> {
+  let ParserMatchClass = ZPRVectorListZ0Z7<0, 3>;
+}
+
 def ZZZ_b  : RegisterOperand<ZPR3, "printTypedVectorList<0,'b'>"> {
   let ParserMatchClass = ZPRVectorList<8, 3>;
 }
diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index 55f4aa4c509c9..33727bf4805b9 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -6412,6 +6412,9 @@ bool AArch64AsmParser::showMatchError(SMLoc Loc, unsigned ErrCode,
     return Error(Loc, "Invalid vector list, expected list with 4 consecutive "
                       "SVE vectors, where the first vector is a multiple of 4 "
                       "and with matching element types");
+  case Match_InvalidSVEVectorList3x0Z0Z7:
+    return Error(Loc, "Invalid vector list, expected list with 3 consecutive "
+                      "SVE vectors starting at z0-z7");
   case Match_InvalidLookupTable:
     return Error(Loc, "Invalid lookup table, expected zt0");
   case Match_InvalidSVEVectorListStrided2x8:
@@ -7029,6 +7032,7 @@ bool AArch64AsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
   case Match_InvalidSVEVectorList2x16Mul2_Hi:
   case Match_InvalidSVEVectorList2x32Mul2_Hi:
   case Match_InvalidSVEVectorList2x64Mul2_Hi:
+  case Match_InvalidSVEVectorList3x0Z0Z7:
   case Match_InvalidSVEVectorListStrided2x8:
   case Match_InvalidSVEVectorListStrided2x16:
   case Match_InvalidSVEVectorListStrided2x32:
diff --git a/llvm/lib/Target/AArch64/SMEInstrFormats.td b/llvm/lib/Target/AArch64/SMEInstrFormats.td
index 13c07c57b8ccb..b39281971a9cb 100644
--- a/llvm/lib/Target/AArch64/SMEInstrFormats.td
+++ b/llvm/lib/Target/AArch64/SMEInstrFormats.td
@@ -3943,7 +3943,7 @@ multiclass sme2_lut_single<string asm, SDPatternOperator intrinsic> {
 //===----------------------------------------------------------------------===//
 // Lookup table read with 6-bit indices (8-bit)
 class sme2_luti6_zt_base<RegisterOperand zd_ty, string asm>
-  : I<(outs zd_ty:$Zd), (ins ZTR:$ZTt, ZZZ_Any:$Zn),
+  : I<(outs zd_ty:$Zd), (ins ZTR:$ZTt, ZZZ_Any_Z0Z7:$Zn),
     asm, "\t$Zd, $ZTt, $Zn", "", []>, Sched<[]> {
   bits<0> ZTt;
   bits<3> Zd;
diff --git a/llvm/test/MC/AArch64/SME2p3/luti6-diagnostics.s b/llvm/test/MC/AArch64/SME2p3/luti6-diagnostics.s
index c25ff664afb73..846c282c4de03 100644
--- a/llvm/test/MC/AArch64/SME2p3/luti6-diagnostics.s
+++ b/llvm/test/MC/AArch64/SME2p3/luti6-diagnostics.s
@@ -117,6 +117,11 @@ luti6 { z0.b - z3.b }, zt0, { z1 - z1 }
 // CHECK-NEXT: luti6 { z0.b - z3.b }, zt0, { z1 - z1 }
 // CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
 
+luti6 { z0.b - z3.b }, zt0, { z8 - z10 }
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: Invalid vector list, expected list with 3 consecutive SVE vectors starting at z0-z7
+// CHECK-NEXT: luti6 { z0.b - z3.b }, zt0, { z8 - z10 }
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
 luti6 { z0.b - z5.b }, zt0, { z7 - z11 }
 // CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid number of vectors
 // CHECK-NEXT: luti6 { z0.b - z5.b }, zt0, { z7 - z11 }

>From 5d2a7c6bb1483a1ffda1d394c5e4706541a20050 Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <jonathan.thackray at arm.com>
Date: Tue, 2 Jun 2026 22:35:38 +0100
Subject: [PATCH 2/6] fixup! Address CR comments

---
 .../lib/Target/AArch64/AArch64RegisterInfo.td | 29 +++++++------------
 1 file changed, 10 insertions(+), 19 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
index 700f798f271d5..1f1578b0007b5 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
@@ -1321,17 +1321,6 @@ class ZPRVectorList<int ElementWidth, int NumRegs> : AsmOperandClass {
   let RenderMethod = "addVectorListOperands<AArch64Operand::VecListIdx_ZReg, " # NumRegs # ">";
 }
 
-class ZPRVectorListZ0Z7<int ElementWidth, int NumRegs>
-  : ZPRVectorList<ElementWidth, NumRegs> {
-  let Name = "SVEVectorList" # NumRegs # "x" # ElementWidth # "Z0Z7";
-  let DiagnosticType = "Invalid" # Name;
-  let PredicateMethod =
-      "isTypedVectorListMultiple<RegKind::SVEDataVector, "
-                                 # NumRegs # ", 0, "
-                                 # ElementWidth #  ", "
-                                 # "AArch64::ZPR_3bRegClassID" # ">";
-}
-
 def Z_b  : RegisterOperand<ZPR,  "printTypedVectorList<0,'b'>"> {
   let ParserMatchClass = ZPRVectorList<8, 1>;
 }
@@ -1376,14 +1365,6 @@ def ZZ_q  : RegisterOperand<ZPR2, "printTypedVectorList<0,'q'>"> {
   let ParserMatchClass = ZPRVectorList<128, 2>;
 }
 
-def ZZZ_Any  : RegisterOperand<ZPR3, "printTypedVectorList<0,0>"> {
-  let ParserMatchClass = ZPRVectorList<0, 3>;
-}
-
-def ZZZ_Any_Z0Z7  : RegisterOperand<ZPR3, "printTypedVectorList<0,0>"> {
-  let ParserMatchClass = ZPRVectorListZ0Z7<0, 3>;
-}
-
 def ZZZ_b  : RegisterOperand<ZPR3, "printTypedVectorList<0,'b'>"> {
   let ParserMatchClass = ZPRVectorList<8, 3>;
 }
@@ -1444,6 +1425,16 @@ class ZPRVectorListMul<int ElementWidth, int NumRegs, string RegClassSuffix = ""
                                  # "AArch64::ZPR" # RegClassSuffix # "RegClassID" # ">";
 }
 
+class ZPRVectorList_3b<int ElementWidth, int NumRegs>
+  : ZPRVectorListMul<ElementWidth, NumRegs, "_3b"> {
+  let Name = "SVEVectorList" # NumRegs # "x" # ElementWidth # "Z0Z7";
+  let DiagnosticType = "Invalid" # Name;
+}
+
+def ZZZ_Any_Z0Z7  : RegisterOperand<ZPR3, "printTypedVectorList<0,0>"> {
+  let ParserMatchClass = ZPRVectorList_3b<0, 3>;
+}
+
 let EncoderMethod = "EncodeRegMul_MinMax<2, 0, 30>",
     DecoderMethod = "DecodeZPR2Mul2RegisterClass<0, 30>" in {
   def ZZ_mul_r : RegisterOperand<ZPR2Mul2, "printTypedVectorList<0,0>"> {

>From 5f93ed5ac69a538d638cca7b0e3fca076145cf7e Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <jonathan.thackray at arm.com>
Date: Wed, 3 Jun 2026 15:08:36 +0100
Subject: [PATCH 3/6] fixup! Address more CR comments

---
 llvm/lib/Target/AArch64/AArch64RegisterInfo.td     | 14 ++++++--------
 .../Target/AArch64/AsmParser/AArch64AsmParser.cpp  |  4 ++--
 llvm/lib/Target/AArch64/SMEInstrFormats.td         |  2 +-
 llvm/utils/TableGen/Common/CodeGenRegisters.cpp    | 11 ++++++++++-
 4 files changed, 19 insertions(+), 12 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
index 1f1578b0007b5..75fe3c4ebe23d 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
@@ -1308,6 +1308,10 @@ def ZPR3  : RegisterClass<"AArch64", [untyped], 128, (add ZSeqTriples)> {
   let Size = 384;
   let DecoderMethod = "DecodeSimpleRegisterClass<AArch64::ZPR3RegClassID, 0, 32>";
 }
+def ZPR3_3b : RegisterClass<"AArch64", [untyped], 128, (add (trunc ZSeqTriples, 8))> {
+  let Size = 384;
+  let DecoderMethod = "DecodeSimpleRegisterClass<AArch64::ZPR3_3bRegClassID, 0, 8>";
+}
 def ZPR4 : RegisterClass<"AArch64", [untyped], 128, (add ZSeqQuads)> {
   let Size = 512;
   let DecoderMethod = "DecodeSimpleRegisterClass<AArch64::ZPR4RegClassID, 0, 32>";
@@ -1425,14 +1429,8 @@ class ZPRVectorListMul<int ElementWidth, int NumRegs, string RegClassSuffix = ""
                                  # "AArch64::ZPR" # RegClassSuffix # "RegClassID" # ">";
 }
 
-class ZPRVectorList_3b<int ElementWidth, int NumRegs>
-  : ZPRVectorListMul<ElementWidth, NumRegs, "_3b"> {
-  let Name = "SVEVectorList" # NumRegs # "x" # ElementWidth # "Z0Z7";
-  let DiagnosticType = "Invalid" # Name;
-}
-
-def ZZZ_Any_Z0Z7  : RegisterOperand<ZPR3, "printTypedVectorList<0,0>"> {
-  let ParserMatchClass = ZPRVectorList_3b<0, 3>;
+def ZZZ_Any_3b  : RegisterOperand<ZPR3_3b, "printTypedVectorList<0,0>"> {
+  let ParserMatchClass = ZPRVectorListMul<0, 3, "_3b">;
 }
 
 let EncoderMethod = "EncodeRegMul_MinMax<2, 0, 30>",
diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index 33727bf4805b9..feea97bcbab39 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -6412,7 +6412,7 @@ bool AArch64AsmParser::showMatchError(SMLoc Loc, unsigned ErrCode,
     return Error(Loc, "Invalid vector list, expected list with 4 consecutive "
                       "SVE vectors, where the first vector is a multiple of 4 "
                       "and with matching element types");
-  case Match_InvalidSVEVectorList3x0Z0Z7:
+  case Match_InvalidSVEVectorList3x0_3b:
     return Error(Loc, "Invalid vector list, expected list with 3 consecutive "
                       "SVE vectors starting at z0-z7");
   case Match_InvalidLookupTable:
@@ -7032,7 +7032,7 @@ bool AArch64AsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
   case Match_InvalidSVEVectorList2x16Mul2_Hi:
   case Match_InvalidSVEVectorList2x32Mul2_Hi:
   case Match_InvalidSVEVectorList2x64Mul2_Hi:
-  case Match_InvalidSVEVectorList3x0Z0Z7:
+  case Match_InvalidSVEVectorList3x0_3b:
   case Match_InvalidSVEVectorListStrided2x8:
   case Match_InvalidSVEVectorListStrided2x16:
   case Match_InvalidSVEVectorListStrided2x32:
diff --git a/llvm/lib/Target/AArch64/SMEInstrFormats.td b/llvm/lib/Target/AArch64/SMEInstrFormats.td
index b39281971a9cb..66af173e616e3 100644
--- a/llvm/lib/Target/AArch64/SMEInstrFormats.td
+++ b/llvm/lib/Target/AArch64/SMEInstrFormats.td
@@ -3943,7 +3943,7 @@ multiclass sme2_lut_single<string asm, SDPatternOperator intrinsic> {
 //===----------------------------------------------------------------------===//
 // Lookup table read with 6-bit indices (8-bit)
 class sme2_luti6_zt_base<RegisterOperand zd_ty, string asm>
-  : I<(outs zd_ty:$Zd), (ins ZTR:$ZTt, ZZZ_Any_Z0Z7:$Zn),
+  : I<(outs zd_ty:$Zd), (ins ZTR:$ZTt, ZZZ_Any_3b:$Zn),
     asm, "\t$Zd, $ZTt, $Zn", "", []>, Sched<[]> {
   bits<0> ZTt;
   bits<3> Zd;
diff --git a/llvm/utils/TableGen/Common/CodeGenRegisters.cpp b/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
index eb6f07d761029..24e75100ec52d 100644
--- a/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
+++ b/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
@@ -1328,8 +1328,17 @@ CodeGenRegBank::getOrCreateSubClass(const CodeGenRegisterClass *RC,
   if (FoundI != Key2RC.end())
     return {FoundI->second, false};
 
+  auto HasRegClassNamed = [&](StringRef Candidate) {
+    return llvm::any_of(RegClasses, [&](const CodeGenRegisterClass &RC) {
+      return RC.getName() == Candidate;
+    });
+  };
+  std::string UniqueName = Name.str();
+  for (unsigned I = 1; HasRegClassNamed(UniqueName); ++I)
+    UniqueName = (Name + "_" + Twine(I)).str();
+
   // Sub-class doesn't exist, create a new one.
-  RegClasses.emplace_back(*this, Name, K);
+  RegClasses.emplace_back(*this, UniqueName, K);
   addToMaps(&RegClasses.back());
   return {&RegClasses.back(), true};
 }

>From de4f258b390ce304ff04584d1cd3e61a50e137a2 Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <jonathan.thackray at arm.com>
Date: Mon, 29 Jun 2026 04:17:07 +0100
Subject: [PATCH 4/6] fixup! implement Carol's suggestion

---
 llvm/lib/Target/AArch64/AArch64RegisterInfo.td  | 11 +++++------
 llvm/utils/TableGen/Common/CodeGenRegisters.cpp | 11 +----------
 2 files changed, 6 insertions(+), 16 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
index 75fe3c4ebe23d..122ce1a8a25b9 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
@@ -1308,10 +1308,6 @@ def ZPR3  : RegisterClass<"AArch64", [untyped], 128, (add ZSeqTriples)> {
   let Size = 384;
   let DecoderMethod = "DecodeSimpleRegisterClass<AArch64::ZPR3RegClassID, 0, 32>";
 }
-def ZPR3_3b : RegisterClass<"AArch64", [untyped], 128, (add (trunc ZSeqTriples, 8))> {
-  let Size = 384;
-  let DecoderMethod = "DecodeSimpleRegisterClass<AArch64::ZPR3_3bRegClassID, 0, 8>";
-}
 def ZPR4 : RegisterClass<"AArch64", [untyped], 128, (add ZSeqQuads)> {
   let Size = 512;
   let DecoderMethod = "DecodeSimpleRegisterClass<AArch64::ZPR4RegClassID, 0, 32>";
@@ -1429,8 +1425,11 @@ class ZPRVectorListMul<int ElementWidth, int NumRegs, string RegClassSuffix = ""
                                  # "AArch64::ZPR" # RegClassSuffix # "RegClassID" # ">";
 }
 
-def ZZZ_Any_3b  : RegisterOperand<ZPR3_3b, "printTypedVectorList<0,0>"> {
-  let ParserMatchClass = ZPRVectorListMul<0, 3, "_3b">;
+let EncoderMethod = "EncodeRegMul_MinMax<1, 0, 7>",
+    DecoderMethod = "DecodeSimpleRegisterClass<AArch64::ZPR3RegClassID, 0, 8>" in {
+  def ZZZ_Any_3b  : RegisterOperand<ZPR3, "printTypedVectorList<0,0>"> {
+    let ParserMatchClass = ZPRVectorListMul<0, 3, "_3b">;
+  }
 }
 
 let EncoderMethod = "EncodeRegMul_MinMax<2, 0, 30>",
diff --git a/llvm/utils/TableGen/Common/CodeGenRegisters.cpp b/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
index 24e75100ec52d..eb6f07d761029 100644
--- a/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
+++ b/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
@@ -1328,17 +1328,8 @@ CodeGenRegBank::getOrCreateSubClass(const CodeGenRegisterClass *RC,
   if (FoundI != Key2RC.end())
     return {FoundI->second, false};
 
-  auto HasRegClassNamed = [&](StringRef Candidate) {
-    return llvm::any_of(RegClasses, [&](const CodeGenRegisterClass &RC) {
-      return RC.getName() == Candidate;
-    });
-  };
-  std::string UniqueName = Name.str();
-  for (unsigned I = 1; HasRegClassNamed(UniqueName); ++I)
-    UniqueName = (Name + "_" + Twine(I)).str();
-
   // Sub-class doesn't exist, create a new one.
-  RegClasses.emplace_back(*this, UniqueName, K);
+  RegClasses.emplace_back(*this, Name, K);
   addToMaps(&RegClasses.back());
   return {&RegClasses.back(), true};
 }

>From 219d634fd8add3539451b0236deb2392fdc36828 Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <jonathan.thackray at arm.com>
Date: Tue, 7 Jul 2026 12:06:29 +0100
Subject: [PATCH 5/6] fixup! Carol's suggestion

---
 .../lib/Target/AArch64/AArch64RegisterInfo.td | 23 ++++++++++++++++---
 .../AArch64/AsmParser/AArch64AsmParser.cpp    | 18 +++++++++++++--
 .../Disassembler/AArch64Disassembler.cpp      | 13 +++++++++++
 .../TableGen/Common/CodeGenRegisters.cpp      | 20 ++++++++++++----
 4 files changed, 65 insertions(+), 9 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
index 122ce1a8a25b9..32557f2512c56 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
@@ -1425,10 +1425,27 @@ class ZPRVectorListMul<int ElementWidth, int NumRegs, string RegClassSuffix = ""
                                  # "AArch64::ZPR" # RegClassSuffix # "RegClassID" # ">";
 }
 
+class ZPRVectorListMinMax<int ElementWidth, int NumRegs, int Min, int Max,
+                          string RegClassSuffix = "">
+  : ZPRVectorList<ElementWidth, NumRegs> {
+  let Name = "SVEVectorList" # NumRegs # "x" # ElementWidth # RegClassSuffix;
+  let DiagnosticType = "Invalid" # Name;
+  let PredicateMethod =
+      "isTypedVectorListMinMax<RegKind::SVEDataVector, "
+                                 # NumRegs # ", 0, "
+                                 # ElementWidth #  ", "
+                                 # Min # ", " # Max # ">";
+}
+
+def ZPR3_3b : RegisterClass<"AArch64", [untyped], 128,
+                            (add (trunc ZSeqTriples, 8))> {
+  let Size = 384;
+}
+
 let EncoderMethod = "EncodeRegMul_MinMax<1, 0, 7>",
-    DecoderMethod = "DecodeSimpleRegisterClass<AArch64::ZPR3RegClassID, 0, 8>" in {
-  def ZZZ_Any_3b  : RegisterOperand<ZPR3, "printTypedVectorList<0,0>"> {
-    let ParserMatchClass = ZPRVectorListMul<0, 3, "_3b">;
+    DecoderMethod = "DecodeMulMinMaxRegisterClass<AArch64::ZPR3_3bRegClassID, 1, 0, 7>" in {
+  def ZZZ_Any_3b : RegisterOperand<ZPR3_3b, "printTypedVectorList<0,0>"> {
+    let ParserMatchClass = ZPRVectorListMinMax<0, 3, 0, 7, "3_3b">;
   }
 }
 
diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index feea97bcbab39..17828b130b29f 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -1252,6 +1252,7 @@ class AArch64Operand : public MCParsedAsmOperand {
     switch (Class) {
     case AArch64::ZPRRegClassID:
     case AArch64::ZPR_3bRegClassID:
+    case AArch64::ZPR3_3bRegClassID:
     case AArch64::ZPR_4bRegClassID:
     case AArch64::ZPRMul2_LoRegClassID:
     case AArch64::ZPRMul2_HiRegClassID:
@@ -1452,6 +1453,19 @@ class AArch64Operand : public MCParsedAsmOperand {
     return DiagnosticPredicate::Match;
   }
 
+  template <RegKind VectorKind, unsigned NumRegs, unsigned NumElements,
+            unsigned ElementWidth, unsigned Min, unsigned Max>
+  DiagnosticPredicate isTypedVectorListMinMax() const {
+    bool Res =
+        isTypedVectorList<VectorKind, NumRegs, NumElements, ElementWidth>();
+    if (!Res)
+      return DiagnosticPredicate::NoMatch;
+    unsigned Reg = Ctx.getRegisterInfo()->getEncodingValue(VectorList.Reg);
+    if (Reg < Min || Reg > Max)
+      return DiagnosticPredicate::NearMatch;
+    return DiagnosticPredicate::Match;
+  }
+
   template <RegKind VectorKind, unsigned NumRegs, unsigned Stride,
             unsigned ElementWidth>
   DiagnosticPredicate isTypedVectorListStrided() const {
@@ -6412,7 +6426,7 @@ bool AArch64AsmParser::showMatchError(SMLoc Loc, unsigned ErrCode,
     return Error(Loc, "Invalid vector list, expected list with 4 consecutive "
                       "SVE vectors, where the first vector is a multiple of 4 "
                       "and with matching element types");
-  case Match_InvalidSVEVectorList3x0_3b:
+  case Match_InvalidSVEVectorList3x03_3b:
     return Error(Loc, "Invalid vector list, expected list with 3 consecutive "
                       "SVE vectors starting at z0-z7");
   case Match_InvalidLookupTable:
@@ -7032,7 +7046,7 @@ bool AArch64AsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
   case Match_InvalidSVEVectorList2x16Mul2_Hi:
   case Match_InvalidSVEVectorList2x32Mul2_Hi:
   case Match_InvalidSVEVectorList2x64Mul2_Hi:
-  case Match_InvalidSVEVectorList3x0_3b:
+  case Match_InvalidSVEVectorList3x03_3b:
   case Match_InvalidSVEVectorListStrided2x8:
   case Match_InvalidSVEVectorListStrided2x16:
   case Match_InvalidSVEVectorListStrided2x32:
diff --git a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
index d98478b385e79..faf046491250d 100644
--- a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
+++ b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
@@ -74,6 +74,19 @@ DecodeGPR64x8ClassRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Address,
   return Success;
 }
 
+template <unsigned RegClassID, unsigned Multiple, unsigned Min, unsigned Max>
+static DecodeStatus
+DecodeMulMinMaxRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Address,
+                             const MCDisassembler *Decoder) {
+  unsigned Reg = (RegNo * Multiple) + Min;
+  if (Reg < Min || Reg > Max || (Reg % Multiple))
+    return Fail;
+  MCRegister Register =
+      getAArch64MCRegisterClass(RegClassID).getRegister(RegNo);
+  Inst.addOperand(MCOperand::createReg(Register));
+  return Success;
+}
+
 template <unsigned Min, unsigned Max>
 static DecodeStatus DecodeZPRMul2_MinMax(MCInst &Inst, unsigned RegNo,
                                          uint64_t Address,
diff --git a/llvm/utils/TableGen/Common/CodeGenRegisters.cpp b/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
index eb6f07d761029..a157a05e9787b 100644
--- a/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
+++ b/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
@@ -2578,10 +2578,22 @@ void CodeGenRegBank::inferMatchingSuperRegClass(
         }
       }
 
-      auto [SubSetRC, Inserted] = getOrCreateSubClass(
-          RC, &SubSetVec,
-          RC->getName() + "_with_" + CompositeSubIdx->getName() + "_in_" +
-              CompositeSubRC->getName());
+      std::string Name =
+          (Twine(RC->getName()) + "_with_" + CompositeSubIdx->getName() +
+           "_in_" + CompositeSubRC->getName())
+              .str();
+
+      auto HasRegClassNamed = [&](StringRef Candidate) {
+        return llvm::any_of(RegClasses, [&](const CodeGenRegisterClass &RC) {
+          return RC.getName() == Candidate;
+        });
+      };
+      if (HasRegClassNamed(Name) && &SubRC != CompositeSubRC)
+        Name = (Twine(RC->getName()) + "_with_" + SubIdx->getName() + "_in_" +
+                SubRC.getName())
+                   .str();
+
+      auto [SubSetRC, Inserted] = getOrCreateSubClass(RC, &SubSetVec, Name);
 
       if (Inserted)
         SubSetRC->setInferredFrom(CompositeSubIdx, CompositeSubRC);

>From 123f03d0d8287742aa451afba068fb3a70df5a39 Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <jonathan.thackray at arm.com>
Date: Fri, 10 Jul 2026 11:51:02 +0100
Subject: [PATCH 6/6] fixup! Address PR comments

---
 .../lib/Target/AArch64/AArch64RegisterInfo.td | 12 ++++-----
 .../Disassembler/AArch64Disassembler.cpp      | 16 +-----------
 .../TableGen/Common/CodeGenRegisters.cpp      | 26 +++++++++----------
 3 files changed, 20 insertions(+), 34 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
index 32557f2512c56..cc004c1f1dfd4 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
@@ -1246,7 +1246,8 @@ def ZPR4b64 : ZPRRegOp<"d", ZPRAsmOp4b64, ElementSizeD, ZPR_4b>;
 class ZPRMul2_MinToMaxRegOp<string Suffix, AsmOperandClass C, int  Min, int Max, ElementSizeEnum  Width, RegisterClass RC>
     : ZPRRegOp<Suffix, C, Width, RC> {
   let EncoderMethod = "EncodeRegMul_MinMax<2," # Min # ", " # Max # ">";
-  let DecoderMethod = "DecodeZPRMul2_MinMax<" # Min # ", " # Max # ">";
+  let DecoderMethod = "DecodeMulMinMaxRegisterClass<AArch64::ZPRRegClassID, "
+                      # "2, " # Min # ", " # Max # ">";
 }
 
 def ZPRMul2AsmOp8_Lo  : ZPRAsmOperand<"VectorB_Lo",  8, "Mul2_Lo">;
@@ -1308,6 +1309,10 @@ def ZPR3  : RegisterClass<"AArch64", [untyped], 128, (add ZSeqTriples)> {
   let Size = 384;
   let DecoderMethod = "DecodeSimpleRegisterClass<AArch64::ZPR3RegClassID, 0, 32>";
 }
+def ZPR3_3b : RegisterClass<"AArch64", [untyped], 128,
+                            (add (trunc ZSeqTriples, 8))> {
+  let Size = 384;
+}
 def ZPR4 : RegisterClass<"AArch64", [untyped], 128, (add ZSeqQuads)> {
   let Size = 512;
   let DecoderMethod = "DecodeSimpleRegisterClass<AArch64::ZPR4RegClassID, 0, 32>";
@@ -1437,11 +1442,6 @@ class ZPRVectorListMinMax<int ElementWidth, int NumRegs, int Min, int Max,
                                  # Min # ", " # Max # ">";
 }
 
-def ZPR3_3b : RegisterClass<"AArch64", [untyped], 128,
-                            (add (trunc ZSeqTriples, 8))> {
-  let Size = 384;
-}
-
 let EncoderMethod = "EncodeRegMul_MinMax<1, 0, 7>",
     DecoderMethod = "DecodeMulMinMaxRegisterClass<AArch64::ZPR3_3bRegClassID, 1, 0, 7>" in {
   def ZZZ_Any_3b : RegisterOperand<ZPR3_3b, "printTypedVectorList<0,0>"> {
diff --git a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
index faf046491250d..3170ad8c99774 100644
--- a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
+++ b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
@@ -81,21 +81,7 @@ DecodeMulMinMaxRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Address,
   unsigned Reg = (RegNo * Multiple) + Min;
   if (Reg < Min || Reg > Max || (Reg % Multiple))
     return Fail;
-  MCRegister Register =
-      getAArch64MCRegisterClass(RegClassID).getRegister(RegNo);
-  Inst.addOperand(MCOperand::createReg(Register));
-  return Success;
-}
-
-template <unsigned Min, unsigned Max>
-static DecodeStatus DecodeZPRMul2_MinMax(MCInst &Inst, unsigned RegNo,
-                                         uint64_t Address,
-                                         const MCDisassembler *Decoder) {
-  unsigned Reg = (RegNo * 2) + Min;
-  if (Reg < Min || Reg > Max || (Reg & 1))
-    return Fail;
-  MCRegister Register =
-      getAArch64MCRegisterClass(AArch64::ZPRRegClassID).getRegister(Reg);
+  MCRegister Register = getAArch64MCRegisterClass(RegClassID).getRegister(Reg);
   Inst.addOperand(MCOperand::createReg(Register));
   return Success;
 }
diff --git a/llvm/utils/TableGen/Common/CodeGenRegisters.cpp b/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
index a157a05e9787b..6ef73a2816042 100644
--- a/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
+++ b/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
@@ -2568,6 +2568,9 @@ void CodeGenRegBank::inferMatchingSuperRegClass(
       // When SubRC is already an inferred class, prefer a name of the form
       // "<RC>_with_<CompositeSubIdx>_in_<SubSubRC>" over a chain of the form
       // "<RC>_with_<SubIdx>_in_<OtherRc>_with_<SubSubIdx>_in_<SubSubRC>".
+      // If that preferred name is already used, fall back to the uncomposed
+      // form so that different inferred classes do not alias through the same
+      // composed name.
       CodeGenSubRegIndex *CompositeSubIdx = SubIdx;
       CodeGenRegisterClass *CompositeSubRC = &SubRC;
       if (CodeGenSubRegIndex *SubSubIdx = SubRC.getInferredFromSubRegIdx()) {
@@ -2578,20 +2581,17 @@ void CodeGenRegBank::inferMatchingSuperRegClass(
         }
       }
 
-      std::string Name =
-          (Twine(RC->getName()) + "_with_" + CompositeSubIdx->getName() +
-           "_in_" + CompositeSubRC->getName())
-              .str();
+      std::string Name = RC->getName() + "_with_" + CompositeSubIdx->getName() +
+                         "_in_" + CompositeSubRC->getName();
 
-      auto HasRegClassNamed = [&](StringRef Candidate) {
-        return llvm::any_of(RegClasses, [&](const CodeGenRegisterClass &RC) {
-          return RC.getName() == Candidate;
-        });
-      };
-      if (HasRegClassNamed(Name) && &SubRC != CompositeSubRC)
-        Name = (Twine(RC->getName()) + "_with_" + SubIdx->getName() + "_in_" +
-                SubRC.getName())
-                   .str();
+      bool HasRegClassNamed =
+          llvm::any_of(RegClasses, [&](const CodeGenRegisterClass &RC) {
+            return RC.getName() == Name;
+          });
+
+      if (HasRegClassNamed)
+        Name = RC->getName() + "_with_" + SubIdx->getName() + "_in_" +
+               SubRC.getName();
 
       auto [SubSetRC, Inserted] = getOrCreateSubClass(RC, &SubSetVec, Name);
 



More information about the llvm-commits mailing list