public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 0/3] [RISC-V] support zcmp extension
@ 2023-08-29  8:37 Fei Gao
  2023-08-29  8:37 ` [PATCH 1/3] [V6] [RISC-V] support cm.push cm.pop cm.popret in zcmp Fei Gao
                   ` (3 more replies)
  0 siblings, 4 replies; 14+ messages in thread
From: Fei Gao @ 2023-08-29  8:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: kito.cheng, palmer, jeffreyalaw, sinan.lin, jiawei, Fei Gao

Fei Gao (3):
  [RISC-V] support cm.push cm.pop cm.popret in zcmp
  [RISC-V] support cm.popretz in zcmp
  [RISC-V] support cm.mva01s cm.mvsa01 in zcmp

 gcc/config/riscv/iterators.md                 |   15 +
 gcc/config/riscv/peephole.md                  |   28 +
 gcc/config/riscv/predicates.md                |  107 ++
 gcc/config/riscv/riscv-protos.h               |    2 +
 gcc/config/riscv/riscv.cc                     |  499 +++++-
 gcc/config/riscv/riscv.h                      |   25 +
 gcc/config/riscv/riscv.md                     |    4 +
 gcc/config/riscv/zc.md                        | 1457 +++++++++++++++++
 gcc/testsuite/gcc.target/riscv/cm_mv_rv32.c   |   23 +
 gcc/testsuite/gcc.target/riscv/rv32e_zcmp.c   |  269 +++
 gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c   |  269 +++
 .../gcc.target/riscv/zcmp_push_fpr.c          |   34 +
 .../gcc.target/riscv/zcmp_stack_alignment.c   |   24 +
 13 files changed, 2705 insertions(+), 51 deletions(-)
 create mode 100644 gcc/config/riscv/zc.md
 create mode 100644 gcc/testsuite/gcc.target/riscv/cm_mv_rv32.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rv32e_zcmp.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zcmp_push_fpr.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zcmp_stack_alignment.c

-- 
2.17.1


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

* [PATCH 1/3] [V6] [RISC-V] support cm.push cm.pop cm.popret in zcmp
  2023-08-29  8:37 [PATCH 0/3] [RISC-V] support zcmp extension Fei Gao
