public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
From: Richard Sandiford <richard.sandiford@arm.com>
To: binutils@sourceware.org
Cc: Richard Sandiford <richard.sandiford@arm.com>
Subject: [PATCH 42/43] aarch64: Add support for strided register lists
Date: Thu, 30 Mar 2023 11:23:58 +0100	[thread overview]
Message-ID: <20230330102359.3327695-43-richard.sandiford@arm.com> (raw)
In-Reply-To: <20230330102359.3327695-1-richard.sandiford@arm.com>

SME2 has instructions that accept strided register lists,
such as { z0.s, z4.s, z8.s, z12.s }.  The purpose of this
patch is to extend binutils to support such lists.

The parsing code already had (unused) support for strides of 2.
The idea here is instead to accept all strides during parsing
and reject invalid strides during constraint checking.

The SME2 instructions that accept strided operands also have
non-strided forms.  The errors about invalid strides therefore
take a bitmask of acceptable strides, which allows multiple
possibilities to be summed up in a single message.

I've tried to update all code that handles register lists.
---
 gas/config/tc-aarch64.c                  | 58 ++++++++++++-------
 gas/testsuite/gas/aarch64/diagnostic.l   |  2 +-
 gas/testsuite/gas/aarch64/illegal-sve2.l | 19 ++++--
 gas/testsuite/gas/aarch64/illegal-sve2.s |  1 +
 include/opcode/aarch64.h                 | 38 ++++++++----
 opcodes/aarch64-dis.c                    |  5 ++
 opcodes/aarch64-opc.c                    | 74 ++++++++++++++++--------
 7 files changed, 135 insertions(+), 62 deletions(-)

diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
index c6cc654095e..0acb3643843 100644
--- a/gas/config/tc-aarch64.c
+++ b/gas/config/tc-aarch64.c
@@ -5065,7 +5065,8 @@ const char* operand_mismatch_kind_names[] =
   "AARCH64_OPDE_SYNTAX_ERROR",
   "AARCH64_OPDE_FATAL_SYNTAX_ERROR",
   "AARCH64_OPDE_INVALID_VARIANT",
-  "AARCH64_OPDE_REG_LIST",
+  "AARCH64_OPDE_REG_LIST_LENGTH",
+  "AARCH64_OPDE_REG_LIST_STRIDE",
   "AARCH64_OPDE_UNTIED_IMMS",
   "AARCH64_OPDE_UNTIED_OPERAND",
   "AARCH64_OPDE_OUT_OF_RANGE",
@@ -5092,10 +5093,11 @@ operand_error_higher_severity_p (enum aarch64_operand_error_kind lhs,
   gas_assert (AARCH64_OPDE_SYNTAX_ERROR > AARCH64_OPDE_EXPECTED_A_AFTER_B);
   gas_assert (AARCH64_OPDE_FATAL_SYNTAX_ERROR > AARCH64_OPDE_SYNTAX_ERROR);
   gas_assert (AARCH64_OPDE_INVALID_VARIANT > AARCH64_OPDE_FATAL_SYNTAX_ERROR);
-  gas_assert (AARCH64_OPDE_REG_LIST > AARCH64_OPDE_INVALID_VARIANT);
-  gas_assert (AARCH64_OPDE_OUT_OF_RANGE > AARCH64_OPDE_REG_LIST);
+  gas_assert (AARCH64_OPDE_REG_LIST_LENGTH > AARCH64_OPDE_INVALID_VARIANT);
+  gas_assert (AARCH64_OPDE_REG_LIST_STRIDE > AARCH64_OPDE_REG_LIST_LENGTH);
+  gas_assert (AARCH64_OPDE_OUT_OF_RANGE > AARCH64_OPDE_REG_LIST_STRIDE);
   gas_assert (AARCH64_OPDE_UNALIGNED > AARCH64_OPDE_OUT_OF_RANGE);
-  gas_assert (AARCH64_OPDE_OTHER_ERROR > AARCH64_OPDE_REG_LIST);
+  gas_assert (AARCH64_OPDE_OTHER_ERROR > AARCH64_OPDE_REG_LIST_STRIDE);
   gas_assert (AARCH64_OPDE_INVALID_REGNO > AARCH64_OPDE_OTHER_ERROR);
   return lhs > rhs;
 }
@@ -5745,7 +5747,7 @@ output_operand_error_record (const operand_error_record *record, char *str)
 		 detail->data[0].i, idx + 1, str);
       break;
 
-    case AARCH64_OPDE_REG_LIST:
+    case AARCH64_OPDE_REG_LIST_LENGTH:
       if (detail->data[0].i == (1 << 1))
 	handler (_("expected a single-register list at operand %d -- `%s'"),
 		 idx + 1, str);
