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

via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 13 04:09:13 PDT 2026


Author: Jonathan Thackray
Date: 2026-07-13T12:09:08+01:00
New Revision: 8cb0e63054ce96860b12d68218eb67c97bc6c378

URL: https://github.com/llvm/llvm-project/commit/8cb0e63054ce96860b12d68218eb67c97bc6c378
DIFF: https://github.com/llvm/llvm-project/commit/8cb0e63054ce96860b12d68218eb67c97bc6c378.diff

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

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

Update tablegen to handle the inferred register-class naming
collision caused by adding the explicit z0-z7 ZPR3 class.

Added: 
    

Modified: 
    llvm/lib/Target/AArch64/AArch64RegisterInfo.td
    llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
    llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
    llvm/lib/Target/AArch64/SMEInstrFormats.td
    llvm/test/MC/AArch64/SME2p3/luti6-diagnostics.s
    llvm/utils/TableGen/Common/CodeGenRegisters.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
index cd94a2590c6d2..b9d851cd3498d 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
@@ -1150,7 +1150,7 @@ class PPRVectorListMul<int ElementWidth, int NumRegs> : PPRVectorList<ElementWid
   let Name = "SVEPredicateListMul" # NumRegs # "x" # ElementWidth;
   let DiagnosticType = "Invalid" # Name;
   let PredicateMethod =
-      "isTypedVectorListMultiple<RegKind::SVEPredicateVector, " # NumRegs # ", 0, "
+      "isTypedVectorListInRegClass<RegKind::SVEPredicateVector, " # NumRegs # ", 0, "
                                                                 # ElementWidth #
                                                                 ", AArch64::PPRMul2RegClassID>";
 }
@@ -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>";
@@ -1365,10 +1370,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_b  : RegisterOperand<ZPR3, "printTypedVectorList<0,'b'>"> {
   let ParserMatchClass = ZPRVectorList<8, 3>;
 }