@ 2023-08-29  8:37 ` Fei Gao
  2023-10-27 20:31   ` Patrick O'Neill
  2023-08-29  8:37 ` [PATCH 2/3] [V2] [RISC-V] support cm.popretz " Fei Gao
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 14+ messages in thread
From: Fei Gao @ 2023-08-29  8:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: kito.cheng, palmer, jeffreyalaw, sinan.lin, jiawei, Fei Gao

Zcmp can share the same logic as save-restore in stack allocation: pre-allocation
by cm.push, step 1 and step 2.

Pre-allocation not only saves callee saved GPRs, but also saves callee saved FPRs and
local variables if any.

Please be noted cm.push pushes ra, s0-s11 in reverse order than what save-restore does.
So adaption has been done in .cfi directives in my patch.

gcc/ChangeLog:

        * config/riscv/iterators.md
        slot0_offset: slot 0 offset in stack GPRs area in bytes
        slot1_offset: slot 1 offset in stack GPRs area in bytes
        slot2_offset: likewise
        slot3_offset: likewise
        slot4_offset: likewise
        slot5_offset: likewise
        slot6_offset: likewise
        slot7_offset: likewise
        slot8_offset: likewise
        slot9_offset: likewise
        slot10_offset: likewise
        slot11_offset: likewise
        slot12_offset: likewise
        * config/riscv/predicates.md
        (stack_push_up_to_ra_operand): predicates of stack adjust pushing ra
        (stack_push_up_to_s0_operand): predicates of stack adjust pushing ra, s0
        (stack_push_up_to_s1_operand): likewise
        (stack_push_up_to_s2_operand): likewise
        (stack_push_up_to_s3_operand): likewise
        (stack_push_up_to_s4_operand): likewise
        (stack_push_up_to_s5_operand): likewise
        (stack_push_up_to_s6_operand): likewise
        (stack_push_up_to_s7_operand): likewise
        (stack_push_up_to_s8_operand): likewise
        (stack_push_up_to_s9_operand): likewise
        (stack_push_up_to_s11_operand): likewise
        (stack_pop_up_to_ra_operand): predicates of stack adjust poping ra
        (stack_pop_up_to_s0_operand): predicates of stack adjust poping ra, s0
        (stack_pop_up_to_s1_operand): likewise
        (stack_pop_up_to_s2_operand): likewise
        (stack_pop_up_to_s3_operand): likewise
        (stack_pop_up_to_s4_operand): likewise
        (stack_pop_up_to_s5_operand): likewise
        (stack_pop_up_to_s6_operand): likewise
        (stack_pop_up_to_s7_operand): likewise
        (stack_pop_up_to_s8_operand): likewise
        (stack_pop_up_to_s9_operand): likewise
        (stack_pop_up_to_s11_operand): likewise
        * config/riscv/riscv-protos.h
        (riscv_zcmp_valid_stack_adj_bytes_p):declaration
        * config/riscv/riscv.cc (struct riscv_frame_info): comment change
        (riscv_avoid_multi_push): helper function of riscv_use_multi_push
        (riscv_use_multi_push): true if multi push is used
        (riscv_multi_push_sregs_count): num of sregs in multi-push
        (riscv_multi_push_regs_count): num of regs in multi-push
        (riscv_16bytes_align): align to 16 bytes
        (riscv_stack_align): moved to a better place
        (riscv_save_libcall_count): no functional change
        (riscv_compute_frame_info): add zcmp frame info
        (riscv_for_each_saved_reg): save or restore fprs in specified slot for zcmp
        (riscv_adjust_multi_push_cfi_prologue): adjust cfi for cm.push
        (riscv_gen_multi_push_pop_insn): gen function for multi push and pop
        (get_multi_push_fpr_mask): get mask for the fprs pushed by cm.push
        (riscv_expand_prologue): allocate stack by cm.push
        (riscv_adjust_multi_pop_cfi_epilogue): adjust cfi for cm.pop[ret]
        (riscv_expand_epilogue): allocate stack by cm.pop[ret]
        (zcmp_base_adj): calculate stack adjustment base size
        (zcmp_additional_adj): calculate stack adjustment additional size
        (riscv_zcmp_valid_stack_adj_bytes_p): check if stack adjustment valid
        * config/riscv/riscv.h (RETURN_ADDR_MASK): mask of ra
        (S0_MASK): likewise
        (S1_MASK): likewise
        (S2_MASK): likewise
        (S3_MASK): likewise
        (S4_MASK): likewise
        (S5_MASK): likewise
        (S6_MASK): likewise
        (S7_MASK): likewise
        (S8_MASK): likewise
        (S9_MASK): likewise
        (S10_MASK): likewise
        (S11_MASK): likewise
        (MULTI_PUSH_GPR_MASK): GPR_MASK that cm.push can cover at most
        (ZCMP_MAX_SPIMM): max spimm value
        (ZCMP_SP_INC_STEP): zcmp sp increment step
        (ZCMP_INVALID_S0S10_SREGS_COUNTS): num of s0-s10
        (ZCMP_S0S11_SREGS_COUNTS): num of s0-s11
        (ZCMP_MAX_GRP_SLOTS): max slots of pushing and poping in zcmp
        (CALLEE_SAVED_FREG_NUMBER): get x of fsx(fs0 ~ fs11)
        * config/riscv/riscv.md: include zc.md
        * config/riscv/zc.md: New file. machine description for zcmp

gcc/testsuite/ChangeLog:

        * gcc.target/riscv/rv32e_zcmp.c: New test.
        * gcc.target/riscv/rv32i_zcmp.c: New test.
        * gcc.target/riscv/zcmp_push_fpr.c: New test.
        * gcc.target/riscv/zcmp_stack_alignment.c: New test.
---
 gcc/config/riscv/iterators.md                 |   15 +
 gcc/config/riscv/predicates.md                |   96 ++
 gcc/config/riscv/riscv-protos.h               |    2 +
 gcc/config/riscv/riscv.cc                     |  435 ++++++-
 gcc/config/riscv/riscv.h                      |   25 +
 gcc/config/riscv/riscv.md                     |    2 +
 gcc/config/riscv/zc.md                        | 1042 +++++++++++++++++
 gcc/testsuite/gcc.target/riscv/rv32e_zcmp.c   |  256 ++++
 gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c   |  256 ++++
 .../gcc.target/riscv/zcmp_push_fpr.c          |   34 +
 .../gcc.target/riscv/zcmp_stack_alignment.c   |   24 +
 11 files changed, 2136 insertions(+), 51 deletions(-)
 create mode 100644 gcc/config/riscv/zc.md
 create mode 100644 gcc/testsuite/gcc.target/riscv/rv32e_zcmp.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zcmp_push_fpr.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zcmp_stack_alignment.c

diff --git a/gcc/config/riscv/iterators.md b/gcc/config/riscv/iterators.md
index a4070de1510..ecf033f2fa7 100644
--- a/gcc/config/riscv/iterators.md
+++ b/gcc/config/riscv/iterators.md
@@ -125,6 +125,21 @@
 (define_mode_attr shiftm1 [(SI "const_si_mask_operand") (DI "const_di_mask_operand")])
 (define_mode_attr shiftm1p [(SI "DsS") (DI "DsD")])
 
+; zcmp mode attribute
+(define_mode_attr slot0_offset  [(SI "-4")  (DI "-8")])
+(define_mode_attr slot1_offset  [(SI "-8")  (DI "-16")])
+(define_mode_attr slot2_offset  [(SI "-12") (DI "-24")])
+(define_mode_attr slot3_offset  [(SI "-16") (DI "-32")])
+(define_mode_attr slot4_offset  [(SI "-20") (DI "-40")])
+(define_mode_attr slot5_offset  [(SI "-24") (DI "-48")])
+(define_mode_attr slot6_offset  [(SI "-28") (DI "-56")])
+(define_mode_attr slot7_offset  [(SI "-32") (DI "-64")])
+(define_mode_attr slot8_offset  [(SI "-36") (DI "-72")])
+(define_mode_attr slot9_offset  [(SI "-40") (DI "-80")])
+(define_mode_attr slot10_offset [(SI "-44") (DI "-88")])
+(define_mode_attr slot11_offset [(SI "-48") (DI "-96")])
+(define_mode_attr slot12_offset [(SI "-52") (DI "-104")])
+
 ;; -------------------------------------------------------------------
 ;; Code Iterators
 ;; -------------------------------------------------------------------
diff --git a/gcc/config/riscv/predicates.md b/gcc/config/riscv/predicates.md
index 618ad607047..3ef09996a85 100644
--- a/gcc/config/riscv/predicates.md
+++ b/gcc/config/riscv/predicates.md
@@ -69,6 +69,102 @@
   (ior (match_operand 0 "const_0_operand")
        (match_operand 0 "register_operand")))
 
+(define_predicate "stack_push_up_to_ra_operand"
+  (and (match_code "const_int")
+       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 1)")))
+
+(define_predicate "stack_push_up_to_s0_operand"
+  (and (match_code "const_int")
+       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 2)")))
+
+(define_predicate "stack_push_up_to_s1_operand"
+  (and (match_code "const_int")
+       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 3)")))
+
+(define_predicate "stack_push_up_to_s2_operand"
+  (and (match_code "const_int")
+       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 4)")))
+
+(define_predicate "stack_push_up_to_s3_operand"
+  (and (match_code "const_int")
+       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 5)")))
+
+(define_predicate "stack_push_up_to_s4_operand"
+  (and (match_code "const_int")
+       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 6)")))
+
+(define_predicate "stack_push_up_to_s5_operand"
+  (and (match_code "const_int")
+       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 7)")))
+
+(define_predicate "stack_push_up_to_s6_operand"
+  (and (match_code "const_int")
+       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 8)")))
+
+(define_predicate "stack_push_up_to_s7_operand"
+  (and (match_code "const_int")
+       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 9)")))
+
+(define_predicate "stack_push_up_to_s8_operand"
+  (and (match_code "const_int")
+       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 10)")))
+
+(define_predicate "stack_push_up_to_s9_operand"
+  (and (match_code "const_int")
+       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 11)")))
+
+(define_predicate "stack_push_up_to_s11_operand"
+  (and (match_code "const_int")
+       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 13)")))
+
+(define_predicate "stack_pop_up_to_ra_operand"
+  (and (match_code "const_int")
+       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 1)")))
+
+(define_predicate "stack_pop_up_to_s0_operand"
+  (and (match_code "const_int")
+       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 2)")))
+
+(define_predicate "stack_pop_up_to_s1_operand"
+  (and (match_code "const_int")
+       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 3)")))
+
+(define_predicate "stack_pop_up_to_s2_operand"
+  (and (match_code "const_int")
+       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 4)")))
+
+(define_predicate "stack_pop_up_to_s3_operand"
+  (and (match_code "const_int")
+       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 5)")))
+
+(define_predicate "stack_pop_up_to_s4_operand"
+  (and (match_code "const_int")
+       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 6)")))
+
+(define_predicate "stack_pop_up_to_s5_operand"
+  (and (match_code "const_int")
+       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 7)")))
+
+(define_predicate "stack_pop_up_to_s6_operand"
+  (and (match_code "const_int")
+       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 8)")))
+
+(define_predicate "stack_pop_up_to_s7_operand"
+  (and (match_code "const_int")
+       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 9)")))
+
+(define_predicate "stack_pop_up_to_s8_operand"
+  (and (match_code "const_int")
+       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 10)")))
+
+(define_predicate "stack_pop_up_to_s9_operand"
+  (and (match_code "const_int")
+       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 11)")))
+
+(define_predicate "stack_pop_up_to_s11_operand"
+  (and (match_code "const_int")
+       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 13)")))
+
 ;; Only use branch-on-bit sequences when the mask is not an ANDI immediate.
 (define_predicate "branch_on_bit_operand"
   (and (match_code "const_int")
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 0e0470280f8..04885bbebd2 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -102,6 +102,8 @@ extern bool riscv_split_64bit_move_p (rtx, rtx);
 extern void riscv_split_doubleword_move (rtx, rtx);
 extern const char *riscv_output_move (rtx, rtx);
 extern const char *riscv_output_return ();
+extern bool
+riscv_zcmp_valid_stack_adj_bytes_p (HOST_WIDE_INT, int);
 
 #ifdef RTX_CODE
 extern void riscv_expand_int_scc (rtx, enum rtx_code, rtx, rtx, bool *invert_ptr = 0);
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 1d6e278ea90..ed4d28b2eb0 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -112,6 +112,14 @@ struct GTY(())  riscv_frame_info {
   /* How much the GPR save/restore routines adjust sp (or 0 if unused).  */
   unsigned save_libcall_adjustment;
 
+  /* the minimum number of bytes, in multiples of 16-byte address increments,
+     required to cover the registers in a multi push & pop.  */
+  unsigned multi_push_adj_base;
+
+  /* the number of additional 16-byte address increments allocated for the stack
+     frame in a multi push & pop.  */
+  unsigned multi_push_adj_addi;
+
   /* Offsets of fixed-point and floating-point save areas from frame bottom */
   poly_int64 gp_sp_offset;
   poly_int64 fp_sp_offset;
@@ -409,6 +417,16 @@ static const struct riscv_tune_info riscv_tune_info_table[] = {
    function.  */
 static bool riscv_save_frame_pointer;
 
+typedef enum
+{
+  PUSH_IDX = 0,
+  POP_IDX,
+  POPRET_IDX,
+  ZCMP_OP_NUM
+} riscv_zcmp_op_t;
+
+typedef insn_code (*code_for_push_pop_t) (machine_mode);
+
 void riscv_frame_info::reset(void)
 {
   total_size = 0;
@@ -5539,6 +5557,34 @@ riscv_save_reg_p (unsigned int regno)
   return false;
 }
 
+/* Return TRUE if Zcmp push and pop insns should be
+   avoided. FALSE otherwise.
+   Only use multi push & pop if all GPRs masked can be covered,
+   and stack access is SP based,
+   and GPRs are at top of the stack frame,
+   and no conflicts in stack allocation with other features  */
+static bool
+riscv_avoid_multi_push (const struct riscv_frame_info *frame)
+{
+  if (!TARGET_ZCMP || crtl->calls_eh_return || frame_pointer_needed
+      || cfun->machine->interrupt_handler_p || cfun->machine->varargs_size != 0
+      || crtl->args.pretend_args_size != 0 || flag_shrink_wrap_separate
+      || (frame->mask & ~MULTI_PUSH_GPR_MASK))
+    return true;
+
+  return false;
+}
+
+/* Determine whether to use multi push insn.  */
+static bool
+riscv_use_multi_push (const struct riscv_frame_info *frame)
+{
+  if (riscv_avoid_multi_push (frame))
+    return false;
+
+  return (frame->multi_push_adj_base != 0);
+}
+
 /* Return TRUE if a libcall to save/restore GPRs should be
    avoided.  FALSE otherwise.  */
 static bool
@@ -5576,6 +5622,50 @@ riscv_save_libcall_count (unsigned mask)
   abort ();
 }
 
+/* calculate number of s regs in multi push and pop.
+   Note that {s0-s10} is not valid in Zcmp, use {s0-s11} instead.  */
+static unsigned
+riscv_multi_push_sregs_count (unsigned mask)
+{
+  unsigned num = riscv_save_libcall_count (mask);
+  return (num == ZCMP_INVALID_S0S10_SREGS_COUNTS) ? ZCMP_S0S11_SREGS_COUNTS
+						  : num;
+}
+
+/* calculate number of regs(ra, s0-sx) in multi push and pop.  */
+static unsigned
+riscv_multi_push_regs_count (unsigned mask)
+{
+  /* 1 is for ra  */
+  return riscv_multi_push_sregs_count (mask) + 1;
+}
+
+/* Handle 16 bytes align for poly_int.  */
+static poly_int64
+riscv_16bytes_align (poly_int64 value)
+{
+  return aligned_upper_bound (value, 16);
+}
+
+static HOST_WIDE_INT
+riscv_16bytes_align (HOST_WIDE_INT value)
+{
+  return ROUND_UP (value, 16);
+}
+
+/* Handle stack align for poly_int.  */
+static poly_int64
+riscv_stack_align (poly_int64 value)
+{
+  return aligned_upper_bound (value, PREFERRED_STACK_BOUNDARY / 8);
+}
+
+static HOST_WIDE_INT
+riscv_stack_align (HOST_WIDE_INT value)
+{
+  return RISCV_STACK_ALIGN (value);
+}
+
 /* Populate the current function's riscv_frame_info structure.
 
    RISC-V stack frames grown downward.  High addresses are at the top.
@@ -5601,7 +5691,7 @@ riscv_save_libcall_count (unsigned mask)
 	|  GPR save area                |       + UNITS_PER_WORD
 	|                               |
 	+-------------------------------+ <-- stack_pointer_rtx + fp_sp_offset
-	|                               |       + UNITS_PER_HWVALUE
+	|                               |       + UNITS_PER_FP_REG
 	|  FPR save area                |
 	|                               |
 	+-------------------------------+ <-- frame_pointer_rtx (virtual)
@@ -5620,19 +5710,6 @@ riscv_save_libcall_count (unsigned mask)
 
 static HOST_WIDE_INT riscv_first_stack_step (struct riscv_frame_info *frame, poly_int64 remaining_size);
 
-/* Handle stack align for poly_int.  */
-static poly_int64
-riscv_stack_align (poly_int64 value)
-{
-  return aligned_upper_bound (value, PREFERRED_STACK_BOUNDARY / 8);
-}
-
-static HOST_WIDE_INT
-riscv_stack_align (HOST_WIDE_INT value)
-{
-  return RISCV_STACK_ALIGN (value);
-}
-
 static void
 riscv_compute_frame_info (void)
 {
@@ -5683,8 +5760,9 @@ riscv_compute_frame_info (void)
   if (frame->mask)
     {
       x_save_size = riscv_stack_align (num_x_saved * UNITS_PER_WORD);
-      unsigned num_save_restore = 1 + riscv_save_libcall_count (frame->mask);
 
+      /* 1 is for ra  */
+      unsigned num_save_restore = 1 + riscv_save_libcall_count (frame->mask);
       /* Only use save/restore routines if they don't alter the stack size.  */
       if (riscv_stack_align (num_save_restore * UNITS_PER_WORD) == x_save_size
           && !riscv_avoid_save_libcall ())
@@ -5696,6 +5774,14 @@ riscv_compute_frame_info (void)
 
 	  frame->save_libcall_adjustment = x_save_size;
 	}
+
+      if (!riscv_avoid_multi_push (frame))
+	{
+	  /* num(ra, s0-sx)  */
+	  unsigned num_multi_push = riscv_multi_push_regs_count (frame->mask);
+	  x_save_size = riscv_stack_align (num_multi_push * UNITS_PER_WORD);
+	  frame->multi_push_adj_base = riscv_16bytes_align (x_save_size);
+	}
     }
 
   /* In an interrupt function, we need extra space for the initial saves of CSRs.  */
@@ -5721,7 +5807,15 @@ riscv_compute_frame_info (void)
   frame->fp_sp_offset = offset - UNITS_PER_FP_REG;
   /* Next are the callee-saved GPRs. */
   if (frame->mask)
-    offset += x_save_size;
+    {
+      offset += x_save_size;
+      /* align to 16 bytes and add paddings to GPR part to honor
+	 both stack alignment and zcmp pus/pop size alignment. */
+      if (riscv_use_multi_push (frame)
+	  && known_lt (offset, frame->multi_push_adj_base
+				 + ZCMP_SP_INC_STEP * ZCMP_MAX_SPIMM))
+	offset = riscv_16bytes_align (offset);
+    }
   frame->gp_sp_offset = offset - UNITS_PER_WORD;
   /* The hard frame pointer points above the callee-saved GPRs. */
   frame->hard_frame_pointer_offset = offset;
@@ -5900,8 +5994,8 @@ static void
 riscv_for_each_saved_reg (poly_int64 sp_offset, riscv_save_restore_fn fn,
 			  bool epilogue, bool maybe_eh_return)
 {
-  HOST_WIDE_INT offset;
-  unsigned int regno;
+  HOST_WIDE_INT offset, first_fp_offset;
+  unsigned int regno, num_masked_fp = 0;
   unsigned int start = GP_REG_FIRST;
   unsigned int limit = GP_REG_LAST;
 
@@ -5987,16 +6081,20 @@ riscv_for_each_saved_reg (poly_int64 sp_offset, riscv_save_restore_fn fn,
 
   /* This loop must iterate over the same space as its companion in
      riscv_compute_frame_info.  */
-  offset = (cfun->machine->frame.fp_sp_offset - sp_offset).to_constant ();
+  first_fp_offset
+    = (cfun->machine->frame.fp_sp_offset - sp_offset).to_constant ();
   for (unsigned int regno = FP_REG_FIRST; regno <= FP_REG_LAST; regno++)
     if (BITSET_P (cfun->machine->frame.fmask, regno - FP_REG_FIRST))
       {
 	bool handle_reg = !cfun->machine->reg_is_wrapped_separately[regno];
 	machine_mode mode = TARGET_DOUBLE_FLOAT ? DFmode : SFmode;
-
+	unsigned int slot = (riscv_use_multi_push (&cfun->machine->frame))
+			      ? CALLEE_SAVED_FREG_NUMBER (regno)
+			      : num_masked_fp;
+	offset = first_fp_offset - slot * GET_MODE_SIZE (mode).to_constant ();
 	if (handle_reg)
 	  riscv_save_restore_reg (mode, regno, offset, fn);
-	offset -= GET_MODE_SIZE (mode).to_constant ();
+	num_masked_fp++;
       }
 }
 
@@ -6093,6 +6191,41 @@ riscv_adjust_libcall_cfi_prologue ()
   return dwarf;
 }
 
+static rtx
+riscv_adjust_multi_push_cfi_prologue (int saved_size)
+{
+  rtx dwarf = NULL_RTX;
+  rtx adjust_sp_rtx, reg, mem, insn;
+  unsigned int mask = cfun->machine->frame.mask;
+  int offset;
+  int saved_cnt = 0;
+
+  if (mask & S10_MASK)
+    mask |= S11_MASK;
+
+  for (int regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--)
+    if (BITSET_P (mask & MULTI_PUSH_GPR_MASK, regno - GP_REG_FIRST))
+      {
+	/* The save order is s11-s0, ra
+	   from high to low addr.  */
+	offset = saved_size - UNITS_PER_WORD * (++saved_cnt);
+
+	reg = gen_rtx_REG (Pmode, regno);
+	mem = gen_frame_mem (Pmode,
+			     plus_constant (Pmode, stack_pointer_rtx, offset));
+
+	insn = gen_rtx_SET (mem, reg);
+	dwarf = alloc_reg_note (REG_CFA_OFFSET, insn, dwarf);
+      }
+
+  /* Debug info for adjust sp.  */
+  adjust_sp_rtx
+    = gen_rtx_SET (stack_pointer_rtx,
+		   plus_constant (Pmode, stack_pointer_rtx, -saved_size));
+  dwarf = alloc_reg_note (REG_CFA_ADJUST_CFA, adjust_sp_rtx, dwarf);
+  return dwarf;
+}
+
 static void
 riscv_emit_stack_tie (void)
 {
@@ -6102,6 +6235,56 @@ riscv_emit_stack_tie (void)
     emit_insn (gen_stack_tiedi (stack_pointer_rtx, hard_frame_pointer_rtx));
 }
 
+/*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_push_up_to_s0, code_for_gpr_multi_pop_up_to_s0,
+      code_for_gpr_multi_popret_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_push_up_to_s2, code_for_gpr_multi_pop_up_to_s2,
+      code_for_gpr_multi_popret_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_push_up_to_s4, code_for_gpr_multi_pop_up_to_s4,
+      code_for_gpr_multi_popret_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_push_up_to_s6, code_for_gpr_multi_pop_up_to_s6,
+      code_for_gpr_multi_popret_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_push_up_to_s8, code_for_gpr_multi_pop_up_to_s8,
+      code_for_gpr_multi_popret_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_push_up_to_s11, code_for_gpr_multi_pop_up_to_s11,
+      code_for_gpr_multi_popret_up_to_s11}};
+
+static rtx
+riscv_gen_multi_push_pop_insn (riscv_zcmp_op_t op, HOST_WIDE_INT adj_size,
+			       unsigned int regs_num)
+{
+  gcc_assert (op < ZCMP_OP_NUM);
+  gcc_assert (regs_num <= ZCMP_MAX_GRP_SLOTS
+	      && regs_num != ZCMP_INVALID_S0S10_SREGS_COUNTS + 1); /* 1 for ra*/
+  rtx stack_adj = GEN_INT (adj_size);
+  return GEN_FCN (code_for_push_pop[regs_num - 1][op](Pmode)) (stack_adj);
+}
+
+static unsigned
+get_multi_push_fpr_mask (unsigned max_fprs_push)
+{
+  unsigned mask_fprs_push = 0, num_f_pushed = 0;
+  for (unsigned regno = FP_REG_FIRST;
+       regno <= FP_REG_LAST && num_f_pushed < max_fprs_push; regno++)
+    if (riscv_save_reg_p (regno))
+      mask_fprs_push |= 1 << (regno - FP_REG_FIRST), num_f_pushed++;
+  return mask_fprs_push;
+}
+
 /* Expand the "prologue" pattern.  */
 
 void
@@ -6110,7 +6293,9 @@ riscv_expand_prologue (void)
   struct riscv_frame_info *frame = &cfun->machine->frame;
   poly_int64 remaining_size = frame->total_size;
   unsigned mask = frame->mask;
-  rtx insn;
+  unsigned fmask = frame->fmask;
+  int spimm, multi_push_additional, stack_adj;
+  rtx insn, dwarf = NULL_RTX;
 
   if (flag_stack_usage_info)
     current_function_static_stack_size = constant_lower_bound (remaining_size);
@@ -6118,8 +6303,46 @@ riscv_expand_prologue (void)
   if (cfun->machine->naked_p)
     return;
 
+  /* prefer muti-push to save-restore libcall.  */
+  if (riscv_use_multi_push (frame))
+    {
+      remaining_size -= frame->multi_push_adj_base;
+      if (known_gt (remaining_size, 2 * ZCMP_SP_INC_STEP))
+	spimm = 3;
+      else if (known_gt (remaining_size, ZCMP_SP_INC_STEP))
+	spimm = 2;
+      else if (known_gt (remaining_size, 0))
+	spimm = 1;
+      else
+	spimm = 0;
+      multi_push_additional = spimm * ZCMP_SP_INC_STEP;
+      frame->multi_push_adj_addi = multi_push_additional;
+      remaining_size -= multi_push_additional;
+
+      /* emit multi push insn & dwarf along with it.  */
+      stack_adj = frame->multi_push_adj_base + multi_push_additional;
+      insn = emit_insn (riscv_gen_multi_push_pop_insn (
+	PUSH_IDX, -stack_adj, riscv_multi_push_regs_count (frame->mask)));
+      dwarf = riscv_adjust_multi_push_cfi_prologue (stack_adj);
+      RTX_FRAME_RELATED_P (insn) = 1;
+      REG_NOTES (insn) = dwarf;
+
+      /* Temporarily fib that we need not save GPRs.  */
+      frame->mask = 0;
+
+      /* push FPRs into the addtional reserved space by cm.push. */
+      if (fmask)
+	{
+	  unsigned mask_fprs_push
+	    = get_multi_push_fpr_mask (multi_push_additional / UNITS_PER_WORD);
+	  frame->fmask &= mask_fprs_push;
+	  riscv_for_each_saved_reg (remaining_size, riscv_save_reg, false,
+				    false);
+	  frame->fmask = fmask & ~mask_fprs_push; /* mask for the rest FPRs.  */
+	}
+    }
   /* When optimizing for size, call a subroutine to save the registers.  */
-  if (riscv_use_save_libcall (frame))
+  else if (riscv_use_save_libcall (frame))
     {
       rtx dwarf = NULL_RTX;
       dwarf = riscv_adjust_libcall_cfi_prologue ();
@@ -6135,17 +6358,20 @@ riscv_expand_prologue (void)
   /* Save the registers.  */
   if ((frame->mask | frame->fmask) != 0)
     {
-      HOST_WIDE_INT step1 = riscv_first_stack_step (frame, remaining_size);
-
-      insn = gen_add3_insn (stack_pointer_rtx,
-			    stack_pointer_rtx,
-			    GEN_INT (-step1));
-      RTX_FRAME_RELATED_P (emit_insn (insn)) = 1;
-      remaining_size -= step1;
+      if (known_gt (remaining_size, frame->frame_pointer_offset))
+	{
+	  HOST_WIDE_INT step1 = riscv_first_stack_step (frame, remaining_size);
+	  remaining_size -= step1;
+	  insn = gen_add3_insn (stack_pointer_rtx, stack_pointer_rtx,
+				GEN_INT (-step1));
+	  RTX_FRAME_RELATED_P (emit_insn (insn)) = 1;
+	}
       riscv_for_each_saved_reg (remaining_size, riscv_save_reg, false, false);
     }
 
-  frame->mask = mask; /* Undo the above fib.  */
+  /* Undo the above fib.  */
+  frame->mask = mask;
+  frame->fmask = fmask;
 
   /* Set up the frame pointer, if we're using one.  */
   if (frame_pointer_needed)
@@ -6198,6 +6424,32 @@ riscv_expand_prologue (void)
     }
 }
 
+static rtx
+riscv_adjust_multi_pop_cfi_epilogue (int saved_size)
+{
+  rtx dwarf = NULL_RTX;
+  rtx adjust_sp_rtx, reg;
+  unsigned int mask = cfun->machine->frame.mask;
+
+  if (mask & S10_MASK)
+    mask |= S11_MASK;
+
+  /* Debug info for adjust sp.  */
+  adjust_sp_rtx
+    = gen_rtx_SET (stack_pointer_rtx,
+		   plus_constant (Pmode, stack_pointer_rtx, saved_size));
+  dwarf = alloc_reg_note (REG_CFA_ADJUST_CFA, adjust_sp_rtx, dwarf);
+
+  for (int regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
+    if (BITSET_P (mask, regno - GP_REG_FIRST))
+      {
+	reg = gen_rtx_REG (Pmode, regno);
+	dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf);
+      }
+
+  return dwarf;
+}
+
 static rtx
 riscv_adjust_libcall_cfi_epilogue ()
 {
@@ -6236,11 +6488,24 @@ riscv_expand_epilogue (int style)
      Start off by assuming that no registers need to be restored.  */
   struct riscv_frame_info *frame = &cfun->machine->frame;
   unsigned mask = frame->mask;
+  unsigned fmask = frame->fmask;
+  unsigned mask_fprs_push = 0;
   HOST_WIDE_INT step2 = 0;
-  bool use_restore_libcall = ((style == NORMAL_RETURN)
-			      && riscv_use_save_libcall (frame));
-  unsigned libcall_size = (use_restore_libcall
-			   ? frame->save_libcall_adjustment : 0);
+  bool use_multi_pop_normal
+    = ((style == NORMAL_RETURN) && riscv_use_multi_push (frame));
+  bool use_multi_pop_sibcall
+    = ((style == SIBCALL_RETURN) && riscv_use_multi_push (frame));
+  bool use_multi_pop = use_multi_pop_normal || use_multi_pop_sibcall;
+
+  bool use_restore_libcall
+    = !use_multi_pop
+      && ((style == NORMAL_RETURN) && riscv_use_save_libcall (frame));
+  unsigned libcall_size = use_restore_libcall && !use_multi_pop
+			    ? frame->save_libcall_adjustment
+			    : 0;
+  unsigned multipop_size
+    = use_multi_pop ? frame->multi_push_adj_base + frame->multi_push_adj_addi
+		    : 0;
   rtx ra = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM);
   rtx insn;
 
@@ -6311,18 +6576,26 @@ riscv_expand_epilogue (int style)
       REG_NOTES (insn) = dwarf;
     }
 
-  if (use_restore_libcall)
-    frame->mask = 0; /* Temporarily fib for GPRs.  */
+  if (use_restore_libcall || use_multi_pop)
+    frame->mask = 0; /* Temporarily fib that we need not restore GPRs.  */
 
   /* If we need to restore registers, deallocate as much stack as
      possible in the second step without going out of range.  */
-  if ((frame->mask | frame->fmask) != 0)
+  if (use_multi_pop)
+    {
+      if (frame->fmask
+	  && known_gt (frame->total_size - multipop_size,
+		       frame->frame_pointer_offset))
+	step2
+	  = riscv_first_stack_step (frame, frame->total_size - multipop_size);
+    }
+  else if ((frame->mask | frame->fmask) != 0)
     step2 = riscv_first_stack_step (frame, frame->total_size - libcall_size);
 
-  if (use_restore_libcall)
+  if (use_restore_libcall || use_multi_pop)
     frame->mask = mask; /* Undo the above fib.  */
 
-  poly_int64 step1 = frame->total_size - step2 - libcall_size;
+  poly_int64 step1 = frame->total_size - step2 - libcall_size - multipop_size;
 
   /* Set TARGET to BASE + STEP1.  */
   if (known_gt (step1, 0))
@@ -6356,8 +6629,9 @@ riscv_expand_epilogue (int style)
 					   stack_pointer_rtx,
 					   adjust));
 	  rtx dwarf = NULL_RTX;
-	  rtx cfa_adjust_rtx = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
-					     GEN_INT (step2 + libcall_size));
+	  rtx cfa_adjust_rtx
+	    = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+			    GEN_INT (step2 + libcall_size + multipop_size));
 
 	  dwarf = alloc_reg_note (REG_CFA_DEF_CFA, cfa_adjust_rtx, dwarf);
 	  RTX_FRAME_RELATED_P (insn) = 1;
@@ -6372,16 +6646,26 @@ riscv_expand_epilogue (int style)
       epilogue_cfa_sp_offset = step2;
     }
 
-  if (use_restore_libcall)
-    frame->mask = 0; /* Temporarily fib that we need not save GPRs.  */
+  if (use_multi_pop)
+    {
+      frame->mask = 0; /* Temporarily fib that we need not restore GPRs.  */
+      if (fmask)
+	{
+	  mask_fprs_push = get_multi_push_fpr_mask (frame->multi_push_adj_addi
+						    / UNITS_PER_WORD);
+	  frame->fmask &= ~mask_fprs_push; /* FPRs not saved by cm.push  */
+	}
+    }
+  else if (use_restore_libcall)
+    frame->mask = 0; /* Temporarily fib that we need not restore GPRs.  */
 
   /* Restore the registers.  */
-  riscv_for_each_saved_reg (frame->total_size - step2 - libcall_size,
-			    riscv_restore_reg,
-			    true, style == EXCEPTION_RETURN);
+  riscv_for_each_saved_reg (frame->total_size - step2 - libcall_size
+			      - multipop_size,
+			    riscv_restore_reg, true, style == EXCEPTION_RETURN);
 
   if (use_restore_libcall)
-      frame->mask = mask; /* Undo the above fib.  */
+    frame->mask = mask; /* Undo the above fib.  */
 
   if (need_barrier_p)
     riscv_emit_stack_tie ();
@@ -6393,15 +6677,43 @@ riscv_expand_epilogue (int style)
 				       GEN_INT (step2)));
 
       rtx dwarf = NULL_RTX;
-      rtx cfa_adjust_rtx = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
-					 GEN_INT (libcall_size));
+      rtx cfa_adjust_rtx
+	= gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+			GEN_INT (libcall_size + multipop_size));
       dwarf = alloc_reg_note (REG_CFA_DEF_CFA, cfa_adjust_rtx, dwarf);
       RTX_FRAME_RELATED_P (insn) = 1;
 
       REG_NOTES (insn) = dwarf;
     }
 
-  if (use_restore_libcall)
+  if (use_multi_pop)
+    {
+      /* restore FPRs pushed by cm.push. */
+      frame->fmask = fmask & mask_fprs_push;
+      if (frame->fmask)
+	riscv_for_each_saved_reg (frame->total_size - libcall_size
+				    - multipop_size,
+				  riscv_restore_reg, true,
+				  style == EXCEPTION_RETURN);
+      /* 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;
+      if (use_multi_pop_normal)
+	return;
+    }
+  else if (use_restore_libcall)
     {
       rtx dwarf = riscv_adjust_libcall_cfi_epilogue ();
       insn = emit_insn (gen_gpr_restore (GEN_INT (riscv_save_libcall_count (mask))));
@@ -7744,6 +8056,27 @@ riscv_gen_gpr_save_insn (struct riscv_frame_info *frame)
   return gen_rtx_PARALLEL (VOIDmode, vec);
 }
 
+static HOST_WIDE_INT
+zcmp_base_adj (int regs_num)
+{
+  return riscv_16bytes_align ((regs_num) *GET_MODE_SIZE (word_mode));
+}
+
+static HOST_WIDE_INT
+zcmp_additional_adj (HOST_WIDE_INT total, int regs_num)
+{
+  return total - zcmp_base_adj (regs_num);
+}
+
+bool
+riscv_zcmp_valid_stack_adj_bytes_p (HOST_WIDE_INT total, int regs_num)
+{
+  HOST_WIDE_INT additioanl_bytes = zcmp_additional_adj (total, regs_num);
+  return additioanl_bytes == 0 || additioanl_bytes == 1 * ZCMP_SP_INC_STEP
+	 || additioanl_bytes == 2 * ZCMP_SP_INC_STEP
+	 || additioanl_bytes == ZCMP_MAX_SPIMM * ZCMP_SP_INC_STEP;
+}
+
 /* Return true if it's valid gpr_save pattern.  */
 
 bool
diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
index e18a0081297..42b6eb784d4 100644
--- a/gcc/config/riscv/riscv.h
+++ b/gcc/config/riscv/riscv.h
@@ -420,6 +420,29 @@ ASM_MISA_SPEC
 #define RISCV_CALL_ADDRESS_TEMP(MODE) \
   gen_rtx_REG (MODE, RISCV_CALL_ADDRESS_TEMP_REGNUM)
 
+#define RETURN_ADDR_MASK (1 << RETURN_ADDR_REGNUM)
+#define S0_MASK (1 << S0_REGNUM)
+#define S1_MASK (1 << S1_REGNUM)
+#define S2_MASK (1 << S2_REGNUM)
+#define S3_MASK (1 << S3_REGNUM)
+#define S4_MASK (1 << S4_REGNUM)
+#define S5_MASK (1 << S5_REGNUM)
+#define S6_MASK (1 << S6_REGNUM)
+#define S7_MASK (1 << S7_REGNUM)
+#define S8_MASK (1 << S8_REGNUM)
+#define S9_MASK (1 << S9_REGNUM)
+#define S10_MASK (1 << S10_REGNUM)
+#define S11_MASK (1 << S11_REGNUM)
+
+#define MULTI_PUSH_GPR_MASK                                                    \
+  (RETURN_ADDR_MASK | S0_MASK | S1_MASK | S2_MASK | S3_MASK | S4_MASK          \
+   | S5_MASK | S6_MASK | S7_MASK | S8_MASK | S9_MASK | S10_MASK | S11_MASK)
+#define ZCMP_MAX_SPIMM 3
+#define ZCMP_SP_INC_STEP 16
+#define ZCMP_INVALID_S0S10_SREGS_COUNTS 11
+#define ZCMP_S0S11_SREGS_COUNTS 12
+#define ZCMP_MAX_GRP_SLOTS 13
+
 #define MCOUNT_NAME "_mcount"
 
 #define NO_PROFILE_COUNTERS 1
@@ -655,6 +678,8 @@ enum reg_class
   ((REGNO) >= 8 && (REGNO) <= 9 ? (REGNO) - 8 :		\
    (REGNO) >= 18 && (REGNO) <= 27 ? (REGNO) - 16 : -1)
 
+#define CALLEE_SAVED_FREG_NUMBER(REGNO) CALLEE_SAVED_REG_NUMBER (REGNO - 32)
+
 #define LIBCALL_VALUE(MODE) \
   riscv_function_value (NULL_TREE, NULL_TREE, MODE)
 
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index 47d14d99903..f489646cec3 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -124,6 +124,7 @@
 
 (define_constants
   [(RETURN_ADDR_REGNUM		1)
+   (SP_REGNUM 			2)
    (GP_REGNUM 			3)
    (TP_REGNUM			4)
    (T0_REGNUM			5)
@@ -3431,3 +3432,4 @@
 (include "thead.md")
 (include "vector.md")
 (include "zicond.md")
+(include "zc.md")
diff --git a/gcc/config/riscv/zc.md b/gcc/config/riscv/zc.md
new file mode 100644
index 00000000000..5c1bf031b8d
--- /dev/null
+++ b/gcc/config/riscv/zc.md
@@ -0,0 +1,1042 @@
+;; Machine description for RISC-V Zc extention.
+;; Copyright (C) 2023 Free Software Foundation, Inc.
+;; Contributed by Fei Gao (gaofei@eswincomputing.com).
+
+;; This file is part of GCC.
+
+;; GCC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+
+;; GCC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.
+
+(define_insn "@gpr_multi_pop_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>))))]
+  "TARGET_ZCMP"
+  "cm.pop	{ra}, %0"
+)
+
+(define_insn "@gpr_multi_pop_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>))))]
+  "TARGET_ZCMP"
+  "cm.pop	{ra, s0}, %0"
+)
+
+(define_insn "@gpr_multi_pop_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>))))]
+  "TARGET_ZCMP"
+  "cm.pop	{ra, s0-s1}, %0"
+)
+
+(define_insn "@gpr_multi_pop_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>))))]
+  "TARGET_ZCMP"
+  "cm.pop	{ra, s0-s2}, %0"
+)
+
+(define_insn "@gpr_multi_pop_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>))))]
+  "TARGET_ZCMP"
+  "cm.pop	{ra, s0-s3}, %0"
+)
+
+(define_insn "@gpr_multi_pop_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>))))]
+  "TARGET_ZCMP"
+  "cm.pop	{ra, s0-s4}, %0"
+)
+
+(define_insn "@gpr_multi_pop_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>))))]
+  "TARGET_ZCMP"
+  "cm.pop	{ra, s0-s5}, %0"
+)
+
+(define_insn "@gpr_multi_pop_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>))))]
+  "TARGET_ZCMP"
+  "cm.pop	{ra, s0-s6}, %0"
+)
+
+(define_insn "@gpr_multi_pop_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>))))]
+  "TARGET_ZCMP"
+  "cm.pop	{ra, s0-s7}, %0"
+)
+
+(define_insn "@gpr_multi_pop_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>))))]
+  "TARGET_ZCMP"
+  "cm.pop	{ra, s0-s8}, %0"
+)
+
+(define_insn "@gpr_multi_pop_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>))))]
+  "TARGET_ZCMP"
+  "cm.pop	{ra, s0-s9}, %0"
+)
+
+(define_insn "@gpr_multi_pop_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>))))]
+  "TARGET_ZCMP"
+  "cm.pop	{ra, s0-s11}, %0"
+)
+
+(define_insn "@gpr_multi_popret_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>))))
+   (return)
+   (use (reg:SI RETURN_ADDR_REGNUM))]
+  "TARGET_ZCMP"
+  "cm.popret	{ra}, %0"
+)
+
+(define_insn "@gpr_multi_popret_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>))))
+   (return)
+   (use (reg:SI RETURN_ADDR_REGNUM))]
+  "TARGET_ZCMP"
+  "cm.popret	{ra, s0}, %0"
+)
+
+(define_insn "@gpr_multi_popret_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>))))
+   (return)
+   (use (reg:SI RETURN_ADDR_REGNUM))]
+  "TARGET_ZCMP"
+  "cm.popret	{ra, s0-s1}, %0"
+)
+
+(define_insn "@gpr_multi_popret_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>))))
+   (return)
+   (use (reg:SI RETURN_ADDR_REGNUM))]
+  "TARGET_ZCMP"
+  "cm.popret	{ra, s0-s2}, %0"
+)
+
+(define_insn "@gpr_multi_popret_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>))))
+   (return)
+   (use (reg:SI RETURN_ADDR_REGNUM))]
+  "TARGET_ZCMP"
+  "cm.popret	{ra, s0-s3}, %0"
+)
+
+(define_insn "@gpr_multi_popret_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>))))
+   (return)
+   (use (reg:SI RETURN_ADDR_REGNUM))]
+  "TARGET_ZCMP"
+  "cm.popret	{ra, s0-s4}, %0"
+)
+
+(define_insn "@gpr_multi_popret_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>))))
+   (return)
+   (use (reg:SI RETURN_ADDR_REGNUM))]
+  "TARGET_ZCMP"
+  "cm.popret	{ra, s0-s5}, %0"
+)
+
+(define_insn "@gpr_multi_popret_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>))))
+   (return)
+   (use (reg:SI RETURN_ADDR_REGNUM))]
+  "TARGET_ZCMP"
+  "cm.popret	{ra, s0-s6}, %0"
+)
+
+(define_insn "@gpr_multi_popret_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>))))
+   (return)
+   (use (reg:SI RETURN_ADDR_REGNUM))]
+  "TARGET_ZCMP"
+  "cm.popret	{ra, s0-s7}, %0"
+)
+
+(define_insn "@gpr_multi_popret_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>))))
+   (return)
+   (use (reg:SI RETURN_ADDR_REGNUM))]
+  "TARGET_ZCMP"
+  "cm.popret	{ra, s0-s8}, %0"
+)
+
+(define_insn "@gpr_multi_popret_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>))))
+   (return)
+   (use (reg:SI RETURN_ADDR_REGNUM))]
+  "TARGET_ZCMP"
+  "cm.popret	{ra, s0-s9}, %0"
+)
+
+(define_insn "@gpr_multi_popret_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>))))
+   (return)
+   (use (reg:SI RETURN_ADDR_REGNUM))]
+  "TARGET_ZCMP"
+  "cm.popret	{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>)))
+        (reg:X RETURN_ADDR_REGNUM))
+   (set (reg:X SP_REGNUM)
+        (plus:X (reg:X SP_REGNUM)
+                 (match_operand 0 "stack_push_up_to_ra_operand" "I")))]
+  "TARGET_ZCMP"
+  "cm.push	{ra}, %0"
+)
+
+(define_insn "@gpr_multi_push_up_to_s0_<mode>"
+  [(set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot0_offset>)))
+        (reg:X S0_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot1_offset>)))
+        (reg:X RETURN_ADDR_REGNUM))
+   (set (reg:X SP_REGNUM)
+        (plus:X (reg:X SP_REGNUM)
+                 (match_operand 0 "stack_push_up_to_s0_operand" "I")))]
+  "TARGET_ZCMP"
+  "cm.push	{ra, s0}, %0"
+)
+
+(define_insn "@gpr_multi_push_up_to_s1_<mode>"
+  [(set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot0_offset>)))
+        (reg:X S1_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot1_offset>)))
+        (reg:X S0_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot2_offset>)))
+        (reg:X RETURN_ADDR_REGNUM))
+   (set (reg:X SP_REGNUM)
+        (plus:X (reg:X SP_REGNUM)
+                 (match_operand 0 "stack_push_up_to_s1_operand" "I")))]
+  "TARGET_ZCMP"
+  "cm.push	{ra, s0-s1}, %0"
+)
+
+(define_insn "@gpr_multi_push_up_to_s2_<mode>"
+  [(set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot0_offset>)))
+        (reg:X S2_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot1_offset>)))
+        (reg:X S1_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot2_offset>)))
+        (reg:X S0_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot3_offset>)))
+        (reg:X RETURN_ADDR_REGNUM))
+   (set (reg:X SP_REGNUM)
+        (plus:X (reg:X SP_REGNUM)
+                 (match_operand 0 "stack_push_up_to_s2_operand" "I")))]
+  "TARGET_ZCMP"
+  "cm.push	{ra, s0-s2}, %0"
+)
+
+(define_insn "@gpr_multi_push_up_to_s3_<mode>"
+  [(set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot0_offset>)))
+        (reg:X S3_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot1_offset>)))
+        (reg:X S2_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot2_offset>)))
+        (reg:X S1_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot3_offset>)))
+        (reg:X S0_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot4_offset>)))
+        (reg:X RETURN_ADDR_REGNUM))
+   (set (reg:X SP_REGNUM)
+        (plus:X (reg:X SP_REGNUM)
+                 (match_operand 0 "stack_push_up_to_s3_operand" "I")))]
+  "TARGET_ZCMP"
+  "cm.push	{ra, s0-s3}, %0"
+)
+
+(define_insn "@gpr_multi_push_up_to_s4_<mode>"
+  [(set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot0_offset>)))
+        (reg:X S4_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot1_offset>)))
+        (reg:X S3_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot2_offset>)))
+        (reg:X S2_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot3_offset>)))
+        (reg:X S1_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot4_offset>)))
+        (reg:X S0_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot5_offset>)))
+        (reg:X RETURN_ADDR_REGNUM))
+   (set (reg:X SP_REGNUM)
+        (plus:X (reg:X SP_REGNUM)
+                 (match_operand 0 "stack_push_up_to_s4_operand" "I")))]
+  "TARGET_ZCMP"
+  "cm.push	{ra, s0-s4}, %0"
+)
+
+(define_insn "@gpr_multi_push_up_to_s5_<mode>"
+  [(set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot0_offset>)))
+        (reg:X S5_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot1_offset>)))
+        (reg:X S4_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot2_offset>)))
+        (reg:X S3_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot3_offset>)))
+        (reg:X S2_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot4_offset>)))
+        (reg:X S1_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot5_offset>)))
+        (reg:X S0_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot6_offset>)))
+        (reg:X RETURN_ADDR_REGNUM))
+   (set (reg:X SP_REGNUM)
+        (plus:X (reg:X SP_REGNUM)
+                 (match_operand 0 "stack_push_up_to_s5_operand" "I")))]
+  "TARGET_ZCMP"
+  "cm.push	{ra, s0-s5}, %0"
+)
+
+(define_insn "@gpr_multi_push_up_to_s6_<mode>"
+  [(set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot0_offset>)))
+        (reg:X S6_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot1_offset>)))
+        (reg:X S5_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot2_offset>)))
+        (reg:X S4_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot3_offset>)))
+        (reg:X S3_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot4_offset>)))
+        (reg:X S2_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot5_offset>)))
+        (reg:X S1_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot6_offset>)))
+        (reg:X S0_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot7_offset>)))
+        (reg:X RETURN_ADDR_REGNUM))
+   (set (reg:X SP_REGNUM)
+        (plus:X (reg:X SP_REGNUM)
+                 (match_operand 0 "stack_push_up_to_s6_operand" "I")))]
+  "TARGET_ZCMP"
+  "cm.push	{ra, s0-s6}, %0"
+)
+
+(define_insn "@gpr_multi_push_up_to_s7_<mode>"
+  [(set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot0_offset>)))
+        (reg:X S7_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot1_offset>)))
+        (reg:X S6_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot2_offset>)))
+        (reg:X S5_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot3_offset>)))
+        (reg:X S4_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot4_offset>)))
+        (reg:X S3_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot5_offset>)))
+        (reg:X S2_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot6_offset>)))
+        (reg:X S1_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot7_offset>)))
+        (reg:X S0_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                      (const_int <slot8_offset>)))
+        (reg:X RETURN_ADDR_REGNUM))
+   (set (reg:X SP_REGNUM)
+        (plus:X (reg:X SP_REGNUM)
+                 (match_operand 0 "stack_push_up_to_s7_operand" "I")))]
+  "TARGET_ZCMP"
+  "cm.push	{ra, s0-s7}, %0"
+)
+
+(define_insn "@gpr_multi_push_up_to_s8_<mode>"
+  [(set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot0_offset>)))
+        (reg:X S8_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot1_offset>)))
+        (reg:X S7_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot2_offset>)))
+        (reg:X S6_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot3_offset>)))
+        (reg:X S5_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot4_offset>)))
+        (reg:X S4_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot5_offset>)))
+        (reg:X S3_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot6_offset>)))
+        (reg:X S2_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot7_offset>)))
+        (reg:X S1_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot8_offset>)))
+        (reg:X S0_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot9_offset>)))
+        (reg:X RETURN_ADDR_REGNUM))
+   (set (reg:X SP_REGNUM)
+        (plus:X (reg:X SP_REGNUM)
+                 (match_operand 0 "stack_push_up_to_s8_operand" "I")))]
+  "TARGET_ZCMP"
+  "cm.push	{ra, s0-s8}, %0"
+)
+
+(define_insn "@gpr_multi_push_up_to_s9_<mode>"
+  [(set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot0_offset>)))
+        (reg:X S9_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot1_offset>)))
+        (reg:X S8_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot2_offset>)))
+        (reg:X S7_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot3_offset>)))
+        (reg:X S6_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot4_offset>)))
+        (reg:X S5_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot5_offset>)))
+        (reg:X S4_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot6_offset>)))
+        (reg:X S3_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot7_offset>)))
+        (reg:X S2_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot8_offset>)))
+        (reg:X S1_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot9_offset>)))
+        (reg:X S0_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot10_offset>)))
+        (reg:X RETURN_ADDR_REGNUM))
+   (set (reg:X SP_REGNUM)
+        (plus:X (reg:X SP_REGNUM)
+                 (match_operand 0 "stack_push_up_to_s9_operand" "I")))]
+  "TARGET_ZCMP"
+  "cm.push	{ra, s0-s9}, %0"
+)
+
+(define_insn "@gpr_multi_push_up_to_s11_<mode>"
+  [(set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot0_offset>)))
+        (reg:X S11_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot1_offset>)))
+        (reg:X S10_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot2_offset>)))
+        (reg:X S9_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot3_offset>)))
+        (reg:X S8_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot4_offset>)))
+        (reg:X S7_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot5_offset>)))
+        (reg:X S6_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot6_offset>)))
+        (reg:X S5_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot7_offset>)))
+        (reg:X S4_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot8_offset>)))
+        (reg:X S3_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot9_offset>)))
+        (reg:X S2_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot10_offset>)))
+        (reg:X S1_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot11_offset>)))
+        (reg:X S0_REGNUM))
+   (set (mem:X (plus:X (reg:X SP_REGNUM)
+                       (const_int <slot12_offset>)))
+        (reg:X RETURN_ADDR_REGNUM))
+   (set (reg:X SP_REGNUM)
+        (plus:X (reg:X SP_REGNUM)
+                 (match_operand 0 "stack_push_up_to_s11_operand" "I")))]
+  "TARGET_ZCMP"
+  "cm.push	{ra, s0-s11}, %0"
+)
diff --git a/gcc/testsuite/gcc.target/riscv/rv32e_zcmp.c b/gcc/testsuite/gcc.target/riscv/rv32e_zcmp.c
new file mode 100644
index 00000000000..57c83249741
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rv32e_zcmp.c
@@ -0,0 +1,256 @@
+/* { dg-do compile } */
+/* { dg-options " -Os -march=rv32e_zca_zcmp -mabi=ilp32e -mcmodel=medlow -fno-shrink-wrap-separate" } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-O1" "-O2" "-Og" "-O3" "-Oz" "-flto"} } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+char
+my_getchar ();
+float
+getf ();
+int __attribute__ ((noinline))
+incoming_stack_args (int arg0, int arg1, int arg2, int arg3, int arg4, int arg5,
+		     int arg6, int arg7, int arg8);
+int
+getint ();
+void
+PrintInts (int n, ...);						 // varargs
+void __attribute__ ((noinline)) PrintIntsNoVaStart (int n, ...); // varargs
+void
+PrintInts2 (int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int n,
+	    ...);
+extern void
+f1 (void);
+extern void
+f2 (void);
+
+/*
+**test1:
+**	...
+**	cm.push	{ra, s0-s1}, -64
+**	...
+**	cm.popret	{ra, s0-s1}, 64
+**	...
+*/
+int
+test1 ()
+{
+  char volatile array[3120];
+  float volatile farray[3120];
+
+  float sum = 0;
+  for (int i = 0; i < 3120; i++)
+    {
+      array[i] = my_getchar ();
+      farray[i] = my_getchar () * 1.2;
+      sum += array[i] + farray[i];
+    }
+  return sum;
+}
+
+/*
+**test2_step1_0_size:
+**	...
+**	cm.push	{ra, s0}, -64
+**	...
+**	cm.popret	{ra, s0}, 64
+**	...
+*/
+int
+test2_step1_0_size ()
+{
+  int volatile iarray[3120 + 1824 / 4 - 8];
+
+  for (int i = 0; i < 3120 + 1824 / 4 - 8; i++)
+    {
+      iarray[i] = my_getchar () * 2;
+    }
+  return iarray[0] + iarray[1];
+}
+
+/*
+**test3:
+**	...
+**	cm.push	{ra, s0-s1}, -64
+**	...
+**	cm.popret	{ra, s0-s1}, 64
+**	...
+*/
+float
+test3 ()
+{
+  char volatile array[3120];
+  float volatile farray[3120];
+
+  float sum = 0, f1 = 0, f2 = 0, f3 = 0, f4 = 0, f5 = 0, f6 = 0, f7 = 0;
+
+  for (int i = 0; i < 3120; i++)
+    {
+      f1 = getf ();
+      f2 = getf ();
+      f3 = getf ();
+      f4 = getf ();
+      array[i] = my_getchar ();
+      farray[i] = my_getchar () * 1.2;
+      sum += array[i] + farray[i] + f1 + f2 + f3 + f4;
+    }
+  return sum;
+}
+
+/*
+**outgoing_stack_args:
+**	...
+**	cm.push	{ra, s0}, -32
+**	...
+**	cm.popret	{ra, s0}, 32
+**	...
+*/
+int
+outgoing_stack_args ()
+{
+  int local = getint ();
+  return local + incoming_stack_args (0, 1, 2, 3, 4, 5, 6, 7, 8);
+}
+
+/*
+**callPrintInts:
+**	...
+**	cm.push	{ra}, -32
+**	...
+**	cm.popret	{ra}, 32
+**	...
+*/
+float
+callPrintInts ()
+{
+  volatile float f = getf (); // f in local
+  PrintInts (9, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+  return f;
+}
+
+/*
+**callPrint:
+**	...
+**	cm.push	{ra}, -32
+**	...
+**	cm.popret	{ra}, 32
+**	...
+*/
+float
+callPrint ()
+{
+  volatile float f = getf (); // f in local
+  PrintIntsNoVaStart (0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+  return f;
+}
+
+/*
+**callPrint_S:
+**	...
+**	cm.push	{ra, s0}, -32
+**	...
+**	cm.popret	{ra, s0}, 32
+**	...
+*/
+float
+callPrint_S ()
+{
+  float f = getf ();
+  PrintIntsNoVaStart (0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+  return f;
+}
+
+/*
+**callPrint_2:
+**	...
+**	cm.push	{ra, s0}, -32
+**	...
+**	cm.popret	{ra, s0}, 32
+**	...
+*/
+float
+callPrint_2 ()
+{
+  float f = getf ();
+  PrintInts2 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+  return f;
+}
+
+/*
+**test_step1_0bytes_save_restore:
+**	...
+**	cm.push	{ra}, -16
+**	...
+**	cm.popret	{ra}, 16
+**	...
+*/
+int
+test_step1_0bytes_save_restore ()
+{
+  int a = 9;
+  int b = my_getchar ();
+  return a + b;
+}
+
+/*
+**test_s0:
+**	...
+**	cm.push	{ra, s0}, -16
+**	...
+**	cm.popret	{ra, s0}, 16
+**	...
+*/
+int
+test_s0 ()
+{
+  int a = my_getchar ();
+  int b = my_getchar ();
+  return a + b;
+}
+
+/*
+**test_s1:
+**	...
+**	cm.push	{ra, s0-s1}, -16
+**	...
+**	cm.popret	{ra, s0-s1}, 16
+**	...
+*/
+int
+test_s1 ()
+{
+  int s0 = my_getchar ();
+  int s1 = my_getchar ();
+  int b = my_getchar ();
+  return s1 + s0 + b;
+}
+
+/*
+**test_f0:
+**	...
+**	cm.push	{ra, s0-s1}, -16
+**	...
+**	cm.popret	{ra, s0-s1}, 16
+**	...
+*/
+int
+test_f0 ()
+{
+  int s0 = my_getchar ();
+  float f0 = getf ();
+  int b = my_getchar ();
+  return f0 + s0 + b;
+}
+
+/*
+**foo:
+**	cm.push	{ra}, -16
+**	call	f1
+**	cm.pop	{ra}, 16
+**	tail	f2
+*/
+void
+foo (void)
+{
+  f1 ();
+  f2 ();
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c b/gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c
new file mode 100644
index 00000000000..f24e0a8bab9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c
@@ -0,0 +1,256 @@
+/* { dg-do compile } */
+/* { dg-options " -Os -march=rv32imaf_zca_zcmp -mabi=ilp32f -mcmodel=medlow -fno-shrink-wrap-separate" }*/
+/* { dg-skip-if "" { *-*-* } {"-O0" "-O1" "-O2" "-Og" "-O3" "-Oz" "-flto"} } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+char
+my_getchar ();
+float
+getf ();
+int __attribute__ ((noinline))
+incoming_stack_args (int arg0, int arg1, int arg2, int arg3, int arg4, int arg5,
+		     int arg6, int arg7, int arg8);
+int
+getint ();
+void
+PrintInts (int n, ...);						 // varargs
+void __attribute__ ((noinline)) PrintIntsNoVaStart (int n, ...); // varargs
+void
+PrintInts2 (int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int n,
+	    ...);
+extern void
+f1 (void);
+extern void
+f2 (void);
+
+/*
+**test1:
+**	...
+**	cm.push	{ra, s0-s4}, -80
+**	...
+**	cm.popret	{ra, s0-s4}, 80
+**	...
+*/
+int
+test1 ()
+{
+  char volatile array[3120];
+  float volatile farray[3120];
+
+  float sum = 0;
+  for (int i = 0; i < 3120; i++)
+    {
+      array[i] = my_getchar ();
+      farray[i] = my_getchar () * 1.2;
+      sum += array[i] + farray[i];
+    }
+  return sum;
+}
+
+/*
+**test2_step1_0_size:
+**	...
+**	cm.push	{ra, s0-s1}, -64
+**	...
+**	cm.popret	{ra, s0-s1}, 64
+**	...
+*/
+int
+test2_step1_0_size ()
+{
+  int volatile iarray[3120 + 1824 / 4 - 8];
+
+  for (int i = 0; i < 3120 + 1824 / 4 - 8; i++)
+    {
+      iarray[i] = my_getchar () * 2;
+    }
+  return iarray[0] + iarray[1];
+}
+
+/*
+**test3:
+**	...
+**	cm.push	{ra, s0-s4}, -80
+**	...
+**	cm.popret	{ra, s0-s4}, 80
+**	...
+*/
+float
+test3 ()
+{
+  char volatile array[3120];
+  float volatile farray[3120];
+
+  float sum = 0, f1 = 0, f2 = 0, f3 = 0, f4 = 0, f5 = 0, f6 = 0, f7 = 0;
+
+  for (int i = 0; i < 3120; i++)
+    {
+      f1 = getf ();
+      f2 = getf ();
+      f3 = getf ();
+      f4 = getf ();
+      array[i] = my_getchar ();
+      farray[i] = my_getchar () * 1.2;
+      sum += array[i] + farray[i] + f1 + f2 + f3 + f4;
+    }
+  return sum;
+}
+
+/*
+**outgoing_stack_args:
+**	...
+**	cm.push	{ra, s0}, -32
+**	...
+**	cm.popret	{ra, s0}, 32
+**	...
+*/
+int
+outgoing_stack_args ()
+{
+  int local = getint ();
+  return local + incoming_stack_args (0, 1, 2, 3, 4, 5, 6, 7, 8);
+}
+
+/*
+**callPrintInts:
+**	...
+**	cm.push	{ra}, -48
+**	...
+**	cm.popret	{ra}, 48
+**	...
+*/
+float
+callPrintInts ()
+{
+  volatile float f = getf (); // f in local
+  PrintInts (9, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+  return f;
+}
+
+/*
+**callPrint:
+**	...
+**	cm.push	{ra}, -48
+**	...
+**	cm.popret	{ra}, 48
+**	...
+*/
+float
+callPrint ()
+{
+  volatile float f = getf (); // f in local
+  PrintIntsNoVaStart (0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+  return f;
+}
+
+/*
+**callPrint_S:
+**	...
+**	cm.push	{ra}, -48
+**	...
+**	cm.popret	{ra}, 48
+**	...
+*/
+float
+callPrint_S ()
+{
+  float f = getf ();
+  PrintIntsNoVaStart (0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+  return f;
+}
+
+/*
+**callPrint_2:
+**	...
+**	cm.push	{ra}, -48
+**	...
+**	cm.popret	{ra}, 48
+**	...
+*/
+float
+callPrint_2 ()
+{
+  float f = getf ();
+  PrintInts2 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+  return f;
+}
+
+/*
+**test_step1_0bytes_save_restore:
+**	...
+**	cm.push	{ra}, -16
+**	...
+**	cm.popret	{ra}, 16
+**	...
+*/
+int
+test_step1_0bytes_save_restore ()
+{
+  int a = 9;
+  int b = my_getchar ();
+  return a + b;
+}
+
+/*
+**test_s0:
+**	...
+**	cm.push	{ra, s0}, -16
+**	...
+**	cm.popret	{ra, s0}, 16
+**	...
+*/
+int
+test_s0 ()
+{
+  int a = my_getchar ();
+  int b = my_getchar ();
+  return a + b;
+}
+
+/*
+**test_s1:
+**	...
+**	cm.push	{ra, s0-s1}, -16
+**	...
+**	cm.popret	{ra, s0-s1}, 16
+**	...
+*/
+int
+test_s1 ()
+{
+  int s0 = my_getchar ();
+  int s1 = my_getchar ();
+  int b = my_getchar ();
+  return s1 + s0 + b;
+}
+
+/*
+**test_f0:
+**	...
+**	cm.push	{ra, s0}, -32
+**	...
+**	cm.popret	{ra, s0}, 32
+**	...
+*/
+int
+test_f0 ()
+{
+  int s0 = my_getchar ();
+  float f0 = getf ();
+  int b = my_getchar ();
+  return f0 + s0 + b;
+}
+
+/*
+**foo:
+**	cm.push	{ra}, -16
+**	call	f1
+**	cm.pop	{ra}, 16
+**	tail	f2
+*/
+void
+foo (void)
+{
+  f1 ();
+  f2 ();
+}
diff --git a/gcc/testsuite/gcc.target/riscv/zcmp_push_fpr.c b/gcc/testsuite/gcc.target/riscv/zcmp_push_fpr.c
new file mode 100644
index 00000000000..530b35b53dd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zcmp_push_fpr.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64imafd_zicsr_zifencei_zca_zcmp -mabi=lp64d -Os -fno-shrink-wrap-separate" } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-O1" "-O2" "-Og" "-O3" "-Oz" "-flto"} } */
+
+typedef struct
+{
+  struct
+  {
+    struct
+    {
+      struct
+      {
+	long a;
+      };
+    } a[129];
+  };
+} b;
+
+struct c
+{
+  void *a[129];
+};
+
+extern void
+f (struct c, b *);
+
+struct c
+d ()
+{
+  struct c a;
+  __builtin_unwind_init ();
+  b e;
+  f (a, &e);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/zcmp_stack_alignment.c b/gcc/testsuite/gcc.target/riscv/zcmp_stack_alignment.c
new file mode 100644
index 00000000000..2f2fa55baac
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zcmp_stack_alignment.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options " -O0 -march=rv32e_zca_zcb_zcmp -mabi=ilp32e -mcmodel=medlow -fomit-frame-pointer -fno-shrink-wrap-separate" } */
+/* { dg-skip-if "" { *-*-* } {"-O2" "-O1" "-Os" "-Og" "-O3" "-Oz" "-flto"} } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+void
+bar ();
+
+/*
+**fool_rv32e:
+**	cm.push	{ra}, -32
+**	...
+**	call	bar
+**	...
+**	lw	a[0-5],32\(sp\)
+**	...
+**	cm.popret	{ra}, 32
+*/
+int
+fool_rv32e (int a0, int a1, int a2, int a3, int a4, int a5, int incoming0)
+{
+  bar ();
+  return a0 + a1 + a2 + a3 + a4 + a5 + incoming0;
+}
-- 
2.17.1


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

* [PATCH 2/3] [V2] [RISC-V] support cm.popretz in zcmp
  2023-08-29  8:37 [PATCH 0/3] [RISC-V] support zcmp extension Fei Gao
  2023-08-29  8:37 ` [PATCH 1/3] [V6] [RISC-V] support cm.push cm.pop cm.popret in zcmp Fei Gao