@@ -5757,6 +5759,15 @@ output_operand_error_record (const operand_error_record *record, char *str)
 		   " at operand %d -- `%s'"), idx + 1, str);
       break;
 
+    case AARCH64_OPDE_REG_LIST_STRIDE:
+      if (detail->data[0].i == (1 << 1))
+	handler (_("the register list must have a stride of %d"
+		   " at operand %d -- `%s'"), 1, idx + 1, str);
+      else
+	handler (_("invalid register stride at operand %d -- `%s'"),
+		 idx + 1, str);
+      break;
+
     case AARCH64_OPDE_UNALIGNED:
       handler (_("immediate value must be a multiple of "
 		 "%d at operand %d -- `%s'"),
@@ -5860,7 +5871,8 @@ output_operand_error_report (char *str, bool non_fatal_only)
 		       curr->detail.data[0].i, curr->detail.data[1].i,
 		       curr->detail.data[2].i);
 	}
-      else if (curr->detail.kind == AARCH64_OPDE_REG_LIST)
+      else if (curr->detail.kind == AARCH64_OPDE_REG_LIST_LENGTH
+	       || curr->detail.kind == AARCH64_OPDE_REG_LIST_STRIDE)
 	{
 	  DEBUG_TRACE ("\t%s [%x]",
 		       operand_mismatch_kind_names[curr->detail.kind],
@@ -5908,7 +5920,8 @@ output_operand_error_report (char *str, bool non_fatal_only)
 			   curr->detail.data[0].i, curr->detail.data[1].i,
 			   curr->detail.data[2].i);
 	    }
