[AArch64][SVE 25/32] Add support for SVE addressing modes

Richard Sandiford richard.sandiford@arm.com
Fri Sep 16 12:06:00 GMT 2016


"Richard Earnshaw (lists)" <Richard.Earnshaw@arm.com> writes:
> On 23/08/16 10:21, Richard Sandiford wrote:
>> This patch adds most of the new SVE addressing modes and associated
>> operands.  A follow-on patch adds MUL VL, since handling it separately
>> makes the changes easier to read.
>> 
>> The patch also introduces a new "operand-dependent data" field to the
>> operand flags, based closely on the existing one for opcode flags.
>> For SVE this new field needs only 2 bits, but it could be widened
>> in future if necessary.
>> 
>> OK to install?
>> 
>> Thanks,
>> Richard
>> 
>> 
>> include/opcode/
>> 	* aarch64.h (AARCH64_OPND_SVE_ADDR_RI_U6): New aarch64_opnd.
>> 	(AARCH64_OPND_SVE_ADDR_RI_U6x2, AARCH64_OPND_SVE_ADDR_RI_U6x4)
>> 	(AARCH64_OPND_SVE_ADDR_RI_U6x8, AARCH64_OPND_SVE_ADDR_RR)
>> 	(AARCH64_OPND_SVE_ADDR_RR_LSL1, AARCH64_OPND_SVE_ADDR_RR_LSL2)
>> 	(AARCH64_OPND_SVE_ADDR_RR_LSL3, AARCH64_OPND_SVE_ADDR_RX)
>> 	(AARCH64_OPND_SVE_ADDR_RX_LSL1, AARCH64_OPND_SVE_ADDR_RX_LSL2)
>> 	(AARCH64_OPND_SVE_ADDR_RX_LSL3, AARCH64_OPND_SVE_ADDR_RZ)
>> 	(AARCH64_OPND_SVE_ADDR_RZ_LSL1, AARCH64_OPND_SVE_ADDR_RZ_LSL2)
>> 	(AARCH64_OPND_SVE_ADDR_RZ_LSL3, AARCH64_OPND_SVE_ADDR_RZ_XTW_14)
>> 	(AARCH64_OPND_SVE_ADDR_RZ_XTW_22, AARCH64_OPND_SVE_ADDR_RZ_XTW1_14)
>> 	(AARCH64_OPND_SVE_ADDR_RZ_XTW1_22, AARCH64_OPND_SVE_ADDR_RZ_XTW2_14)
>> 	(AARCH64_OPND_SVE_ADDR_RZ_XTW2_22, AARCH64_OPND_SVE_ADDR_RZ_XTW3_14)
>> 	(AARCH64_OPND_SVE_ADDR_RZ_XTW3_22, AARCH64_OPND_SVE_ADDR_ZI_U5)
>> 	(AARCH64_OPND_SVE_ADDR_ZI_U5x2, AARCH64_OPND_SVE_ADDR_ZI_U5x4)
>> 	(AARCH64_OPND_SVE_ADDR_ZI_U5x8, AARCH64_OPND_SVE_ADDR_ZZ_LSL)
>> 	(AARCH64_OPND_SVE_ADDR_ZZ_SXTW, AARCH64_OPND_SVE_ADDR_ZZ_UXTW):
>> 	Likewise.
>> 
>> opcodes/
>> 	* aarch64-tbl.h (AARCH64_OPERANDS): Add entries for the new SVE
>> 	address operands.
>> 	* aarch64-opc.h (FLD_SVE_imm6, FLD_SVE_msz, FLD_SVE_xs_14)
>> 	(FLD_SVE_xs_22): New aarch64_field_kinds.
>> 	(OPD_F_OD_MASK, OPD_F_OD_LSB, OPD_F_NO_ZR): New flags.
>> 	(get_operand_specific_data): New function.
>> 	* aarch64-opc.c (fields): Add entries for FLD_SVE_imm6, FLD_SVE_msz,
>> 	FLD_SVE_xs_14 and FLD_SVE_xs_22.
>> 	(operand_general_constraint_met_p): Handle the new SVE address
>> 	operands.
>> 	(sve_reg): New array.
>> 	(get_addr_sve_reg_name): New function.
>> 	(aarch64_print_operand): Handle the new SVE address operands.
>> 	* aarch64-opc-2.c: Regenerate.
>> 	* aarch64-asm.h (ins_sve_addr_ri_u6, ins_sve_addr_rr_lsl)
>> 	(ins_sve_addr_rz_xtw, ins_sve_addr_zi_u5, ins_sve_addr_zz_lsl)
>> 	(ins_sve_addr_zz_sxtw, ins_sve_addr_zz_uxtw): New inserters.
>> 	* aarch64-asm.c (aarch64_ins_sve_addr_ri_u6): New function.
>> 	(aarch64_ins_sve_addr_rr_lsl): Likewise.
>> 	(aarch64_ins_sve_addr_rz_xtw): Likewise.
>> 	(aarch64_ins_sve_addr_zi_u5): Likewise.
>> 	(aarch64_ins_sve_addr_zz): Likewise.
>> 	(aarch64_ins_sve_addr_zz_lsl): Likewise.
>> 	(aarch64_ins_sve_addr_zz_sxtw): Likewise.
>> 	(aarch64_ins_sve_addr_zz_uxtw): Likewise.
>> 	* aarch64-asm-2.c: Regenerate.
>> 	* aarch64-dis.h (ext_sve_addr_ri_u6, ext_sve_addr_rr_lsl)
>> 	(ext_sve_addr_rz_xtw, ext_sve_addr_zi_u5, ext_sve_addr_zz_lsl)
>> 	(ext_sve_addr_zz_sxtw, ext_sve_addr_zz_uxtw): New extractors.
>> 	* aarch64-dis.c (aarch64_ext_sve_add_reg_imm): New function.
>> 	(aarch64_ext_sve_addr_ri_u6): Likewise.
>> 	(aarch64_ext_sve_addr_rr_lsl): Likewise.
>> 	(aarch64_ext_sve_addr_rz_xtw): Likewise.
>> 	(aarch64_ext_sve_addr_zi_u5): Likewise.
>> 	(aarch64_ext_sve_addr_zz): Likewise.
>> 	(aarch64_ext_sve_addr_zz_lsl): Likewise.
>> 	(aarch64_ext_sve_addr_zz_sxtw): Likewise.
>> 	(aarch64_ext_sve_addr_zz_uxtw): Likewise.
>> 	* aarch64-dis-2.c: Regenerate.
>> 
>> gas/
>> 	* config/tc-aarch64.c (aarch64_addr_reg_parse): New function,
>> 	split out from aarch64_reg_parse_32_64.  Handle Z registers too.
>> 	(aarch64_reg_parse_32_64): Call it.
>> 	(parse_address_main): Add base_qualifier, offset_qualifier
>> 	and accept_sve parameters.  Handle SVE base and offset registers.
>
> Ug!  Another bool parameter.

Here's an updated version, based on the new versions of patches
11 and 12.  It adds register type enums for the registers that
can be used as bases and offsets in SVE instructions (which is
the normal set plus Zn.D and Zn.S).  We can then use register
types instead of boolean parameters to say which registers
are acceptable.

Tested on aarch64-linux-gnu.  OK to install?

Thanks,
Richard


include/opcode/
	* aarch64.h (AARCH64_OPND_SVE_ADDR_RI_U6): New aarch64_opnd.
	(AARCH64_OPND_SVE_ADDR_RI_U6x2, AARCH64_OPND_SVE_ADDR_RI_U6x4)
	(AARCH64_OPND_SVE_ADDR_RI_U6x8, AARCH64_OPND_SVE_ADDR_RR)
	(AARCH64_OPND_SVE_ADDR_RR_LSL1, AARCH64_OPND_SVE_ADDR_RR_LSL2)
	(AARCH64_OPND_SVE_ADDR_RR_LSL3, AARCH64_OPND_SVE_ADDR_RX)
	(AARCH64_OPND_SVE_ADDR_RX_LSL1, AARCH64_OPND_SVE_ADDR_RX_LSL2)
	(AARCH64_OPND_SVE_ADDR_RX_LSL3, AARCH64_OPND_SVE_ADDR_RZ)
	(AARCH64_OPND_SVE_ADDR_RZ_LSL1, AARCH64_OPND_SVE_ADDR_RZ_LSL2)
	(AARCH64_OPND_SVE_ADDR_RZ_LSL3, AARCH64_OPND_SVE_ADDR_RZ_XTW_14)
	(AARCH64_OPND_SVE_ADDR_RZ_XTW_22, AARCH64_OPND_SVE_ADDR_RZ_XTW1_14)
	(AARCH64_OPND_SVE_ADDR_RZ_XTW1_22, AARCH64_OPND_SVE_ADDR_RZ_XTW2_14)
	(AARCH64_OPND_SVE_ADDR_RZ_XTW2_22, AARCH64_OPND_SVE_ADDR_RZ_XTW3_14)
	(AARCH64_OPND_SVE_ADDR_RZ_XTW3_22, AARCH64_OPND_SVE_ADDR_ZI_U5)
	(AARCH64_OPND_SVE_ADDR_ZI_U5x2, AARCH64_OPND_SVE_ADDR_ZI_U5x4)
	(AARCH64_OPND_SVE_ADDR_ZI_U5x8, AARCH64_OPND_SVE_ADDR_ZZ_LSL)
	(AARCH64_OPND_SVE_ADDR_ZZ_SXTW, AARCH64_OPND_SVE_ADDR_ZZ_UXTW):
	Likewise.

opcodes/
	* aarch64-tbl.h (AARCH64_OPERANDS): Add entries for the new SVE
	address operands.
	* aarch64-opc.h (FLD_SVE_imm6, FLD_SVE_msz, FLD_SVE_xs_14)
	(FLD_SVE_xs_22): New aarch64_field_kinds.
	(OPD_F_OD_MASK, OPD_F_OD_LSB, OPD_F_NO_ZR): New flags.
	(get_operand_specific_data): New function.
	* aarch64-opc.c (fields): Add entries for FLD_SVE_imm6, FLD_SVE_msz,
	FLD_SVE_xs_14 and FLD_SVE_xs_22.
	(operand_general_constraint_met_p): Handle the new SVE address
	operands.
	(sve_reg): New array.
	(get_addr_sve_reg_name): New function.
	(aarch64_print_operand): Handle the new SVE address operands.
	* aarch64-opc-2.c: Regenerate.
	* aarch64-asm.h (ins_sve_addr_ri_u6, ins_sve_addr_rr_lsl)
	(ins_sve_addr_rz_xtw, ins_sve_addr_zi_u5, ins_sve_addr_zz_lsl)
	(ins_sve_addr_zz_sxtw, ins_sve_addr_zz_uxtw): New inserters.
	* aarch64-asm.c (aarch64_ins_sve_addr_ri_u6): New function.
	(aarch64_ins_sve_addr_rr_lsl): Likewise.
	(aarch64_ins_sve_addr_rz_xtw): Likewise.
	(aarch64_ins_sve_addr_zi_u5): Likewise.
	(aarch64_ins_sve_addr_zz): Likewise.
	(aarch64_ins_sve_addr_zz_lsl): Likewise.
	(aarch64_ins_sve_addr_zz_sxtw): Likewise.
	(aarch64_ins_sve_addr_zz_uxtw): Likewise.
	* aarch64-asm-2.c: Regenerate.
	* aarch64-dis.h (ext_sve_addr_ri_u6, ext_sve_addr_rr_lsl)
	(ext_sve_addr_rz_xtw, ext_sve_addr_zi_u5, ext_sve_addr_zz_lsl)
	(ext_sve_addr_zz_sxtw, ext_sve_addr_zz_uxtw): New extractors.
	* aarch64-dis.c (aarch64_ext_sve_add_reg_imm): New function.
	(aarch64_ext_sve_addr_ri_u6): Likewise.
	(aarch64_ext_sve_addr_rr_lsl): Likewise.
	(aarch64_ext_sve_addr_rz_xtw): Likewise.
	(aarch64_ext_sve_addr_zi_u5): Likewise.
	(aarch64_ext_sve_addr_zz): Likewise.
	(aarch64_ext_sve_addr_zz_lsl): Likewise.
	(aarch64_ext_sve_addr_zz_sxtw): Likewise.
	(aarch64_ext_sve_addr_zz_uxtw): Likewise.
	* aarch64-dis-2.c: Regenerate.

