diff mbox series

[2/3,V2,RISC-V] support cm.popretz in zcmp

Message ID 20230829083746.1458-3-gaofei@eswincomputing.com
State New
Headers show
Series support zcmp extension | expand

Commit Message

Fei Gao Aug. 29, 2023, 8:37 a.m. UTC
Generate cm.popretz instead of cm.popret if return value is 0.

gcc/ChangeLog:

        * config/riscv/riscv.cc
        (riscv_zcmp_can_use_popretz): true if popretz can be used
        (riscv_gen_multi_pop_insn): interface to generate cm.pop[ret][z]
        (riscv_expand_epilogue): expand cm.pop[ret][z] in epilogue
        * config/riscv/riscv.md: define A0_REGNUM
        * config/riscv/zc.md
        (@gpr_multi_popretz_up_to_ra_<mode>): md for popretz ra
        (@gpr_multi_popretz_up_to_s0_<mode>): md for popretz ra, s0
        (@gpr_multi_popretz_up_to_s1_<mode>): likewise
        (@gpr_multi_popretz_up_to_s2_<mode>): likewise
        (@gpr_multi_popretz_up_to_s3_<mode>): likewise
        (@gpr_multi_popretz_up_to_s4_<mode>): likewise
        (@gpr_multi_popretz_up_to_s5_<mode>): likewise
        (@gpr_multi_popretz_up_to_s6_<mode>): likewise
        (@gpr_multi_popretz_up_to_s7_<mode>): likewise
        (@gpr_multi_popretz_up_to_s8_<mode>): likewise
        (@gpr_multi_popretz_up_to_s9_<mode>): likewise
        (@gpr_multi_popretz_up_to_s11_<mode>): likewise

gcc/testsuite/ChangeLog:

        * gcc.target/riscv/rv32e_zcmp.c: add testcase for cm.popretz in rv32e
        * gcc.target/riscv/rv32i_zcmp.c: add testcase for cm.popretz in rv32i
---
 gcc/config/riscv/riscv.cc                   | 114 ++++--
 gcc/config/riscv/riscv.md                   |   1 +
 gcc/config/riscv/zc.md                      | 393 ++++++++++++++++++++
 gcc/testsuite/gcc.target/riscv/rv32e_zcmp.c |  13 +
 gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c |  13 +
 5 files changed, 509 insertions(+), 25 deletions(-)
diff mbox series

Patch

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index ed4d28b2eb0..78600ba73b6 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -422,6 +422,7 @@  typedef enum
   PUSH_IDX = 0,
   POP_IDX,
   POPRET_IDX,
+  POPRETZ_IDX,
   ZCMP_OP_NUM
 } riscv_zcmp_op_t;
 
