[1/2] aarch64: Add FEAT_MOPS_GO instructions

Message ID 20251202124417.3809316-2-yury.khrustalev@arm.com
State Superseded
Headers
Series aarch64: Add FEAT_MOPS_GO instructions |

Commit Message

Yury Khrustalev Dec. 2, 2025, 12:44 p.m. UTC
  ---
 gas/config/tc-aarch64.c  |   1 +
 include/opcode/aarch64.h |   2 +
 opcodes/aarch64-dis-2.c  | 128 +++++++++++++++++++++++++++++++++++++--
 opcodes/aarch64-opc.c    |  53 ++++++++++++----
 opcodes/aarch64-tbl-2.h  |  12 ++++
 opcodes/aarch64-tbl.h    |  32 ++++++++++
 6 files changed, 213 insertions(+), 15 deletions(-)
  

Comments

Alice Carlotti Dec. 17, 2025, 5:29 p.m. UTC | #1
On Tue, Dec 02, 2025 at 12:44:16PM +0000, Yury Khrustalev wrote:
> ---
>  gas/config/tc-aarch64.c  |   1 +
>  include/opcode/aarch64.h |   2 +
>  opcodes/aarch64-dis-2.c  | 128 +++++++++++++++++++++++++++++++++++++--
>  opcodes/aarch64-opc.c    |  53 ++++++++++++----
>  opcodes/aarch64-tbl-2.h  |  12 ++++
>  opcodes/aarch64-tbl.h    |  32 ++++++++++
>  6 files changed, 213 insertions(+), 15 deletions(-)
> 
> diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
> index 0ca54c3bd40..a8921c8be9e 100644
> --- a/gas/config/tc-aarch64.c
> +++ b/gas/config/tc-aarch64.c
> @@ -10905,6 +10905,7 @@ static const struct aarch64_option_cpu_value_table aarch64_features[] = {
>    {"ssve-fexpa",	AARCH64_FEATURE (SSVE_FEXPA), AARCH64_FEATURE (SME2)},
>    {"sme-tmop",		AARCH64_FEATURE (SME_TMOP), AARCH64_FEATURE (SME2)},
>    {"sme-mop4",		AARCH64_FEATURE (SME_MOP4), AARCH64_FEATURE (SME2)},
> +  {"mops-go",		AARCH64_FEATURE (MOPS_GO), AARCH64_FEATURE (MOPS)},
>    {NULL,		AARCH64_NO_FEATURES, AARCH64_NO_FEATURES},
>  };
>  
> diff --git a/include/opcode/aarch64.h b/include/opcode/aarch64.h
> index e65b61c3f9c..e9e1a6d9650 100644
> --- a/include/opcode/aarch64.h
> +++ b/include/opcode/aarch64.h
> @@ -290,6 +290,8 @@ enum aarch64_feature_bit {
>    AARCH64_FEATURE_SVE2p1_SME2p1,
>    /* +sve2p2 or +sme2p2 */
>    AARCH64_FEATURE_SVE2p2_SME2p2,
> +  /* +mops-go */
> +  AARCH64_FEATURE_MOPS_GO,
This should be inserted before the comment beginning "Virtual features" -
everything at the end of the enum is a virtual feature bit with no
corresponding command line flag.

>    AARCH64_NUM_FEATURES
>  };
>  
> diff --git a/opcodes/aarch64-dis-2.c b/opcodes/aarch64-dis-2.c
> index ecaea2d2fdb..e2a8c16ca3b 100644
> --- a/opcodes/aarch64-dis-2.c
> +++ b/opcodes/aarch64-dis-2.c
> @@ -27898,10 +27898,130 @@ aarch64_opcode_lookup_1 (uint32_t word)
>                              {
>                                if (((word >> 10) & 0x1) == 0)
>                                  {
> -                                  /* 33222222222211111111110000000000
> -                                     10987654321098765432109876543210
> -                                     xx011101x1xxxxxxxxxxx0xxxxxxxxxx.  */
> -                                  return A64_OPID_1d400800_ldapur_Ft_RCPC3_ADDR_OFFSET;
> +                                  if (((word >> 11) & 0x1) == 0)
> +                                    {
> +                                      if (((word >> 12) & 0x1) == 0)
> +                                        {
> +                                          if (((word >> 13) & 0x1) == 0)
> +                                            {
> +                                              if (((word >> 14) & 0x1) == 0)
> +                                                {
> +                                                  if (((word >> 15) & 0x1) == 0)
> +                                                    {
> +                                                      /* 33222222222211111111110000000000
> +                                                         10987654321098765432109876543210
> +                                                         xx011101x1xxxxxx000000xxxxxxxxxx.  */
> +                                                      return A64_OPID_1ddf0000_setgop_MOPS_ADDR_Rd_MOPS_WB_Rn;
> +                                                    }
> +                                                  else
> +                                                    {
> +                                                      /* 33222222222211111111110000000000
> +                                                         10987654321098765432109876543210
> +                                                         xx011101x1xxxxxx100000xxxxxxxxxx.  */
> +                                                      return A64_OPID_1ddf8000_setgoe_MOPS_ADDR_Rd_MOPS_WB_Rn;
> +                                                    }
> +                                                }
> +                                              else
> +                                                {
> +                                                  /* 33222222222211111111110000000000
> +                                                     10987654321098765432109876543210
> +                                                     xx011101x1xxxxxxx10000xxxxxxxxxx.  */
> +                                                  return A64_OPID_1ddf4000_setgom_MOPS_ADDR_Rd_MOPS_WB_Rn;
> +                                                }
> +                                            }
> +                                          else
> +                                            {
> +                                              if (((word >> 14) & 0x1) == 0)
> +                                                {
> +                                                  if (((word >> 15) & 0x1) == 0)
> +                                                    {
> +                                                      /* 33222222222211111111110000000000
> +                                                         10987654321098765432109876543210
> +                                                         xx011101x1xxxxxx001000xxxxxxxxxx.  */
> +                                                      return A64_OPID_1ddf2000_setgopn_MOPS_ADDR_Rd_MOPS_WB_Rn;
> +                                                    }
> +                                                  else
> +                                                    {
> +                                                      /* 33222222222211111111110000000000
> +                                                         10987654321098765432109876543210
> +                                                         xx011101x1xxxxxx101000xxxxxxxxxx.  */
> +                                                      return A64_OPID_1ddfa000_setgoen_MOPS_ADDR_Rd_MOPS_WB_Rn;
> +                                                    }
> +                                                }
> +                                              else
> +                                                {
> +                                                  /* 33222222222211111111110000000000
> +                                                     10987654321098765432109876543210
> +                                                     xx011101x1xxxxxxx11000xxxxxxxxxx.  */
> +                                                  return A64_OPID_1ddf6000_setgomn_MOPS_ADDR_Rd_MOPS_WB_Rn;
> +                                                }
> +                                            }
> +                                        }
> +                                      else
> +                                        {
> +                                          if (((word >> 13) & 0x1) == 0)
> +                                            {
> +                                              if (((word >> 14) & 0x1) == 0)
> +                                                {
> +                                                  if (((word >> 15) & 0x1) == 0)
> +                                                    {
> +                                                      /* 33222222222211111111110000000000
> +                                                         10987654321098765432109876543210
> +                                                         xx011101x1xxxxxx000100xxxxxxxxxx.  */
> +                                                      return A64_OPID_1ddf1000_setgopt_MOPS_ADDR_Rd_MOPS_WB_Rn;
> +                                                    }
> +                                                  else
> +                                                    {
> +                                                      /* 33222222222211111111110000000000
> +                                                         10987654321098765432109876543210
> +                                                         xx011101x1xxxxxx100100xxxxxxxxxx.  */
> +                                                      return A64_OPID_1ddf9000_setgoet_MOPS_ADDR_Rd_MOPS_WB_Rn;
> +                                                    }
> +                                                }
> +                                              else
> +                                                {
> +                                                  /* 33222222222211111111110000000000
> +                                                     10987654321098765432109876543210
> +                                                     xx011101x1xxxxxxx10100xxxxxxxxxx.  */
> +                                                  return A64_OPID_1ddf5000_setgomt_MOPS_ADDR_Rd_MOPS_WB_Rn;
> +                                                }
> +                                            }
> +                                          else
> +                                            {
> +                                              if (((word >> 14) & 0x1) == 0)
> +                                                {
> +                                                  if (((word >> 15) & 0x1) == 0)
> +                                                    {
> +                                                      /* 33222222222211111111110000000000
> +                                                         10987654321098765432109876543210
> +                                                         xx011101x1xxxxxx001100xxxxxxxxxx.  */
> +                                                      return A64_OPID_1ddf3000_setgoptn_MOPS_ADDR_Rd_MOPS_WB_Rn;
> +                                                    }
> +                                                  else
> +                                                    {
> +                                                      /* 33222222222211111111110000000000
> +                                                         10987654321098765432109876543210
> +                                                         xx011101x1xxxxxx101100xxxxxxxxxx.  */
> +                                                      return A64_OPID_1ddfb000_setgoetn_MOPS_ADDR_Rd_MOPS_WB_Rn;
> +                                                    }
> +                                                }
> +                                              else
> +                                                {
> +                                                  /* 33222222222211111111110000000000
> +                                                     10987654321098765432109876543210
> +                                                     xx011101x1xxxxxxx11100xxxxxxxxxx.  */
> +                                                  return A64_OPID_1ddf7000_setgomtn_MOPS_ADDR_Rd_MOPS_WB_Rn;
> +                                                }
> +                                            }
> +                                        }
> +                                    }
> +                                  else
> +                                    {
> +                                      /* 33222222222211111111110000000000
> +                                         10987654321098765432109876543210
> +                                         xx011101x1xxxxxxxxxx10xxxxxxxxxx.  */
> +                                      return A64_OPID_1d400800_ldapur_Ft_RCPC3_ADDR_OFFSET;
> +                                    }
>                                  }
>                                else
>                                  {
> diff --git a/opcodes/aarch64-opc.c b/opcodes/aarch64-opc.c
> index b074765920e..ef03dd1cfdb 100644
> --- a/opcodes/aarch64-opc.c
> +++ b/opcodes/aarch64-opc.c
> @@ -5587,6 +5587,22 @@ verify_elem_sd (const struct aarch64_inst *inst, const aarch64_insn insn,
>    return ERR_OK;
>  }
>  
> +
> +static enum err_type
> +verify_three_different_regs_impl (int rx, int ry, int rz,
> +				  aarch64_operand_error *mismatch_detail,
> +				  const char *error)
> +{
> +  if (rx == ry || rx == rz || ry == rz)
> +    {
> +      mismatch_detail->kind = AARCH64_OPDE_SYNTAX_ERROR;
> +      mismatch_detail->error = error;
> +      mismatch_detail->index = -1;
> +      return ERR_UND;
> +    }
> +  return ERR_OK;
> +}
> +
>  /* Check an instruction that takes three register operands and that
>     requires the register numbers to be distinct from one another.  */
>  
> @@ -5595,8 +5611,7 @@ verify_three_different_regs (const struct aarch64_inst *inst,
>  			     const aarch64_insn insn ATTRIBUTE_UNUSED,
>  			     bfd_vma pc ATTRIBUTE_UNUSED,
>  			     bool encoding ATTRIBUTE_UNUSED,
> -			     aarch64_operand_error *mismatch_detail
> -			       ATTRIBUTE_UNUSED,
> +			     aarch64_operand_error *mismatch_detail,
>  			     aarch64_instr_sequence *insn_sequence
>  			       ATTRIBUTE_UNUSED)
>  {
> @@ -5605,16 +5620,32 @@ verify_three_different_regs (const struct aarch64_inst *inst,
>    rd = inst->operands[0].reg.regno;
>    rs = inst->operands[1].reg.regno;
>    rn = inst->operands[2].reg.regno;
> -  if (rd == rs || rd == rn || rs == rn)
> -    {
> -      mismatch_detail->kind = AARCH64_OPDE_SYNTAX_ERROR;
> -      mismatch_detail->error
> -	= _("the three register operands must be distinct from one another");
> -      mismatch_detail->index = -1;
> -      return ERR_UND;
> -    }
>  
> -  return ERR_OK;
> +  return verify_three_different_regs_impl (rd, rs, rn, mismatch_detail,
> +    _("the three register operands must be distinct from one another"));
> +}

This change makes the code less readable.  The two verifiers are sufficiently
different that I don't think it's worth trying to share part of the
implementation.

> +
> +
> +/* Check an instruction that takes two register operands and that
> +   requires the register numbers to be distinct from one another
> +   and also different from 31.  */
> +
> +static enum err_type
> +verify_two_diff_regs_not_31 (const struct aarch64_inst *inst,
> +			     const aarch64_insn insn ATTRIBUTE_UNUSED,
> +			     bfd_vma pc ATTRIBUTE_UNUSED,
> +			     bool encoding ATTRIBUTE_UNUSED,
> +			     aarch64_operand_error *mismatch_detail,
> +			     aarch64_instr_sequence *insn_sequence
> +			       ATTRIBUTE_UNUSED)
> +{
> +  int rd, rn;
> +
> +  rd = inst->operands[0].reg.regno;
> +  rn = inst->operands[1].reg.regno;
> +
> +  return verify_three_different_regs_impl (rd, rn, 31, mismatch_detail,
> +    _("the two register operands must be distinct from each other"));

This would give the wrong error message if rd or rn were 31, but I think that
possibility is already ruled out by the existing choice of operand.  The only
necessary check here is for (rd != rn).

>  }
>  
>  /* Add INST to the end of INSN_SEQUENCE.  */
> diff --git a/opcodes/aarch64-tbl-2.h b/opcodes/aarch64-tbl-2.h
> index 1263f1f9bd8..993bffa7673 100644
> --- a/opcodes/aarch64-tbl-2.h
> +++ b/opcodes/aarch64-tbl-2.h
> @@ -3395,6 +3395,18 @@ enum aarch64_opcode_idx
>    A64_OPID_1dc03400_setgptn_MOPS_ADDR_Rd_MOPS_WB_Rn_Rm,
>    A64_OPID_1dc07400_setgmtn_MOPS_ADDR_Rd_MOPS_WB_Rn_Rm,
>    A64_OPID_1dc0b400_setgetn_MOPS_ADDR_Rd_MOPS_WB_Rn_Rm,
> +  A64_OPID_1ddf0000_setgop_MOPS_ADDR_Rd_MOPS_WB_Rn,
> +  A64_OPID_1ddf4000_setgom_MOPS_ADDR_Rd_MOPS_WB_Rn,
> +  A64_OPID_1ddf8000_setgoe_MOPS_ADDR_Rd_MOPS_WB_Rn,
> +  A64_OPID_1ddf1000_setgopt_MOPS_ADDR_Rd_MOPS_WB_Rn,
> +  A64_OPID_1ddf5000_setgomt_MOPS_ADDR_Rd_MOPS_WB_Rn,
> +  A64_OPID_1ddf9000_setgoet_MOPS_ADDR_Rd_MOPS_WB_Rn,
> +  A64_OPID_1ddf2000_setgopn_MOPS_ADDR_Rd_MOPS_WB_Rn,
> +  A64_OPID_1ddf6000_setgomn_MOPS_ADDR_Rd_MOPS_WB_Rn,
> +  A64_OPID_1ddfa000_setgoen_MOPS_ADDR_Rd_MOPS_WB_Rn,
> +  A64_OPID_1ddf3000_setgoptn_MOPS_ADDR_Rd_MOPS_WB_Rn,
> +  A64_OPID_1ddf7000_setgomtn_MOPS_ADDR_Rd_MOPS_WB_Rn,
> +  A64_OPID_1ddfb000_setgoetn_MOPS_ADDR_Rd_MOPS_WB_Rn,
>    A64_OPID_54000010_bc_c_ADDR_PCREL19,
>    A64_OPID_11c00000_smax_Rd_Rn_CSSC_SIMM8,
>    A64_OPID_11c40000_umax_Rd_Rn_CSSC_UIMM8,
> diff --git a/opcodes/aarch64-tbl.h b/opcodes/aarch64-tbl.h
> index 2fc69c27791..e596a2c54ee 100644
> --- a/opcodes/aarch64-tbl.h
> +++ b/opcodes/aarch64-tbl.h
> @@ -2927,6 +2927,8 @@ static const aarch64_feature_set aarch64_feature_mops =
>    AARCH64_FEATURE (MOPS);
>  static const aarch64_feature_set aarch64_feature_mops_memtag =
>    AARCH64_FEATURES (2, MOPS, MEMTAG);
> +static const aarch64_feature_set aarch64_feature_mops_go_memtag =
> +  AARCH64_FEATURES (2, MOPS_GO, MEMTAG);
>  static const aarch64_feature_set aarch64_feature_hbc =
>    AARCH64_FEATURE (HBC);
>  static const aarch64_feature_set aarch64_feature_cssc =
> @@ -3116,6 +3118,7 @@ static const aarch64_feature_set aarch64_feature_sme_mop4_i16i64 =
>  #define WFXT	  &aarch64_feature_wfxt
>  #define MOPS	  &aarch64_feature_mops
>  #define MOPS_MEMTAG &aarch64_feature_mops_memtag
> +#define MOPS_GO_MEMTAG &aarch64_feature_mops_go_memtag
>  #define HBC	  &aarch64_feature_hbc
>  #define CSSC	  &aarch64_feature_cssc
>  #define CHK	  &aarch64_feature_chk
> @@ -3371,6 +3374,9 @@ static const aarch64_feature_set aarch64_feature_sme_mop4_i16i64 =
>  #define MOPS_MEMTAG_INSN(NAME, OPCODE, MASK, CLASS, OPS, QUALS, FLAGS, CONSTRAINTS, VERIFIER) \
>    { NAME, OPCODE, MASK, CLASS, 0, MOPS_MEMTAG, OPS, QUALS, FLAGS, \
>      CONSTRAINTS, 0, VERIFIER }
> +#define MOPS_GO_MEMTAG_INSN(NAME, OPCODE, MASK, CLASS, OPS, QUALS, FLAGS, CONSTRAINTS, VERIFIER) \
> +  { NAME, OPCODE, MASK, CLASS, 0, MOPS_GO_MEMTAG, OPS, QUALS, FLAGS, \
> +    CONSTRAINTS, 0, VERIFIER }
>  #define HBC_INSN(NAME,OPCODE,MASK,CLASS,OPS,QUALS,FLAGS) \
>    { NAME, OPCODE, MASK, CLASS, 0, HBC, OPS, QUALS, FLAGS, 0, 0, NULL }
>  #define CSSC_INSN(NAME,OPCODE,MASK,OPS,QUALS,FLAGS) \
> @@ -3543,6 +3549,11 @@ static const aarch64_feature_set aarch64_feature_sme_mop4_i16i64 =
>         OP3 (MOPS_ADDR_Rd, MOPS_WB_Rn, Rm), QL_I3SAMEX, FLAGS, \
>         CONSTRAINTS, VERIFIER (three_different_regs))
>  
> +#define MOPS_GO_SET_OP1_OP2_PME_INSN(NAME, OPCODE, MASK, FLAGS, CONSTRAINTS, ISA) \
> +  ISA (NAME, OPCODE, MASK, 0, \
> +       OP2 (MOPS_ADDR_Rd, MOPS_WB_Rn), QL_I2SAMEX, FLAGS, \
> +       CONSTRAINTS, VERIFIER (two_diff_regs_not_31))
> +
>  /* These instructions must remain consecutive, since we rely on the order
>     when detecting invalid sequences.  */
>  #define MOPS_SET_OP1_OP2_INSN(NAME, SUFFIX, OPCODE, MASK, ISA) \
> @@ -3553,12 +3564,28 @@ static const aarch64_feature_set aarch64_feature_sme_mop4_i16i64 =
>    MOPS_SET_OP1_OP2_PME_INSN (NAME "e" SUFFIX, OPCODE | 0x8000, MASK, \
>  			     0, C_SCAN_MOPS_E, ISA)
>  
> +/* These instructions must remain consecutive, since we rely on the order
> +   when detecting invalid sequences.  */
> +#define MOPS_GO_SET_OP1_OP2_INSN(NAME, SUFFIX, OPCODE, MASK, ISA) \
> +  MOPS_GO_SET_OP1_OP2_PME_INSN (NAME "p" SUFFIX, OPCODE, MASK, \
> +				F_SCAN, C_SCAN_MOPS_P, ISA), \
> +  MOPS_GO_SET_OP1_OP2_PME_INSN (NAME "m" SUFFIX, OPCODE | 0x4000, MASK, \
> +				0, C_SCAN_MOPS_M, ISA), \
> +  MOPS_GO_SET_OP1_OP2_PME_INSN (NAME "e" SUFFIX, OPCODE | 0x8000, MASK, \
> +				0, C_SCAN_MOPS_E, ISA)
> +
>  #define MOPS_SET_INSN(NAME, OPCODE, MASK, ISA) \
>    MOPS_SET_OP1_OP2_INSN (NAME, "", OPCODE, MASK, ISA), \
>    MOPS_SET_OP1_OP2_INSN (NAME, "t", OPCODE | 0x1000, MASK, ISA), \
>    MOPS_SET_OP1_OP2_INSN (NAME, "n", OPCODE | 0x2000, MASK, ISA), \
>    MOPS_SET_OP1_OP2_INSN (NAME, "tn", OPCODE | 0x3000, MASK, ISA)
>  
> +#define MOPS_GO_SET_INSN(NAME, OPCODE, MASK, ISA) \
> +  MOPS_GO_SET_OP1_OP2_INSN (NAME, "", OPCODE, MASK, ISA), \
> +  MOPS_GO_SET_OP1_OP2_INSN (NAME, "t", OPCODE | 0x1000, MASK, ISA), \
> +  MOPS_GO_SET_OP1_OP2_INSN (NAME, "n", OPCODE | 0x2000, MASK, ISA), \
> +  MOPS_GO_SET_OP1_OP2_INSN (NAME, "tn", OPCODE | 0x3000, MASK, ISA)
> +
>  #define PREDRES2_INSN(NAME,OPCODE,MASK,CLASS,OPS,QUALS,FLAGS) \
>    { NAME, OPCODE, MASK, CLASS, 0, PREDRES2, OPS, QUALS, FLAGS, 0, 0, NULL }
>  
> @@ -7031,6 +7058,11 @@ const struct aarch64_opcode aarch64_opcode_table[] =
>       setge setget setgen setgetn  */
>    MOPS_SET_INSN ("setg", 0x1dc00400, 0xffe0fc00, MOPS_MEMTAG_INSN),
>  
> +  /* setgop setgopt setgopn setgoptn
> +     setgom setgomt setgomn setgomtn
> +     setgoe setgoet setgoen setgoetn  */
> +  MOPS_GO_SET_INSN ("setgo", 0x1ddf0000, 0x3ffffc00, MOPS_GO_MEMTAG_INSN),
> +
>    HBC_INSN ("bc.c", 0x54000010, 0xff000010, condbranch, OP1 (ADDR_PCREL19), QL_PCREL_NIL, F_COND),
>  
>  /* CSSC with immediates.  */
> -- 
> 2.47.3
>
  
Alice Carlotti Dec. 17, 2025, 5:59 p.m. UTC | #2
On Tue, Dec 02, 2025 at 12:44:16PM +0000, Yury Khrustalev wrote:
One more comment - I think there should be a dependency from +mops-go ->
+memtag, and the instructions would then only need to depend directly upon
MOPS_GO (although I haven't yet confirmed this with the LLVM team).  In that
case, as well as adjusting the feature dependencies, we could drop '_memtag'
from the names below and remove '+memtag' from the tests.


Also, could you combine these two patches please?  I think it's better to add
the tests for new instruction as part of the patch that introduces those
instructions.

Alice

> diff --git a/opcodes/aarch64-tbl.h b/opcodes/aarch64-tbl.h
> index 2fc69c27791..e596a2c54ee 100644
> --- a/opcodes/aarch64-tbl.h
> +++ b/opcodes/aarch64-tbl.h
> @@ -2927,6 +2927,8 @@ static const aarch64_feature_set aarch64_feature_mops =
>    AARCH64_FEATURE (MOPS);
>  static const aarch64_feature_set aarch64_feature_mops_memtag =
>    AARCH64_FEATURES (2, MOPS, MEMTAG);
> +static const aarch64_feature_set aarch64_feature_mops_go_memtag =
> +  AARCH64_FEATURES (2, MOPS_GO, MEMTAG);
>  static const aarch64_feature_set aarch64_feature_hbc =
>    AARCH64_FEATURE (HBC);
>  static const aarch64_feature_set aarch64_feature_cssc =
> @@ -3116,6 +3118,7 @@ static const aarch64_feature_set aarch64_feature_sme_mop4_i16i64 =
>  #define WFXT	  &aarch64_feature_wfxt
>  #define MOPS	  &aarch64_feature_mops
>  #define MOPS_MEMTAG &aarch64_feature_mops_memtag
> +#define MOPS_GO_MEMTAG &aarch64_feature_mops_go_memtag
>  #define HBC	  &aarch64_feature_hbc
>  #define CSSC	  &aarch64_feature_cssc
>  #define CHK	  &aarch64_feature_chk
> @@ -3371,6 +3374,9 @@ static const aarch64_feature_set aarch64_feature_sme_mop4_i16i64 =
>  #define MOPS_MEMTAG_INSN(NAME, OPCODE, MASK, CLASS, OPS, QUALS, FLAGS, CONSTRAINTS, VERIFIER) \
>    { NAME, OPCODE, MASK, CLASS, 0, MOPS_MEMTAG, OPS, QUALS, FLAGS, \
>      CONSTRAINTS, 0, VERIFIER }
> +#define MOPS_GO_MEMTAG_INSN(NAME, OPCODE, MASK, CLASS, OPS, QUALS, FLAGS, CONSTRAINTS, VERIFIER) \
> +  { NAME, OPCODE, MASK, CLASS, 0, MOPS_GO_MEMTAG, OPS, QUALS, FLAGS, \
> +    CONSTRAINTS, 0, VERIFIER }
>  #define HBC_INSN(NAME,OPCODE,MASK,CLASS,OPS,QUALS,FLAGS) \
>    { NAME, OPCODE, MASK, CLASS, 0, HBC, OPS, QUALS, FLAGS, 0, 0, NULL }
>  #define CSSC_INSN(NAME,OPCODE,MASK,OPS,QUALS,FLAGS) \
  

Patch

diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
index 0ca54c3bd40..a8921c8be9e 100644
--- a/gas/config/tc-aarch64.c
+++ b/gas/config/tc-aarch64.c
@@ -10905,6 +10905,7 @@  static const struct aarch64_option_cpu_value_table aarch64_features[] = {
   {"ssve-fexpa",	AARCH64_FEATURE (SSVE_FEXPA), AARCH64_FEATURE (SME2)},
   {"sme-tmop",		AARCH64_FEATURE (SME_TMOP), AARCH64_FEATURE (SME2)},
   {"sme-mop4",		AARCH64_FEATURE (SME_MOP4), AARCH64_FEATURE (SME2)},
+  {"mops-go",		AARCH64_FEATURE (MOPS_GO), AARCH64_FEATURE (MOPS)},
   {NULL,		AARCH64_NO_FEATURES, AARCH64_NO_FEATURES},
 };
 
diff --git a/include/opcode/aarch64.h b/include/opcode/aarch64.h
index e65b61c3f9c..e9e1a6d9650 100644
--- a/include/opcode/aarch64.h
+++ b/include/opcode/aarch64.h
@@ -290,6 +290,8 @@  enum aarch64_feature_bit {
   AARCH64_FEATURE_SVE2p1_SME2p1,
   /* +sve2p2 or +sme2p2 */
   AARCH64_FEATURE_SVE2p2_SME2p2,
+  /* +mops-go */
+  AARCH64_FEATURE_MOPS_GO,
   AARCH64_NUM_FEATURES
 };
 
diff --git a/opcodes/aarch64-dis-2.c b/opcodes/aarch64-dis-2.c
index ecaea2d2fdb..e2a8c16ca3b 100644
--- a/opcodes/aarch64-dis-2.c
+++ b/opcodes/aarch64-dis-2.c
@@ -27898,10 +27898,130 @@  aarch64_opcode_lookup_1 (uint32_t word)
                             {
                               if (((word >> 10) & 0x1) == 0)
                                 {
-                                  /* 33222222222211111111110000000000
-                                     10987654321098765432109876543210
-                                     xx011101x1xxxxxxxxxxx0xxxxxxxxxx.  */
-                                  return A64_OPID_1d400800_ldapur_Ft_RCPC3_ADDR_OFFSET;
+                                  if (((word >> 11) & 0x1) == 0)
+                                    {
+                                      if (((word >> 12) & 0x1) == 0)
+                                        {
+                                          if (((word >> 13) & 0x1) == 0)
+                                            {
+                                              if (((word >> 14) & 0x1) == 0)
+                                                {
+                                                  if (((word >> 15) & 0x1) == 0)
+                                                    {
+                                                      /* 33222222222211111111110000000000
+                                                         10987654321098765432109876543210
+                                                         xx011101x1xxxxxx000000xxxxxxxxxx.  */
+                                                      return A64_OPID_1ddf0000_setgop_MOPS_ADDR_Rd_MOPS_WB_Rn;
+                                                    }
+                                                  else
+                                                    {
+                                                      /* 33222222222211111111110000000000
+                                                         10987654321098765432109876543210
+                                                         xx011101x1xxxxxx100000xxxxxxxxxx.  */
+                                                      return A64_OPID_1ddf8000_setgoe_MOPS_ADDR_Rd_MOPS_WB_Rn;
+                                                    }
+                                                }
+                                              else
+                                                {
+                                                  /* 33222222222211111111110000000000
+                                                     10987654321098765432109876543210
+                                                     xx011101x1xxxxxxx10000xxxxxxxxxx.  */
+                                                  return A64_OPID_1ddf4000_setgom_MOPS_ADDR_Rd_MOPS_WB_Rn;
+                                                }
+                                            }
+                                          else
+                                            {
+                                              if (((word >> 14) & 0x1) == 0)
+                                                {
+                                                  if (((word >> 15) & 0x1) == 0)
+                                                    {
+                                                      /* 33222222222211111111110000000000
+                                                         10987654321098765432109876543210
+                                                         xx011101x1xxxxxx001000xxxxxxxxxx.  */
+                                                      return A64_OPID_1ddf2000_setgopn_MOPS_ADDR_Rd_MOPS_WB_Rn;
+                                                    }
+                                                  else
+                                                    {
+                                                      /* 33222222222211111111110000000000
+                                                         10987654321098765432109876543210
+                                                         xx011101x1xxxxxx101000xxxxxxxxxx.  */
+                                                      return A64_OPID_1ddfa000_setgoen_MOPS_ADDR_Rd_MOPS_WB_Rn;
+                                                    }
+                                                }
+                                              else
+                                                {
+                                                  /* 33222222222211111111110000000000
+                                                     10987654321098765432109876543210
+                                                     xx011101x1xxxxxxx11000xxxxxxxxxx.  */
+                                                  return A64_OPID_1ddf6000_setgomn_MOPS_ADDR_Rd_MOPS_WB_Rn;
+                                                }
+                                            }
+                                        }
+                                      else
+                                        {
+                                          if (((word >> 13) & 0x1) == 0)
+                                            {
+                                              if (((word >> 14) & 0x1) == 0)
+                                                {
+                                                  if (((word >> 15) & 0x1) == 0)
+                                                    {
+                                                      /* 33222222222211111111110000000000
+                                                         10987654321098765432109876543210
+                                                         xx011101x1xxxxxx000100xxxxxxxxxx.  */
+                                                      return A64_OPID_1ddf1000_setgopt_MOPS_ADDR_Rd_MOPS_WB_Rn;
+                                                    }
+                                                  else
+                                                    {
+                                                      /* 33222222222211111111110000000000
+                                                         10987654321098765432109876543210
+                                                         xx011101x1xxxxxx100100xxxxxxxxxx.  */
+                                                      return A64_OPID_1ddf9000_setgoet_MOPS_ADDR_Rd_MOPS_WB_Rn;
+                                                    }
+                                                }
+                                              else
+                                                {
+                                                  /* 33222222222211111111110000000000
+                                                     10987654321098765432109876543210
+                                                     xx011101x1xxxxxxx10100xxxxxxxxxx.  */
+                                                  return A64_OPID_1ddf5000_setgomt_MOPS_ADDR_Rd_MOPS_WB_Rn;
+                                                }
+                                            }
+                                          else
+                                            {
+                                              if (((word >> 14) & 0x1) == 0)
+                                                {
+                                                  if (((word >> 15) & 0x1) == 0)
+                                                    {
+                                                      /* 33222222222211111111110000000000
+                                                         10987654321098765432109876543210
+                                                         xx011101x1xxxxxx001100xxxxxxxxxx.  */
+                                                      return A64_OPID_1ddf3000_setgoptn_MOPS_ADDR_Rd_MOPS_WB_Rn;
+                                                    }
+                                                  else
+                                                    {
+                                                      /* 33222222222211111111110000000000
+                                                         10987654321098765432109876543210
+                                                         xx011101x1xxxxxx101100xxxxxxxxxx.  */
+                                                      return A64_OPID_1ddfb000_setgoetn_MOPS_ADDR_Rd_MOPS_WB_Rn;
+                                                    }
+                                                }
+                                              else
+                                                {
+                                                  /* 33222222222211111111110000000000
+                                                     10987654321098765432109876543210
+                                                     xx011101x1xxxxxxx11100xxxxxxxxxx.  */
+                                                  return A64_OPID_1ddf7000_setgomtn_MOPS_ADDR_Rd_MOPS_WB_Rn;
+                                                }
+                                            }
+                                        }
+                                    }
+                                  else
+                                    {
+                                      /* 33222222222211111111110000000000
+                                         10987654321098765432109876543210
+                                         xx011101x1xxxxxxxxxx10xxxxxxxxxx.  */
+                                      return A64_OPID_1d400800_ldapur_Ft_RCPC3_ADDR_OFFSET;
+                                    }
                                 }
                               else
                                 {
diff --git a/opcodes/aarch64-opc.c b/opcodes/aarch64-opc.c
index b074765920e..ef03dd1cfdb 100644
--- a/opcodes/aarch64-opc.c
+++ b/opcodes/aarch64-opc.c
@@ -5587,6 +5587,22 @@  verify_elem_sd (const struct aarch64_inst *inst, const aarch64_insn insn,
   return ERR_OK;
 }
 
+
+static enum err_type
+verify_three_different_regs_impl (int rx, int ry, int rz,
+				  aarch64_operand_error *mismatch_detail,
+				  const char *error)
+{
+  if (rx == ry || rx == rz || ry == rz)
+    {
+      mismatch_detail->kind = AARCH64_OPDE_SYNTAX_ERROR;
+      mismatch_detail->error = error;
+      mismatch_detail->index = -1;
+      return ERR_UND;
+    }
+  return ERR_OK;
+}
+
 /* Check an instruction that takes three register operands and that
    requires the register numbers to be distinct from one another.  */
 
@@ -5595,8 +5611,7 @@  verify_three_different_regs (const struct aarch64_inst *inst,
 			     const aarch64_insn insn ATTRIBUTE_UNUSED,
 			     bfd_vma pc ATTRIBUTE_UNUSED,
 			     bool encoding ATTRIBUTE_UNUSED,
-			     aarch64_operand_error *mismatch_detail
-			       ATTRIBUTE_UNUSED,
+			     aarch64_operand_error *mismatch_detail,
 			     aarch64_instr_sequence *insn_sequence
 			       ATTRIBUTE_UNUSED)
 {
@@ -5605,16 +5620,32 @@  verify_three_different_regs (const struct aarch64_inst *inst,
   rd = inst->operands[0].reg.regno;
   rs = inst->operands[1].reg.regno;
   rn = inst->operands[2].reg.regno;
-  if (rd == rs || rd == rn || rs == rn)
-    {
-      mismatch_detail->kind = AARCH64_OPDE_SYNTAX_ERROR;
-      mismatch_detail->error
-	= _("the three register operands must be distinct from one another");
-      mismatch_detail->index = -1;
-      return ERR_UND;
-    }
 
-  return ERR_OK;
+  return verify_three_different_regs_impl (rd, rs, rn, mismatch_detail,
+    _("the three register operands must be distinct from one another"));
+}
+
+
+/* Check an instruction that takes two register operands and that
+   requires the register numbers to be distinct from one another
+   and also different from 31.  */
+
+static enum err_type
+verify_two_diff_regs_not_31 (const struct aarch64_inst *inst,
+			     const aarch64_insn insn ATTRIBUTE_UNUSED,
+			     bfd_vma pc ATTRIBUTE_UNUSED,
+			     bool encoding ATTRIBUTE_UNUSED,
+			     aarch64_operand_error *mismatch_detail,
+			     aarch64_instr_sequence *insn_sequence
+			       ATTRIBUTE_UNUSED)
+{
+  int rd, rn;
+
+  rd = inst->operands[0].reg.regno;
+  rn = inst->operands[1].reg.regno;
+
+  return verify_three_different_regs_impl (rd, rn, 31, mismatch_detail,
+    _("the two register operands must be distinct from each other"));
 }
 
 /* Add INST to the end of INSN_SEQUENCE.  */
diff --git a/opcodes/aarch64-tbl-2.h b/opcodes/aarch64-tbl-2.h
index 1263f1f9bd8..993bffa7673 100644
--- a/opcodes/aarch64-tbl-2.h
+++ b/opcodes/aarch64-tbl-2.h
@@ -3395,6 +3395,18 @@  enum aarch64_opcode_idx
   A64_OPID_1dc03400_setgptn_MOPS_ADDR_Rd_MOPS_WB_Rn_Rm,
   A64_OPID_1dc07400_setgmtn_MOPS_ADDR_Rd_MOPS_WB_Rn_Rm,
   A64_OPID_1dc0b400_setgetn_MOPS_ADDR_Rd_MOPS_WB_Rn_Rm,
+  A64_OPID_1ddf0000_setgop_MOPS_ADDR_Rd_MOPS_WB_Rn,
+  A64_OPID_1ddf4000_setgom_MOPS_ADDR_Rd_MOPS_WB_Rn,
+  A64_OPID_1ddf8000_setgoe_MOPS_ADDR_Rd_MOPS_WB_Rn,
+  A64_OPID_1ddf1000_setgopt_MOPS_ADDR_Rd_MOPS_WB_Rn,
+  A64_OPID_1ddf5000_setgomt_MOPS_ADDR_Rd_MOPS_WB_Rn,
+  A64_OPID_1ddf9000_setgoet_MOPS_ADDR_Rd_MOPS_WB_Rn,
+  A64_OPID_1ddf2000_setgopn_MOPS_ADDR_Rd_MOPS_WB_Rn,
+  A64_OPID_1ddf6000_setgomn_MOPS_ADDR_Rd_MOPS_WB_Rn,
+  A64_OPID_1ddfa000_setgoen_MOPS_ADDR_Rd_MOPS_WB_Rn,
+  A64_OPID_1ddf3000_setgoptn_MOPS_ADDR_Rd_MOPS_WB_Rn,
+  A64_OPID_1ddf7000_setgomtn_MOPS_ADDR_Rd_MOPS_WB_Rn,
+  A64_OPID_1ddfb000_setgoetn_MOPS_ADDR_Rd_MOPS_WB_Rn,
   A64_OPID_54000010_bc_c_ADDR_PCREL19,
   A64_OPID_11c00000_smax_Rd_Rn_CSSC_SIMM8,
   A64_OPID_11c40000_umax_Rd_Rn_CSSC_UIMM8,
diff --git a/opcodes/aarch64-tbl.h b/opcodes/aarch64-tbl.h
index 2fc69c27791..e596a2c54ee 100644
--- a/opcodes/aarch64-tbl.h
+++ b/opcodes/aarch64-tbl.h
@@ -2927,6 +2927,8 @@  static const aarch64_feature_set aarch64_feature_mops =
   AARCH64_FEATURE (MOPS);
 static const aarch64_feature_set aarch64_feature_mops_memtag =
   AARCH64_FEATURES (2, MOPS, MEMTAG);
+static const aarch64_feature_set aarch64_feature_mops_go_memtag =
+  AARCH64_FEATURES (2, MOPS_GO, MEMTAG);
 static const aarch64_feature_set aarch64_feature_hbc =
   AARCH64_FEATURE (HBC);
 static const aarch64_feature_set aarch64_feature_cssc =
@@ -3116,6 +3118,7 @@  static const aarch64_feature_set aarch64_feature_sme_mop4_i16i64 =
 #define WFXT	  &aarch64_feature_wfxt
 #define MOPS	  &aarch64_feature_mops
 #define MOPS_MEMTAG &aarch64_feature_mops_memtag
+#define MOPS_GO_MEMTAG &aarch64_feature_mops_go_memtag
 #define HBC	  &aarch64_feature_hbc
 #define CSSC	  &aarch64_feature_cssc
 #define CHK	  &aarch64_feature_chk
@@ -3371,6 +3374,9 @@  static const aarch64_feature_set aarch64_feature_sme_mop4_i16i64 =
 #define MOPS_MEMTAG_INSN(NAME, OPCODE, MASK, CLASS, OPS, QUALS, FLAGS, CONSTRAINTS, VERIFIER) \
   { NAME, OPCODE, MASK, CLASS, 0, MOPS_MEMTAG, OPS, QUALS, FLAGS, \
     CONSTRAINTS, 0, VERIFIER }
+#define MOPS_GO_MEMTAG_INSN(NAME, OPCODE, MASK, CLASS, OPS, QUALS, FLAGS, CONSTRAINTS, VERIFIER) \
+  { NAME, OPCODE, MASK, CLASS, 0, MOPS_GO_MEMTAG, OPS, QUALS, FLAGS, \
+    CONSTRAINTS, 0, VERIFIER }
 #define HBC_INSN(NAME,OPCODE,MASK,CLASS,OPS,QUALS,FLAGS) \
   { NAME, OPCODE, MASK, CLASS, 0, HBC, OPS, QUALS, FLAGS, 0, 0, NULL }
 #define CSSC_INSN(NAME,OPCODE,MASK,OPS,QUALS,FLAGS) \
@@ -3543,6 +3549,11 @@  static const aarch64_feature_set aarch64_feature_sme_mop4_i16i64 =
        OP3 (MOPS_ADDR_Rd, MOPS_WB_Rn, Rm), QL_I3SAMEX, FLAGS, \
        CONSTRAINTS, VERIFIER (three_different_regs))
 
+#define MOPS_GO_SET_OP1_OP2_PME_INSN(NAME, OPCODE, MASK, FLAGS, CONSTRAINTS, ISA) \
+  ISA (NAME, OPCODE, MASK, 0, \
+       OP2 (MOPS_ADDR_Rd, MOPS_WB_Rn), QL_I2SAMEX, FLAGS, \
+       CONSTRAINTS, VERIFIER (two_diff_regs_not_31))
+
 /* These instructions must remain consecutive, since we rely on the order
    when detecting invalid sequences.  */
 #define MOPS_SET_OP1_OP2_INSN(NAME, SUFFIX, OPCODE, MASK, ISA) \
@@ -3553,12 +3564,28 @@  static const aarch64_feature_set aarch64_feature_sme_mop4_i16i64 =
   MOPS_SET_OP1_OP2_PME_INSN (NAME "e" SUFFIX, OPCODE | 0x8000, MASK, \
 			     0, C_SCAN_MOPS_E, ISA)
 
+/* These instructions must remain consecutive, since we rely on the order
+   when detecting invalid sequences.  */
+#define MOPS_GO_SET_OP1_OP2_INSN(NAME, SUFFIX, OPCODE, MASK, ISA) \
+  MOPS_GO_SET_OP1_OP2_PME_INSN (NAME "p" SUFFIX, OPCODE, MASK, \
+				F_SCAN, C_SCAN_MOPS_P, ISA), \
+  MOPS_GO_SET_OP1_OP2_PME_INSN (NAME "m" SUFFIX, OPCODE | 0x4000, MASK, \
+				0, C_SCAN_MOPS_M, ISA), \
+  MOPS_GO_SET_OP1_OP2_PME_INSN (NAME "e" SUFFIX, OPCODE | 0x8000, MASK, \
+				0, C_SCAN_MOPS_E, ISA)
+
 #define MOPS_SET_INSN(NAME, OPCODE, MASK, ISA) \
   MOPS_SET_OP1_OP2_INSN (NAME, "", OPCODE, MASK, ISA), \
   MOPS_SET_OP1_OP2_INSN (NAME, "t", OPCODE | 0x1000, MASK, ISA), \
   MOPS_SET_OP1_OP2_INSN (NAME, "n", OPCODE | 0x2000, MASK, ISA), \
   MOPS_SET_OP1_OP2_INSN (NAME, "tn", OPCODE | 0x3000, MASK, ISA)
 
+#define MOPS_GO_SET_INSN(NAME, OPCODE, MASK, ISA) \
+  MOPS_GO_SET_OP1_OP2_INSN (NAME, "", OPCODE, MASK, ISA), \
+  MOPS_GO_SET_OP1_OP2_INSN (NAME, "t", OPCODE | 0x1000, MASK, ISA), \
+  MOPS_GO_SET_OP1_OP2_INSN (NAME, "n", OPCODE | 0x2000, MASK, ISA), \
+  MOPS_GO_SET_OP1_OP2_INSN (NAME, "tn", OPCODE | 0x3000, MASK, ISA)
+
 #define PREDRES2_INSN(NAME,OPCODE,MASK,CLASS,OPS,QUALS,FLAGS) \
   { NAME, OPCODE, MASK, CLASS, 0, PREDRES2, OPS, QUALS, FLAGS, 0, 0, NULL }
 
@@ -7031,6 +7058,11 @@  const struct aarch64_opcode aarch64_opcode_table[] =
      setge setget setgen setgetn  */
   MOPS_SET_INSN ("setg", 0x1dc00400, 0xffe0fc00, MOPS_MEMTAG_INSN),
 
+  /* setgop setgopt setgopn setgoptn
+     setgom setgomt setgomn setgomtn
+     setgoe setgoet setgoen setgoetn  */
+  MOPS_GO_SET_INSN ("setgo", 0x1ddf0000, 0x3ffffc00, MOPS_GO_MEMTAG_INSN),
+
   HBC_INSN ("bc.c", 0x54000010, 0xff000010, condbranch, OP1 (ADDR_PCREL19), QL_PCREL_NIL, F_COND),
 
 /* CSSC with immediates.  */