gas/
	* config/tc-aarch64.c (REG_TYPE_SVE_BASE, REG_TYPE_SVE_OFFSET): New
	register types.
	(get_reg_expected_msg): Handle them.
	(aarch64_addr_reg_parse): New function, split out from
	aarch64_reg_parse_32_64.  Handle Z registers too.
	(aarch64_reg_parse_32_64): Call it.
	(parse_address_main): Add base_qualifier, offset_qualifier,
	base_type and offset_type parameters.  Handle SVE base and offset
	registers.
	(parse_address): Update call to parse_address_main.
	(parse_sve_address): New function.
	(parse_operands): Parse the new SVE address operands.

diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
index 79ee054..e59333f 100644
--- a/gas/config/tc-aarch64.c
+++ b/gas/config/tc-aarch64.c
@@ -272,9 +272,16 @@ struct reloc_entry
   BASIC_REG_TYPE(PN)	/* p[0-15] */	\
   /* Typecheck: any 64-bit int reg         (inc SP exc XZR).  */	\
   MULTI_REG_TYPE(R64_SP, REG_TYPE(R_64) | REG_TYPE(SP_64))		\
+  /* Typecheck: same, plus SVE registers.  */				\
+  MULTI_REG_TYPE(SVE_BASE, REG_TYPE(R_64) | REG_TYPE(SP_64)		\
+		 | REG_TYPE(ZN))					\
   /* Typecheck: x[0-30], w[0-30] or [xw]zr.  */				\
   MULTI_REG_TYPE(R_Z, REG_TYPE(R_32) | REG_TYPE(R_64)			\
 		 | REG_TYPE(Z_32) | REG_TYPE(Z_64))			\
+  /* Typecheck: same, plus SVE registers.  */				\
+  MULTI_REG_TYPE(SVE_OFFSET, REG_TYPE(R_32) | REG_TYPE(R_64)		\
+		 | REG_TYPE(Z_32) | REG_TYPE(Z_64)			\
+		 | REG_TYPE(ZN))					\
   /* Typecheck: x[0-30], w[0-30] or {w}sp.  */				\
   MULTI_REG_TYPE(R_SP, REG_TYPE(R_32) | REG_TYPE(R_64)			\
 		 | REG_TYPE(SP_32) | REG_TYPE(SP_64))			\
@@ -358,9 +365,15 @@ get_reg_expected_msg (aarch64_reg_type reg_type)
     case REG_TYPE_R64_SP:
       msg = N_("64-bit integer or SP register expected");
       break;
+    case REG_TYPE_SVE_BASE:
+      msg = N_("base register expected");
+      break;
     case REG_TYPE_R_Z:
       msg = N_("integer or zero register expected");
       break;
+    case REG_TYPE_SVE_OFFSET:
+      msg = N_("offset register expected");
+      break;
     case REG_TYPE_R_SP:
       msg = N_("integer or SP register expected");
       break;
@@ -697,14 +710,16 @@ aarch64_check_reg_type (const reg_entry *reg, aarch64_reg_type type)
   return (reg_type_masks[type] & (1 << reg->type)) != 0;
 }
 
-/* Try to parse a base or offset register.  Return the register entry
-   on success, setting *QUALIFIER to the register qualifier.  Return null
-   otherwise.
+/* Try to parse a base or offset register.  Allow SVE base and offset
+   registers if REG_TYPE includes SVE registers.  Return the register
+   entry on success, setting *QUALIFIER to the register qualifier.
+   Return null otherwise.
 
    Note that this function does not issue any diagnostics.  */
 
 static const reg_entry *
-aarch64_reg_parse_32_64 (char **ccp, aarch64_opnd_qualifier_t *qualifier)
+aarch64_addr_reg_parse (char **ccp, aarch64_reg_type reg_type,
+			aarch64_opnd_qualifier_t *qualifier)
 {
   char *str = *ccp;
   const reg_entry *reg = parse_reg (&str);
@@ -726,6 +741,24 @@ aarch64_reg_parse_32_64 (char **ccp, aarch64_opnd_qualifier_t *qualifier)
       *qualifier = AARCH64_OPND_QLF_X;
       break;
 
+    case REG_TYPE_ZN:
+      if ((reg_type_masks[reg_type] & (1 << REG_TYPE_ZN)) == 0
+	  || str[0] != '.')
+	return NULL;
+      switch (TOLOWER (str[1]))
+	{
+	case 's':
+	  *qualifier = AARCH64_OPND_QLF_S_S;
+	  break;
+	case 'd':
+	  *qualifier = AARCH64_OPND_QLF_S_D;
+	  break;
+	default:
+	  return NULL;
+	}
+      str += 2;
+      break;
+
     default:
       return NULL;
     }
@@ -735,6 +768,18 @@ aarch64_reg_parse_32_64 (char **ccp, aarch64_opnd_qualifier_t *qualifier)
   return reg;
 }
 
+/* Try to parse a base or offset register.  Return the register entry
+   on success, setting *QUALIFIER to the register qualifier.  Return null
+   otherwise.
+
+   Note that this function does not issue any diagnostics.  */
+
+static const reg_entry *
+aarch64_reg_parse_32_64 (char **ccp, aarch64_opnd_qualifier_t *qualifier)
+{
+  return aarch64_addr_reg_parse (ccp, REG_TYPE_R_Z_SP, qualifier);
+}
+
 /* Parse the qualifier of a vector register or vector element of type
    REG_TYPE.  Fill in *PARSED_TYPE and return TRUE if the parsing
    succeeds; otherwise return FALSE.
@@ -3209,8 +3254,8 @@ parse_shifter_operand_reloc (char **str, aarch64_opnd_info *operand,
    The A64 instruction set has the following addressing modes:
 
    Offset
-     [base]			// in SIMD ld/st structure
-     [base{,#0}]		// in ld/st exclusive
+     [base]			 // in SIMD ld/st structure
+     [base{,#0}]		 // in ld/st exclusive
      [base{,#imm}]
      [base,Xm{,LSL #imm}]
      [base,Xm,SXTX {#imm}]
@@ -3219,10 +3264,18 @@ parse_shifter_operand_reloc (char **str, aarch64_opnd_info *operand,
      [base,#imm]!
    Post-indexed
      [base],#imm
-     [base],Xm			// in SIMD ld/st structure
+     [base],Xm			 // in SIMD ld/st structure
    PC-relative (literal)
      label
-     =immediate
+   SVE:
+     [base,Zm.D{,LSL #imm}]
+     [base,Zm.S,(S|U)XTW {#imm}]
+     [base,Zm.D,(S|U)XTW {#imm}] // ignores top 32 bits of Zm.D elements
+     [Zn.S,#imm]
+     [Zn.D,#imm]
+     [Zn.S,Zm.S{,LSL #imm}]      // in ADR
+     [Zn.D,Zm.D{,LSL #imm}]      // in ADR
+     [Zn.D,Zm.D,(S|U)XTW {#imm}] // in ADR
 
    (As a convenience, the notation "=immediate" is permitted in conjunction
    with the pc-relative literal load instructions to automatically place an
@@ -3249,19 +3302,27 @@ parse_shifter_operand_reloc (char **str, aarch64_opnd_info *operand,
      .pcrel=1; .preind=1; .postind=0; .writeback=0
 
    The shift/extension information, if any, will be stored in .shifter.
+   The base and offset qualifiers will be stored in *BASE_QUALIFIER and
+   *OFFSET_QUALIFIER respectively, with NIL being used if there's no
+   corresponding register.
 
-   It is the caller's responsibility to check for addressing modes not
+   BASE_TYPE says which types of base register should be accepted and
+   OFFSET_TYPE says the same for offset registers.  In all other respects,
+   it is the caller's responsibility to check for addressing modes not
    supported by the instruction, and to set inst.reloc.type.  */
 
 static bfd_boolean