@@ -1418,64 +1419,72 @@ def ZPR4Mul4 : RegisterClass<"AArch64", [untyped], 128, (add (decimate ZSeqQuads
   let Size = 512;
 }
 
-class ZPRVectorListMul<int ElementWidth, int NumRegs, string RegClassSuffix = "">
+class ZPRVectorListInRegClass<int ElementWidth, int NumRegs,
+                              string RegClassSuffix = "">
   : ZPRVectorList<ElementWidth, NumRegs> {
   let Name = "SVEVectorList" # NumRegs # "x" # ElementWidth # RegClassSuffix;
   let DiagnosticType = "Invalid" # Name;
   let PredicateMethod =
-      "isTypedVectorListMultiple<RegKind::SVEDataVector, "
+      "isTypedVectorListInRegClass<RegKind::SVEDataVector, "
                                  # NumRegs # ", 0, "
                                  # ElementWidth #  ", "
                                  # "AArch64::ZPR" # RegClassSuffix # "RegClassID" # ">";
 }
 
+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>"> {
+    let ParserMatchClass = ZPRVectorListInRegClass<0, 3, "_3b">;
+  }
+}
+
 let EncoderMethod = "EncodeRegMul_MinMax<2, 0, 30>",
     DecoderMethod = "DecodeZPR2Mul2RegisterClass<0, 30>" in {
   def ZZ_mul_r : RegisterOperand<ZPR2Mul2, "printTypedVectorList<0,0>"> {
-    let ParserMatchClass = ZPRVectorListMul<0, 2, "Mul2">;
+    let ParserMatchClass = ZPRVectorListInRegClass<0, 2, "Mul2">;
   }
 
   def ZZ_b_mul_r : RegisterOperand<ZPR2Mul2, "printTypedVectorList<0,'b'>"> {
-    let ParserMatchClass = ZPRVectorListMul<8, 2, "Mul2">;
+    let ParserMatchClass = ZPRVectorListInRegClass<8, 2, "Mul2">;
   }
 
   def ZZ_h_mul_r : RegisterOperand<ZPR2Mul2, "printTypedVectorList<0,'h'>"> {
-    let ParserMatchClass = ZPRVectorListMul<16, 2, "Mul2">;
+    let ParserMatchClass = ZPRVectorListInRegClass<16, 2, "Mul2">;
   }
 
   def ZZ_s_mul_r : RegisterOperand<ZPR2Mul2, "printTypedVectorList<0,'s'>"> {
-    let ParserMatchClass = ZPRVectorListMul<32, 2, "Mul2">;
+    let ParserMatchClass = ZPRVectorListInRegClass<32, 2, "Mul2">;
   }
 
   def ZZ_d_mul_r : RegisterOperand<ZPR2Mul2, "printTypedVectorList<0,'d'>"> {
-    let ParserMatchClass = ZPRVectorListMul<64, 2, "Mul2">;
+    let ParserMatchClass = ZPRVectorListInRegClass<64, 2, "Mul2">;
   }
 
   def ZZ_q_mul_r : RegisterOperand<ZPR2Mul2, "printTypedVectorList<0,'q'>"> {
-    let ParserMatchClass = ZPRVectorListMul<128, 2, "Mul2">;
+    let ParserMatchClass = ZPRVectorListInRegClass<128, 2, "Mul2">;
   }
 } // end let EncoderMethod/DecoderMethod
 
 let EncoderMethod = "EncodeRegMul_MinMax<4, 0, 28>",
     DecoderMethod = "DecodeZPR4Mul4RegisterClass" in {
   def ZZZZ_b_mul_r : RegisterOperand<ZPR4Mul4, "printTypedVectorList<0,'b'>"> {
-    let ParserMatchClass = ZPRVectorListMul<8, 4, "Mul4">;
+    let ParserMatchClass = ZPRVectorListInRegClass<8, 4, "Mul4">;
   }
 
   def ZZZZ_h_mul_r : RegisterOperand<ZPR4Mul4, "printTypedVectorList<0,'h'>"> {
-    let ParserMatchClass = ZPRVectorListMul<16, 4, "Mul4">;
+    let ParserMatchClass = ZPRVectorListInRegClass<16, 4, "Mul4">;
   }
 
   def ZZZZ_s_mul_r : RegisterOperand<ZPR4Mul4, "printTypedVectorList<0,'s'>"> {
-    let ParserMatchClass = ZPRVectorListMul<32, 4, "Mul4">;
+    let ParserMatchClass = ZPRVectorListInRegClass<32, 4, "Mul4">;
   }
 
   def ZZZZ_d_mul_r : RegisterOperand<ZPR4Mul4, "printTypedVectorList<0,'d'>"> {
-    let ParserMatchClass = ZPRVectorListMul<64, 4, "Mul4">;
+    let ParserMatchClass = ZPRVectorListInRegClass<64, 4, "Mul4">;
   }
 
   def ZZZZ_q_mul_r : RegisterOperand<ZPR4Mul4, "printTypedVectorList<0,'q'>"> {
-    let ParserMatchClass = ZPRVectorListMul<128, 4, "Mul4">;
+    let ParserMatchClass = ZPRVectorListInRegClass<128, 4, "Mul4">;
   }
 } // end let EncoderMethod/DecoderMethod
 
@@ -1494,38 +1503,38 @@ def ZPR2Mul2_Hi : RegisterClass<"AArch64", [untyped], 128,
 let EncoderMethod = "EncodeRegMul_MinMax<2, 0, 14>",
     DecoderMethod = "DecodeZPR2Mul2RegisterClass<0, 16>" in {
   def ZZ_b_mul_r_Lo : RegisterOperand<ZPR2Mul2_Lo, "printTypedVectorList<0,'b'>"> {
-    let ParserMatchClass = ZPRVectorListMul<8, 2, "Mul2_Lo">;
+    let ParserMatchClass = ZPRVectorListInRegClass<8, 2, "Mul2_Lo">;
   }
 
   def ZZ_h_mul_r_Lo : RegisterOperand<ZPR2Mul2_Lo, "printTypedVectorList<0,'h'>"> {
-    let ParserMatchClass = ZPRVectorListMul<16, 2, "Mul2_Lo">;
+    let ParserMatchClass = ZPRVectorListInRegClass<16, 2, "Mul2_Lo">;
   }
 
   def ZZ_s_mul_r_Lo : RegisterOperand<ZPR2Mul2_Lo, "printTypedVectorList<0,'s'>"> {
-    let ParserMatchClass = ZPRVectorListMul<32, 2, "Mul2_Lo">;
+    let ParserMatchClass = ZPRVectorListInRegClass<32, 2, "Mul2_Lo">;
   }
 
   def ZZ_d_mul_r_Lo : RegisterOperand<ZPR2Mul2_Lo, "printTypedVectorList<0,'d'>"> {
-    let ParserMatchClass = ZPRVectorListMul<64, 2, "Mul2_Lo">;
+    let ParserMatchClass = ZPRVectorListInRegClass<64, 2, "Mul2_Lo">;
   }
 }
 
 let EncoderMethod = "EncodeRegMul_MinMax<2, 16, 30>",
     DecoderMethod = "DecodeZPR2Mul2RegisterClass<16, 31>" in {
   def ZZ_b_mul_r_Hi : RegisterOperand<ZPR2Mul2_Hi, "printTypedVectorList<0,'b'>"> {
-    let ParserMatchClass = ZPRVectorListMul<8, 2, "Mul2_Hi">;
+    let ParserMatchClass = ZPRVectorListInRegClass<8, 2, "Mul2_Hi">;
   }
 
   def ZZ_h_mul_r_Hi : RegisterOperand<ZPR2Mul2_Hi, "printTypedVectorList<0,'h'>"> {
-    let ParserMatchClass = ZPRVectorListMul<16, 2, "Mul2_Hi">;
+    let ParserMatchClass = ZPRVectorListInRegClass<16, 2, "Mul2_Hi">;
   }
 
   def ZZ_s_mul_r_Hi : RegisterOperand<ZPR2Mul2_Hi, "printTypedVectorList<0,'s'>"> {
-    let ParserMatchClass = ZPRVectorListMul<32, 2, "Mul2_Hi">;
+    let ParserMatchClass = ZPRVectorListInRegClass<32, 2, "Mul2_Hi">;
   }
 
   def ZZ_d_mul_r_Hi : RegisterOperand<ZPR2Mul2_Hi, "printTypedVectorList<0,'d'>"> {
-    let ParserMatchClass = ZPRVectorListMul<64, 2, "Mul2_Hi">;
+    let ParserMatchClass = ZPRVectorListInRegClass<64, 2, "Mul2_Hi">;
   }
  } // end let EncoderMethod/DecoderMethod
 

