public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] RISC-V: Support Zcmp push/pop instructions
@ 2023-07-26  3:22 Jiawei
  2023-07-26  6:50 ` Tsukasa OI
  0 siblings, 1 reply; 3+ messages in thread
From: Jiawei @ 2023-07-26  3:22 UTC (permalink / raw)
  To: binutils
  Cc: nelson, kito.cheng, palmer, jbeulich, christoph.muellner,
	jeremy.bennett, nandni.jamnadas, mary.bennett, charlie.keaney,
	simon.cook, sinan.lin, gaofei, fujin.zhao, wuwei2016, shihua,
	shiyulong, chenyixuan, Jiawei

Support zcmp extension push/pop/popret and popret zero instructions.
`reg_list` is a list containing 1 to 13 registers, we can use: "{ra}, {ra,
s0}, {ra, s0-s1}, {ra, s0-s2}, …, {ra, s0-sN}" to present this feature.
`stack_adj` is the total size of the stack frame, use
`riscv_get_sp_base` function to calculate it.
Most work was finished by Sinan Lin.

Co-Authored by: Charlie Keaney <charlie.keaney@embecosm.com>
Co-Authored by: Mary Bennett <mary.bennett@embecosm.com>
Co-Authored by: Nandni Jamnadas <nandni.jamnadas@embecosm.com>
Co-Authored by: Sinan Lin <sinan.lin@linux.alibaba.com>
Co-Authored by: Simon Cook <simon.cook@embecosm.com>
Co-Authored by: Shihua Liao <shihua@iscas.ac.cn>
Co-Authored by: Yulong Shi <yulong@iscas.ac.cn>

bfd/ChangeLog:

        * elfxx-riscv.c (riscv_get_sp_base): New function.
        (riscv_multi_subset_supports): New extension.
        (riscv_multi_subset_supports_ext): Ditto.
        * elfxx-riscv.h (SP_ALIGNMENT): New macro.
        (riscv_get_sp_base): New function prototype.

gas/ChangeLog:

        * config/tc-riscv.c (regno_to_rlist): New regs mapping.
        (reglist_lookup): New function.
        (validate_riscv_insn): New operators.
        (riscv_ip): Ditto.
        * testsuite/gas/riscv/zcmp-push-pop-fail.d: New test.
        * testsuite/gas/riscv/zcmp-push-pop-fail.l: New test.
        * testsuite/gas/riscv/zcmp-push-pop-fail.s: New test.
        * testsuite/gas/riscv/zcmp-push-pop.d: New test.
        * testsuite/gas/riscv/zcmp-push-pop.s: New test.

include/ChangeLog:

        * opcode/riscv-opc.h (MATCH_CM_PUSH): New opcode.
        (MASK_CM_PUSH): New mask.
        (MATCH_CM_POP): New opcode.
        (MASK_CM_POP): New mask.
        (MATCH_CM_POPRET): New opcode.
        (MASK_CM_POPRET): New mask.
        (MATCH_CM_POPRETZ): New opcode.
        (MASK_CM_POPRETZ): New mask.
        * opcode/riscv.h (EXTRACT_ZCMP_SPIMM): New inline function.
        (ENCODE_ZCMP_SPIMM): Ditto.
        (VALID_ZCMP_SPIMM): Ditto.
        (OP_MASK_RLIST): New mask.
        (OP_SH_RLIST): New operand code.
        (X_S0): New reg number.
        (X_S1): Ditto.
        (X_S2): Ditto.
        (X_S10): Ditto.
        (X_S11): Ditto.
        (enum riscv_insn_class): New extension class.

opcodes/ChangeLog:

        * riscv-dis.c (set_default_riscv_dis_options): New var.
        (parse_riscv_dis_option_without_args): Ditto.
        (print_rlist): New print function.
        (riscv_get_spimm): New function.
        (print_insn_args): New operators.
        * riscv-opc.c: New instructions.
---
 bfd/elfxx-riscv.c                            |  23 ++-
 bfd/elfxx-riscv.h                            |   4 +
 gas/config/tc-riscv.c                        | 180 ++++++++++++++++-
 gas/testsuite/gas/riscv/zcmp-push-pop-fail.d |   3 +
 gas/testsuite/gas/riscv/zcmp-push-pop-fail.l |   9 +
 gas/testsuite/gas/riscv/zcmp-push-pop-fail.s |  13 ++
 gas/testsuite/gas/riscv/zcmp-push-pop.d      | 154 +++++++++++++++
 gas/testsuite/gas/riscv/zcmp-push-pop.s      | 197 +++++++++++++++++++
 include/opcode/riscv-opc.h                   |   9 +
 include/opcode/riscv.h                       |  13 ++
 opcodes/riscv-dis.c                          |  57 ++++++
 opcodes/riscv-opc.c                          |   6 +
 12 files changed, 665 insertions(+), 3 deletions(-)
 create mode 100644 gas/testsuite/gas/riscv/zcmp-push-pop-fail.d
 create mode 100644 gas/testsuite/gas/riscv/zcmp-push-pop-fail.l
 create mode 100644 gas/testsuite/gas/riscv/zcmp-push-pop-fail.s
 create mode 100644 gas/testsuite/gas/riscv/zcmp-push-pop.d
 create mode 100644 gas/testsuite/gas/riscv/zcmp-push-pop.s

diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
index b43d2cfa0fa..2800edb8206 100644
--- a/bfd/elfxx-riscv.c
+++ b/bfd/elfxx-riscv.c
@@ -1084,6 +1084,19 @@ check_implicit_for_i (const char *implicit ATTRIBUTE_UNUSED,
 	      && subset->minor_version < 1));
 }
 
+/* get sp base adjustment */
+
+int
+riscv_get_sp_base (insn_t opcode, riscv_parse_subset_t *rps)
+{
+  unsigned reg_size = *(rps->xlen) / 8;
+  unsigned rlist = EXTRACT_BITS (opcode, OP_MASK_RLIST, OP_SH_RLIST);
+
+  unsigned min_sp_adj = (rlist - 3) * reg_size + (rlist == 15 ? reg_size : 0);
+  return ((min_sp_adj / SP_ALIGNMENT) + (min_sp_adj % SP_ALIGNMENT != 0))
+    * SP_ALIGNMENT;
+}
+
 /* Record all implicit information for the subsets.  */
 struct riscv_implicit_subset
 {
@@ -1176,6 +1189,7 @@ static struct riscv_implicit_subset riscv_implicit_subsets[] =
   {"zcf", "zca",	check_implicit_always},
   {"zcd", "zca",	check_implicit_always},
   {"zcb", "zca",	check_implicit_always},
+  {"zcmp", "zca",	check_implicit_always},
   {"smaia", "ssaia",		check_implicit_always},
   {"smstateen", "ssstateen",	check_implicit_always},
   {"smepmp", "zicsr",		check_implicit_always},
@@ -1313,6 +1327,7 @@ static struct riscv_supported_ext riscv_supported_std_z_ext[] =
   {"zcb",		ISA_SPEC_CLASS_DRAFT,		1, 0,  0 },
   {"zcf",		ISA_SPEC_CLASS_DRAFT,		1, 0,  0 },
   {"zcd",		ISA_SPEC_CLASS_DRAFT,		1, 0,  0 },
+  {"zcmp",		ISA_SPEC_CLASS_DRAFT,		1, 0,  0 },
   {NULL, 0, 0, 0, 0}
 };
 
@@ -2514,8 +2529,10 @@ riscv_multi_subset_supports (riscv_parse_subset_t *rps,
       return (riscv_subset_supports (rps, "zcb")
 	      && riscv_subset_supports (rps, "zba"));
     case INSN_CLASS_ZCB_AND_ZMMUL:
-      return (riscv_subset_supports (rps, "zcb")
-	      && riscv_subset_supports (rps, "zmmul"));
+      return riscv_subset_supports (rps, "zcb")
+	      && riscv_subset_supports (rps, "zmmul");
+    case INSN_CLASS_ZCMP:
+      return riscv_subset_supports (rps, "zcmp");
     case INSN_CLASS_SVINVAL:
       return riscv_subset_supports (rps, "svinval");
     case INSN_CLASS_H:
@@ -2732,6 +2749,8 @@ riscv_multi_subset_supports_ext (riscv_parse_subset_t *rps,
       return _("zcb' and `zbb");
     case INSN_CLASS_ZCB_AND_ZMMUL:
       return _("zcb' and `zmmul', or `zcb' and `m");
+    case INSN_CLASS_ZCMP:
+      return "zcmp";
     case INSN_CLASS_SVINVAL:
       return "svinval";
     case INSN_CLASS_H:
diff --git a/bfd/elfxx-riscv.h b/bfd/elfxx-riscv.h
index abcb409bd78..ae144567116 100644
--- a/bfd/elfxx-riscv.h
+++ b/bfd/elfxx-riscv.h
@@ -26,6 +26,7 @@
 #include "cpu-riscv.h"
 
 #define RISCV_UNKNOWN_VERSION -1
+#define SP_ALIGNMENT 16
 
 struct riscv_elf_params
 {
@@ -123,3 +124,6 @@ extern void
 bfd_elf32_riscv_set_data_segment_info (struct bfd_link_info *, int *);
 extern void
 bfd_elf64_riscv_set_data_segment_info (struct bfd_link_info *, int *);
+
+extern int
+riscv_get_sp_base (insn_t, riscv_parse_subset_t *);
\ No newline at end of file
diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
index aaf8b9be64f..266a91451b7 100644
--- a/gas/config/tc-riscv.c
+++ b/gas/config/tc-riscv.c
@@ -1237,6 +1237,152 @@ flt_lookup (float f, const float *array, size_t size, unsigned *regnop)
   return false;
 }
 
+/* Map ra and s-register to [4,15], so that we can check if the
+    reg2 in register list reg1-reg2 or single reg2 is valid or not,
+    and obtain the corresponding rlist value.
+
+   ra - 4
+   s0 - 5
+   s1 - 6
+    ....
+   s10 - 0 (invalid)
+   s11 - 15
+*/
+
+static int
+regno_to_rlist (unsigned regno)
+{
+  if (regno == X_RA)
+    return 4;
+  else if (regno == X_S0 || regno == X_S1)
+    return 5 + regno - X_S0;
+  else if (regno >= X_S2 && regno < X_S10)
+    return 7 + regno - X_S2;
+  else if (regno == X_S11)
+    return 15;
+
+  return 0; /* invalid symbol */
+}
+
+/* Parse register list, and the parsed rlist value is stored in rlist
+  argument.
+
+  If ABI register names are used (e.g. ra and s0), the register
+  list could be "{ra}", "{ra, s0}", "{ra, s0-sN}", where 0 < N < 10 or
+  N == 11.
+
+  If numeric register names are used (e.g. x1 and x8), the register list
+  could be "{x1}", "{x1,x8}", "{x1,x8-x9}", "{x1,x8-x9, x18}" and
+  "{x1,x8-x9,x18-xN}", where 19 < N < 25 or N == 27.
+
+  It will fail if numeric register names and ABI register names are used
+  at the same time.
+  */
+
+static bool
+reglist_lookup (char **s, unsigned *rlist)
+{
+  unsigned regno;
+  /* Use to check if the register format is xreg.  */
+  bool use_xreg = **s == 'x';
+
+  /* The first register in register list should be ra.  */
+  if (!reg_lookup (s, RCLASS_GPR, &regno)
+      || !(*rlist = regno_to_rlist (regno)) /* update rlist */
+      || regno != X_RA)
+    return FALSE;
+
+  /* Skip "whitespace, whitespace" pattern.  */
+  while (ISSPACE (**s))
+    ++ *s;
+  if (**s == '}')
+    return TRUE;
+  else if (**s != ',')
+    return FALSE;
+  while (ISSPACE (*++*s))
+    ++ *s;
+
+  /* Do not use numeric and abi names at the same time.  */
+  if (use_xreg && **s != 'x')
+    return FALSE;
+
+  /* Reg1 should be s0 or its numeric names x8.  */
+  if (!reg_lookup (s, RCLASS_GPR, &regno)
+      || !(*rlist = regno_to_rlist (regno))
+      || regno != X_S0)
+    return FALSE;
+
+  /* Skip "whitespace - whitespace" pattern.  */
+  while (ISSPACE (**s))
+    ++ *s;
+  if (**s == '}')
+    return TRUE;
+  else if (**s != '-')
+    return FALSE;
+  while (ISSPACE (*++*s))
+    ++ *s;
+
+  if (use_xreg && **s != 'x')
+    return FALSE;
+
+  /* Reg2 is x9 if the numeric name is used, otherwise,
+    it could be any other sN register, where N > 0.  */
+  if (!reg_lookup (s, RCLASS_GPR, &regno)
+      || !(*rlist = regno_to_rlist (regno))
+      || regno <= X_S0
+      || (use_xreg && regno != X_S1))
+    return FALSE;
+
+   /* Skip whitespace */
+  while (ISSPACE (**s))
+    ++ *s;
+
+  /* Check if it is the end of register list.  */
+  if (**s == '}')
+    return TRUE;
+  else if (!use_xreg)
+    return FALSE;
+
+  /* Here is not reachable if the abi name is used.  */
+  gas_assert (use_xreg);
+
+  /* If the numeric name is used, we need to parse extra
+    register list, reg3 or reg3-reg4.  */
+
+  /* Skip ", white space" pattern.  */
+  if (**s != ',')
+    return FALSE;
+  while (ISSPACE (*++*s))
+    ++ *s;
+
+  if (use_xreg && **s != 'x')
+    return FALSE;
+
+  /* Reg3 should be s2.  */
+    if (!reg_lookup (s, RCLASS_GPR, &regno)
+	|| !(*rlist = regno_to_rlist (regno))
+	|| regno != X_S2)
+      return FALSE;
+
+  /* skip "whitespace - whitespace" pattern.  */
+  while (ISSPACE (**s))
+    ++ *s;
+  if (**s == '}')
+    return TRUE;
+  else if (**s != '-')
+    return FALSE;
+  while (ISSPACE (*++*s))
+    ++ *s;
+
+  /* Reg4 could be any other sN register, where N > 1.  */
+  if (!reg_lookup (s, RCLASS_GPR, &regno)
+      || !(*rlist = regno_to_rlist (regno))
+      || regno <= X_S2)
+    return FALSE;
+
+  return TRUE;
+}
+
 #define USE_BITS(mask,shift) (used_bits |= ((insn_t)(mask) << (shift)))
 #define USE_IMM(n, s) \
   (used_bits |= ((insn_t)((1ull<<n)-1) << (s)))
@@ -1353,6 +1499,9 @@ validate_riscv_insn (const struct riscv_opcode *opc, int length)
 	case ',': break;
 	case '(': break;
 	case ')': break;
+	case '{': break;
+	case '}': break;
+	case '!': break;
 	case '<': USE_BITS (OP_MASK_SHAMTW, OP_SH_SHAMTW); break;
 	case '>': USE_BITS (OP_MASK_SHAMT, OP_SH_SHAMT); break;
 	case 'A': break; /* Macro operand, must be symbol.  */
@@ -1433,6 +1582,10 @@ validate_riscv_insn (const struct riscv_opcode *opc, int length)
 		case 'h': used_bits |= ENCODE_ZCB_HALFWORD_UIMM (-1U); break;
 		/* halfword immediate operators, load/store halfword insns.  */
 		case 'b': used_bits |= ENCODE_ZCB_BYTE_UIMM (-1U); break;
+    /* immediate offset operand for cm.push and cm.pop.  */
+		case 'p': used_bits |= ENCODE_ZCMP_SPIMM (-1U); break;
+		/* register list operand for cm.push and cm.pop.  */
+		case 'r': USE_BITS (OP_MASK_RLIST, OP_SH_RLIST); break;
 		case 'f': break;
 		default:
 		  goto unknown_validate_operand;
@@ -3141,6 +3294,8 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
 	    case ')':
 	    case '[':
 	    case ']':
+	    case '{':
+	    case '}':
 	      if (*asarg++ == *oparg)
 		continue;
 	      break;
@@ -3597,7 +3752,30 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
 		      ip->insn_opcode |= ENCODE_ZCB_BYTE_UIMM (imm_expr->X_add_number);
 		      goto rvc_imm_done;
 
-		    case 'f': /* Operand for matching immediate 255.  */
+		    case 'r':
+		      /* we use regno to store reglist value here.  */
+		      if (!reglist_lookup (&asarg, &regno))
+			break;
+		      INSERT_OPERAND (RLIST, *ip, regno);
+			continue;
+
+		    case 'p':
+		      if (my_getSmallExpression (imm_expr, imm_reloc, asarg, p)
+			|| imm_expr->X_op != O_constant)
+			break;
+		      /* convert stack adjust of cm.push to a positive offset.  */
+		      if (ip->insn_mo->match == MATCH_CM_PUSH)
+			imm_expr->X_add_number *= -1;
+		      /* subtract base stack adjust and get spimm.  */
+		      imm_expr->X_add_number -=
+			      riscv_get_sp_base (ip->insn_opcode, &riscv_rps_as);
+		      if (!VALID_ZCMP_SPIMM (imm_expr->X_add_number))
+			break;
+		      ip->insn_opcode |=
+			ENCODE_ZCMP_SPIMM (imm_expr->X_add_number);
+		      goto rvc_imm_done;
+
+			case 'f': /* operand for matching immediate 255.  */
 		      if (my_getSmallExpression (imm_expr, imm_reloc, asarg, p)
 			  || imm_expr->X_op != O_constant
 			  || imm_expr->X_add_number != 255)