@ 2023-08-29  8:37 ` Fei Gao
  2023-08-29  8:37 ` [PATCH 3/3] [V2] [RISC-V] support cm.mva01s cm.mvsa01 " Fei Gao
  2023-08-30 10:03 ` [PATCH 0/3] [RISC-V] support zcmp extension Kito Cheng
  3 siblings, 0 replies; 14+ messages in thread
From: Fei Gao @ 2023-08-29  8:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: kito.cheng, palmer, jeffreyalaw, sinan.lin, jiawei, Fei Gao

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 --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;
+}
-- 
2.17.1


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

* [PATCH 3/3] [V2] [RISC-V] support cm.mva01s cm.mvsa01 in zcmp
  2023-08-29  8:37 [PATCH 0/3] [RISC-V] support zcmp extension Fei Gao
  2023-08-29  8:37 ` [PATCH 1/3] [V6] [RISC-V] support cm.push cm.pop cm.popret in zcmp Fei Gao
  2023-08-29  8:37 ` [PATCH 2/3] [V2] [RISC-V] support cm.popretz " Fei Gao
@ 2023-08-29  8:37 ` Fei Gao
  2023-09-07 20:16   ` Dimitar Dimitrov
  2023-08-30 10:03 ` [PATCH 0/3] [RISC-V] support zcmp extension Kito Cheng
  3 siblings, 1 reply; 14+ messages in thread
From: Fei Gao @ 2023-08-29  8:37 UTC (permalink / raw)
  To: gcc-patches
  Cc: kito.cheng, palmer, jeffreyalaw, sinan.lin, jiawei, Fei Gao, Die Li

From: Die Li <lidie@eswincomputing.com>

Signed-off-by: Die Li <lidie@eswincomputing.com>
Co-Authored-By: Fei Gao <gaofei@eswincomputing.com>

gcc/ChangeLog:

        * config/riscv/peephole.md: New pattern.
        * config/riscv/predicates.md (a0a1_reg_operand): New predicate.
        (zcmp_mv_sreg_operand): New predicate.
        * config/riscv/riscv.md: New predicate.
        * config/riscv/zc.md (*mva01s<X:mode>): New pattern.
        (*mvsa01<X:mode>): New pattern.

gcc/testsuite/ChangeLog:

        * gcc.target/riscv/cm_mv_rv32.c: New test.
---
 gcc/config/riscv/peephole.md                | 28 +++++++++++++++++++++
 gcc/config/riscv/predicates.md              | 11 ++++++++
 gcc/config/riscv/riscv.md                   |  1 +
 gcc/config/riscv/zc.md                      | 22 ++++++++++++++++
 gcc/testsuite/gcc.target/riscv/cm_mv_rv32.c | 23 +++++++++++++++++
 5 files changed, 85 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/riscv/cm_mv_rv32.c

diff --git a/gcc/config/riscv/peephole.md b/gcc/config/riscv/peephole.md
index 0ef0c04410b..92e57f9a447 100644
--- a/gcc/config/riscv/peephole.md
+++ b/gcc/config/riscv/peephole.md
@@ -38,3 +38,31 @@
 {
   operands[5] = GEN_INT (INTVAL (operands[2]) - INTVAL (operands[5]));
 })