-parse_address_main (char **str, aarch64_opnd_info *operand)
+parse_address_main (char **str, aarch64_opnd_info *operand,
+		    aarch64_opnd_qualifier_t *base_qualifier,
+		    aarch64_opnd_qualifier_t *offset_qualifier,
+		    aarch64_reg_type base_type, aarch64_reg_type offset_type)
 {
   char *p = *str;
   const reg_entry *reg;
-  aarch64_opnd_qualifier_t base_qualifier;
-  aarch64_opnd_qualifier_t offset_qualifier;
   expressionS *exp = &inst.reloc.exp;
 
+  *base_qualifier = AARCH64_OPND_QLF_NIL;
+  *offset_qualifier = AARCH64_OPND_QLF_NIL;
   if (! skip_past_char (&p, '['))
     {
       /* =immediate or label.  */
@@ -3336,10 +3397,10 @@ parse_address_main (char **str, aarch64_opnd_info *operand)
 
   /* [ */
 
-  reg = aarch64_reg_parse_32_64 (&p, &base_qualifier);
-  if (!reg || !aarch64_check_reg_type (reg, REG_TYPE_R64_SP))
+  reg = aarch64_addr_reg_parse (&p, base_type, base_qualifier);
+  if (!reg || !aarch64_check_reg_type (reg, base_type))
     {
-      set_syntax_error (_(get_reg_expected_msg (REG_TYPE_R64_SP)));
+      set_syntax_error (_(get_reg_expected_msg (base_type)));
       return FALSE;
     }
   operand->addr.base_regno = reg->number;
@@ -3350,12 +3411,12 @@ parse_address_main (char **str, aarch64_opnd_info *operand)
       /* [Xn, */
       operand->addr.preind = 1;
 
-      reg = aarch64_reg_parse_32_64 (&p, &offset_qualifier);
+      reg = aarch64_addr_reg_parse (&p, offset_type, offset_qualifier);
       if (reg)
 	{
-	  if (!aarch64_check_reg_type (reg, REG_TYPE_R_Z))
+	  if (!aarch64_check_reg_type (reg, offset_type))
 	    {
-	      set_syntax_error (_(get_reg_expected_msg (REG_TYPE_R_Z)));
+	      set_syntax_error (_(get_reg_expected_msg (offset_type)));
 	      return FALSE;
 	    }
 
@@ -3379,13 +3440,19 @@ parse_address_main (char **str, aarch64_opnd_info *operand)
 	      || operand->shifter.kind == AARCH64_MOD_LSL
 	      || operand->shifter.kind == AARCH64_MOD_SXTX)
 	    {
-	      if (offset_qualifier == AARCH64_OPND_QLF_W)
+	      if (*offset_qualifier == AARCH64_OPND_QLF_W)
 		{
 		  set_syntax_error (_("invalid use of 32-bit register offset"));
 		  return FALSE;
 		}
+	      if (aarch64_get_qualifier_esize (*base_qualifier)
+		  != aarch64_get_qualifier_esize (*offset_qualifier))
+		{
+		  set_syntax_error (_("offset has different size from base"));
+		  return FALSE;
+		}
 	    }
-	  else if (offset_qualifier == AARCH64_OPND_QLF_X)
+	  else if (*offset_qualifier == AARCH64_OPND_QLF_X)
 	    {
 	      set_syntax_error (_("invalid use of 64-bit register offset"));
 	      return FALSE;
@@ -3468,7 +3535,7 @@ parse_address_main (char **str, aarch64_opnd_info *operand)
 	  return FALSE;
 	}
 
-      reg = aarch64_reg_parse_32_64 (&p, &offset_qualifier);
+      reg = aarch64_reg_parse_32_64 (&p, offset_qualifier);
       if (reg)
 	{
 	  /* [Xn],Xm */
@@ -3513,7 +3580,21 @@ parse_address_main (char **str, aarch64_opnd_info *operand)
 static bfd_boolean
 parse_address (char **str, aarch64_opnd_info *operand)
 {
-  return parse_address_main (str, operand);
+  aarch64_opnd_qualifier_t base_qualifier, offset_qualifier;
+  return parse_address_main (str, operand, &base_qualifier, &offset_qualifier,
+			     REG_TYPE_R64_SP, REG_TYPE_R_Z);
+}
+
+/* Parse an address in which SVE vector registers are allowed.
+   The arguments have the same meaning as for parse_address_main.
+   Return TRUE on success.  */
+static bfd_boolean
+parse_sve_address (char **str, aarch64_opnd_info *operand,
+		   aarch64_opnd_qualifier_t *base_qualifier,
+		   aarch64_opnd_qualifier_t *offset_qualifier)
+{
+  return parse_address_main (str, operand, base_qualifier, offset_qualifier,
+			     REG_TYPE_SVE_BASE, REG_TYPE_SVE_OFFSET);
 }
 
 /* Parse an operand for a MOVZ, MOVN or MOVK instruction.
@@ -5123,7 +5204,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
       int comma_skipped_p = 0;
       aarch64_reg_type rtype;
       struct vector_type_el vectype;
-      aarch64_opnd_qualifier_t qualifier;
+      aarch64_opnd_qualifier_t qualifier, base_qualifier, offset_qualifier;
       aarch64_opnd_info *info = &inst.base.operands[i];
       aarch64_reg_type reg_type;
 
@@ -5757,6 +5838,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
 	case AARCH64_OPND_ADDR_REGOFF:
 	  /* [<Xn|SP>, <R><m>{, <extend> {<amount>}}]  */
 	  po_misc_or_fail (parse_address (&str, info));
+	regoff_addr:
 	  if (info->addr.pcrel || !info->addr.offset.is_reg
 	      || !info->addr.preind || info->addr.postind
 	      || info->addr.writeback)
@@ -5856,6 +5938,123 @@ parse_operands (char *str, const aarch64_opcode *opcode)
 	  /* No qualifier.  */
 	  break;
 
+	case AARCH64_OPND_SVE_ADDR_RI_U6:
+	case AARCH64_OPND_SVE_ADDR_RI_U6x2:
+	case AARCH64_OPND_SVE_ADDR_RI_U6x4:
+	case AARCH64_OPND_SVE_ADDR_RI_U6x8:
+	  /* [X<n>{, #imm}]
+	     but recognizing SVE registers.  */
+	  po_misc_or_fail (parse_sve_address (&str, info, &base_qualifier,
+					      &offset_qualifier));
+	  if (base_qualifier != AARCH64_OPND_QLF_X)
+	    {
+	      set_syntax_error (_("invalid addressing mode"));
+	      goto failure;
+	    }
+	sve_regimm:
+	  if (info->addr.pcrel || info->addr.offset.is_reg
+	      || !info->addr.preind || info->addr.writeback)
+	    {
+	      set_syntax_error (_("invalid addressing mode"));
+	      goto failure;
+	    }
+	  if (inst.reloc.type != BFD_RELOC_UNUSED
+	      || inst.reloc.exp.X_op != O_constant)
+	    {
+	      /* Make sure this has priority over
+		 "invalid addressing mode".  */
+	      set_fatal_syntax_error (_("constant offset required"));
+	      goto failure;
+	    }
+	  info->addr.offset.imm = inst.reloc.exp.X_add_number;
+	  break;
+
+	case AARCH64_OPND_SVE_ADDR_RR:
+	case AARCH64_OPND_SVE_ADDR_RR_LSL1:
+	case AARCH64_OPND_SVE_ADDR_RR_LSL2:
+	case AARCH64_OPND_SVE_ADDR_RR_LSL3:
+	case AARCH64_OPND_SVE_ADDR_RX:
+	case AARCH64_OPND_SVE_ADDR_RX_LSL1:
+	case AARCH64_OPND_SVE_ADDR_RX_LSL2:
+	case AARCH64_OPND_SVE_ADDR_RX_LSL3:
+	  /* [<Xn|SP>, <R><m>{, lsl #<amount>}]
+	     but recognizing SVE registers.  */
+	  po_misc_or_fail (parse_sve_address (&str, info, &base_qualifier,
+					      &offset_qualifier));
+	  if (base_qualifier != AARCH64_OPND_QLF_X
+	      || offset_qualifier != AARCH64_OPND_QLF_X)
+	    {
+	      set_syntax_error (_("invalid addressing mode"));
+	      goto failure;
+	    }
+	  goto regoff_addr;
+
+	case AARCH64_OPND_SVE_ADDR_RZ:
+	case AARCH64_OPND_SVE_ADDR_RZ_LSL1:
+	case AARCH64_OPND_SVE_ADDR_RZ_LSL2:
+	case AARCH64_OPND_SVE_ADDR_RZ_LSL3:
+	case AARCH64_OPND_SVE_ADDR_RZ_XTW_14:
+	case AARCH64_OPND_SVE_ADDR_RZ_XTW_22:
+	case AARCH64_OPND_SVE_ADDR_RZ_XTW1_14:
+	case AARCH64_OPND_SVE_ADDR_RZ_XTW1_22:
+	case AARCH64_OPND_SVE_ADDR_RZ_XTW2_14:
+	case AARCH64_OPND_SVE_ADDR_RZ_XTW2_22:
+	case AARCH64_OPND_SVE_ADDR_RZ_XTW3_14:
+	case AARCH64_OPND_SVE_ADDR_RZ_XTW3_22:
+	  /* [<Xn|SP>, Z<m>.D{, LSL #<amount>}]
+	     [<Xn|SP>, Z<m>.<T>, <extend> {#<amount>}]  */
+	  po_misc_or_fail (parse_sve_address (&str, info, &base_qualifier,
+					      &offset_qualifier));
+	  if (base_qualifier != AARCH64_OPND_QLF_X
+	      || (offset_qualifier != AARCH64_OPND_QLF_S_S
+		  && offset_qualifier != AARCH64_OPND_QLF_S_D))
+	    {
+	      set_syntax_error (_("invalid addressing mode"));
+	      goto failure;
+	    }
+	  info->qualifier = offset_qualifier;
+	  goto regoff_addr;
+
+	case AARCH64_OPND_SVE_ADDR_ZI_U5:
+	case AARCH64_OPND_SVE_ADDR_ZI_U5x2:
+	case AARCH64_OPND_SVE_ADDR_ZI_U5x4:
+	case AARCH64_OPND_SVE_ADDR_ZI_U5x8:
+	  /* [Z<n>.<T>{, #imm}]  */
+	  po_misc_or_fail (parse_sve_address (&str, info, &base_qualifier,
+					      &offset_qualifier));
+	  if (base_qualifier != AARCH64_OPND_QLF_S_S
+	      && base_qualifier != AARCH64_OPND_QLF_S_D)
+	    {
+	      set_syntax_error (_("invalid addressing mode"));
+	      goto failure;
+	    }
+	  info->qualifier = base_qualifier;
+	  goto sve_regimm;
+
+	case AARCH64_OPND_SVE_ADDR_ZZ_LSL:
+	case AARCH64_OPND_SVE_ADDR_ZZ_SXTW:
+	case AARCH64_OPND_SVE_ADDR_ZZ_UXTW:
+	  /* [Z<n>.<T>, Z<m>.<T>{, LSL #<amount>}]
+	     [Z<n>.D, Z<m>.D, <extend> {#<amount>}]
+
+	     We don't reject:
+
+	     [Z<n>.S, Z<m>.S, <extend> {#<amount>}]
+
+	     here since we get better error messages by leaving it to
+	     the qualifier checking routines.  */
+	  po_misc_or_fail (parse_sve_address (&str, info, &base_qualifier,
+					      &offset_qualifier));
+	  if ((base_qualifier != AARCH64_OPND_QLF_S_S
+	       && base_qualifier != AARCH64_OPND_QLF_S_D)
+	      || offset_qualifier != base_qualifier)
+	    {
+	      set_syntax_error (_("invalid addressing mode"));
+	      goto failure;
+	    }
+	  info->qualifier = base_qualifier;
+	  goto regoff_addr;
+
 	case AARCH64_OPND_SYSREG:
 	  if ((val = parse_sys_reg (&str, aarch64_sys_regs_hsh, 1, 0))
 	      == PARSE_FAIL)
diff --git a/include/opcode/aarch64.h b/include/opcode/aarch64.h
index 49b4413..e61ac9c 100644
--- a/include/opcode/aarch64.h
+++ b/include/opcode/aarch64.h
@@ -244,6 +244,45 @@ enum aarch64_opnd
   AARCH64_OPND_PRFOP,		/* Prefetch operation.  */
   AARCH64_OPND_BARRIER_PSB,	/* Barrier operand for PSB.  */
 
+  AARCH64_OPND_SVE_ADDR_RI_U6,	    /* SVE [<Xn|SP>, #<uimm6>].  */
+  AARCH64_OPND_SVE_ADDR_RI_U6x2,    /* SVE [<Xn|SP>, #<uimm6>*2].  */
+  AARCH64_OPND_SVE_ADDR_RI_U6x4,    /* SVE [<Xn|SP>, #<uimm6>*4].  */
+  AARCH64_OPND_SVE_ADDR_RI_U6x8,    /* SVE [<Xn|SP>, #<uimm6>*8].  */
+  AARCH64_OPND_SVE_ADDR_RR,	    /* SVE [<Xn|SP>, <Xm|XZR>].  */
+  AARCH64_OPND_SVE_ADDR_RR_LSL1,    /* SVE [<Xn|SP>, <Xm|XZR>, LSL #1].  */
+  AARCH64_OPND_SVE_ADDR_RR_LSL2,    /* SVE [<Xn|SP>, <Xm|XZR>, LSL #2].  */
+  AARCH64_OPND_SVE_ADDR_RR_LSL3,    /* SVE [<Xn|SP>, <Xm|XZR>, LSL #3].  */
+  AARCH64_OPND_SVE_ADDR_RX,	    /* SVE [<Xn|SP>, <Xm>].  */
+  AARCH64_OPND_SVE_ADDR_RX_LSL1,    /* SVE [<Xn|SP>, <Xm>, LSL #1].  */
+  AARCH64_OPND_SVE_ADDR_RX_LSL2,    /* SVE [<Xn|SP>, <Xm>, LSL #2].  */
+  AARCH64_OPND_SVE_ADDR_RX_LSL3,    /* SVE [<Xn|SP>, <Xm>, LSL #3].  */
+  AARCH64_OPND_SVE_ADDR_RZ,	    /* SVE [<Xn|SP>, Zm.D].  */
+  AARCH64_OPND_SVE_ADDR_RZ_LSL1,    /* SVE [<Xn|SP>, Zm.D, LSL #1].  */
+  AARCH64_OPND_SVE_ADDR_RZ_LSL2,    /* SVE [<Xn|SP>, Zm.D, LSL #2].  */
+  AARCH64_OPND_SVE_ADDR_RZ_LSL3,    /* SVE [<Xn|SP>, Zm.D, LSL #3].  */
+  AARCH64_OPND_SVE_ADDR_RZ_XTW_14,  /* SVE [<Xn|SP>, Zm.<T>, (S|U)XTW].
+				       Bit 14 controls S/U choice.  */
+  AARCH64_OPND_SVE_ADDR_RZ_XTW_22,  /* SVE [<Xn|SP>, Zm.<T>, (S|U)XTW].
+				       Bit 22 controls S/U choice.  */
+  AARCH64_OPND_SVE_ADDR_RZ_XTW1_14, /* SVE [<Xn|SP>, Zm.<T>, (S|U)XTW #1].
+				       Bit 14 controls S/U choice.  */
+  AARCH64_OPND_SVE_ADDR_RZ_XTW1_22, /* SVE [<Xn|SP>, Zm.<T>, (S|U)XTW #1].
+				       Bit 22 controls S/U choice.  */
+  AARCH64_OPND_SVE_ADDR_RZ_XTW2_14, /* SVE [<Xn|SP>, Zm.<T>, (S|U)XTW #2].
+				       Bit 14 controls S/U choice.  */
+  AARCH64_OPND_SVE_ADDR_RZ_XTW2_22, /* SVE [<Xn|SP>, Zm.<T>, (S|U)XTW #2].
+				       Bit 22 controls S/U choice.  */
+  AARCH64_OPND_SVE_ADDR_RZ_XTW3_14, /* SVE [<Xn|SP>, Zm.<T>, (S|U)XTW #3].
+				       Bit 14 controls S/U choice.  */
+  AARCH64_OPND_SVE_ADDR_RZ_XTW3_22, /* SVE [<Xn|SP>, Zm.<T>, (S|U)XTW #3].
+				       Bit 22 controls S/U choice.  */
+  AARCH64_OPND_SVE_ADDR_ZI_U5,	    /* SVE [Zn.<T>, #<uimm5>].  */
+  AARCH64_OPND_SVE_ADDR_ZI_U5x2,    /* SVE [Zn.<T>, #<uimm5>*2].  */
+  AARCH64_OPND_SVE_ADDR_ZI_U5x4,    /* SVE [Zn.<T>, #<uimm5>*4].  */
+  AARCH64_OPND_SVE_ADDR_ZI_U5x8,    /* SVE [Zn.<T>, #<uimm5>*8].  */
+  AARCH64_OPND_SVE_ADDR_ZZ_LSL,     /* SVE [Zn.<T>, Zm,<T>, LSL #<msz>].  */
+  AARCH64_OPND_SVE_ADDR_ZZ_SXTW,    /* SVE [Zn.<T>, Zm,<T>, SXTW #<msz>].  */
+  AARCH64_OPND_SVE_ADDR_ZZ_UXTW,    /* SVE [Zn.<T>, Zm,<T>, UXTW #<msz>].  */
   AARCH64_OPND_SVE_PATTERN,	/* SVE vector pattern enumeration.  */
   AARCH64_OPND_SVE_PATTERN_SCALED, /* Likewise, with additional MUL factor.  */
   AARCH64_OPND_SVE_PRFOP,	/* SVE prefetch operation.  */
diff --git a/opcodes/aarch64-asm-2.c b/opcodes/aarch64-asm-2.c
index 039b9be..47a414c 100644
--- a/opcodes/aarch64-asm-2.c
+++ b/opcodes/aarch64-asm-2.c
@@ -480,21 +480,21 @@ aarch64_insert_operand (const aarch64_operand *self,
     case 27:
     case 35:
     case 36:
-    case 92:
-    case 93:
-    case 94:
-    case 95:
-    case 96:
-    case 97:
-    case 98:
-    case 99:
-    case 100:
-    case 101:
-    case 102:
-    case 103:
-    case 104:
-    case 105:
-    case 108:
+    case 123:
+    case 124:
+    case 125:
+    case 126:
+    case 127:
+    case 128:
+    case 129:
+    case 130:
+    case 131:
+    case 132:
+    case 133:
+    case 134:
+    case 135:
+    case 136:
+    case 139:
       return aarch64_ins_regno (self, info, code, inst);
     case 12:
       return aarch64_ins_reg_extended (self, info, code, inst);
@@ -531,8 +531,8 @@ aarch64_insert_operand (const aarch64_operand *self,
     case 68:
     case 69:
     case 70:
-    case 89:
-    case 91:
+    case 120:
+    case 122:
       return aarch64_ins_imm (self, info, code, inst);
     case 38:
     case 39:
@@ -583,12 +583,50 @@ aarch64_insert_operand (const aarch64_operand *self,
       return aarch64_ins_prfop (self, info, code, inst);
     case 88:
       return aarch64_ins_hint (self, info, code, inst);
+    case 89:
     case 90:
-      return aarch64_ins_sve_scale (self, info, code, inst);
+    case 91:
+    case 92:
+      return aarch64_ins_sve_addr_ri_u6 (self, info, code, inst);
+    case 93:
+    case 94:
+    case 95:
+    case 96:
+    case 97:
+    case 98:
+    case 99:
+    case 100:
+    case 101:
+    case 102:
+    case 103:
+    case 104:
+      return aarch64_ins_sve_addr_rr_lsl (self, info, code, inst);
+    case 105:
     case 106:
-      return aarch64_ins_sve_index (self, info, code, inst);
     case 107:
+    case 108:
     case 109:
+    case 110:
+    case 111:
+    case 112:
+      return aarch64_ins_sve_addr_rz_xtw (self, info, code, inst);
+    case 113:
+    case 114:
+    case 115:
+    case 116:
+      return aarch64_ins_sve_addr_zi_u5 (self, info, code, inst);
+    case 117:
+      return aarch64_ins_sve_addr_zz_lsl (self, info, code, inst);
+    case 118:
+      return aarch64_ins_sve_addr_zz_sxtw (self, info, code, inst);
+    case 119:
+      return aarch64_ins_sve_addr_zz_uxtw (self, info, code, inst);
+    case 121:
+      return aarch64_ins_sve_scale (self, info, code, inst);
+    case 137:
+      return aarch64_ins_sve_index (self, info, code, inst);
+    case 138:
+    case 140:
       return aarch64_ins_sve_reglist (self, info, code, inst);
     default: assert (0); abort ();
     }
diff --git a/opcodes/aarch64-asm.c b/opcodes/aarch64-asm.c
index 117a3c6..0d3b2c7 100644
--- a/opcodes/aarch64-asm.c
+++ b/opcodes/aarch64-asm.c
@@ -745,6 +745,114 @@ aarch64_ins_reg_shifted (const aarch64_operand *self ATTRIBUTE_UNUSED,
   return NULL;
 }
 
+/* Encode an SVE address [X<n>, #<SVE_imm6> << <shift>], where <SVE_imm6>
+   is a 6-bit unsigned number and where <shift> is SELF's operand-dependent
+   value.  fields[0] specifies the base register field.  */
+const char *
+aarch64_ins_sve_addr_ri_u6 (const aarch64_operand *self,
+			    const aarch64_opnd_info *info, aarch64_insn *code,
+			    const aarch64_inst *inst ATTRIBUTE_UNUSED)
+{
+  int factor = 1 << get_operand_specific_data (self);
+  insert_field (self->fields[0], code, info->addr.base_regno, 0);
+  insert_field (FLD_SVE_imm6, code, info->addr.offset.imm / factor, 0);
+  return NULL;
+}
+
+/* Encode an SVE address [X<n>, X<m>{, LSL #<shift>}], where <shift>
+   is SELF's operand-dependent value.  fields[0] specifies the base
+   register field and fields[1] specifies the offset register field.  */
+const char *
+aarch64_ins_sve_addr_rr_lsl (const aarch64_operand *self,
+			     const aarch64_opnd_info *info, aarch64_insn *code,
+			     const aarch64_inst *inst ATTRIBUTE_UNUSED)
+{
+  insert_field (self->fields[0], code, info->addr.base_regno, 0);
+  insert_field (self->fields[1], code, info->addr.offset.regno, 0);
+  return NULL;
+}
+
+/* Encode an SVE address [X<n>, Z<m>.<T>, (S|U)XTW {#<shift>}], where
+   <shift> is SELF's operand-dependent value.  fields[0] specifies the
+   base register field, fields[1] specifies the offset register field and
+   fields[2] is a single-bit field that selects SXTW over UXTW.  */
+const char *
+aarch64_ins_sve_addr_rz_xtw (const aarch64_operand *self,
+			     const aarch64_opnd_info *info, aarch64_insn *code,
+			     const aarch64_inst *inst ATTRIBUTE_UNUSED)
+{
+  insert_field (self->fields[0], code, info->addr.base_regno, 0);
+  insert_field (self->fields[1], code, info->addr.offset.regno, 0);
+  if (info->shifter.kind == AARCH64_MOD_UXTW)
+    insert_field (self->fields[2], code, 0, 0);
+  else
+    insert_field (self->fields[2], code, 1, 0);
+  return NULL;
+}
+
+/* Encode an SVE address [Z<n>.<T>, #<imm5> << <shift>], where <imm5> is a
+   5-bit unsigned number and where <shift> is SELF's operand-dependent value.
+   fields[0] specifies the base register field.  */
+const char *
+aarch64_ins_sve_addr_zi_u5 (const aarch64_operand *self,
+			    const aarch64_opnd_info *info, aarch64_insn *code,
+			    const aarch64_inst *inst ATTRIBUTE_UNUSED)
+{
+  int factor = 1 << get_operand_specific_data (self);
+  insert_field (self->fields[0], code, info->addr.base_regno, 0);
+  insert_field (FLD_imm5, code, info->addr.offset.imm / factor, 0);
+  return NULL;
+}
+
+/* Encode an SVE address [Z<n>.<T>, Z<m>.<T>{, <modifier> {#<msz>}}],
+   where <modifier> is fixed by the instruction and where <msz> is a
+   2-bit unsigned number.  fields[0] specifies the base register field
+   and fields[1] specifies the offset register field.  */
+static const char *
+aarch64_ext_sve_addr_zz (const aarch64_operand *self,
+			 const aarch64_opnd_info *info, aarch64_insn *code)
+{
+  insert_field (self->fields[0], code, info->addr.base_regno, 0);
+  insert_field (self->fields[1], code, info->addr.offset.regno, 0);
+  insert_field (FLD_SVE_msz, code, info->shifter.amount, 0);
+  return NULL;
+}
+
+/* Encode an SVE address [Z<n>.<T>, Z<m>.<T>{, LSL #<msz>}], where
+   <msz> is a 2-bit unsigned number.  fields[0] specifies the base register
+   field and fields[1] specifies the offset register field.  */
+const char *
+aarch64_ins_sve_addr_zz_lsl (const aarch64_operand *self,
+			     const aarch64_opnd_info *info, aarch64_insn *code,
+			     const aarch64_inst *inst ATTRIBUTE_UNUSED)
+{
+  return aarch64_ext_sve_addr_zz (self, info, code);
+}
+
+/* Encode an SVE address [Z<n>.<T>, Z<m>.<T>, SXTW {#<msz>}], where
+   <msz> is a 2-bit unsigned number.  fields[0] specifies the base register
+   field and fields[1] specifies the offset register field.  */
+const char *
+aarch64_ins_sve_addr_zz_sxtw (const aarch64_operand *self,
+			      const aarch64_opnd_info *info,
+			      aarch64_insn *code,
+			      const aarch64_inst *inst ATTRIBUTE_UNUSED)
+{
+  return aarch64_ext_sve_addr_zz (self, info, code);
+}
+
+/* Encode an SVE address [Z<n>.<T>, Z<m>.<T>, UXTW {#<msz>}], where
+   <msz> is a 2-bit unsigned number.  fields[0] specifies the base register
+   field and fields[1] specifies the offset register field.  */
+const char *
+aarch64_ins_sve_addr_zz_uxtw (const aarch64_operand *self,
+			      const aarch64_opnd_info *info,
+			      aarch64_insn *code,
+			      const aarch64_inst *inst ATTRIBUTE_UNUSED)
+{
+  return aarch64_ext_sve_addr_zz (self, info, code);
+}
+
 /* Encode Zn[MM], where MM has a 7-bit triangular encoding.  The fields
    array specifies which field to use for Zn.  MM is encoded in the
    concatenation of imm5 and SVE_tszh, with imm5 being the less
diff --git a/opcodes/aarch64-asm.h b/opcodes/aarch64-asm.h
index ac5faeb..b81cfa1 100644
--- a/opcodes/aarch64-asm.h
+++ b/opcodes/aarch64-asm.h
@@ -69,6 +69,13 @@ AARCH64_DECL_OPD_INSERTER (ins_hint);
 AARCH64_DECL_OPD_INSERTER (ins_prfop);
 AARCH64_DECL_OPD_INSERTER (ins_reg_extended);
 AARCH64_DECL_OPD_INSERTER (ins_reg_shifted);
+AARCH64_DECL_OPD_INSERTER (ins_sve_addr_ri_u6);
+AARCH64_DECL_OPD_INSERTER (ins_sve_addr_rr_lsl);
+AARCH64_DECL_OPD_INSERTER (ins_sve_addr_rz_xtw);
+AARCH64_DECL_OPD_INSERTER (ins_sve_addr_zi_u5);
+AARCH64_DECL_OPD_INSERTER (ins_sve_addr_zz_lsl);
+AARCH64_DECL_OPD_INSERTER (ins_sve_addr_zz_sxtw);
+AARCH64_DECL_OPD_INSERTER (ins_sve_addr_zz_uxtw);
 AARCH64_DECL_OPD_INSERTER (ins_sve_index);
 AARCH64_DECL_OPD_INSERTER (ins_sve_reglist);
 AARCH64_DECL_OPD_INSERTER (ins_sve_scale);
diff --git a/opcodes/aarch64-dis-2.c b/opcodes/aarch64-dis-2.c
index 124385d..3dd714f 100644
--- a/opcodes/aarch64-dis-2.c
+++ b/opcodes/aarch64-dis-2.c
@@ -10426,21 +10426,21 @@ aarch64_extract_operand (const aarch64_operand *self,
     case 27:
     case 35:
     case 36:
-    case 92:
-    case 93:
-    case 94:
-    case 95:
-    case 96:
-    case 97:
-    case 98:
-    case 99:
-    case 100:
-    case 101:
-    case 102:
-    case 103:
-    case 104:
-    case 105:
-    case 108:
+    case 123:
+    case 124:
+    case 125:
+    case 126:
+    case 127:
+    case 128:
+    case 129:
+    case 130:
+    case 131:
+    case 132:
+    case 133:
+    case 134:
+    case 135:
+    case 136:
+    case 139:
       return aarch64_ext_regno (self, info, code, inst);
     case 8:
       return aarch64_ext_regrt_sysins (self, info, code, inst);
@@ -10482,8 +10482,8 @@ aarch64_extract_operand (const aarch64_operand *self,
     case 68:
     case 69:
     case 70:
-    case 89:
-    case 91:
+    case 120:
+    case 122:
       return aarch64_ext_imm (self, info, code, inst);
     case 38:
     case 39:
@@ -10536,12 +10536,50 @@ aarch64_extract_operand (const aarch64_operand *self,
       return aarch64_ext_prfop (self, info, code, inst);
     case 88:
       return aarch64_ext_hint (self, info, code, inst);
+    case 89:
     case 90:
-      return aarch64_ext_sve_scale (self, info, code, inst);
+    case 91:
+    case 92:
+      return aarch64_ext_sve_addr_ri_u6 (self, info, code, inst);
+    case 93:
+    case 94:
+    case 95:
+    case 96:
+    case 97:
+    case 98:
+    case 99:
+    case 100:
+    case 101:
+    case 102:
+    case 103:
+    case 104:
+      return aarch64_ext_sve_addr_rr_lsl (self, info, code, inst);
+    case 105:
     case 106:
-      return aarch64_ext_sve_index (self, info, code, inst);
     case 107:
+    case 108:
     case 109:
+    case 110:
+    case 111:
+    case 112:
+      return aarch64_ext_sve_addr_rz_xtw (self, info, code, inst);
+    case 113:
+    case 114:
+    case 115:
+    case 116:
+      return aarch64_ext_sve_addr_zi_u5 (self, info, code, inst);
+    case 117:
+      return aarch64_ext_sve_addr_zz_lsl (self, info, code, inst);
+    case 118:
+      return aarch64_ext_sve_addr_zz_sxtw (self, info, code, inst);
+    case 119:
+      return aarch64_ext_sve_addr_zz_uxtw (self, info, code, inst);
+    case 121:
+      return aarch64_ext_sve_scale (self, info, code, inst);
+    case 137:
+      return aarch64_ext_sve_index (self, info, code, inst);
+    case 138:
+    case 140:
       return aarch64_ext_sve_reglist (self, info, code, inst);
     default: assert (0); abort ();
     }
diff --git a/opcodes/aarch64-dis.c b/opcodes/aarch64-dis.c
index 1d00c0a..ed77b4d 100644
--- a/opcodes/aarch64-dis.c
+++ b/opcodes/aarch64-dis.c
@@ -1186,6 +1186,152 @@ aarch64_ext_reg_shifted (const aarch64_operand *self ATTRIBUTE_UNUSED,
   return 1;
 }
 
+/* Decode an SVE address [<base>, #<offset> << <shift>], where <offset>
+   is given by the OFFSET parameter and where <shift> is SELF's operand-
+   dependent value.  fields[0] specifies the base register field <base>.  */
+static int
+aarch64_ext_sve_addr_reg_imm (const aarch64_operand *self,
+			      aarch64_opnd_info *info, aarch64_insn code,
+			      int64_t offset)
+{
+  info->addr.base_regno = extract_field (self->fields[0], code, 0);
+  info->addr.offset.imm = offset * (1 << get_operand_specific_data (self));
+  info->addr.offset.is_reg = FALSE;
+  info->addr.writeback = FALSE;
+  info->addr.preind = TRUE;
+  info->shifter.operator_present = FALSE;
+  info->shifter.amount_present = FALSE;
+  return 1;
+}
+
+/* Decode an SVE address [X<n>, #<SVE_imm6> << <shift>], where <SVE_imm6>
+   is a 6-bit unsigned number and where <shift> is SELF's operand-dependent
+   value.  fields[0] specifies the base register field.  */
+int
+aarch64_ext_sve_addr_ri_u6 (const aarch64_operand *self,
+			    aarch64_opnd_info *info, aarch64_insn code,
+			    const aarch64_inst *inst ATTRIBUTE_UNUSED)
+{
+  int offset = extract_field (FLD_SVE_imm6, code, 0);
+  return aarch64_ext_sve_addr_reg_imm (self, info, code, offset);
+}
+
+/* Decode an SVE address [X<n>, X<m>{, LSL #<shift>}], where <shift>
+   is SELF's operand-dependent value.  fields[0] specifies the base
+   register field and fields[1] specifies the offset register field.  */
+int
+aarch64_ext_sve_addr_rr_lsl (const aarch64_operand *self,
+			     aarch64_opnd_info *info, aarch64_insn code,
+			     const aarch64_inst *inst ATTRIBUTE_UNUSED)
+{
+  int index;
+
+  index = extract_field (self->fields[1], code, 0);
+  if (index == 31 && (self->flags & OPD_F_NO_ZR) != 0)
+    return 0;
+
+  info->addr.base_regno = extract_field (self->fields[0], code, 0);
+  info->addr.offset.regno = index;
+  info->addr.offset.is_reg = TRUE;
+  info->addr.writeback = FALSE;
+  info->addr.preind = TRUE;
+  info->shifter.kind = AARCH64_MOD_LSL;
+  info->shifter.amount = get_operand_specific_data (self);
+  info->shifter.operator_present = (info->shifter.amount != 0);
+  info->shifter.amount_present = (info->shifter.amount != 0);
+  return 1;
+}
+
+/* Decode an SVE address [X<n>, Z<m>.<T>, (S|U)XTW {#<shift>}], where
+   <shift> is SELF's operand-dependent value.  fields[0] specifies the
+   base register field, fields[1] specifies the offset register field and
+   fields[2] is a single-bit field that selects SXTW over UXTW.  */
+int
+aarch64_ext_sve_addr_rz_xtw (const aarch64_operand *self,
+			     aarch64_opnd_info *info, aarch64_insn code,
+			     const aarch64_inst *inst ATTRIBUTE_UNUSED)
+{
+  info->addr.base_regno = extract_field (self->fields[0], code, 0);
+  info->addr.offset.regno = extract_field (self->fields[1], code, 0);
+  info->addr.offset.is_reg = TRUE;
+  info->addr.writeback = FALSE;
+  info->addr.preind = TRUE;
+  if (extract_field (self->fields[2], code, 0))
+    info->shifter.kind = AARCH64_MOD_SXTW;
+  else
+    info->shifter.kind = AARCH64_MOD_UXTW;
+  info->shifter.amount = get_operand_specific_data (self);
+  info->shifter.operator_present = TRUE;
+  info->shifter.amount_present = (info->shifter.amount != 0);
+  return 1;
+}
+
+/* Decode an SVE address [Z<n>.<T>, #<imm5> << <shift>], where <imm5> is a
+   5-bit unsigned number and where <shift> is SELF's operand-dependent value.
+   fields[0] specifies the base register field.  */
+int
+aarch64_ext_sve_addr_zi_u5 (const aarch64_operand *self,
+			    aarch64_opnd_info *info, aarch64_insn code,
+			    const aarch64_inst *inst ATTRIBUTE_UNUSED)
+{
+  int offset = extract_field (FLD_imm5, code, 0);
+  return aarch64_ext_sve_addr_reg_imm (self, info, code, offset);
+}
+
+/* Decode an SVE address [Z<n>.<T>, Z<m>.<T>{, <modifier> {#<msz>}}],
+   where <modifier> is given by KIND and where <msz> is a 2-bit unsigned
+   number.  fields[0] specifies the base register field and fields[1]
+   specifies the offset register field.  */
+static int
+aarch64_ext_sve_addr_zz (const aarch64_operand *self, aarch64_opnd_info *info,
+			 aarch64_insn code, enum aarch64_modifier_kind kind)
+{
+  info->addr.base_regno = extract_field (self->fields[0], code, 0);
+  info->addr.offset.regno = extract_field (self->fields[1], code, 0);
+  info->addr.offset.is_reg = TRUE;
+  info->addr.writeback = FALSE;
+  info->addr.preind = TRUE;
+  info->shifter.kind = kind;
+  info->shifter.amount = extract_field (FLD_SVE_msz, code, 0);
+  info->shifter.operator_present = (kind != AARCH64_MOD_LSL
+				    || info->shifter.amount != 0);
+  info->shifter.amount_present = (info->shifter.amount != 0);
+  return 1;
+}
+
+/* Decode an SVE address [Z<n>.<T>, Z<m>.<T>{, LSL #<msz>}], where
+   <msz> is a 2-bit unsigned number.  fields[0] specifies the base register
+   field and fields[1] specifies the offset register field.  */
+int
+aarch64_ext_sve_addr_zz_lsl (const aarch64_operand *self,
+			     aarch64_opnd_info *info, aarch64_insn code,
+			     const aarch64_inst *inst ATTRIBUTE_UNUSED)
+{
+  return aarch64_ext_sve_addr_zz (self, info, code, AARCH64_MOD_LSL);
+}
+
+/* Decode an SVE address [Z<n>.<T>, Z<m>.<T>, SXTW {#<msz>}], where
+   <msz> is a 2-bit unsigned number.  fields[0] specifies the base register
+   field and fields[1] specifies the offset register field.  */
+int
+aarch64_ext_sve_addr_zz_sxtw (const aarch64_operand *self,
+			      aarch64_opnd_info *info, aarch64_insn code,
+			      const aarch64_inst *inst ATTRIBUTE_UNUSED)
+{
+  return aarch64_ext_sve_addr_zz (self, info, code, AARCH64_MOD_SXTW);
+}
+
+/* Decode an SVE address [Z<n>.<T>, Z<m>.<T>, UXTW {#<msz>}], where
+   <msz> is a 2-bit unsigned number.  fields[0] specifies the base register
+   field and fields[1] specifies the offset register field.  */
+int
+aarch64_ext_sve_addr_zz_uxtw (const aarch64_operand *self,
+			      aarch64_opnd_info *info, aarch64_insn code,
+			      const aarch64_inst *inst ATTRIBUTE_UNUSED)
+{
+  return aarch64_ext_sve_addr_zz (self, info, code, AARCH64_MOD_UXTW);
+}
+
 /* Decode Zn[MM], where MM has a 7-bit triangular encoding.  The fields
    array specifies which field to use for Zn.  MM is encoded in the
    concatenation of imm5 and SVE_tszh, with imm5 being the less
diff --git a/opcodes/aarch64-dis.h b/opcodes/aarch64-dis.h
index 92f5ad4..0ce2d89 100644
--- a/opcodes/aarch64-dis.h
+++ b/opcodes/aarch64-dis.h
@@ -91,6 +91,13 @@ AARCH64_DECL_OPD_EXTRACTOR (ext_hint);
 AARCH64_DECL_OPD_EXTRACTOR (ext_prfop);
 AARCH64_DECL_OPD_EXTRACTOR (ext_reg_extended);
 AARCH64_DECL_OPD_EXTRACTOR (ext_reg_shifted);
+AARCH64_DECL_OPD_EXTRACTOR (ext_sve_addr_ri_u6);
+AARCH64_DECL_OPD_EXTRACTOR (ext_sve_addr_rr_lsl);
+AARCH64_DECL_OPD_EXTRACTOR (ext_sve_addr_rz_xtw);
+AARCH64_DECL_OPD_EXTRACTOR (ext_sve_addr_zi_u5);
+AARCH64_DECL_OPD_EXTRACTOR (ext_sve_addr_zz_lsl);
+AARCH64_DECL_OPD_EXTRACTOR (ext_sve_addr_zz_sxtw);
+AARCH64_DECL_OPD_EXTRACTOR (ext_sve_addr_zz_uxtw);
 AARCH64_DECL_OPD_EXTRACTOR (ext_sve_index);
 AARCH64_DECL_OPD_EXTRACTOR (ext_sve_reglist);
 AARCH64_DECL_OPD_EXTRACTOR (ext_sve_scale);
diff --git a/opcodes/aarch64-opc-2.c b/opcodes/aarch64-opc-2.c
index 8f221b8..ed2b70b 100644
--- a/opcodes/aarch64-opc-2.c
+++ b/opcodes/aarch64-opc-2.c
@@ -113,6 +113,37 @@ const struct aarch64_operand aarch64_operands[] =
   {AARCH64_OPND_CLASS_SYSTEM, "BARRIER_ISB", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {}, "the ISB option name SY or an optional 4-bit unsigned immediate"},
   {AARCH64_OPND_CLASS_SYSTEM, "PRFOP", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {}, "a prefetch operation specifier"},
   {AARCH64_OPND_CLASS_SYSTEM, "BARRIER_PSB", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {}, "the PSB option name CSYNC"},
+  {AARCH64_OPND_CLASS_ADDRESS, "SVE_ADDR_RI_U6", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rn}, "an address with a 6-bit unsigned offset"},
+  {AARCH64_OPND_CLASS_ADDRESS, "SVE_ADDR_RI_U6x2", 1 << OPD_F_OD_LSB | OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rn}, "an address with a 6-bit unsigned offset, multiplied by 2"},
+  {AARCH64_OPND_CLASS_ADDRESS, "SVE_ADDR_RI_U6x4", 2 << OPD_F_OD_LSB | OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rn}, "an address with a 6-bit unsigned offset, multiplied by 4"},
+  {AARCH64_OPND_CLASS_ADDRESS, "SVE_ADDR_RI_U6x8", 3 << OPD_F_OD_LSB | OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rn}, "an address with a 6-bit unsigned offset, multiplied by 8"},
+  {AARCH64_OPND_CLASS_ADDRESS, "SVE_ADDR_RR", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rn,FLD_Rm}, "an address with a scalar register offset"},
+  {AARCH64_OPND_CLASS_ADDRESS, "SVE_ADDR_RR_LSL1", 1 << OPD_F_OD_LSB | OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rn,FLD_Rm}, "an address with a scalar register offset"},
+  {AARCH64_OPND_CLASS_ADDRESS, "SVE_ADDR_RR_LSL2", 2 << OPD_F_OD_LSB | OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rn,FLD_Rm}, "an address with a scalar register offset"},
+  {AARCH64_OPND_CLASS_ADDRESS, "SVE_ADDR_RR_LSL3", 3 << OPD_F_OD_LSB | OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rn,FLD_Rm}, "an address with a scalar register offset"},
+  {AARCH64_OPND_CLASS_ADDRESS, "SVE_ADDR_RX", (0 << OPD_F_OD_LSB) | OPD_F_NO_ZR | OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rn,FLD_Rm}, "an address with a scalar register offset"},
+  {AARCH64_OPND_CLASS_ADDRESS, "SVE_ADDR_RX_LSL1", (1 << OPD_F_OD_LSB) | OPD_F_NO_ZR | OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rn,FLD_Rm}, "an address with a scalar register offset"},
+  {AARCH64_OPND_CLASS_ADDRESS, "SVE_ADDR_RX_LSL2", (2 << OPD_F_OD_LSB) | OPD_F_NO_ZR | OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rn,FLD_Rm}, "an address with a scalar register offset"},
+  {AARCH64_OPND_CLASS_ADDRESS, "SVE_ADDR_RX_LSL3", (3 << OPD_F_OD_LSB) | OPD_F_NO_ZR | OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rn,FLD_Rm}, "an address with a scalar register offset"},
+  {AARCH64_OPND_CLASS_ADDRESS, "SVE_ADDR_RZ", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rn,FLD_SVE_Zm_16}, "an address with a vector register offset"},
+  {AARCH64_OPND_CLASS_ADDRESS, "SVE_ADDR_RZ_LSL1", 1 << OPD_F_OD_LSB | OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rn,FLD_SVE_Zm_16}, "an address with a vector register offset"},
+  {AARCH64_OPND_CLASS_ADDRESS, "SVE_ADDR_RZ_LSL2", 2 << OPD_F_OD_LSB | OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rn,FLD_SVE_Zm_16}, "an address with a vector register offset"},
+  {AARCH64_OPND_CLASS_ADDRESS, "SVE_ADDR_RZ_LSL3", 3 << OPD_F_OD_LSB | OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rn,FLD_SVE_Zm_16}, "an address with a vector register offset"},
+  {AARCH64_OPND_CLASS_ADDRESS, "SVE_ADDR_RZ_XTW_14", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rn,FLD_SVE_Zm_16,FLD_SVE_xs_14}, "an address with a vector register offset"},
+  {AARCH64_OPND_CLASS_ADDRESS, "SVE_ADDR_RZ_XTW_22", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rn,FLD_SVE_Zm_16,FLD_SVE_xs_22}, "an address with a vector register offset"},
+  {AARCH64_OPND_CLASS_ADDRESS, "SVE_ADDR_RZ_XTW1_14", 1 << OPD_F_OD_LSB | OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rn,FLD_SVE_Zm_16,FLD_SVE_xs_14}, "an address with a vector register offset"},
+  {AARCH64_OPND_CLASS_ADDRESS, "SVE_ADDR_RZ_XTW1_22", 1 << OPD_F_OD_LSB | OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rn,FLD_SVE_Zm_16,FLD_SVE_xs_22}, "an address with a vector register offset"},
+  {AARCH64_OPND_CLASS_ADDRESS, "SVE_ADDR_RZ_XTW2_14", 2 << OPD_F_OD_LSB | OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rn,FLD_SVE_Zm_16,FLD_SVE_xs_14}, "an address with a vector register offset"},
+  {AARCH64_OPND_CLASS_ADDRESS, "SVE_ADDR_RZ_XTW2_22", 2 << OPD_F_OD_LSB | OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rn,FLD_SVE_Zm_16,FLD_SVE_xs_22}, "an address with a vector register offset"},
+  {AARCH64_OPND_CLASS_ADDRESS, "SVE_ADDR_RZ_XTW3_14", 3 << OPD_F_OD_LSB | OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rn,FLD_SVE_Zm_16,FLD_SVE_xs_14}, "an address with a vector register offset"},
+  {AARCH64_OPND_CLASS_ADDRESS, "SVE_ADDR_RZ_XTW3_22", 3 << OPD_F_OD_LSB | OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rn,FLD_SVE_Zm_16,FLD_SVE_xs_22}, "an address with a vector register offset"},
+  {AARCH64_OPND_CLASS_ADDRESS, "SVE_ADDR_ZI_U5", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_SVE_Zn}, "an address with a 5-bit unsigned offset"},
+  {AARCH64_OPND_CLASS_ADDRESS, "SVE_ADDR_ZI_U5x2", 1 << OPD_F_OD_LSB | OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_SVE_Zn}, "an address with a 5-bit unsigned offset, multiplied by 2"},
+  {AARCH64_OPND_CLASS_ADDRESS, "SVE_ADDR_ZI_U5x4", 2 << OPD_F_OD_LSB | OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_SVE_Zn}, "an address with a 5-bit unsigned offset, multiplied by 4"},
+  {AARCH64_OPND_CLASS_ADDRESS, "SVE_ADDR_ZI_U5x8", 3 << OPD_F_OD_LSB | OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_SVE_Zn}, "an address with a 5-bit unsigned offset, multiplied by 8"},
+  {AARCH64_OPND_CLASS_ADDRESS, "SVE_ADDR_ZZ_LSL", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_SVE_Zn,FLD_SVE_Zm_16}, "an address with a vector register offset"},
+  {AARCH64_OPND_CLASS_ADDRESS, "SVE_ADDR_ZZ_SXTW", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_SVE_Zn,FLD_SVE_Zm_16}, "an address with a vector register offset"},
+  {AARCH64_OPND_CLASS_ADDRESS, "SVE_ADDR_ZZ_UXTW", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_SVE_Zn,FLD_SVE_Zm_16}, "an address with a vector register offset"},
   {AARCH64_OPND_CLASS_IMMEDIATE, "SVE_PATTERN", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_SVE_pattern}, "an enumeration value such as POW2"},
   {AARCH64_OPND_CLASS_IMMEDIATE, "SVE_PATTERN_SCALED", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_SVE_pattern}, "an enumeration value such as POW2"},
   {AARCH64_OPND_CLASS_IMMEDIATE, "SVE_PRFOP", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_SVE_prfop}, "an enumeration value such as PLDL1KEEP"},
diff --git a/opcodes/aarch64-opc.c b/opcodes/aarch64-opc.c
index 326b94e..6617e28 100644
--- a/opcodes/aarch64-opc.c
+++ b/opcodes/aarch64-opc.c
@@ -280,9 +280,13 @@ const aarch64_field fields[] =
     {  5,  5 }, /* SVE_Zn: SVE vector register, bits [9,5].  */
     {  0,  5 }, /* SVE_Zt: SVE vector register, bits [4,0].  */
     { 16,  4 }, /* SVE_imm4: 4-bit immediate field.  */
+    { 16,  6 }, /* SVE_imm6: 6-bit immediate field.  */
+    { 10,  2 }, /* SVE_msz: 2-bit shift amount for ADR.  */
     {  5,  5 }, /* SVE_pattern: vector pattern enumeration.  */
     {  0,  4 }, /* SVE_prfop: prefetch operation for SVE PRF[BHWD].  */
     { 22,  2 }, /* SVE_tszh: triangular size select high, bits [23,22].  */
+    { 14,  1 }, /* SVE_xs_14: UXTW/SXTW select (bit 14).  */
+    { 22,  1 }  /* SVE_xs_22: UXTW/SXTW select (bit 22).  */
 };
 
 enum aarch64_operand_class
@@ -1368,9 +1372,9 @@ operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx,
 				  const aarch64_opcode *opcode,
 				  aarch64_operand_error *mismatch_detail)
 {
-  unsigned num;
+  unsigned num, modifiers;
   unsigned char size;
-  int64_t imm;
+  int64_t imm, min_value, max_value;
   const aarch64_opnd_info *opnd = opnds + idx;
   aarch64_opnd_qualifier_t qualifier = opnd->qualifier;
 
@@ -1662,6 +1666,113 @@ operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx,
 	    }
 	  break;
 
+	case AARCH64_OPND_SVE_ADDR_RI_U6:
+	case AARCH64_OPND_SVE_ADDR_RI_U6x2:
+	case AARCH64_OPND_SVE_ADDR_RI_U6x4:
+	case AARCH64_OPND_SVE_ADDR_RI_U6x8:
+	  min_value = 0;
+	  max_value = 63;
+	sve_imm_offset:
+	  assert (!opnd->addr.offset.is_reg);
+	  assert (opnd->addr.preind);
+	  num = 1 << get_operand_specific_data (&aarch64_operands[type]);
+	  min_value *= num;
+	  max_value *= num;
+	  if (opnd->shifter.operator_present
+	      || opnd->shifter.amount_present)
+	    {
+	      set_other_error (mismatch_detail, idx,
+			       _("invalid addressing mode"));
+	      return 0;
+	    }
+	  if (!value_in_range_p (opnd->addr.offset.imm, min_value, max_value))
+	    {
+	      set_offset_out_of_range_error (mismatch_detail, idx,
+					     min_value, max_value);
+	      return 0;
+	    }
+	  if (!value_aligned_p (opnd->addr.offset.imm, num))
+	    {
+	      set_unaligned_error (mismatch_detail, idx, num);
+	      return 0;
+	    }
+	  break;
+
+	case AARCH64_OPND_SVE_ADDR_RR:
+	case AARCH64_OPND_SVE_ADDR_RR_LSL1:
+	case AARCH64_OPND_SVE_ADDR_RR_LSL2:
+	case AARCH64_OPND_SVE_ADDR_RR_LSL3:
+	case AARCH64_OPND_SVE_ADDR_RX:
+	case AARCH64_OPND_SVE_ADDR_RX_LSL1:
+	case AARCH64_OPND_SVE_ADDR_RX_LSL2:
+	case AARCH64_OPND_SVE_ADDR_RX_LSL3:
+	case AARCH64_OPND_SVE_ADDR_RZ:
+	case AARCH64_OPND_SVE_ADDR_RZ_LSL1:
+	case AARCH64_OPND_SVE_ADDR_RZ_LSL2:
+	case AARCH64_OPND_SVE_ADDR_RZ_LSL3:
+	  modifiers = 1 << AARCH64_MOD_LSL;
+	sve_rr_operand:
+	  assert (opnd->addr.offset.is_reg);
+	  assert (opnd->addr.preind);
+	  if ((aarch64_operands[type].flags & OPD_F_NO_ZR) != 0
+	      && opnd->addr.offset.regno == 31)
+	    {
+	      set_other_error (mismatch_detail, idx,
+			       _("index register xzr is not allowed"));
+	      return 0;
+	    }
+	  if (((1 << opnd->shifter.kind) & modifiers) == 0
+	      || (opnd->shifter.amount
+		  != get_operand_specific_data (&aarch64_operands[type])))
+	    {
+	      set_other_error (mismatch_detail, idx,
+			       _("invalid addressing mode"));
+	      return 0;
+	    }
+	  break;
+
+	case AARCH64_OPND_SVE_ADDR_RZ_XTW_14:
+	case AARCH64_OPND_SVE_ADDR_RZ_XTW_22:
+	case AARCH64_OPND_SVE_ADDR_RZ_XTW1_14:
+	case AARCH64_OPND_SVE_ADDR_RZ_XTW1_22:
+	case AARCH64_OPND_SVE_ADDR_RZ_XTW2_14:
+	case AARCH64_OPND_SVE_ADDR_RZ_XTW2_22:
+	case AARCH64_OPND_SVE_ADDR_RZ_XTW3_14:
+	case AARCH64_OPND_SVE_ADDR_RZ_XTW3_22:
+	  modifiers = (1 << AARCH64_MOD_SXTW) | (1 << AARCH64_MOD_UXTW);
+	  goto sve_rr_operand;
+
+	case AARCH64_OPND_SVE_ADDR_ZI_U5:
+	case AARCH64_OPND_SVE_ADDR_ZI_U5x2:
+	case AARCH64_OPND_SVE_ADDR_ZI_U5x4:
+	case AARCH64_OPND_SVE_ADDR_ZI_U5x8:
+	  min_value = 0;
+	  max_value = 31;
+	  goto sve_imm_offset;
+
+	case AARCH64_OPND_SVE_ADDR_ZZ_LSL:
+	  modifiers = 1 << AARCH64_MOD_LSL;
+	sve_zz_operand:
+	  assert (opnd->addr.offset.is_reg);
+	  assert (opnd->addr.preind);
+	  if (((1 << opnd->shifter.kind) & modifiers) == 0
+	      || opnd->shifter.amount < 0
+	      || opnd->shifter.amount > 3)
+	    {
+	      set_other_error (mismatch_detail, idx,
+			       _("invalid addressing mode"));
+	      return 0;
+	    }
+	  break;
+
+	case AARCH64_OPND_SVE_ADDR_ZZ_SXTW:
+	  modifiers = (1 << AARCH64_MOD_SXTW);
+	  goto sve_zz_operand;
+
+	case AARCH64_OPND_SVE_ADDR_ZZ_UXTW:
+	  modifiers = 1 << AARCH64_MOD_UXTW;
+	  goto sve_zz_operand;
+
 	default:
 	  break;
 	}
@@ -2330,6 +2441,17 @@ static const char *int_reg[2][2][32] = {
 #undef R64
 #undef R32
 };
+
+/* Names of the SVE vector registers, first with .S suffixes,
+   then with .D suffixes.  */
+
+static const char *sve_reg[2][32] = {
+#define ZS(X) "z" #X ".s"
+#define ZD(X) "z" #X ".d"
+  BANK (ZS, ZS (31)), BANK (ZD, ZD (31))
+#undef ZD
+#undef ZS
+};
 #undef BANK
 
 /* Return the integer register name.
@@ -2373,6 +2495,17 @@ get_offset_int_reg_name (const aarch64_opnd_info *opnd)
     }
 }
 
+/* Get the name of the SVE vector offset register in OPND, using the operand
+   qualifier to decide whether the suffix should be .S or .D.  */
+
+static inline const char *
+get_addr_sve_reg_name (int regno, aarch64_opnd_qualifier_t qualifier)
+{
+  assert (qualifier == AARCH64_OPND_QLF_S_S
+	  || qualifier == AARCH64_OPND_QLF_S_D);
+  return sve_reg[qualifier == AARCH64_OPND_QLF_S_D][regno];
+}
+
 /* Types for expanding an encoded 8-bit value to a floating-point value.  */
 
 typedef union
@@ -2948,18 +3081,65 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc,
       break;
 
     case AARCH64_OPND_ADDR_REGOFF:
+    case AARCH64_OPND_SVE_ADDR_RR:
+    case AARCH64_OPND_SVE_ADDR_RR_LSL1:
+    case AARCH64_OPND_SVE_ADDR_RR_LSL2:
+    case AARCH64_OPND_SVE_ADDR_RR_LSL3:
+    case AARCH64_OPND_SVE_ADDR_RX:
+    case AARCH64_OPND_SVE_ADDR_RX_LSL1:
+    case AARCH64_OPND_SVE_ADDR_RX_LSL2:
+    case AARCH64_OPND_SVE_ADDR_RX_LSL3:
       print_register_offset_address
 	(buf, size, opnd, get_64bit_int_reg_name (opnd->addr.base_regno, 1),
 	 get_offset_int_reg_name (opnd));
       break;
 
+    case AARCH64_OPND_SVE_ADDR_RZ:
+    case AARCH64_OPND_SVE_ADDR_RZ_LSL1:
+    case AARCH64_OPND_SVE_ADDR_RZ_LSL2:
+    case AARCH64_OPND_SVE_ADDR_RZ_LSL3:
+    case AARCH64_OPND_SVE_ADDR_RZ_XTW_14:
+    case AARCH64_OPND_SVE_ADDR_RZ_XTW_22:
+    case AARCH64_OPND_SVE_ADDR_RZ_XTW1_14:
+    case AARCH64_OPND_SVE_ADDR_RZ_XTW1_22:
+    case AARCH64_OPND_SVE_ADDR_RZ_XTW2_14:
+    case AARCH64_OPND_SVE_ADDR_RZ_XTW2_22:
+    case AARCH64_OPND_SVE_ADDR_RZ_XTW3_14:
+    case AARCH64_OPND_SVE_ADDR_RZ_XTW3_22:
+      print_register_offset_address
+	(buf, size, opnd, get_64bit_int_reg_name (opnd->addr.base_regno, 1),
+	 get_addr_sve_reg_name (opnd->addr.offset.regno, opnd->qualifier));
+      break;
+
     case AARCH64_OPND_ADDR_SIMM7:
     case AARCH64_OPND_ADDR_SIMM9:
     case AARCH64_OPND_ADDR_SIMM9_2:
+    case AARCH64_OPND_SVE_ADDR_RI_U6:
+    case AARCH64_OPND_SVE_ADDR_RI_U6x2:
+    case AARCH64_OPND_SVE_ADDR_RI_U6x4:
+    case AARCH64_OPND_SVE_ADDR_RI_U6x8:
       print_immediate_offset_address
 	(buf, size, opnd, get_64bit_int_reg_name (opnd->addr.base_regno, 1));
       break;
 
+    case AARCH64_OPND_SVE_ADDR_ZI_U5:
+    case AARCH64_OPND_SVE_ADDR_ZI_U5x2:
+    case AARCH64_OPND_SVE_ADDR_ZI_U5x4:
+    case AARCH64_OPND_SVE_ADDR_ZI_U5x8:
+      print_immediate_offset_address
+	(buf, size, opnd,
+	 get_addr_sve_reg_name (opnd->addr.base_regno, opnd->qualifier));
+      break;
+
+    case AARCH64_OPND_SVE_ADDR_ZZ_LSL:
+    case AARCH64_OPND_SVE_ADDR_ZZ_SXTW:
+    case AARCH64_OPND_SVE_ADDR_ZZ_UXTW:
+      print_register_offset_address
+	(buf, size, opnd,
+	 get_addr_sve_reg_name (opnd->addr.base_regno, opnd->qualifier),
+	 get_addr_sve_reg_name (opnd->addr.offset.regno, opnd->qualifier));
+      break;
+
     case AARCH64_OPND_ADDR_UIMM12:
       name = get_64bit_int_reg_name (opnd->addr.base_regno, 1);
       if (opnd->addr.offset.imm)
diff --git a/opcodes/aarch64-opc.h b/opcodes/aarch64-opc.h
index 3406f6e..e823146 100644
--- a/opcodes/aarch64-opc.h
+++ b/opcodes/aarch64-opc.h
@@ -107,9 +107,13 @@ enum aarch64_field_kind
   FLD_SVE_Zn,
   FLD_SVE_Zt,
   FLD_SVE_imm4,
+  FLD_SVE_imm6,
+  FLD_SVE_msz,
   FLD_SVE_pattern,
   FLD_SVE_prfop,
   FLD_SVE_tszh,
+  FLD_SVE_xs_14,
+  FLD_SVE_xs_22,
 };
 
 /* Field description.  */
@@ -156,6 +160,9 @@ extern const aarch64_operand aarch64_operands[];
 						   value by 2 to get the value
 						   of an immediate operand.  */
 #define OPD_F_MAYBE_SP		0x00000010	/* May potentially be SP.  */
+#define OPD_F_OD_MASK		0x00000060	/* Operand-dependent data.  */
+#define OPD_F_OD_LSB		5
+#define OPD_F_NO_ZR		0x00000080	/* ZR index not allowed.  */
 
 static inline bfd_boolean
 operand_has_inserter (const aarch64_operand *operand)
@@ -187,6 +194,13 @@ operand_maybe_stack_pointer (const aarch64_operand *operand)
   return (operand->flags & OPD_F_MAYBE_SP) ? TRUE : FALSE;
 }
 