diff --git a/gas/testsuite/gas/riscv/zcmp-push-pop-fail.d b/gas/testsuite/gas/riscv/zcmp-push-pop-fail.d
new file mode 100644
index 00000000000..ca1d88e6299
--- /dev/null
+++ b/gas/testsuite/gas/riscv/zcmp-push-pop-fail.d
@@ -0,0 +1,3 @@
+#as: -march=rv64i_zcmp
+#source: zcmp-push-pop-fail.s
+#error_output: zcmp-push-pop-fail.l
\ No newline at end of file
diff --git a/gas/testsuite/gas/riscv/zcmp-push-pop-fail.l b/gas/testsuite/gas/riscv/zcmp-push-pop-fail.l
new file mode 100644
index 00000000000..955e495d5bb
--- /dev/null
+++ b/gas/testsuite/gas/riscv/zcmp-push-pop-fail.l
@@ -0,0 +1,9 @@
+.*: Assembler messages:
+.*: Error: illegal operands `cm.push \{a0\},-64'
+.*: Error: illegal operands `cm.pop \{ra,s1\},-64'
+.*: Error: illegal operands `cm.popret \{ra,s2-s3\},-64'
+.*: Error: illegal operands `cm.popretz \{ra,s0-s10\},-112'
+.*: Error: illegal operands `cm.push \{ra\},0'
+.*: Error: illegal operands `cm.pop \{ra,s0\},-80'
+.*: Error: illegal operands `cm.popret \{ra,s0-s1\},-15'
+.*: Error: illegal operands `cm.popretz \{ra,s0-s11\},-165'
diff --git a/gas/testsuite/gas/riscv/zcmp-push-pop-fail.s b/gas/testsuite/gas/riscv/zcmp-push-pop-fail.s
new file mode 100644
index 00000000000..a82f9399787
--- /dev/null
+++ b/gas/testsuite/gas/riscv/zcmp-push-pop-fail.s
@@ -0,0 +1,13 @@
+target:
+
+	# rlist
+	cm.push {a0}, -64
+	cm.pop {ra, s1}, -64
+	cm.popret {ra, s2-s3}, -64
+	cm.popretz {ra, s0-s10}, -112
+
+	# spimm
+	cm.push {ra}, 0
+	cm.pop {ra, s0}, -80
+	cm.popret {ra, s0-s1}, -15
+	cm.popretz {ra, s0-s11}, -165
diff --git a/gas/testsuite/gas/riscv/zcmp-push-pop.d b/gas/testsuite/gas/riscv/zcmp-push-pop.d
new file mode 100644
index 00000000000..e21295051ec
--- /dev/null
+++ b/gas/testsuite/gas/riscv/zcmp-push-pop.d
@@ -0,0 +1,154 @@
+#as: -march=rv64i_zcmp
+#source: zcmp-push-pop.s
+#objdump: -dr -Mno-aliases
+
+.*:[	 ]+file format .*
+
+
+Disassembly of section .text:
+
+0+000 <target>:
+[	 ]*[0-9a-f]+:[	 ]+b84e[	 ]+cm.push[	 ]+\{ra\},-64
+[	 ]*[0-9a-f]+:[	 ]+b85e[	 ]+cm.push[	 ]+\{ra,s0\},-64
+[	 ]*[0-9a-f]+:[	 ]+b86a[	 ]+cm.push[	 ]+\{ra,s0-s1\},-64
+[	 ]*[0-9a-f]+:[	 ]+b87a[	 ]+cm.push[	 ]+\{ra,s0-s2\},-64
+[	 ]*[0-9a-f]+:[	 ]+b8da[	 ]+cm.push[	 ]+\{ra,s0-s8\},-112
+[	 ]*[0-9a-f]+:[	 ]+b8e6[	 ]+cm.push[	 ]+\{ra,s0-s9\},-112
+[	 ]*[0-9a-f]+:[	 ]+b8f2[	 ]+cm.push[	 ]+\{ra,s0-s11\},-112
+[	 ]*[0-9a-f]+:[	 ]+b84e[	 ]+cm.push[	 ]+\{ra\},-64
+[	 ]*[0-9a-f]+:[	 ]+b85e[	 ]+cm.push[	 ]+\{ra,s0\},-64
+[	 ]*[0-9a-f]+:[	 ]+b86a[	 ]+cm.push[	 ]+\{ra,s0-s1\},-64
+[	 ]*[0-9a-f]+:[	 ]+b87a[	 ]+cm.push[	 ]+\{ra,s0-s2\},-64
+[	 ]*[0-9a-f]+:[	 ]+b8da[	 ]+cm.push[	 ]+\{ra,s0-s8\},-112
+[	 ]*[0-9a-f]+:[	 ]+b8e6[	 ]+cm.push[	 ]+\{ra,s0-s9\},-112
+[	 ]*[0-9a-f]+:[	 ]+b8f2[	 ]+cm.push[	 ]+\{ra,s0-s11},-112
+[	 ]*[0-9a-f]+:[	 ]+b842[	 ]+cm.push[	 ]+\{ra\},-16
+[	 ]*[0-9a-f]+:[	 ]+b846[	 ]+cm.push[	 ]+\{ra\},-32
+[	 ]*[0-9a-f]+:[	 ]+b84e[	 ]+cm.push[	 ]+\{ra\},-64
+[	 ]*[0-9a-f]+:[	 ]+b872[	 ]+cm.push[	 ]+\{ra,s0-s2\},-32
+[	 ]*[0-9a-f]+:[	 ]+b87a[	 ]+cm.push[	 ]+\{ra,s0-s2\},-64
+[	 ]*[0-9a-f]+:[	 ]+b87e[	 ]+cm.push[	 ]+\{ra,s0-s2\},-80
+[	 ]*[0-9a-f]+:[	 ]+b882[	 ]+cm.push[	 ]+\{ra,s0-s3\},-48
+[	 ]*[0-9a-f]+:[	 ]+b886[	 ]+cm.push[	 ]+\{ra,s0-s3\},-64
+[	 ]*[0-9a-f]+:[	 ]+b88e[	 ]+cm.push[	 ]+\{ra,s0-s3\},-96
+[	 ]*[0-9a-f]+:[	 ]+b8b2[	 ]+cm.push[	 ]+\{ra,s0-s6\},-64
+[	 ]*[0-9a-f]+:[	 ]+b8b6[	 ]+cm.push[	 ]+\{ra,s0-s6\},-80
+[	 ]*[0-9a-f]+:[	 ]+b8be[	 ]+cm.push[	 ]+\{ra,s0-s6\},-112
+[	 ]*[0-9a-f]+:[	 ]+b8c2[	 ]+cm.push[	 ]+\{ra,s0-s7\},-80
+[	 ]*[0-9a-f]+:[	 ]+b8c6[	 ]+cm.push[	 ]+\{ra,s0-s7\},-96
+[	 ]*[0-9a-f]+:[	 ]+b8ce[	 ]+cm.push[	 ]+\{ra,s0-s7\},-128
+[	 ]*[0-9a-f]+:[	 ]+b8e2[	 ]+cm.push[	 ]+\{ra,s0-s9\},-96
+[	 ]*[0-9a-f]+:[	 ]+b8e6[	 ]+cm.push[	 ]+\{ra,s0-s9\},-112
+[	 ]*[0-9a-f]+:[	 ]+b8ee[	 ]+cm.push[	 ]+\{ra,s0-s9\},-144
+[	 ]*[0-9a-f]+:[	 ]+b8f2[	 ]+cm.push[	 ]+\{ra,s0-s11\},-112
+[	 ]*[0-9a-f]+:[	 ]+b8f6[	 ]+cm.push[	 ]+\{ra,s0-s11\},-128
+[	 ]*[0-9a-f]+:[	 ]+b8fa[	 ]+cm.push[	 ]+\{ra,s0-s11\},-144
+[	 ]*[0-9a-f]+:[	 ]+b8fe[	 ]+cm.push[	 ]+\{ra,s0-s11\},-160
+[	 ]*[0-9a-f]+:[	 ]+ba4e[	 ]+cm.pop[	 ]+\{ra\},64
+[	 ]*[0-9a-f]+:[	 ]+ba5e[	 ]+cm.pop[	 ]+\{ra,s0\},64
+[	 ]*[0-9a-f]+:[	 ]+ba6a[	 ]+cm.pop[	 ]+\{ra,s0-s1\},64
+[	 ]*[0-9a-f]+:[	 ]+ba7a[	 ]+cm.pop[	 ]+\{ra,s0-s2\},64
+[	 ]*[0-9a-f]+:[	 ]+bada[	 ]+cm.pop[	 ]+\{ra,s0-s8\},112
+[	 ]*[0-9a-f]+:[	 ]+bae6[	 ]+cm.pop[	 ]+\{ra,s0-s9\},112
+[	 ]*[0-9a-f]+:[	 ]+baf2[	 ]+cm.pop[	 ]+\{ra,s0-s11\},112
+[	 ]*[0-9a-f]+:[	 ]+ba4e[	 ]+cm.pop[	 ]+\{ra\},64
+[	 ]*[0-9a-f]+:[	 ]+ba5e[	 ]+cm.pop[	 ]+\{ra,s0\},64
+[	 ]*[0-9a-f]+:[	 ]+ba6a[	 ]+cm.pop[	 ]+\{ra,s0-s1\},64
+[	 ]*[0-9a-f]+:[	 ]+ba7a[	 ]+cm.pop[	 ]+\{ra,s0-s2\},64
+[	 ]*[0-9a-f]+:[	 ]+bada[	 ]+cm.pop[	 ]+\{ra,s0-s8\},112
+[	 ]*[0-9a-f]+:[	 ]+bae6[	 ]+cm.pop[	 ]+\{ra,s0-s9\},112
+[	 ]*[0-9a-f]+:[	 ]+baf2[	 ]+cm.pop[	 ]+\{ra,s0-s11},112
+[	 ]*[0-9a-f]+:[	 ]+ba42[	 ]+cm.pop[	 ]+\{ra\},16
+[	 ]*[0-9a-f]+:[	 ]+ba46[	 ]+cm.pop[	 ]+\{ra\},32
+[	 ]*[0-9a-f]+:[	 ]+ba4e[	 ]+cm.pop[	 ]+\{ra\},64
+[	 ]*[0-9a-f]+:[	 ]+ba72[	 ]+cm.pop[	 ]+\{ra,s0-s2\},32
+[	 ]*[0-9a-f]+:[	 ]+ba7a[	 ]+cm.pop[	 ]+\{ra,s0-s2\},64
+[	 ]*[0-9a-f]+:[	 ]+ba7e[	 ]+cm.pop[	 ]+\{ra,s0-s2\},80
+[	 ]*[0-9a-f]+:[	 ]+ba82[	 ]+cm.pop[	 ]+\{ra,s0-s3\},48
+[	 ]*[0-9a-f]+:[	 ]+ba86[	 ]+cm.pop[	 ]+\{ra,s0-s3\},64
+[	 ]*[0-9a-f]+:[	 ]+ba8e[	 ]+cm.pop[	 ]+\{ra,s0-s3\},96
+[	 ]*[0-9a-f]+:[	 ]+bab2[	 ]+cm.pop[	 ]+\{ra,s0-s6\},64
+[	 ]*[0-9a-f]+:[	 ]+bab6[	 ]+cm.pop[	 ]+\{ra,s0-s6\},80
+[	 ]*[0-9a-f]+:[	 ]+babe[	 ]+cm.pop[	 ]+\{ra,s0-s6\},112
+[	 ]*[0-9a-f]+:[	 ]+bac2[	 ]+cm.pop[	 ]+\{ra,s0-s7\},80
+[	 ]*[0-9a-f]+:[	 ]+bac6[	 ]+cm.pop[	 ]+\{ra,s0-s7\},96
+[	 ]*[0-9a-f]+:[	 ]+bace[	 ]+cm.pop[	 ]+\{ra,s0-s7\},128
+[	 ]*[0-9a-f]+:[	 ]+bae2[	 ]+cm.pop[	 ]+\{ra,s0-s9\},96
+[	 ]*[0-9a-f]+:[	 ]+bae6[	 ]+cm.pop[	 ]+\{ra,s0-s9\},112
+[	 ]*[0-9a-f]+:[	 ]+baee[	 ]+cm.pop[	 ]+\{ra,s0-s9\},144
+[	 ]*[0-9a-f]+:[	 ]+baf2[	 ]+cm.pop[	 ]+\{ra,s0-s11\},112
+[	 ]*[0-9a-f]+:[	 ]+baf6[	 ]+cm.pop[	 ]+\{ra,s0-s11\},128
+[	 ]*[0-9a-f]+:[	 ]+bafa[	 ]+cm.pop[	 ]+\{ra,s0-s11\},144
+[	 ]*[0-9a-f]+:[	 ]+bafe[	 ]+cm.pop[	 ]+\{ra,s0-s11\},160
+[	 ]*[0-9a-f]+:[	 ]+be4e[	 ]+cm.popret[	 ]+\{ra\},64
+[	 ]*[0-9a-f]+:[	 ]+be5e[	 ]+cm.popret[	 ]+\{ra,s0\},64
+[	 ]*[0-9a-f]+:[	 ]+be6a[	 ]+cm.popret[	 ]+\{ra,s0-s1\},64
+[	 ]*[0-9a-f]+:[	 ]+be7a[	 ]+cm.popret[	 ]+\{ra,s0-s2\},64
+[	 ]*[0-9a-f]+:[	 ]+beda[	 ]+cm.popret[	 ]+\{ra,s0-s8\},112
+[	 ]*[0-9a-f]+:[	 ]+bee6[	 ]+cm.popret[	 ]+\{ra,s0-s9\},112
+[	 ]*[0-9a-f]+:[	 ]+bef2[	 ]+cm.popret[	 ]+\{ra,s0-s11\},112
+[	 ]*[0-9a-f]+:[	 ]+be4e[	 ]+cm.popret[	 ]+\{ra\},64
+[	 ]*[0-9a-f]+:[	 ]+be5e[	 ]+cm.popret[	 ]+\{ra,s0\},64
+[	 ]*[0-9a-f]+:[	 ]+be6a[	 ]+cm.popret[	 ]+\{ra,s0-s1\},64
+[	 ]*[0-9a-f]+:[	 ]+be7a[	 ]+cm.popret[	 ]+\{ra,s0-s2\},64
+[	 ]*[0-9a-f]+:[	 ]+beda[	 ]+cm.popret[	 ]+\{ra,s0-s8\},112
+[	 ]*[0-9a-f]+:[	 ]+bee6[	 ]+cm.popret[	 ]+\{ra,s0-s9\},112
+[	 ]*[0-9a-f]+:[	 ]+bef2[	 ]+cm.popret[	 ]+\{ra,s0-s11},112
+[	 ]*[0-9a-f]+:[	 ]+be42[	 ]+cm.popret[	 ]+\{ra\},16
+[	 ]*[0-9a-f]+:[	 ]+be46[	 ]+cm.popret[	 ]+\{ra\},32
+[	 ]*[0-9a-f]+:[	 ]+be4e[	 ]+cm.popret[	 ]+\{ra\},64
+[	 ]*[0-9a-f]+:[	 ]+be72[	 ]+cm.popret[	 ]+\{ra,s0-s2\},32
+[	 ]*[0-9a-f]+:[	 ]+be7a[	 ]+cm.popret[	 ]+\{ra,s0-s2\},64
+[	 ]*[0-9a-f]+:[	 ]+be7e[	 ]+cm.popret[	 ]+\{ra,s0-s2\},80
+[	 ]*[0-9a-f]+:[	 ]+be82[	 ]+cm.popret[	 ]+\{ra,s0-s3\},48
+[	 ]*[0-9a-f]+:[	 ]+be86[	 ]+cm.popret[	 ]+\{ra,s0-s3\},64
+[	 ]*[0-9a-f]+:[	 ]+be8e[	 ]+cm.popret[	 ]+\{ra,s0-s3\},96
+[	 ]*[0-9a-f]+:[	 ]+beb2[	 ]+cm.popret[	 ]+\{ra,s0-s6\},64
+[	 ]*[0-9a-f]+:[	 ]+beb6[	 ]+cm.popret[	 ]+\{ra,s0-s6\},80
+[	 ]*[0-9a-f]+:[	 ]+bebe[	 ]+cm.popret[	 ]+\{ra,s0-s6\},112
+[	 ]*[0-9a-f]+:[	 ]+bec2[	 ]+cm.popret[	 ]+\{ra,s0-s7\},80
+[	 ]*[0-9a-f]+:[	 ]+bec6[	 ]+cm.popret[	 ]+\{ra,s0-s7\},96
+[	 ]*[0-9a-f]+:[	 ]+bece[	 ]+cm.popret[	 ]+\{ra,s0-s7\},128
+[	 ]*[0-9a-f]+:[	 ]+bee2[	 ]+cm.popret[	 ]+\{ra,s0-s9\},96
+[	 ]*[0-9a-f]+:[	 ]+bee6[	 ]+cm.popret[	 ]+\{ra,s0-s9\},112
+[	 ]*[0-9a-f]+:[	 ]+beee[	 ]+cm.popret[	 ]+\{ra,s0-s9\},144
+[	 ]*[0-9a-f]+:[	 ]+bef2[	 ]+cm.popret[	 ]+\{ra,s0-s11\},112
+[	 ]*[0-9a-f]+:[	 ]+bef6[	 ]+cm.popret[	 ]+\{ra,s0-s11\},128
+[	 ]*[0-9a-f]+:[	 ]+befa[	 ]+cm.popret[	 ]+\{ra,s0-s11\},144
+[	 ]*[0-9a-f]+:[	 ]+befe[	 ]+cm.popret[	 ]+\{ra,s0-s11\},160
+[	 ]*[0-9a-f]+:[	 ]+bc4e[	 ]+cm.popretz[	 ]+\{ra\},64
+[	 ]*[0-9a-f]+:[	 ]+bc5e[	 ]+cm.popretz[	 ]+\{ra,s0\},64
+[	 ]*[0-9a-f]+:[	 ]+bc6a[	 ]+cm.popretz[	 ]+\{ra,s0-s1\},64
+[	 ]*[0-9a-f]+:[	 ]+bc7a[	 ]+cm.popretz[	 ]+\{ra,s0-s2\},64
+[	 ]*[0-9a-f]+:[	 ]+bcda[	 ]+cm.popretz[	 ]+\{ra,s0-s8\},112
+[	 ]*[0-9a-f]+:[	 ]+bce6[	 ]+cm.popretz[	 ]+\{ra,s0-s9\},112
+[	 ]*[0-9a-f]+:[	 ]+bcf2[	 ]+cm.popretz[	 ]+\{ra,s0-s11\},112
+[	 ]*[0-9a-f]+:[	 ]+bc4e[	 ]+cm.popretz[	 ]+\{ra\},64
+[	 ]*[0-9a-f]+:[	 ]+bc5e[	 ]+cm.popretz[	 ]+\{ra,s0\},64
+[	 ]*[0-9a-f]+:[	 ]+bc6a[	 ]+cm.popretz[	 ]+\{ra,s0-s1\},64
+[	 ]*[0-9a-f]+:[	 ]+bc7a[	 ]+cm.popretz[	 ]+\{ra,s0-s2\},64
+[	 ]*[0-9a-f]+:[	 ]+bcda[	 ]+cm.popretz[	 ]+\{ra,s0-s8\},112
+[	 ]*[0-9a-f]+:[	 ]+bce6[	 ]+cm.popretz[	 ]+\{ra,s0-s9\},112
+[	 ]*[0-9a-f]+:[	 ]+bcf2[	 ]+cm.popretz[	 ]+\{ra,s0-s11},112
+[	 ]*[0-9a-f]+:[	 ]+bc42[	 ]+cm.popretz[	 ]+\{ra\},16
+[	 ]*[0-9a-f]+:[	 ]+bc46[	 ]+cm.popretz[	 ]+\{ra\},32
+[	 ]*[0-9a-f]+:[	 ]+bc4e[	 ]+cm.popretz[	 ]+\{ra\},64
+[	 ]*[0-9a-f]+:[	 ]+bc72[	 ]+cm.popretz[	 ]+\{ra,s0-s2\},32
+[	 ]*[0-9a-f]+:[	 ]+bc7a[	 ]+cm.popretz[	 ]+\{ra,s0-s2\},64
+[	 ]*[0-9a-f]+:[	 ]+bc7e[	 ]+cm.popretz[	 ]+\{ra,s0-s2\},80
+[	 ]*[0-9a-f]+:[	 ]+bc82[	 ]+cm.popretz[	 ]+\{ra,s0-s3\},48
+[	 ]*[0-9a-f]+:[	 ]+bc86[	 ]+cm.popretz[	 ]+\{ra,s0-s3\},64
+[	 ]*[0-9a-f]+:[	 ]+bc8e[	 ]+cm.popretz[	 ]+\{ra,s0-s3\},96
+[	 ]*[0-9a-f]+:[	 ]+bcb2[	 ]+cm.popretz[	 ]+\{ra,s0-s6\},64
+[	 ]*[0-9a-f]+:[	 ]+bcb6[	 ]+cm.popretz[	 ]+\{ra,s0-s6\},80
+[	 ]*[0-9a-f]+:[	 ]+bcbe[	 ]+cm.popretz[	 ]+\{ra,s0-s6\},112
+[	 ]*[0-9a-f]+:[	 ]+bcc2[	 ]+cm.popretz[	 ]+\{ra,s0-s7\},80
+[	 ]*[0-9a-f]+:[	 ]+bcc6[	 ]+cm.popretz[	 ]+\{ra,s0-s7\},96
+[	 ]*[0-9a-f]+:[	 ]+bcce[	 ]+cm.popretz[	 ]+\{ra,s0-s7\},128
+[	 ]*[0-9a-f]+:[	 ]+bce2[	 ]+cm.popretz[	 ]+\{ra,s0-s9\},96
+[	 ]*[0-9a-f]+:[	 ]+bce6[	 ]+cm.popretz[	 ]+\{ra,s0-s9\},112
+[	 ]*[0-9a-f]+:[	 ]+bcee[	 ]+cm.popretz[	 ]+\{ra,s0-s9\},144
+[	 ]*[0-9a-f]+:[	 ]+bcf2[	 ]+cm.popretz[	 ]+\{ra,s0-s11\},112
+[	 ]*[0-9a-f]+:[	 ]+bcf6[	 ]+cm.popretz[	 ]+\{ra,s0-s11\},128
+[	 ]*[0-9a-f]+:[	 ]+bcfa[	 ]+cm.popretz[	 ]+\{ra,s0-s11\},144
+[	 ]*[0-9a-f]+:[	 ]+bcfe[	 ]+cm.popretz[	 ]+\{ra,s0-s11\},160
diff --git a/gas/testsuite/gas/riscv/zcmp-push-pop.s b/gas/testsuite/gas/riscv/zcmp-push-pop.s
new file mode 100644
index 00000000000..bec40ebbcbc
--- /dev/null
+++ b/gas/testsuite/gas/riscv/zcmp-push-pop.s
@@ -0,0 +1,197 @@
+target:
+
+	# push
+	# abi names
+	cm.push {ra}, -64
+	cm.push {ra, s0}, -64
+	cm.push {ra, s0-s1}, -64
+	cm.push {ra, s0-s2}, -64
+	cm.push {ra, s0-s8}, -112
+	cm.push {ra, s0-s9}, -112
+	cm.push {ra, s0-s11}, -112
+
+	# numeric names
+	cm.push {x1}, -64
+	cm.push {x1, x8}, -64
+	cm.push {x1, x8-x9}, -64
+	cm.push {x1, x8-x9, x18}, -64
+	cm.push {x1, x8-x9, x18-x24}, -112
+	cm.push {x1, x8-x9, x18-x25}, -112
+	cm.push {x1, x8-x9, x18-x27}, -112
+
+	# spimm
+	cm.push {ra}, -16
+	cm.push {ra}, -32
+	cm.push {ra}, -64
+
+	cm.push {ra, s0-s2}, -32
+	cm.push {ra, s0-s2}, -64
+	cm.push {ra, s0-s2}, -80
+
+	cm.push {ra, s0-s3}, -48
+	cm.push {ra, s0-s3}, -64
+	cm.push {ra, s0-s3}, -96
+
+	cm.push {ra, s0-s6}, -64
+	cm.push {ra, s0-s6}, -80
+	cm.push {ra, s0-s6}, -112
+
+	cm.push {ra, s0-s7}, -80
+	cm.push {ra, s0-s7}, -96
+	cm.push {ra, s0-s7}, -128
+
+	cm.push {ra, s0-s9}, -96
+	cm.push {ra, s0-s9}, -112
+	cm.push {ra, s0-s9}, -144
+
+	cm.push {ra, s0-s11}, -112
+	cm.push {ra, s0-s11}, -128
+	cm.push {ra, s0-s11}, -144
+	cm.push {ra, s0-s11}, -160
+
+	# pop
+	# abi names
+	cm.pop {ra}, 64
+	cm.pop {ra, s0}, 64
+	cm.pop {ra, s0-s1}, 64
+	cm.pop {ra, s0-s2}, 64
+	cm.pop {ra, s0-s8}, 112
+	cm.pop {ra, s0-s9}, 112
+	cm.pop {ra, s0-s11}, 112
+
+	# numeric names
+	cm.pop {x1}, 64
+	cm.pop {x1, x8}, 64
+	cm.pop {x1, x8-x9}, 64
+	cm.pop {x1, x8-x9, x18}, 64
+	cm.pop {x1, x8-x9, x18-x24}, 112
+	cm.pop {x1, x8-x9, x18-x25}, 112
+	cm.pop {x1, x8-x9, x18-x27}, 112
+
+	# spimm
+	cm.pop {ra}, 16
+	cm.pop {ra}, 32
+	cm.pop {ra}, 64
+
+	cm.pop {ra, s0-s2}, 32
+	cm.pop {ra, s0-s2}, 64
+	cm.pop {ra, s0-s2}, 80
+
+	cm.pop {ra, s0-s3}, 48
+	cm.pop {ra, s0-s3}, 64
+	cm.pop {ra, s0-s3}, 96
+
+	cm.pop {ra, s0-s6}, 64
+	cm.pop {ra, s0-s6}, 80
+	cm.pop {ra, s0-s6}, 112
+
+	cm.pop {ra, s0-s7}, 80
+	cm.pop {ra, s0-s7}, 96
+	cm.pop {ra, s0-s7}, 128
+
+	cm.pop {ra, s0-s9}, 96
+	cm.pop {ra, s0-s9}, 112
+	cm.pop {ra, s0-s9}, 144
+
+	cm.pop {ra, s0-s11}, 112
+	cm.pop {ra, s0-s11}, 128
+	cm.pop {ra, s0-s11}, 144
+	cm.pop {ra, s0-s11}, 160
+
+	# popret
+	# abi names
+	cm.popret {ra}, 64
+	cm.popret {ra, s0}, 64
+	cm.popret {ra, s0-s1}, 64
+	cm.popret {ra, s0-s2}, 64
+	cm.popret {ra, s0-s8}, 112
+	cm.popret {ra, s0-s9}, 112
+	cm.popret {ra, s0-s11}, 112
+
+	# numeric names
+	cm.popret {x1}, 64
+	cm.popret {x1, x8}, 64
+	cm.popret {x1, x8-x9}, 64
+	cm.popret {x1, x8-x9, x18}, 64
+	cm.popret {x1, x8-x9, x18-x24}, 112
+	cm.popret {x1, x8-x9, x18-x25}, 112
+	cm.popret {x1, x8-x9, x18-x27}, 112
+
+	# spimm
+	cm.popret {ra}, 16
+	cm.popret {ra}, 32
+	cm.popret {ra}, 64
+
+	cm.popret {ra, s0-s2}, 32
+	cm.popret {ra, s0-s2}, 64
+	cm.popret {ra, s0-s2}, 80
+
+	cm.popret {ra, s0-s3}, 48
+	cm.popret {ra, s0-s3}, 64
+	cm.popret {ra, s0-s3}, 96
+
+	cm.popret {ra, s0-s6}, 64
+	cm.popret {ra, s0-s6}, 80
+	cm.popret {ra, s0-s6}, 112
+
+	cm.popret {ra, s0-s7}, 80
+	cm.popret {ra, s0-s7}, 96
+	cm.popret {ra, s0-s7}, 128
+
+	cm.popret {ra, s0-s9}, 96
+	cm.popret {ra, s0-s9}, 112
+	cm.popret {ra, s0-s9}, 144
+
+	cm.popret {ra, s0-s11}, 112
+	cm.popret {ra, s0-s11}, 128
+	cm.popret {ra, s0-s11}, 144
+	cm.popret {ra, s0-s11}, 160
+
+	# popretz
+	# abi names
+	cm.popretz {ra}, 64
+	cm.popretz {ra, s0}, 64
+	cm.popretz {ra, s0-s1}, 64
+	cm.popretz {ra, s0-s2}, 64
+	cm.popretz {ra, s0-s8}, 112
+	cm.popretz {ra, s0-s9}, 112
+	cm.popretz {ra, s0-s11}, 112
+
+	# numeric names
+	cm.popretz {x1}, 64
+	cm.popretz {x1, x8}, 64
+	cm.popretz {x1, x8-x9}, 64
+	cm.popretz {x1, x8-x9, x18}, 64
+	cm.popretz {x1, x8-x9, x18-x24}, 112
+	cm.popretz {x1, x8-x9, x18-x25}, 112
+	cm.popretz {x1, x8-x9, x18-x27}, 112
+
+	# spimm
+	cm.popretz {ra}, 16
+	cm.popretz {ra}, 32
+	cm.popretz {ra}, 64
+
+	cm.popretz {ra, s0-s2}, 32
+	cm.popretz {ra, s0-s2}, 64
+	cm.popretz {ra, s0-s2}, 80
+
+	cm.popretz {ra, s0-s3}, 48
+	cm.popretz {ra, s0-s3}, 64
+	cm.popretz {ra, s0-s3}, 96
+
+	cm.popretz {ra, s0-s6}, 64
+	cm.popretz {ra, s0-s6}, 80
+	cm.popretz {ra, s0-s6}, 112
+
+	cm.popretz {ra, s0-s7}, 80
+	cm.popretz {ra, s0-s7}, 96
+	cm.popretz {ra, s0-s7}, 128
+
+	cm.popretz {ra, s0-s9}, 96
+	cm.popretz {ra, s0-s9}, 112
+	cm.popretz {ra, s0-s9}, 144
+
+	cm.popretz {ra, s0-s11}, 112
+	cm.popretz {ra, s0-s11}, 128
+	cm.popretz {ra, s0-s11}, 144
+	cm.popretz {ra, s0-s11}, 160
diff --git a/include/opcode/riscv-opc.h b/include/opcode/riscv-opc.h
index 53f5f200508..e2724dde3bf 100644
--- a/include/opcode/riscv-opc.h
+++ b/include/opcode/riscv-opc.h
@@ -2235,6 +2235,15 @@
 #define MASK_C_NOT 0xfc7f
 #define MATCH_C_MUL 0x9c41
 #define MASK_C_MUL 0xfc63
