[llvm] [AArch64] Verify consecutive vector registers in tbl, tbx (PR #120262)

Guy David via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 17 08:24:53 PST 2024


https://github.com/guy-david created https://github.com/llvm/llvm-project/pull/120262

Table lookup instructions expect the vectors that define the table itself to be consecutive (wraparound allowed).
Relevant documentation:
https://developer.arm.com/documentation/100069/0606/SIMD-Vector-Instructions/TBL--vector-

>From ea5fe7caf7be22bf27aff13eb3a4c8a25849a741 Mon Sep 17 00:00:00 2001
From: Guy David <guyda96 at gmail.com>
Date: Tue, 17 Dec 2024 18:10:55 +0200
Subject: [PATCH] [AArch64] Verify consecutive vector registers in tbl, tbx

---
 .../lib/Target/AArch64/AArch64InstrFormats.td | 32 +++++++++----------
 .../lib/Target/AArch64/AArch64RegisterInfo.td | 13 +++++++-
 .../AArch64/AsmParser/AArch64AsmParser.cpp    |  8 +++--
 llvm/test/MC/AArch64/neon-diagnostics.s       |  8 +++++
 4 files changed, 41 insertions(+), 20 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
index 56ff7b0d3a280d..47c4c6c39565f4 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
@@ -8528,28 +8528,28 @@ multiclass SIMDTableLookup<bit op, string asm> {
 
   def : SIMDTableLookupAlias<asm # ".8b",
                          !cast<Instruction>(NAME#"v8i8One"),
-                         V64, VecListOne128>;
+                         V64, VecListOneConsecutive128>;
   def : SIMDTableLookupAlias<asm # ".8b",
                          !cast<Instruction>(NAME#"v8i8Two"),
-                         V64, VecListTwo128>;
+                         V64, VecListTwoConsecutive128>;
   def : SIMDTableLookupAlias<asm # ".8b",
                          !cast<Instruction>(NAME#"v8i8Three"),
-                         V64, VecListThree128>;
+                         V64, VecListThreeConsecutive128>;
   def : SIMDTableLookupAlias<asm # ".8b",
                          !cast<Instruction>(NAME#"v8i8Four"),
-                         V64, VecListFour128>;
+                         V64, VecListFourConsecutive128>;
   def : SIMDTableLookupAlias<asm # ".16b",
                          !cast<Instruction>(NAME#"v16i8One"),
-                         V128, VecListOne128>;
+                         V128, VecListOneConsecutive128>;
   def : SIMDTableLookupAlias<asm # ".16b",
                          !cast<Instruction>(NAME#"v16i8Two"),
-                         V128, VecListTwo128>;
+                         V128, VecListTwoConsecutive128>;
   def : SIMDTableLookupAlias<asm # ".16b",
                          !cast<Instruction>(NAME#"v16i8Three"),
-                         V128, VecListThree128>;
+                         V128, VecListThreeConsecutive128>;
   def : SIMDTableLookupAlias<asm # ".16b",
                          !cast<Instruction>(NAME#"v16i8Four"),
-                         V128, VecListFour128>;
+                         V128, VecListFourConsecutive128>;
 }
 
 multiclass SIMDTableLookupTied<bit op, string asm> {
@@ -8572,28 +8572,28 @@ multiclass SIMDTableLookupTied<bit op, string asm> {
 
   def : SIMDTableLookupAlias<asm # ".8b",
                          !cast<Instruction>(NAME#"v8i8One"),
-                         V64, VecListOne128>;
+                         V64, VecListOneConsecutive128>;
   def : SIMDTableLookupAlias<asm # ".8b",
                          !cast<Instruction>(NAME#"v8i8Two"),
-                         V64, VecListTwo128>;
+                         V64, VecListTwoConsecutive128>;
   def : SIMDTableLookupAlias<asm # ".8b",
                          !cast<Instruction>(NAME#"v8i8Three"),
-                         V64, VecListThree128>;
+                         V64, VecListThreeConsecutive128>;
   def : SIMDTableLookupAlias<asm # ".8b",
                          !cast<Instruction>(NAME#"v8i8Four"),
-                         V64, VecListFour128>;
+                         V64, VecListFourConsecutive128>;
   def : SIMDTableLookupAlias<asm # ".16b",
                          !cast<Instruction>(NAME#"v16i8One"),
-                         V128, VecListOne128>;
+                         V128, VecListOneConsecutive128>;
   def : SIMDTableLookupAlias<asm # ".16b",
                          !cast<Instruction>(NAME#"v16i8Two"),
-                         V128, VecListTwo128>;
+                         V128, VecListTwoConsecutive128>;
   def : SIMDTableLookupAlias<asm # ".16b",
                          !cast<Instruction>(NAME#"v16i8Three"),
-                         V128, VecListThree128>;
+                         V128, VecListThreeConsecutive128>;
   def : SIMDTableLookupAlias<asm # ".16b",
                          !cast<Instruction>(NAME#"v16i8Four"),
-                         V128, VecListFour128>;
+                         V128, VecListFourConsecutive128>;
 }
 
 //----------------------------------------------------------------------------
diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
index 4fec120391f016..dd4f2549929f84 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
@@ -646,7 +646,7 @@ class TypedVecListRegOperand<RegisterClass Reg, int lanes, string eltsize>
                                                    # eltsize # "'>">;
 
 multiclass VectorList<int count, RegisterClass Reg64, RegisterClass Reg128> {
-  // With implicit types (probably on instruction instead). E.g. { v0, v1 }
+  // With implicit types (probably on instruction instead). E.g. { v0, v1 } or {v0, v2, v4}.
   def _64AsmOperand : AsmOperandClass {
     let Name = NAME # "64";
     let PredicateMethod = "isImplicitlyTypedVectorList<RegKind::NeonVector, " # count # ">";
@@ -667,6 +667,17 @@ multiclass VectorList<int count, RegisterClass Reg64, RegisterClass Reg128> {
     let ParserMatchClass = !cast<AsmOperandClass>(NAME # "_128AsmOperand");
   }
 
+  // With implicit types (probably on instruction instead), consecutive registers. E.g. { v0, v1, v2 }
+  def _Consecutive128AsmOperand : AsmOperandClass {
+    let Name = NAME # "Consecutive128";
+    let PredicateMethod = "isImplicitlyTypedVectorList<RegKind::NeonVector, " # count # ", true>";
+    let RenderMethod = "addVectorListOperands<AArch64Operand::VecListIdx_QReg, " # count # ", true>";
+  }
+
+  def "Consecutive128" : RegisterOperand<Reg128, "printImplicitlyTypedVectorList"> {
+    let ParserMatchClass = !cast<AsmOperandClass>(NAME # "_Consecutive128AsmOperand");
+  }
+
   // 64-bit register lists with explicit type.
 
   // { v0.8b, v1.8b }
diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index 93c85ba62f90e2..5cda34dd4dde7e 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -1445,11 +1445,12 @@ class AArch64Operand : public MCParsedAsmOperand {
 
   /// Is this a vector list with the type implicit (presumably attached to the
   /// instruction itself)?
-  template <RegKind VectorKind, unsigned NumRegs>
+  template <RegKind VectorKind, unsigned NumRegs, bool IsConsecutive = false>
   bool isImplicitlyTypedVectorList() const {
     return Kind == k_VectorList && VectorList.Count == NumRegs &&
            VectorList.NumElements == 0 &&
-           VectorList.RegisterKind == VectorKind;
+           VectorList.RegisterKind == VectorKind &&
+           (!IsConsecutive || (VectorList.Stride == 1));
   }
 
   template <RegKind VectorKind, unsigned NumRegs, unsigned NumElements,
@@ -1864,9 +1865,10 @@ class AArch64Operand : public MCParsedAsmOperand {
     VecListIdx_PReg = 3,
   };
 
-  template <VecListIndexType RegTy, unsigned NumRegs>
+  template <VecListIndexType RegTy, unsigned NumRegs, bool IsConsecutive = false>
   void addVectorListOperands(MCInst &Inst, unsigned N) const {
     assert(N == 1 && "Invalid number of operands!");
+    assert((!IsConsecutive || (getVectorListStride() == 1)) && "Expected consecutive registers");
     static const unsigned FirstRegs[][5] = {
       /* DReg */ { AArch64::Q0,
                    AArch64::D0,       AArch64::D0_D1,
diff --git a/llvm/test/MC/AArch64/neon-diagnostics.s b/llvm/test/MC/AArch64/neon-diagnostics.s
index 6863a89bbe189e..8449ebbdef7ef6 100644
--- a/llvm/test/MC/AArch64/neon-diagnostics.s
+++ b/llvm/test/MC/AArch64/neon-diagnostics.s
@@ -6914,6 +6914,7 @@
         tbl v0.8b, {v1.8b, v2.8b, v3.8b}, v2.8b
         tbl v0.8b, {v1.8b, v2.8b, v3.8b, v4.8b}, v2.8b
         tbl v0.8b, {v1.16b, v2.16b, v3.16b, v4.16b, v5.16b}, v2.8b
+        tbl.8b v0, {v2, v4, v6, v8}, v10
 
 // CHECK-ERROR: error: invalid operand for instruction
 // CHECK-ERROR:        tbl v0.8b, {v1.8b}, v2.8b
@@ -6930,12 +6931,16 @@
 // CHECK-ERROR: error: invalid number of vectors
 // CHECK-ERROR:        tbl v0.8b, {v1.16b, v2.16b, v3.16b, v4.16b, v5.16b}, v2.8b
 // CHECK-ERROR:                                                    ^
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-ERROR:        tbl.8b v0, {v2, v4, v6, v8}, v10
+// CHECK-ERROR:                            ^
 
         tbx v0.8b, {v1.8b}, v2.8b
         tbx v0.8b, {v1.8b, v2.8b}, v2.8b
         tbx v0.8b, {v1.8b, v2.8b, v3.8b}, v2.8b
         tbx v0.8b, {v1.8b, v2.8b, v3.8b, v4.8b}, v2.8b
         tbx v0.8b, {v1.16b, v2.16b, v3.16b, v4.16b, v5.16b}, v2.8b
+        tbx.8b v0, {v2, v4, v6, v8}, v10
 
 // CHECK-ERROR: error: invalid operand for instruction
 // CHECK-ERROR:        tbx v0.8b, {v1.8b}, v2.8b
@@ -6952,6 +6957,9 @@
 // CHECK-ERROR: error: invalid number of vectors
 // CHECK-ERROR:        tbx v0.8b, {v1.16b, v2.16b, v3.16b, v4.16b, v5.16b}, v2.8b
 // CHECK-ERROR:                                                    ^
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-ERROR:        tbx.8b v0, {v2, v4, v6, v8}, v10
+// CHECK-ERROR:                            ^
 
 //----------------------------------------------------------------------
 // Scalar Floating-point Convert To Lower Precision Narrow, Rounding To



More information about the llvm-commits mailing list