+
+;; ZCMP
+(define_peephole2
+  [(set (match_operand:X 0 "a0a1_reg_operand")
+        (match_operand:X 1 "zcmp_mv_sreg_operand"))
+   (set (match_operand:X 2 "a0a1_reg_operand")
+        (match_operand:X 3 "zcmp_mv_sreg_operand"))]
+  "TARGET_ZCMP
+   && (REGNO (operands[2]) != REGNO (operands[0]))"
+  [(parallel [(set (match_dup 0)
+                   (match_dup 1))
+              (set (match_dup 2)
+                   (match_dup 3))])]
+)
+
+(define_peephole2
+  [(set (match_operand:X 0 "zcmp_mv_sreg_operand")
+        (match_operand:X 1 "a0a1_reg_operand"))
+   (set (match_operand:X 2 "zcmp_mv_sreg_operand")
+        (match_operand:X 3 "a0a1_reg_operand"))]
+  "TARGET_ZCMP
+   && (REGNO (operands[0]) != REGNO (operands[2]))
+   && (REGNO (operands[1]) != REGNO (operands[3]))"
+  [(parallel [(set (match_dup 0)
+                   (match_dup 1))
+              (set (match_dup 2)
+                   (match_dup 3))])]
+)
diff --git a/gcc/config/riscv/predicates.md b/gcc/config/riscv/predicates.md
index 3ef09996a85..772f45df65c 100644
--- a/gcc/config/riscv/predicates.md
+++ b/gcc/config/riscv/predicates.md
@@ -165,6 +165,17 @@
   (and (match_code "const_int")
        (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 13)")))
 
+;; ZCMP predicates
+(define_predicate "a0a1_reg_operand"
+  (and (match_operand 0 "register_operand")
+       (match_test "IN_RANGE (REGNO (op), A0_REGNUM, A1_REGNUM)")))
+
+(define_predicate "zcmp_mv_sreg_operand"
+  (and (match_operand 0 "register_operand")
+       (match_test "TARGET_RVE ? IN_RANGE (REGNO (op), S0_REGNUM, S1_REGNUM)
+                    : IN_RANGE (REGNO (op), S0_REGNUM, S1_REGNUM)
+                    || IN_RANGE (REGNO (op), S2_REGNUM, S7_REGNUM)")))
+
 ;; Only use branch-on-bit sequences when the mask is not an ANDI immediate.
 (define_predicate "branch_on_bit_operand"
   (and (match_code "const_int")
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index 8e09df6ff63..aa2b5b960dc 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -132,6 +132,7 @@
    (S0_REGNUM			8)
    (S1_REGNUM			9)
    (A0_REGNUM			10)
+   (A1_REGNUM			11)
    (S2_REGNUM			18)
    (S3_REGNUM			19)
    (S4_REGNUM			20)
diff --git a/gcc/config/riscv/zc.md b/gcc/config/riscv/zc.md
index 8d7de97daad..77b28adde95 100644
--- a/gcc/config/riscv/zc.md
+++ b/gcc/config/riscv/zc.md
@@ -1433,3 +1433,25 @@
   "TARGET_ZCMP"
   "cm.push	{ra, s0-s11}, %0"
 )
+
+;; ZCMP mv
+(define_insn "*mva01s<X:mode>"
+  [(set (match_operand:X 0 "a0a1_reg_operand" "=r")
+        (match_operand:X 1 "zcmp_mv_sreg_operand" "r"))
+   (set (match_operand:X 2 "a0a1_reg_operand" "=r")
+        (match_operand:X 3 "zcmp_mv_sreg_operand" "r"))]
+  "TARGET_ZCMP
+   && (REGNO (operands[2]) != REGNO (operands[0]))"
+  { return (REGNO (operands[0]) == A0_REGNUM)?"cm.mva01s\t%1,%3":"cm.mva01s\t%3,%1"; }
+  [(set_attr "mode" "<X:MODE>")])
+
+(define_insn "*mvsa01<X:mode>"
+  [(set (match_operand:X 0 "zcmp_mv_sreg_operand" "=r")
+        (match_operand:X 1 "a0a1_reg_operand" "r"))
+   (set (match_operand:X 2 "zcmp_mv_sreg_operand" "=r")
+        (match_operand:X 3 "a0a1_reg_operand" "r"))]
+  "TARGET_ZCMP
+   && (REGNO (operands[0]) != REGNO (operands[2]))
+   && (REGNO (operands[1]) != REGNO (operands[3]))"
+  { return (REGNO (operands[1]) == A0_REGNUM)?"cm.mvsa01\t%0,%2":"cm.mvsa01\t%2,%0"; }
+  [(set_attr "mode" "<X:MODE>")])
diff --git a/gcc/testsuite/gcc.target/riscv/cm_mv_rv32.c b/gcc/testsuite/gcc.target/riscv/cm_mv_rv32.c
new file mode 100644
index 00000000000..2c1b3f9cabf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/cm_mv_rv32.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options " -Os -march=rv32i_zca_zcmp -mabi=ilp32 " } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-O1" "-O2" "-Og" "-O3" "-Oz" "-flto"} } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+int
+func (int a, int b);
+
+/*
+**sum:
+**	...
+**	cm.mvsa01	s1,s2
+**	call	func
+**	mv	s0,a0
+**	cm.mva01s	s1,s2
+**	call	func
+**	...
+*/
+int
+sum (int a, int b)
+{
+  return func (a, b) + func (a, b);
+}
-- 
2.17.1


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

* Re: [PATCH 0/3] [RISC-V] support zcmp extension
  2023-08-29  8:37 [PATCH 0/3] [RISC-V] support zcmp extension Fei Gao
                   ` (2 preceding siblings ...)
  2023-08-29  8:37 ` [PATCH 3/3] [V2] [RISC-V] support cm.mva01s cm.mvsa01 " Fei Gao
@ 2023-08-30 10:03 ` Kito Cheng
  3 siblings, 0 replies; 14+ messages in thread
From: Kito Cheng @ 2023-08-30 10:03 UTC (permalink / raw)
  To: Fei Gao; +Cc: gcc-patches, jiawei

Pass regression without introducing any new fail, push to trunk :)

On Tue, Aug 29, 2023 at 4:39 PM Fei Gao <gaofei@eswincomputing.com> wrote:
>
> Fei Gao (3):
>   [RISC-V] support cm.push cm.pop cm.popret in zcmp
>   [RISC-V] support cm.popretz in zcmp
>   [RISC-V] support cm.mva01s cm.mvsa01 in zcmp
>
>  gcc/config/riscv/iterators.md                 |   15 +
>  gcc/config/riscv/peephole.md                  |   28 +
>  gcc/config/riscv/predicates.md                |  107 ++
>  gcc/config/riscv/riscv-protos.h               |    2 +
>  gcc/config/riscv/riscv.cc                     |  499 +++++-
>  gcc/config/riscv/riscv.h                      |   25 +
>  gcc/config/riscv/riscv.md                     |    4 +
>  gcc/config/riscv/zc.md                        | 1457 +++++++++++++++++
>  gcc/testsuite/gcc.target/riscv/cm_mv_rv32.c   |   23 +
>  gcc/testsuite/gcc.target/riscv/rv32e_zcmp.c   |  269 +++
>  gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c   |  269 +++
>  .../gcc.target/riscv/zcmp_push_fpr.c          |   34 +
>  .../gcc.target/riscv/zcmp_stack_alignment.c   |   24 +
>  13 files changed, 2705 insertions(+), 51 deletions(-)
>  create mode 100644 gcc/config/riscv/zc.md
>  create mode 100644 gcc/testsuite/gcc.target/riscv/cm_mv_rv32.c
>  create mode 100644 gcc/testsuite/gcc.target/riscv/rv32e_zcmp.c
>  create mode 100644 gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c
>  create mode 100644 gcc/testsuite/gcc.target/riscv/zcmp_push_fpr.c
>  create mode 100644 gcc/testsuite/gcc.target/riscv/zcmp_stack_alignment.c
>
> --
> 2.17.1
>

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

* Re: [PATCH 3/3] [V2] [RISC-V] support cm.mva01s cm.mvsa01 in zcmp
  2023-08-29  8:37 ` [PATCH 3/3] [V2] [RISC-V] support cm.mva01s cm.mvsa01 " Fei Gao
@ 2023-09-07 20:16   ` Dimitar Dimitrov
  2023-09-07 20:33     ` Palmer Dabbelt
  0 siblings, 1 reply; 14+ messages in thread
From: Dimitar Dimitrov @ 2023-09-07 20:16 UTC (permalink / raw)
  To: Fei Gao; +Cc: gcc-patches, kito.cheng, jiawei, Die Li

Hi,

This patch appears to have caused PR 111259.

Regards,
Dimitar

On Tue, Aug 29, 2023 at 08:37:46AM +0000, Fei Gao wrote:
> From: Die Li <lidie@eswincomputing.com>
> 
> Signed-off-by: Die Li <lidie@eswincomputing.com>
> Co-Authored-By: Fei Gao <gaofei@eswincomputing.com>
> 
> gcc/ChangeLog:
> 
>         * config/riscv/peephole.md: New pattern.
>         * config/riscv/predicates.md (a0a1_reg_operand): New predicate.
>         (zcmp_mv_sreg_operand): New predicate.
>         * config/riscv/riscv.md: New predicate.
>         * config/riscv/zc.md (*mva01s<X:mode>): New pattern.
>         (*mvsa01<X:mode>): New pattern.
> 
> gcc/testsuite/ChangeLog:
> 
>         * gcc.target/riscv/cm_mv_rv32.c: New test.
> ---
>  gcc/config/riscv/peephole.md                | 28 +++++++++++++++++++++
>  gcc/config/riscv/predicates.md              | 11 ++++++++
>  gcc/config/riscv/riscv.md                   |  1 +
>  gcc/config/riscv/zc.md                      | 22 ++++++++++++++++
>  gcc/testsuite/gcc.target/riscv/cm_mv_rv32.c | 23 +++++++++++++++++
>  5 files changed, 85 insertions(+)
>  create mode 100644 gcc/testsuite/gcc.target/riscv/cm_mv_rv32.c
> 
> diff --git a/gcc/config/riscv/peephole.md b/gcc/config/riscv/peephole.md
> index 0ef0c04410b..92e57f9a447 100644
> --- a/gcc/config/riscv/peephole.md
> +++ b/gcc/config/riscv/peephole.md
> @@ -38,3 +38,31 @@
>  {
>    operands[5] = GEN_INT (INTVAL (operands[2]) - INTVAL (operands[5]));
>  })
> +
> +;; ZCMP
> +(define_peephole2
> +  [(set (match_operand:X 0 "a0a1_reg_operand")
> +        (match_operand:X 1 "zcmp_mv_sreg_operand"))
> +   (set (match_operand:X 2 "a0a1_reg_operand")
> +        (match_operand:X 3 "zcmp_mv_sreg_operand"))]
> +  "TARGET_ZCMP
> +   && (REGNO (operands[2]) != REGNO (operands[0]))"
> +  [(parallel [(set (match_dup 0)
> +                   (match_dup 1))
> +              (set (match_dup 2)
> +                   (match_dup 3))])]
> +)
> +
> +(define_peephole2
> +  [(set (match_operand:X 0 "zcmp_mv_sreg_operand")
> +        (match_operand:X 1 "a0a1_reg_operand"))
> +   (set (match_operand:X 2 "zcmp_mv_sreg_operand")
> +        (match_operand:X 3 "a0a1_reg_operand"))]
> +  "TARGET_ZCMP
> +   && (REGNO (operands[0]) != REGNO (operands[2]))
> +   && (REGNO (operands[1]) != REGNO (operands[3]))"
> +  [(parallel [(set (match_dup 0)
> +                   (match_dup 1))
> +              (set (match_dup 2)
> +                   (match_dup 3))])]
> +)
> diff --git a/gcc/config/riscv/predicates.md b/gcc/config/riscv/predicates.md
> index 3ef09996a85..772f45df65c 100644
> --- a/gcc/config/riscv/predicates.md
> +++ b/gcc/config/riscv/predicates.md
> @@ -165,6 +165,17 @@
>    (and (match_code "const_int")
>         (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 13)")))
>  
> +;; ZCMP predicates
> +(define_predicate "a0a1_reg_operand"
> +  (and (match_operand 0 "register_operand")
> +       (match_test "IN_RANGE (REGNO (op), A0_REGNUM, A1_REGNUM)")))
> +
> +(define_predicate "zcmp_mv_sreg_operand"
> +  (and (match_operand 0 "register_operand")
> +       (match_test "TARGET_RVE ? IN_RANGE (REGNO (op), S0_REGNUM, S1_REGNUM)
> +                    : IN_RANGE (REGNO (op), S0_REGNUM, S1_REGNUM)
> +                    || IN_RANGE (REGNO (op), S2_REGNUM, S7_REGNUM)")))
> +
>  ;; Only use branch-on-bit sequences when the mask is not an ANDI immediate.
>  (define_predicate "branch_on_bit_operand"
>    (and (match_code "const_int")
> diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
> index 8e09df6ff63..aa2b5b960dc 100644
> --- a/gcc/config/riscv/riscv.md
> +++ b/gcc/config/riscv/riscv.md
> @@ -132,6 +132,7 @@
>     (S0_REGNUM			8)
>     (S1_REGNUM			9)
>     (A0_REGNUM			10)
> +   (A1_REGNUM			11)
>     (S2_REGNUM			18)
>     (S3_REGNUM			19)
>     (S4_REGNUM			20)
> diff --git a/gcc/config/riscv/zc.md b/gcc/config/riscv/zc.md
> index 8d7de97daad..77b28adde95 100644
> --- a/gcc/config/riscv/zc.md
> +++ b/gcc/config/riscv/zc.md
> @@ -1433,3 +1433,25 @@
>    "TARGET_ZCMP"
>    "cm.push	{ra, s0-s11}, %0"
>  )
> +
> +;; ZCMP mv
> +(define_insn "*mva01s<X:mode>"
> +  [(set (match_operand:X 0 "a0a1_reg_operand" "=r")
> +        (match_operand:X 1 "zcmp_mv_sreg_operand" "r"))
> +   (set (match_operand:X 2 "a0a1_reg_operand" "=r")
> +        (match_operand:X 3 "zcmp_mv_sreg_operand" "r"))]
> +  "TARGET_ZCMP
> +   && (REGNO (operands[2]) != REGNO (operands[0]))"
> +  { return (REGNO (operands[0]) == A0_REGNUM)?"cm.mva01s\t%1,%3":"cm.mva01s\t%3,%1"; }
> +  [(set_attr "mode" "<X:MODE>")])
> +
> +(define_insn "*mvsa01<X:mode>"
> +  [(set (match_operand:X 0 "zcmp_mv_sreg_operand" "=r")
> +        (match_operand:X 1 "a0a1_reg_operand" "r"))
> +   (set (match_operand:X 2 "zcmp_mv_sreg_operand" "=r")
> +        (match_operand:X 3 "a0a1_reg_operand" "r"))]
> +  "TARGET_ZCMP
> +   && (REGNO (operands[0]) != REGNO (operands[2]))
> +   && (REGNO (operands[1]) != REGNO (operands[3]))"
> +  { return (REGNO (operands[1]) == A0_REGNUM)?"cm.mvsa01\t%0,%2":"cm.mvsa01\t%2,%0"; }
> +  [(set_attr "mode" "<X:MODE>")])
> diff --git a/gcc/testsuite/gcc.target/riscv/cm_mv_rv32.c b/gcc/testsuite/gcc.target/riscv/cm_mv_rv32.c
> new file mode 100644
> index 00000000000..2c1b3f9cabf
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/cm_mv_rv32.c
> @@ -0,0 +1,23 @@
> +/* { dg-do compile } */
> +/* { dg-options " -Os -march=rv32i_zca_zcmp -mabi=ilp32 " } */
> +/* { dg-skip-if "" { *-*-* } {"-O0" "-O1" "-O2" "-Og" "-O3" "-Oz" "-flto"} } */
> +/* { dg-final { check-function-bodies "**" "" } } */
> +
> +int
> +func (int a, int b);
> +
> +/*
> +**sum:
> +**	...
> +**	cm.mvsa01	s1,s2
> +**	call	func
> +**	mv	s0,a0
> +**	cm.mva01s	s1,s2
> +**	call	func
> +**	...
> +*/
> +int
> +sum (int a, int b)
> +{
> +  return func (a, b) + func (a, b);
> +}
> -- 
> 2.17.1
> 

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

* Re: [PATCH 3/3] [V2] [RISC-V] support cm.mva01s cm.mvsa01 in zcmp
  2023-09-07 20:16   ` Dimitar Dimitrov
@ 2023-09-07 20:33     ` Palmer Dabbelt
  2023-09-08  2:06       ` Fei Gao
  2023-09-12  3:15       ` Jeff Law
  0 siblings, 2 replies; 14+ messages in thread
From: Palmer Dabbelt @ 2023-09-07 20:33 UTC (permalink / raw)
  To: dimitar, Patrick O'Neill
  Cc: gaofei, gcc-patches, Kito Cheng, jiawei, lidie

On Thu, 07 Sep 2023 13:16:36 PDT (-0700), dimitar@dinux.eu wrote:
> Hi,
>
> This patch appears to have caused PR 111259.

Thanks.  Looks like wer'e not running our tests with RTL checking, 
Patrick is going to try and see if we've got compute time left for some 
builds -- even just having builds with checking would be a good one, we 
get bit by these bugs from time to time.

I'm spinning up a --enable-checking=yes build.  Maybe we just need 
something like

    diff --git a/gcc/config/riscv/predicates.md b/gcc/config/riscv/predicates.md
    index 53e7c1d03aa..aa4f02c67d5 100644
    --- a/gcc/config/riscv/predicates.md
    +++ b/gcc/config/riscv/predicates.md
    @@ -172,11 +172,11 @@ (define_predicate "stack_pop_up_to_s11_operand"
     
     ;; ZCMP predicates
     (define_predicate "a0a1_reg_operand"
    -  (and (match_operand 0 "register_operand")
    +  (and (match_code "reg")
            (match_test "IN_RANGE (REGNO (op), A0_REGNUM, A1_REGNUM)")))
     
     (define_predicate "zcmp_mv_sreg_operand"
    -  (and (match_operand 0 "register_operand")
    +  (and (match_code "reg")
            (match_test "TARGET_RVE ? IN_RANGE (REGNO (op), S0_REGNUM, S1_REGNUM)
                         : IN_RANGE (REGNO (op), S0_REGNUM, S1_REGNUM)
                         || IN_RANGE (REGNO (op), S2_REGNUM, S7_REGNUM)")))

> Regards,
> Dimitar
>
> On Tue, Aug 29, 2023 at 08:37:46AM +0000, Fei Gao wrote:
>> From: Die Li <lidie@eswincomputing.com>
>>
>> Signed-off-by: Die Li <lidie@eswincomputing.com>
>> Co-Authored-By: Fei Gao <gaofei@eswincomputing.com>
>>
>> gcc/ChangeLog:
>>
>>         * config/riscv/peephole.md: New pattern.
>>         * config/riscv/predicates.md (a0a1_reg_operand): New predicate.
>>         (zcmp_mv_sreg_operand): New predicate.
>>         * config/riscv/riscv.md: New predicate.
>>         * config/riscv/zc.md (*mva01s<X:mode>): New pattern.
>>         (*mvsa01<X:mode>): New pattern.
>>
>> gcc/testsuite/ChangeLog:
>>
>>         * gcc.target/riscv/cm_mv_rv32.c: New test.
>> ---
>>  gcc/config/riscv/peephole.md                | 28 +++++++++++++++++++++
>>  gcc/config/riscv/predicates.md              | 11 ++++++++
>>  gcc/config/riscv/riscv.md                   |  1 +
>>  gcc/config/riscv/zc.md                      | 22 ++++++++++++++++
>>  gcc/testsuite/gcc.target/riscv/cm_mv_rv32.c | 23 +++++++++++++++++
>>  5 files changed, 85 insertions(+)
>>  create mode 100644 gcc/testsuite/gcc.target/riscv/cm_mv_rv32.c
>>
>> diff --git a/gcc/config/riscv/peephole.md b/gcc/config/riscv/peephole.md
>> index 0ef0c04410b..92e57f9a447 100644
>> --- a/gcc/config/riscv/peephole.md
>> +++ b/gcc/config/riscv/peephole.md
>> @@ -38,3 +38,31 @@
>>  {
>>    operands[5] = GEN_INT (INTVAL (operands[2]) - INTVAL (operands[5]));
>>  })
>> +
>> +;; ZCMP
>> +(define_peephole2
>> +  [(set (match_operand:X 0 "a0a1_reg_operand")
>> +        (match_operand:X 1 "zcmp_mv_sreg_operand"))
>> +   (set (match_operand:X 2 "a0a1_reg_operand")
>> +        (match_operand:X 3 "zcmp_mv_sreg_operand"))]
>> +  "TARGET_ZCMP
>> +   && (REGNO (operands[2]) != REGNO (operands[0]))"
>> +  [(parallel [(set (match_dup 0)
>> +                   (match_dup 1))
>> +              (set (match_dup 2)
>> +                   (match_dup 3))])]
>> +)
>> +
>> +(define_peephole2
>> +  [(set (match_operand:X 0 "zcmp_mv_sreg_operand")
>> +        (match_operand:X 1 "a0a1_reg_operand"))
>> +   (set (match_operand:X 2 "zcmp_mv_sreg_operand")
>> +        (match_operand:X 3 "a0a1_reg_operand"))]
>> +  "TARGET_ZCMP
>> +   && (REGNO (operands[0]) != REGNO (operands[2]))
>> +   && (REGNO (operands[1]) != REGNO (operands[3]))"
>> +  [(parallel [(set (match_dup 0)
>> +                   (match_dup 1))
>> +              (set (match_dup 2)
>> +                   (match_dup 3))])]
>> +)
>> diff --git a/gcc/config/riscv/predicates.md b/gcc/config/riscv/predicates.md
>> index 3ef09996a85..772f45df65c 100644
>> --- a/gcc/config/riscv/predicates.md
>> +++ b/gcc/config/riscv/predicates.md
>> @@ -165,6 +165,17 @@
>>    (and (match_code "const_int")
>>         (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 13)")))
>>
>> +;; ZCMP predicates
>> +(define_predicate "a0a1_reg_operand"
>> +  (and (match_operand 0 "register_operand")
>> +       (match_test "IN_RANGE (REGNO (op), A0_REGNUM, A1_REGNUM)")))
>> +
>> +(define_predicate "zcmp_mv_sreg_operand"
>> +  (and (match_operand 0 "register_operand")
>> +       (match_test "TARGET_RVE ? IN_RANGE (REGNO (op), S0_REGNUM, S1_REGNUM)
>> +                    : IN_RANGE (REGNO (op), S0_REGNUM, S1_REGNUM)
>> +                    || IN_RANGE (REGNO (op), S2_REGNUM, S7_REGNUM)")))
>> +
>>  ;; Only use branch-on-bit sequences when the mask is not an ANDI immediate.
>>  (define_predicate "branch_on_bit_operand"
>>    (and (match_code "const_int")
>> diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
>> index 8e09df6ff63..aa2b5b960dc 100644
>> --- a/gcc/config/riscv/riscv.md
>> +++ b/gcc/config/riscv/riscv.md
>> @@ -132,6 +132,7 @@
>>     (S0_REGNUM			8)
>>     (S1_REGNUM			9)
>>     (A0_REGNUM			10)
>> +   (A1_REGNUM			11)
>>     (S2_REGNUM			18)
>>     (S3_REGNUM			19)
>>     (S4_REGNUM			20)
>> diff --git a/gcc/config/riscv/zc.md b/gcc/config/riscv/zc.md
>> index 8d7de97daad..77b28adde95 100644
>> --- a/gcc/config/riscv/zc.md
>> +++ b/gcc/config/riscv/zc.md
>> @@ -1433,3 +1433,25 @@
>>    "TARGET_ZCMP"
>>    "cm.push	{ra, s0-s11}, %0"
>>  )
>> +
>> +;; ZCMP mv
>> +(define_insn "*mva01s<X:mode>"
>> +  [(set (match_operand:X 0 "a0a1_reg_operand" "=r")
>> +        (match_operand:X 1 "zcmp_mv_sreg_operand" "r"))
>> +   (set (match_operand:X 2 "a0a1_reg_operand" "=r")
>> +        (match_operand:X 3 "zcmp_mv_sreg_operand" "r"))]
>> +  "TARGET_ZCMP
>> +   && (REGNO (operands[2]) != REGNO (operands[0]))"
>> +  { return (REGNO (operands[0]) == A0_REGNUM)?"cm.mva01s\t%1,%3":"cm.mva01s\t%3,%1"; }
>> +  [(set_attr "mode" "<X:MODE>")])
>> +
>> +(define_insn "*mvsa01<X:mode>"
>> +  [(set (match_operand:X 0 "zcmp_mv_sreg_operand" "=r")
>> +        (match_operand:X 1 "a0a1_reg_operand" "r"))
>> +   (set (match_operand:X 2 "zcmp_mv_sreg_operand" "=r")
>> +        (match_operand:X 3 "a0a1_reg_operand" "r"))]
>> +  "TARGET_ZCMP
>> +   && (REGNO (operands[0]) != REGNO (operands[2]))
>> +   && (REGNO (operands[1]) != REGNO (operands[3]))"
>> +  { return (REGNO (operands[1]) == A0_REGNUM)?"cm.mvsa01\t%0,%2":"cm.mvsa01\t%2,%0"; }
>> +  [(set_attr "mode" "<X:MODE>")])
>> diff --git a/gcc/testsuite/gcc.target/riscv/cm_mv_rv32.c b/gcc/testsuite/gcc.target/riscv/cm_mv_rv32.c
>> new file mode 100644
>> index 00000000000..2c1b3f9cabf
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/riscv/cm_mv_rv32.c
>> @@ -0,0 +1,23 @@
>> +/* { dg-do compile } */
>> +/* { dg-options " -Os -march=rv32i_zca_zcmp -mabi=ilp32 " } */
>> +/* { dg-skip-if "" { *-*-* } {"-O0" "-O1" "-O2" "-Og" "-O3" "-Oz" "-flto"} } */
>> +/* { dg-final { check-function-bodies "**" "" } } */
>> +
>> +int
>> +func (int a, int b);
>> +
>> +/*
>> +**sum:
>> +**	...
>> +**	cm.mvsa01	s1,s2
>> +**	call	func
>> +**	mv	s0,a0
>> +**	cm.mva01s	s1,s2
>> +**	call	func
>> +**	...
>> +*/
>> +int
>> +sum (int a, int b)
>> +{
>> +  return func (a, b) + func (a, b);
>> +}
>> --
>> 2.17.1
>>

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

* Re: Re: [PATCH 3/3] [V2] [RISC-V] support cm.mva01s cm.mvsa01 in zcmp
  2023-09-07 20:33     ` Palmer Dabbelt
@ 2023-09-08  2:06       ` Fei Gao
  2023-09-08 15:23         ` Jeff Law
  2023-09-12  3:15       ` Jeff Law
  1 sibling, 1 reply; 14+ messages in thread
From: Fei Gao @ 2023-09-08  2:06 UTC (permalink / raw)
  To: Patrick O'Neill
  Cc: gcc-patches, Kito Cheng, jiawei, lidie, dimitar, Palmer Dabbelt

On 2023-09-08 04:33  Palmer Dabbelt <palmer@dabbelt.com> wrote:
>
>On Thu, 07 Sep 2023 13:16:36 PDT (-0700), dimitar@dinux.eu wrote:
>> Hi,
>>
>> This patch appears to have caused PR 111259. 
Hi Patrick 

We're reproducing the issue also. 

One thing that puzzles me is why a zcmp predicate casused
a regression in rv64gc single lib build. The new define_insn
and define_peephole2 are all gated by TARGET_ZCMP, which
is false when building libgcc.

Could you please share more about your findings regading 
"This patch appears to have caused PR 111259"?

BR, 
Fei

>
>Thanks.  Looks like wer'e not running our tests with RTL checking,
>Patrick is going to try and see if we've got compute time left for some
>builds -- even just having builds with checking would be a good one, we
>get bit by these bugs from time to time.
>
>I'm spinning up a --enable-checking=yes build.  Maybe we just need
>something like
>
>    diff --git a/gcc/config/riscv/predicates.md b/gcc/config/riscv/predicates.md
>    index 53e7c1d03aa..aa4f02c67d5 100644
>    --- a/gcc/config/riscv/predicates.md
>    +++ b/gcc/config/riscv/predicates.md
>    @@ -172,11 +172,11 @@ (define_predicate "stack_pop_up_to_s11_operand"
>    
>     ;; ZCMP predicates
>     (define_predicate "a0a1_reg_operand"
>    -  (and (match_operand 0 "register_operand")
>    +  (and (match_code "reg")
>            (match_test "IN_RANGE (REGNO (op), A0_REGNUM, A1_REGNUM)")))
>    
>     (define_predicate "zcmp_mv_sreg_operand"
>    -  (and (match_operand 0 "register_operand")
>    +  (and (match_code "reg")
>            (match_test "TARGET_RVE ? IN_RANGE (REGNO (op), S0_REGNUM, S1_REGNUM)
>                         : IN_RANGE (REGNO (op), S0_REGNUM, S1_REGNUM)
>                         || IN_RANGE (REGNO (op), S2_REGNUM, S7_REGNUM)")))
>
>> Regards,
>> Dimitar
>>
>> On Tue, Aug 29, 2023 at 08:37:46AM +0000, Fei Gao wrote:
>>> From: Die Li <lidie@eswincomputing.com>
>>>
>>> Signed-off-by: Die Li <lidie@eswincomputing.com>
>>> Co-Authored-By: Fei Gao <gaofei@eswincomputing.com>
>>>
>>> gcc/ChangeLog:
>>>
>>>         * config/riscv/peephole.md: New pattern.
>>>         * config/riscv/predicates.md (a0a1_reg_operand): New predicate.
>>>         (zcmp_mv_sreg_operand): New predicate.
>>>         * config/riscv/riscv.md: New predicate.
>>>         * config/riscv/zc.md (*mva01s<X:mode>): New pattern.
>>>         (*mvsa01<X:mode>): New pattern.
>>>
>>> gcc/testsuite/ChangeLog:
>>>
>>>         * gcc.target/riscv/cm_mv_rv32.c: New test.
>>> ---
>>>  gcc/config/riscv/peephole.md                | 28 +++++++++++++++++++++
>>>  gcc/config/riscv/predicates.md              | 11 ++++++++
>>>  gcc/config/riscv/riscv.md                   |  1 +
>>>  gcc/config/riscv/zc.md                      | 22 ++++++++++++++++
>>>  gcc/testsuite/gcc.target/riscv/cm_mv_rv32.c | 23 +++++++++++++++++
>>>  5 files changed, 85 insertions(+)
>>>  create mode 100644 gcc/testsuite/gcc.target/riscv/cm_mv_rv32.c
>>>
>>> diff --git a/gcc/config/riscv/peephole.md b/gcc/config/riscv/peephole.md
>>> index 0ef0c04410b..92e57f9a447 100644
>>> --- a/gcc/config/riscv/peephole.md
>>> +++ b/gcc/config/riscv/peephole.md
>>> @@ -38,3 +38,31 @@
>>>  {
>>>    operands[5] = GEN_INT (INTVAL (operands[2]) - INTVAL (operands[5]));
>>>  })
>>> +
>>> +;; ZCMP
>>> +(define_peephole2
>>> +  [(set (match_operand:X 0 "a0a1_reg_operand")
>>> +        (match_operand:X 1 "zcmp_mv_sreg_operand"))
>>> +   (set (match_operand:X 2 "a0a1_reg_operand")
>>> +        (match_operand:X 3 "zcmp_mv_sreg_operand"))]
>>> +  "TARGET_ZCMP
>>> +   && (REGNO (operands[2]) != REGNO (operands[0]))"
>>> +  [(parallel [(set (match_dup 0)
>>> +                   (match_dup 1))
>>> +              (set (match_dup 2)
>>> +                   (match_dup 3))])]
>>> +)
>>> +
>>> +(define_peephole2
>>> +  [(set (match_operand:X 0 "zcmp_mv_sreg_operand")
>>> +        (match_operand:X 1 "a0a1_reg_operand"))
>>> +   (set (match_operand:X 2 "zcmp_mv_sreg_operand")
>>> +        (match_operand:X 3 "a0a1_reg_operand"))]
>>> +  "TARGET_ZCMP
>>> +   && (REGNO (operands[0]) != REGNO (operands[2]))
>>> +   && (REGNO (operands[1]) != REGNO (operands[3]))"
>>> +  [(parallel [(set (match_dup 0)
>>> +                   (match_dup 1))
>>> +              (set (match_dup 2)
>>> +                   (match_dup 3))])]
>>> +)
>>> diff --git a/gcc/config/riscv/predicates.md b/gcc/config/riscv/predicates.md
>>> index 3ef09996a85..772f45df65c 100644
>>> --- a/gcc/config/riscv/predicates.md
>>> +++ b/gcc/config/riscv/predicates.md
>>> @@ -165,6 +165,17 @@
>>>    (and (match_code "const_int")
>>>         (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 13)")))
>>>
>>> +;; ZCMP predicates
>>> +(define_predicate "a0a1_reg_operand"
>>> +  (and (match_operand 0 "register_operand")
>>> +       (match_test "IN_RANGE (REGNO (op), A0_REGNUM, A1_REGNUM)")))
>>> +
>>> +(define_predicate "zcmp_mv_sreg_operand"
>>> +  (and (match_operand 0 "register_operand")
>>> +       (match_test "TARGET_RVE ? IN_RANGE (REGNO (op), S0_REGNUM, S1_REGNUM)
>>> +                    : IN_RANGE (REGNO (op), S0_REGNUM, S1_REGNUM)
>>> +                    || IN_RANGE (REGNO (op), S2_REGNUM, S7_REGNUM)")))
>>> +
>>>  ;; Only use branch-on-bit sequences when the mask is not an ANDI immediate.
>>>  (define_predicate "branch_on_bit_operand"
>>>    (and (match_code "const_int")
>>> diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
>>> index 8e09df6ff63..aa2b5b960dc 100644
>>> --- a/gcc/config/riscv/riscv.md
>>> +++ b/gcc/config/riscv/riscv.md
>>> @@ -132,6 +132,7 @@
>>>     (S0_REGNUM	8)
>>>     (S1_REGNUM	9)
>>>     (A0_REGNUM	10)
>>> +   (A1_REGNUM	11)
>>>     (S2_REGNUM	18)
>>>     (S3_REGNUM	19)
>>>     (S4_REGNUM	20)
>>> diff --git a/gcc/config/riscv/zc.md b/gcc/config/riscv/zc.md
>>> index 8d7de97daad..77b28adde95 100644
>>> --- a/gcc/config/riscv/zc.md
>>> +++ b/gcc/config/riscv/zc.md
>>> @@ -1433,3 +1433,25 @@
>>>    "TARGET_ZCMP"
>>>    "cm.push	{ra, s0-s11}, %0"
>>>  )
>>> +
>>> +;; ZCMP mv
>>> +(define_insn "*mva01s<X:mode>"
>>> +  [(set (match_operand:X 0 "a0a1_reg_operand" "=r")
>>> +        (match_operand:X 1 "zcmp_mv_sreg_operand" "r"))
>>> +   (set (match_operand:X 2 "a0a1_reg_operand" "=r")
>>> +        (match_operand:X 3 "zcmp_mv_sreg_operand" "r"))]
>>> +  "TARGET_ZCMP
>>> +   && (REGNO (operands[2]) != REGNO (operands[0]))"
>>> +  { return (REGNO (operands[0]) == A0_REGNUM)?"cm.mva01s\t%1,%3":"cm.mva01s\t%3,%1"; }
>>> +  [(set_attr "mode" "<X:MODE>")])
>>> +
>>> +(define_insn "*mvsa01<X:mode>"
>>> +  [(set (match_operand:X 0 "zcmp_mv_sreg_operand" "=r")
>>> +        (match_operand:X 1 "a0a1_reg_operand" "r"))
>>> +   (set (match_operand:X 2 "zcmp_mv_sreg_operand" "=r")
>>> +        (match_operand:X 3 "a0a1_reg_operand" "r"))]
>>> +  "TARGET_ZCMP
>>> +   && (REGNO (operands[0]) != REGNO (operands[2]))
>>> +   && (REGNO (operands[1]) != REGNO (operands[3]))"
>>> +  { return (REGNO (operands[1]) == A0_REGNUM)?"cm.mvsa01\t%0,%2":"cm.mvsa01\t%2,%0"; }
>>> +  [(set_attr "mode" "<X:MODE>")])
>>> diff --git a/gcc/testsuite/gcc.target/riscv/cm_mv_rv32.c b/gcc/testsuite/gcc.target/riscv/cm_mv_rv32.c
>>> new file mode 100644
>>> index 00000000000..2c1b3f9cabf
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/riscv/cm_mv_rv32.c
>>> @@ -0,0 +1,23 @@
>>> +/* { dg-do compile } */
>>> +/* { dg-options " -Os -march=rv32i_zca_zcmp -mabi=ilp32 " } */
>>> +/* { dg-skip-if "" { *-*-* } {"-O0" "-O1" "-O2" "-Og" "-O3" "-Oz" "-flto"} } */
>>> +/* { dg-final { check-function-bodies "**" "" } } */
>>> +
>>> +int
>>> +func (int a, int b);
>>> +
>>> +/*
>>> +**sum:
>>> +**	...
>>> +**	cm.mvsa01	s1,s2
>>> +**	call	func
>>> +**	mv	s0,a0
>>> +**	cm.mva01s	s1,s2
>>> +**	call	func
>>> +**	...
>>> +*/
>>> +int
>>> +sum (int a, int b)
>>> +{
>>> +  return func (a, b) + func (a, b);
>>> +}
>>> --
>>> 2.17.1
>>>

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

* Re: [PATCH 3/3] [V2] [RISC-V] support cm.mva01s cm.mvsa01 in zcmp
  2023-09-08  2:06       ` Fei Gao
@ 2023-09-08 15:23         ` Jeff Law
  0 siblings, 0 replies; 14+ messages in thread
From: Jeff Law @ 2023-09-08 15:23 UTC (permalink / raw)
  To: Fei Gao, Patrick O'Neill; +Cc: Kito Cheng, jiawei, gcc-patches, lidie



On 9/7/23 20:06, Fei Gao wrote:
> On 2023-09-08 04:33  Palmer Dabbelt <palmer@dabbelt.com> wrote:
>>
>> On Thu, 07 Sep 2023 13:16:36 PDT (-0700), dimitar@dinux.eu wrote:
>>> Hi,
>>>
>>> This patch appears to have caused PR 111259.
> Hi Patrick
> 
> We're reproducing the issue also.
> 
> One thing that puzzles me is why a zcmp predicate casused
> a regression in rv64gc single lib build. The new define_insn
> and define_peephole2 are all gated by TARGET_ZCMP, which
> is false when building libgcc.
Operand predicates are checked for validity before the insn condition is 
checked.

Jeff

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

* Re: [PATCH 3/3] [V2] [RISC-V] support cm.mva01s cm.mvsa01 in zcmp
  2023-09-07 20:33     ` Palmer Dabbelt
  2023-09-08  2:06       ` Fei Gao
@ 2023-09-12  3:15       ` Jeff Law
  1 sibling, 0 replies; 14+ messages in thread
From: Jeff Law @ 2023-09-12  3:15 UTC (permalink / raw)
  To: Palmer Dabbelt, dimitar, Patrick O'Neill
  Cc: gcc-patches, Kito Cheng, lidie, jiawei



On 9/7/23 14:33, Palmer Dabbelt wrote:
> On Thu, 07 Sep 2023 13:16:36 PDT (-0700), dimitar@dinux.eu wrote:
>> Hi,
>>
>> This patch appears to have caused PR 111259.
> 
> Thanks.  Looks like wer'e not running our tests with RTL checking, 
> Patrick is going to try and see if we've got compute time left for some 
> builds -- even just having builds with checking would be a good one, we 
> get bit by these bugs from time to time.
> 
> I'm spinning up a --enable-checking=yes build.  Maybe we just need 
> something like
> 
>     diff --git a/gcc/config/riscv/predicates.md 
> b/gcc/config/riscv/predicates.md
>     index 53e7c1d03aa..aa4f02c67d5 100644
>     --- a/gcc/config/riscv/predicates.md
>     +++ b/gcc/config/riscv/predicates.md
>     @@ -172,11 +172,11 @@ (define_predicate "stack_pop_up_to_s11_operand"
>      ;; ZCMP predicates
>      (define_predicate "a0a1_reg_operand"
>     -  (and (match_operand 0 "register_operand")
>     +  (and (match_code "reg")
>             (match_test "IN_RANGE (REGNO (op), A0_REGNUM, A1_REGNUM)")))
>      (define_predicate "zcmp_mv_sreg_operand"
>     -  (and (match_operand 0 "register_operand")
>     +  (and (match_code "reg")
>             (match_test "TARGET_RVE ? IN_RANGE (REGNO (op), S0_REGNUM, 
> S1_REGNUM)
>                          : IN_RANGE (REGNO (op), S0_REGNUM, S1_REGNUM)
>                          || IN_RANGE (REGNO (op), S2_REGNUM, S7_REGNUM)")))
Presumably you got a SUBREG if that patch solves the problem.

Note that due to RTL checking's compile-time cost, I think it's a 
separate option to enable-checking.  It's probably not feasible to turn 
it on for anything but cross testing right now.

IIRC Jakub does RTL checking builds & regression testing just once a 
year in the spring due to its cost.  And I think on just one target 
(x86).  We could probably do something similar to weed out these kinds 
of problems.  Spin it in November and wait however long it takes :-)

jeff


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

* Re: [PATCH 1/3] [V6] [RISC-V] support cm.push cm.pop cm.popret in zcmp
  2023-08-29  8:37 ` [PATCH 1/3] [V6] [RISC-V] support cm.push cm.pop cm.popret in zcmp Fei Gao
@ 2023-10-27 20:31   ` Patrick O'Neill
  2023-10-28  2:32     ` Jeff Law
  2023-10-28  2:35     ` Jeff Law
  0 siblings, 2 replies; 14+ messages in thread
From: Patrick O'Neill @ 2023-10-27 20:31 UTC (permalink / raw)
  To: Fei Gao, gcc-patches; +Cc: kito.cheng, jiawei, Jeff Law

[-- Attachment #1: Type: text/plain, Size: 94959 bytes --]

Hi Fei,

A recent change to GCC [1] updated the  the registers in the cm.push and 
cm.pop insns for these testcases:

|FAIL: gcc.target/riscv/rv32i_zcmp.c -Os check-function-bodies test1 
FAIL: gcc.target/riscv/rv32i_zcmp.c -Os check-function-bodies 
test2_step1_0_size FAIL: gcc.target/riscv/rv32i_zcmp.c -Os 
check-function-bodies test3|

Debug log:

Executing on host: /github/patrick-postcommit-runner-1/_work/gcc-postcommit-ci/gcc-postcommit-ci/riscv-gnu-toolchain/build/build-gcc-linux-stage2/gcc/xgcc -B/github/patrick-postcommit-runner-1/_work/gcc-postcommit-ci/gcc-postcommit-ci/riscv-gnu-toolchain/build/build-gcc-linux-stage2/gcc/  /github/patrick-postcommit-runner-1/_work/gcc-postcommit-ci/gcc-postcommit-ci/riscv-gnu-toolchain/gcc/gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c  -march=rv64gcv -mabi=lp64d -mcmodel=medlow   -fdiagnostics-plain-output    -Os   -Os -march=rv32imaf_zca_zcmp -mabi=ilp32f -mcmodel=medlow -S   -o rv32i_zcmp.s    (timeout = 600)
spawn -ignore SIGHUP /github/patrick-postcommit-runner-1/_work/gcc-postcommit-ci/gcc-postcommit-ci/riscv-gnu-toolchain/build/build-gcc-linux-stage2/gcc/xgcc -B/github/patrick-postcommit-runner-1/_work/gcc-postcommit-ci/gcc-postcommit-ci/riscv-gnu-toolchain/build/build-gcc-linux-stage2/gcc/ /github/patrick-postcommit-runner-1/_work/gcc-postcommit-ci/gcc-postcommit-ci/riscv-gnu-toolchain/gcc/gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c -march=rv64gcv -mabi=lp64d -mcmodel=medlow -fdiagnostics-plain-output -Os -Os -march=rv32imaf_zca_zcmp -mabi=ilp32f -mcmodel=medlow -S -o rv32i_zcmp.s
PASS: gcc.target/riscv/rv32i_zcmp.c   -Os  (test for excess errors)
body: .*\tcm.push	{ra, s0-s4}, -80
.*\tcm.popret	{ra, s0-s4}, 80
.*
against: 	lui	a5,%hi(.LC0)
	li	t0,-16384
	cm.push	{ra, s0-s6}, -80
	addi	t0,t0,816
	fsw	fs0,44(sp)
	lw	s2,%lo(.LC0)(a5)
	lw	s3,%lo(.LC0+4)(a5)
	fmv.s.x	fs0,zero
	li	a5,4096
	add	sp,sp,t0
	addi	a5,a5,-784
	li	s1,4096
	li	s0,0
	addi	s5,sp,-784
	add	s4,sp,a5
	addi	s1,s1,-976
	call	my_getchar
	add	s6,s5,s0
	sb	a0,784(s6)
	call	my_getchar
	call	__floatsidf
	mv	a2,s2
	mv	a3,s3
	call	__muldf3
	call	__truncdfsf2
	slli	a5,s0,2
	add	a5,s4,a5
	fsw	fa0,-192(a5)
	addi	s0,s0,1
	lbu	a4,784(s6)
	fcvt.s.w	fa5,a4
	flw	fa4,-192(a5)
	fadd.s	fa5,fa5,fa4
	fadd.s	fs0,fs0,fa5
	bne	s0,s1,.L2
	li	t0,16384
	addi	t0,t0,-816
	add	sp,sp,t0
	fcvt.w.s a0,fs0,rtz
	flw	fs0,44(sp)
	cm.popret	{ra, s0-s6}, 80

FAIL: gcc.target/riscv/rv32i_zcmp.c   -Os   check-function-bodies test1

Would  it be OK if we made the regex accept any s[0-9] register (or 
would it be better if it was [1-9])?
Proposed change:

diff --git a/gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c b/gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c
index ea562b7a233..5f65a1c7c0b 100644
--- a/gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c
+++ b/gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c
@@ -26,9 +26,9 @@ f2 (void);
  /*
  **test1:
  **     ...
-**     cm.push {ra, s0-s4}, -80
+**     cm.push {ra, s0-s[0-9]}, -80
  **     ...
-**     cm.popret       {ra, s0-s4}, 80
+**     cm.popret       {ra, s0-s[0-9]}, 80
  **     ...
  */
  int
@@ -50,9 +50,9 @@ test1 ()
  /*
  **test2_step1_0_size:
  **     ...
-**     cm.push {ra, s0-s1}, -64
+**     cm.push {ra, s0-s[0-9]}, -64
  **     ...
-**     cm.popret       {ra, s0-s1}, 64
+**     cm.popret       {ra, s0-s[0-9]}, 64
  **     ...
  */
  int
@@ -70,9 +70,9 @@ test2_step1_0_size ()
  /*
  **test3:
  **     ...
-**     cm.push {ra, s0-s4}, -80
+**     cm.push {ra, s0-s[0-9]}, -80
  **     ...
-**     cm.popret       {ra, s0-s4}, 80
+**     cm.popret       {ra, s0-s[0-9]}, 80
  **     ...
  */
  float

Thanks,
Patrick

[1] It was one of these commits:
https://github.com/gcc-mirror/gcc/compare/a4ca8691333344cecc595d1af8b21e51f588e2f2...4d49685d671e4e604b2b873ada65aaac89348794

On 8/29/23 01:37, Fei Gao wrote:
> Zcmp can share the same logic as save-restore in stack allocation: pre-allocation
> by cm.push, step 1 and step 2.
>
> Pre-allocation not only saves callee saved GPRs, but also saves callee saved FPRs and
> local variables if any.
>
> Please be noted cm.push pushes ra, s0-s11 in reverse order than what save-restore does.
> So adaption has been done in .cfi directives in my patch.
>
> gcc/ChangeLog:
>
>          * config/riscv/iterators.md
>          slot0_offset: slot 0 offset in stack GPRs area in bytes
>          slot1_offset: slot 1 offset in stack GPRs area in bytes
>          slot2_offset: likewise
>          slot3_offset: likewise
>          slot4_offset: likewise
>          slot5_offset: likewise
>          slot6_offset: likewise
>          slot7_offset: likewise
>          slot8_offset: likewise
>          slot9_offset: likewise
>          slot10_offset: likewise
>          slot11_offset: likewise
>          slot12_offset: likewise
>          * config/riscv/predicates.md
>          (stack_push_up_to_ra_operand): predicates of stack adjust pushing ra
>          (stack_push_up_to_s0_operand): predicates of stack adjust pushing ra, s0
>          (stack_push_up_to_s1_operand): likewise
>          (stack_push_up_to_s2_operand): likewise
>          (stack_push_up_to_s3_operand): likewise
>          (stack_push_up_to_s4_operand): likewise
>          (stack_push_up_to_s5_operand): likewise
>          (stack_push_up_to_s6_operand): likewise
>          (stack_push_up_to_s7_operand): likewise
>          (stack_push_up_to_s8_operand): likewise
>          (stack_push_up_to_s9_operand): likewise
>          (stack_push_up_to_s11_operand): likewise
>          (stack_pop_up_to_ra_operand): predicates of stack adjust poping ra
>          (stack_pop_up_to_s0_operand): predicates of stack adjust poping ra, s0
>          (stack_pop_up_to_s1_operand): likewise
>          (stack_pop_up_to_s2_operand): likewise
>          (stack_pop_up_to_s3_operand): likewise
>          (stack_pop_up_to_s4_operand): likewise
>          (stack_pop_up_to_s5_operand): likewise
>          (stack_pop_up_to_s6_operand): likewise
>          (stack_pop_up_to_s7_operand): likewise
>          (stack_pop_up_to_s8_operand): likewise
>          (stack_pop_up_to_s9_operand): likewise
>          (stack_pop_up_to_s11_operand): likewise
>          * config/riscv/riscv-protos.h
>          (riscv_zcmp_valid_stack_adj_bytes_p):declaration
>          * config/riscv/riscv.cc (struct riscv_frame_info): comment change
>          (riscv_avoid_multi_push): helper function of riscv_use_multi_push
>          (riscv_use_multi_push): true if multi push is used
>          (riscv_multi_push_sregs_count): num of sregs in multi-push
>          (riscv_multi_push_regs_count): num of regs in multi-push
>          (riscv_16bytes_align): align to 16 bytes
>          (riscv_stack_align): moved to a better place
>          (riscv_save_libcall_count): no functional change
>          (riscv_compute_frame_info): add zcmp frame info
>          (riscv_for_each_saved_reg): save or restore fprs in specified slot for zcmp
>          (riscv_adjust_multi_push_cfi_prologue): adjust cfi for cm.push
>          (riscv_gen_multi_push_pop_insn): gen function for multi push and pop
>          (get_multi_push_fpr_mask): get mask for the fprs pushed by cm.push
>          (riscv_expand_prologue): allocate stack by cm.push
>          (riscv_adjust_multi_pop_cfi_epilogue): adjust cfi for cm.pop[ret]
>          (riscv_expand_epilogue): allocate stack by cm.pop[ret]
>          (zcmp_base_adj): calculate stack adjustment base size
>          (zcmp_additional_adj): calculate stack adjustment additional size
>          (riscv_zcmp_valid_stack_adj_bytes_p): check if stack adjustment valid
>          * config/riscv/riscv.h (RETURN_ADDR_MASK): mask of ra
>          (S0_MASK): likewise
>          (S1_MASK): likewise
>          (S2_MASK): likewise
>          (S3_MASK): likewise
>          (S4_MASK): likewise
>          (S5_MASK): likewise
>          (S6_MASK): likewise
>          (S7_MASK): likewise
>          (S8_MASK): likewise
>          (S9_MASK): likewise
>          (S10_MASK): likewise
>          (S11_MASK): likewise
>          (MULTI_PUSH_GPR_MASK): GPR_MASK that cm.push can cover at most
>          (ZCMP_MAX_SPIMM): max spimm value
>          (ZCMP_SP_INC_STEP): zcmp sp increment step
>          (ZCMP_INVALID_S0S10_SREGS_COUNTS): num of s0-s10
>          (ZCMP_S0S11_SREGS_COUNTS): num of s0-s11
>          (ZCMP_MAX_GRP_SLOTS): max slots of pushing and poping in zcmp
>          (CALLEE_SAVED_FREG_NUMBER): get x of fsx(fs0 ~ fs11)
>          * config/riscv/riscv.md: include zc.md
>          * config/riscv/zc.md: New file. machine description for zcmp
>
> gcc/testsuite/ChangeLog:
>
>          * gcc.target/riscv/rv32e_zcmp.c: New test.
>          * gcc.target/riscv/rv32i_zcmp.c: New test.
>          * gcc.target/riscv/zcmp_push_fpr.c: New test.
>          * gcc.target/riscv/zcmp_stack_alignment.c: New test.
> ---
>   gcc/config/riscv/iterators.md                 |   15 +
>   gcc/config/riscv/predicates.md                |   96 ++
>   gcc/config/riscv/riscv-protos.h               |    2 +
>   gcc/config/riscv/riscv.cc                     |  435 ++++++-
>   gcc/config/riscv/riscv.h                      |   25 +
>   gcc/config/riscv/riscv.md                     |    2 +
>   gcc/config/riscv/zc.md                        | 1042 +++++++++++++++++
>   gcc/testsuite/gcc.target/riscv/rv32e_zcmp.c   |  256 ++++
>   gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c   |  256 ++++
>   .../gcc.target/riscv/zcmp_push_fpr.c          |   34 +
>   .../gcc.target/riscv/zcmp_stack_alignment.c   |   24 +
>   11 files changed, 2136 insertions(+), 51 deletions(-)
>   create mode 100644 gcc/config/riscv/zc.md
>   create mode 100644 gcc/testsuite/gcc.target/riscv/rv32e_zcmp.c
>   create mode 100644 gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c
>   create mode 100644 gcc/testsuite/gcc.target/riscv/zcmp_push_fpr.c
>   create mode 100644 gcc/testsuite/gcc.target/riscv/zcmp_stack_alignment.c
>
> diff --git a/gcc/config/riscv/iterators.md b/gcc/config/riscv/iterators.md
> index a4070de1510..ecf033f2fa7 100644
> --- a/gcc/config/riscv/iterators.md
> +++ b/gcc/config/riscv/iterators.md
> @@ -125,6 +125,21 @@
>   (define_mode_attr shiftm1 [(SI "const_si_mask_operand") (DI "const_di_mask_operand")])
>   (define_mode_attr shiftm1p [(SI "DsS") (DI "DsD")])
>   
> +; zcmp mode attribute
> +(define_mode_attr slot0_offset  [(SI "-4")  (DI "-8")])
> +(define_mode_attr slot1_offset  [(SI "-8")  (DI "-16")])
> +(define_mode_attr slot2_offset  [(SI "-12") (DI "-24")])
> +(define_mode_attr slot3_offset  [(SI "-16") (DI "-32")])
> +(define_mode_attr slot4_offset  [(SI "-20") (DI "-40")])
> +(define_mode_attr slot5_offset  [(SI "-24") (DI "-48")])
> +(define_mode_attr slot6_offset  [(SI "-28") (DI "-56")])
> +(define_mode_attr slot7_offset  [(SI "-32") (DI "-64")])
> +(define_mode_attr slot8_offset  [(SI "-36") (DI "-72")])
> +(define_mode_attr slot9_offset  [(SI "-40") (DI "-80")])
> +(define_mode_attr slot10_offset [(SI "-44") (DI "-88")])
> +(define_mode_attr slot11_offset [(SI "-48") (DI "-96")])
> +(define_mode_attr slot12_offset [(SI "-52") (DI "-104")])
> +
>   ;; -------------------------------------------------------------------
>   ;; Code Iterators
>   ;; -------------------------------------------------------------------
> diff --git a/gcc/config/riscv/predicates.md b/gcc/config/riscv/predicates.md
> index 618ad607047..3ef09996a85 100644
> --- a/gcc/config/riscv/predicates.md
> +++ b/gcc/config/riscv/predicates.md
> @@ -69,6 +69,102 @@
>     (ior (match_operand 0 "const_0_operand")
>          (match_operand 0 "register_operand")))
>   
> +(define_predicate "stack_push_up_to_ra_operand"
> +  (and (match_code "const_int")
> +       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 1)")))
> +
> +(define_predicate "stack_push_up_to_s0_operand"
> +  (and (match_code "const_int")
> +       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 2)")))
> +
> +(define_predicate "stack_push_up_to_s1_operand"
> +  (and (match_code "const_int")
> +       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 3)")))
> +
> +(define_predicate "stack_push_up_to_s2_operand"
> +  (and (match_code "const_int")
> +       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 4)")))
> +
> +(define_predicate "stack_push_up_to_s3_operand"
> +  (and (match_code "const_int")
> +       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 5)")))
> +
> +(define_predicate "stack_push_up_to_s4_operand"
> +  (and (match_code "const_int")
> +       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 6)")))
> +
> +(define_predicate "stack_push_up_to_s5_operand"
> +  (and (match_code "const_int")
> +       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 7)")))
> +
> +(define_predicate "stack_push_up_to_s6_operand"
> +  (and (match_code "const_int")
> +       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 8)")))
> +
> +(define_predicate "stack_push_up_to_s7_operand"
> +  (and (match_code "const_int")
> +       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 9)")))
> +
> +(define_predicate "stack_push_up_to_s8_operand"
> +  (and (match_code "const_int")
> +       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 10)")))
> +
> +(define_predicate "stack_push_up_to_s9_operand"
> +  (and (match_code "const_int")
> +       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 11)")))
> +
> +(define_predicate "stack_push_up_to_s11_operand"
> +  (and (match_code "const_int")
> +       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op) * -1, 13)")))
> +
> +(define_predicate "stack_pop_up_to_ra_operand"
> +  (and (match_code "const_int")
> +       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 1)")))
> +
> +(define_predicate "stack_pop_up_to_s0_operand"
> +  (and (match_code "const_int")
> +       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 2)")))
> +
> +(define_predicate "stack_pop_up_to_s1_operand"
> +  (and (match_code "const_int")
> +       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 3)")))
> +
> +(define_predicate "stack_pop_up_to_s2_operand"
> +  (and (match_code "const_int")
> +       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 4)")))
> +
> +(define_predicate "stack_pop_up_to_s3_operand"
> +  (and (match_code "const_int")
> +       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 5)")))
> +
> +(define_predicate "stack_pop_up_to_s4_operand"
> +  (and (match_code "const_int")
> +       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 6)")))
> +
> +(define_predicate "stack_pop_up_to_s5_operand"
> +  (and (match_code "const_int")
> +       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 7)")))
> +
> +(define_predicate "stack_pop_up_to_s6_operand"
> +  (and (match_code "const_int")
> +       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 8)")))
> +
> +(define_predicate "stack_pop_up_to_s7_operand"
> +  (and (match_code "const_int")
> +       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 9)")))
> +
> +(define_predicate "stack_pop_up_to_s8_operand"
> +  (and (match_code "const_int")
> +       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 10)")))
> +
> +(define_predicate "stack_pop_up_to_s9_operand"
> +  (and (match_code "const_int")
> +       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 11)")))
> +
> +(define_predicate "stack_pop_up_to_s11_operand"
> +  (and (match_code "const_int")
> +       (match_test "riscv_zcmp_valid_stack_adj_bytes_p (INTVAL (op), 13)")))
> +
>   ;; Only use branch-on-bit sequences when the mask is not an ANDI immediate.
>   (define_predicate "branch_on_bit_operand"
>     (and (match_code "const_int")
> diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
> index 0e0470280f8..04885bbebd2 100644
> --- a/gcc/config/riscv/riscv-protos.h
> +++ b/gcc/config/riscv/riscv-protos.h
> @@ -102,6 +102,8 @@ extern bool riscv_split_64bit_move_p (rtx, rtx);
>   extern void riscv_split_doubleword_move (rtx, rtx);
>   extern const char *riscv_output_move (rtx, rtx);
>   extern const char *riscv_output_return ();
> +extern bool
> +riscv_zcmp_valid_stack_adj_bytes_p (HOST_WIDE_INT, int);
>   
>   #ifdef RTX_CODE
>   extern void riscv_expand_int_scc (rtx, enum rtx_code, rtx, rtx, bool *invert_ptr = 0);
> diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
> index 1d6e278ea90..ed4d28b2eb0 100644
> --- a/gcc/config/riscv/riscv.cc
> +++ b/gcc/config/riscv/riscv.cc
> @@ -112,6 +112,14 @@ struct GTY(())  riscv_frame_info {
>     /* How much the GPR save/restore routines adjust sp (or 0 if unused).  */
>     unsigned save_libcall_adjustment;
>   
> +  /* the minimum number of bytes, in multiples of 16-byte address increments,
> +     required to cover the registers in a multi push & pop.  */
> +  unsigned multi_push_adj_base;
> +
> +  /* the number of additional 16-byte address increments allocated for the stack
> +     frame in a multi push & pop.  */
> +  unsigned multi_push_adj_addi;
> +
>     /* Offsets of fixed-point and floating-point save areas from frame bottom */
>     poly_int64 gp_sp_offset;
>     poly_int64 fp_sp_offset;
> @@ -409,6 +417,16 @@ static const struct riscv_tune_info riscv_tune_info_table[] = {
>      function.  */
>   static bool riscv_save_frame_pointer;
>   
> +typedef enum
> +{
> +  PUSH_IDX = 0,
> +  POP_IDX,
> +  POPRET_IDX,
> +  ZCMP_OP_NUM
> +} riscv_zcmp_op_t;
> +
> +typedef insn_code (*code_for_push_pop_t) (machine_mode);
> +
>   void riscv_frame_info::reset(void)
>   {
>     total_size = 0;
> @@ -5539,6 +5557,34 @@ riscv_save_reg_p (unsigned int regno)
>     return false;
>   }
>   
> +/* Return TRUE if Zcmp push and pop insns should be
> +   avoided. FALSE otherwise.
> +   Only use multi push & pop if all GPRs masked can be covered,
> +   and stack access is SP based,
> +   and GPRs are at top of the stack frame,
> +   and no conflicts in stack allocation with other features  */
> +static bool
> +riscv_avoid_multi_push (const struct riscv_frame_info *frame)
> +{
> +  if (!TARGET_ZCMP || crtl->calls_eh_return || frame_pointer_needed
> +      || cfun->machine->interrupt_handler_p || cfun->machine->varargs_size != 0
> +      || crtl->args.pretend_args_size != 0 || flag_shrink_wrap_separate
> +      || (frame->mask & ~MULTI_PUSH_GPR_MASK))
> +    return true;
> +
> +  return false;
> +}
> +
> +/* Determine whether to use multi push insn.  */
> +static bool
> +riscv_use_multi_push (const struct riscv_frame_info *frame)
> +{
> +  if (riscv_avoid_multi_push (frame))
> +    return false;
> +
> +  return (frame->multi_push_adj_base != 0);
> +}
> +
>   /* Return TRUE if a libcall to save/restore GPRs should be
>      avoided.  FALSE otherwise.  */
>   static bool
> @@ -5576,6 +5622,50 @@ riscv_save_libcall_count (unsigned mask)
>     abort ();
>   }
>   
> +/* calculate number of s regs in multi push and pop.
> +   Note that {s0-s10} is not valid in Zcmp, use {s0-s11} instead.  */
> +static unsigned
> +riscv_multi_push_sregs_count (unsigned mask)
> +{
> +  unsigned num = riscv_save_libcall_count (mask);
> +  return (num == ZCMP_INVALID_S0S10_SREGS_COUNTS) ? ZCMP_S0S11_SREGS_COUNTS
> +						  : num;
> +}
> +
> +/* calculate number of regs(ra, s0-sx) in multi push and pop.  */
> +static unsigned
> +riscv_multi_push_regs_count (unsigned mask)
> +{
> +  /* 1 is for ra  */
> +  return riscv_multi_push_sregs_count (mask) + 1;
> +}
> +
> +/* Handle 16 bytes align for poly_int.  */
> +static poly_int64
> +riscv_16bytes_align (poly_int64 value)
> +{
> +  return aligned_upper_bound (value, 16);
> +}
> +
> +static HOST_WIDE_INT
> +riscv_16bytes_align (HOST_WIDE_INT value)
> +{
> +  return ROUND_UP (value, 16);
> +}
> +
> +/* Handle stack align for poly_int.  */
> +static poly_int64
> +riscv_stack_align (poly_int64 value)
> +{
> +  return aligned_upper_bound (value, PREFERRED_STACK_BOUNDARY / 8);
> +}
> +
> +static HOST_WIDE_INT
> +riscv_stack_align (HOST_WIDE_INT value)
> +{
> +  return RISCV_STACK_ALIGN (value);
> +}
> +
>   /* Populate the current function's riscv_frame_info structure.
>   
>      RISC-V stack frames grown downward.  High addresses are at the top.
> @@ -5601,7 +5691,7 @@ riscv_save_libcall_count (unsigned mask)
>   	|  GPR save area                |       + UNITS_PER_WORD
>   	|                               |
>   	+-------------------------------+ <-- stack_pointer_rtx + fp_sp_offset
> -	|                               |       + UNITS_PER_HWVALUE
> +	|                               |       + UNITS_PER_FP_REG
>   	|  FPR save area                |
>   	|                               |
>   	+-------------------------------+ <-- frame_pointer_rtx (virtual)
> @@ -5620,19 +5710,6 @@ riscv_save_libcall_count (unsigned mask)
>   
>   static HOST_WIDE_INT riscv_first_stack_step (struct riscv_frame_info *frame, poly_int64 remaining_size);
>   
> -/* Handle stack align for poly_int.  */
> -static poly_int64
> -riscv_stack_align (poly_int64 value)
> -{
> -  return aligned_upper_bound (value, PREFERRED_STACK_BOUNDARY / 8);
> -}
> -
> -static HOST_WIDE_INT
> -riscv_stack_align (HOST_WIDE_INT value)
> -{
> -  return RISCV_STACK_ALIGN (value);
> -}
> -
>   static void
>   riscv_compute_frame_info (void)
>   {
> @@ -5683,8 +5760,9 @@ riscv_compute_frame_info (void)
>     if (frame->mask)
>       {
>         x_save_size = riscv_stack_align (num_x_saved * UNITS_PER_WORD);
> -      unsigned num_save_restore = 1 + riscv_save_libcall_count (frame->mask);
>   
> +      /* 1 is for ra  */
> +      unsigned num_save_restore = 1 + riscv_save_libcall_count (frame->mask);
>         /* Only use save/restore routines if they don't alter the stack size.  */
>         if (riscv_stack_align (num_save_restore * UNITS_PER_WORD) == x_save_size
>             && !riscv_avoid_save_libcall ())
> @@ -5696,6 +5774,14 @@ riscv_compute_frame_info (void)
>   
>   	  frame->save_libcall_adjustment = x_save_size;
>   	}
> +
> +      if (!riscv_avoid_multi_push (frame))
> +	{
> +	  /* num(ra, s0-sx)  */
> +	  unsigned num_multi_push = riscv_multi_push_regs_count (frame->mask);
> +	  x_save_size = riscv_stack_align (num_multi_push * UNITS_PER_WORD);
> +	  frame->multi_push_adj_base = riscv_16bytes_align (x_save_size);
> +	}
>       }
>   
>     /* In an interrupt function, we need extra space for the initial saves of CSRs.  */
> @@ -5721,7 +5807,15 @@ riscv_compute_frame_info (void)
>     frame->fp_sp_offset = offset - UNITS_PER_FP_REG;
>     /* Next are the callee-saved GPRs. */
>     if (frame->mask)
> -    offset += x_save_size;
> +    {
> +      offset += x_save_size;
> +      /* align to 16 bytes and add paddings to GPR part to honor
> +	 both stack alignment and zcmp pus/pop size alignment. */
> +      if (riscv_use_multi_push (frame)
> +	  && known_lt (offset, frame->multi_push_adj_base
> +				 + ZCMP_SP_INC_STEP * ZCMP_MAX_SPIMM))
> +	offset = riscv_16bytes_align (offset);
> +    }
>     frame->gp_sp_offset = offset - UNITS_PER_WORD;
>     /* The hard frame pointer points above the callee-saved GPRs. */
>     frame->hard_frame_pointer_offset = offset;
> @@ -5900,8 +5994,8 @@ static void
>   riscv_for_each_saved_reg (poly_int64 sp_offset, riscv_save_restore_fn fn,
>   			  bool epilogue, bool maybe_eh_return)
>   {
> -  HOST_WIDE_INT offset;
> -  unsigned int regno;
> +  HOST_WIDE_INT offset, first_fp_offset;
> +  unsigned int regno, num_masked_fp = 0;
>     unsigned int start = GP_REG_FIRST;
>     unsigned int limit = GP_REG_LAST;
>   
> @@ -5987,16 +6081,20 @@ riscv_for_each_saved_reg (poly_int64 sp_offset, riscv_save_restore_fn fn,
>   
>     /* This loop must iterate over the same space as its companion in
>        riscv_compute_frame_info.  */
> -  offset = (cfun->machine->frame.fp_sp_offset - sp_offset).to_constant ();
> +  first_fp_offset
> +    = (cfun->machine->frame.fp_sp_offset - sp_offset).to_constant ();
>     for (unsigned int regno = FP_REG_FIRST; regno <= FP_REG_LAST; regno++)
>       if (BITSET_P (cfun->machine->frame.fmask, regno - FP_REG_FIRST))
>         {
>   	bool handle_reg = !cfun->machine->reg_is_wrapped_separately[regno];
>   	machine_mode mode = TARGET_DOUBLE_FLOAT ? DFmode : SFmode;
> -
> +	unsigned int slot = (riscv_use_multi_push (&cfun->machine->frame))
> +			      ? CALLEE_SAVED_FREG_NUMBER (regno)
> +			      : num_masked_fp;
> +	offset = first_fp_offset - slot * GET_MODE_SIZE (mode).to_constant ();
>   	if (handle_reg)
>   	  riscv_save_restore_reg (mode, regno, offset, fn);
> -	offset -= GET_MODE_SIZE (mode).to_constant ();
> +	num_masked_fp++;
>         }
>   }
>   
> @@ -6093,6 +6191,41 @@ riscv_adjust_libcall_cfi_prologue ()
>     return dwarf;
>   }
>   
> +static rtx
> +riscv_adjust_multi_push_cfi_prologue (int saved_size)
> +{
> +  rtx dwarf = NULL_RTX;
> +  rtx adjust_sp_rtx, reg, mem, insn;
> +  unsigned int mask = cfun->machine->frame.mask;
> +  int offset;
> +  int saved_cnt = 0;
> +
> +  if (mask & S10_MASK)
> +    mask |= S11_MASK;
> +
> +  for (int regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--)
> +    if (BITSET_P (mask & MULTI_PUSH_GPR_MASK, regno - GP_REG_FIRST))
> +      {
> +	/* The save order is s11-s0, ra
> +	   from high to low addr.  */
> +	offset = saved_size - UNITS_PER_WORD * (++saved_cnt);
> +
> +	reg = gen_rtx_REG (Pmode, regno);
> +	mem = gen_frame_mem (Pmode,
> +			     plus_constant (Pmode, stack_pointer_rtx, offset));
> +
> +	insn = gen_rtx_SET (mem, reg);
> +	dwarf = alloc_reg_note (REG_CFA_OFFSET, insn, dwarf);
> +      }
> +
> +  /* Debug info for adjust sp.  */
> +  adjust_sp_rtx
> +    = gen_rtx_SET (stack_pointer_rtx,
> +		   plus_constant (Pmode, stack_pointer_rtx, -saved_size));
> +  dwarf = alloc_reg_note (REG_CFA_ADJUST_CFA, adjust_sp_rtx, dwarf);
> +  return dwarf;
> +}
> +
>   static void
>   riscv_emit_stack_tie (void)
>   {
> @@ -6102,6 +6235,56 @@ riscv_emit_stack_tie (void)
>       emit_insn (gen_stack_tiedi (stack_pointer_rtx, hard_frame_pointer_rtx));
>   }
>   
> +/*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_push_up_to_s0, code_for_gpr_multi_pop_up_to_s0,
> +      code_for_gpr_multi_popret_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_push_up_to_s2, code_for_gpr_multi_pop_up_to_s2,
> +      code_for_gpr_multi_popret_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_push_up_to_s4, code_for_gpr_multi_pop_up_to_s4,
> +      code_for_gpr_multi_popret_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_push_up_to_s6, code_for_gpr_multi_pop_up_to_s6,
> +      code_for_gpr_multi_popret_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_push_up_to_s8, code_for_gpr_multi_pop_up_to_s8,
> +      code_for_gpr_multi_popret_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_push_up_to_s11, code_for_gpr_multi_pop_up_to_s11,
> +      code_for_gpr_multi_popret_up_to_s11}};
> +
> +static rtx
> +riscv_gen_multi_push_pop_insn (riscv_zcmp_op_t op, HOST_WIDE_INT adj_size,
> +			       unsigned int regs_num)
> +{
> +  gcc_assert (op < ZCMP_OP_NUM);
> +  gcc_assert (regs_num <= ZCMP_MAX_GRP_SLOTS
> +	      && regs_num != ZCMP_INVALID_S0S10_SREGS_COUNTS + 1); /* 1 for ra*/
> +  rtx stack_adj = GEN_INT (adj_size);
> +  return GEN_FCN (code_for_push_pop[regs_num - 1][op](Pmode)) (stack_adj);
> +}
> +
> +static unsigned
> +get_multi_push_fpr_mask (unsigned max_fprs_push)
> +{
> +  unsigned mask_fprs_push = 0, num_f_pushed = 0;
> +  for (unsigned regno = FP_REG_FIRST;
> +       regno <= FP_REG_LAST && num_f_pushed < max_fprs_push; regno++)
> +    if (riscv_save_reg_p (regno))
> +      mask_fprs_push |= 1 << (regno - FP_REG_FIRST), num_f_pushed++;
> +  return mask_fprs_push;
> +}
> +
>   /* Expand the "prologue" pattern.  */
>   
>   void
> @@ -6110,7 +6293,9 @@ riscv_expand_prologue (void)
>     struct riscv_frame_info *frame = &cfun->machine->frame;
>     poly_int64 remaining_size = frame->total_size;
>     unsigned mask = frame->mask;
> -  rtx insn;
> +  unsigned fmask = frame->fmask;
> +  int spimm, multi_push_additional, stack_adj;
> +  rtx insn, dwarf = NULL_RTX;
>   
>     if (flag_stack_usage_info)
>       current_function_static_stack_size = constant_lower_bound (remaining_size);
> @@ -6118,8 +6303,46 @@ riscv_expand_prologue (void)
>     if (cfun->machine->naked_p)
>       return;
>   
> +  /* prefer muti-push to save-restore libcall.  */
> +  if (riscv_use_multi_push (frame))
> +    {
> +      remaining_size -= frame->multi_push_adj_base;
> +      if (known_gt (remaining_size, 2 * ZCMP_SP_INC_STEP))
> +	spimm = 3;
> +      else if (known_gt (remaining_size, ZCMP_SP_INC_STEP))
> +	spimm = 2;
> +      else if (known_gt (remaining_size, 0))
> +	spimm = 1;
> +      else
> +	spimm = 0;
> +      multi_push_additional = spimm * ZCMP_SP_INC_STEP;
> +      frame->multi_push_adj_addi = multi_push_additional;
> +      remaining_size -= multi_push_additional;
> +
> +      /* emit multi push insn & dwarf along with it.  */
> +      stack_adj = frame->multi_push_adj_base + multi_push_additional;
> +      insn = emit_insn (riscv_gen_multi_push_pop_insn (
> +	PUSH_IDX, -stack_adj, riscv_multi_push_regs_count (frame->mask)));
> +      dwarf = riscv_adjust_multi_push_cfi_prologue (stack_adj);
> +      RTX_FRAME_RELATED_P (insn) = 1;
> +      REG_NOTES (insn) = dwarf;
> +
> +      /* Temporarily fib that we need not save GPRs.  */
> +      frame->mask = 0;
> +
> +      /* push FPRs into the addtional reserved space by cm.push. */
> +      if (fmask)
> +	{
> +	  unsigned mask_fprs_push
> +	    = get_multi_push_fpr_mask (multi_push_additional / UNITS_PER_WORD);
> +	  frame->fmask &= mask_fprs_push;
> +	  riscv_for_each_saved_reg (remaining_size, riscv_save_reg, false,
> +				    false);
> +	  frame->fmask = fmask & ~mask_fprs_push; /* mask for the rest FPRs.  */
> +	}
> +    }
>     /* When optimizing for size, call a subroutine to save the registers.  */
> -  if (riscv_use_save_libcall (frame))
> +  else if (riscv_use_save_libcall (frame))
>       {
>         rtx dwarf = NULL_RTX;
>         dwarf = riscv_adjust_libcall_cfi_prologue ();
> @@ -6135,17 +6358,20 @@ riscv_expand_prologue (void)
>     /* Save the registers.  */
>     if ((frame->mask | frame->fmask) != 0)
>       {
> -      HOST_WIDE_INT step1 = riscv_first_stack_step (frame, remaining_size);
> -
> -      insn = gen_add3_insn (stack_pointer_rtx,
> -			    stack_pointer_rtx,
> -			    GEN_INT (-step1));
> -      RTX_FRAME_RELATED_P (emit_insn (insn)) = 1;
> -      remaining_size -= step1;
> +      if (known_gt (remaining_size, frame->frame_pointer_offset))
> +	{
> +	  HOST_WIDE_INT step1 = riscv_first_stack_step (frame, remaining_size);
> +	  remaining_size -= step1;
> +	  insn = gen_add3_insn (stack_pointer_rtx, stack_pointer_rtx,
> +				GEN_INT (-step1));
> +	  RTX_FRAME_RELATED_P (emit_insn (insn)) = 1;
> +	}
>         riscv_for_each_saved_reg (remaining_size, riscv_save_reg, false, false);
>       }
>   
> -  frame->mask = mask; /* Undo the above fib.  */
> +  /* Undo the above fib.  */
> +  frame->mask = mask;
> +  frame->fmask = fmask;
>   
>     /* Set up the frame pointer, if we're using one.  */
>     if (frame_pointer_needed)
> @@ -6198,6 +6424,32 @@ riscv_expand_prologue (void)
>       }
>   }
>   
> +static rtx
> +riscv_adjust_multi_pop_cfi_epilogue (int saved_size)
> +{
> +  rtx dwarf = NULL_RTX;
> +  rtx adjust_sp_rtx, reg;
> +  unsigned int mask = cfun->machine->frame.mask;
> +
> +  if (mask & S10_MASK)
> +    mask |= S11_MASK;
> +
> +  /* Debug info for adjust sp.  */
> +  adjust_sp_rtx
> +    = gen_rtx_SET (stack_pointer_rtx,
> +		   plus_constant (Pmode, stack_pointer_rtx, saved_size));
> +  dwarf = alloc_reg_note (REG_CFA_ADJUST_CFA, adjust_sp_rtx, dwarf);
> +
> +  for (int regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
> +    if (BITSET_P (mask, regno - GP_REG_FIRST))
> +      {
> +	reg = gen_rtx_REG (Pmode, regno);
> +	dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf);
> +      }
> +
> +  return dwarf;
> +}
> +
>   static rtx
>   riscv_adjust_libcall_cfi_epilogue ()
>   {
> @@ -6236,11 +6488,24 @@ riscv_expand_epilogue (int style)
>        Start off by assuming that no registers need to be restored.  */
>     struct riscv_frame_info *frame = &cfun->machine->frame;
>     unsigned mask = frame->mask;
> +  unsigned fmask = frame->fmask;
> +  unsigned mask_fprs_push = 0;
>     HOST_WIDE_INT step2 = 0;
> -  bool use_restore_libcall = ((style == NORMAL_RETURN)
> -			      && riscv_use_save_libcall (frame));
> -  unsigned libcall_size = (use_restore_libcall
> -			   ? frame->save_libcall_adjustment : 0);
> +  bool use_multi_pop_normal
> +    = ((style == NORMAL_RETURN) && riscv_use_multi_push (frame));
> +  bool use_multi_pop_sibcall
> +    = ((style == SIBCALL_RETURN) && riscv_use_multi_push (frame));
> +  bool use_multi_pop = use_multi_pop_normal || use_multi_pop_sibcall;
> +
> +  bool use_restore_libcall
> +    = !use_multi_pop
> +      && ((style == NORMAL_RETURN) && riscv_use_save_libcall (frame));
> +  unsigned libcall_size = use_restore_libcall && !use_multi_pop
> +			    ? frame->save_libcall_adjustment
> +			    : 0;
> +  unsigned multipop_size
> +    = use_multi_pop ? frame->multi_push_adj_base + frame->multi_push_adj_addi
> +		    : 0;
>     rtx ra = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM);
>     rtx insn;
>   
> @@ -6311,18 +6576,26 @@ riscv_expand_epilogue (int style)
>         REG_NOTES (insn) = dwarf;
>       }
>   
> -  if (use_restore_libcall)
> -    frame->mask = 0; /* Temporarily fib for GPRs.  */
> +  if (use_restore_libcall || use_multi_pop)
> +    frame->mask = 0; /* Temporarily fib that we need not restore GPRs.  */
>   
>     /* If we need to restore registers, deallocate as much stack as
>        possible in the second step without going out of range.  */
> -  if ((frame->mask | frame->fmask) != 0)
> +  if (use_multi_pop)
> +    {
> +      if (frame->fmask
> +	  && known_gt (frame->total_size - multipop_size,
> +		       frame->frame_pointer_offset))
> +	step2
> +	  = riscv_first_stack_step (frame, frame->total_size - multipop_size);
> +    }
> +  else if ((frame->mask | frame->fmask) != 0)
>       step2 = riscv_first_stack_step (frame, frame->total_size - libcall_size);
>   
> -  if (use_restore_libcall)
> +  if (use_restore_libcall || use_multi_pop)
>       frame->mask = mask; /* Undo the above fib.  */
>   
> -  poly_int64 step1 = frame->total_size - step2 - libcall_size;
> +  poly_int64 step1 = frame->total_size - step2 - libcall_size - multipop_size;
>   
>     /* Set TARGET to BASE + STEP1.  */
>     if (known_gt (step1, 0))
> @@ -6356,8 +6629,9 @@ riscv_expand_epilogue (int style)
>   					   stack_pointer_rtx,
>   					   adjust));
>   	  rtx dwarf = NULL_RTX;
> -	  rtx cfa_adjust_rtx = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
> -					     GEN_INT (step2 + libcall_size));
> +	  rtx cfa_adjust_rtx
> +	    = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
> +			    GEN_INT (step2 + libcall_size + multipop_size));
>   
>   	  dwarf = alloc_reg_note (REG_CFA_DEF_CFA, cfa_adjust_rtx, dwarf);
>   	  RTX_FRAME_RELATED_P (insn) = 1;
> @@ -6372,16 +6646,26 @@ riscv_expand_epilogue (int style)
>         epilogue_cfa_sp_offset = step2;
>       }
>   
> -  if (use_restore_libcall)
> -    frame->mask = 0; /* Temporarily fib that we need not save GPRs.  */
> +  if (use_multi_pop)
> +    {
> +      frame->mask = 0; /* Temporarily fib that we need not restore GPRs.  */
> +      if (fmask)
> +	{
> +	  mask_fprs_push = get_multi_push_fpr_mask (frame->multi_push_adj_addi
> +						    / UNITS_PER_WORD);
> +	  frame->fmask &= ~mask_fprs_push; /* FPRs not saved by cm.push  */
> +	}
> +    }
> +  else if (use_restore_libcall)
> +    frame->mask = 0; /* Temporarily fib that we need not restore GPRs.  */
>   
>     /* Restore the registers.  */
> -  riscv_for_each_saved_reg (frame->total_size - step2 - libcall_size,
> -			    riscv_restore_reg,
> -			    true, style == EXCEPTION_RETURN);
> +  riscv_for_each_saved_reg (frame->total_size - step2 - libcall_size
> +			      - multipop_size,
> +			    riscv_restore_reg, true, style == EXCEPTION_RETURN);
>   
>     if (use_restore_libcall)
> -      frame->mask = mask; /* Undo the above fib.  */
> +    frame->mask = mask; /* Undo the above fib.  */
>   
>     if (need_barrier_p)
>       riscv_emit_stack_tie ();
> @@ -6393,15 +6677,43 @@ riscv_expand_epilogue (int style)
>   				       GEN_INT (step2)));
>   
>         rtx dwarf = NULL_RTX;
> -      rtx cfa_adjust_rtx = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
> -					 GEN_INT (libcall_size));
> +      rtx cfa_adjust_rtx
> +	= gen_rtx_PLUS (Pmode, stack_pointer_rtx,
> +			GEN_INT (libcall_size + multipop_size));
>         dwarf = alloc_reg_note (REG_CFA_DEF_CFA, cfa_adjust_rtx, dwarf);
>         RTX_FRAME_RELATED_P (insn) = 1;
>   
>         REG_NOTES (insn) = dwarf;
>       }
>   
> -  if (use_restore_libcall)
> +  if (use_multi_pop)
> +    {
> +      /* restore FPRs pushed by cm.push. */
> +      frame->fmask = fmask & mask_fprs_push;
> +      if (frame->fmask)
> +	riscv_for_each_saved_reg (frame->total_size - libcall_size
> +				    - multipop_size,
> +				  riscv_restore_reg, true,
> +				  style == EXCEPTION_RETURN);
> +      /* 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;
> +      if (use_multi_pop_normal)
> +	return;
> +    }
> +  else if (use_restore_libcall)
>       {
>         rtx dwarf = riscv_adjust_libcall_cfi_epilogue ();
>         insn = emit_insn (gen_gpr_restore (GEN_INT (riscv_save_libcall_count (mask))));
> @@ -7744,6 +8056,27 @@ riscv_gen_gpr_save_insn (struct riscv_frame_info *frame)
>     return gen_rtx_PARALLEL (VOIDmode, vec);
>   }
>   
> +static HOST_WIDE_INT
> +zcmp_base_adj (int regs_num)
> +{
> +  return riscv_16bytes_align ((regs_num) *GET_MODE_SIZE (word_mode));
> +}
> +
> +static HOST_WIDE_INT
> +zcmp_additional_adj (HOST_WIDE_INT total, int regs_num)
> +{
> +  return total - zcmp_base_adj (regs_num);
> +}
> +
> +bool
> +riscv_zcmp_valid_stack_adj_bytes_p (HOST_WIDE_INT total, int regs_num)
> +{
> +  HOST_WIDE_INT additioanl_bytes = zcmp_additional_adj (total, regs_num);
> +  return additioanl_bytes == 0 || additioanl_bytes == 1 * ZCMP_SP_INC_STEP
> +	 || additioanl_bytes == 2 * ZCMP_SP_INC_STEP
> +	 || additioanl_bytes == ZCMP_MAX_SPIMM * ZCMP_SP_INC_STEP;
> +}
> +
>   /* Return true if it's valid gpr_save pattern.  */
>   
>   bool
> diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
> index e18a0081297..42b6eb784d4 100644
> --- a/gcc/config/riscv/riscv.h
> +++ b/gcc/config/riscv/riscv.h
> @@ -420,6 +420,29 @@ ASM_MISA_SPEC
>   #define RISCV_CALL_ADDRESS_TEMP(MODE) \
>     gen_rtx_REG (MODE, RISCV_CALL_ADDRESS_TEMP_REGNUM)
>   
> +#define RETURN_ADDR_MASK (1 << RETURN_ADDR_REGNUM)
> +#define S0_MASK (1 << S0_REGNUM)
> +#define S1_MASK (1 << S1_REGNUM)
> +#define S2_MASK (1 << S2_REGNUM)
> +#define S3_MASK (1 << S3_REGNUM)
> +#define S4_MASK (1 << S4_REGNUM)
> +#define S5_MASK (1 << S5_REGNUM)
> +#define S6_MASK (1 << S6_REGNUM)
> +#define S7_MASK (1 << S7_REGNUM)
> +#define S8_MASK (1 << S8_REGNUM)
> +#define S9_MASK (1 << S9_REGNUM)
> +#define S10_MASK (1 << S10_REGNUM)
> +#define S11_MASK (1 << S11_REGNUM)
> +
> +#define MULTI_PUSH_GPR_MASK                                                    \
> +  (RETURN_ADDR_MASK | S0_MASK | S1_MASK | S2_MASK | S3_MASK | S4_MASK          \
> +   | S5_MASK | S6_MASK | S7_MASK | S8_MASK | S9_MASK | S10_MASK | S11_MASK)
> +#define ZCMP_MAX_SPIMM 3
> +#define ZCMP_SP_INC_STEP 16
> +#define ZCMP_INVALID_S0S10_SREGS_COUNTS 11
> +#define ZCMP_S0S11_SREGS_COUNTS 12
> +#define ZCMP_MAX_GRP_SLOTS 13
> +
>   #define MCOUNT_NAME "_mcount"
>   
>   #define NO_PROFILE_COUNTERS 1
> @@ -655,6 +678,8 @@ enum reg_class
>     ((REGNO) >= 8 && (REGNO) <= 9 ? (REGNO) - 8 :		\
>      (REGNO) >= 18 && (REGNO) <= 27 ? (REGNO) - 16 : -1)
>   
> +#define CALLEE_SAVED_FREG_NUMBER(REGNO) CALLEE_SAVED_REG_NUMBER (REGNO - 32)
> +
>   #define LIBCALL_VALUE(MODE) \
>     riscv_function_value (NULL_TREE, NULL_TREE, MODE)
>   
> diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
> index 47d14d99903..f489646cec3 100644
> --- a/gcc/config/riscv/riscv.md
> +++ b/gcc/config/riscv/riscv.md
> @@ -124,6 +124,7 @@
>   
>   (define_constants
>     [(RETURN_ADDR_REGNUM		1)
> +   (SP_REGNUM 			2)
>      (GP_REGNUM 			3)
>      (TP_REGNUM			4)
>      (T0_REGNUM			5)
> @@ -3431,3 +3432,4 @@
>   (include "thead.md")
>   (include "vector.md")
>   (include "zicond.md")
> +(include "zc.md")
> diff --git a/gcc/config/riscv/zc.md b/gcc/config/riscv/zc.md
> new file mode 100644
> index 00000000000..5c1bf031b8d
> --- /dev/null
> +++ b/gcc/config/riscv/zc.md
> @@ -0,0 +1,1042 @@
> +;; Machine description for RISC-V Zc extention.
> +;; Copyright (C) 2023 Free Software Foundation, Inc.
> +;; Contributed by Fei Gao (gaofei@eswincomputing.com).
> +
> +;; This file is part of GCC.
> +
> +;; GCC is free software; you can redistribute it and/or modify
> +;; it under the terms of the GNU General Public License as published by
> +;; the Free Software Foundation; either version 3, or (at your option)
> +;; any later version.
> +
> +;; GCC is distributed in the hope that it will be useful,
> +;; but WITHOUT ANY WARRANTY; without even the implied warranty of
> +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +;; GNU General Public License for more details.
> +
> +;; You should have received a copy of the GNU General Public License
> +;; along with GCC; see the file COPYING3.  If not see
> +;;<http://www.gnu.org/licenses/>.
> +
> +(define_insn "@gpr_multi_pop_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>))))]
> +  "TARGET_ZCMP"
> +  "cm.pop	{ra}, %0"
> +)
> +
> +(define_insn "@gpr_multi_pop_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>))))]
> +  "TARGET_ZCMP"
> +  "cm.pop	{ra, s0}, %0"
> +)
> +
> +(define_insn "@gpr_multi_pop_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>))))]
> +  "TARGET_ZCMP"
> +  "cm.pop	{ra, s0-s1}, %0"
> +)
> +
> +(define_insn "@gpr_multi_pop_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>))))]
> +  "TARGET_ZCMP"
> +  "cm.pop	{ra, s0-s2}, %0"
> +)
> +
> +(define_insn "@gpr_multi_pop_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>))))]
> +  "TARGET_ZCMP"
> +  "cm.pop	{ra, s0-s3}, %0"
> +)
> +
> +(define_insn "@gpr_multi_pop_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>))))]
> +  "TARGET_ZCMP"
> +  "cm.pop	{ra, s0-s4}, %0"
> +)
> +
> +(define_insn "@gpr_multi_pop_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>))))]
> +  "TARGET_ZCMP"
> +  "cm.pop	{ra, s0-s5}, %0"
> +)
> +
> +(define_insn "@gpr_multi_pop_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>))))]
> +  "TARGET_ZCMP"
> +  "cm.pop	{ra, s0-s6}, %0"
> +)
> +
> +(define_insn "@gpr_multi_pop_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>))))]
> +  "TARGET_ZCMP"
> +  "cm.pop	{ra, s0-s7}, %0"
> +)
> +
> +(define_insn "@gpr_multi_pop_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>))))]
> +  "TARGET_ZCMP"
> +  "cm.pop	{ra, s0-s8}, %0"
> +)
> +
> +(define_insn "@gpr_multi_pop_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>))))]
> +  "TARGET_ZCMP"
> +  "cm.pop	{ra, s0-s9}, %0"
> +)
> +
> +(define_insn "@gpr_multi_pop_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>))))]
> +  "TARGET_ZCMP"
> +  "cm.pop	{ra, s0-s11}, %0"
> +)
> +
> +(define_insn "@gpr_multi_popret_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>))))
> +   (return)
> +   (use (reg:SI RETURN_ADDR_REGNUM))]
> +  "TARGET_ZCMP"
> +  "cm.popret	{ra}, %0"
> +)
> +
> +(define_insn "@gpr_multi_popret_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>))))
> +   (return)
> +   (use (reg:SI RETURN_ADDR_REGNUM))]
> +  "TARGET_ZCMP"
> +  "cm.popret	{ra, s0}, %0"
> +)
> +
> +(define_insn "@gpr_multi_popret_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>))))
> +   (return)
> +   (use (reg:SI RETURN_ADDR_REGNUM))]
> +  "TARGET_ZCMP"
> +  "cm.popret	{ra, s0-s1}, %0"
> +)
> +
> +(define_insn "@gpr_multi_popret_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>))))
> +   (return)
> +   (use (reg:SI RETURN_ADDR_REGNUM))]
> +  "TARGET_ZCMP"
> +  "cm.popret	{ra, s0-s2}, %0"
> +)
> +
> +(define_insn "@gpr_multi_popret_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>))))
> +   (return)
> +   (use (reg:SI RETURN_ADDR_REGNUM))]
> +  "TARGET_ZCMP"
> +  "cm.popret	{ra, s0-s3}, %0"
> +)
> +
> +(define_insn "@gpr_multi_popret_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>))))
> +   (return)
> +   (use (reg:SI RETURN_ADDR_REGNUM))]
> +  "TARGET_ZCMP"
> +  "cm.popret	{ra, s0-s4}, %0"
> +)
> +
> +(define_insn "@gpr_multi_popret_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>))))
> +   (return)
> +   (use (reg:SI RETURN_ADDR_REGNUM))]
> +  "TARGET_ZCMP"
> +  "cm.popret	{ra, s0-s5}, %0"
> +)
> +
> +(define_insn "@gpr_multi_popret_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>))))
> +   (return)
> +   (use (reg:SI RETURN_ADDR_REGNUM))]
> +  "TARGET_ZCMP"
> +  "cm.popret	{ra, s0-s6}, %0"
> +)
> +
> +(define_insn "@gpr_multi_popret_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>))))
> +   (return)
> +   (use (reg:SI RETURN_ADDR_REGNUM))]
> +  "TARGET_ZCMP"
> +  "cm.popret	{ra, s0-s7}, %0"
> +)
> +
> +(define_insn "@gpr_multi_popret_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>))))
> +   (return)
> +   (use (reg:SI RETURN_ADDR_REGNUM))]
> +  "TARGET_ZCMP"
> +  "cm.popret	{ra, s0-s8}, %0"
> +)
> +
> +(define_insn "@gpr_multi_popret_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>))))
> +   (return)
> +   (use (reg:SI RETURN_ADDR_REGNUM))]
> +  "TARGET_ZCMP"
> +  "cm.popret	{ra, s0-s9}, %0"
> +)
> +
> +(define_insn "@gpr_multi_popret_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>))))
> +   (return)
> +   (use (reg:SI RETURN_ADDR_REGNUM))]
> +  "TARGET_ZCMP"
> +  "cm.popret	{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>)))
> +        (reg:X RETURN_ADDR_REGNUM))
> +   (set (reg:X SP_REGNUM)
> +        (plus:X (reg:X SP_REGNUM)
> +                 (match_operand 0 "stack_push_up_to_ra_operand" "I")))]
> +  "TARGET_ZCMP"
> +  "cm.push	{ra}, %0"
> +)
> +
> +(define_insn "@gpr_multi_push_up_to_s0_<mode>"
> +  [(set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot0_offset>)))
> +        (reg:X S0_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot1_offset>)))
> +        (reg:X RETURN_ADDR_REGNUM))
> +   (set (reg:X SP_REGNUM)
> +        (plus:X (reg:X SP_REGNUM)
> +                 (match_operand 0 "stack_push_up_to_s0_operand" "I")))]
> +  "TARGET_ZCMP"
> +  "cm.push	{ra, s0}, %0"
> +)
> +
> +(define_insn "@gpr_multi_push_up_to_s1_<mode>"
> +  [(set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot0_offset>)))
> +        (reg:X S1_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot1_offset>)))
> +        (reg:X S0_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot2_offset>)))
> +        (reg:X RETURN_ADDR_REGNUM))
> +   (set (reg:X SP_REGNUM)
> +        (plus:X (reg:X SP_REGNUM)
> +                 (match_operand 0 "stack_push_up_to_s1_operand" "I")))]
> +  "TARGET_ZCMP"
> +  "cm.push	{ra, s0-s1}, %0"
> +)
> +
> +(define_insn "@gpr_multi_push_up_to_s2_<mode>"
> +  [(set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot0_offset>)))
> +        (reg:X S2_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot1_offset>)))
> +        (reg:X S1_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot2_offset>)))
> +        (reg:X S0_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot3_offset>)))
> +        (reg:X RETURN_ADDR_REGNUM))
> +   (set (reg:X SP_REGNUM)
> +        (plus:X (reg:X SP_REGNUM)
> +                 (match_operand 0 "stack_push_up_to_s2_operand" "I")))]
> +  "TARGET_ZCMP"
> +  "cm.push	{ra, s0-s2}, %0"
> +)
> +
> +(define_insn "@gpr_multi_push_up_to_s3_<mode>"
> +  [(set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot0_offset>)))
> +        (reg:X S3_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot1_offset>)))
> +        (reg:X S2_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot2_offset>)))
> +        (reg:X S1_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot3_offset>)))
> +        (reg:X S0_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot4_offset>)))
> +        (reg:X RETURN_ADDR_REGNUM))
> +   (set (reg:X SP_REGNUM)
> +        (plus:X (reg:X SP_REGNUM)
> +                 (match_operand 0 "stack_push_up_to_s3_operand" "I")))]
> +  "TARGET_ZCMP"
> +  "cm.push	{ra, s0-s3}, %0"
> +)
> +
> +(define_insn "@gpr_multi_push_up_to_s4_<mode>"
> +  [(set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot0_offset>)))
> +        (reg:X S4_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot1_offset>)))
> +        (reg:X S3_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot2_offset>)))
> +        (reg:X S2_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot3_offset>)))
> +        (reg:X S1_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot4_offset>)))
> +        (reg:X S0_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot5_offset>)))
> +        (reg:X RETURN_ADDR_REGNUM))
> +   (set (reg:X SP_REGNUM)
> +        (plus:X (reg:X SP_REGNUM)
> +                 (match_operand 0 "stack_push_up_to_s4_operand" "I")))]
> +  "TARGET_ZCMP"
> +  "cm.push	{ra, s0-s4}, %0"
> +)
> +
> +(define_insn "@gpr_multi_push_up_to_s5_<mode>"
> +  [(set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot0_offset>)))
> +        (reg:X S5_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot1_offset>)))
> +        (reg:X S4_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot2_offset>)))
> +        (reg:X S3_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot3_offset>)))
> +        (reg:X S2_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot4_offset>)))
> +        (reg:X S1_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot5_offset>)))
> +        (reg:X S0_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot6_offset>)))
> +        (reg:X RETURN_ADDR_REGNUM))
> +   (set (reg:X SP_REGNUM)
> +        (plus:X (reg:X SP_REGNUM)
> +                 (match_operand 0 "stack_push_up_to_s5_operand" "I")))]
> +  "TARGET_ZCMP"
> +  "cm.push	{ra, s0-s5}, %0"
> +)
> +
> +(define_insn "@gpr_multi_push_up_to_s6_<mode>"
> +  [(set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot0_offset>)))
> +        (reg:X S6_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot1_offset>)))
> +        (reg:X S5_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot2_offset>)))
> +        (reg:X S4_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot3_offset>)))
> +        (reg:X S3_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot4_offset>)))
> +        (reg:X S2_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot5_offset>)))
> +        (reg:X S1_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot6_offset>)))
> +        (reg:X S0_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot7_offset>)))
> +        (reg:X RETURN_ADDR_REGNUM))
> +   (set (reg:X SP_REGNUM)
> +        (plus:X (reg:X SP_REGNUM)
> +                 (match_operand 0 "stack_push_up_to_s6_operand" "I")))]
> +  "TARGET_ZCMP"
> +  "cm.push	{ra, s0-s6}, %0"
> +)
> +
> +(define_insn "@gpr_multi_push_up_to_s7_<mode>"
> +  [(set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot0_offset>)))
> +        (reg:X S7_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot1_offset>)))
> +        (reg:X S6_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot2_offset>)))
> +        (reg:X S5_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot3_offset>)))
> +        (reg:X S4_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot4_offset>)))
> +        (reg:X S3_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot5_offset>)))
> +        (reg:X S2_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot6_offset>)))
> +        (reg:X S1_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot7_offset>)))
> +        (reg:X S0_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                      (const_int <slot8_offset>)))
> +        (reg:X RETURN_ADDR_REGNUM))
> +   (set (reg:X SP_REGNUM)
> +        (plus:X (reg:X SP_REGNUM)
> +                 (match_operand 0 "stack_push_up_to_s7_operand" "I")))]
> +  "TARGET_ZCMP"
> +  "cm.push	{ra, s0-s7}, %0"
> +)
> +
> +(define_insn "@gpr_multi_push_up_to_s8_<mode>"
> +  [(set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot0_offset>)))
> +        (reg:X S8_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot1_offset>)))
> +        (reg:X S7_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot2_offset>)))
> +        (reg:X S6_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot3_offset>)))
> +        (reg:X S5_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot4_offset>)))
> +        (reg:X S4_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot5_offset>)))
> +        (reg:X S3_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot6_offset>)))
> +        (reg:X S2_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot7_offset>)))
> +        (reg:X S1_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot8_offset>)))
> +        (reg:X S0_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot9_offset>)))
> +        (reg:X RETURN_ADDR_REGNUM))
> +   (set (reg:X SP_REGNUM)
> +        (plus:X (reg:X SP_REGNUM)
> +                 (match_operand 0 "stack_push_up_to_s8_operand" "I")))]
> +  "TARGET_ZCMP"
> +  "cm.push	{ra, s0-s8}, %0"
> +)
> +
> +(define_insn "@gpr_multi_push_up_to_s9_<mode>"
> +  [(set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot0_offset>)))
> +        (reg:X S9_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot1_offset>)))
> +        (reg:X S8_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot2_offset>)))
> +        (reg:X S7_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot3_offset>)))
> +        (reg:X S6_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot4_offset>)))
> +        (reg:X S5_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot5_offset>)))
> +        (reg:X S4_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot6_offset>)))
> +        (reg:X S3_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot7_offset>)))
> +        (reg:X S2_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot8_offset>)))
> +        (reg:X S1_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot9_offset>)))
> +        (reg:X S0_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot10_offset>)))
> +        (reg:X RETURN_ADDR_REGNUM))
> +   (set (reg:X SP_REGNUM)
> +        (plus:X (reg:X SP_REGNUM)
> +                 (match_operand 0 "stack_push_up_to_s9_operand" "I")))]
> +  "TARGET_ZCMP"
> +  "cm.push	{ra, s0-s9}, %0"
> +)
> +
> +(define_insn "@gpr_multi_push_up_to_s11_<mode>"
> +  [(set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot0_offset>)))
> +        (reg:X S11_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot1_offset>)))
> +        (reg:X S10_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot2_offset>)))
> +        (reg:X S9_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot3_offset>)))
> +        (reg:X S8_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot4_offset>)))
> +        (reg:X S7_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot5_offset>)))
> +        (reg:X S6_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot6_offset>)))
> +        (reg:X S5_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot7_offset>)))
> +        (reg:X S4_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot8_offset>)))
> +        (reg:X S3_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot9_offset>)))
> +        (reg:X S2_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot10_offset>)))
> +        (reg:X S1_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot11_offset>)))
> +        (reg:X S0_REGNUM))
> +   (set (mem:X (plus:X (reg:X SP_REGNUM)
> +                       (const_int <slot12_offset>)))
> +        (reg:X RETURN_ADDR_REGNUM))
> +   (set (reg:X SP_REGNUM)
> +        (plus:X (reg:X SP_REGNUM)
> +                 (match_operand 0 "stack_push_up_to_s11_operand" "I")))]
> +  "TARGET_ZCMP"
> +  "cm.push	{ra, s0-s11}, %0"
> +)
> diff --git a/gcc/testsuite/gcc.target/riscv/rv32e_zcmp.c b/gcc/testsuite/gcc.target/riscv/rv32e_zcmp.c
> new file mode 100644
> index 00000000000..57c83249741
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/rv32e_zcmp.c
> @@ -0,0 +1,256 @@
> +/* { dg-do compile } */
> +/* { dg-options " -Os -march=rv32e_zca_zcmp -mabi=ilp32e -mcmodel=medlow -fno-shrink-wrap-separate" } */
> +/* { dg-skip-if "" { *-*-* } {"-O0" "-O1" "-O2" "-Og" "-O3" "-Oz" "-flto"} } */
> +/* { dg-final { check-function-bodies "**" "" } } */
> +
> +char
> +my_getchar ();
> +float
> +getf ();
> +int __attribute__ ((noinline))
> +incoming_stack_args (int arg0, int arg1, int arg2, int arg3, int arg4, int arg5,
> +		     int arg6, int arg7, int arg8);
> +int
> +getint ();
> +void
> +PrintInts (int n, ...);						 // varargs
> +void __attribute__ ((noinline)) PrintIntsNoVaStart (int n, ...); // varargs
> +void
> +PrintInts2 (int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int n,
> +	    ...);
> +extern void
> +f1 (void);
> +extern void
> +f2 (void);
> +
> +/*
> +**test1:
> +**	...
> +**	cm.push	{ra, s0-s1}, -64
> +**	...
> +**	cm.popret	{ra, s0-s1}, 64
> +**	...
> +*/
> +int
> +test1 ()
> +{
> +  char volatile array[3120];
> +  float volatile farray[3120];
> +
> +  float sum = 0;
> +  for (int i = 0; i < 3120; i++)
> +    {
> +      array[i] = my_getchar ();
> +      farray[i] = my_getchar () * 1.2;
> +      sum += array[i] + farray[i];
> +    }
> +  return sum;
> +}
> +
> +/*
> +**test2_step1_0_size:
> +**	...
> +**	cm.push	{ra, s0}, -64
> +**	...
> +**	cm.popret	{ra, s0}, 64
> +**	...
> +*/
> +int
> +test2_step1_0_size ()
> +{
> +  int volatile iarray[3120 + 1824 / 4 - 8];
> +
> +  for (int i = 0; i < 3120 + 1824 / 4 - 8; i++)
> +    {
> +      iarray[i] = my_getchar () * 2;
> +    }
> +  return iarray[0] + iarray[1];
> +}
> +
> +/*
> +**test3:
> +**	...
> +**	cm.push	{ra, s0-s1}, -64
> +**	...
> +**	cm.popret	{ra, s0-s1}, 64
> +**	...
> +*/
> +float
> +test3 ()
> +{
> +  char volatile array[3120];
> +  float volatile farray[3120];
> +
> +  float sum = 0, f1 = 0, f2 = 0, f3 = 0, f4 = 0, f5 = 0, f6 = 0, f7 = 0;
> +
> +  for (int i = 0; i < 3120; i++)
> +    {
> +      f1 = getf ();
> +      f2 = getf ();
> +      f3 = getf ();
> +      f4 = getf ();
> +      array[i] = my_getchar ();
> +      farray[i] = my_getchar () * 1.2;
> +      sum += array[i] + farray[i] + f1 + f2 + f3 + f4;
> +    }
> +  return sum;
> +}
> +
> +/*
> +**outgoing_stack_args:
> +**	...
> +**	cm.push	{ra, s0}, -32
> +**	...
> +**	cm.popret	{ra, s0}, 32
> +**	...
> +*/
> +int
> +outgoing_stack_args ()
> +{
> +  int local = getint ();
> +  return local + incoming_stack_args (0, 1, 2, 3, 4, 5, 6, 7, 8);
> +}
> +
> +/*
> +**callPrintInts:
> +**	...
> +**	cm.push	{ra}, -32
> +**	...
> +**	cm.popret	{ra}, 32
> +**	...
> +*/
> +float
> +callPrintInts ()
> +{
> +  volatile float f = getf (); // f in local
> +  PrintInts (9, 1, 2, 3, 4, 5, 6, 7, 8, 9);
> +  return f;
> +}
> +
> +/*
> +**callPrint:
> +**	...
> +**	cm.push	{ra}, -32
> +**	...
> +**	cm.popret	{ra}, 32
> +**	...
> +*/
> +float
> +callPrint ()
> +{
> +  volatile float f = getf (); // f in local
> +  PrintIntsNoVaStart (0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
> +  return f;
> +}
> +
> +/*
> +**callPrint_S:
> +**	...
> +**	cm.push	{ra, s0}, -32
> +**	...
> +**	cm.popret	{ra, s0}, 32
> +**	...
> +*/
> +float
> +callPrint_S ()
> +{
> +  float f = getf ();
> +  PrintIntsNoVaStart (0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
> +  return f;
> +}
> +
> +/*
> +**callPrint_2:
> +**	...
> +**	cm.push	{ra, s0}, -32
> +**	...
> +**	cm.popret	{ra, s0}, 32
> +**	...
> +*/
> +float
> +callPrint_2 ()
> +{
> +  float f = getf ();
> +  PrintInts2 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
> +  return f;
> +}
> +
> +/*
> +**test_step1_0bytes_save_restore:
> +**	...
> +**	cm.push	{ra}, -16
> +**	...
> +**	cm.popret	{ra}, 16
> +**	...
> +*/
> +int
> +test_step1_0bytes_save_restore ()
> +{
> +  int a = 9;
> +  int b = my_getchar ();
> +  return a + b;
> +}
> +
> +/*
> +**test_s0:
> +**	...
> +**	cm.push	{ra, s0}, -16
> +**	...
> +**	cm.popret	{ra, s0}, 16
> +**	...
> +*/
> +int
> +test_s0 ()
> +{
> +  int a = my_getchar ();
> +  int b = my_getchar ();
> +  return a + b;
> +}
> +
> +/*
> +**test_s1:
> +**	...
> +**	cm.push	{ra, s0-s1}, -16
> +**	...
> +**	cm.popret	{ra, s0-s1}, 16
> +**	...
> +*/
> +int
> +test_s1 ()
> +{
> +  int s0 = my_getchar ();
> +  int s1 = my_getchar ();
> +  int b = my_getchar ();
> +  return s1 + s0 + b;
> +}
> +
> +/*
> +**test_f0:
> +**	...
> +**	cm.push	{ra, s0-s1}, -16
> +**	...
> +**	cm.popret	{ra, s0-s1}, 16
> +**	...
> +*/
> +int
> +test_f0 ()
> +{
> +  int s0 = my_getchar ();
> +  float f0 = getf ();
> +  int b = my_getchar ();
> +  return f0 + s0 + b;
> +}
> +
> +/*
> +**foo:
> +**	cm.push	{ra}, -16
> +**	call	f1
> +**	cm.pop	{ra}, 16
> +**	tail	f2
> +*/
> +void
> +foo (void)
> +{
> +  f1 ();
> +  f2 ();
> +}
> diff --git a/gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c b/gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c
> new file mode 100644
> index 00000000000..f24e0a8bab9
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c
> @@ -0,0 +1,256 @@
> +/* { dg-do compile } */
> +/* { dg-options " -Os -march=rv32imaf_zca_zcmp -mabi=ilp32f -mcmodel=medlow -fno-shrink-wrap-separate" }*/
> +/* { dg-skip-if "" { *-*-* } {"-O0" "-O1" "-O2" "-Og" "-O3" "-Oz" "-flto"} } */
> +/* { dg-final { check-function-bodies "**" "" } } */
> +
> +char
> +my_getchar ();
> +float
> +getf ();
> +int __attribute__ ((noinline))
> +incoming_stack_args (int arg0, int arg1, int arg2, int arg3, int arg4, int arg5,
> +		     int arg6, int arg7, int arg8);
> +int
> +getint ();
> +void
> +PrintInts (int n, ...);						 // varargs
> +void __attribute__ ((noinline)) PrintIntsNoVaStart (int n, ...); // varargs
> +void
> +PrintInts2 (int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int n,
> +	    ...);
> +extern void
> +f1 (void);
> +extern void
> +f2 (void);
> +
> +/*
> +**test1:
> +**	...
> +**	cm.push	{ra, s0-s4}, -80
> +**	...
> +**	cm.popret	{ra, s0-s4}, 80
> +**	...
> +*/
> +int
> +test1 ()
> +{
> +  char volatile array[3120];
> +  float volatile farray[3120];
> +
> +  float sum = 0;
> +  for (int i = 0; i < 3120; i++)
> +    {
> +      array[i] = my_getchar ();
> +      farray[i] = my_getchar () * 1.2;
> +      sum += array[i] + farray[i];
> +    }
> +  return sum;
> +}
> +
> +/*
> +**test2_step1_0_size:
> +**	...
> +**	cm.push	{ra, s0-s1}, -64
> +**	...
> +**	cm.popret	{ra, s0-s1}, 64
> +**	...
> +*/
> +int
> +test2_step1_0_size ()
> +{
> +  int volatile iarray[3120 + 1824 / 4 - 8];
> +
> +  for (int i = 0; i < 3120 + 1824 / 4 - 8; i++)
> +    {
> +      iarray[i] = my_getchar () * 2;
> +    }
> +  return iarray[0] + iarray[1];
> +}
> +
> +/*
> +**test3:
> +**	...
> +**	cm.push	{ra, s0-s4}, -80
> +**	...
> +**	cm.popret	{ra, s0-s4}, 80
> +**	...
> +*/
> +float
> +test3 ()
> +{
> +  char volatile array[3120];
> +  float volatile farray[3120];
> +
> +  float sum = 0, f1 = 0, f2 = 0, f3 = 0, f4 = 0, f5 = 0, f6 = 0, f7 = 0;
> +
> +  for (int i = 0; i < 3120; i++)
> +    {
> +      f1 = getf ();
> +      f2 = getf ();
> +      f3 = getf ();
> +      f4 = getf ();
> +      array[i] = my_getchar ();
> +      farray[i] = my_getchar () * 1.2;
> +      sum += array[i] + farray[i] + f1 + f2 + f3 + f4;
> +    }
> +  return sum;
> +}
> +
> +/*
> +**outgoing_stack_args:
> +**	...
> +**	cm.push	{ra, s0}, -32
> +**	...
> +**	cm.popret	{ra, s0}, 32
> +**	...
> +*/
> +int
> +outgoing_stack_args ()
> +{
> +  int local = getint ();
> +  return local + incoming_stack_args (0, 1, 2, 3, 4, 5, 6, 7, 8);
> +}
> +
> +/*
> +**callPrintInts:
> +**	...
> +**	cm.push	{ra}, -48
> +**	...
> +**	cm.popret	{ra}, 48
> +**	...
> +*/
> +float
> +callPrintInts ()
> +{
> +  volatile float f = getf (); // f in local
> +  PrintInts (9, 1, 2, 3, 4, 5, 6, 7, 8, 9);
> +  return f;
> +}
> +
> +/*
> +**callPrint:
> +**	...
> +**	cm.push	{ra}, -48
> +**	...
> +**	cm.popret	{ra}, 48
> +**	...
> +*/
> +float
> +callPrint ()
> +{
> +  volatile float f = getf (); // f in local
> +  PrintIntsNoVaStart (0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
> +  return f;
> +}
> +
> +/*
> +**callPrint_S:
> +**	...
> +**	cm.push	{ra}, -48
> +**	...
> +**	cm.popret	{ra}, 48
> +**	...
> +*/
> +float
> +callPrint_S ()
> +{
> +  float f = getf ();
> +  PrintIntsNoVaStart (0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
> +  return f;
> +}
> +
> +/*
> +**callPrint_2:
> +**	...
> +**	cm.push	{ra}, -48
> +**	...
> +**	cm.popret	{ra}, 48
> +**	...
> +*/
> +float
> +callPrint_2 ()
> +{
> +  float f = getf ();
> +  PrintInts2 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
> +  return f;
> +}
> +
> +/*
> +**test_step1_0bytes_save_restore:
> +**	...
> +**	cm.push	{ra}, -16
> +**	...
> +**	cm.popret	{ra}, 16
> +**	...
> +*/
> +int
> +test_step1_0bytes_save_restore ()
> +{
> +  int a = 9;
> +  int b = my_getchar ();
> +  return a + b;
> +}
> +
> +/*
> +**test_s0:
> +**	...
> +**	cm.push	{ra, s0}, -16
> +**	...
> +**	cm.popret	{ra, s0}, 16
> +**	...
> +*/
> +int
> +test_s0 ()
> +{
> +  int a = my_getchar ();
> +  int b = my_getchar ();
> +  return a + b;
> +}
> +
> +/*
> +**test_s1:
> +**	...
> +**	cm.push	{ra, s0-s1}, -16
> +**	...
> +**	cm.popret	{ra, s0-s1}, 16
> +**	...
> +*/
> +int
> +test_s1 ()
> +{
> +  int s0 = my_getchar ();
> +  int s1 = my_getchar ();
> +  int b = my_getchar ();
> +  return s1 + s0 + b;
> +}
> +
> +/*
> +**test_f0:
> +**	...
> +**	cm.push	{ra, s0}, -32
> +**	...
> +**	cm.popret	{ra, s0}, 32
> +**	...
> +*/
> +int
> +test_f0 ()
> +{
> +  int s0 = my_getchar ();
> +  float f0 = getf ();
> +  int b = my_getchar ();
> +  return f0 + s0 + b;
> +}
> +
> +/*
> +**foo:
> +**	cm.push	{ra}, -16
> +**	call	f1
> +**	cm.pop	{ra}, 16
> +**	tail	f2
> +*/
> +void
> +foo (void)
> +{
> +  f1 ();
> +  f2 ();
> +}
> diff --git a/gcc/testsuite/gcc.target/riscv/zcmp_push_fpr.c b/gcc/testsuite/gcc.target/riscv/zcmp_push_fpr.c
> new file mode 100644
> index 00000000000..530b35b53dd
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/zcmp_push_fpr.c
> @@ -0,0 +1,34 @@
> +/* { dg-do compile } */
> +/* { dg-options "-march=rv64imafd_zicsr_zifencei_zca_zcmp -mabi=lp64d -Os -fno-shrink-wrap-separate" } */
> +/* { dg-skip-if "" { *-*-* } {"-O0" "-O1" "-O2" "-Og" "-O3" "-Oz" "-flto"} } */
> +
> +typedef struct
> +{
> +  struct
> +  {
> +    struct
> +    {
> +      struct
> +      {
> +	long a;
> +      };
> +    } a[129];
> +  };
> +} b;
> +
> +struct c
> +{
> +  void *a[129];
> +};
> +
> +extern void
> +f (struct c, b *);
> +
> +struct c
> +d ()
> +{
> +  struct c a;
> +  __builtin_unwind_init ();
> +  b e;
> +  f (a, &e);
> +}
> diff --git a/gcc/testsuite/gcc.target/riscv/zcmp_stack_alignment.c b/gcc/testsuite/gcc.target/riscv/zcmp_stack_alignment.c
> new file mode 100644
> index 00000000000..2f2fa55baac
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/zcmp_stack_alignment.c
> @@ -0,0 +1,24 @@
> +/* { dg-do compile } */
> +/* { dg-options " -O0 -march=rv32e_zca_zcb_zcmp -mabi=ilp32e -mcmodel=medlow -fomit-frame-pointer -fno-shrink-wrap-separate" } */
> +/* { dg-skip-if "" { *-*-* } {"-O2" "-O1" "-Os" "-Og" "-O3" "-Oz" "-flto"} } */
> +/* { dg-final { check-function-bodies "**" "" } } */
> +
> +void
> +bar ();
> +
> +/*
> +**fool_rv32e:
> +**	cm.push	{ra}, -32
> +**	...
> +**	call	bar
> +**	...
> +**	lw	a[0-5],32\(sp\)
> +**	...
> +**	cm.popret	{ra}, 32
> +*/
> +int
> +fool_rv32e (int a0, int a1, int a2, int a3, int a4, int a5, int incoming0)
> +{
> +  bar ();
> +  return a0 + a1 + a2 + a3 + a4 + a5 + incoming0;
> +}

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

* Re: [PATCH 1/3] [V6] [RISC-V] support cm.push cm.pop cm.popret in zcmp
  2023-10-27 20:31   ` Patrick O'Neill
@ 2023-10-28  2:32     ` Jeff Law
  2023-10-28  2:35     ` Jeff Law
  1 sibling, 0 replies; 14+ messages in thread
From: Jeff Law @ 2023-10-28  2:32 UTC (permalink / raw)
  To: Patrick O'Neill, Fei Gao, gcc-patches; +Cc: kito.cheng, jiawei



On 10/27/23 14:31, Patrick O'Neill wrote:
> Hi Fei,
> 
> A recent change to GCC [1] updated the  the registers in the cm.push and 
> cm.pop insns for these testcases:
> 
> |FAIL: gcc.target/riscv/rv32i_zcmp.c -Os check-function-bodies test1 
> FAIL: gcc.target/riscv/rv32i_zcmp.c -Os check-function-bodies 
> test2_step1_0_size FAIL: gcc.target/riscv/rv32i_zcmp.c -Os 
> check-function-bodies test3|
> 
> Debug log:
> 
> Executing on host: /github/patrick-postcommit-runner-1/_work/gcc-postcommit-ci/gcc-postcommit-ci/riscv-gnu-toolchain/build/build-gcc-linux-stage2/gcc/xgcc -B/github/patrick-postcommit-runner-1/_work/gcc-postcommit-ci/gcc-postcommit-ci/riscv-gnu-toolchain/build/build-gcc-linux-stage2/gcc/  /github/patrick-postcommit-runner-1/_work/gcc-postcommit-ci/gcc-postcommit-ci/riscv-gnu-toolchain/gcc/gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c  -march=rv64gcv -mabi=lp64d -mcmodel=medlow   -fdiagnostics-plain-output    -Os   -Os -march=rv32imaf_zca_zcmp -mabi=ilp32f -mcmodel=medlow -S   -o rv32i_zcmp.s    (timeout = 600)
> spawn -ignore SIGHUP /github/patrick-postcommit-runner-1/_work/gcc-postcommit-ci/gcc-postcommit-ci/riscv-gnu-toolchain/build/build-gcc-linux-stage2/gcc/xgcc -B/github/patrick-postcommit-runner-1/_work/gcc-postcommit-ci/gcc-postcommit-ci/riscv-gnu-toolchain/build/build-gcc-linux-stage2/gcc/ /github/patrick-postcommit-runner-1/_work/gcc-postcommit-ci/gcc-postcommit-ci/riscv-gnu-toolchain/gcc/gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c -march=rv64gcv -mabi=lp64d -mcmodel=medlow -fdiagnostics-plain-output -Os -Os -march=rv32imaf_zca_zcmp -mabi=ilp32f -mcmodel=medlow -S -o rv32i_zcmp.s
> PASS: gcc.target/riscv/rv32i_zcmp.c   -Os  (test for excess errors)
> body: .*\tcm.push	{ra, s0-s4}, -80
> .*\tcm.popret	{ra, s0-s4}, 80
> .*
> against: 	lui	a5,%hi(.LC0)
> 	li	t0,-16384
> 	cm.push	{ra, s0-s6}, -80
> 	addi	t0,t0,816
> 	fsw	fs0,44(sp)
> 	lw	s2,%lo(.LC0)(a5)
> 	lw	s3,%lo(.LC0+4)(a5)
> 	fmv.s.x	fs0,zero
> 	li	a5,4096
> 	add	sp,sp,t0
> 	addi	a5,a5,-784
> 	li	s1,4096
> 	li	s0,0
> 	addi	s5,sp,-784
> 	add	s4,sp,a5
> 	addi	s1,s1,-976
> 	call	my_getchar
> 	add	s6,s5,s0
> 	sb	a0,784(s6)
> 	call	my_getchar
> 	call	__floatsidf
> 	mv	a2,s2
> 	mv	a3,s3
> 	call	__muldf3
> 	call	__truncdfsf2
> 	slli	a5,s0,2
> 	add	a5,s4,a5
> 	fsw	fa0,-192(a5)
> 	addi	s0,s0,1
> 	lbu	a4,784(s6)
> 	fcvt.s.w	fa5,a4
> 	flw	fa4,-192(a5)
> 	fadd.s	fa5,fa5,fa4
> 	fadd.s	fs0,fs0,fa5
> 	bne	s0,s1,.L2
> 	li	t0,16384
> 	addi	t0,t0,-816
> 	add	sp,sp,t0
> 	fcvt.w.s a0,fs0,rtz
> 	flw	fs0,44(sp)
> 	cm.popret	{ra, s0-s6}, 80
> 
> FAIL: gcc.target/riscv/rv32i_zcmp.c   -Os   check-function-bodies test1
> 
> Would  it be OK if we made the regex accept any s[0-9] register (or 
> would it be better if it was [1-9])?
> Proposed change:
I'd think your proposed change would be fine.


> 
> [1] It was one of these commits:
> https://github.com/gcc-mirror/gcc/compare/a4ca8691333344cecc595d1af8b21e51f588e2f2...4d49685d671e4e604b2b873ada65aaac89348794
Almost certainly the regsiter allocator change.

Jeff

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

* Re: [PATCH 1/3] [V6] [RISC-V] support cm.push cm.pop cm.popret in zcmp
  2023-10-27 20:31   ` Patrick O'Neill
  2023-10-28  2:32     ` Jeff Law
@ 2023-10-28  2:35     ` Jeff Law
  2023-10-30  7:46       ` Fei Gao
  1 sibling, 1 reply; 14+ messages in thread
From: Jeff Law @ 2023-10-28  2:35 UTC (permalink / raw)
  To: Patrick O'Neill, Fei Gao, gcc-patches; +Cc: kito.cheng, jiawei



On 10/27/23 14:31, Patrick O'Neill wrote:
> Hi Fei,
> 
> A recent change to GCC [1] updated the  the registers in the cm.push and 
> cm.pop insns for these testcases:
> 
> |FAIL: gcc.target/riscv/rv32i_zcmp.c -Os check-function-bodies test1 
> FAIL: gcc.target/riscv/rv32i_zcmp.c -Os check-function-bodies 
> test2_step1_0_size FAIL: gcc.target/riscv/rv32i_zcmp.c -Os 
> check-function-bodies test3|
[ ... ]
Actually [1-9] looks better upon further review.

jeff

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

* Re: Re: [PATCH 1/3] [V6] [RISC-V] support cm.push cm.pop cm.popret in zcmp
  2023-10-28  2:35     ` Jeff Law
@ 2023-10-30  7:46       ` Fei Gao
  0 siblings, 0 replies; 14+ messages in thread
From: Fei Gao @ 2023-10-30  7:46 UTC (permalink / raw)
  To: jeffreyalaw, Patrick O'Neill, gcc-patches; +Cc: Kito Cheng, jiawei



On 2023-10-28 10:35  Jeff Law <jeffreyalaw@gmail.com> wrote:
>
>
>
>On 10/27/23 14:31, Patrick O'Neill wrote:
>> Hi Fei,
>>
>> A recent change to GCC [1] updated the  the registers in the cm.push and
>> cm.pop insns for these testcases:
>>
>> |FAIL: gcc.target/riscv/rv32i_zcmp.c -Os check-function-bodies test1
>> FAIL: gcc.target/riscv/rv32i_zcmp.c -Os check-function-bodies
>> test2_step1_0_size FAIL: gcc.target/riscv/rv32i_zcmp.c -Os
>> check-function-bodies test3|
>[ ... ]
>Actually [1-9] looks better upon further review. 

hi Patrick

Thanks for adapting the TCs.
I follow Jeff's advice {ra, s0-s[1-9]} for case {ra, s0-sx}.

BR
Fei
>
>jeff

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

end of thread, other threads:[~2023-10-30  7:46 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-29  8:37 [PATCH 0/3] [RISC-V] support zcmp extension Fei Gao
2023-08-29  8:37 ` [PATCH 1/3] [V6] [RISC-V] support cm.push cm.pop cm.popret in zcmp Fei Gao
2023-10-27 20:31   ` Patrick O'Neill
2023-10-28  2:32     ` Jeff Law
2023-10-28  2:35     ` Jeff Law
2023-10-30  7:46       ` Fei Gao
2023-08-29  8:37 ` [PATCH 2/3] [V2] [RISC-V] support cm.popretz " Fei Gao
2023-08-29  8:37 ` [PATCH 3/3] [V2] [RISC-V] support cm.mva01s cm.mvsa01 " Fei Gao
2023-09-07 20:16   ` Dimitar Dimitrov
2023-09-07 20:33     ` Palmer Dabbelt
2023-09-08  2:06       ` Fei Gao
2023-09-08 15:23         ` Jeff Law
2023-09-12  3:15       ` Jeff Law
2023-08-30 10:03 ` [PATCH 0/3] [RISC-V] support zcmp extension Kito Cheng

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).