+/* ZCMP instructions.  */
+#define MATCH_CM_PUSH 0xb802
+#define MASK_CM_PUSH 0xff03
+#define MATCH_CM_POP 0xba02
+#define MASK_CM_POP 0xff03
+#define MATCH_CM_POPRET 0xbe02
+#define MASK_CM_POPRET 0xff03
+#define MATCH_CM_POPRETZ 0xbc02
+#define MASK_CM_POPRETZ 0xff03
 /* Svinval instruction.  */
 #define MATCH_SINVAL_VMA 0x16000073
 #define MASK_SINVAL_VMA 0xfe007fff
diff --git a/include/opcode/riscv.h b/include/opcode/riscv.h
index 808f3657303..024b1e9f2bc 100644
--- a/include/opcode/riscv.h
+++ b/include/opcode/riscv.h
@@ -112,6 +112,8 @@ static inline unsigned int riscv_insn_length (insn_t insn)
   (RV_X(x, 6, 1) | (RV_X(x, 5, 1) << 1))
 #define EXTRACT_ZCB_HALFWORD_UIMM(x) \
   (RV_X(x, 5, 1) << 1)
+#define EXTRACT_ZCMP_SPIMM(x) \
+  (RV_X(x, 2, 2) << 4)
 
 #define ENCODE_ITYPE_IMM(x) \
   (RV_X(x, 0, 12) << 20)
@@ -163,6 +165,8 @@ static inline unsigned int riscv_insn_length (insn_t insn)
   ((RV_X(x, 0, 1) << 6) | (RV_X(x, 1, 1) << 5))
 #define ENCODE_ZCB_HALFWORD_UIMM(x) \
   (RV_X(x, 1, 1) << 5)
+#define ENCODE_ZCMP_SPIMM(x) \
+  (RV_X(x, 4, 2) << 2)
 
 #define VALID_ITYPE_IMM(x) (EXTRACT_ITYPE_IMM(ENCODE_ITYPE_IMM(x)) == (x))
 #define VALID_STYPE_IMM(x) (EXTRACT_STYPE_IMM(ENCODE_STYPE_IMM(x)) == (x))
@@ -190,6 +194,7 @@ static inline unsigned int riscv_insn_length (insn_t insn)
 #define VALID_RVV_VC_IMM(x) (EXTRACT_RVV_VC_IMM(ENCODE_RVV_VC_IMM(x)) == (x))
 #define VALID_ZCB_BYTE_UIMM(x) (EXTRACT_ZCB_BYTE_UIMM(ENCODE_ZCB_BYTE_UIMM(x)) == (x))
 #define VALID_ZCB_HALFWORD_UIMM(x) (EXTRACT_ZCB_HALFWORD_UIMM(ENCODE_ZCB_HALFWORD_UIMM(x)) == (x))
+#define VALID_ZCMP_SPIMM(x) (EXTRACT_ZCMP_SPIMM(ENCODE_ZCMP_SPIMM(x)) == (x))
 
 #define RISCV_RTYPE(insn, rd, rs1, rs2) \
   ((MATCH_ ## insn) | ((rd) << OP_SH_RD) | ((rs1) << OP_SH_RS1) | ((rs2) << OP_SH_RS2))
@@ -254,6 +259,8 @@ static inline unsigned int riscv_insn_length (insn_t insn)
 #define OP_SH_AQ		26
 #define OP_MASK_RL		0x1
 #define OP_SH_RL		25
+#define OP_MASK_RLIST		0xf
+#define OP_SH_RLIST		4
 
 #define OP_MASK_CSR		0xfffU
 #define OP_SH_CSR		20
@@ -330,6 +337,11 @@ static inline unsigned int riscv_insn_length (insn_t insn)
 #define X_T0 5
 #define X_T1 6
 #define X_T2 7
+#define X_S0 8
+#define X_S1 9
+#define X_S2 18
+#define X_S10 26
+#define X_S11 27
 #define X_T3 28
 
 #define NGPR 32
@@ -435,6 +447,7 @@ enum riscv_insn_class
   INSN_CLASS_ZCB_AND_ZBA,
   INSN_CLASS_ZCB_AND_ZBB,
   INSN_CLASS_ZCB_AND_ZMMUL,
+  INSN_CLASS_ZCMP,
   INSN_CLASS_SVINVAL,
   INSN_CLASS_ZICBOM,
   INSN_CLASS_ZICBOP,
diff --git a/opcodes/riscv-dis.c b/opcodes/riscv-dis.c
index 2826248f8af..d938c9cb2ed 100644
--- a/opcodes/riscv-dis.c
+++ b/opcodes/riscv-dis.c
@@ -75,6 +75,8 @@ static const char * const *riscv_fpr_names;
 /* If set, disassemble as most general instruction.  */
 static bool no_aliases = false;
 
+/* If set, disassemble numeric register names instead of ABI names.  */
+static int numeric = 0;
 
 /* Set default RISC-V disassembler options.  */
 
@@ -84,6 +86,7 @@ set_default_riscv_dis_options (void)
   riscv_gpr_names = riscv_gpr_names_abi;
   riscv_fpr_names = riscv_fpr_names_abi;
   no_aliases = false;
+  numeric = 0;
 }
 
 /* Parse RISC-V disassembler option (without arguments).  */
@@ -97,6 +100,7 @@ parse_riscv_dis_option_without_args (const char *option)
     {
       riscv_gpr_names = riscv_gpr_names_numeric;
       riscv_fpr_names = riscv_fpr_names_numeric;
+      numeric = 1;
     }
   else
     return false;
@@ -215,6 +219,50 @@ maybe_print_address (struct riscv_private_data *pd, int base_reg, int offset,
     pd->print_addr = (bfd_vma)(uint32_t)pd->print_addr;
 }
 
+/* Get ZCMP rlist field.  */
+
+static void
+print_rlist (disassemble_info *info, insn_t l)
+{
+  unsigned rlist = (int)EXTRACT_OPERAND (RLIST, l);
+  unsigned r_start = numeric ? X_S2 : X_S0;
+  info->fprintf_func (info->stream, "%s", riscv_gpr_names[X_RA]);
+
+  if (rlist == 5)
+    info->fprintf_func (info->stream, ",%s", riscv_gpr_names[X_S0]);
+  else if (rlist == 6 || (numeric && rlist > 6))
+    info->fprintf_func (info->stream, ",%s-%s",
+	  riscv_gpr_names[X_S0],
+	  riscv_gpr_names[X_S1]);
+
+  if (rlist == 15)
+    info->fprintf_func (info->stream, ",%s-%s",
+	  riscv_gpr_names[r_start],
+	  riscv_gpr_names[X_S11]);
+  else if (rlist == 7 && numeric)
+    info->fprintf_func (info->stream, ",%s",
+	  riscv_gpr_names[X_S2]);
+  else if (rlist > 6)
+    info->fprintf_func (info->stream, ",%s-%s",
+	  riscv_gpr_names[r_start],
+	  riscv_gpr_names[rlist + 11]);
+}
+
+/* Get ZCMP sp adjustment immediate.  */
+
+static int
+riscv_get_spimm (insn_t l)
+{
+  int spimm = riscv_get_sp_base(l, &riscv_rps_dis);
+
+  spimm += EXTRACT_ZCMP_SPIMM (l);
+
+  if (((l ^ MATCH_CM_PUSH) & MASK_CM_PUSH) == 0)
+    spimm *= -1;
+
+  return spimm;
+}
+
 /* Print insn arguments for 32/64-bit code.  */
 
 static void
@@ -420,6 +468,8 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info
 	case ')':
 	case '[':
 	case ']':
+	case '{':
+	case '}':
 	  print (info->stream, dis_style_text, "%c", *oparg);
 	  break;
 
@@ -625,6 +675,13 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info
 		    print (info->stream, dis_style_immediate, "%d",
 		      (int)EXTRACT_ZCB_HALFWORD_UIMM (l));
 		    break;
+		  case 'r':
+		    print_rlist (info, l);
+		    break;
+		  case 'p':
+		    print (info->stream, dis_style_immediate, "%d",
+		      riscv_get_spimm (l));
+		    break;
 		  default: break;
 		  }
 		break;
diff --git a/opcodes/riscv-opc.c b/opcodes/riscv-opc.c
index 6a854736fec..7d2f92e736b 100644
--- a/opcodes/riscv-opc.c
+++ b/opcodes/riscv-opc.c
@@ -1967,6 +1967,12 @@ const struct riscv_opcode riscv_opcodes[] =
 {"c.zext.b",   0, INSN_CLASS_ZCB, "Cs",  MATCH_C_ZEXT_B, MASK_C_ZEXT_B, match_opcode, 0 },
 {"c.sext.w",  64, INSN_CLASS_ZCB, "d",  MATCH_C_ADDIW, MASK_C_ADDIW|MASK_RVC_IMM, match_rd_nonzero, INSN_ALIAS },
 
+/* Zcmp instructions.  */
+{"cm.push",    0,  INSN_CLASS_ZCMP, "{Wcr},Wcp",  MATCH_CM_PUSH, MASK_CM_PUSH, match_opcode, 0 },
+{"cm.pop",     0,  INSN_CLASS_ZCMP, "{Wcr},Wcp",  MATCH_CM_POP, MASK_CM_POP, match_opcode, 0 },
+{"cm.popret",  0,  INSN_CLASS_ZCMP, "{Wcr},Wcp",  MATCH_CM_POPRET, MASK_CM_POPRET, match_opcode, 0 },
+{"cm.popretz", 0,  INSN_CLASS_ZCMP, "{Wcr},Wcp",  MATCH_CM_POPRETZ, MASK_CM_POPRETZ, match_opcode, 0 },
+
 /* Supervisor instructions.  */
 {"csrr",       0, INSN_CLASS_ZICSR, "d,E",   MATCH_CSRRS, MASK_CSRRS|MASK_RS1, match_opcode, INSN_ALIAS },
 {"csrw",       0, INSN_CLASS_ZICSR, "E,s",   MATCH_CSRRW, MASK_CSRRW|MASK_RD, match_opcode, INSN_ALIAS },
-- 
2.25.1


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] RISC-V: Support Zcmp push/pop instructions
  2023-07-26  3:22 [PATCH] RISC-V: Support Zcmp push/pop instructions Jiawei
@ 2023-07-26  6:50 ` Tsukasa OI
  2023-07-26  6:56   ` Tsukasa OI
  0 siblings, 1 reply; 3+ messages in thread
From: Tsukasa OI @ 2023-07-26  6:50 UTC (permalink / raw)
  To: jiawei; +Cc: binutils

Magnificent!
The register list parser is well written and makes sense.

My review comments include very minor formatting issue but functionally,
it's almost complete and feels good (in other words, it's almost the
time to improve/fix the formatting, too).

Thanks,
Tsukasa

On 2023/07/26 12:22, Jiawei wrote:
> Support zcmp extension push/pop/popret and popret zero instructions.
> `reg_list` is a list containing 1 to 13 registers, we can use: "{ra}, {ra,
> s0}, {ra, s0-s1}, {ra, s0-s2}, …, {ra, s0-sN}" to present this feature.
> `stack_adj` is the total size of the stack frame, use
> `riscv_get_sp_base` function to calculate it.
> Most work was finished by Sinan Lin.
> 
> Co-Authored by: Charlie Keaney <charlie.keaney@embecosm.com>
> Co-Authored by: Mary Bennett <mary.bennett@embecosm.com>
> Co-Authored by: Nandni Jamnadas <nandni.jamnadas@embecosm.com>
> Co-Authored by: Sinan Lin <sinan.lin@linux.alibaba.com>
> Co-Authored by: Simon Cook <simon.cook@embecosm.com>
> Co-Authored by: Shihua Liao <shihua@iscas.ac.cn>
> Co-Authored by: Yulong Shi <yulong@iscas.ac.cn>
> 
> bfd/ChangeLog:
> 
>         * elfxx-riscv.c (riscv_get_sp_base): New function.
>         (riscv_multi_subset_supports): New extension.
>         (riscv_multi_subset_supports_ext): Ditto.
>         * elfxx-riscv.h (SP_ALIGNMENT): New macro.
>         (riscv_get_sp_base): New function prototype.
> 
> gas/ChangeLog:
> 
>         * config/tc-riscv.c (regno_to_rlist): New regs mapping.
>         (reglist_lookup): New function.
>         (validate_riscv_insn): New operators.
>         (riscv_ip): Ditto.
>         * testsuite/gas/riscv/zcmp-push-pop-fail.d: New test.
>         * testsuite/gas/riscv/zcmp-push-pop-fail.l: New test.
>         * testsuite/gas/riscv/zcmp-push-pop-fail.s: New test.
>         * testsuite/gas/riscv/zcmp-push-pop.d: New test.
>         * testsuite/gas/riscv/zcmp-push-pop.s: New test.
> 
> include/ChangeLog:
> 
>         * opcode/riscv-opc.h (MATCH_CM_PUSH): New opcode.
>         (MASK_CM_PUSH): New mask.
>         (MATCH_CM_POP): New opcode.
>         (MASK_CM_POP): New mask.
>         (MATCH_CM_POPRET): New opcode.
>         (MASK_CM_POPRET): New mask.
>         (MATCH_CM_POPRETZ): New opcode.
>         (MASK_CM_POPRETZ): New mask.
>         * opcode/riscv.h (EXTRACT_ZCMP_SPIMM): New inline function.
>         (ENCODE_ZCMP_SPIMM): Ditto.
>         (VALID_ZCMP_SPIMM): Ditto.
>         (OP_MASK_RLIST): New mask.
>         (OP_SH_RLIST): New operand code.
>         (X_S0): New reg number.
>         (X_S1): Ditto.
>         (X_S2): Ditto.
>         (X_S10): Ditto.
>         (X_S11): Ditto.
>         (enum riscv_insn_class): New extension class.
> 
> opcodes/ChangeLog:
> 
>         * riscv-dis.c (set_default_riscv_dis_options): New var.
>         (parse_riscv_dis_option_without_args): Ditto.
>         (print_rlist): New print function.
>         (riscv_get_spimm): New function.
>         (print_insn_args): New operators.
>         * riscv-opc.c: New instructions.
> ---
>  bfd/elfxx-riscv.c                            |  23 ++-
>  bfd/elfxx-riscv.h                            |   4 +
>  gas/config/tc-riscv.c                        | 180 ++++++++++++++++-
>  gas/testsuite/gas/riscv/zcmp-push-pop-fail.d |   3 +
>  gas/testsuite/gas/riscv/zcmp-push-pop-fail.l |   9 +
>  gas/testsuite/gas/riscv/zcmp-push-pop-fail.s |  13 ++
>  gas/testsuite/gas/riscv/zcmp-push-pop.d      | 154 +++++++++++++++
>  gas/testsuite/gas/riscv/zcmp-push-pop.s      | 197 +++++++++++++++++++
>  include/opcode/riscv-opc.h                   |   9 +
>  include/opcode/riscv.h                       |  13 ++
>  opcodes/riscv-dis.c                          |  57 ++++++
>  opcodes/riscv-opc.c                          |   6 +
>  12 files changed, 665 insertions(+), 3 deletions(-)
>  create mode 100644 gas/testsuite/gas/riscv/zcmp-push-pop-fail.d
>  create mode 100644 gas/testsuite/gas/riscv/zcmp-push-pop-fail.l
>  create mode 100644 gas/testsuite/gas/riscv/zcmp-push-pop-fail.s
>  create mode 100644 gas/testsuite/gas/riscv/zcmp-push-pop.d
>  create mode 100644 gas/testsuite/gas/riscv/zcmp-push-pop.s
> 
> diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
> index b43d2cfa0fa..2800edb8206 100644
> --- a/bfd/elfxx-riscv.c
> +++ b/bfd/elfxx-riscv.c
> @@ -1084,6 +1084,19 @@ check_implicit_for_i (const char *implicit ATTRIBUTE_UNUSED,
>  	      && subset->minor_version < 1));
>  }
>  
> +/* get sp base adjustment */
> +
> +int
> +riscv_get_sp_base (insn_t opcode, riscv_parse_subset_t *rps)

Is this *that* generic (could be used outside?)  I will prefer either:
1.  riscv_get_sp_base_from_rlist
2.  riscv_zcmp_get_sp_base

Also, I think the most appropriate position of this function would be in
binutils/include/opcode/riscv.h (like the "riscv_insn_length" function).

We could accept "unsigned xlen" instead of a complex object "rps".

