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

Message ID 20230607055215.29332-3-gaofei@eswincomputing.com
State Dropped
Delegated to: Kito Cheng
Headers
Series support zcmp extention |

Commit Message

Fei Gao June 7, 2023, 5:52 a.m. UTC
  Generate cm.popretz instead of cm.popret if return value is 0.

Signed-off-by: Fei Gao <gaofei@eswincomputing.com>

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:
        * 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 |  12 +
 gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c |  12 +
 5 files changed, 508 insertions(+), 24 deletions(-)
  

Comments

Kito Cheng July 13, 2023, 8:31 a.m. UTC | #1
I was thinking does it possible to using peephole2 to optimize this
case, but I realized their is several barrier, like stack tie and
note...so it seems hard to just leverage peephole2.

And the patch is LGTM, only a few minor coding format issues, but you
don't need to send new patch, I can fix those stuff when I push, and I
would strongly suggest you setup git-format-patch, <gcc-src>/contrib
has a clang format setting , that can release you from the boring
coding format issues.

# Copy to <gcc-src>/.clang-format, so that clang-format can found that
automatically.
$ cp contrib/clang-format .clang-format


> @@ -5747,6 +5748,80 @@ 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)

Need space between function name and (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)

Same issue here, need space between argument and function name.
  

Patch

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index c476c699f4c..f60c241a526 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -435,6 +435,7 @@  typedef enum
   PUSH_IDX = 0,
   POP_IDX,
   POPRET_IDX,
+  POPRETZ_IDX,
   ZCMP_OP_NUM
 } riscv_zcmp_op_t;
 
@@ -5535,30 +5536,30 @@  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,
@@ -5747,6 +5748,80 @@  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.  */
 
@@ -5943,17 +6018,8 @@  riscv_expand_epilogue (int style)
 
   if (use_multi_pop)
     {
-      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 c858b3bc9ef..b2e1f82f627 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -120,6 +120,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 6dbe489da9b..05e52df99c2 100644
--- a/gcc/testsuite/gcc.target/riscv/rv32e_zcmp.c
+++ b/gcc/testsuite/gcc.target/riscv/rv32e_zcmp.c
@@ -237,3 +237,15 @@  void 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 924197cb3c4..7d5c1121c35 100644
--- a/gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c
+++ b/gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c
@@ -237,3 +237,15 @@  void foo(void)
   f1();
   f2();
 }
+
+/*
+**test_popretz:
+**	cm.push	{ra}, -16
+**	call	f1
+**	cm.popretz	{ra}, 16
+*/
+long test_popretz()
+{
+        f1();
+        return 0;
+}