-	  else if (kind == AARCH64_OPDE_REG_LIST)
+	  else if (kind == AARCH64_OPDE_REG_LIST_LENGTH
+		   || kind == AARCH64_OPDE_REG_LIST_STRIDE)
 	    {
 	      record->detail.data[0].i |= curr->detail.data[0].i;
 	      DEBUG_TRACE ("\t--> %s [%x]",
@@ -6352,33 +6365,40 @@ ldst_lo12_determine_real_reloc_type (void)
 }
 
 /* Check whether a register list REGINFO is valid.  The registers must be
-   numbered in increasing order (modulo 32), in increments of one or two.
+   numbered in increasing order (modulo 32).  They must also have a
+   consistent stride.
 
-   If ACCEPT_ALTERNATE is non-zero, the register numbers should be in
-   increments of two.
-
-   Return FALSE if such a register list is invalid, otherwise return TRUE.  */
+   Return true if the list is valid, describing it in LIST if so.  */
 
 static bool
-reg_list_valid_p (uint32_t reginfo, int accept_alternate)
+reg_list_valid_p (uint32_t reginfo, struct aarch64_reglist *list)
 {
   uint32_t i, nb_regs, prev_regno, incr;
 
   nb_regs = 1 + (reginfo & 0x3);
   reginfo >>= 2;
   prev_regno = reginfo & 0x1f;
-  incr = accept_alternate ? 2 : 1;
+  incr = 1;
+
+  list->first_regno = prev_regno;
+  list->num_regs = nb_regs;
 
   for (i = 1; i < nb_regs; ++i)
     {
-      uint32_t curr_regno;
+      uint32_t curr_regno, curr_incr;
       reginfo >>= 5;
       curr_regno = reginfo & 0x1f;
-      if (curr_regno != ((prev_regno + incr) & 0x1f))
+      curr_incr = (curr_regno - prev_regno) & 0x1f;
+      if (curr_incr == 0)
+	return false;
+      else if (i == 1)
+	incr = curr_incr;
+      else if (curr_incr != incr)
 	return false;
       prev_regno = curr_regno;
     }
 
+  list->stride = incr;
   return true;
 }
 
@@ -6628,6 +6648,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
 		goto failure;
 	      info->reglist.first_regno = reg->number;
 	      info->reglist.num_regs = 1;
+	      info->reglist.stride = 1;
 	    }
 	  else
 	    {
@@ -6635,7 +6656,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
 	      if (val == PARSE_FAIL)
 		goto failure;
 
-	      if (! reg_list_valid_p (val, /* accept_alternate */ 0))
+	      if (! reg_list_valid_p (val, &info->reglist))
 		{
 		  set_fatal_syntax_error (_("invalid register list"));
 		  goto failure;
@@ -6647,9 +6668,6 @@ parse_operands (char *str, const aarch64_opcode *opcode)
 		    (_("expected element type rather than vector type"));
 		  goto failure;
 		}
-
-	      info->reglist.first_regno = (val >> 2) & 0x1f;
-	      info->reglist.num_regs = (val & 0x3) + 1;
 	    }
 	  if (operands[i] == AARCH64_OPND_LEt)
 	    {
diff --git a/gas/testsuite/gas/aarch64/diagnostic.l b/gas/testsuite/gas/aarch64/diagnostic.l
index 6d59564a543..85ec9fe6900 100644
--- a/gas/testsuite/gas/aarch64/diagnostic.l
+++ b/gas/testsuite/gas/aarch64/diagnostic.l
@@ -78,7 +78,7 @@
 [^:]*:80: Error: immediate value out of range 0 to 15 at operand 1 -- `dmb #16'
 [^:]*:81: Error: immediate value out of range 0 to 31 at operand 2 -- `tbz w0,#40,0x17c'
 [^:]*:82: Error: expected a list of 2 registers at operand 1 -- `st2 \{v4.2d,v5.2d,v6.2d\},\[x3\]'
-[^:]*:83: Error: invalid register list at operand 1 -- `ld2 \{v1.4h,v0.4h\},\[x1\]'
+[^:]*:83: Error: the register list must have a stride of 1 at operand 1 -- `ld2 \{v1.4h,v0.4h\},\[x1\]'
 [^:]*:84: Error: the specified option is not accepted in ISB at operand 1 -- `isb osh'
 [^:]*:85: Error: invalid address at operand 2 -- `st2 \{v4.2d,v5.2d,v6.2d\},\\\[x3\\\]'
 [^:]*:86: Error: immediate value must be a multiple of 4 at operand 3 -- `ldnp w7,w15,\[x3,#3\]'
diff --git a/gas/testsuite/gas/aarch64/illegal-sve2.l b/gas/testsuite/gas/aarch64/illegal-sve2.l
index 369c0e6983a..48281fcc4cd 100644
--- a/gas/testsuite/gas/aarch64/illegal-sve2.l
+++ b/gas/testsuite/gas/aarch64/illegal-sve2.l
@@ -239,7 +239,7 @@
 [^ :]+:[0-9]+: Error: expected an SVE vector register at operand 2 -- `eortb z0\.s,z32\.s,z0\.s'
 [^ :]+:[0-9]+: Error: expected an SVE vector register at operand 3 -- `eortb z0\.s,z0\.s,z32\.s'
 [^ :]+:[0-9]+: Error: syntax error in register list at operand 2 -- `ext z0\.b,{,},#0'
-[^ :]+:[0-9]+: Error: invalid register list at operand 2 -- `ext z0\.b,{z0\.b,z2\.b},#0'
+[^ :]+:[0-9]+: Error: the register list must have a stride of 1 at operand 2 -- `ext z0\.b,{z0\.b,z2\.b},#0'
 [^ :]+:[0-9]+: Error: operand mismatch -- `ext z0\.h,{z0\.b,z1\.b},#0'
 [^ :]+:[0-9]+: Info:    did you mean this\?
 [^ :]+:[0-9]+: Info:    	ext z0\.b, {z0\.b, z1\.b}, #0
@@ -251,8 +251,8 @@
 [^ :]+:[0-9]+: Error: expected a list of 2 registers at operand 2 -- `ext z0\.b,{z0\.b,z1\.b,z2\.b},#0'
 [^ :]+:[0-9]+: Error: expected a list of 2 registers at operand 2 -- `ext z0\.b,{z0\.b},#0'
 [^ :]+:[0-9]+: Error: expected an SVE vector register at operand 3 -- `ext z0\.b,z0\.b,#0'
-[^ :]+:[0-9]+: Error: invalid register list at operand 2 -- `ext z0\.b,{z31\.b,z1\.b},#0'
-[^ :]+:[0-9]+: Error: invalid register list at operand 2 -- `ext z0\.b,{z0\.b,z31\.b},#0'
+[^ :]+:[0-9]+: Error: the register list must have a stride of 1 at operand 2 -- `ext z0\.b,{z31\.b,z1\.b},#0'
+[^ :]+:[0-9]+: Error: the register list must have a stride of 1 at operand 2 -- `ext z0\.b,{z0\.b,z31\.b},#0'
 [^ :]+:[0-9]+: Error: immediate value out of range 0 to 255 at operand 3 -- `ext z0\.b,{z0\.b,z1\.b},#256'
 [^ :]+:[0-9]+: Error: expected a vector register at operand 1 -- `ext z32\.b,{z0\.b,z1\.b},#0'
 [^ :]+:[0-9]+: Error: operand 2 must be a list of SVE vector registers -- `ext z0\.b,{z31\.b,z32\.b},#0'
@@ -1277,7 +1277,7 @@
 [^ :]+:[0-9]+: Info:    other valid variant\(s\):
 [^ :]+:[0-9]+: Info:    	smullt z0\.s, z0\.h, z0\.h
 [^ :]+:[0-9]+: Info:    	smullt z0\.d, z0\.s, z0\.s
-[^ :]+:[0-9]+: Error: invalid register list at operand 3 -- `splice z0\.b,p0,{z0\.b,z2\.b}'
+[^ :]+:[0-9]+: Error: the register list must have a stride of 1 at operand 3 -- `splice z0\.b,p0,{z0\.b,z2\.b}'
 [^ :]+:[0-9]+: Error: operand mismatch -- `splice z0\.h,p0,{z0\.b,z1\.b}'
 [^ :]+:[0-9]+: Info:    did you mean this\?
 [^ :]+:[0-9]+: Info:    	splice z0\.b, p0, {z0\.b, z1\.b}
@@ -1289,7 +1289,7 @@
 [^ :]+:[0-9]+: Error: type mismatch in vector register list at operand 3 -- `splice z0\.b,p0,{z0\.b,z1\.h}'
 [^ :]+:[0-9]+: Error: expected an SVE vector register at operand 1 -- `splice z32\.b,p0,{z0\.b,z1\.b}'
 [^ :]+:[0-9]+: Error: p0-p7 expected at operand 2 -- `splice z0\.b,p8,{z0\.b,z1\.b}'
-[^ :]+:[0-9]+: Error: invalid register list at operand 3 -- `splice z0\.b,p0,{z31\.b,z1\.b}'
+[^ :]+:[0-9]+: Error: the register list must have a stride of 1 at operand 3 -- `splice z0\.b,p0,{z31\.b,z1\.b}'
 [^ :]+:[0-9]+: Error: operand 3 must be a list of SVE vector registers -- `splice z0\.b,p0,{z31\.b,z32\.b}'
 [^ :]+:[0-9]+: Error: expected an SVE vector register at operand 3 -- `splice z0\.b,p0,{z32\.b,z1\.b}'
 [^ :]+:[0-9]+: Error: expected a register at operand 1 -- `sqabs z32\.b,p0/m,z0\.b'
@@ -2332,7 +2332,7 @@
 [^ :]+:[0-9]+: Info:    	suqadd z0\.d, p0/m, z0\.d, z0\.d
 [^ :]+:[0-9]+: Error: expected a vector register at operand 1 -- `tbl z32\.b,{z0\.b,z1\.b},z0\.b'
 [^ :]+:[0-9]+: Error: operand 2 must be a list of SVE vector registers -- `tbl z0\.b,{z31\.b,z32\.b},z0\.b'
-[^ :]+:[0-9]+: Error: invalid register list at operand 2 -- `tbl z0\.b,{z31\.b,z1\.b},z0\.b'
+[^ :]+:[0-9]+: Error: the register list must have a stride of 1 at operand 2 -- `tbl z0\.b,{z31\.b,z1\.b},z0\.b'
 [^ :]+:[0-9]+: Error: expected an SVE vector register at operand 3 -- `tbl z0\.b,{z0\.b,z1\.b},z32\.b'
 [^ :]+:[0-9]+: Error: operand mismatch -- `tbl z0\.b,{z0\.b,z1\.b},z0\.h'
 [^ :]+:[0-9]+: Info:    did you mean this\?
@@ -2344,6 +2344,13 @@
 [^ :]+:[0-9]+: Error: type mismatch in vector register list at operand 2 -- `tbl z0\.b,{z0\.b,z1\.h},z0\.b'
 [^ :]+:[0-9]+: Error: type mismatch in vector register list at operand 2 -- `tbl z0\.b,{z0\.h,z0\.b},z0\.b'
 [^ :]+:[0-9]+: Error: invalid register list at operand 2 -- `tbl z0\.h,{z0\.b,z0\.b},z0\.b'
+[^ :]+:[0-9]+: Error: operand mismatch -- `tbl z0\.h,{z0\.b,z1\.b},z0\.b'
+[^ :]+:[0-9]+: Info:    did you mean this\?
+[^ :]+:[0-9]+: Info:    	tbl z0\.b, {z0\.b, z1\.b}, z0\.b
+[^ :]+:[0-9]+: Info:    other valid variant\(s\):
+[^ :]+:[0-9]+: Info:    	tbl z0\.h, {z0\.h, z1\.h}, z0\.h
+[^ :]+:[0-9]+: Info:    	tbl z0\.s, {z0\.s, z1\.s}, z0\.s
+[^ :]+:[0-9]+: Info:    	tbl z0\.d, {z0\.d, z1\.d}, z0\.d
 [^ :]+:[0-9]+: Error: expected a vector register at operand 1 -- `tbx z32\.h,z0\.b,z0\.b'
 [^ :]+:[0-9]+: Error: expected an SVE vector register at operand 2 -- `tbx z0\.h,z32\.b,z0\.b'
 [^ :]+:[0-9]+: Error: expected an SVE vector register at operand 3 -- `tbx z0\.h,z0\.b,z32\.b'
diff --git a/gas/testsuite/gas/aarch64/illegal-sve2.s b/gas/testsuite/gas/aarch64/illegal-sve2.s
index 4b6285c185e..172d0f4b16b 100644
--- a/gas/testsuite/gas/aarch64/illegal-sve2.s
+++ b/gas/testsuite/gas/aarch64/illegal-sve2.s
@@ -1526,6 +1526,7 @@ tbl z0.b, { z0.b, z1.b }, z0.h
 tbl z0.b, { z0.b, z1.h }, z0.b
 tbl z0.b, { z0.h, z0.b }, z0.b
 tbl z0.h, { z0.b, z0.b }, z0.b
+tbl z0.h, { z0.b, z1.b }, z0.b
 
 tbx z32.h, z0.b, z0.b
 tbx z0.h, z32.b, z0.b
diff --git a/include/opcode/aarch64.h b/include/opcode/aarch64.h
index 61afe561a12..ef59d531d17 100644
--- a/include/opcode/aarch64.h
+++ b/include/opcode/aarch64.h
@@ -1122,6 +1122,19 @@ struct aarch64_indexed_za
   unsigned v : 1;	/* <HV> horizontal or vertical vector indicator.  */
 };
 
+/* Information about a list of registers.  */
+struct aarch64_reglist
+{
+  unsigned first_regno : 8;
+  unsigned num_regs : 8;
+  /* The difference between the nth and the n+1th register.  */
+  unsigned stride : 8;
+  /* 1 if it is a list of reg element.  */
+  unsigned has_index : 1;
+  /* Lane index; valid only when has_index is 1.  */
+  int64_t index;
+} reglist;
+
 /* Structure representing an operand.  */
 
 struct aarch64_opnd_info
@@ -1142,15 +1155,7 @@ struct aarch64_opnd_info
 	  int64_t index;
 	} reglane;
       /* e.g. LVn.  */