> +{
> +  unsigned reg_size = *(rps->xlen) / 8;
> +  unsigned rlist = EXTRACT_BITS (opcode, OP_MASK_RLIST, OP_SH_RLIST);
> +
> +  unsigned min_sp_adj = (rlist - 3) * reg_size + (rlist == 15 ? reg_size : 0);
> +  return ((min_sp_adj / SP_ALIGNMENT) + (min_sp_adj % SP_ALIGNMENT != 0))
> +    * SP_ALIGNMENT;
> +}
> +
>  /* Record all implicit information for the subsets.  */
>  struct riscv_implicit_subset
>  {
> @@ -1176,6 +1189,7 @@ static struct riscv_implicit_subset riscv_implicit_subsets[] =
>    {"zcf", "zca",	check_implicit_always},
>    {"zcd", "zca",	check_implicit_always},
>    {"zcb", "zca",	check_implicit_always},
> +  {"zcmp", "zca",	check_implicit_always},
>    {"smaia", "ssaia",		check_implicit_always},
>    {"smstateen", "ssstateen",	check_implicit_always},
>    {"smepmp", "zicsr",		check_implicit_always},
> @@ -1313,6 +1327,7 @@ static struct riscv_supported_ext riscv_supported_std_z_ext[] =
>    {"zcb",		ISA_SPEC_CLASS_DRAFT,		1, 0,  0 },
>    {"zcf",		ISA_SPEC_CLASS_DRAFT,		1, 0,  0 },
>    {"zcd",		ISA_SPEC_CLASS_DRAFT,		1, 0,  0 },
> +  {"zcmp",		ISA_SPEC_CLASS_DRAFT,		1, 0,  0 },
>    {NULL, 0, 0, 0, 0}
>  };
>  
> @@ -2514,8 +2529,10 @@ riscv_multi_subset_supports (riscv_parse_subset_t *rps,
>        return (riscv_subset_supports (rps, "zcb")
>  	      && riscv_subset_supports (rps, "zba"));
>      case INSN_CLASS_ZCB_AND_ZMMUL:
> -      return (riscv_subset_supports (rps, "zcb")
> -	      && riscv_subset_supports (rps, "zmmul"));
> +      return riscv_subset_supports (rps, "zcb")
> +	      && riscv_subset_supports (rps, "zmmul");
> +    case INSN_CLASS_ZCMP:
> +      return riscv_subset_supports (rps, "zcmp");
>      case INSN_CLASS_SVINVAL:
>        return riscv_subset_supports (rps, "svinval");
>      case INSN_CLASS_H:
> @@ -2732,6 +2749,8 @@ riscv_multi_subset_supports_ext (riscv_parse_subset_t *rps,
>        return _("zcb' and `zbb");
>      case INSN_CLASS_ZCB_AND_ZMMUL:
>        return _("zcb' and `zmmul', or `zcb' and `m");
> +    case INSN_CLASS_ZCMP:
> +      return "zcmp";
>      case INSN_CLASS_SVINVAL:
>        return "svinval";
>      case INSN_CLASS_H:
> diff --git a/bfd/elfxx-riscv.h b/bfd/elfxx-riscv.h
> index abcb409bd78..ae144567116 100644
> --- a/bfd/elfxx-riscv.h
> +++ b/bfd/elfxx-riscv.h
> @@ -26,6 +26,7 @@
>  #include "cpu-riscv.h"
>  
>  #define RISCV_UNKNOWN_VERSION -1
> +#define SP_ALIGNMENT 16
>  
>  struct riscv_elf_params
>  {
> @@ -123,3 +124,6 @@ extern void
>  bfd_elf32_riscv_set_data_segment_info (struct bfd_link_info *, int *);
>  extern void
>  bfd_elf64_riscv_set_data_segment_info (struct bfd_link_info *, int *);
> +
> +extern int
> +riscv_get_sp_base (insn_t, riscv_parse_subset_t *);
> \ No newline at end of file

No new line at EOF is a problem.  Insert a new line after that
declaration.  If you move the function to
binutils/include/opcode/riscv.h, this declaration will be no longer
required.

> diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
> index aaf8b9be64f..266a91451b7 100644
> --- a/gas/config/tc-riscv.c
> +++ b/gas/config/tc-riscv.c
> @@ -1237,6 +1237,152 @@ flt_lookup (float f, const float *array, size_t size, unsigned *regnop)
>    return false;
>  }
>  
> +/* Map ra and s-register to [4,15], so that we can check if the
> +    reg2 in register list reg1-reg2 or single reg2 is valid or not,
> +    and obtain the corresponding rlist value.

Indentation: 3 spaces before "reg2" and "and".

> +
> +   ra - 4
> +   s0 - 5
> +   s1 - 6
> +    ....
> +   s10 - 0 (invalid)
> +   s11 - 15
> +*/
> +
> +static int
> +regno_to_rlist (unsigned regno)
> +{
> +  if (regno == X_RA)
> +    return 4;
> +  else if (regno == X_S0 || regno == X_S1)
> +    return 5 + regno - X_S0;
> +  else if (regno >= X_S2 && regno < X_S10)
> +    return 7 + regno - X_S2;
> +  else if (regno == X_S11)
> +    return 15;
> +
> +  return 0; /* invalid symbol */
> +}
> +
> +/* Parse register list, and the parsed rlist value is stored in rlist
> +  argument.
> +
> +  If ABI register names are used (e.g. ra and s0), the register
> +  list could be "{ra}", "{ra, s0}", "{ra, s0-sN}", where 0 < N < 10 or
> +  N == 11.
> +
> +  If numeric register names are used (e.g. x1 and x8), the register list
> +  could be "{x1}", "{x1,x8}", "{x1,x8-x9}", "{x1,x8-x9, x18}" and
> +  "{x1,x8-x9,x18-xN}", where 19 < N < 25 or N == 27.
> +
> +  It will fail if numeric register names and ABI register names are used
> +  at the same time.
> +  */

Formatting: use 3 (instead of 2) spaces before the comment text (line 2
and later on the comment and end of the comment "*/").

> +
> +static bool
> +reglist_lookup (char **s, unsigned *rlist)
> +{
> +  unsigned regno;
> +  /* Use to check if the register format is xreg.  */
> +  bool use_xreg = **s == 'x';
> +
> +  /* The first register in register list should be ra.  */
> +  if (!reg_lookup (s, RCLASS_GPR, &regno)
> +      || !(*rlist = regno_to_rlist (regno)) /* update rlist */
> +      || regno != X_RA)
> +    return FALSE;

Use "false" instead of "FALSE". It applies to the all occurrences of
"FALSE" later.

> +
> +  /* Skip "whitespace, whitespace" pattern.  */
> +  while (ISSPACE (**s))
> +    ++ *s;
> +  if (**s == '}')
> +    return TRUE;

Likewise, use "true" instead of "TRUE".

> +  else if (**s != ',')
> +    return FALSE;
> +  while (ISSPACE (*++*s))
> +    ++ *s;
> +
> +  /* Do not use numeric and abi names at the same time.  */
> +  if (use_xreg && **s != 'x')
> +    return FALSE;
> +
> +  /* Reg1 should be s0 or its numeric names x8.  */
> +  if (!reg_lookup (s, RCLASS_GPR, &regno)
> +      || !(*rlist = regno_to_rlist (regno))
> +      || regno != X_S0)
> +    return FALSE;
> +
> +  /* Skip "whitespace - whitespace" pattern.  */
> +  while (ISSPACE (**s))
> +    ++ *s;
> +  if (**s == '}')
> +    return TRUE;
> +  else if (**s != '-')
> +    return FALSE;
> +  while (ISSPACE (*++*s))
> +    ++ *s;
> +
> +  if (use_xreg && **s != 'x')
> +    return FALSE;
> +
> +  /* Reg2 is x9 if the numeric name is used, otherwise,
> +    it could be any other sN register, where N > 0.  */

Indentation: 3 spaces before "it".

> +  if (!reg_lookup (s, RCLASS_GPR, &regno)
> +      || !(*rlist = regno_to_rlist (regno))
> +      || regno <= X_S0
> +      || (use_xreg && regno != X_S1))
> +    return FALSE;
> +
> +   /* Skip whitespace */

Indentation: 2 spaces before "/*".

> +  while (ISSPACE (**s))
> +    ++ *s;
> +
> +  /* Check if it is the end of register list.  */
> +  if (**s == '}')
> +    return TRUE;
> +  else if (!use_xreg)
> +    return FALSE;
> +
> +  /* Here is not reachable if the abi name is used.  */
> +  gas_assert (use_xreg);
> +
> +  /* If the numeric name is used, we need to parse extra
> +    register list, reg3 or reg3-reg4.  */

Indentation: 3 spaces before "register".

> +
> +  /* Skip ", white space" pattern.  */
> +  if (**s != ',')
> +    return FALSE;
> +  while (ISSPACE (*++*s))
> +    ++ *s;
> +
> +  if (use_xreg && **s != 'x')
> +    return FALSE;
> +
> +  /* Reg3 should be s2.  */
> +    if (!reg_lookup (s, RCLASS_GPR, &regno)
> +	|| !(*rlist = regno_to_rlist (regno))
> +	|| regno != X_S2)
> +      return FALSE;

On "if" block, reduce the indentation by 2 (prefixing 1 tab will become
6 spaces after applying this fix).

> +
> +  /* skip "whitespace - whitespace" pattern.  */
> +  while (ISSPACE (**s))
> +    ++ *s;
> +  if (**s == '}')
> +    return TRUE;
> +  else if (**s != '-')
> +    return FALSE;
> +  while (ISSPACE (*++*s))
> +    ++ *s;
> +
> +  /* Reg4 could be any other sN register, where N > 1.  */
> +  if (!reg_lookup (s, RCLASS_GPR, &regno)
> +      || !(*rlist = regno_to_rlist (regno))
> +      || regno <= X_S2)
> +    return FALSE;
> +
> +  return TRUE;
> +}
> +
>  #define USE_BITS(mask,shift) (used_bits |= ((insn_t)(mask) << (shift)))
>  #define USE_IMM(n, s) \
>    (used_bits |= ((insn_t)((1ull<<n)-1) << (s)))
> @@ -1353,6 +1499,9 @@ validate_riscv_insn (const struct riscv_opcode *opc, int length)
>  	case ',': break;
>  	case '(': break;
>  	case ')': break;
> +	case '{': break;
> +	case '}': break;
> +	case '!': break;
>  	case '<': USE_BITS (OP_MASK_SHAMTW, OP_SH_SHAMTW); break;
>  	case '>': USE_BITS (OP_MASK_SHAMT, OP_SH_SHAMT); break;
>  	case 'A': break; /* Macro operand, must be symbol.  */
> @@ -1433,6 +1582,10 @@ validate_riscv_insn (const struct riscv_opcode *opc, int length)
>  		case 'h': used_bits |= ENCODE_ZCB_HALFWORD_UIMM (-1U); break;
>  		/* halfword immediate operators, load/store halfword insns.  */
>  		case 'b': used_bits |= ENCODE_ZCB_BYTE_UIMM (-1U); break;
> +    /* immediate offset operand for cm.push and cm.pop.  */

Indentation: 2 tabs before "/*".

> +		case 'p': used_bits |= ENCODE_ZCMP_SPIMM (-1U); break;
> +		/* register list operand for cm.push and cm.pop.  */
> +		case 'r': USE_BITS (OP_MASK_RLIST, OP_SH_RLIST); break;
>  		case 'f': break;
>  		default:
>  		  goto unknown_validate_operand;
> @@ -3141,6 +3294,8 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
>  	    case ')':
>  	    case '[':
>  	    case ']':
> +	    case '{':
> +	    case '}':
>  	      if (*asarg++ == *oparg)
>  		continue;
>  	      break;
> @@ -3597,7 +3752,30 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
>  		      ip->insn_opcode |= ENCODE_ZCB_BYTE_UIMM (imm_expr->X_add_number);
>  		      goto rvc_imm_done;
>  
> -		    case 'f': /* Operand for matching immediate 255.  */
> +		    case 'r':
> +		      /* we use regno to store reglist value here.  */
> +		      if (!reglist_lookup (&asarg, &regno))
> +			break;
> +		      INSERT_OPERAND (RLIST, *ip, regno);
> +			continue;
> +
> +		    case 'p':
> +		      if (my_getSmallExpression (imm_expr, imm_reloc, asarg, p)
> +			|| imm_expr->X_op != O_constant)
> +			break;
> +		      /* convert stack adjust of cm.push to a positive offset.  */
> +		      if (ip->insn_mo->match == MATCH_CM_PUSH)
> +			imm_expr->X_add_number *= -1;
> +		      /* subtract base stack adjust and get spimm.  */
> +		      imm_expr->X_add_number -=
> +			      riscv_get_sp_base (ip->insn_opcode, &riscv_rps_as);
> +		      if (!VALID_ZCMP_SPIMM (imm_expr->X_add_number))
> +			break;
> +		      ip->insn_opcode |=
> +			ENCODE_ZCMP_SPIMM (imm_expr->X_add_number);
> +		      goto rvc_imm_done;
> +
> +			case 'f': /* operand for matching immediate 255.  */

Indentation: 2 tabs and 4 spaces before "case".

>  		      if (my_getSmallExpression (imm_expr, imm_reloc, asarg, p)
>  			  || imm_expr->X_op != O_constant
>  			  || imm_expr->X_add_number != 255)
> diff --git a/gas/testsuite/gas/riscv/zcmp-push-pop-fail.d b/gas/testsuite/gas/riscv/zcmp-push-pop-fail.d

Tests are very good (except missing new line I comment later).

But, I will recommend using the file names beginning with "zcmp-"
instead of "zcmp-push-pop-".  I think that the push/pop and "move two
registers" are being separately developed but splitting the file name
feels... too much for the final submission.

> new file mode 100644
> index 00000000000..ca1d88e6299
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/zcmp-push-pop-fail.d
> @@ -0,0 +1,3 @@
> +#as: -march=rv64i_zcmp
> +#source: zcmp-push-pop-fail.s
> +#error_output: zcmp-push-pop-fail.l
> \ No newline at end of file

Place a new line after "-fail.l".

> diff --git a/gas/testsuite/gas/riscv/zcmp-push-pop-fail.l b/gas/testsuite/gas/riscv/zcmp-push-pop-fail.l
> new file mode 100644
> index 00000000000..955e495d5bb
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/zcmp-push-pop-fail.l
> @@ -0,0 +1,9 @@
> +.*: Assembler messages:
> +.*: Error: illegal operands `cm.push \{a0\},-64'
> +.*: Error: illegal operands `cm.pop \{ra,s1\},-64'
> +.*: Error: illegal operands `cm.popret \{ra,s2-s3\},-64'
> +.*: Error: illegal operands `cm.popretz \{ra,s0-s10\},-112'
> +.*: Error: illegal operands `cm.push \{ra\},0'
> +.*: Error: illegal operands `cm.pop \{ra,s0\},-80'
> +.*: Error: illegal operands `cm.popret \{ra,s0-s1\},-15'
> +.*: Error: illegal operands `cm.popretz \{ra,s0-s11\},-165'
> diff --git a/gas/testsuite/gas/riscv/zcmp-push-pop-fail.s b/gas/testsuite/gas/riscv/zcmp-push-pop-fail.s
> new file mode 100644
> index 00000000000..a82f9399787
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/zcmp-push-pop-fail.s
> @@ -0,0 +1,13 @@
> +target:
> +
> +	# rlist
> +	cm.push {a0}, -64
> +	cm.pop {ra, s1}, -64
> +	cm.popret {ra, s2-s3}, -64
> +	cm.popretz {ra, s0-s10}, -112
> +
> +	# spimm
> +	cm.push {ra}, 0
> +	cm.pop {ra, s0}, -80
> +	cm.popret {ra, s0-s1}, -15
> +	cm.popretz {ra, s0-s11}, -165
> diff --git a/gas/testsuite/gas/riscv/zcmp-push-pop.d b/gas/testsuite/gas/riscv/zcmp-push-pop.d
> new file mode 100644
> index 00000000000..e21295051ec
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/zcmp-push-pop.d
> @@ -0,0 +1,154 @@
> +#as: -march=rv64i_zcmp
> +#source: zcmp-push-pop.s
> +#objdump: -dr -Mno-aliases
> +
> +.*:[	 ]+file format .*
> +
> +
> +Disassembly of section .text:
> +
> +0+000 <target>:
> +[	 ]*[0-9a-f]+:[	 ]+b84e[	 ]+cm.push[	 ]+\{ra\},-64
> +[	 ]*[0-9a-f]+:[	 ]+b85e[	 ]+cm.push[	 ]+\{ra,s0\},-64
> +[	 ]*[0-9a-f]+:[	 ]+b86a[	 ]+cm.push[	 ]+\{ra,s0-s1\},-64
> +[	 ]*[0-9a-f]+:[	 ]+b87a[	 ]+cm.push[	 ]+\{ra,s0-s2\},-64
> +[	 ]*[0-9a-f]+:[	 ]+b8da[	 ]+cm.push[	 ]+\{ra,s0-s8\},-112
> +[	 ]*[0-9a-f]+:[	 ]+b8e6[	 ]+cm.push[	 ]+\{ra,s0-s9\},-112
> +[	 ]*[0-9a-f]+:[	 ]+b8f2[	 ]+cm.push[	 ]+\{ra,s0-s11\},-112
> +[	 ]*[0-9a-f]+:[	 ]+b84e[	 ]+cm.push[	 ]+\{ra\},-64
> +[	 ]*[0-9a-f]+:[	 ]+b85e[	 ]+cm.push[	 ]+\{ra,s0\},-64
> +[	 ]*[0-9a-f]+:[	 ]+b86a[	 ]+cm.push[	 ]+\{ra,s0-s1\},-64
> +[	 ]*[0-9a-f]+:[	 ]+b87a[	 ]+cm.push[	 ]+\{ra,s0-s2\},-64
> +[	 ]*[0-9a-f]+:[	 ]+b8da[	 ]+cm.push[	 ]+\{ra,s0-s8\},-112
> +[	 ]*[0-9a-f]+:[	 ]+b8e6[	 ]+cm.push[	 ]+\{ra,s0-s9\},-112
> +[	 ]*[0-9a-f]+:[	 ]+b8f2[	 ]+cm.push[	 ]+\{ra,s0-s11},-112
> +[	 ]*[0-9a-f]+:[	 ]+b842[	 ]+cm.push[	 ]+\{ra\},-16
> +[	 ]*[0-9a-f]+:[	 ]+b846[	 ]+cm.push[	 ]+\{ra\},-32
> +[	 ]*[0-9a-f]+:[	 ]+b84e[	 ]+cm.push[	 ]+\{ra\},-64
> +[	 ]*[0-9a-f]+:[	 ]+b872[	 ]+cm.push[	 ]+\{ra,s0-s2\},-32
> +[	 ]*[0-9a-f]+:[	 ]+b87a[	 ]+cm.push[	 ]+\{ra,s0-s2\},-64
> +[	 ]*[0-9a-f]+:[	 ]+b87e[	 ]+cm.push[	 ]+\{ra,s0-s2\},-80
> +[	 ]*[0-9a-f]+:[	 ]+b882[	 ]+cm.push[	 ]+\{ra,s0-s3\},-48
> +[	 ]*[0-9a-f]+:[	 ]+b886[	 ]+cm.push[	 ]+\{ra,s0-s3\},-64
> +[	 ]*[0-9a-f]+:[	 ]+b88e[	 ]+cm.push[	 ]+\{ra,s0-s3\},-96
> +[	 ]*[0-9a-f]+:[	 ]+b8b2[	 ]+cm.push[	 ]+\{ra,s0-s6\},-64
> +[	 ]*[0-9a-f]+:[	 ]+b8b6[	 ]+cm.push[	 ]+\{ra,s0-s6\},-80
> +[	 ]*[0-9a-f]+:[	 ]+b8be[	 ]+cm.push[	 ]+\{ra,s0-s6\},-112
> +[	 ]*[0-9a-f]+:[	 ]+b8c2[	 ]+cm.push[	 ]+\{ra,s0-s7\},-80
> +[	 ]*[0-9a-f]+:[	 ]+b8c6[	 ]+cm.push[	 ]+\{ra,s0-s7\},-96
> +[	 ]*[0-9a-f]+:[	 ]+b8ce[	 ]+cm.push[	 ]+\{ra,s0-s7\},-128
> +[	 ]*[0-9a-f]+:[	 ]+b8e2[	 ]+cm.push[	 ]+\{ra,s0-s9\},-96
> +[	 ]*[0-9a-f]+:[	 ]+b8e6[	 ]+cm.push[	 ]+\{ra,s0-s9\},-112
> +[	 ]*[0-9a-f]+:[	 ]+b8ee[	 ]+cm.push[	 ]+\{ra,s0-s9\},-144
> +[	 ]*[0-9a-f]+:[	 ]+b8f2[	 ]+cm.push[	 ]+\{ra,s0-s11\},-112
> +[	 ]*[0-9a-f]+:[	 ]+b8f6[	 ]+cm.push[	 ]+\{ra,s0-s11\},-128
> +[	 ]*[0-9a-f]+:[	 ]+b8fa[	 ]+cm.push[	 ]+\{ra,s0-s11\},-144
> +[	 ]*[0-9a-f]+:[	 ]+b8fe[	 ]+cm.push[	 ]+\{ra,s0-s11\},-160
> +[	 ]*[0-9a-f]+:[	 ]+ba4e[	 ]+cm.pop[	 ]+\{ra\},64
> +[	 ]*[0-9a-f]+:[	 ]+ba5e[	 ]+cm.pop[	 ]+\{ra,s0\},64
> +[	 ]*[0-9a-f]+:[	 ]+ba6a[	 ]+cm.pop[	 ]+\{ra,s0-s1\},64
> +[	 ]*[0-9a-f]+:[	 ]+ba7a[	 ]+cm.pop[	 ]+\{ra,s0-s2\},64
> +[	 ]*[0-9a-f]+:[	 ]+bada[	 ]+cm.pop[	 ]+\{ra,s0-s8\},112
> +[	 ]*[0-9a-f]+:[	 ]+bae6[	 ]+cm.pop[	 ]+\{ra,s0-s9\},112
> +[	 ]*[0-9a-f]+:[	 ]+baf2[	 ]+cm.pop[	 ]+\{ra,s0-s11\},112
> +[	 ]*[0-9a-f]+:[	 ]+ba4e[	 ]+cm.pop[	 ]+\{ra\},64
> +[	 ]*[0-9a-f]+:[	 ]+ba5e[	 ]+cm.pop[	 ]+\{ra,s0\},64
> +[	 ]*[0-9a-f]+:[	 ]+ba6a[	 ]+cm.pop[	 ]+\{ra,s0-s1\},64
> +[	 ]*[0-9a-f]+:[	 ]+ba7a[	 ]+cm.pop[	 ]+\{ra,s0-s2\},64
> +[	 ]*[0-9a-f]+:[	 ]+bada[	 ]+cm.pop[	 ]+\{ra,s0-s8\},112
> +[	 ]*[0-9a-f]+:[	 ]+bae6[	 ]+cm.pop[	 ]+\{ra,s0-s9\},112
> +[	 ]*[0-9a-f]+:[	 ]+baf2[	 ]+cm.pop[	 ]+\{ra,s0-s11},112
> +[	 ]*[0-9a-f]+:[	 ]+ba42[	 ]+cm.pop[	 ]+\{ra\},16
> +[	 ]*[0-9a-f]+:[	 ]+ba46[	 ]+cm.pop[	 ]+\{ra\},32
> +[	 ]*[0-9a-f]+:[	 ]+ba4e[	 ]+cm.pop[	 ]+\{ra\},64
> +[	 ]*[0-9a-f]+:[	 ]+ba72[	 ]+cm.pop[	 ]+\{ra,s0-s2\},32
> +[	 ]*[0-9a-f]+:[	 ]+ba7a[	 ]+cm.pop[	 ]+\{ra,s0-s2\},64
> +[	 ]*[0-9a-f]+:[	 ]+ba7e[	 ]+cm.pop[	 ]+\{ra,s0-s2\},80
> +[	 ]*[0-9a-f]+:[	 ]+ba82[	 ]+cm.pop[	 ]+\{ra,s0-s3\},48
> +[	 ]*[0-9a-f]+:[	 ]+ba86[	 ]+cm.pop[	 ]+\{ra,s0-s3\},64
> +[	 ]*[0-9a-f]+:[	 ]+ba8e[	 ]+cm.pop[	 ]+\{ra,s0-s3\},96
> +[	 ]*[0-9a-f]+:[	 ]+bab2[	 ]+cm.pop[	 ]+\{ra,s0-s6\},64
> +[	 ]*[0-9a-f]+:[	 ]+bab6[	 ]+cm.pop[	 ]+\{ra,s0-s6\},80
> +[	 ]*[0-9a-f]+:[	 ]+babe[	 ]+cm.pop[	 ]+\{ra,s0-s6\},112
> +[	 ]*[0-9a-f]+:[	 ]+bac2[	 ]+cm.pop[	 ]+\{ra,s0-s7\},80
> +[	 ]*[0-9a-f]+:[	 ]+bac6[	 ]+cm.pop[	 ]+\{ra,s0-s7\},96
> +[	 ]*[0-9a-f]+:[	 ]+bace[	 ]+cm.pop[	 ]+\{ra,s0-s7\},128
> +[	 ]*[0-9a-f]+:[	 ]+bae2[	 ]+cm.pop[	 ]+\{ra,s0-s9\},96
> +[	 ]*[0-9a-f]+:[	 ]+bae6[	 ]+cm.pop[	 ]+\{ra,s0-s9\},112
> +[	 ]*[0-9a-f]+:[	 ]+baee[	 ]+cm.pop[	 ]+\{ra,s0-s9\},144
> +[	 ]*[0-9a-f]+:[	 ]+baf2[	 ]+cm.pop[	 ]+\{ra,s0-s11\},112
> +[	 ]*[0-9a-f]+:[	 ]+baf6[	 ]+cm.pop[	 ]+\{ra,s0-s11\},128
> +[	 ]*[0-9a-f]+:[	 ]+bafa[	 ]+cm.pop[	 ]+\{ra,s0-s11\},144
> +[	 ]*[0-9a-f]+:[	 ]+bafe[	 ]+cm.pop[	 ]+\{ra,s0-s11\},160
> +[	 ]*[0-9a-f]+:[	 ]+be4e[	 ]+cm.popret[	 ]+\{ra\},64
> +[	 ]*[0-9a-f]+:[	 ]+be5e[	 ]+cm.popret[	 ]+\{ra,s0\},64
> +[	 ]*[0-9a-f]+:[	 ]+be6a[	 ]+cm.popret[	 ]+\{ra,s0-s1\},64
> +[	 ]*[0-9a-f]+:[	 ]+be7a[	 ]+cm.popret[	 ]+\{ra,s0-s2\},64
> +[	 ]*[0-9a-f]+:[	 ]+beda[	 ]+cm.popret[	 ]+\{ra,s0-s8\},112
> +[	 ]*[0-9a-f]+:[	 ]+bee6[	 ]+cm.popret[	 ]+\{ra,s0-s9\},112
> +[	 ]*[0-9a-f]+:[	 ]+bef2[	 ]+cm.popret[	 ]+\{ra,s0-s11\},112
> +[	 ]*[0-9a-f]+:[	 ]+be4e[	 ]+cm.popret[	 ]+\{ra\},64
> +[	 ]*[0-9a-f]+:[	 ]+be5e[	 ]+cm.popret[	 ]+\{ra,s0\},64
> +[	 ]*[0-9a-f]+:[	 ]+be6a[	 ]+cm.popret[	 ]+\{ra,s0-s1\},64
> +[	 ]*[0-9a-f]+:[	 ]+be7a[	 ]+cm.popret[	 ]+\{ra,s0-s2\},64
> +[	 ]*[0-9a-f]+:[	 ]+beda[	 ]+cm.popret[	 ]+\{ra,s0-s8\},112
> +[	 ]*[0-9a-f]+:[	 ]+bee6[	 ]+cm.popret[	 ]+\{ra,s0-s9\},112
> +[	 ]*[0-9a-f]+:[	 ]+bef2[	 ]+cm.popret[	 ]+\{ra,s0-s11},112
> +[	 ]*[0-9a-f]+:[	 ]+be42[	 ]+cm.popret[	 ]+\{ra\},16
> +[	 ]*[0-9a-f]+:[	 ]+be46[	 ]+cm.popret[	 ]+\{ra\},32
> +[	 ]*[0-9a-f]+:[	 ]+be4e[	 ]+cm.popret[	 ]+\{ra\},64
> +[	 ]*[0-9a-f]+:[	 ]+be72[	 ]+cm.popret[	 ]+\{ra,s0-s2\},32
> +[	 ]*[0-9a-f]+:[	 ]+be7a[	 ]+cm.popret[	 ]+\{ra,s0-s2\},64
> +[	 ]*[0-9a-f]+:[	 ]+be7e[	 ]+cm.popret[	 ]+\{ra,s0-s2\},80
> +[	 ]*[0-9a-f]+:[	 ]+be82[	 ]+cm.popret[	 ]+\{ra,s0-s3\},48
> +[	 ]*[0-9a-f]+:[	 ]+be86[	 ]+cm.popret[	 ]+\{ra,s0-s3\},64
> +[	 ]*[0-9a-f]+:[	 ]+be8e[	 ]+cm.popret[	 ]+\{ra,s0-s3\},96
> +[	 ]*[0-9a-f]+:[	 ]+beb2[	 ]+cm.popret[	 ]+\{ra,s0-s6\},64
> +[	 ]*[0-9a-f]+:[	 ]+beb6[	 ]+cm.popret[	 ]+\{ra,s0-s6\},80
> +[	 ]*[0-9a-f]+:[	 ]+bebe[	 ]+cm.popret[	 ]+\{ra,s0-s6\},112
> +[	 ]*[0-9a-f]+:[	 ]+bec2[	 ]+cm.popret[	 ]+\{ra,s0-s7\},80
> +[	 ]*[0-9a-f]+:[	 ]+bec6[	 ]+cm.popret[	 ]+\{ra,s0-s7\},96
> +[	 ]*[0-9a-f]+:[	 ]+bece[	 ]+cm.popret[	 ]+\{ra,s0-s7\},128
> +[	 ]*[0-9a-f]+:[	 ]+bee2[	 ]+cm.popret[	 ]+\{ra,s0-s9\},96
> +[	 ]*[0-9a-f]+:[	 ]+bee6[	 ]+cm.popret[	 ]+\{ra,s0-s9\},112
> +[	 ]*[0-9a-f]+:[	 ]+beee[	 ]+cm.popret[	 ]+\{ra,s0-s9\},144
> +[	 ]*[0-9a-f]+:[	 ]+bef2[	 ]+cm.popret[	 ]+\{ra,s0-s11\},112
> +[	 ]*[0-9a-f]+:[	 ]+bef6[	 ]+cm.popret[	 ]+\{ra,s0-s11\},128
> +[	 ]*[0-9a-f]+:[	 ]+befa[	 ]+cm.popret[	 ]+\{ra,s0-s11\},144
> +[	 ]*[0-9a-f]+:[	 ]+befe[	 ]+cm.popret[	 ]+\{ra,s0-s11\},160
> +[	 ]*[0-9a-f]+:[	 ]+bc4e[	 ]+cm.popretz[	 ]+\{ra\},64
> +[	 ]*[0-9a-f]+:[	 ]+bc5e[	 ]+cm.popretz[	 ]+\{ra,s0\},64
> +[	 ]*[0-9a-f]+:[	 ]+bc6a[	 ]+cm.popretz[	 ]+\{ra,s0-s1\},64
> +[	 ]*[0-9a-f]+:[	 ]+bc7a[	 ]+cm.popretz[	 ]+\{ra,s0-s2\},64
> +[	 ]*[0-9a-f]+:[	 ]+bcda[	 ]+cm.popretz[	 ]+\{ra,s0-s8\},112
> +[	 ]*[0-9a-f]+:[	 ]+bce6[	 ]+cm.popretz[	 ]+\{ra,s0-s9\},112
> +[	 ]*[0-9a-f]+:[	 ]+bcf2[	 ]+cm.popretz[	 ]+\{ra,s0-s11\},112
> +[	 ]*[0-9a-f]+:[	 ]+bc4e[	 ]+cm.popretz[	 ]+\{ra\},64
> +[	 ]*[0-9a-f]+:[	 ]+bc5e[	 ]+cm.popretz[	 ]+\{ra,s0\},64
> +[	 ]*[0-9a-f]+:[	 ]+bc6a[	 ]+cm.popretz[	 ]+\{ra,s0-s1\},64
> +[	 ]*[0-9a-f]+:[	 ]+bc7a[	 ]+cm.popretz[	 ]+\{ra,s0-s2\},64
> +[	 ]*[0-9a-f]+:[	 ]+bcda[	 ]+cm.popretz[	 ]+\{ra,s0-s8\},112
> +[	 ]*[0-9a-f]+:[	 ]+bce6[	 ]+cm.popretz[	 ]+\{ra,s0-s9\},112
> +[	 ]*[0-9a-f]+:[	 ]+bcf2[	 ]+cm.popretz[	 ]+\{ra,s0-s11},112
> +[	 ]*[0-9a-f]+:[	 ]+bc42[	 ]+cm.popretz[	 ]+\{ra\},16
> +[	 ]*[0-9a-f]+:[	 ]+bc46[	 ]+cm.popretz[	 ]+\{ra\},32
> +[	 ]*[0-9a-f]+:[	 ]+bc4e[	 ]+cm.popretz[	 ]+\{ra\},64
> +[	 ]*[0-9a-f]+:[	 ]+bc72[	 ]+cm.popretz[	 ]+\{ra,s0-s2\},32
> +[	 ]*[0-9a-f]+:[	 ]+bc7a[	 ]+cm.popretz[	 ]+\{ra,s0-s2\},64
> +[	 ]*[0-9a-f]+:[	 ]+bc7e[	 ]+cm.popretz[	 ]+\{ra,s0-s2\},80
> +[	 ]*[0-9a-f]+:[	 ]+bc82[	 ]+cm.popretz[	 ]+\{ra,s0-s3\},48
> +[	 ]*[0-9a-f]+:[	 ]+bc86[	 ]+cm.popretz[	 ]+\{ra,s0-s3\},64
> +[	 ]*[0-9a-f]+:[	 ]+bc8e[	 ]+cm.popretz[	 ]+\{ra,s0-s3\},96
> +[	 ]*[0-9a-f]+:[	 ]+bcb2[	 ]+cm.popretz[	 ]+\{ra,s0-s6\},64
> +[	 ]*[0-9a-f]+:[	 ]+bcb6[	 ]+cm.popretz[	 ]+\{ra,s0-s6\},80
> +[	 ]*[0-9a-f]+:[	 ]+bcbe[	 ]+cm.popretz[	 ]+\{ra,s0-s6\},112
> +[	 ]*[0-9a-f]+:[	 ]+bcc2[	 ]+cm.popretz[	 ]+\{ra,s0-s7\},80
> +[	 ]*[0-9a-f]+:[	 ]+bcc6[	 ]+cm.popretz[	 ]+\{ra,s0-s7\},96
> +[	 ]*[0-9a-f]+:[	 ]+bcce[	 ]+cm.popretz[	 ]+\{ra,s0-s7\},128
> +[	 ]*[0-9a-f]+:[	 ]+bce2[	 ]+cm.popretz[	 ]+\{ra,s0-s9\},96
> +[	 ]*[0-9a-f]+:[	 ]+bce6[	 ]+cm.popretz[	 ]+\{ra,s0-s9\},112
> +[	 ]*[0-9a-f]+:[	 ]+bcee[	 ]+cm.popretz[	 ]+\{ra,s0-s9\},144
> +[	 ]*[0-9a-f]+:[	 ]+bcf2[	 ]+cm.popretz[	 ]+\{ra,s0-s11\},112
> +[	 ]*[0-9a-f]+:[	 ]+bcf6[	 ]+cm.popretz[	 ]+\{ra,s0-s11\},128
> +[	 ]*[0-9a-f]+:[	 ]+bcfa[	 ]+cm.popretz[	 ]+\{ra,s0-s11\},144
> +[	 ]*[0-9a-f]+:[	 ]+bcfe[	 ]+cm.popretz[	 ]+\{ra,s0-s11\},160
> diff --git a/gas/testsuite/gas/riscv/zcmp-push-pop.s b/gas/testsuite/gas/riscv/zcmp-push-pop.s
> new file mode 100644
> index 00000000000..bec40ebbcbc
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/zcmp-push-pop.s
> @@ -0,0 +1,197 @@
> +target:
> +
> +	# push
> +	# abi names
> +	cm.push {ra}, -64
> +	cm.push {ra, s0}, -64
> +	cm.push {ra, s0-s1}, -64
> +	cm.push {ra, s0-s2}, -64
> +	cm.push {ra, s0-s8}, -112
> +	cm.push {ra, s0-s9}, -112
> +	cm.push {ra, s0-s11}, -112
> +
> +	# numeric names
> +	cm.push {x1}, -64
> +	cm.push {x1, x8}, -64
> +	cm.push {x1, x8-x9}, -64
> +	cm.push {x1, x8-x9, x18}, -64
> +	cm.push {x1, x8-x9, x18-x24}, -112
> +	cm.push {x1, x8-x9, x18-x25}, -112
> +	cm.push {x1, x8-x9, x18-x27}, -112
> +
> +	# spimm
> +	cm.push {ra}, -16
> +	cm.push {ra}, -32
> +	cm.push {ra}, -64
> +
> +	cm.push {ra, s0-s2}, -32
> +	cm.push {ra, s0-s2}, -64
> +	cm.push {ra, s0-s2}, -80
> +
> +	cm.push {ra, s0-s3}, -48
> +	cm.push {ra, s0-s3}, -64
> +	cm.push {ra, s0-s3}, -96
> +
> +	cm.push {ra, s0-s6}, -64
> +	cm.push {ra, s0-s6}, -80
> +	cm.push {ra, s0-s6}, -112
> +
> +	cm.push {ra, s0-s7}, -80
> +	cm.push {ra, s0-s7}, -96
> +	cm.push {ra, s0-s7}, -128
> +
> +	cm.push {ra, s0-s9}, -96
> +	cm.push {ra, s0-s9}, -112
> +	cm.push {ra, s0-s9}, -144
> +
> +	cm.push {ra, s0-s11}, -112
> +	cm.push {ra, s0-s11}, -128
> +	cm.push {ra, s0-s11}, -144
> +	cm.push {ra, s0-s11}, -160
> +
> +	# pop
> +	# abi names
> +	cm.pop {ra}, 64
> +	cm.pop {ra, s0}, 64
> +	cm.pop {ra, s0-s1}, 64
> +	cm.pop {ra, s0-s2}, 64
> +	cm.pop {ra, s0-s8}, 112
> +	cm.pop {ra, s0-s9}, 112
> +	cm.pop {ra, s0-s11}, 112
> +
> +	# numeric names
> +	cm.pop {x1}, 64
> +	cm.pop {x1, x8}, 64
> +	cm.pop {x1, x8-x9}, 64
> +	cm.pop {x1, x8-x9, x18}, 64
> +	cm.pop {x1, x8-x9, x18-x24}, 112
> +	cm.pop {x1, x8-x9, x18-x25}, 112
> +	cm.pop {x1, x8-x9, x18-x27}, 112
> +
> +	# spimm
> +	cm.pop {ra}, 16
> +	cm.pop {ra}, 32
> +	cm.pop {ra}, 64
> +
> +	cm.pop {ra, s0-s2}, 32
> +	cm.pop {ra, s0-s2}, 64
> +	cm.pop {ra, s0-s2}, 80
> +
> +	cm.pop {ra, s0-s3}, 48
> +	cm.pop {ra, s0-s3}, 64
> +	cm.pop {ra, s0-s3}, 96
> +
> +	cm.pop {ra, s0-s6}, 64
> +	cm.pop {ra, s0-s6}, 80
> +	cm.pop {ra, s0-s6}, 112
> +
> +	cm.pop {ra, s0-s7}, 80
> +	cm.pop {ra, s0-s7}, 96
> +	cm.pop {ra, s0-s7}, 128
> +
> +	cm.pop {ra, s0-s9}, 96
> +	cm.pop {ra, s0-s9}, 112
> +	cm.pop {ra, s0-s9}, 144
> +
> +	cm.pop {ra, s0-s11}, 112
> +	cm.pop {ra, s0-s11}, 128
> +	cm.pop {ra, s0-s11}, 144
> +	cm.pop {ra, s0-s11}, 160
> +
> +	# popret
> +	# abi names
> +	cm.popret {ra}, 64
> +	cm.popret {ra, s0}, 64
> +	cm.popret {ra, s0-s1}, 64
> +	cm.popret {ra, s0-s2}, 64
> +	cm.popret {ra, s0-s8}, 112
> +	cm.popret {ra, s0-s9}, 112
> +	cm.popret {ra, s0-s11}, 112
> +
> +	# numeric names
> +	cm.popret {x1}, 64
> +	cm.popret {x1, x8}, 64
> +	cm.popret {x1, x8-x9}, 64
> +	cm.popret {x1, x8-x9, x18}, 64
> +	cm.popret {x1, x8-x9, x18-x24}, 112
> +	cm.popret {x1, x8-x9, x18-x25}, 112
> +	cm.popret {x1, x8-x9, x18-x27}, 112
> +
> +	# spimm
> +	cm.popret {ra}, 16
> +	cm.popret {ra}, 32
> +	cm.popret {ra}, 64
> +
> +	cm.popret {ra, s0-s2}, 32
> +	cm.popret {ra, s0-s2}, 64
> +	cm.popret {ra, s0-s2}, 80
> +
> +	cm.popret {ra, s0-s3}, 48
> +	cm.popret {ra, s0-s3}, 64
> +	cm.popret {ra, s0-s3}, 96
> +
> +	cm.popret {ra, s0-s6}, 64
> +	cm.popret {ra, s0-s6}, 80
> +	cm.popret {ra, s0-s6}, 112
> +
> +	cm.popret {ra, s0-s7}, 80
> +	cm.popret {ra, s0-s7}, 96
> +	cm.popret {ra, s0-s7}, 128
> +
> +	cm.popret {ra, s0-s9}, 96
> +	cm.popret {ra, s0-s9}, 112
> +	cm.popret {ra, s0-s9}, 144
> +
> +	cm.popret {ra, s0-s11}, 112
> +	cm.popret {ra, s0-s11}, 128
> +	cm.popret {ra, s0-s11}, 144
> +	cm.popret {ra, s0-s11}, 160
> +
> +	# popretz
> +	# abi names
> +	cm.popretz {ra}, 64
> +	cm.popretz {ra, s0}, 64
> +	cm.popretz {ra, s0-s1}, 64
> +	cm.popretz {ra, s0-s2}, 64
> +	cm.popretz {ra, s0-s8}, 112
> +	cm.popretz {ra, s0-s9}, 112
> +	cm.popretz {ra, s0-s11}, 112
> +
> +	# numeric names
> +	cm.popretz {x1}, 64
> +	cm.popretz {x1, x8}, 64
> +	cm.popretz {x1, x8-x9}, 64
> +	cm.popretz {x1, x8-x9, x18}, 64
> +	cm.popretz {x1, x8-x9, x18-x24}, 112
> +	cm.popretz {x1, x8-x9, x18-x25}, 112
> +	cm.popretz {x1, x8-x9, x18-x27}, 112
> +
> +	# spimm
> +	cm.popretz {ra}, 16
> +	cm.popretz {ra}, 32
> +	cm.popretz {ra}, 64
> +
> +	cm.popretz {ra, s0-s2}, 32
> +	cm.popretz {ra, s0-s2}, 64
> +	cm.popretz {ra, s0-s2}, 80
> +
> +	cm.popretz {ra, s0-s3}, 48
> +	cm.popretz {ra, s0-s3}, 64
> +	cm.popretz {ra, s0-s3}, 96
> +
> +	cm.popretz {ra, s0-s6}, 64
> +	cm.popretz {ra, s0-s6}, 80
> +	cm.popretz {ra, s0-s6}, 112
> +
> +	cm.popretz {ra, s0-s7}, 80
> +	cm.popretz {ra, s0-s7}, 96
> +	cm.popretz {ra, s0-s7}, 128
> +
> +	cm.popretz {ra, s0-s9}, 96
> +	cm.popretz {ra, s0-s9}, 112
> +	cm.popretz {ra, s0-s9}, 144
> +
> +	cm.popretz {ra, s0-s11}, 112
> +	cm.popretz {ra, s0-s11}, 128
> +	cm.popretz {ra, s0-s11}, 144
> +	cm.popretz {ra, s0-s11}, 160
> diff --git a/include/opcode/riscv-opc.h b/include/opcode/riscv-opc.h
> index 53f5f200508..e2724dde3bf 100644
> --- a/include/opcode/riscv-opc.h
> +++ b/include/opcode/riscv-opc.h
> @@ -2235,6 +2235,15 @@
>  #define MASK_C_NOT 0xfc7f
>  #define MATCH_C_MUL 0x9c41
>  #define MASK_C_MUL 0xfc63
> +/* ZCMP instructions.  */

"Zcmp" is preferred.

> +#define MATCH_CM_PUSH 0xb802
> +#define MASK_CM_PUSH 0xff03
> +#define MATCH_CM_POP 0xba02
> +#define MASK_CM_POP 0xff03
> +#define MATCH_CM_POPRET 0xbe02
> +#define MASK_CM_POPRET 0xff03
> +#define MATCH_CM_POPRETZ 0xbc02
> +#define MASK_CM_POPRETZ 0xff03
>  /* Svinval instruction.  */
>  #define MATCH_SINVAL_VMA 0x16000073
>  #define MASK_SINVAL_VMA 0xfe007fff
> diff --git a/include/opcode/riscv.h b/include/opcode/riscv.h
> index 808f3657303..024b1e9f2bc 100644
> --- a/include/opcode/riscv.h
> +++ b/include/opcode/riscv.h
> @@ -112,6 +112,8 @@ static inline unsigned int riscv_insn_length (insn_t insn)
>    (RV_X(x, 6, 1) | (RV_X(x, 5, 1) << 1))
>  #define EXTRACT_ZCB_HALFWORD_UIMM(x) \
>    (RV_X(x, 5, 1) << 1)
> +#define EXTRACT_ZCMP_SPIMM(x) \
> +  (RV_X(x, 2, 2) << 4)
>  
>  #define ENCODE_ITYPE_IMM(x) \
>    (RV_X(x, 0, 12) << 20)
> @@ -163,6 +165,8 @@ static inline unsigned int riscv_insn_length (insn_t insn)
>    ((RV_X(x, 0, 1) << 6) | (RV_X(x, 1, 1) << 5))
>  #define ENCODE_ZCB_HALFWORD_UIMM(x) \
>    (RV_X(x, 1, 1) << 5)
> +#define ENCODE_ZCMP_SPIMM(x) \
> +  (RV_X(x, 4, 2) << 2)
>  
>  #define VALID_ITYPE_IMM(x) (EXTRACT_ITYPE_IMM(ENCODE_ITYPE_IMM(x)) == (x))
>  #define VALID_STYPE_IMM(x) (EXTRACT_STYPE_IMM(ENCODE_STYPE_IMM(x)) == (x))
> @@ -190,6 +194,7 @@ static inline unsigned int riscv_insn_length (insn_t insn)
>  #define VALID_RVV_VC_IMM(x) (EXTRACT_RVV_VC_IMM(ENCODE_RVV_VC_IMM(x)) == (x))
>  #define VALID_ZCB_BYTE_UIMM(x) (EXTRACT_ZCB_BYTE_UIMM(ENCODE_ZCB_BYTE_UIMM(x)) == (x))
>  #define VALID_ZCB_HALFWORD_UIMM(x) (EXTRACT_ZCB_HALFWORD_UIMM(ENCODE_ZCB_HALFWORD_UIMM(x)) == (x))
> +#define VALID_ZCMP_SPIMM(x) (EXTRACT_ZCMP_SPIMM(ENCODE_ZCMP_SPIMM(x)) == (x))
>  
>  #define RISCV_RTYPE(insn, rd, rs1, rs2) \
>    ((MATCH_ ## insn) | ((rd) << OP_SH_RD) | ((rs1) << OP_SH_RS1) | ((rs2) << OP_SH_RS2))
> @@ -254,6 +259,8 @@ static inline unsigned int riscv_insn_length (insn_t insn)
>  #define OP_SH_AQ		26
>  #define OP_MASK_RL		0x1
>  #define OP_SH_RL		25
> +#define OP_MASK_RLIST		0xf
> +#define OP_SH_RLIST		4
>  
>  #define OP_MASK_CSR		0xfffU
>  #define OP_SH_CSR		20
> @@ -330,6 +337,11 @@ static inline unsigned int riscv_insn_length (insn_t insn)
>  #define X_T0 5
>  #define X_T1 6
>  #define X_T2 7
> +#define X_S0 8
> +#define X_S1 9
> +#define X_S2 18
> +#define X_S10 26
> +#define X_S11 27
>  #define X_T3 28
>  
>  #define NGPR 32
> @@ -435,6 +447,7 @@ enum riscv_insn_class
>    INSN_CLASS_ZCB_AND_ZBA,
>    INSN_CLASS_ZCB_AND_ZBB,
>    INSN_CLASS_ZCB_AND_ZMMUL,
> +  INSN_CLASS_ZCMP,
>    INSN_CLASS_SVINVAL,
>    INSN_CLASS_ZICBOM,
>    INSN_CLASS_ZICBOP,
> diff --git a/opcodes/riscv-dis.c b/opcodes/riscv-dis.c
> index 2826248f8af..d938c9cb2ed 100644
> --- a/opcodes/riscv-dis.c
> +++ b/opcodes/riscv-dis.c
> @@ -75,6 +75,8 @@ static const char * const *riscv_fpr_names;
>  /* If set, disassemble as most general instruction.  */
>  static bool no_aliases = false;
>  
> +/* If set, disassemble numeric register names instead of ABI names.  */
> +static int numeric = 0;

Use boolean variable and use "true" and "false" instead of "1" and "0".

>  
>  /* Set default RISC-V disassembler options.  */
>  
> @@ -84,6 +86,7 @@ set_default_riscv_dis_options (void)
>    riscv_gpr_names = riscv_gpr_names_abi;
>    riscv_fpr_names = riscv_fpr_names_abi;
>    no_aliases = false;
> +  numeric = 0;
>  }
>  
>  /* Parse RISC-V disassembler option (without arguments).  */
> @@ -97,6 +100,7 @@ parse_riscv_dis_option_without_args (const char *option)
>      {
>        riscv_gpr_names = riscv_gpr_names_numeric;
>        riscv_fpr_names = riscv_fpr_names_numeric;
> +      numeric = 1;
>      }
>    else
>      return false;
> @@ -215,6 +219,50 @@ maybe_print_address (struct riscv_private_data *pd, int base_reg, int offset,
>      pd->print_addr = (bfd_vma)(uint32_t)pd->print_addr;
>  }
>  
> +/* Get ZCMP rlist field.  */

"Zcmp" is preferred.

> +
> +static void
> +print_rlist (disassemble_info *info, insn_t l)
> +{
> +  unsigned rlist = (int)EXTRACT_OPERAND (RLIST, l);
> +  unsigned r_start = numeric ? X_S2 : X_S0;
> +  info->fprintf_func (info->stream, "%s", riscv_gpr_names[X_RA]);
> +
> +  if (rlist == 5)
> +    info->fprintf_func (info->stream, ",%s", riscv_gpr_names[X_S0]);
> +  else if (rlist == 6 || (numeric && rlist > 6))
> +    info->fprintf_func (info->stream, ",%s-%s",
> +	  riscv_gpr_names[X_S0],
> +	  riscv_gpr_names[X_S1]);
> +
> +  if (rlist == 15)
> +    info->fprintf_func (info->stream, ",%s-%s",
> +	  riscv_gpr_names[r_start],
> +	  riscv_gpr_names[X_S11]);
> +  else if (rlist == 7 && numeric)
> +    info->fprintf_func (info->stream, ",%s",
> +	  riscv_gpr_names[X_S2]);
> +  else if (rlist > 6)
> +    info->fprintf_func (info->stream, ",%s-%s",
> +	  riscv_gpr_names[r_start],
> +	  riscv_gpr_names[rlist + 11]);
> +}
> +
> +/* Get ZCMP sp adjustment immediate.  */

"Zcmp" is preferred.

> +
> +static int
> +riscv_get_spimm (insn_t l)

Is this *that* generic?
I will prefer riscv_cm_pushpop_get_spimm or some.

> +{
> +  int spimm = riscv_get_sp_base(l, &riscv_rps_dis);
> +
> +  spimm += EXTRACT_ZCMP_SPIMM (l);
> +
> +  if (((l ^ MATCH_CM_PUSH) & MASK_CM_PUSH) == 0)
> +    spimm *= -1;
> +
> +  return spimm;
> +}
> +
>  /* Print insn arguments for 32/64-bit code.  */
>  
>  static void
> @@ -420,6 +468,8 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info
>  	case ')':
>  	case '[':
>  	case ']':
> +	case '{':
> +	case '}':
>  	  print (info->stream, dis_style_text, "%c", *oparg);
>  	  break;
>  
> @@ -625,6 +675,13 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info
>  		    print (info->stream, dis_style_immediate, "%d",
>  		      (int)EXTRACT_ZCB_HALFWORD_UIMM (l));
>  		    break;
> +		  case 'r':
> +		    print_rlist (info, l);
> +		    break;
> +		  case 'p':
> +		    print (info->stream, dis_style_immediate, "%d",
> +		      riscv_get_spimm (l));

Indentation: 3 tabs and 3 spaces before "riscv_get_spimm".

> +		    break;
>  		  default: break;
>  		  }
>  		break;
> diff --git a/opcodes/riscv-opc.c b/opcodes/riscv-opc.c
> index 6a854736fec..7d2f92e736b 100644
> --- a/opcodes/riscv-opc.c
> +++ b/opcodes/riscv-opc.c
> @@ -1967,6 +1967,12 @@ const struct riscv_opcode riscv_opcodes[] =
>  {"c.zext.b",   0, INSN_CLASS_ZCB, "Cs",  MATCH_C_ZEXT_B, MASK_C_ZEXT_B, match_opcode, 0 },
>  {"c.sext.w",  64, INSN_CLASS_ZCB, "d",  MATCH_C_ADDIW, MASK_C_ADDIW|MASK_RVC_IMM, match_rd_nonzero, INSN_ALIAS },
>  
> +/* Zcmp instructions.  */
> +{"cm.push",    0,  INSN_CLASS_ZCMP, "{Wcr},Wcp",  MATCH_CM_PUSH, MASK_CM_PUSH, match_opcode, 0 },
> +{"cm.pop",     0,  INSN_CLASS_ZCMP, "{Wcr},Wcp",  MATCH_CM_POP, MASK_CM_POP, match_opcode, 0 },
> +{"cm.popret",  0,  INSN_CLASS_ZCMP, "{Wcr},Wcp",  MATCH_CM_POPRET, MASK_CM_POPRET, match_opcode, 0 },
> +{"cm.popretz", 0,  INSN_CLASS_ZCMP, "{Wcr},Wcp",  MATCH_CM_POPRETZ, MASK_CM_POPRETZ, match_opcode, 0 },
> +
>  /* Supervisor instructions.  */
>  {"csrr",       0, INSN_CLASS_ZICSR, "d,E",   MATCH_CSRRS, MASK_CSRRS|MASK_RS1, match_opcode, INSN_ALIAS },
>  {"csrw",       0, INSN_CLASS_ZICSR, "E,s",   MATCH_CSRRW, MASK_CSRRW|MASK_RD, match_opcode, INSN_ALIAS },

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] RISC-V: Support Zcmp push/pop instructions
  2023-07-26  6:50 ` Tsukasa OI
@ 2023-07-26  6:56   ` Tsukasa OI
  0 siblings, 0 replies; 3+ messages in thread
From: Tsukasa OI @ 2023-07-26  6:56 UTC (permalink / raw)
  To: jiawei; +Cc: Binutils

On 2023/07/26 15:50, Tsukasa OI via Binutils wrote:
> Magnificent!
> The register list parser is well written and makes sense.
> 
> My review comments include very minor formatting issue but functionally,
> it's almost complete and feels good (in other words, it's almost the
> time to improve/fix the formatting, too).
> 
> Thanks,
> Tsukasa
> 
> On 2023/07/26 12:22, Jiawei wrote:
>> Support zcmp extension push/pop/popret and popret zero instructions.
>> `reg_list` is a list containing 1 to 13 registers, we can use: "{ra}, {ra,
>> s0}, {ra, s0-s1}, {ra, s0-s2}, …, {ra, s0-sN}" to present this feature.
>> `stack_adj` is the total size of the stack frame, use
>> `riscv_get_sp_base` function to calculate it.
>> Most work was finished by Sinan Lin.
>>
>> Co-Authored by: Charlie Keaney <charlie.keaney@embecosm.com>
>> Co-Authored by: Mary Bennett <mary.bennett@embecosm.com>
>> Co-Authored by: Nandni Jamnadas <nandni.jamnadas@embecosm.com>
>> Co-Authored by: Sinan Lin <sinan.lin@linux.alibaba.com>
>> Co-Authored by: Simon Cook <simon.cook@embecosm.com>
>> Co-Authored by: Shihua Liao <shihua@iscas.ac.cn>
>> Co-Authored by: Yulong Shi <yulong@iscas.ac.cn>
>>
>> bfd/ChangeLog:
>>
>>         * elfxx-riscv.c (riscv_get_sp_base): New function.
>>         (riscv_multi_subset_supports): New extension.
>>         (riscv_multi_subset_supports_ext): Ditto.
>>         * elfxx-riscv.h (SP_ALIGNMENT): New macro.
>>         (riscv_get_sp_base): New function prototype.
>>
>> gas/ChangeLog:
>>
>>         * config/tc-riscv.c (regno_to_rlist): New regs mapping.
>>         (reglist_lookup): New function.
>>         (validate_riscv_insn): New operators.
>>         (riscv_ip): Ditto.
>>         * testsuite/gas/riscv/zcmp-push-pop-fail.d: New test.
>>         * testsuite/gas/riscv/zcmp-push-pop-fail.l: New test.
>>         * testsuite/gas/riscv/zcmp-push-pop-fail.s: New test.
>>         * testsuite/gas/riscv/zcmp-push-pop.d: New test.
>>         * testsuite/gas/riscv/zcmp-push-pop.s: New test.
>>
>> include/ChangeLog:
>>
>>         * opcode/riscv-opc.h (MATCH_CM_PUSH): New opcode.
>>         (MASK_CM_PUSH): New mask.
>>         (MATCH_CM_POP): New opcode.
>>         (MASK_CM_POP): New mask.
>>         (MATCH_CM_POPRET): New opcode.
>>         (MASK_CM_POPRET): New mask.
>>         (MATCH_CM_POPRETZ): New opcode.
>>         (MASK_CM_POPRETZ): New mask.
>>         * opcode/riscv.h (EXTRACT_ZCMP_SPIMM): New inline function.
>>         (ENCODE_ZCMP_SPIMM): Ditto.
>>         (VALID_ZCMP_SPIMM): Ditto.
>>         (OP_MASK_RLIST): New mask.
>>         (OP_SH_RLIST): New operand code.
>>         (X_S0): New reg number.
>>         (X_S1): Ditto.
>>         (X_S2): Ditto.
>>         (X_S10): Ditto.
>>         (X_S11): Ditto.
>>         (enum riscv_insn_class): New extension class.
>>
>> opcodes/ChangeLog:
>>
>>         * riscv-dis.c (set_default_riscv_dis_options): New var.
>>         (parse_riscv_dis_option_without_args): Ditto.
>>         (print_rlist): New print function.
>>         (riscv_get_spimm): New function.
>>         (print_insn_args): New operators.
>>         * riscv-opc.c: New instructions.
>> ---
>>  bfd/elfxx-riscv.c                            |  23 ++-
>>  bfd/elfxx-riscv.h                            |   4 +
>>  gas/config/tc-riscv.c                        | 180 ++++++++++++++++-
>>  gas/testsuite/gas/riscv/zcmp-push-pop-fail.d |   3 +
>>  gas/testsuite/gas/riscv/zcmp-push-pop-fail.l |   9 +
>>  gas/testsuite/gas/riscv/zcmp-push-pop-fail.s |  13 ++
>>  gas/testsuite/gas/riscv/zcmp-push-pop.d      | 154 +++++++++++++++
>>  gas/testsuite/gas/riscv/zcmp-push-pop.s      | 197 +++++++++++++++++++
>>  include/opcode/riscv-opc.h                   |   9 +
>>  include/opcode/riscv.h                       |  13 ++
>>  opcodes/riscv-dis.c                          |  57 ++++++
>>  opcodes/riscv-opc.c                          |   6 +
>>  12 files changed, 665 insertions(+), 3 deletions(-)
>>  create mode 100644 gas/testsuite/gas/riscv/zcmp-push-pop-fail.d
>>  create mode 100644 gas/testsuite/gas/riscv/zcmp-push-pop-fail.l
>>  create mode 100644 gas/testsuite/gas/riscv/zcmp-push-pop-fail.s
>>  create mode 100644 gas/testsuite/gas/riscv/zcmp-push-pop.d
>>  create mode 100644 gas/testsuite/gas/riscv/zcmp-push-pop.s
>>
>> diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
>> index b43d2cfa0fa..2800edb8206 100644
>> --- a/bfd/elfxx-riscv.c
>> +++ b/bfd/elfxx-riscv.c
>> @@ -1084,6 +1084,19 @@ check_implicit_for_i (const char *implicit ATTRIBUTE_UNUSED,
>>  	      && subset->minor_version < 1));
>>  }
>>  
>> +/* get sp base adjustment */
>> +
>> +int
>> +riscv_get_sp_base (insn_t opcode, riscv_parse_subset_t *rps)
> 
> Is this *that* generic (could be used outside?)  I will prefer either:
> 1.  riscv_get_sp_base_from_rlist
> 2.  riscv_zcmp_get_sp_base
> 
> Also, I think the most appropriate position of this function would be in
> binutils/include/opcode/riscv.h (like the "riscv_insn_length" function).
> 
> We could accept "unsigned xlen" instead of a complex object "rps".
> 
>> +{
>> +  unsigned reg_size = *(rps->xlen) / 8;
>> +  unsigned rlist = EXTRACT_BITS (opcode, OP_MASK_RLIST, OP_SH_RLIST);
>> +
>> +  unsigned min_sp_adj = (rlist - 3) * reg_size + (rlist == 15 ? reg_size : 0);
>> +  return ((min_sp_adj / SP_ALIGNMENT) + (min_sp_adj % SP_ALIGNMENT != 0))
>> +    * SP_ALIGNMENT;
>> +}
>> +
>>  /* Record all implicit information for the subsets.  */
>>  struct riscv_implicit_subset
>>  {
>> @@ -1176,6 +1189,7 @@ static struct riscv_implicit_subset riscv_implicit_subsets[] =
>>    {"zcf", "zca",	check_implicit_always},
>>    {"zcd", "zca",	check_implicit_always},
>>    {"zcb", "zca",	check_implicit_always},
>> +  {"zcmp", "zca",	check_implicit_always},
>>    {"smaia", "ssaia",		check_implicit_always},
>>    {"smstateen", "ssstateen",	check_implicit_always},
>>    {"smepmp", "zicsr",		check_implicit_always},
>> @@ -1313,6 +1327,7 @@ static struct riscv_supported_ext riscv_supported_std_z_ext[] =
>>    {"zcb",		ISA_SPEC_CLASS_DRAFT,		1, 0,  0 },
>>    {"zcf",		ISA_SPEC_CLASS_DRAFT,		1, 0,  0 },
>>    {"zcd",		ISA_SPEC_CLASS_DRAFT,		1, 0,  0 },
>> +  {"zcmp",		ISA_SPEC_CLASS_DRAFT,		1, 0,  0 },
>>    {NULL, 0, 0, 0, 0}
>>  };
>>  
>> @@ -2514,8 +2529,10 @@ riscv_multi_subset_supports (riscv_parse_subset_t *rps,
>>        return (riscv_subset_supports (rps, "zcb")
>>  	      && riscv_subset_supports (rps, "zba"));
>>      case INSN_CLASS_ZCB_AND_ZMMUL:
>> -      return (riscv_subset_supports (rps, "zcb")
>> -	      && riscv_subset_supports (rps, "zmmul"));
>> +      return riscv_subset_supports (rps, "zcb")
>> +	      && riscv_subset_supports (rps, "zmmul");
>> +    case INSN_CLASS_ZCMP:
>> +      return riscv_subset_supports (rps, "zcmp");
>>      case INSN_CLASS_SVINVAL:
>>        return riscv_subset_supports (rps, "svinval");
>>      case INSN_CLASS_H:
>> @@ -2732,6 +2749,8 @@ riscv_multi_subset_supports_ext (riscv_parse_subset_t *rps,
>>        return _("zcb' and `zbb");
>>      case INSN_CLASS_ZCB_AND_ZMMUL:
>>        return _("zcb' and `zmmul', or `zcb' and `m");
>> +    case INSN_CLASS_ZCMP:
>> +      return "zcmp";
>>      case INSN_CLASS_SVINVAL:
>>        return "svinval";
>>      case INSN_CLASS_H:
>> diff --git a/bfd/elfxx-riscv.h b/bfd/elfxx-riscv.h
>> index abcb409bd78..ae144567116 100644
>> --- a/bfd/elfxx-riscv.h
>> +++ b/bfd/elfxx-riscv.h
>> @@ -26,6 +26,7 @@
>>  #include "cpu-riscv.h"
>>  
>>  #define RISCV_UNKNOWN_VERSION -1
>> +#define SP_ALIGNMENT 16
>>  
>>  struct riscv_elf_params
>>  {
>> @@ -123,3 +124,6 @@ extern void
>>  bfd_elf32_riscv_set_data_segment_info (struct bfd_link_info *, int *);
>>  extern void
>>  bfd_elf64_riscv_set_data_segment_info (struct bfd_link_info *, int *);
>> +
>> +extern int
>> +riscv_get_sp_base (insn_t, riscv_parse_subset_t *);
>> \ No newline at end of file
> 
> No new line at EOF is a problem.  Insert a new line after that
> declaration.  If you move the function to
> binutils/include/opcode/riscv.h, this declaration will be no longer
> required.
> 
>> diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
>> index aaf8b9be64f..266a91451b7 100644
>> --- a/gas/config/tc-riscv.c
>> +++ b/gas/config/tc-riscv.c
>> @@ -1237,6 +1237,152 @@ flt_lookup (float f, const float *array, size_t size, unsigned *regnop)
>>    return false;
>>  }
>>  
>> +/* Map ra and s-register to [4,15], so that we can check if the
>> +    reg2 in register list reg1-reg2 or single reg2 is valid or not,
>> +    and obtain the corresponding rlist value.
> 
> Indentation: 3 spaces before "reg2" and "and".
> 
>> +
>> +   ra - 4
>> +   s0 - 5
>> +   s1 - 6
>> +    ....
>> +   s10 - 0 (invalid)
>> +   s11 - 15
>> +*/
>> +
>> +static int
>> +regno_to_rlist (unsigned regno)
>> +{
>> +  if (regno == X_RA)
>> +    return 4;
>> +  else if (regno == X_S0 || regno == X_S1)
>> +    return 5 + regno - X_S0;
>> +  else if (regno >= X_S2 && regno < X_S10)
>> +    return 7 + regno - X_S2;
>> +  else if (regno == X_S11)
>> +    return 15;
>> +
>> +  return 0; /* invalid symbol */
>> +}
>> +
>> +/* Parse register list, and the parsed rlist value is stored in rlist
>> +  argument.
>> +
>> +  If ABI register names are used (e.g. ra and s0), the register
>> +  list could be "{ra}", "{ra, s0}", "{ra, s0-sN}", where 0 < N < 10 or
>> +  N == 11.
>> +
>> +  If numeric register names are used (e.g. x1 and x8), the register list
>> +  could be "{x1}", "{x1,x8}", "{x1,x8-x9}", "{x1,x8-x9, x18}" and
>> +  "{x1,x8-x9,x18-xN}", where 19 < N < 25 or N == 27.
>> +
>> +  It will fail if numeric register names and ABI register names are used
>> +  at the same time.
>> +  */
> 
> Formatting: use 3 (instead of 2) spaces before the comment text (line 2
> and later on the comment and end of the comment "*/").
> 
>> +
>> +static bool
>> +reglist_lookup (char **s, unsigned *rlist)
>> +{
>> +  unsigned regno;
>> +  /* Use to check if the register format is xreg.  */
>> +  bool use_xreg = **s == 'x';
>> +
>> +  /* The first register in register list should be ra.  */
>> +  if (!reg_lookup (s, RCLASS_GPR, &regno)
>> +      || !(*rlist = regno_to_rlist (regno)) /* update rlist */
>> +      || regno != X_RA)
>> +    return FALSE;
> 
> Use "false" instead of "FALSE". It applies to the all occurrences of
> "FALSE" later.
> 
>> +
>> +  /* Skip "whitespace, whitespace" pattern.  */
>> +  while (ISSPACE (**s))
>> +    ++ *s;
>> +  if (**s == '}')
>> +    return TRUE;
> 
> Likewise, use "true" instead of "TRUE".
> 
>> +  else if (**s != ',')
>> +    return FALSE;
>> +  while (ISSPACE (*++*s))
>> +    ++ *s;
>> +
>> +  /* Do not use numeric and abi names at the same time.  */
>> +  if (use_xreg && **s != 'x')
>> +    return FALSE;
>> +
>> +  /* Reg1 should be s0 or its numeric names x8.  */
>> +  if (!reg_lookup (s, RCLASS_GPR, &regno)
>> +      || !(*rlist = regno_to_rlist (regno))
>> +      || regno != X_S0)
>> +    return FALSE;
>> +
>> +  /* Skip "whitespace - whitespace" pattern.  */
>> +  while (ISSPACE (**s))
>> +    ++ *s;
>> +  if (**s == '}')
>> +    return TRUE;
>> +  else if (**s != '-')
>> +    return FALSE;
>> +  while (ISSPACE (*++*s))
>> +    ++ *s;
>> +
>> +  if (use_xreg && **s != 'x')
>> +    return FALSE;
>> +
>> +  /* Reg2 is x9 if the numeric name is used, otherwise,
>> +    it could be any other sN register, where N > 0.  */
> 
> Indentation: 3 spaces before "it".

Oops, my bad.  It should have been: **5** spaces before "it".

> 
>> +  if (!reg_lookup (s, RCLASS_GPR, &regno)
>> +      || !(*rlist = regno_to_rlist (regno))
>> +      || regno <= X_S0
>> +      || (use_xreg && regno != X_S1))
>> +    return FALSE;
>> +
>> +   /* Skip whitespace */
> 
> Indentation: 2 spaces before "/*".
> 
>> +  while (ISSPACE (**s))
>> +    ++ *s;
>> +
>> +  /* Check if it is the end of register list.  */
>> +  if (**s == '}')
>> +    return TRUE;
>> +  else if (!use_xreg)
>> +    return FALSE;
>> +
>> +  /* Here is not reachable if the abi name is used.  */
>> +  gas_assert (use_xreg);
>> +
>> +  /* If the numeric name is used, we need to parse extra
>> +    register list, reg3 or reg3-reg4.  */
> 
> Indentation: 3 spaces before "register".
> 
>> +
>> +  /* Skip ", white space" pattern.  */
>> +  if (**s != ',')
>> +    return FALSE;
>> +  while (ISSPACE (*++*s))
>> +    ++ *s;
>> +
>> +  if (use_xreg && **s != 'x')
>> +    return FALSE;
>> +
>> +  /* Reg3 should be s2.  */
>> +    if (!reg_lookup (s, RCLASS_GPR, &regno)
>> +	|| !(*rlist = regno_to_rlist (regno))
>> +	|| regno != X_S2)
>> +      return FALSE;
> 
> On "if" block, reduce the indentation by 2 (prefixing 1 tab will become
> 6 spaces after applying this fix).
> 
>> +
>> +  /* skip "whitespace - whitespace" pattern.  */
>> +  while (ISSPACE (**s))
>> +    ++ *s;
>> +  if (**s == '}')
>> +    return TRUE;
>> +  else if (**s != '-')
>> +    return FALSE;
>> +  while (ISSPACE (*++*s))
>> +    ++ *s;
>> +
>> +  /* Reg4 could be any other sN register, where N > 1.  */
>> +  if (!reg_lookup (s, RCLASS_GPR, &regno)
>> +      || !(*rlist = regno_to_rlist (regno))
>> +      || regno <= X_S2)
>> +    return FALSE;
>> +
>> +  return TRUE;
>> +}
>> +
>>  #define USE_BITS(mask,shift) (used_bits |= ((insn_t)(mask) << (shift)))
>>  #define USE_IMM(n, s) \
>>    (used_bits |= ((insn_t)((1ull<<n)-1) << (s)))
>> @@ -1353,6 +1499,9 @@ validate_riscv_insn (const struct riscv_opcode *opc, int length)
>>  	case ',': break;
>>  	case '(': break;
>>  	case ')': break;
>> +	case '{': break;
>> +	case '}': break;
>> +	case '!': break;
>>  	case '<': USE_BITS (OP_MASK_SHAMTW, OP_SH_SHAMTW); break;
>>  	case '>': USE_BITS (OP_MASK_SHAMT, OP_SH_SHAMT); break;
>>  	case 'A': break; /* Macro operand, must be symbol.  */
>> @@ -1433,6 +1582,10 @@ validate_riscv_insn (const struct riscv_opcode *opc, int length)
>>  		case 'h': used_bits |= ENCODE_ZCB_HALFWORD_UIMM (-1U); break;
>>  		/* halfword immediate operators, load/store halfword insns.  */
>>  		case 'b': used_bits |= ENCODE_ZCB_BYTE_UIMM (-1U); break;
>> +    /* immediate offset operand for cm.push and cm.pop.  */
> 
> Indentation: 2 tabs before "/*".
> 
>> +		case 'p': used_bits |= ENCODE_ZCMP_SPIMM (-1U); break;
>> +		/* register list operand for cm.push and cm.pop.  */
>> +		case 'r': USE_BITS (OP_MASK_RLIST, OP_SH_RLIST); break;
>>  		case 'f': break;
>>  		default:
>>  		  goto unknown_validate_operand;
>> @@ -3141,6 +3294,8 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
>>  	    case ')':
>>  	    case '[':
>>  	    case ']':
>> +	    case '{':
>> +	    case '}':
>>  	      if (*asarg++ == *oparg)
>>  		continue;
>>  	      break;
>> @@ -3597,7 +3752,30 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
>>  		      ip->insn_opcode |= ENCODE_ZCB_BYTE_UIMM (imm_expr->X_add_number);
>>  		      goto rvc_imm_done;
>>  
>> -		    case 'f': /* Operand for matching immediate 255.  */
>> +		    case 'r':
>> +		      /* we use regno to store reglist value here.  */
>> +		      if (!reglist_lookup (&asarg, &regno))
>> +			break;
>> +		      INSERT_OPERAND (RLIST, *ip, regno);
>> +			continue;
>> +
>> +		    case 'p':
>> +		      if (my_getSmallExpression (imm_expr, imm_reloc, asarg, p)
>> +			|| imm_expr->X_op != O_constant)
>> +			break;
>> +		      /* convert stack adjust of cm.push to a positive offset.  */
>> +		      if (ip->insn_mo->match == MATCH_CM_PUSH)
>> +			imm_expr->X_add_number *= -1;
>> +		      /* subtract base stack adjust and get spimm.  */
>> +		      imm_expr->X_add_number -=
>> +			      riscv_get_sp_base (ip->insn_opcode, &riscv_rps_as);
>> +		      if (!VALID_ZCMP_SPIMM (imm_expr->X_add_number))
>> +			break;
>> +		      ip->insn_opcode |=
>> +			ENCODE_ZCMP_SPIMM (imm_expr->X_add_number);
>> +		      goto rvc_imm_done;
>> +
>> +			case 'f': /* operand for matching immediate 255.  */
> 
> Indentation: 2 tabs and 4 spaces before "case".
> 
>>  		      if (my_getSmallExpression (imm_expr, imm_reloc, asarg, p)
>>  			  || imm_expr->X_op != O_constant
>>  			  || imm_expr->X_add_number != 255)
>> diff --git a/gas/testsuite/gas/riscv/zcmp-push-pop-fail.d b/gas/testsuite/gas/riscv/zcmp-push-pop-fail.d
> 
> Tests are very good (except missing new line I comment later).
> 
> But, I will recommend using the file names beginning with "zcmp-"
> instead of "zcmp-push-pop-".  I think that the push/pop and "move two
> registers" are being separately developed but splitting the file name
> feels... too much for the final submission.
> 
>> new file mode 100644
>> index 00000000000..ca1d88e6299
>> --- /dev/null
>> +++ b/gas/testsuite/gas/riscv/zcmp-push-pop-fail.d
>> @@ -0,0 +1,3 @@
>> +#as: -march=rv64i_zcmp
>> +#source: zcmp-push-pop-fail.s
>> +#error_output: zcmp-push-pop-fail.l
>> \ No newline at end of file
> 
> Place a new line after "-fail.l".
> 
>> diff --git a/gas/testsuite/gas/riscv/zcmp-push-pop-fail.l b/gas/testsuite/gas/riscv/zcmp-push-pop-fail.l
>> new file mode 100644
>> index 00000000000..955e495d5bb
>> --- /dev/null
>> +++ b/gas/testsuite/gas/riscv/zcmp-push-pop-fail.l
>> @@ -0,0 +1,9 @@
>> +.*: Assembler messages:
>> +.*: Error: illegal operands `cm.push \{a0\},-64'
>> +.*: Error: illegal operands `cm.pop \{ra,s1\},-64'
>> +.*: Error: illegal operands `cm.popret \{ra,s2-s3\},-64'
>> +.*: Error: illegal operands `cm.popretz \{ra,s0-s10\},-112'
>> +.*: Error: illegal operands `cm.push \{ra\},0'
>> +.*: Error: illegal operands `cm.pop \{ra,s0\},-80'
>> +.*: Error: illegal operands `cm.popret \{ra,s0-s1\},-15'
>> +.*: Error: illegal operands `cm.popretz \{ra,s0-s11\},-165'
>> diff --git a/gas/testsuite/gas/riscv/zcmp-push-pop-fail.s b/gas/testsuite/gas/riscv/zcmp-push-pop-fail.s
>> new file mode 100644
>> index 00000000000..a82f9399787
>> --- /dev/null
>> +++ b/gas/testsuite/gas/riscv/zcmp-push-pop-fail.s
>> @@ -0,0 +1,13 @@
>> +target:
>> +
>> +	# rlist
>> +	cm.push {a0}, -64
>> +	cm.pop {ra, s1}, -64
>> +	cm.popret {ra, s2-s3}, -64
>> +	cm.popretz {ra, s0-s10}, -112
>> +
>> +	# spimm
>> +	cm.push {ra}, 0
>> +	cm.pop {ra, s0}, -80
>> +	cm.popret {ra, s0-s1}, -15
>> +	cm.popretz {ra, s0-s11}, -165
>> diff --git a/gas/testsuite/gas/riscv/zcmp-push-pop.d b/gas/testsuite/gas/riscv/zcmp-push-pop.d
>> new file mode 100644
>> index 00000000000..e21295051ec
>> --- /dev/null
>> +++ b/gas/testsuite/gas/riscv/zcmp-push-pop.d
>> @@ -0,0 +1,154 @@
>> +#as: -march=rv64i_zcmp
>> +#source: zcmp-push-pop.s
>> +#objdump: -dr -Mno-aliases
>> +
>> +.*:[	 ]+file format .*
>> +
>> +
>> +Disassembly of section .text:
>> +
>> +0+000 <target>:
>> +[	 ]*[0-9a-f]+:[	 ]+b84e[	 ]+cm.push[	 ]+\{ra\},-64
>> +[	 ]*[0-9a-f]+:[	 ]+b85e[	 ]+cm.push[	 ]+\{ra,s0\},-64
>> +[	 ]*[0-9a-f]+:[	 ]+b86a[	 ]+cm.push[	 ]+\{ra,s0-s1\},-64
>> +[	 ]*[0-9a-f]+:[	 ]+b87a[	 ]+cm.push[	 ]+\{ra,s0-s2\},-64
>> +[	 ]*[0-9a-f]+:[	 ]+b8da[	 ]+cm.push[	 ]+\{ra,s0-s8\},-112
>> +[	 ]*[0-9a-f]+:[	 ]+b8e6[	 ]+cm.push[	 ]+\{ra,s0-s9\},-112
>> +[	 ]*[0-9a-f]+:[	 ]+b8f2[	 ]+cm.push[	 ]+\{ra,s0-s11\},-112
>> +[	 ]*[0-9a-f]+:[	 ]+b84e[	 ]+cm.push[	 ]+\{ra\},-64
>> +[	 ]*[0-9a-f]+:[	 ]+b85e[	 ]+cm.push[	 ]+\{ra,s0\},-64
>> +[	 ]*[0-9a-f]+:[	 ]+b86a[	 ]+cm.push[	 ]+\{ra,s0-s1\},-64
>> +[	 ]*[0-9a-f]+:[	 ]+b87a[	 ]+cm.push[	 ]+\{ra,s0-s2\},-64
>> +[	 ]*[0-9a-f]+:[	 ]+b8da[	 ]+cm.push[	 ]+\{ra,s0-s8\},-112
>> +[	 ]*[0-9a-f]+:[	 ]+b8e6[	 ]+cm.push[	 ]+\{ra,s0-s9\},-112
>> +[	 ]*[0-9a-f]+:[	 ]+b8f2[	 ]+cm.push[	 ]+\{ra,s0-s11},-112
>> +[	 ]*[0-9a-f]+:[	 ]+b842[	 ]+cm.push[	 ]+\{ra\},-16
>> +[	 ]*[0-9a-f]+:[	 ]+b846[	 ]+cm.push[	 ]+\{ra\},-32
>> +[	 ]*[0-9a-f]+:[	 ]+b84e[	 ]+cm.push[	 ]+\{ra\},-64
>> +[	 ]*[0-9a-f]+:[	 ]+b872[	 ]+cm.push[	 ]+\{ra,s0-s2\},-32
>> +[	 ]*[0-9a-f]+:[	 ]+b87a[	 ]+cm.push[	 ]+\{ra,s0-s2\},-64
>> +[	 ]*[0-9a-f]+:[	 ]+b87e[	 ]+cm.push[	 ]+\{ra,s0-s2\},-80
>> +[	 ]*[0-9a-f]+:[	 ]+b882[	 ]+cm.push[	 ]+\{ra,s0-s3\},-48
>> +[	 ]*[0-9a-f]+:[	 ]+b886[	 ]+cm.push[	 ]+\{ra,s0-s3\},-64
>> +[	 ]*[0-9a-f]+:[	 ]+b88e[	 ]+cm.push[	 ]+\{ra,s0-s3\},-96
>> +[	 ]*[0-9a-f]+:[	 ]+b8b2[	 ]+cm.push[	 ]+\{ra,s0-s6\},-64
>> +[	 ]*[0-9a-f]+:[	 ]+b8b6[	 ]+cm.push[	 ]+\{ra,s0-s6\},-80
>> +[	 ]*[0-9a-f]+:[	 ]+b8be[	 ]+cm.push[	 ]+\{ra,s0-s6\},-112
>> +[	 ]*[0-9a-f]+:[	 ]+b8c2[	 ]+cm.push[	 ]+\{ra,s0-s7\},-80
>> +[	 ]*[0-9a-f]+:[	 ]+b8c6[	 ]+cm.push[	 ]+\{ra,s0-s7\},-96
>> +[	 ]*[0-9a-f]+:[	 ]+b8ce[	 ]+cm.push[	 ]+\{ra,s0-s7\},-128
>> +[	 ]*[0-9a-f]+:[	 ]+b8e2[	 ]+cm.push[	 ]+\{ra,s0-s9\},-96
>> +[	 ]*[0-9a-f]+:[	 ]+b8e6[	 ]+cm.push[	 ]+\{ra,s0-s9\},-112
>> +[	 ]*[0-9a-f]+:[	 ]+b8ee[	 ]+cm.push[	 ]+\{ra,s0-s9\},-144
>> +[	 ]*[0-9a-f]+:[	 ]+b8f2[	 ]+cm.push[	 ]+\{ra,s0-s11\},-112
>> +[	 ]*[0-9a-f]+:[	 ]+b8f6[	 ]+cm.push[	 ]+\{ra,s0-s11\},-128
>> +[	 ]*[0-9a-f]+:[	 ]+b8fa[	 ]+cm.push[	 ]+\{ra,s0-s11\},-144
>> +[	 ]*[0-9a-f]+:[	 ]+b8fe[	 ]+cm.push[	 ]+\{ra,s0-s11\},-160
>> +[	 ]*[0-9a-f]+:[	 ]+ba4e[	 ]+cm.pop[	 ]+\{ra\},64
>> +[	 ]*[0-9a-f]+:[	 ]+ba5e[	 ]+cm.pop[	 ]+\{ra,s0\},64
>> +[	 ]*[0-9a-f]+:[	 ]+ba6a[	 ]+cm.pop[	 ]+\{ra,s0-s1\},64
>> +[	 ]*[0-9a-f]+:[	 ]+ba7a[	 ]+cm.pop[	 ]+\{ra,s0-s2\},64
>> +[	 ]*[0-9a-f]+:[	 ]+bada[	 ]+cm.pop[	 ]+\{ra,s0-s8\},112
>> +[	 ]*[0-9a-f]+:[	 ]+bae6[	 ]+cm.pop[	 ]+\{ra,s0-s9\},112
>> +[	 ]*[0-9a-f]+:[	 ]+baf2[	 ]+cm.pop[	 ]+\{ra,s0-s11\},112
>> +[	 ]*[0-9a-f]+:[	 ]+ba4e[	 ]+cm.pop[	 ]+\{ra\},64
>> +[	 ]*[0-9a-f]+:[	 ]+ba5e[	 ]+cm.pop[	 ]+\{ra,s0\},64
>> +[	 ]*[0-9a-f]+:[	 ]+ba6a[	 ]+cm.pop[	 ]+\{ra,s0-s1\},64
>> +[	 ]*[0-9a-f]+:[	 ]+ba7a[	 ]+cm.pop[	 ]+\{ra,s0-s2\},64
>> +[	 ]*[0-9a-f]+:[	 ]+bada[	 ]+cm.pop[	 ]+\{ra,s0-s8\},112
>> +[	 ]*[0-9a-f]+:[	 ]+bae6[	 ]+cm.pop[	 ]+\{ra,s0-s9\},112
>> +[	 ]*[0-9a-f]+:[	 ]+baf2[	 ]+cm.pop[	 ]+\{ra,s0-s11},112
>> +[	 ]*[0-9a-f]+:[	 ]+ba42[	 ]+cm.pop[	 ]+\{ra\},16
>> +[	 ]*[0-9a-f]+:[	 ]+ba46[	 ]+cm.pop[	 ]+\{ra\},32
>> +[	 ]*[0-9a-f]+:[	 ]+ba4e[	 ]+cm.pop[	 ]+\{ra\},64
>> +[	 ]*[0-9a-f]+:[	 ]+ba72[	 ]+cm.pop[	 ]+\{ra,s0-s2\},32
>> +[	 ]*[0-9a-f]+:[	 ]+ba7a[	 ]+cm.pop[	 ]+\{ra,s0-s2\},64
>> +[	 ]*[0-9a-f]+:[	 ]+ba7e[	 ]+cm.pop[	 ]+\{ra,s0-s2\},80
>> +[	 ]*[0-9a-f]+:[	 ]+ba82[	 ]+cm.pop[	 ]+\{ra,s0-s3\},48
>> +[	 ]*[0-9a-f]+:[	 ]+ba86[	 ]+cm.pop[	 ]+\{ra,s0-s3\},64
>> +[	 ]*[0-9a-f]+:[	 ]+ba8e[	 ]+cm.pop[	 ]+\{ra,s0-s3\},96
>> +[	 ]*[0-9a-f]+:[	 ]+bab2[	 ]+cm.pop[	 ]+\{ra,s0-s6\},64
>> +[	 ]*[0-9a-f]+:[	 ]+bab6[	 ]+cm.pop[	 ]+\{ra,s0-s6\},80
>> +[	 ]*[0-9a-f]+:[	 ]+babe[	 ]+cm.pop[	 ]+\{ra,s0-s6\},112
>> +[	 ]*[0-9a-f]+:[	 ]+bac2[	 ]+cm.pop[	 ]+\{ra,s0-s7\},80
>> +[	 ]*[0-9a-f]+:[	 ]+bac6[	 ]+cm.pop[	 ]+\{ra,s0-s7\},96
>> +[	 ]*[0-9a-f]+:[	 ]+bace[	 ]+cm.pop[	 ]+\{ra,s0-s7\},128
>> +[	 ]*[0-9a-f]+:[	 ]+bae2[	 ]+cm.pop[	 ]+\{ra,s0-s9\},96
>> +[	 ]*[0-9a-f]+:[	 ]+bae6[	 ]+cm.pop[	 ]+\{ra,s0-s9\},112
>> +[	 ]*[0-9a-f]+:[	 ]+baee[	 ]+cm.pop[	 ]+\{ra,s0-s9\},144
>> +[	 ]*[0-9a-f]+:[	 ]+baf2[	 ]+cm.pop[	 ]+\{ra,s0-s11\},112
>> +[	 ]*[0-9a-f]+:[	 ]+baf6[	 ]+cm.pop[	 ]+\{ra,s0-s11\},128
>> +[	 ]*[0-9a-f]+:[	 ]+bafa[	 ]+cm.pop[	 ]+\{ra,s0-s11\},144
>> +[	 ]*[0-9a-f]+:[	 ]+bafe[	 ]+cm.pop[	 ]+\{ra,s0-s11\},160
>> +[	 ]*[0-9a-f]+:[	 ]+be4e[	 ]+cm.popret[	 ]+\{ra\},64
>> +[	 ]*[0-9a-f]+:[	 ]+be5e[	 ]+cm.popret[	 ]+\{ra,s0\},64
>> +[	 ]*[0-9a-f]+:[	 ]+be6a[	 ]+cm.popret[	 ]+\{ra,s0-s1\},64
>> +[	 ]*[0-9a-f]+:[	 ]+be7a[	 ]+cm.popret[	 ]+\{ra,s0-s2\},64
>> +[	 ]*[0-9a-f]+:[	 ]+beda[	 ]+cm.popret[	 ]+\{ra,s0-s8\},112
>> +[	 ]*[0-9a-f]+:[	 ]+bee6[	 ]+cm.popret[	 ]+\{ra,s0-s9\},112
>> +[	 ]*[0-9a-f]+:[	 ]+bef2[	 ]+cm.popret[	 ]+\{ra,s0-s11\},112
>> +[	 ]*[0-9a-f]+:[	 ]+be4e[	 ]+cm.popret[	 ]+\{ra\},64
>> +[	 ]*[0-9a-f]+:[	 ]+be5e[	 ]+cm.popret[	 ]+\{ra,s0\},64
>> +[	 ]*[0-9a-f]+:[	 ]+be6a[	 ]+cm.popret[	 ]+\{ra,s0-s1\},64
>> +[	 ]*[0-9a-f]+:[	 ]+be7a[	 ]+cm.popret[	 ]+\{ra,s0-s2\},64
>> +[	 ]*[0-9a-f]+:[	 ]+beda[	 ]+cm.popret[	 ]+\{ra,s0-s8\},112
>> +[	 ]*[0-9a-f]+:[	 ]+bee6[	 ]+cm.popret[	 ]+\{ra,s0-s9\},112
>> +[	 ]*[0-9a-f]+:[	 ]+bef2[	 ]+cm.popret[	 ]+\{ra,s0-s11},112
>> +[	 ]*[0-9a-f]+:[	 ]+be42[	 ]+cm.popret[	 ]+\{ra\},16
>> +[	 ]*[0-9a-f]+:[	 ]+be46[	 ]+cm.popret[	 ]+\{ra\},32
>> +[	 ]*[0-9a-f]+:[	 ]+be4e[	 ]+cm.popret[	 ]+\{ra\},64
>> +[	 ]*[0-9a-f]+:[	 ]+be72[	 ]+cm.popret[	 ]+\{ra,s0-s2\},32
>> +[	 ]*[0-9a-f]+:[	 ]+be7a[	 ]+cm.popret[	 ]+\{ra,s0-s2\},64
>> +[	 ]*[0-9a-f]+:[	 ]+be7e[	 ]+cm.popret[	 ]+\{ra,s0-s2\},80
>> +[	 ]*[0-9a-f]+:[	 ]+be82[	 ]+cm.popret[	 ]+\{ra,s0-s3\},48
>> +[	 ]*[0-9a-f]+:[	 ]+be86[	 ]+cm.popret[	 ]+\{ra,s0-s3\},64
>> +[	 ]*[0-9a-f]+:[	 ]+be8e[	 ]+cm.popret[	 ]+\{ra,s0-s3\},96
>> +[	 ]*[0-9a-f]+:[	 ]+beb2[	 ]+cm.popret[	 ]+\{ra,s0-s6\},64
>> +[	 ]*[0-9a-f]+:[	 ]+beb6[	 ]+cm.popret[	 ]+\{ra,s0-s6\},80
>> +[	 ]*[0-9a-f]+:[	 ]+bebe[	 ]+cm.popret[	 ]+\{ra,s0-s6\},112
>> +[	 ]*[0-9a-f]+:[	 ]+bec2[	 ]+cm.popret[	 ]+\{ra,s0-s7\},80
>> +[	 ]*[0-9a-f]+:[	 ]+bec6[	 ]+cm.popret[	 ]+\{ra,s0-s7\},96
>> +[	 ]*[0-9a-f]+:[	 ]+bece[	 ]+cm.popret[	 ]+\{ra,s0-s7\},128
>> +[	 ]*[0-9a-f]+:[	 ]+bee2[	 ]+cm.popret[	 ]+\{ra,s0-s9\},96
>> +[	 ]*[0-9a-f]+:[	 ]+bee6[	 ]+cm.popret[	 ]+\{ra,s0-s9\},112
>> +[	 ]*[0-9a-f]+:[	 ]+beee[	 ]+cm.popret[	 ]+\{ra,s0-s9\},144
>> +[	 ]*[0-9a-f]+:[	 ]+bef2[	 ]+cm.popret[	 ]+\{ra,s0-s11\},112
>> +[	 ]*[0-9a-f]+:[	 ]+bef6[	 ]+cm.popret[	 ]+\{ra,s0-s11\},128
>> +[	 ]*[0-9a-f]+:[	 ]+befa[	 ]+cm.popret[	 ]+\{ra,s0-s11\},144
>> +[	 ]*[0-9a-f]+:[	 ]+befe[	 ]+cm.popret[	 ]+\{ra,s0-s11\},160
>> +[	 ]*[0-9a-f]+:[	 ]+bc4e[	 ]+cm.popretz[	 ]+\{ra\},64
>> +[	 ]*[0-9a-f]+:[	 ]+bc5e[	 ]+cm.popretz[	 ]+\{ra,s0\},64
>> +[	 ]*[0-9a-f]+:[	 ]+bc6a[	 ]+cm.popretz[	 ]+\{ra,s0-s1\},64
>> +[	 ]*[0-9a-f]+:[	 ]+bc7a[	 ]+cm.popretz[	 ]+\{ra,s0-s2\},64
>> +[	 ]*[0-9a-f]+:[	 ]+bcda[	 ]+cm.popretz[	 ]+\{ra,s0-s8\},112
>> +[	 ]*[0-9a-f]+:[	 ]+bce6[	 ]+cm.popretz[	 ]+\{ra,s0-s9\},112
>> +[	 ]*[0-9a-f]+:[	 ]+bcf2[	 ]+cm.popretz[	 ]+\{ra,s0-s11\},112
>> +[	 ]*[0-9a-f]+:[	 ]+bc4e[	 ]+cm.popretz[	 ]+\{ra\},64
>> +[	 ]*[0-9a-f]+:[	 ]+bc5e[	 ]+cm.popretz[	 ]+\{ra,s0\},64
>> +[	 ]*[0-9a-f]+:[	 ]+bc6a[	 ]+cm.popretz[	 ]+\{ra,s0-s1\},64
>> +[	 ]*[0-9a-f]+:[	 ]+bc7a[	 ]+cm.popretz[	 ]+\{ra,s0-s2\},64
>> +[	 ]*[0-9a-f]+:[	 ]+bcda[	 ]+cm.popretz[	 ]+\{ra,s0-s8\},112
>> +[	 ]*[0-9a-f]+:[	 ]+bce6[	 ]+cm.popretz[	 ]+\{ra,s0-s9\},112
>> +[	 ]*[0-9a-f]+:[	 ]+bcf2[	 ]+cm.popretz[	 ]+\{ra,s0-s11},112
>> +[	 ]*[0-9a-f]+:[	 ]+bc42[	 ]+cm.popretz[	 ]+\{ra\},16
>> +[	 ]*[0-9a-f]+:[	 ]+bc46[	 ]+cm.popretz[	 ]+\{ra\},32
>> +[	 ]*[0-9a-f]+:[	 ]+bc4e[	 ]+cm.popretz[	 ]+\{ra\},64
>> +[	 ]*[0-9a-f]+:[	 ]+bc72[	 ]+cm.popretz[	 ]+\{ra,s0-s2\},32
>> +[	 ]*[0-9a-f]+:[	 ]+bc7a[	 ]+cm.popretz[	 ]+\{ra,s0-s2\},64
>> +[	 ]*[0-9a-f]+:[	 ]+bc7e[	 ]+cm.popretz[	 ]+\{ra,s0-s2\},80
>> +[	 ]*[0-9a-f]+:[	 ]+bc82[	 ]+cm.popretz[	 ]+\{ra,s0-s3\},48
>> +[	 ]*[0-9a-f]+:[	 ]+bc86[	 ]+cm.popretz[	 ]+\{ra,s0-s3\},64
>> +[	 ]*[0-9a-f]+:[	 ]+bc8e[	 ]+cm.popretz[	 ]+\{ra,s0-s3\},96
>> +[	 ]*[0-9a-f]+:[	 ]+bcb2[	 ]+cm.popretz[	 ]+\{ra,s0-s6\},64
>> +[	 ]*[0-9a-f]+:[	 ]+bcb6[	 ]+cm.popretz[	 ]+\{ra,s0-s6\},80
>> +[	 ]*[0-9a-f]+:[	 ]+bcbe[	 ]+cm.popretz[	 ]+\{ra,s0-s6\},112
>> +[	 ]*[0-9a-f]+:[	 ]+bcc2[	 ]+cm.popretz[	 ]+\{ra,s0-s7\},80
>> +[	 ]*[0-9a-f]+:[	 ]+bcc6[	 ]+cm.popretz[	 ]+\{ra,s0-s7\},96
>> +[	 ]*[0-9a-f]+:[	 ]+bcce[	 ]+cm.popretz[	 ]+\{ra,s0-s7\},128
>> +[	 ]*[0-9a-f]+:[	 ]+bce2[	 ]+cm.popretz[	 ]+\{ra,s0-s9\},96
>> +[	 ]*[0-9a-f]+:[	 ]+bce6[	 ]+cm.popretz[	 ]+\{ra,s0-s9\},112
>> +[	 ]*[0-9a-f]+:[	 ]+bcee[	 ]+cm.popretz[	 ]+\{ra,s0-s9\},144
>> +[	 ]*[0-9a-f]+:[	 ]+bcf2[	 ]+cm.popretz[	 ]+\{ra,s0-s11\},112
>> +[	 ]*[0-9a-f]+:[	 ]+bcf6[	 ]+cm.popretz[	 ]+\{ra,s0-s11\},128
>> +[	 ]*[0-9a-f]+:[	 ]+bcfa[	 ]+cm.popretz[	 ]+\{ra,s0-s11\},144
>> +[	 ]*[0-9a-f]+:[	 ]+bcfe[	 ]+cm.popretz[	 ]+\{ra,s0-s11\},160
>> diff --git a/gas/testsuite/gas/riscv/zcmp-push-pop.s b/gas/testsuite/gas/riscv/zcmp-push-pop.s
>> new file mode 100644
>> index 00000000000..bec40ebbcbc
>> --- /dev/null
>> +++ b/gas/testsuite/gas/riscv/zcmp-push-pop.s
>> @@ -0,0 +1,197 @@
>> +target:
>> +
>> +	# push
>> +	# abi names
>> +	cm.push {ra}, -64
>> +	cm.push {ra, s0}, -64
>> +	cm.push {ra, s0-s1}, -64
>> +	cm.push {ra, s0-s2}, -64
>> +	cm.push {ra, s0-s8}, -112
>> +	cm.push {ra, s0-s9}, -112
>> +	cm.push {ra, s0-s11}, -112
>> +
>> +	# numeric names
>> +	cm.push {x1}, -64
>> +	cm.push {x1, x8}, -64
>> +	cm.push {x1, x8-x9}, -64
>> +	cm.push {x1, x8-x9, x18}, -64
>> +	cm.push {x1, x8-x9, x18-x24}, -112
>> +	cm.push {x1, x8-x9, x18-x25}, -112
>> +	cm.push {x1, x8-x9, x18-x27}, -112
>> +
>> +	# spimm
>> +	cm.push {ra}, -16
>> +	cm.push {ra}, -32
>> +	cm.push {ra}, -64
>> +
>> +	cm.push {ra, s0-s2}, -32
>> +	cm.push {ra, s0-s2}, -64
>> +	cm.push {ra, s0-s2}, -80
>> +
>> +	cm.push {ra, s0-s3}, -48
>> +	cm.push {ra, s0-s3}, -64
>> +	cm.push {ra, s0-s3}, -96
>> +
>> +	cm.push {ra, s0-s6}, -64
>> +	cm.push {ra, s0-s6}, -80
>> +	cm.push {ra, s0-s6}, -112
>> +
>> +	cm.push {ra, s0-s7}, -80
>> +	cm.push {ra, s0-s7}, -96
>> +	cm.push {ra, s0-s7}, -128
>> +
>> +	cm.push {ra, s0-s9}, -96
>> +	cm.push {ra, s0-s9}, -112
>> +	cm.push {ra, s0-s9}, -144
>> +
>> +	cm.push {ra, s0-s11}, -112
>> +	cm.push {ra, s0-s11}, -128
>> +	cm.push {ra, s0-s11}, -144
>> +	cm.push {ra, s0-s11}, -160
>> +
>> +	# pop
>> +	# abi names
>> +	cm.pop {ra}, 64
>> +	cm.pop {ra, s0}, 64
>> +	cm.pop {ra, s0-s1}, 64
>> +	cm.pop {ra, s0-s2}, 64
>> +	cm.pop {ra, s0-s8}, 112
>> +	cm.pop {ra, s0-s9}, 112
>> +	cm.pop {ra, s0-s11}, 112
>> +
>> +	# numeric names
>> +	cm.pop {x1}, 64
>> +	cm.pop {x1, x8}, 64
>> +	cm.pop {x1, x8-x9}, 64
>> +	cm.pop {x1, x8-x9, x18}, 64
>> +	cm.pop {x1, x8-x9, x18-x24}, 112
>> +	cm.pop {x1, x8-x9, x18-x25}, 112
>> +	cm.pop {x1, x8-x9, x18-x27}, 112
>> +
>> +	# spimm
>> +	cm.pop {ra}, 16
>> +	cm.pop {ra}, 32
>> +	cm.pop {ra}, 64
>> +
>> +	cm.pop {ra, s0-s2}, 32
>> +	cm.pop {ra, s0-s2}, 64
>> +	cm.pop {ra, s0-s2}, 80
>> +
>> +	cm.pop {ra, s0-s3}, 48
>> +	cm.pop {ra, s0-s3}, 64
>> +	cm.pop {ra, s0-s3}, 96
>> +
>> +	cm.pop {ra, s0-s6}, 64
>> +	cm.pop {ra, s0-s6}, 80
>> +	cm.pop {ra, s0-s6}, 112
>> +
>> +	cm.pop {ra, s0-s7}, 80
>> +	cm.pop {ra, s0-s7}, 96
>> +	cm.pop {ra, s0-s7}, 128
>> +
>> +	cm.pop {ra, s0-s9}, 96
>> +	cm.pop {ra, s0-s9}, 112
>> +	cm.pop {ra, s0-s9}, 144
>> +
>> +	cm.pop {ra, s0-s11}, 112
>> +	cm.pop {ra, s0-s11}, 128
>> +	cm.pop {ra, s0-s11}, 144
>> +	cm.pop {ra, s0-s11}, 160
>> +
>> +	# popret
>> +	# abi names
>> +	cm.popret {ra}, 64
>> +	cm.popret {ra, s0}, 64
>> +	cm.popret {ra, s0-s1}, 64
>> +	cm.popret {ra, s0-s2}, 64
>> +	cm.popret {ra, s0-s8}, 112
>> +	cm.popret {ra, s0-s9}, 112
>> +	cm.popret {ra, s0-s11}, 112
>> +
>> +	# numeric names
>> +	cm.popret {x1}, 64
>> +	cm.popret {x1, x8}, 64
>> +	cm.popret {x1, x8-x9}, 64
>> +	cm.popret {x1, x8-x9, x18}, 64
>> +	cm.popret {x1, x8-x9, x18-x24}, 112
>> +	cm.popret {x1, x8-x9, x18-x25}, 112
>> +	cm.popret {x1, x8-x9, x18-x27}, 112
>> +
>> +	# spimm
>> +	cm.popret {ra}, 16
>> +	cm.popret {ra}, 32
>> +	cm.popret {ra}, 64
>> +
>> +	cm.popret {ra, s0-s2}, 32
>> +	cm.popret {ra, s0-s2}, 64
>> +	cm.popret {ra, s0-s2}, 80
>> +
>> +	cm.popret {ra, s0-s3}, 48
>> +	cm.popret {ra, s0-s3}, 64
>> +	cm.popret {ra, s0-s3}, 96
>> +
>> +	cm.popret {ra, s0-s6}, 64
>> +	cm.popret {ra, s0-s6}, 80
>> +	cm.popret {ra, s0-s6}, 112
>> +
>> +	cm.popret {ra, s0-s7}, 80
>> +	cm.popret {ra, s0-s7}, 96
>> +	cm.popret {ra, s0-s7}, 128
>> +
>> +	cm.popret {ra, s0-s9}, 96
>> +	cm.popret {ra, s0-s9}, 112
>> +	cm.popret {ra, s0-s9}, 144
>> +
>> +	cm.popret {ra, s0-s11}, 112
>> +	cm.popret {ra, s0-s11}, 128
>> +	cm.popret {ra, s0-s11}, 144
>> +	cm.popret {ra, s0-s11}, 160
>> +
>> +	# popretz
>> +	# abi names
>> +	cm.popretz {ra}, 64
>> +	cm.popretz {ra, s0}, 64
>> +	cm.popretz {ra, s0-s1}, 64
>> +	cm.popretz {ra, s0-s2}, 64
>> +	cm.popretz {ra, s0-s8}, 112
>> +	cm.popretz {ra, s0-s9}, 112
>> +	cm.popretz {ra, s0-s11}, 112
>> +
>> +	# numeric names
>> +	cm.popretz {x1}, 64
>> +	cm.popretz {x1, x8}, 64
>> +	cm.popretz {x1, x8-x9}, 64
>> +	cm.popretz {x1, x8-x9, x18}, 64
>> +	cm.popretz {x1, x8-x9, x18-x24}, 112
>> +	cm.popretz {x1, x8-x9, x18-x25}, 112
>> +	cm.popretz {x1, x8-x9, x18-x27}, 112
>> +
>> +	# spimm
>> +	cm.popretz {ra}, 16
>> +	cm.popretz {ra}, 32
>> +	cm.popretz {ra}, 64
>> +
>> +	cm.popretz {ra, s0-s2}, 32
>> +	cm.popretz {ra, s0-s2}, 64
>> +	cm.popretz {ra, s0-s2}, 80
>> +
>> +	cm.popretz {ra, s0-s3}, 48
>> +	cm.popretz {ra, s0-s3}, 64
>> +	cm.popretz {ra, s0-s3}, 96
>> +
>> +	cm.popretz {ra, s0-s6}, 64
>> +	cm.popretz {ra, s0-s6}, 80
>> +	cm.popretz {ra, s0-s6}, 112
>> +
>> +	cm.popretz {ra, s0-s7}, 80
>> +	cm.popretz {ra, s0-s7}, 96
>> +	cm.popretz {ra, s0-s7}, 128
>> +
>> +	cm.popretz {ra, s0-s9}, 96
>> +	cm.popretz {ra, s0-s9}, 112
>> +	cm.popretz {ra, s0-s9}, 144
>> +
>> +	cm.popretz {ra, s0-s11}, 112
>> +	cm.popretz {ra, s0-s11}, 128
>> +	cm.popretz {ra, s0-s11}, 144
>> +	cm.popretz {ra, s0-s11}, 160
>> diff --git a/include/opcode/riscv-opc.h b/include/opcode/riscv-opc.h
>> index 53f5f200508..e2724dde3bf 100644
>> --- a/include/opcode/riscv-opc.h
>> +++ b/include/opcode/riscv-opc.h
>> @@ -2235,6 +2235,15 @@
>>  #define MASK_C_NOT 0xfc7f
>>  #define MATCH_C_MUL 0x9c41
>>  #define MASK_C_MUL 0xfc63
>> +/* ZCMP instructions.  */
> 
> "Zcmp" is preferred.
> 
>> +#define MATCH_CM_PUSH 0xb802
>> +#define MASK_CM_PUSH 0xff03
>> +#define MATCH_CM_POP 0xba02
>> +#define MASK_CM_POP 0xff03
>> +#define MATCH_CM_POPRET 0xbe02
>> +#define MASK_CM_POPRET 0xff03
>> +#define MATCH_CM_POPRETZ 0xbc02
>> +#define MASK_CM_POPRETZ 0xff03
>>  /* Svinval instruction.  */
>>  #define MATCH_SINVAL_VMA 0x16000073
>>  #define MASK_SINVAL_VMA 0xfe007fff
>> diff --git a/include/opcode/riscv.h b/include/opcode/riscv.h
>> index 808f3657303..024b1e9f2bc 100644
>> --- a/include/opcode/riscv.h
>> +++ b/include/opcode/riscv.h
>> @@ -112,6 +112,8 @@ static inline unsigned int riscv_insn_length (insn_t insn)
>>    (RV_X(x, 6, 1) | (RV_X(x, 5, 1) << 1))
>>  #define EXTRACT_ZCB_HALFWORD_UIMM(x) \
>>    (RV_X(x, 5, 1) << 1)
>> +#define EXTRACT_ZCMP_SPIMM(x) \
>> +  (RV_X(x, 2, 2) << 4)
>>  
>>  #define ENCODE_ITYPE_IMM(x) \
>>    (RV_X(x, 0, 12) << 20)
>> @@ -163,6 +165,8 @@ static inline unsigned int riscv_insn_length (insn_t insn)
>>    ((RV_X(x, 0, 1) << 6) | (RV_X(x, 1, 1) << 5))
>>  #define ENCODE_ZCB_HALFWORD_UIMM(x) \
>>    (RV_X(x, 1, 1) << 5)
>> +#define ENCODE_ZCMP_SPIMM(x) \
>> +  (RV_X(x, 4, 2) << 2)
>>  
>>  #define VALID_ITYPE_IMM(x) (EXTRACT_ITYPE_IMM(ENCODE_ITYPE_IMM(x)) == (x))
>>  #define VALID_STYPE_IMM(x) (EXTRACT_STYPE_IMM(ENCODE_STYPE_IMM(x)) == (x))
>> @@ -190,6 +194,7 @@ static inline unsigned int riscv_insn_length (insn_t insn)
>>  #define VALID_RVV_VC_IMM(x) (EXTRACT_RVV_VC_IMM(ENCODE_RVV_VC_IMM(x)) == (x))
>>  #define VALID_ZCB_BYTE_UIMM(x) (EXTRACT_ZCB_BYTE_UIMM(ENCODE_ZCB_BYTE_UIMM(x)) == (x))
>>  #define VALID_ZCB_HALFWORD_UIMM(x) (EXTRACT_ZCB_HALFWORD_UIMM(ENCODE_ZCB_HALFWORD_UIMM(x)) == (x))
>> +#define VALID_ZCMP_SPIMM(x) (EXTRACT_ZCMP_SPIMM(ENCODE_ZCMP_SPIMM(x)) == (x))
>>  
>>  #define RISCV_RTYPE(insn, rd, rs1, rs2) \
>>    ((MATCH_ ## insn) | ((rd) << OP_SH_RD) | ((rs1) << OP_SH_RS1) | ((rs2) << OP_SH_RS2))
>> @@ -254,6 +259,8 @@ static inline unsigned int riscv_insn_length (insn_t insn)
>>  #define OP_SH_AQ		26
>>  #define OP_MASK_RL		0x1
>>  #define OP_SH_RL		25
>> +#define OP_MASK_RLIST		0xf
>> +#define OP_SH_RLIST		4
>>  
>>  #define OP_MASK_CSR		0xfffU
>>  #define OP_SH_CSR		20
>> @@ -330,6 +337,11 @@ static inline unsigned int riscv_insn_length (insn_t insn)
>>  #define X_T0 5
>>  #define X_T1 6
>>  #define X_T2 7
>> +#define X_S0 8
>> +#define X_S1 9
>> +#define X_S2 18
>> +#define X_S10 26
>> +#define X_S11 27
>>  #define X_T3 28
>>  
>>  #define NGPR 32
>> @@ -435,6 +447,7 @@ enum riscv_insn_class
>>    INSN_CLASS_ZCB_AND_ZBA,
>>    INSN_CLASS_ZCB_AND_ZBB,
>>    INSN_CLASS_ZCB_AND_ZMMUL,
>> +  INSN_CLASS_ZCMP,
>>    INSN_CLASS_SVINVAL,
>>    INSN_CLASS_ZICBOM,
>>    INSN_CLASS_ZICBOP,
>> diff --git a/opcodes/riscv-dis.c b/opcodes/riscv-dis.c
>> index 2826248f8af..d938c9cb2ed 100644
>> --- a/opcodes/riscv-dis.c
>> +++ b/opcodes/riscv-dis.c
>> @@ -75,6 +75,8 @@ static const char * const *riscv_fpr_names;
>>  /* If set, disassemble as most general instruction.  */
>>  static bool no_aliases = false;
>>  
>> +/* If set, disassemble numeric register names instead of ABI names.  */
>> +static int numeric = 0;
> 
> Use boolean variable and use "true" and "false" instead of "1" and "0".
> 
>>  
>>  /* Set default RISC-V disassembler options.  */
>>  
>> @@ -84,6 +86,7 @@ set_default_riscv_dis_options (void)
>>    riscv_gpr_names = riscv_gpr_names_abi;
>>    riscv_fpr_names = riscv_fpr_names_abi;
>>    no_aliases = false;
>> +  numeric = 0;
>>  }
>>  
>>  /* Parse RISC-V disassembler option (without arguments).  */
>> @@ -97,6 +100,7 @@ parse_riscv_dis_option_without_args (const char *option)
>>      {
>>        riscv_gpr_names = riscv_gpr_names_numeric;
>>        riscv_fpr_names = riscv_fpr_names_numeric;
>> +      numeric = 1;
>>      }
>>    else
>>      return false;
>> @@ -215,6 +219,50 @@ maybe_print_address (struct riscv_private_data *pd, int base_reg, int offset,
>>      pd->print_addr = (bfd_vma)(uint32_t)pd->print_addr;
>>  }
>>  
>> +/* Get ZCMP rlist field.  */
> 
> "Zcmp" is preferred.
> 
>> +
>> +static void
>> +print_rlist (disassemble_info *info, insn_t l)
>> +{
>> +  unsigned rlist = (int)EXTRACT_OPERAND (RLIST, l);
>> +  unsigned r_start = numeric ? X_S2 : X_S0;
>> +  info->fprintf_func (info->stream, "%s", riscv_gpr_names[X_RA]);
>> +
>> +  if (rlist == 5)
>> +    info->fprintf_func (info->stream, ",%s", riscv_gpr_names[X_S0]);
>> +  else if (rlist == 6 || (numeric && rlist > 6))
>> +    info->fprintf_func (info->stream, ",%s-%s",
>> +	  riscv_gpr_names[X_S0],
>> +	  riscv_gpr_names[X_S1]);
>> +
>> +  if (rlist == 15)
>> +    info->fprintf_func (info->stream, ",%s-%s",
>> +	  riscv_gpr_names[r_start],
>> +	  riscv_gpr_names[X_S11]);
>> +  else if (rlist == 7 && numeric)
>> +    info->fprintf_func (info->stream, ",%s",
>> +	  riscv_gpr_names[X_S2]);
>> +  else if (rlist > 6)
>> +    info->fprintf_func (info->stream, ",%s-%s",
>> +	  riscv_gpr_names[r_start],
>> +	  riscv_gpr_names[rlist + 11]);
>> +}
>> +
>> +/* Get ZCMP sp adjustment immediate.  */
> 
> "Zcmp" is preferred.
> 
>> +
>> +static int
>> +riscv_get_spimm (insn_t l)
> 
> Is this *that* generic?
> I will prefer riscv_cm_pushpop_get_spimm or some.
> 
>> +{
>> +  int spimm = riscv_get_sp_base(l, &riscv_rps_dis);
>> +
>> +  spimm += EXTRACT_ZCMP_SPIMM (l);
>> +
>> +  if (((l ^ MATCH_CM_PUSH) & MASK_CM_PUSH) == 0)
>> +    spimm *= -1;
>> +
>> +  return spimm;
>> +}
>> +
>>  /* Print insn arguments for 32/64-bit code.  */
>>  
>>  static void
>> @@ -420,6 +468,8 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info
>>  	case ')':
>>  	case '[':
>>  	case ']':
>> +	case '{':
>> +	case '}':
>>  	  print (info->stream, dis_style_text, "%c", *oparg);
>>  	  break;
>>  
>> @@ -625,6 +675,13 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info
>>  		    print (info->stream, dis_style_immediate, "%d",
>>  		      (int)EXTRACT_ZCB_HALFWORD_UIMM (l));
>>  		    break;
>> +		  case 'r':
>> +		    print_rlist (info, l);
>> +		    break;
>> +		  case 'p':
>> +		    print (info->stream, dis_style_immediate, "%d",
>> +		      riscv_get_spimm (l));
> 
> Indentation: 3 tabs and 3 spaces before "riscv_get_spimm".
> 
>> +		    break;
>>  		  default: break;
>>  		  }
>>  		break;
>> diff --git a/opcodes/riscv-opc.c b/opcodes/riscv-opc.c
>> index 6a854736fec..7d2f92e736b 100644
>> --- a/opcodes/riscv-opc.c
>> +++ b/opcodes/riscv-opc.c
>> @@ -1967,6 +1967,12 @@ const struct riscv_opcode riscv_opcodes[] =
>>  {"c.zext.b",   0, INSN_CLASS_ZCB, "Cs",  MATCH_C_ZEXT_B, MASK_C_ZEXT_B, match_opcode, 0 },
>>  {"c.sext.w",  64, INSN_CLASS_ZCB, "d",  MATCH_C_ADDIW, MASK_C_ADDIW|MASK_RVC_IMM, match_rd_nonzero, INSN_ALIAS },
>>  
>> +/* Zcmp instructions.  */
>> +{"cm.push",    0,  INSN_CLASS_ZCMP, "{Wcr},Wcp",  MATCH_CM_PUSH, MASK_CM_PUSH, match_opcode, 0 },
>> +{"cm.pop",     0,  INSN_CLASS_ZCMP, "{Wcr},Wcp",  MATCH_CM_POP, MASK_CM_POP, match_opcode, 0 },
>> +{"cm.popret",  0,  INSN_CLASS_ZCMP, "{Wcr},Wcp",  MATCH_CM_POPRET, MASK_CM_POPRET, match_opcode, 0 },
>> +{"cm.popretz", 0,  INSN_CLASS_ZCMP, "{Wcr},Wcp",  MATCH_CM_POPRETZ, MASK_CM_POPRETZ, match_opcode, 0 },
>> +
>>  /* Supervisor instructions.  */
>>  {"csrr",       0, INSN_CLASS_ZICSR, "d,E",   MATCH_CSRRS, MASK_CSRRS|MASK_RS1, match_opcode, INSN_ALIAS },
>>  {"csrw",       0, INSN_CLASS_ZICSR, "E,s",   MATCH_CSRRW, MASK_CSRRW|MASK_RD, match_opcode, INSN_ALIAS },
> 

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2023-07-26  6:56 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-07-26  3:22 [PATCH] RISC-V: Support Zcmp push/pop instructions Jiawei
2023-07-26  6:50 ` Tsukasa OI
2023-07-26  6:56   ` Tsukasa OI

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).