diff  --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index 55f4aa4c509c9..4bb51c2e21934 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -1442,7 +1442,7 @@ class AArch64Operand : public MCParsedAsmOperand {
 
   template <RegKind VectorKind, unsigned NumRegs, unsigned NumElements,
             unsigned ElementWidth, unsigned RegClass>
-  DiagnosticPredicate isTypedVectorListMultiple() const {
+  DiagnosticPredicate isTypedVectorListInRegClass() const {
     bool Res =
         isTypedVectorList<VectorKind, NumRegs, NumElements, ElementWidth>();
     if (!Res)
@@ -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_InvalidSVEVectorList3x0_3b:
+    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_InvalidSVEVectorList3x0_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..3170ad8c99774 100644
--- a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
+++ b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
@@ -74,15 +74,14 @@ DecodeGPR64x8ClassRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Address,
   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))
+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(AArch64::ZPRRegClassID).getRegister(Reg);
+  MCRegister Register = getAArch64MCRegisterClass(RegClassID).getRegister(Reg);
   Inst.addOperand(MCOperand::createReg(Register));
   return Success;
 }

diff  --git a/llvm/lib/Target/AArch64/SMEInstrFormats.td b/llvm/lib/Target/AArch64/SMEInstrFormats.td
index 968faf46418e8..5a8a357464227 100644
--- a/llvm/lib/Target/AArch64/SMEInstrFormats.td
+++ b/llvm/lib/Target/AArch64/SMEInstrFormats.td
@@ -3955,7 +3955,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_3b:$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 }

diff  --git a/llvm/utils/TableGen/Common/CodeGenRegisters.cpp b/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
index eb6f07d761029..cbbce39e267d9 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 
diff erent inferred classes do not alias through the same
+      // composed name.
       CodeGenSubRegIndex *CompositeSubIdx = SubIdx;
       CodeGenRegisterClass *CompositeSubRC = &SubRC;
       if (CodeGenSubRegIndex *SubSubIdx = SubRC.getInferredFromSubRegIdx()) {
@@ -2578,10 +2581,19 @@ void CodeGenRegBank::inferMatchingSuperRegClass(
         }
       }
 
-      auto [SubSetRC, Inserted] = getOrCreateSubClass(
-          RC, &SubSetVec,
-          RC->getName() + "_with_" + CompositeSubIdx->getName() + "_in_" +
-              CompositeSubRC->getName());
+      std::string Name = RC->getName() + "_with_" + CompositeSubIdx->getName() +
+                         "_in_" + CompositeSubRC->getName();
+
+      const 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);
 
       if (Inserted)
         SubSetRC->setInferredFrom(CompositeSubIdx, CompositeSubRC);


        


More information about the llvm-commits mailing list