@@ -6238,30 +6239,31 @@  riscv_emit_stack_tie (void)
 /*zcmp multi push and pop code_for_push_pop function ptr array  */
 const code_for_push_pop_t code_for_push_pop[ZCMP_MAX_GRP_SLOTS][ZCMP_OP_NUM]
   = {{code_for_gpr_multi_push_up_to_ra, code_for_gpr_multi_pop_up_to_ra,
-      code_for_gpr_multi_popret_up_to_ra},
+      code_for_gpr_multi_popret_up_to_ra, code_for_gpr_multi_popretz_up_to_ra},
      {code_for_gpr_multi_push_up_to_s0, code_for_gpr_multi_pop_up_to_s0,
-      code_for_gpr_multi_popret_up_to_s0},
+      code_for_gpr_multi_popret_up_to_s0, code_for_gpr_multi_popretz_up_to_s0},
      {code_for_gpr_multi_push_up_to_s1, code_for_gpr_multi_pop_up_to_s1,
-      code_for_gpr_multi_popret_up_to_s1},
+      code_for_gpr_multi_popret_up_to_s1, code_for_gpr_multi_popretz_up_to_s1},
      {code_for_gpr_multi_push_up_to_s2, code_for_gpr_multi_pop_up_to_s2,
-      code_for_gpr_multi_popret_up_to_s2},
+      code_for_gpr_multi_popret_up_to_s2, code_for_gpr_multi_popretz_up_to_s2},
      {code_for_gpr_multi_push_up_to_s3, code_for_gpr_multi_pop_up_to_s3,
-      code_for_gpr_multi_popret_up_to_s3},
+      code_for_gpr_multi_popret_up_to_s3, code_for_gpr_multi_popretz_up_to_s3},
      {code_for_gpr_multi_push_up_to_s4, code_for_gpr_multi_pop_up_to_s4,
-      code_for_gpr_multi_popret_up_to_s4},
+      code_for_gpr_multi_popret_up_to_s4, code_for_gpr_multi_popretz_up_to_s4},
      {code_for_gpr_multi_push_up_to_s5, code_for_gpr_multi_pop_up_to_s5,
-      code_for_gpr_multi_popret_up_to_s5},
+      code_for_gpr_multi_popret_up_to_s5, code_for_gpr_multi_popretz_up_to_s5},
      {code_for_gpr_multi_push_up_to_s6, code_for_gpr_multi_pop_up_to_s6,
-      code_for_gpr_multi_popret_up_to_s6},
+      code_for_gpr_multi_popret_up_to_s6, code_for_gpr_multi_popretz_up_to_s6},
      {code_for_gpr_multi_push_up_to_s7, code_for_gpr_multi_pop_up_to_s7,
-      code_for_gpr_multi_popret_up_to_s7},
+      code_for_gpr_multi_popret_up_to_s7, code_for_gpr_multi_popretz_up_to_s7},
      {code_for_gpr_multi_push_up_to_s8, code_for_gpr_multi_pop_up_to_s8,
-      code_for_gpr_multi_popret_up_to_s8},
+      code_for_gpr_multi_popret_up_to_s8, code_for_gpr_multi_popretz_up_to_s8},
      {code_for_gpr_multi_push_up_to_s9, code_for_gpr_multi_pop_up_to_s9,
-      code_for_gpr_multi_popret_up_to_s9},
-     {nullptr, nullptr, nullptr},
+      code_for_gpr_multi_popret_up_to_s9, code_for_gpr_multi_popretz_up_to_s9},
+     {nullptr, nullptr, nullptr, nullptr},
      {code_for_gpr_multi_push_up_to_s11, code_for_gpr_multi_pop_up_to_s11,
-      code_for_gpr_multi_popret_up_to_s11}};
+      code_for_gpr_multi_popret_up_to_s11,
+      code_for_gpr_multi_popretz_up_to_s11}};
 
 static rtx
 riscv_gen_multi_push_pop_insn (riscv_zcmp_op_t op, HOST_WIDE_INT adj_size,
@@ -6474,6 +6476,78 @@  riscv_adjust_libcall_cfi_epilogue ()
   return dwarf;
 }
 