-      struct
-	{
-	  unsigned first_regno : 5;
-	  unsigned num_regs : 3;
-	  /* 1 if it is a list of reg element.  */
-	  unsigned has_index : 1;
-	  /* Lane index; valid only when has_index is 1.  */
-	  int64_t index;
-	} reglist;
+      struct aarch64_reglist reglist;
       /* e.g. immediate or pc relative address offset.  */
       struct
 	{
@@ -1288,11 +1293,19 @@ struct aarch64_inst
    The following errors are only reported against an asm string that is
    syntactically valid and that has valid operand qualifiers.
 
-   AARCH64_OPDE_REG_LIST
-     Error about the register list operand having an unexpected number of
+   AARCH64_OPDE_REG_LIST_LENGTH
+     Error about a register list operand having an unexpected number of
      registers.  This error is low severity because there might be another
      opcode entry that supports the given number of registers.
 
+   AARCH64_OPDE_REG_LIST_STRIDE
+     Error about a register list operand having the correct number
+     (and type) of registers, but an unexpected stride.  This error is
+     more severe than AARCH64_OPDE_REG_LIST_LENGTH because it implies
+     that the length is known to be correct.  However, it is lower than
+     many other errors, since some instructions have forms that share
+     the same number of registers but have different strides.
+
    AARCH64_OPDE_UNTIED_IMMS
      The asm failed to use the same immediate for a destination operand
      and a tied source operand.
@@ -1342,7 +1355,8 @@ enum aarch64_operand_error_kind
   AARCH64_OPDE_SYNTAX_ERROR,
   AARCH64_OPDE_FATAL_SYNTAX_ERROR,
   AARCH64_OPDE_INVALID_VARIANT,
-  AARCH64_OPDE_REG_LIST,
+  AARCH64_OPDE_REG_LIST_LENGTH,
+  AARCH64_OPDE_REG_LIST_STRIDE,
   AARCH64_OPDE_UNTIED_IMMS,
   AARCH64_OPDE_UNTIED_OPERAND,
   AARCH64_OPDE_OUT_OF_RANGE,
diff --git a/opcodes/aarch64-dis.c b/opcodes/aarch64-dis.c
index 05e285fac99..e722514053e 100644
--- a/opcodes/aarch64-dis.c
+++ b/opcodes/aarch64-dis.c
@@ -439,6 +439,7 @@ aarch64_ext_reglist (const aarch64_operand *self, aarch64_opnd_info *info,
   info->reglist.first_regno = extract_field (self->fields[0], code, 0);
   /* len */
   info->reglist.num_regs = extract_field (FLD_len, code, 0) + 1;
+  info->reglist.stride = 1;
   return true;
 }
 
@@ -482,6 +483,7 @@ aarch64_ext_ldst_reglist (const aarch64_operand *self ATTRIBUTE_UNUSED,
   if (expected_num != data[value].num_elements || data[value].is_reserved)
     return false;
   info->reglist.num_regs = data[value].num_regs;
+  info->reglist.stride = 1;
 
   return true;
 }
@@ -510,6 +512,7 @@ aarch64_ext_ldst_reglist_r (const aarch64_operand *self ATTRIBUTE_UNUSED,
   if (info->reglist.num_regs == 1 && value == (aarch64_insn) 1)
     info->reglist.num_regs = 2;
 
+  info->reglist.stride = 1;
   return true;
 }
 
@@ -573,6 +576,7 @@ aarch64_ext_ldst_elemlist (const aarch64_operand *self ATTRIBUTE_UNUSED,
 
   info->reglist.has_index = 1;
   info->reglist.num_regs = 0;
+  info->reglist.stride = 1;
   /* Number of registers is equal to the number of elements in
      each structure to be loaded/stored.  */
   info->reglist.num_regs = get_opcode_dependent_value (inst->opcode);
@@ -1982,6 +1986,7 @@ aarch64_ext_sve_reglist (const aarch64_operand *self,
 {
   info->reglist.first_regno = extract_field (self->fields[0], code, 0);
   info->reglist.num_regs = get_opcode_dependent_value (inst->opcode);
+  info->reglist.stride = 1;
   return true;
 }
 
diff --git a/opcodes/aarch64-opc.c b/opcodes/aarch64-opc.c
index 8a9e51faebd..4e950cf70f8 100644
--- a/opcodes/aarch64-opc.c
+++ b/opcodes/aarch64-opc.c
@@ -1439,12 +1439,22 @@ set_unaligned_error (aarch64_operand_error *mismatch_detail, int idx,
 }
 
 static inline void
-set_reg_list_error (aarch64_operand_error *mismatch_detail, int idx,
-		    int expected_num)
+set_reg_list_length_error (aarch64_operand_error *mismatch_detail, int idx,
+			   int expected_num)
 {
   if (mismatch_detail == NULL)
     return;
-  set_error (mismatch_detail, AARCH64_OPDE_REG_LIST, idx, NULL);
+  set_error (mismatch_detail, AARCH64_OPDE_REG_LIST_LENGTH, idx, NULL);
+  mismatch_detail->data[0].i = 1 << expected_num;
+}
+
+static inline void
+set_reg_list_stride_error (aarch64_operand_error *mismatch_detail, int idx,
+			   int expected_num)
+{
+  if (mismatch_detail == NULL)
+    return;
+  set_error (mismatch_detail, AARCH64_OPDE_REG_LIST_STRIDE, idx, NULL);
   mismatch_detail->data[0].i = 1 << expected_num;
 }
 
@@ -1482,6 +1492,27 @@ check_reglane (const aarch64_opnd_info *opnd,
   return true;
 }
 
+/* Check that register list operand OPND has NUM_REGS registers and a
+   register stride of STRIDE.  */
+
+static bool
+check_reglist (const aarch64_opnd_info *opnd,
+	       aarch64_operand_error *mismatch_detail, int idx,
+	       int num_regs, int stride)
+{
+  if (opnd->reglist.num_regs != num_regs)
+    {
+      set_reg_list_length_error (mismatch_detail, idx, num_regs);
+      return false;
+    }
+  if (opnd->reglist.stride != stride)
+    {
+      set_reg_list_stride_error (mismatch_detail, idx, stride);
+      return false;
+    }
+  return true;
+}
+
 /* Check that indexed ZA operand OPND has:
 
    - a selection register in the range [MIN_WREG, MIN_WREG + 3]
@@ -1637,11 +1668,8 @@ operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx,
 
     case AARCH64_OPND_CLASS_SVE_REGLIST:
       num = get_opcode_dependent_value (opcode);
-      if (opnd->reglist.num_regs != num)
-	{
-	  set_reg_list_error (mismatch_detail, idx, num);
-	  return 0;
-	}
+      if (!check_reglist (opnd, mismatch_detail, idx, num, 1))
+	return 0;
       break;
 
     case AARCH64_OPND_CLASS_ZA_ACCESS:
@@ -2123,26 +2151,25 @@ operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx,
 	  assert (num >= 1 && num <= 4);
 	  /* Unless LD1/ST1, the number of registers should be equal to that
 	     of the structure elements.  */
-	  if (num != 1 && opnd->reglist.num_regs != num)
-	    {
-	      set_reg_list_error (mismatch_detail, idx, num);
-	      return 0;
-	    }
+	  if (num != 1 && !check_reglist (opnd, mismatch_detail, idx, num, 1))
+	    return 0;
 	  break;
 	case AARCH64_OPND_LVt_AL:
 	case AARCH64_OPND_LEt:
 	  assert (num >= 1 && num <= 4);
 	  /* The number of registers should be equal to that of the structure
 	     elements.  */
-	  if (opnd->reglist.num_regs != num)
-	    {
-	      set_reg_list_error (mismatch_detail, idx, num);
-	      return 0;
-	    }
+	  if (!check_reglist (opnd, mismatch_detail, idx, num, 1))
+	    return 0;
 	  break;
 	default:
 	  break;
 	}
+      if (opnd->reglist.stride != 1)
+	{
+	  set_reg_list_stride_error (mismatch_detail, idx, 1);
+	  return 0;
+	}
       break;
 
     case AARCH64_OPND_CLASS_IMMEDIATE:
@@ -3199,8 +3226,9 @@ print_register_list (char *buf, size_t size, const aarch64_opnd_info *opnd,
 		     const char *prefix, struct aarch64_styler *styler)
 {
   const int num_regs = opnd->reglist.num_regs;
+  const int stride = opnd->reglist.stride;
   const int first_reg = opnd->reglist.first_regno;
-  const int last_reg = (first_reg + num_regs - 1) & 0x1f;
+  const int last_reg = (first_reg + (num_regs - 1) * stride) & 0x1f;
   const char *qlf_name = aarch64_get_qualifier_name (opnd->qualifier);
   char tb[16];	/* Temporary buffer.  */
 
@@ -3218,16 +3246,16 @@ print_register_list (char *buf, size_t size, const aarch64_opnd_info *opnd,
   /* The hyphenated form is preferred for disassembly if there are
      more than two registers in the list, and the register numbers
      are monotonically increasing in increments of one.  */
-  if (num_regs > 2 && last_reg > first_reg)
+  if (stride == 1 && num_regs > 2 && last_reg > first_reg)
     snprintf (buf, size, "{%s-%s}%s",
 	      style_reg (styler, "%s%d.%s", prefix, first_reg, qlf_name),
 	      style_reg (styler, "%s%d.%s", prefix, last_reg, qlf_name), tb);
   else
     {
       const int reg0 = first_reg;
-      const int reg1 = (first_reg + 1) & 0x1f;
-      const int reg2 = (first_reg + 2) & 0x1f;
-      const int reg3 = (first_reg + 3) & 0x1f;
+      const int reg1 = (first_reg + stride) & 0x1f;
+      const int reg2 = (first_reg + stride * 2) & 0x1f;
+      const int reg3 = (first_reg + stride * 3) & 0x1f;
 
       switch (num_regs)
 	{
-- 
2.25.1


  parent reply	other threads:[~2023-03-30 10:24 UTC|newest]

Thread overview: 46+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-03-30 10:23 [PATCH 00/43] aarch64: Groundwork for SME2 support Richard Sandiford
2023-03-30 10:23 ` [PATCH 01/43] aarch64: Fix PSEL opcode mask Richard Sandiford
2023-03-30 10:23 ` [PATCH 02/43] aarch64: Restrict range of PRFM opcodes Richard Sandiford
2023-03-30 10:23 ` [PATCH 03/43] aarch64: Fix SVE2 register/immediate distinction Richard Sandiford
2023-03-30 10:23 ` [PATCH 04/43] aarch64: Make SME instructions use F_STRICT Richard Sandiford
2023-03-30 10:23 ` [PATCH 05/43] aarch64: Use aarch64_operand_error more widely Richard Sandiford
2023-03-30 10:23 ` [PATCH 06/43] aarch64: Rename REG_TYPE_ZA* to REG_TYPE_ZAT* Richard Sandiford
2023-03-30 10:23 ` [PATCH 07/43] aarch64: Add REG_TYPE_ZATHV Richard Sandiford
2023-03-30 10:23 ` [PATCH 08/43] aarch64: Move vectype_to_qualifier further up Richard Sandiford
2023-03-30 10:23 ` [PATCH 09/43] aarch64: Rework parse_typed_reg interface Richard Sandiford
2023-03-30 10:23 ` [PATCH 10/43] aarch64: Reuse parse_typed_reg for ZA tiles Richard Sandiford
2023-03-30 10:23 ` [PATCH 11/43] aarch64: Consolidate ZA tile range checks Richard Sandiford
2023-03-30 10:23 ` [PATCH 12/43] aarch64: Treat ZA as a register Richard Sandiford
2023-03-30 10:23 ` [PATCH 13/43] aarch64: Rename za_tile_vector to za_index Richard Sandiford
2023-03-30 10:23 ` [PATCH 14/43] aarch64: Make indexed_za use 64-bit immediates Richard Sandiford
2023-03-30 10:23 ` [PATCH 15/43] aarch64: Pass aarch64_indexed_za to parsers Richard Sandiford
2023-03-30 10:23 ` [PATCH 16/43] aarch64: Move ZA range checks to aarch64-opc.c Richard Sandiford
2023-03-30 10:23 ` [PATCH 17/43] aarch64: Consolidate ZA slice parsing Richard Sandiford
2023-03-30 10:23 ` [PATCH 18/43] aarch64: Commonise index parsing Richard Sandiford
2023-03-30 10:23 ` [PATCH 19/43] aarch64: Move w12-w15 range check to libopcodes Richard Sandiford
2023-03-30 10:23 ` [PATCH 20/43] aarch64: Tweak error for missing immediate offset Richard Sandiford
2023-03-30 10:23 ` [PATCH 21/43] aarch64: Tweak errors for base & offset registers Richard Sandiford
2023-03-30 10:23 ` [PATCH 22/43] aarch64: Tweak parsing of integer & FP registers Richard Sandiford
2023-03-30 10:23 ` [PATCH 23/43] aarch64: Improve errors for malformed register lists Richard Sandiford
2023-03-30 10:23 ` [PATCH 24/43] aarch64: Try to avoid inappropriate default errors Richard Sandiford
2023-03-30 10:23 ` [PATCH 25/43] aarch64: Rework reporting of failed register checks Richard Sandiford
2023-03-30 10:23 ` [PATCH 26/43] aarch64: Update operand_mismatch_kind_names Richard Sandiford
2023-03-30 10:23 ` [PATCH 27/43] aarch64: Deprioritise AARCH64_OPDE_REG_LIST Richard Sandiford
2023-03-30 10:23 ` [PATCH 28/43] aarch64: Add an error code for out-of-range registers Richard Sandiford
2023-03-30 10:23 ` [PATCH 29/43] aarch64: Commonise checks for index operands Richard Sandiford
2023-03-30 10:23 ` [PATCH 30/43] aarch64: Add an operand class for SVE register lists Richard Sandiford
2023-03-30 10:23 ` [PATCH 31/43] aarch64: Make AARCH64_OPDE_REG_LIST take a bitfield Richard Sandiford
2023-03-30 10:23 ` [PATCH 32/43] aarch64: Tweak register list errors Richard Sandiford
2023-03-30 10:23 ` [PATCH 33/43] aarch64: Try to report invalid variants against the closest match Richard Sandiford
2023-03-30 10:23 ` [PATCH 34/43] aarch64: Tweak priorities of parsing-related errors Richard Sandiford
2023-03-30 10:23 ` [PATCH 35/43] aarch64: Rename aarch64-tbl.h OP_SME_* macros Richard Sandiford
2023-03-30 10:23 ` [PATCH 36/43] aarch64: Reorder some OP_SVE_* macros Richard Sandiford
2023-03-30 10:23 ` [PATCH 37/43] aarch64: Add a aarch64_cpu_supports_inst_p helper Richard Sandiford
2023-03-30 10:23 ` [PATCH 38/43] aarch64: Rename some of GAS's REG_TYPE_* macros Richard Sandiford
2023-03-30 10:23 ` [PATCH 39/43] aarch64: Regularise FLD_* suffixes Richard Sandiford
2023-03-30 10:23 ` [PATCH 40/43] aarch64: Resync field names Richard Sandiford
2023-03-30 10:23 ` [PATCH 41/43] aarch64: Sort fields alphanumerically Richard Sandiford
2023-03-30 10:23 ` Richard Sandiford [this message]
2023-03-30 15:50   ` [PATCH 42/43] aarch64: Add support for strided register lists Simon Marchi
2023-03-30 16:06     ` Richard Sandiford
2023-03-30 10:23 ` [PATCH 43/43] aarch64: Prefer register ranges & support wrapping Richard Sandiford

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230330102359.3327695-43-richard.sandiford@arm.com \
    --to=richard.sandiford@arm.com \
    --cc=binutils@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).