public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/vendors/riscv/heads/gcc-13-with-riscv-opts)] RISC-V: support cm.push cm.pop cm.popret in zcmp
@ 2023-09-11 13:33 Jeff Law
0 siblings, 0 replies; only message in thread
From: Jeff Law @ 2023-09-11 13:33 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:e2727993a2aa25359c4010581c1a80ef15d51098
commit e2727993a2aa25359c4010581c1a80ef15d51098
Author: Fei Gao <gaofei@eswincomputing.com>
Date: Tue Aug 29 08:37:44 2023 +0000
RISC-V: support cm.push cm.pop cm.popret in zcmp
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.
(cherry picked from commit 3d1d3132b9d4dc8b6069ad95dad624371124f297)
Diff:
---
gcc/config/riscv/iterators.md | 15 +
gcc/config/riscv/predicates.md | 96 ++
gcc/config/riscv/riscv-protos.h | 2 +
gcc/config/riscv/riscv.cc | 437 +++++++-
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/testsuite/gcc.target/riscv/zcmp_push_fpr.c | 34 +
.../gcc.target/riscv/zcmp_stack_alignment.c | 24 +
11 files changed, 2137 insertions(+), 52 deletions(-)
diff --git a/gcc/config/riscv/iterators.md b/gcc/config/riscv/iterators.md
index a4070de15108..ecf033f2fa79 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 51cf7eb75148..602e69dbc16a 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 4137bb14b808..65d20cebd9e9 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 2b39a6167442..9f0511d18d9a 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;
@@ -413,6 +421,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;
@@ -5565,6 +5583,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
@@ -5602,6 +5648,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.
@@ -5627,7 +5717,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)
@@ -5646,19 +5736,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)
{
@@ -5709,8 +5786,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 ())
@@ -5722,6 +5800,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. */
@@ -5747,7 +5833,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;
@@ -5926,8 +6020,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;
@@ -6013,16 +6107,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++;
}
}
@@ -6119,6 +6217,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)
{
@@ -6128,6 +6261,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 */
+static 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
@@ -6136,7 +6319,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);
@@ -6144,8 +6329,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 ();
@@ -6161,17 +6384,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)
@@ -6224,6 +6450,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 ()
{
@@ -6234,7 +6486,7 @@ riscv_adjust_libcall_cfi_epilogue ()
/* Debug info for adjust sp. */
adjust_sp_rtx =
gen_rtx_SET (stack_pointer_rtx,
- gen_rtx_PLUS (GET_MODE(stack_pointer_rtx), stack_pointer_rtx, GEN_INT (saved_size)));
+ gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (saved_size)));
dwarf = alloc_reg_note (REG_CFA_ADJUST_CFA, adjust_sp_rtx,
dwarf);
@@ -6262,11 +6514,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;
@@ -6337,18 +6602,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))
@@ -6382,8 +6655,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;
@@ -6398,16 +6672,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 ();
@@ -6419,15 +6703,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))));
@@ -7776,6 +8088,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 e093db09d31e..fa0d795168eb 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 0127b9e5abbd..f9f4e8b08e90 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)
@@ -3432,3 +3433,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 000000000000..5c1bf031b8da
--- /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 000000000000..57c832497414
--- /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 000000000000..f24e0a8bab9a
--- /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 000000000000..530b35b53dd0
--- /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 000000000000..2f2fa55baac5
--- /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] only message in thread
only message in thread, other threads:[~2023-09-11 13:33 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-09-11 13:33 [gcc(refs/vendors/riscv/heads/gcc-13-with-riscv-opts)] RISC-V: support cm.push cm.pop cm.popret in zcmp Jeff Law
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).