+/* return true if popretz pattern can be matched.
+   set (reg 10 a0) (const_int 0)
+   use (reg 10 a0)
+   NOTE_INSN_EPILOGUE_BEG  */
+static rtx_insn *
+riscv_zcmp_can_use_popretz (void)
+{
+  rtx_insn *insn = NULL, *use = NULL, *clear = NULL;
+
+  /* sequence stack for NOTE_INSN_EPILOGUE_BEG*/
+  struct sequence_stack *outer_seq = get_current_sequence ()->next;
+  if (!outer_seq)
+    return NULL;
+  insn = outer_seq->first;
+  if (!insn || !NOTE_P (insn) || NOTE_KIND (insn) != NOTE_INSN_EPILOGUE_BEG)
+    return NULL;
+
+  /* sequence stack for the insn before NOTE_INSN_EPILOGUE_BEG*/
+  outer_seq = outer_seq->next;
+  if (outer_seq)
+    insn = outer_seq->last;
+
+  /* skip notes  */
+  while (insn && NOTE_P (insn))
+    {
+      insn = PREV_INSN (insn);
+    }
+  use = insn;
+
+  /* match use (reg 10 a0)  */
+  if (use == NULL || !INSN_P (use) || GET_CODE (PATTERN (use)) != USE
+      || !REG_P (XEXP (PATTERN (use), 0))
+      || REGNO (XEXP (PATTERN (use), 0)) != A0_REGNUM)
+    return NULL;
+
+  /* match set (reg 10 a0) (const_int 0 [0])  */
+  clear = PREV_INSN (use);
+  if (clear != NULL && INSN_P (clear) && GET_CODE (PATTERN (clear)) == SET
+      && REG_P (SET_DEST (PATTERN (clear)))
+      && REGNO (SET_DEST (PATTERN (clear))) == A0_REGNUM
+      && SET_SRC (PATTERN (clear)) == const0_rtx)
+    return clear;
+
+  return NULL;
+}
+
+static void
+riscv_gen_multi_pop_insn (bool use_multi_pop_normal, unsigned mask,
+			  unsigned multipop_size)
+{
+  rtx insn;
+  unsigned regs_count = riscv_multi_push_regs_count (mask);
+
+  if (!use_multi_pop_normal)
+    insn = emit_insn (
+      riscv_gen_multi_push_pop_insn (POP_IDX, multipop_size, regs_count));
+  else if (rtx_insn *clear_a0_insn = riscv_zcmp_can_use_popretz ())
+    {
+      delete_insn (NEXT_INSN (clear_a0_insn));
+      delete_insn (clear_a0_insn);
+      insn = emit_jump_insn (
+	riscv_gen_multi_push_pop_insn (POPRETZ_IDX, multipop_size, regs_count));
+    }
+  else
+    insn = emit_jump_insn (
+      riscv_gen_multi_push_pop_insn (POPRET_IDX, multipop_size, regs_count));
+
+  rtx dwarf = riscv_adjust_multi_pop_cfi_epilogue (multipop_size);
+  RTX_FRAME_RELATED_P (insn) = 1;
+  REG_NOTES (insn) = dwarf;
+}
+
 /* Expand an "epilogue", "sibcall_epilogue", or "eh_return_internal" pattern;
    style says which.  */
 
@@ -6698,18 +6772,8 @@  riscv_expand_epilogue (int style)
       /* Undo the above fib.  */
       frame->mask = mask;
       frame->fmask = fmask;
-      unsigned regs_count = riscv_multi_push_regs_count (frame->mask);
-      if (use_multi_pop_normal)
-	insn = emit_jump_insn (riscv_gen_multi_push_pop_insn (POPRET_IDX,
-							      multipop_size,
-							      regs_count));
-      else
-	insn = emit_insn (
-	  riscv_gen_multi_push_pop_insn (POP_IDX, multipop_size, regs_count));
-
-      rtx dwarf = riscv_adjust_multi_pop_cfi_epilogue (multipop_size);
-      RTX_FRAME_RELATED_P (insn) = 1;
-      REG_NOTES (insn) = dwarf;
+      riscv_gen_multi_pop_insn (use_multi_pop_normal, frame->mask,
+				multipop_size);
       if (use_multi_pop_normal)
 	return;
     }
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index f489646cec3..8e09df6ff63 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -131,6 +131,7 @@ 
    (T1_REGNUM			6)
    (S0_REGNUM			8)
    (S1_REGNUM			9)
+   (A0_REGNUM			10)
    (S2_REGNUM			18)
    (S3_REGNUM			19)
    (S4_REGNUM			20)
diff --git a/gcc/config/riscv/zc.md b/gcc/config/riscv/zc.md
index 5c1bf031b8d..8d7de97daad 100644
--- a/gcc/config/riscv/zc.md
+++ b/gcc/config/riscv/zc.md
@@ -708,6 +708,399 @@ 
   "cm.popret	{ra, s0-s11}, %0"
 )
 
