[PATCH] aarch64: Add support for FEAT_CMH

Alice Carlotti alice.carlotti@arm.com
Wed Jan 14 04:39:36 GMT 2026


On Fri, Jan 09, 2026 at 11:42:52AM +0000, richard.ball@arm.com wrote:
> From: Richard Ball <Richard.Ball@arm.com>
> 
> This patch adds the new instructions from FEAT_CMH
> These new instructions are hints, STCPH and SHUH.
> SHUH can have an operand PH or no operand.
> ---
>  gas/config/tc-aarch64.c             |  6 +++++-
>  gas/testsuite/gas/aarch64/cmh-bad.d |  4 ++++
>  gas/testsuite/gas/aarch64/cmh-bad.l |  3 +++
>  gas/testsuite/gas/aarch64/cmh-bad.s |  3 +++
>  gas/testsuite/gas/aarch64/cmh.d     | 11 +++++++++++
>  gas/testsuite/gas/aarch64/cmh.s     |  4 ++++
>  gas/testsuite/gas/aarch64/system.d  |  6 +++---
>  include/opcode/aarch64.h            |  2 ++
>  opcodes/aarch64-asm-2.c             |  3 +++
>  opcodes/aarch64-dis-2.c             |  7 +++++++
>  opcodes/aarch64-opc-2.c             |  1 +
>  opcodes/aarch64-opc.c               |  8 ++++++++
>  opcodes/aarch64-opc.h               |  3 +++
>  opcodes/aarch64-tbl-2.h             |  2 ++
>  opcodes/aarch64-tbl.h               |  4 ++++
>  15 files changed, 63 insertions(+), 4 deletions(-)
>  create mode 100644 gas/testsuite/gas/aarch64/cmh-bad.d
>  create mode 100644 gas/testsuite/gas/aarch64/cmh-bad.l
>  create mode 100644 gas/testsuite/gas/aarch64/cmh-bad.s
>  create mode 100644 gas/testsuite/gas/aarch64/cmh.d
>  create mode 100644 gas/testsuite/gas/aarch64/cmh.s
> 
> diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
> index 6a03dfe41ec..e768625062a 100644
> --- a/gas/config/tc-aarch64.c
> +++ b/gas/config/tc-aarch64.c
> @@ -4618,7 +4618,9 @@ parse_hint_opt (const char *name, char **str,
>  	  && (o->value != HINT_OPD_C && o->value != HINT_OPD_J
>  	      && o->value != HINT_OPD_JC && o->value != HINT_OPD_R))
>        || ((strcmp ("stshh", name) == 0)
> -	  && (o->value != HINT_OPD_KEEP && o->value != HINT_OPD_STRM)))
> +	  && (o->value != HINT_OPD_KEEP && o->value != HINT_OPD_STRM))
> +      || ((strcmp ("shuh", name) == 0)
> +	  && (o->value != HINT_OPD_PHINT)))
>        return false;
>  
>    *str = q;
> @@ -6435,6 +6437,7 @@ process_omitted_operand (enum aarch64_opnd type, const aarch64_opcode *opcode,
>        break;
>  
>      case AARCH64_OPND_BTI_TARGET:
> +    case AARCH64_OPND_SHUH_PHINT:
>        operand->hint_option = aarch64_hint_options + default_value;
>        break;
>  
> @@ -8308,6 +8311,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
>  	  break;
>  
>  	case AARCH64_OPND_BTI_TARGET:
> +	case AARCH64_OPND_SHUH_PHINT:
>  	  if (!parse_hint_opt (opcode->name, &str, &(info->hint_option)))
>  	    goto failure;
>  	  break;
> diff --git a/gas/testsuite/gas/aarch64/cmh-bad.d b/gas/testsuite/gas/aarch64/cmh-bad.d
> new file mode 100644
> index 00000000000..c68620add61
> --- /dev/null
> +++ b/gas/testsuite/gas/aarch64/cmh-bad.d
> @@ -0,0 +1,4 @@
> +#name: Negative test of CMH instructions.
> +#as: -march=armv8-a
> +#source: cmh-bad.s
> +#error_output: cmh-bad.l
> diff --git a/gas/testsuite/gas/aarch64/cmh-bad.l b/gas/testsuite/gas/aarch64/cmh-bad.l
> new file mode 100644
> index 00000000000..303fb28829e
> --- /dev/null
> +++ b/gas/testsuite/gas/aarch64/cmh-bad.l
> @@ -0,0 +1,3 @@
> +[^ :]+: Assembler messages:
> +[^ :]+:[0-9]+: Error: operand 1 must be a priority hint \(ph\) -- `shuh p'
> +[^ :]+:[0-9]+: Error: unexpected characters following instruction -- `stcph ph'
> diff --git a/gas/testsuite/gas/aarch64/cmh-bad.s b/gas/testsuite/gas/aarch64/cmh-bad.s
> new file mode 100644
> index 00000000000..eed46a4ff06
> --- /dev/null
> +++ b/gas/testsuite/gas/aarch64/cmh-bad.s
> @@ -0,0 +1,3 @@
> +a:
> +	shuh p
> +	stcph ph
> diff --git a/gas/testsuite/gas/aarch64/cmh.d b/gas/testsuite/gas/aarch64/cmh.d
> new file mode 100644
> index 00000000000..3a9f143cbde
> --- /dev/null
> +++ b/gas/testsuite/gas/aarch64/cmh.d
> @@ -0,0 +1,11 @@
> +#as: -march=armv8-a
> +#objdump: -dr
> +
> +.*:     file format .*
> +
> +Disassembly of section \.text:
> +
> +0+ <.*>:
> +.*:	d503265f 	shuh
> +.*:	d503267f 	shuh	ph
> +.*:	d503269f 	stcph
> diff --git a/gas/testsuite/gas/aarch64/cmh.s b/gas/testsuite/gas/aarch64/cmh.s
> new file mode 100644
> index 00000000000..0045c8ade17
> --- /dev/null
> +++ b/gas/testsuite/gas/aarch64/cmh.s
> @@ -0,0 +1,4 @@
> +a:
> +	shuh
> +	shuh ph
> +	stcph
> diff --git a/gas/testsuite/gas/aarch64/system.d b/gas/testsuite/gas/aarch64/system.d
> index 6d90420d539..11498317e66 100644
> --- a/gas/testsuite/gas/aarch64/system.d
> +++ b/gas/testsuite/gas/aarch64/system.d
> @@ -68,9 +68,9 @@ Disassembly of section \.text:
>  .*:	d50325ff 	hint	#0x2f
>  .*:	d503261f 	(hint	#0x30|stshh	keep)
>  .*:	d503263f 	(hint	#0x31|stshh	strm)
> -.*:	d503265f 	hint	#0x32
> -.*:	d503267f 	hint	#0x33
> -.*:	d503269f 	hint	#0x34
> +.*:	d503265f 	(hint	#0x32|shuh)
> +.*:	d503267f 	(hint	#0x33|shuh	ph)
> +.*:	d503269f 	(hint	#0x34|stcph)
>  .*:	d50326bf 	hint	#0x35
>  .*:	d50326df 	hint	#0x36
>  .*:	d50326ff 	hint	#0x37
> diff --git a/include/opcode/aarch64.h b/include/opcode/aarch64.h
> index b885a06f526..27fad8d1095 100644
> --- a/include/opcode/aarch64.h
> +++ b/include/opcode/aarch64.h
> @@ -759,6 +759,7 @@ enum aarch64_opnd
>    AARCH64_OPND_BARRIER_GCSB,	/* Barrier operand for GCSB.  */
>    AARCH64_OPND_BTI_TARGET,	/* BTI {<target>}.  */
>    AARCH64_OPND_STSHH_POLICY,	/* STSHH {<policy>}.  */
> +  AARCH64_OPND_SHUH_PHINT,	/* SHUH Priority Hint.  */
>    AARCH64_OPND_BRBOP,		/* BRB operation IALL or INJ in bit 5.  */
>    AARCH64_OPND_Rt_IN_SYS_ALIASES,	/* Defaulted and omitted Rt used in SYS aliases such as brb.  */
>    AARCH64_OPND_LSE128_Rt,	/* LSE128 <Xt1>.  */
> @@ -1890,6 +1891,7 @@ struct aarch64_inst
>  #define HINT_OPD_JC	0x26
>  #define HINT_OPD_KEEP	0x30
>  #define HINT_OPD_STRM	0x31
> +#define HINT_OPD_PHINT	0x33
>  #define HINT_OPD_NULL	0x00
>  
>  
> diff --git a/opcodes/aarch64-asm-2.c b/opcodes/aarch64-asm-2.c
> index ca2c939d5b2..8e8cbf43d18 100644
> --- a/opcodes/aarch64-asm-2.c
> +++ b/opcodes/aarch64-asm-2.c
> @@ -543,6 +543,8 @@ aarch64_find_real_opcode (const aarch64_opcode *opcode)
>      case A64_OPID_d503241f_bti_BTI_TARGET:
>      case A64_OPID_d503229f_csdb:
>      case A64_OPID_d503201f_nop:
> +    case A64_OPID_d503265f_shuh_SHUH_PHINT:
> +    case A64_OPID_d503269f_stcph:
>      case A64_OPID_d503261f_stshh_STSHH_POLICY:
>      case A64_OPID_d503201f_hint_UIMM7:
>        value = A64_OPID_d503201f_hint_UIMM7;
> @@ -1035,6 +1037,7 @@ aarch64_insert_operand (const aarch64_operand *self,
>        return aarch64_ins_prfop (self, info, code, inst, errors);
>      case AARCH64_OPND_BTI_TARGET:
>      case AARCH64_OPND_STSHH_POLICY:
> +    case AARCH64_OPND_SHUH_PHINT:
>        return aarch64_ins_hint (self, info, code, inst, errors);
>      case AARCH64_OPND_SVE_ADDR_RI_S4x16:
>      case AARCH64_OPND_SVE_ADDR_RI_S4x32:
> diff --git a/opcodes/aarch64-dis-2.c b/opcodes/aarch64-dis-2.c
> index 9dcb83fefac..9aeb3df19b2 100644
> --- a/opcodes/aarch64-dis-2.c
> +++ b/opcodes/aarch64-dis-2.c
> @@ -37534,6 +37534,12 @@ aarch64_find_next_alias_opcode (const aarch64_opcode *opcode)
>        value = A64_OPID_d503201f_nop;
>        break;
>      case A64_OPID_d503201f_nop:
> +      value = A64_OPID_d503265f_shuh_SHUH_PHINT;
> +      break;
> +    case A64_OPID_d503265f_shuh_SHUH_PHINT:
> +      value = A64_OPID_d503269f_stcph;
> +      break;
> +    case A64_OPID_d503269f_stcph:
>        value = A64_OPID_d503261f_stshh_STSHH_POLICY;
>        break;
>      case A64_OPID_d503261f_stshh_STSHH_POLICY:
> @@ -38017,6 +38023,7 @@ aarch64_extract_operand (const aarch64_operand *self,
>        return aarch64_ext_prfop (self, info, code, inst, errors);
>      case AARCH64_OPND_BTI_TARGET:
>      case AARCH64_OPND_STSHH_POLICY:
> +    case AARCH64_OPND_SHUH_PHINT:
>        return aarch64_ext_hint (self, info, code, inst, errors);
>      case AARCH64_OPND_SVE_ADDR_RI_S4x16:
>      case AARCH64_OPND_SVE_ADDR_RI_S4x32:
> diff --git a/opcodes/aarch64-opc-2.c b/opcodes/aarch64-opc-2.c
> index 4f447aef78f..0456c267066 100644
> --- a/opcodes/aarch64-opc-2.c
> +++ b/opcodes/aarch64-opc-2.c
> @@ -154,6 +154,7 @@ const struct aarch64_operand aarch64_operands[] =
>    {AARCH64_OPND_CLASS_SYSTEM, "BARRIER_GCSB", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {}, "the GCSB option name DSYNC"},
>    {AARCH64_OPND_CLASS_SYSTEM, "BTI_TARGET", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {}, "BTI targets r/j/c/jc"},
>    {AARCH64_OPND_CLASS_SYSTEM, "STSHH_POLICY", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {}, "an STSHH policy (keep/strm)"},
> +  {AARCH64_OPND_CLASS_SYSTEM, "SHUH_PHINT", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {}, "a priority hint (ph)"},
>    {AARCH64_OPND_CLASS_SYSTEM, "BRBOP", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_brbop}, "Branch Record Buffer operation operand"},
>    {AARCH64_OPND_CLASS_INT_REG, "Rt_IN_SYS_ALIASES", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_Rt}, "Rt register with defaults for SYS aliases"},
>    {AARCH64_OPND_CLASS_INT_REG, "LSE128_Rt", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_LSE128_Rt}, "an integer register"},
> diff --git a/opcodes/aarch64-opc.c b/opcodes/aarch64-opc.c
> index e4ce347bdc9..e033151deda 100644
> --- a/opcodes/aarch64-opc.c
> +++ b/opcodes/aarch64-opc.c
> @@ -599,6 +599,7 @@ const struct aarch64_name_value_pair aarch64_hint_options[] =
>  {
>    /* BTI.  This is also the F_DEFAULT entry for AARCH64_OPND_BTI_TARGET.  */
>    { "r",	HINT_OPD_R },		/* BTI R.  */
> +  { " ",	HINT_ENCODE (HINT_OPD_F_NOPRINT, 0x32) }, /* SHUH. */
>    { "csync",	HINT_OPD_CSYNC },	/* PSB CSYNC.  */
>    { "dsync",	HINT_OPD_DSYNC },	/* GCSB DSYNC.  */
>    { "c",	HINT_OPD_C },		/* BTI C.  */
> @@ -606,6 +607,7 @@ const struct aarch64_name_value_pair aarch64_hint_options[] =
>    { "jc",	HINT_OPD_JC },		/* BTI JC.  */
>    { "keep",	HINT_OPD_KEEP },	/* STSHH KEEP  */
>    { "strm",	HINT_OPD_STRM },	/* STSHH STRM  */
> +  { "ph",	HINT_OPD_PHINT },	/* SHUH PH.  */
>    { NULL,	HINT_OPD_NULL },
>  };
>  
> @@ -5178,6 +5180,12 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc,
>        snprintf (buf, size, "%s", style_sub_mnem (styler, opnd->hint_option->name));
>        break;
>  
> +    case AARCH64_OPND_SHUH_PHINT:
> +      if ((HINT_FLAG (opnd->hint_option->value) & HINT_OPD_F_NOPRINT) == 0)
> +	snprintf (buf, size, "%s",
> +		  style_sub_mnem (styler, opnd->hint_option->name));
> +      break;
> +
>      case AARCH64_OPND_MOPS_ADDR_Rd:
>      case AARCH64_OPND_MOPS_ADDR_Rs:
>        snprintf (buf, size, "[%s]!",
> diff --git a/opcodes/aarch64-opc.h b/opcodes/aarch64-opc.h
> index a612c3a3db9..57eb7198538 100644
> --- a/opcodes/aarch64-opc.h
> +++ b/opcodes/aarch64-opc.h
> @@ -392,6 +392,9 @@ verify_constraints (const struct aarch64_inst *, const aarch64_insn, bfd_vma,
>  #define F_REG_MAX_VALUE(X) ((X) << 15)
>  #define F_GET_REG_MAX_VALUE(X) (((X) >> 15) & 0x0f)
>  
> +/* HINT operand flags.  */
> +#define HINT_OPD_F_NOPRINT	(1 << 0)  /* Should not be printed.  */
> +

Rather than reintroducing this flag, can we instead use an empty string in the table and test for that?

>  /* Encode 7-bit HINT #imm in the lower 8 bits.  Use higher bits for flags.  */
>  #define HINT_ENCODE(flag, val) ((flag << 8) | val)
>  #define HINT_FLAG(val) (val >> 8)
> diff --git a/opcodes/aarch64-tbl-2.h b/opcodes/aarch64-tbl-2.h
> index e9bc188c69f..64e79d709d5 100644
> --- a/opcodes/aarch64-tbl-2.h
> +++ b/opcodes/aarch64-tbl-2.h
> @@ -1368,6 +1368,8 @@ enum aarch64_opcode_idx
>    A64_OPID_d503407f_smstop_SME_SM_ZA,
>    A64_OPID_d503251f_chkfeat_X16,
>    A64_OPID_d503261f_stshh_STSHH_POLICY,
> +  A64_OPID_d503269f_stcph,
> +  A64_OPID_d503265f_shuh_SHUH_PHINT,
>    A64_OPID_d500401f_msr_PSTATEFIELD_UIMM4,
>    A64_OPID_d503201f_hint_UIMM7,
>    A64_OPID_d503201f_nop,
> diff --git a/opcodes/aarch64-tbl.h b/opcodes/aarch64-tbl.h
> index 82b3e9dd2ce..3f0d82a1ee9 100644
> --- a/opcodes/aarch64-tbl.h
> +++ b/opcodes/aarch64-tbl.h
> @@ -5098,6 +5098,8 @@ const struct aarch64_opcode aarch64_opcode_table[] =
>    /* System.  */
>    CHK_INSN ("chkfeat", 0xd503251f, 0xffffffff, OP1 (X16), QL_I1X, 0),
>    CORE_INSN ("stshh", 0xd503261f, 0xffffffdf, ic_system, 0, OP1 (STSHH_POLICY), {}, F_ALIAS),
> +  CORE_INSN ("stcph", 0xd503269f, 0xffffffff, ic_system, 0, OP0 (), {}, F_ALIAS),
> +  CORE_INSN ("shuh", 0xd503265f, 0xffffffdf, ic_system, 0, OP1 (SHUH_PHINT), {}, F_ALIAS | F_OPD0_OPT | F_DEFAULT (0x0)),

This F_DEFAULT value is used to reference an entry in the aarch64_hint_options
array.  The zeroth entry is for BTI R.  It happens to give the correct encoding
in this case, because BTI R is hint #0x20, which is a subset of the bits in
used in hint #0x32 (SHUH).

This whole way we handle hint instructions is quite messy, but fixing that
isn't a job for days before the branch.  So for now I'd suggest making this
F_DEFAULT (0x1), and adding comments to the table stating that "bti r" and
"shuh" need to be the first and second entries to match the F_DEFAULT values.


>    CORE_INSN ("msr", 0xd500401f, 0xfff8f01f, ic_system, 0, OP2 (PSTATEFIELD, UIMM4), {}, F_SYS_WRITE),
>    CORE_INSN ("hint",0xd503201f, 0xfffff01f, ic_system, 0, OP1 (UIMM7), {}, F_HAS_ALIAS),
>    CORE_INSN ("nop", 0xd503201f, 0xffffffff, ic_system, 0, OP0 (), {}, F_ALIAS),
> @@ -8162,6 +8164,8 @@ const struct aarch64_opcode aarch64_opcode_table[] =
>        "BTI targets r/j/c/jc")						\
>      Y(SYSTEM, hint, "STSHH_POLICY", 0, F(),				\
>        "an STSHH policy (keep/strm)")					\
> +    Y(SYSTEM, hint, "SHUH_PHINT", 0, F(),				\
> +      "a priority hint (ph)")						\

I think the error message would be slightly better with the word "optional"
added - i.e. "an optional priority hint (ph)".

>      Y(SYSTEM, imm, "BRBOP", 0, F(FLD_brbop),				\
>        "Branch Record Buffer operation operand")				\
>      Y(INT_REG, regno, "Rt_IN_SYS_ALIASES", 0, F(FLD_Rt),		\
> -- 
> 2.34.1
> 


More information about the Binutils mailing list