+/* Return the value of the operand-specific data field (OPD_F_OD_MASK).  */
+static inline unsigned int
+get_operand_specific_data (const aarch64_operand *operand)
+{
+  return (operand->flags & OPD_F_OD_MASK) >> OPD_F_OD_LSB;
+}
+
 /* Return the total width of the operand *OPERAND.  */
 static inline unsigned
 get_operand_fields_width (const aarch64_operand *operand)
diff --git a/opcodes/aarch64-tbl.h b/opcodes/aarch64-tbl.h
index 491235f..aba4b2d 100644
--- a/opcodes/aarch64-tbl.h
+++ b/opcodes/aarch64-tbl.h
@@ -2818,8 +2818,95 @@ struct aarch64_opcode aarch64_opcode_table[] =
       "the ISB option name SY or an optional 4-bit unsigned immediate")	\
     Y(SYSTEM, prfop, "PRFOP", 0, F(),					\
       "a prefetch operation specifier")					\
-    Y (SYSTEM, hint, "BARRIER_PSB", 0, F (),				\
+    Y(SYSTEM, hint, "BARRIER_PSB", 0, F (),				\
       "the PSB option name CSYNC")					\
+    Y(ADDRESS, sve_addr_ri_u6, "SVE_ADDR_RI_U6", 0 << OPD_F_OD_LSB,	\
+      F(FLD_Rn), "an address with a 6-bit unsigned offset")		\
+    Y(ADDRESS, sve_addr_ri_u6, "SVE_ADDR_RI_U6x2", 1 << OPD_F_OD_LSB,	\
+      F(FLD_Rn),							\
+      "an address with a 6-bit unsigned offset, multiplied by 2")	\
+    Y(ADDRESS, sve_addr_ri_u6, "SVE_ADDR_RI_U6x4", 2 << OPD_F_OD_LSB,	\
+      F(FLD_Rn),							\
+      "an address with a 6-bit unsigned offset, multiplied by 4")	\
+    Y(ADDRESS, sve_addr_ri_u6, "SVE_ADDR_RI_U6x8", 3 << OPD_F_OD_LSB,	\
+      F(FLD_Rn),							\
+      "an address with a 6-bit unsigned offset, multiplied by 8")	\
+    Y(ADDRESS, sve_addr_rr_lsl, "SVE_ADDR_RR", 0 << OPD_F_OD_LSB,	\
+      F(FLD_Rn,FLD_Rm), "an address with a scalar register offset")	\
+    Y(ADDRESS, sve_addr_rr_lsl, "SVE_ADDR_RR_LSL1", 1 << OPD_F_OD_LSB,	\
+      F(FLD_Rn,FLD_Rm), "an address with a scalar register offset")	\
+    Y(ADDRESS, sve_addr_rr_lsl, "SVE_ADDR_RR_LSL2", 2 << OPD_F_OD_LSB,	\
+      F(FLD_Rn,FLD_Rm), "an address with a scalar register offset")	\
+    Y(ADDRESS, sve_addr_rr_lsl, "SVE_ADDR_RR_LSL3", 3 << OPD_F_OD_LSB,	\
+      F(FLD_Rn,FLD_Rm), "an address with a scalar register offset")	\
+    Y(ADDRESS, sve_addr_rr_lsl, "SVE_ADDR_RX",				\
+      (0 << OPD_F_OD_LSB) | OPD_F_NO_ZR, F(FLD_Rn,FLD_Rm),		\
+      "an address with a scalar register offset")			\
+    Y(ADDRESS, sve_addr_rr_lsl, "SVE_ADDR_RX_LSL1",			\
+      (1 << OPD_F_OD_LSB) | OPD_F_NO_ZR, F(FLD_Rn,FLD_Rm),		\
+      "an address with a scalar register offset")			\
+    Y(ADDRESS, sve_addr_rr_lsl, "SVE_ADDR_RX_LSL2",			\
+      (2 << OPD_F_OD_LSB) | OPD_F_NO_ZR, F(FLD_Rn,FLD_Rm),		\
+      "an address with a scalar register offset")			\
+    Y(ADDRESS, sve_addr_rr_lsl, "SVE_ADDR_RX_LSL3",			\
+      (3 << OPD_F_OD_LSB) | OPD_F_NO_ZR, F(FLD_Rn,FLD_Rm),		\
+      "an address with a scalar register offset")			\
+    Y(ADDRESS, sve_addr_rr_lsl, "SVE_ADDR_RZ", 0 << OPD_F_OD_LSB,	\
+      F(FLD_Rn,FLD_SVE_Zm_16),						\
+      "an address with a vector register offset")			\
+    Y(ADDRESS, sve_addr_rr_lsl, "SVE_ADDR_RZ_LSL1", 1 << OPD_F_OD_LSB,	\
+      F(FLD_Rn,FLD_SVE_Zm_16),						\
+      "an address with a vector register offset")			\
+    Y(ADDRESS, sve_addr_rr_lsl, "SVE_ADDR_RZ_LSL2", 2 << OPD_F_OD_LSB,	\
+      F(FLD_Rn,FLD_SVE_Zm_16),						\
+      "an address with a vector register offset")			\
+    Y(ADDRESS, sve_addr_rr_lsl, "SVE_ADDR_RZ_LSL3", 3 << OPD_F_OD_LSB,	\
+      F(FLD_Rn,FLD_SVE_Zm_16),						\
+      "an address with a vector register offset")			\
+    Y(ADDRESS, sve_addr_rz_xtw, "SVE_ADDR_RZ_XTW_14",			\
+      0 << OPD_F_OD_LSB, F(FLD_Rn,FLD_SVE_Zm_16,FLD_SVE_xs_14),		\
+      "an address with a vector register offset")			\
+    Y(ADDRESS, sve_addr_rz_xtw, "SVE_ADDR_RZ_XTW_22",			\
+      0 << OPD_F_OD_LSB, F(FLD_Rn,FLD_SVE_Zm_16,FLD_SVE_xs_22),		\
+      "an address with a vector register offset")			\
+    Y(ADDRESS, sve_addr_rz_xtw, "SVE_ADDR_RZ_XTW1_14",			\
+      1 << OPD_F_OD_LSB, F(FLD_Rn,FLD_SVE_Zm_16,FLD_SVE_xs_14),		\
+      "an address with a vector register offset")			\
+    Y(ADDRESS, sve_addr_rz_xtw, "SVE_ADDR_RZ_XTW1_22",			\
+      1 << OPD_F_OD_LSB, F(FLD_Rn,FLD_SVE_Zm_16,FLD_SVE_xs_22),		\
+      "an address with a vector register offset")			\
+    Y(ADDRESS, sve_addr_rz_xtw, "SVE_ADDR_RZ_XTW2_14",			\
+      2 << OPD_F_OD_LSB, F(FLD_Rn,FLD_SVE_Zm_16,FLD_SVE_xs_14),		\
+      "an address with a vector register offset")			\
+    Y(ADDRESS, sve_addr_rz_xtw, "SVE_ADDR_RZ_XTW2_22",			\
+      2 << OPD_F_OD_LSB, F(FLD_Rn,FLD_SVE_Zm_16,FLD_SVE_xs_22),		\
+      "an address with a vector register offset")			\
+    Y(ADDRESS, sve_addr_rz_xtw, "SVE_ADDR_RZ_XTW3_14",			\
+      3 << OPD_F_OD_LSB, F(FLD_Rn,FLD_SVE_Zm_16,FLD_SVE_xs_14),		\
+      "an address with a vector register offset")			\
+    Y(ADDRESS, sve_addr_rz_xtw, "SVE_ADDR_RZ_XTW3_22",			\
+      3 << OPD_F_OD_LSB, F(FLD_Rn,FLD_SVE_Zm_16,FLD_SVE_xs_22),		\
+      "an address with a vector register offset")			\
+    Y(ADDRESS, sve_addr_zi_u5, "SVE_ADDR_ZI_U5", 0 << OPD_F_OD_LSB,	\
+      F(FLD_SVE_Zn), "an address with a 5-bit unsigned offset")		\
+    Y(ADDRESS, sve_addr_zi_u5, "SVE_ADDR_ZI_U5x2", 1 << OPD_F_OD_LSB,	\
+      F(FLD_SVE_Zn),							\
+      "an address with a 5-bit unsigned offset, multiplied by 2")	\
+    Y(ADDRESS, sve_addr_zi_u5, "SVE_ADDR_ZI_U5x4", 2 << OPD_F_OD_LSB,	\
+      F(FLD_SVE_Zn),							\
+      "an address with a 5-bit unsigned offset, multiplied by 4")	\
+    Y(ADDRESS, sve_addr_zi_u5, "SVE_ADDR_ZI_U5x8", 3 << OPD_F_OD_LSB,	\
+      F(FLD_SVE_Zn),							\
+      "an address with a 5-bit unsigned offset, multiplied by 8")	\
+    Y(ADDRESS, sve_addr_zz_lsl, "SVE_ADDR_ZZ_LSL", 0,			\
+      F(FLD_SVE_Zn,FLD_SVE_Zm_16),					\
+      "an address with a vector register offset")			\
+    Y(ADDRESS, sve_addr_zz_sxtw, "SVE_ADDR_ZZ_SXTW", 0,			\
+      F(FLD_SVE_Zn,FLD_SVE_Zm_16),					\
+      "an address with a vector register offset")			\
+    Y(ADDRESS, sve_addr_zz_uxtw, "SVE_ADDR_ZZ_UXTW", 0,			\
+      F(FLD_SVE_Zn,FLD_SVE_Zm_16),					\
+      "an address with a vector register offset")			\
     Y(IMMEDIATE, imm, "SVE_PATTERN", 0, F(FLD_SVE_pattern),		\
       "an enumeration value such as POW2")				\
     Y(IMMEDIATE, sve_scale, "SVE_PATTERN_SCALED", 0,			\



More information about the Binutils mailing list