+(define_insn "@gpr_multi_popretz_up_to_ra_<mode>"
+  [(set (reg:X SP_REGNUM)
+        (plus:X (reg:X SP_REGNUM)
+                 (match_operand 0 "stack_pop_up_to_ra_operand" "I")))
+   (set (reg:X RETURN_ADDR_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot0_offset>))))
+   (set (reg:X A0_REGNUM)
+        (const_int 0))
+   (use (reg:X A0_REGNUM))
+   (return)
+   (use (reg:SI RETURN_ADDR_REGNUM))]
+  "TARGET_ZCMP"
+  "cm.popretz	{ra}, %0"
+)
+
+(define_insn "@gpr_multi_popretz_up_to_s0_<mode>"
+  [(set (reg:X SP_REGNUM)
+        (plus:X (reg:X SP_REGNUM)
+                 (match_operand 0 "stack_pop_up_to_s0_operand" "I")))
+   (set (reg:X S0_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot0_offset>))))
+   (set (reg:X RETURN_ADDR_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot1_offset>))))
+   (set (reg:X A0_REGNUM)
+        (const_int 0))
+   (use (reg:X A0_REGNUM))
+   (return)
+   (use (reg:SI RETURN_ADDR_REGNUM))]
+  "TARGET_ZCMP"
+  "cm.popretz	{ra, s0}, %0"
+)
+
+(define_insn "@gpr_multi_popretz_up_to_s1_<mode>"
+  [(set (reg:X SP_REGNUM)
+        (plus:X (reg:X SP_REGNUM)
+                 (match_operand 0 "stack_pop_up_to_s1_operand" "I")))
+   (set (reg:X S1_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot0_offset>))))
+   (set (reg:X S0_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot1_offset>))))
+   (set (reg:X RETURN_ADDR_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot2_offset>))))
+   (set (reg:X A0_REGNUM)
+        (const_int 0))
+   (use (reg:X A0_REGNUM))
+   (return)
+   (use (reg:SI RETURN_ADDR_REGNUM))]
+  "TARGET_ZCMP"
+  "cm.popretz	{ra, s0-s1}, %0"
+)
+
+(define_insn "@gpr_multi_popretz_up_to_s2_<mode>"
+  [(set (reg:X SP_REGNUM)
+        (plus:X (reg:X SP_REGNUM)
+                 (match_operand 0 "stack_pop_up_to_s2_operand" "I")))
+   (set (reg:X S2_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot0_offset>))))
+   (set (reg:X S1_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot1_offset>))))
+   (set (reg:X S0_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot2_offset>))))
+   (set (reg:X RETURN_ADDR_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot3_offset>))))
+   (set (reg:X A0_REGNUM)
+        (const_int 0))
+   (use (reg:X A0_REGNUM))
+   (return)
+   (use (reg:SI RETURN_ADDR_REGNUM))]
+  "TARGET_ZCMP"
+  "cm.popretz	{ra, s0-s2}, %0"
+)
+
+(define_insn "@gpr_multi_popretz_up_to_s3_<mode>"
+  [(set (reg:X SP_REGNUM)
+        (plus:X (reg:X SP_REGNUM)
+                 (match_operand 0 "stack_pop_up_to_s3_operand" "I")))
+   (set (reg:X S3_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot0_offset>))))
+   (set (reg:X S2_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot1_offset>))))
+   (set (reg:X S1_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot2_offset>))))
+   (set (reg:X S0_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot3_offset>))))
+   (set (reg:X RETURN_ADDR_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot4_offset>))))
+   (set (reg:X A0_REGNUM)
+        (const_int 0))
+   (use (reg:X A0_REGNUM))
+   (return)
+   (use (reg:SI RETURN_ADDR_REGNUM))]
+  "TARGET_ZCMP"
+  "cm.popretz	{ra, s0-s3}, %0"
+)
+
+(define_insn "@gpr_multi_popretz_up_to_s4_<mode>"
+  [(set (reg:X SP_REGNUM)
+        (plus:X (reg:X SP_REGNUM)
+                 (match_operand 0 "stack_pop_up_to_s4_operand" "I")))
+   (set (reg:X S4_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot0_offset>))))
+   (set (reg:X S3_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot1_offset>))))
+   (set (reg:X S2_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot2_offset>))))
+   (set (reg:X S1_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot3_offset>))))
+   (set (reg:X S0_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot4_offset>))))
+   (set (reg:X RETURN_ADDR_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot5_offset>))))
+   (set (reg:X A0_REGNUM)
+        (const_int 0))
+   (use (reg:X A0_REGNUM))
+   (return)
+   (use (reg:SI RETURN_ADDR_REGNUM))]
+  "TARGET_ZCMP"
+  "cm.popretz	{ra, s0-s4}, %0"
+)
+
+(define_insn "@gpr_multi_popretz_up_to_s5_<mode>"
+  [(set (reg:X SP_REGNUM)
+        (plus:X (reg:X SP_REGNUM)
+                 (match_operand 0 "stack_pop_up_to_s5_operand" "I")))
+   (set (reg:X S5_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot0_offset>))))
+   (set (reg:X S4_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot1_offset>))))
+   (set (reg:X S3_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot2_offset>))))
+   (set (reg:X S2_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot3_offset>))))
+   (set (reg:X S1_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot4_offset>))))
+   (set (reg:X S0_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot5_offset>))))
+   (set (reg:X RETURN_ADDR_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot6_offset>))))
+   (set (reg:X A0_REGNUM)
+        (const_int 0))
+   (use (reg:X A0_REGNUM))
+   (return)
+   (use (reg:SI RETURN_ADDR_REGNUM))]
+  "TARGET_ZCMP"
+  "cm.popretz	{ra, s0-s5}, %0"
+)
+
+(define_insn "@gpr_multi_popretz_up_to_s6_<mode>"
+  [(set (reg:X SP_REGNUM)
+        (plus:X (reg:X SP_REGNUM)
+                 (match_operand 0 "stack_pop_up_to_s6_operand" "I")))
+   (set (reg:X S6_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot0_offset>))))
+   (set (reg:X S5_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot1_offset>))))
+   (set (reg:X S4_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot2_offset>))))
+   (set (reg:X S3_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot3_offset>))))
+   (set (reg:X S2_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot4_offset>))))
+   (set (reg:X S1_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot5_offset>))))
+   (set (reg:X S0_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot6_offset>))))
+   (set (reg:X RETURN_ADDR_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot7_offset>))))
+   (set (reg:X A0_REGNUM)
+        (const_int 0))
+   (use (reg:X A0_REGNUM))
+   (return)
+   (use (reg:SI RETURN_ADDR_REGNUM))]
+  "TARGET_ZCMP"
+  "cm.popretz	{ra, s0-s6}, %0"
+)
+
+(define_insn "@gpr_multi_popretz_up_to_s7_<mode>"
+  [(set (reg:X SP_REGNUM)
+        (plus:X (reg:X SP_REGNUM)
+                 (match_operand 0 "stack_pop_up_to_s7_operand" "I")))
+   (set (reg:X S7_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot0_offset>))))
+   (set (reg:X S6_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot1_offset>))))
+   (set (reg:X S5_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot2_offset>))))
+   (set (reg:X S4_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot3_offset>))))
+   (set (reg:X S3_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot4_offset>))))
+   (set (reg:X S2_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot5_offset>))))
+   (set (reg:X S1_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot6_offset>))))
+   (set (reg:X S0_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot7_offset>))))
+   (set (reg:X RETURN_ADDR_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot8_offset>))))
+   (set (reg:X A0_REGNUM)
+        (const_int 0))
+   (use (reg:X A0_REGNUM))
+   (return)
+   (use (reg:SI RETURN_ADDR_REGNUM))]
+  "TARGET_ZCMP"
+  "cm.popretz	{ra, s0-s7}, %0"
+)
+
+(define_insn "@gpr_multi_popretz_up_to_s8_<mode>"
+  [(set (reg:X SP_REGNUM)
+        (plus:X (reg:X SP_REGNUM)
+                 (match_operand 0 "stack_pop_up_to_s8_operand" "I")))
+   (set (reg:X S8_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot0_offset>))))
+   (set (reg:X S7_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot1_offset>))))
+   (set (reg:X S6_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot2_offset>))))
+   (set (reg:X S5_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot3_offset>))))
+   (set (reg:X S4_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot4_offset>))))
+   (set (reg:X S3_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot5_offset>))))
+   (set (reg:X S2_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot6_offset>))))
+   (set (reg:X S1_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot7_offset>))))
+   (set (reg:X S0_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot8_offset>))))
+   (set (reg:X RETURN_ADDR_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot9_offset>))))
+   (set (reg:X A0_REGNUM)
+        (const_int 0))
+   (use (reg:X A0_REGNUM))
+   (return)
+   (use (reg:SI RETURN_ADDR_REGNUM))]
+  "TARGET_ZCMP"
+  "cm.popretz	{ra, s0-s8}, %0"
+)
+
+(define_insn "@gpr_multi_popretz_up_to_s9_<mode>"
+  [(set (reg:X SP_REGNUM)
+        (plus:X (reg:X SP_REGNUM)
+                 (match_operand 0 "stack_pop_up_to_s9_operand" "I")))
+   (set (reg:X S9_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot0_offset>))))
+   (set (reg:X S8_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot1_offset>))))
+   (set (reg:X S7_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot2_offset>))))
+   (set (reg:X S6_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot3_offset>))))
+   (set (reg:X S5_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot4_offset>))))
+   (set (reg:X S4_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot5_offset>))))
+   (set (reg:X S3_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot6_offset>))))
+   (set (reg:X S2_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot7_offset>))))
+   (set (reg:X S1_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot8_offset>))))
+   (set (reg:X S0_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot9_offset>))))
+   (set (reg:X RETURN_ADDR_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot10_offset>))))
+   (set (reg:X A0_REGNUM)
+        (const_int 0))
+   (use (reg:X A0_REGNUM))
+   (return)
+   (use (reg:SI RETURN_ADDR_REGNUM))]
+  "TARGET_ZCMP"
+  "cm.popretz	{ra, s0-s9}, %0"
+)
+
+(define_insn "@gpr_multi_popretz_up_to_s11_<mode>"
+  [(set (reg:X SP_REGNUM)
+        (plus:X (reg:X SP_REGNUM)
+                 (match_operand 0 "stack_pop_up_to_s11_operand" "I")))
+   (set (reg:X S11_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot0_offset>))))
+   (set (reg:X S10_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot1_offset>))))
+   (set (reg:X S9_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot2_offset>))))
+   (set (reg:X S8_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot3_offset>))))
+   (set (reg:X S7_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot4_offset>))))
+   (set (reg:X S6_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot5_offset>))))
+   (set (reg:X S5_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot6_offset>))))
+   (set (reg:X S4_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot7_offset>))))
+   (set (reg:X S3_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                      (const_int <slot8_offset>))))
+   (set (reg:X S2_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot9_offset>))))
+   (set (reg:X S1_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot10_offset>))))
+   (set (reg:X S0_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot11_offset>))))
+   (set (reg:X RETURN_ADDR_REGNUM)
+        (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot12_offset>))))
+   (set (reg:X A0_REGNUM)
+        (const_int 0))
+   (use (reg:X A0_REGNUM))
+   (return)
+   (use (reg:SI RETURN_ADDR_REGNUM))]
+  "TARGET_ZCMP"
+  "cm.popretz	{ra, s0-s11}, %0"
+)
+
 (define_insn "@gpr_multi_push_up_to_ra_<mode>"
   [(set (mem:X (plus:X (reg:X SP_REGNUM)
                        (const_int <slot0_offset>)))
diff --git a/gcc/testsuite/gcc.target/riscv/rv32e_zcmp.c b/gcc/testsuite/gcc.target/riscv/rv32e_zcmp.c
index 57c83249741..394459c4ed7 100644
--- a/gcc/testsuite/gcc.target/riscv/rv32e_zcmp.c
+++ b/gcc/testsuite/gcc.target/riscv/rv32e_zcmp.c
@@ -254,3 +254,16 @@  foo (void)
   f1 ();
   f2 ();
 }
+
+/*
+**test_popretz:
+**	cm.push	{ra}, -16
+**	call	f1
+**	cm.popretz	{ra}, 16
+*/
+long
+test_popretz ()
+{
+  f1 ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c b/gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c
index f24e0a8bab9..f00338a9d17 100644
--- a/gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c
+++ b/gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c
@@ -254,3 +254,16 @@  foo (void)
   f1 ();
   f2 ();
 }
+
+/*
+**test_popretz:
+**	cm.push	{ra}, -16
+**	call	f1
+**	cm.popretz	{ra}, 16
+*/
+long
+test_popretz ()
+{
+  f1 ();
+  return 0;
+}