Message ID | 20230607055215.29332-2-gaofei@eswincomputing.com |
---|---|
State | New |
Headers | show |
Series | support zcmp extention | expand |
Seems there are some indent format problems in the patch, could you fix them :) ``` patch:509: indent with spaces. x_save_size = riscv_stack_align (num_multi_push * UNITS_PER_WORD); error: patch failed: gcc/config/riscv/riscv.cc:5652 error: gcc/config/riscv/riscv.cc: patch does not apply ``` > -----原始邮件----- > 发件人: "Fei Gao" <gaofei@eswincomputing.com> > 发送时间: 2023-06-07 13:52:12 (星期三) > 收件人: gcc-patches@gcc.gnu.org > 抄送: kito.cheng@gmail.com, palmer@dabbelt.com, jeffreyalaw@gmail.com, sinan.lin@linux.alibaba.com, jiawei@iscas.ac.cn, "Fei Gao" <gaofei@eswincomputing.com> > 主题: [PATCH 1/4][V4][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. > > 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. > > Signed-off-by: Fei Gao <gaofei@eswincomputing.com> > > 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_adjust_multi_push_cfi_prologue): adjust cfi for cm.push > (riscv_gen_multi_push_pop_insn): gen function for multi push and pop > (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 > * 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_stack_alignment.c: New test. > --- > gcc/config/riscv/iterators.md | 15 + > gcc/config/riscv/predicates.md | 96 ++ > gcc/config/riscv/riscv-protos.h | 1 + > gcc/config/riscv/riscv.cc | 360 +++++- > gcc/config/riscv/riscv.h | 23 + > gcc/config/riscv/riscv.md | 2 + > gcc/config/riscv/zc.md | 1042 +++++++++++++++++ > gcc/testsuite/gcc.target/riscv/rv32e_zcmp.c | 239 ++++ > gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c | 239 ++++ > .../gcc.target/riscv/zcmp_stack_alignment.c | 23 + > 10 files changed, 2000 insertions(+), 40 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_stack_alignment.c > > diff --git a/gcc/config/riscv/iterators.md b/gcc/config/riscv/iterators.md > index d374a10810c..6ed4174f9cc 100644 > --- a/gcc/config/riscv/iterators.md > +++ b/gcc/config/riscv/iterators.md > @@ -120,6 +120,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 04ca6ceabc7..ab67b3332f0 100644 > --- a/gcc/config/riscv/predicates.md > +++ b/gcc/config/riscv/predicates.md > @@ -65,6 +65,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 00e1b20c6c6..f23b11622a2 100644 > --- a/gcc/config/riscv/riscv-protos.h > +++ b/gcc/config/riscv/riscv-protos.h > @@ -56,6 +56,7 @@ 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); > diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc > index 3954c89a039..c476c699f4c 100644 > --- a/gcc/config/riscv/riscv.cc > +++ b/gcc/config/riscv/riscv.cc > @@ -126,6 +126,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; > @@ -422,6 +430,16 @@ static const struct riscv_tune_info riscv_tune_info_table[] = { > #include "riscv-cores.def" > }; > > +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; > @@ -4876,6 +4894,37 @@ 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 > + || (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 > @@ -4913,6 +4962,51 @@ 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. > @@ -4938,7 +5032,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) > @@ -4957,19 +5051,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) > { > @@ -5017,8 +5098,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 ()) > @@ -5030,6 +5112,15 @@ 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); > + } > } > > /* At the bottom of the frame are any outgoing stack arguments. */ > @@ -5044,7 +5135,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; > @@ -5388,6 +5487,42 @@ 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) > { > @@ -5397,6 +5532,45 @@ 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); > +} > + > /* Expand the "prologue" pattern. */ > > void > @@ -5405,7 +5579,8 @@ 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; > + 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); > @@ -5413,8 +5588,35 @@ 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; > + } > /* 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 (); > @@ -5430,13 +5632,15 @@ 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); > } > > @@ -5493,6 +5697,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 () > { > @@ -5532,10 +5762,18 @@ riscv_expand_epilogue (int style) > struct riscv_frame_info *frame = &cfun->machine->frame; > unsigned mask = frame->mask; > 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; > > @@ -5606,18 +5844,25 @@ 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 save 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)) > @@ -5652,7 +5897,7 @@ riscv_expand_epilogue (int style) > adjust)); > rtx dwarf = NULL_RTX; > rtx cfa_adjust_rtx = gen_rtx_PLUS (Pmode, stack_pointer_rtx, > - GEN_INT (step2 + libcall_size)); > + 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; > @@ -5667,15 +5912,15 @@ riscv_expand_epilogue (int style) > epilogue_cfa_sp_offset = step2; > } > > - if (use_restore_libcall) > + if (use_restore_libcall || use_multi_pop) > frame->mask = 0; /* Temporarily fib that we need not save GPRs. */ > > /* Restore the registers. */ > - riscv_for_each_saved_reg (frame->total_size - step2 - libcall_size, > + riscv_for_each_saved_reg (frame->total_size - step2 - libcall_size - multipop_size, > riscv_restore_reg, > true, style == EXCEPTION_RETURN); > > - if (use_restore_libcall) > + if (use_restore_libcall || use_multi_pop) > frame->mask = mask; /* Undo the above fib. */ > > if (need_barrier_p) > @@ -5689,14 +5934,30 @@ riscv_expand_epilogue (int style) > > rtx dwarf = NULL_RTX; > rtx cfa_adjust_rtx = gen_rtx_PLUS (Pmode, stack_pointer_rtx, > - GEN_INT (libcall_size)); > + 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) > + { > + 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)))); > @@ -6980,6 +7241,25 @@ 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 4541255a8ae..2fa555dce2d 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 > diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md > index be960583101..c858b3bc9ef 100644 > --- a/gcc/config/riscv/riscv.md > +++ b/gcc/config/riscv/riscv.md > @@ -113,6 +113,7 @@ > > (define_constants > [(RETURN_ADDR_REGNUM 1) > + (SP_REGNUM 2) > (GP_REGNUM 3) > (TP_REGNUM 4) > (T0_REGNUM 5) > @@ -3163,3 +3164,4 @@ > (include "sifive-7.md") > (include "thead.md") > (include "vector.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=""></http:>. > + > +(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..6dbe489da9b > --- /dev/null > +++ b/gcc/testsuite/gcc.target/riscv/rv32e_zcmp.c > @@ -0,0 +1,239 @@ > +/* { dg-do compile } */ > +/* { dg-options " -Os -march=rv32e_zca_zcmp -mabi=ilp32e -mcmodel=medlow" } */ > +/* { 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..924197cb3c4 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c > @@ -0,0 +1,239 @@ > +/* { dg-do compile } */ > +/* { dg-options " -Os -march=rv32imaf_zca_zcmp -mabi=ilp32f -mcmodel=medlow" } */ > +/* { 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_stack_alignment.c b/gcc/testsuite/gcc.target/riscv/zcmp_stack_alignment.c > new file mode 100644 > index 00000000000..05602302a8f > --- /dev/null > +++ b/gcc/testsuite/gcc.target/riscv/zcmp_stack_alignment.c > @@ -0,0 +1,23 @@ > +/* { dg-do compile } */ > +/* { dg-options " -O0 -march=rv32e_zca_zcb_zcmp -mabi=ilp32e -mcmodel=medlow -fomit-frame-pointer" } */ > +/* { 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 a5,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 </slot12_offset></slot11_offset></slot10_offset></slot9_offset></slot8_offset></slot7_offset></slot6_offset></slot5_offset></slot4_offset></slot3_offset></slot2_offset></slot1_offset></slot0_offset></mode></slot10_offset></slot9_offset></slot8_offset></slot7_offset></slot6_offset></slot5_offset></slot4_offset></slot3_offset></slot2_offset></slot1_offset></slot0_offset></mode></slot9_offset></slot8_offset></slot7_offset></slot6_offset></slot5_offset></slot4_offset></slot3_offset></slot2_offset></slot1_offset></slot0_offset></mode></slot8_offset></slot7_offset></slot6_offset></slot5_offset></slot4_offset></slot3_offset></slot2_offset></slot1_offset></slot0_offset></mode></slot7_offset></slot6_offset></slot5_offset></slot4_offset></slot3_offset></slot2_offset></slot1_offset></slot0_offset></mode></slot6_offset></slot5_offset></slot4_offset></slot3_offset></slot2_offset></slot1_offset></slot0_offset></mode></slot5_offset></slot4_offset></slot3_offset></slot2_offset></slot1_offset></slot0_offset></mode></slot4_offset></slot3_offset></slot2_offset></slot1_offset></slot0_offset></mode></slot3_offset></slot2_offset></slot1_offset></slot0_offset></mode></slot2_offset></slot1_offset></slot0_offset></mode></slot1_offset></slot0_offset></mode></slot0_offset></mode></slot12_offset></slot11_offset></slot10_offset></slot9_offset></slot8_offset></slot7_offset></slot6_offset></slot5_offset></slot4_offset></slot3_offset></slot2_offset></slot1_offset></slot0_offset></mode></slot10_offset></slot9_offset></slot8_offset></slot7_offset></slot6_offset></slot5_offset></slot4_offset></slot3_offset></slot2_offset></slot1_offset></slot0_offset></mode></slot9_offset></slot8_offset></slot7_offset></slot6_offset></slot5_offset></slot4_offset></slot3_offset></slot2_offset></slot1_offset></slot0_offset></mode></slot8_offset></slot7_offset></slot6_offset></slot5_offset></slot4_offset></slot3_offset></slot2_offset></slot1_offset></slot0_offset></mode></slot7_offset></slot6_offset></slot5_offset></slot4_offset></slot3_offset></slot2_offset></slot1_offset></slot0_offset></mode></slot6_offset></slot5_offset></slot4_offset></slot3_offset></slot2_offset></slot1_offset></slot0_offset></mode></slot5_offset></slot4_offset></slot3_offset></slot2_offset></slot1_offset></slot0_offset></mode></slot4_offset></slot3_offset></slot2_offset></slot1_offset></slot0_offset></mode></slot3_offset></slot2_offset></slot1_offset></slot0_offset></mode></slot2_offset></slot1_offset></slot0_offset></mode></slot1_offset></slot0_offset></mode></slot0_offset></mode></slot12_offset></slot11_offset></slot10_offset></slot9_offset></slot8_offset></slot7_offset></slot6_offset></slot5_offset></slot4_offset></slot3_offset></slot2_offset></slot1_offset></slot0_offset></mode></slot10_offset></slot9_offset></slot8_offset></slot7_offset></slot6_offset></slot5_offset></slot4_offset></slot3_offset></slot2_offset></slot1_offset></slot0_offset></mode></slot9_offset></slot8_offset></slot7_offset></slot6_offset></slot5_offset></slot4_offset></slot3_offset></slot2_offset></slot1_offset></slot0_offset></mode></slot8_offset></slot7_offset></slot6_offset></slot5_offset></slot4_offset></slot3_offset></slot2_offset></slot1_offset></slot0_offset></mode></slot7_offset></slot6_offset></slot5_offset></slot4_offset></slot3_offset></slot2_offset></slot1_offset></slot0_offset></mode></slot6_offset></slot5_offset></slot4_offset></slot3_offset></slot2_offset></slot1_offset></slot0_offset></mode></slot5_offset></slot4_offset></slot3_offset></slot2_offset></slot1_offset></slot0_offset></mode></slot4_offset></slot3_offset></slot2_offset></slot1_offset></slot0_offset></mode></slot3_offset></slot2_offset></slot1_offset></slot0_offset></mode></slot2_offset></slot1_offset></slot0_offset></mode></slot1_offset></slot0_offset></mode></slot0_offset></mode></gaofei@eswincomputing.com></gaofei@eswincomputing.com></gaofei@eswincomputing.com>
Hi Fei: Tried to use Jiawei's patch to test this patch and found some issue: > @@ -5430,13 +5632,15 @@ 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); > } > I hit some issue here during building libgcc, I use riscv-gnu-toolchain with --with-arch=rv64gzca_zcmp And the error message is: In file included from ../../../../../riscv-gnu-toolchain-trunk/gcc/libgcc/unwind-dw2.c:1471: ../../../../../riscv-gnu-toolchain-trunk/gcc/libgcc/unwind.inc: In function '_Unwind_Backtrace': ../../../../../riscv-gnu-toolchain-trunk/gcc/libgcc/unwind.inc:330:1: internal compiler error: in gen_reg_rtx, at emit-rtl.cc:1176 330 | } | ^ 0x83753a gen_reg_rtx(machine_mode) ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/emit-rtl.cc:1176 0xf5566f maybe_legitimize_operand ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/optabs.cc:8047 0xf5566f maybe_legitimize_operands(insn_code, unsigned int, unsigned int, expand_operand*) ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/optabs.cc:8191 0xf511d9 maybe_gen_insn(insn_code, unsigned int, expand_operand*) ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/optabs.cc:8210 0xf58539 expand_binop_directly ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/optabs.cc:1452 0xf56666 expand_binop(machine_mode, optab_tag, rtx_def*, rtx_def*, rtx_def*, int, optab_methods) ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/optabs.cc:1539 0xcbfdd0 force_operand(rtx_def*, rtx_def*) ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/expr.cc:8231 0xc8fca1 force_reg(machine_mode, rtx_def*) ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/explow.cc:687 0x144b8cd riscv_force_temporary ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:1531 0x144b8cd riscv_force_address ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:1528 0x144b8cd riscv_legitimize_move(machine_mode, rtx_def*, rtx_def*) ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:2387 0x1af063e gen_movdf(rtx_def*, rtx_def*) ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.md:2107 0xcba503 rtx_insn* insn_gen_fn::operator()<rtx_def*, rtx_def*>(rtx_def*, rtx_def*) const ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/recog.h:411 0xcba503 emit_move_insn_1(rtx_def*, rtx_def*) ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/expr.cc:4164 0x143d6c4 riscv_emit_move(rtx_def*, rtx_def*) ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:1486 0x143d6c4 riscv_save_reg ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:5715 0x143e2b9 riscv_for_each_saved_reg ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:5904 0x14480d0 riscv_expand_prologue() ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:6156 0x1af57fb gen_prologue() ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.md:2816 0x143c746 target_gen_prologue ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.md:3302 Reduced case: $ riscv64-unknown-elf-gcc -march=rv64imafd_zicsr_zifencei_zca_zcmp -mabi=lp64d unwind-dw2.i -Os typedef struct { struct { struct { struct { long a } } a[129] } } b; struct c { void *a[129] } d() { struct c a; __builtin_unwind_init(); b e; f(a, &e); }
Another fail case for CFI: $ riscv64-unknown-elf-gcc _mulhc3.i -march=rv64imafd_zicsr_zifencei_zca_zcmp -mabi=lp64d -g -O2 -o _mulhc3.s typedef float a __attribute__((mode(HF))); b, c; f() { a a, d, e = a + d; if (g() && e) c = b; } 0x10e508a maybe_record_trace_start ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/dwarf2cfi.cc:2584 0x10e58fb scan_trace ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/dwarf2cfi.cc:2784 0x10e5fab create_cfi_notes ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/dwarf2cfi.cc:2938 0x10e6ee4 execute_dwarf2_frame ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/dwarf2cfi.cc:3309 0x10e7c5a execute ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/dwarf2cfi.cc:3797 On Wed, Aug 16, 2023 at 4:33 PM Kito Cheng <kito.cheng@gmail.com> wrote: > > Hi Fei: > > Tried to use Jiawei's patch to test this patch and found some issue: > > > > @@ -5430,13 +5632,15 @@ 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); > > } > > > > I hit some issue here during building libgcc, I use > riscv-gnu-toolchain with --with-arch=rv64gzca_zcmp > > And the error message is: > > In file included from > ../../../../../riscv-gnu-toolchain-trunk/gcc/libgcc/unwind-dw2.c:1471: > ../../../../../riscv-gnu-toolchain-trunk/gcc/libgcc/unwind.inc: In > function '_Unwind_Backtrace': > ../../../../../riscv-gnu-toolchain-trunk/gcc/libgcc/unwind.inc:330:1: > internal compiler error: in gen_reg_rtx, at emit-rtl.cc:1176 > 330 | } > | ^ > 0x83753a gen_reg_rtx(machine_mode) > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/emit-rtl.cc:1176 > 0xf5566f maybe_legitimize_operand > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/optabs.cc:8047 > 0xf5566f maybe_legitimize_operands(insn_code, unsigned int, unsigned > int, expand_operand*) > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/optabs.cc:8191 > 0xf511d9 maybe_gen_insn(insn_code, unsigned int, expand_operand*) > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/optabs.cc:8210 > 0xf58539 expand_binop_directly > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/optabs.cc:1452 > 0xf56666 expand_binop(machine_mode, optab_tag, rtx_def*, rtx_def*, > rtx_def*, int, optab_methods) > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/optabs.cc:1539 > 0xcbfdd0 force_operand(rtx_def*, rtx_def*) > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/expr.cc:8231 > 0xc8fca1 force_reg(machine_mode, rtx_def*) > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/explow.cc:687 > 0x144b8cd riscv_force_temporary > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:1531 > 0x144b8cd riscv_force_address > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:1528 > 0x144b8cd riscv_legitimize_move(machine_mode, rtx_def*, rtx_def*) > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:2387 > 0x1af063e gen_movdf(rtx_def*, rtx_def*) > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.md:2107 > 0xcba503 rtx_insn* insn_gen_fn::operator()<rtx_def*, > rtx_def*>(rtx_def*, rtx_def*) const > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/recog.h:411 > 0xcba503 emit_move_insn_1(rtx_def*, rtx_def*) > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/expr.cc:4164 > 0x143d6c4 riscv_emit_move(rtx_def*, rtx_def*) > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:1486 > 0x143d6c4 riscv_save_reg > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:5715 > 0x143e2b9 riscv_for_each_saved_reg > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:5904 > 0x14480d0 riscv_expand_prologue() > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:6156 > 0x1af57fb gen_prologue() > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.md:2816 > 0x143c746 target_gen_prologue > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.md:3302 > > > Reduced case: > > $ riscv64-unknown-elf-gcc -march=rv64imafd_zicsr_zifencei_zca_zcmp > -mabi=lp64d unwind-dw2.i -Os > > typedef struct { > struct { > struct { > struct { > long a > } > } a[129] > } > } b; > struct c { > void *a[129] > } d() { > struct c a; > __builtin_unwind_init(); > b e; > f(a, &e); > }
Hi Kito Thanks for reporting these 2 issues. Let me check and feedback you soon. BR Fei On 2023-08-16 16:38 Kito Cheng <kito.cheng@gmail.com> wrote: > >Another fail case for CFI: > >$ riscv64-unknown-elf-gcc _mulhc3.i >-march=rv64imafd_zicsr_zifencei_zca_zcmp -mabi=lp64d -g -O2 -o >_mulhc3.s > >typedef float a __attribute__((mode(HF))); >b, c; >f() { > a a, d, e = a + d; > if (g() && e) > c = b; >} > > >0x10e508a maybe_record_trace_start > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/dwarf2cfi.cc:2584 >0x10e58fb scan_trace > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/dwarf2cfi.cc:2784 >0x10e5fab create_cfi_notes > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/dwarf2cfi.cc:2938 >0x10e6ee4 execute_dwarf2_frame > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/dwarf2cfi.cc:3309 >0x10e7c5a execute > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/dwarf2cfi.cc:3797 > >On Wed, Aug 16, 2023 at 4:33 PM Kito Cheng <kito.cheng@gmail.com> wrote: >> >> Hi Fei: >> >> Tried to use Jiawei's patch to test this patch and found some issue: >> >> >> > @@ -5430,13 +5632,15 @@ 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); >> > } >> > >> >> I hit some issue here during building libgcc, I use >> riscv-gnu-toolchain with --with-arch=rv64gzca_zcmp >> >> And the error message is: >> >> In file included from >> ../../../../../riscv-gnu-toolchain-trunk/gcc/libgcc/unwind-dw2.c:1471: >> ../../../../../riscv-gnu-toolchain-trunk/gcc/libgcc/unwind.inc: In >> function '_Unwind_Backtrace': >> ../../../../../riscv-gnu-toolchain-trunk/gcc/libgcc/unwind.inc:330:1: >> internal compiler error: in gen_reg_rtx, at emit-rtl.cc:1176 >> 330 | } >> | ^ >> 0x83753a gen_reg_rtx(machine_mode) >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/emit-rtl.cc:1176 >> 0xf5566f maybe_legitimize_operand >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/optabs.cc:8047 >> 0xf5566f maybe_legitimize_operands(insn_code, unsigned int, unsigned >> int, expand_operand*) >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/optabs.cc:8191 >> 0xf511d9 maybe_gen_insn(insn_code, unsigned int, expand_operand*) >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/optabs.cc:8210 >> 0xf58539 expand_binop_directly >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/optabs.cc:1452 >> 0xf56666 expand_binop(machine_mode, optab_tag, rtx_def*, rtx_def*, >> rtx_def*, int, optab_methods) >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/optabs.cc:1539 >> 0xcbfdd0 force_operand(rtx_def*, rtx_def*) >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/expr.cc:8231 >> 0xc8fca1 force_reg(machine_mode, rtx_def*) >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/explow.cc:687 >> 0x144b8cd riscv_force_temporary >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:1531 >> 0x144b8cd riscv_force_address >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:1528 >> 0x144b8cd riscv_legitimize_move(machine_mode, rtx_def*, rtx_def*) >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:2387 >> 0x1af063e gen_movdf(rtx_def*, rtx_def*) >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.md:2107 >> 0xcba503 rtx_insn* insn_gen_fn::operator()<rtx_def*, >> rtx_def*>(rtx_def*, rtx_def*) const >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/recog.h:411 >> 0xcba503 emit_move_insn_1(rtx_def*, rtx_def*) >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/expr.cc:4164 >> 0x143d6c4 riscv_emit_move(rtx_def*, rtx_def*) >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:1486 >> 0x143d6c4 riscv_save_reg >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:5715 >> 0x143e2b9 riscv_for_each_saved_reg >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:5904 >> 0x14480d0 riscv_expand_prologue() >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:6156 >> 0x1af57fb gen_prologue() >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.md:2816 >> 0x143c746 target_gen_prologue >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.md:3302 >> >> >> Reduced case: >> >> $ riscv64-unknown-elf-gcc -march=rv64imafd_zicsr_zifencei_zca_zcmp >> -mabi=lp64d unwind-dw2.i -Os >> >> typedef struct { >> struct { >> struct { >> struct { >> long a >> } >> } a[129] >> } >> } b; >> struct c { >> void *a[129] >> } d() { >> struct c a; >> __builtin_unwind_init(); >> b e; >> f(a, &e); >> }
Hi Kito Root cause has been identified. Here's the frame layout fo the TC, please use courier font :) +-------------------------------+ | | | GPR save area 112 B | | | +-------------------------------+ | |<-- fs0 is beyond sp based 12-bit range | FPR save area 96 B | | | +-------------------------------+ | | | local variables |<-- stack_pointer_rtx after riscv_first_stack_step | | +-------------------------------+ During stack frame allocation: 1. cm.push reserves 160 bytes, 112 for ra and sregs with 128-bit alignment as per ABI, and additional 48 bytes for first 6 fprs. 2. riscv_first_stack_step reserves 2032 bytes for the rest 6 fprs and local variables. 3. riscv_for_each_saved_reg tries to save fs0 which is beyond sp based 12-bit range, thus breaking gcc_assert (can_create_pseudo_p ()) in gen_reg_rtx when doing force reg as it's already after reload complete. I tried with a solution like saving first 6 fprs immediately after cm.push. It seems working:) I will fix epilogue correspondingly as well. Thanks again for your test. BR, Fei On 2023-08-16 16:33 Kito Cheng <kito.cheng@gmail.com> wrote: > >Hi Fei: > >Tried to use Jiawei's patch to test this patch and found some issue: > > >> @@ -5430,13 +5632,15 @@ 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); >> } >> > >I hit some issue here during building libgcc, I use >riscv-gnu-toolchain with --with-arch=rv64gzca_zcmp > >And the error message is: > >In file included from >../../../../../riscv-gnu-toolchain-trunk/gcc/libgcc/unwind-dw2.c:1471: >../../../../../riscv-gnu-toolchain-trunk/gcc/libgcc/unwind.inc: In >function '_Unwind_Backtrace': >../../../../../riscv-gnu-toolchain-trunk/gcc/libgcc/unwind.inc:330:1: >internal compiler error: in gen_reg_rtx, at emit-rtl.cc:1176 > 330 | } > | ^ >0x83753a gen_reg_rtx(machine_mode) > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/emit-rtl.cc:1176 >0xf5566f maybe_legitimize_operand > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/optabs.cc:8047 >0xf5566f maybe_legitimize_operands(insn_code, unsigned int, unsigned >int, expand_operand*) > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/optabs.cc:8191 >0xf511d9 maybe_gen_insn(insn_code, unsigned int, expand_operand*) > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/optabs.cc:8210 >0xf58539 expand_binop_directly > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/optabs.cc:1452 >0xf56666 expand_binop(machine_mode, optab_tag, rtx_def*, rtx_def*, >rtx_def*, int, optab_methods) > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/optabs.cc:1539 >0xcbfdd0 force_operand(rtx_def*, rtx_def*) > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/expr.cc:8231 >0xc8fca1 force_reg(machine_mode, rtx_def*) > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/explow.cc:687 >0x144b8cd riscv_force_temporary > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:1531 >0x144b8cd riscv_force_address > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:1528 >0x144b8cd riscv_legitimize_move(machine_mode, rtx_def*, rtx_def*) > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:2387 >0x1af063e gen_movdf(rtx_def*, rtx_def*) > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.md:2107 >0xcba503 rtx_insn* insn_gen_fn::operator()<rtx_def*, >rtx_def*>(rtx_def*, rtx_def*) const > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/recog.h:411 >0xcba503 emit_move_insn_1(rtx_def*, rtx_def*) > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/expr.cc:4164 >0x143d6c4 riscv_emit_move(rtx_def*, rtx_def*) > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:1486 >0x143d6c4 riscv_save_reg > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:5715 >0x143e2b9 riscv_for_each_saved_reg > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:5904 >0x14480d0 riscv_expand_prologue() > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:6156 >0x1af57fb gen_prologue() > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.md:2816 >0x143c746 target_gen_prologue > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.md:3302 > > >Reduced case: > >$ riscv64-unknown-elf-gcc -march=rv64imafd_zicsr_zifencei_zca_zcmp >-mabi=lp64d unwind-dw2.i -Os > >typedef struct { > struct { > struct { > struct { > long a > } > } a[129] > } >} b; >struct c { > void *a[129] >} d() { > struct c a; > __builtin_unwind_init(); > b e; > f(a, &e); >}
Hi Kito This issue is due to zcmp and shrink-wrap-separate conflict, which has been addressed by an under-review patch. [PATCH 0/2] resolve confilct between RISC-V zcmp and shrink-wrap-separate https://patchwork.sourceware.org/project/gcc/list/?series=21577 https://www.mail-archive.com/gcc-patches@gcc.gnu.org/msg311487.html I'm making [PATCH 1/4][V5][RISC-V] support cm.push cm.pop cm.popret in zcmp for the 1st issue you catched. Please let me know if you want me to merge https://www.mail-archive.com/gcc-patches@gcc.gnu.org/msg311486.html into [PATCH 1/4][V5][RISC-V]. BR, Fei On 2023-08-16 16:38 Kito Cheng <kito.cheng@gmail.com> wrote: > >Another fail case for CFI: > >$ riscv64-unknown-elf-gcc _mulhc3.i >-march=rv64imafd_zicsr_zifencei_zca_zcmp -mabi=lp64d -g -O2 -o >_mulhc3.s > >typedef float a __attribute__((mode(HF))); >b, c; >f() { > a a, d, e = a + d; > if (g() && e) > c = b; >} > > >0x10e508a maybe_record_trace_start > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/dwarf2cfi.cc:2584 >0x10e58fb scan_trace > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/dwarf2cfi.cc:2784 >0x10e5fab create_cfi_notes > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/dwarf2cfi.cc:2938 >0x10e6ee4 execute_dwarf2_frame > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/dwarf2cfi.cc:3309 >0x10e7c5a execute > ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/dwarf2cfi.cc:3797 > >On Wed, Aug 16, 2023 at 4:33 PM Kito Cheng <kito.cheng@gmail.com> wrote: >> >> Hi Fei: >> >> Tried to use Jiawei's patch to test this patch and found some issue: >> >> >> > @@ -5430,13 +5632,15 @@ 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); >> > } >> > >> >> I hit some issue here during building libgcc, I use >> riscv-gnu-toolchain with --with-arch=rv64gzca_zcmp >> >> And the error message is: >> >> In file included from >> ../../../../../riscv-gnu-toolchain-trunk/gcc/libgcc/unwind-dw2.c:1471: >> ../../../../../riscv-gnu-toolchain-trunk/gcc/libgcc/unwind.inc: In >> function '_Unwind_Backtrace': >> ../../../../../riscv-gnu-toolchain-trunk/gcc/libgcc/unwind.inc:330:1: >> internal compiler error: in gen_reg_rtx, at emit-rtl.cc:1176 >> 330 | } >> | ^ >> 0x83753a gen_reg_rtx(machine_mode) >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/emit-rtl.cc:1176 >> 0xf5566f maybe_legitimize_operand >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/optabs.cc:8047 >> 0xf5566f maybe_legitimize_operands(insn_code, unsigned int, unsigned >> int, expand_operand*) >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/optabs.cc:8191 >> 0xf511d9 maybe_gen_insn(insn_code, unsigned int, expand_operand*) >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/optabs.cc:8210 >> 0xf58539 expand_binop_directly >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/optabs.cc:1452 >> 0xf56666 expand_binop(machine_mode, optab_tag, rtx_def*, rtx_def*, >> rtx_def*, int, optab_methods) >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/optabs.cc:1539 >> 0xcbfdd0 force_operand(rtx_def*, rtx_def*) >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/expr.cc:8231 >> 0xc8fca1 force_reg(machine_mode, rtx_def*) >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/explow.cc:687 >> 0x144b8cd riscv_force_temporary >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:1531 >> 0x144b8cd riscv_force_address >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:1528 >> 0x144b8cd riscv_legitimize_move(machine_mode, rtx_def*, rtx_def*) >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:2387 >> 0x1af063e gen_movdf(rtx_def*, rtx_def*) >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.md:2107 >> 0xcba503 rtx_insn* insn_gen_fn::operator()<rtx_def*, >> rtx_def*>(rtx_def*, rtx_def*) const >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/recog.h:411 >> 0xcba503 emit_move_insn_1(rtx_def*, rtx_def*) >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/expr.cc:4164 >> 0x143d6c4 riscv_emit_move(rtx_def*, rtx_def*) >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:1486 >> 0x143d6c4 riscv_save_reg >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:5715 >> 0x143e2b9 riscv_for_each_saved_reg >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:5904 >> 0x14480d0 riscv_expand_prologue() >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:6156 >> 0x1af57fb gen_prologue() >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.md:2816 >> 0x143c746 target_gen_prologue >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.md:3302 >> >> >> Reduced case: >> >> $ riscv64-unknown-elf-gcc -march=rv64imafd_zicsr_zifencei_zca_zcmp >> -mabi=lp64d unwind-dw2.i -Os >> >> typedef struct { >> struct { >> struct { >> struct { >> long a >> } >> } a[129] >> } >> } b; >> struct c { >> void *a[129] >> } d() { >> struct c a; >> __builtin_unwind_init(); >> b e; >> f(a, &e); >> }
Hi Kito & Jeff A new series for zcmp(https://patchwork.sourceware.org/project/gcc/list/?series=23929) to: 1. solve the 2 issues Kito catched 2. rebase The new series would be a replacement of the following: https://patchwork.sourceware.org/project/gcc/list/?series=21577 https://patchwork.sourceware.org/project/gcc/patch/20230607055215.29332-2-gaofei@eswincomputing.com/ The rest of zcmp patches will be send out after the new series accepted to avoid rebase again an again. BR, Fei On 2023-08-20 18:53 Fei Gao <gaofei@eswincomputing.com> wrote: > > >Hi Kito > >This issue is due to zcmp and shrink-wrap-separate conflict, >which has been addressed by an under-review patch. >[PATCH 0/2] resolve confilct between RISC-V zcmp and shrink-wrap-separate >https://patchwork.sourceware.org/project/gcc/list/?series=21577 >https://www.mail-archive.com/gcc-patches@gcc.gnu.org/msg311487.html > >I'm making [PATCH 1/4][V5][RISC-V] support cm.push cm.pop cm.popret in zcmp for the 1st issue you catched. >Please let me know if you want me to merge >https://www.mail-archive.com/gcc-patches@gcc.gnu.org/msg311486.html >into [PATCH 1/4][V5][RISC-V]. > >BR, >Fei >On 2023-08-16 16:38 Kito Cheng <kito.cheng@gmail.com> wrote: >> >>Another fail case for CFI: >> >>$ riscv64-unknown-elf-gcc _mulhc3.i >>-march=rv64imafd_zicsr_zifencei_zca_zcmp -mabi=lp64d -g -O2 -o >>_mulhc3.s >> >>typedef float a __attribute__((mode(HF))); >>b, c; >>f() { >> a a, d, e = a + d; >> if (g() && e) >> c = b; >>} >> >> >>0x10e508a maybe_record_trace_start >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/dwarf2cfi.cc:2584 >>0x10e58fb scan_trace >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/dwarf2cfi.cc:2784 >>0x10e5fab create_cfi_notes >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/dwarf2cfi.cc:2938 >>0x10e6ee4 execute_dwarf2_frame >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/dwarf2cfi.cc:3309 >>0x10e7c5a execute >> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/dwarf2cfi.cc:3797 >> >>On Wed, Aug 16, 2023 at 4:33 PM Kito Cheng <kito.cheng@gmail.com> wrote: >>> >>> Hi Fei: >>> >>> Tried to use Jiawei's patch to test this patch and found some issue: >>> >>> >>> > @@ -5430,13 +5632,15 @@ 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); >>> > } >>> > >>> >>> I hit some issue here during building libgcc, I use >>> riscv-gnu-toolchain with --with-arch=rv64gzca_zcmp >>> >>> And the error message is: >>> >>> In file included from >>> ../../../../../riscv-gnu-toolchain-trunk/gcc/libgcc/unwind-dw2.c:1471: >>> ../../../../../riscv-gnu-toolchain-trunk/gcc/libgcc/unwind.inc: In >>> function '_Unwind_Backtrace': >>> ../../../../../riscv-gnu-toolchain-trunk/gcc/libgcc/unwind.inc:330:1: >>> internal compiler error: in gen_reg_rtx, at emit-rtl.cc:1176 >>> 330 | } >>> | ^ >>> 0x83753a gen_reg_rtx(machine_mode) >>> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/emit-rtl.cc:1176 >>> 0xf5566f maybe_legitimize_operand >>> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/optabs.cc:8047 >>> 0xf5566f maybe_legitimize_operands(insn_code, unsigned int, unsigned >>> int, expand_operand*) >>> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/optabs.cc:8191 >>> 0xf511d9 maybe_gen_insn(insn_code, unsigned int, expand_operand*) >>> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/optabs.cc:8210 >>> 0xf58539 expand_binop_directly >>> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/optabs.cc:1452 >>> 0xf56666 expand_binop(machine_mode, optab_tag, rtx_def*, rtx_def*, >>> rtx_def*, int, optab_methods) >>> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/optabs.cc:1539 >>> 0xcbfdd0 force_operand(rtx_def*, rtx_def*) >>> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/expr.cc:8231 >>> 0xc8fca1 force_reg(machine_mode, rtx_def*) >>> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/explow.cc:687 >>> 0x144b8cd riscv_force_temporary >>> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:1531 >>> 0x144b8cd riscv_force_address >>> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:1528 >>> 0x144b8cd riscv_legitimize_move(machine_mode, rtx_def*, rtx_def*) >>> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:2387 >>> 0x1af063e gen_movdf(rtx_def*, rtx_def*) >>> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.md:2107 >>> 0xcba503 rtx_insn* insn_gen_fn::operator()<rtx_def*, >>> rtx_def*>(rtx_def*, rtx_def*) const >>> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/recog.h:411 >>> 0xcba503 emit_move_insn_1(rtx_def*, rtx_def*) >>> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/expr.cc:4164 >>> 0x143d6c4 riscv_emit_move(rtx_def*, rtx_def*) >>> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:1486 >>> 0x143d6c4 riscv_save_reg >>> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:5715 >>> 0x143e2b9 riscv_for_each_saved_reg >>> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:5904 >>> 0x14480d0 riscv_expand_prologue() >>> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.cc:6156 >>> 0x1af57fb gen_prologue() >>> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.md:2816 >>> 0x143c746 target_gen_prologue >>> ../../../../riscv-gnu-toolchain-trunk/gcc/gcc/config/riscv/riscv.md:3302 >>> >>> >>> Reduced case: >>> >>> $ riscv64-unknown-elf-gcc -march=rv64imafd_zicsr_zifencei_zca_zcmp >>> -mabi=lp64d unwind-dw2.i -Os >>> >>> typedef struct { >>> struct { >>> struct { >>> struct { >>> long a >>> } >>> } a[129] >>> } >>> } b; >>> struct c { >>> void *a[129] >>> } d() { >>> struct c a; >>> __builtin_unwind_init(); >>> b e; >>> f(a, &e); >>> }
diff --git a/gcc/config/riscv/iterators.md b/gcc/config/riscv/iterators.md index d374a10810c..6ed4174f9cc 100644 --- a/gcc/config/riscv/iterators.md +++ b/gcc/config/riscv/iterators.md @@ -120,6 +120,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 04ca6ceabc7..ab67b3332f0 100644 --- a/gcc/config/riscv/predicates.md +++ b/gcc/config/riscv/predicates.md @@ -65,6 +65,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 00e1b20c6c6..f23b11622a2 100644 --- a/gcc/config/riscv/riscv-protos.h +++ b/gcc/config/riscv/riscv-protos.h @@ -56,6 +56,7 @@ 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); diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index 3954c89a039..c476c699f4c 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -126,6 +126,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; @@ -422,6 +430,16 @@ static const struct riscv_tune_info riscv_tune_info_table[] = { #include "riscv-cores.def" }; +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; @@ -4876,6 +4894,37 @@ 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 + || (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 @@ -4913,6 +4962,51 @@ 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. @@ -4938,7 +5032,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) @@ -4957,19 +5051,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) { @@ -5017,8 +5098,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 ()) @@ -5030,6 +5112,15 @@ 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); + } } /* At the bottom of the frame are any outgoing stack arguments. */ @@ -5044,7 +5135,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; @@ -5388,6 +5487,42 @@ 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) { @@ -5397,6 +5532,45 @@ 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); +} + /* Expand the "prologue" pattern. */ void @@ -5405,7 +5579,8 @@ 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; + 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); @@ -5413,8 +5588,35 @@ 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; + } /* 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 (); @@ -5430,13 +5632,15 @@ 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); } @@ -5493,6 +5697,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 () { @@ -5532,10 +5762,18 @@ riscv_expand_epilogue (int style) struct riscv_frame_info *frame = &cfun->machine->frame; unsigned mask = frame->mask; 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; @@ -5606,18 +5844,25 @@ 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 save 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)) @@ -5652,7 +5897,7 @@ riscv_expand_epilogue (int style) adjust)); rtx dwarf = NULL_RTX; rtx cfa_adjust_rtx = gen_rtx_PLUS (Pmode, stack_pointer_rtx, - GEN_INT (step2 + libcall_size)); + 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; @@ -5667,15 +5912,15 @@ riscv_expand_epilogue (int style) epilogue_cfa_sp_offset = step2; } - if (use_restore_libcall) + if (use_restore_libcall || use_multi_pop) frame->mask = 0; /* Temporarily fib that we need not save GPRs. */ /* Restore the registers. */ - riscv_for_each_saved_reg (frame->total_size - step2 - libcall_size, + riscv_for_each_saved_reg (frame->total_size - step2 - libcall_size - multipop_size, riscv_restore_reg, true, style == EXCEPTION_RETURN); - if (use_restore_libcall) + if (use_restore_libcall || use_multi_pop) frame->mask = mask; /* Undo the above fib. */ if (need_barrier_p) @@ -5689,14 +5934,30 @@ riscv_expand_epilogue (int style) rtx dwarf = NULL_RTX; rtx cfa_adjust_rtx = gen_rtx_PLUS (Pmode, stack_pointer_rtx, - GEN_INT (libcall_size)); + 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) + { + 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)))); @@ -6980,6 +7241,25 @@ 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 4541255a8ae..2fa555dce2d 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 diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index be960583101..c858b3bc9ef 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -113,6 +113,7 @@ (define_constants [(RETURN_ADDR_REGNUM 1) + (SP_REGNUM 2) (GP_REGNUM 3) (TP_REGNUM 4) (T0_REGNUM 5) @@ -3163,3 +3164,4 @@ (include "sifive-7.md") (include "thead.md") (include "vector.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..6dbe489da9b --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rv32e_zcmp.c @@ -0,0 +1,239 @@ +/* { dg-do compile } */ +/* { dg-options " -Os -march=rv32e_zca_zcmp -mabi=ilp32e -mcmodel=medlow" } */ +/* { 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..924197cb3c4 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c @@ -0,0 +1,239 @@ +/* { dg-do compile } */ +/* { dg-options " -Os -march=rv32imaf_zca_zcmp -mabi=ilp32f -mcmodel=medlow" } */ +/* { 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_stack_alignment.c b/gcc/testsuite/gcc.target/riscv/zcmp_stack_alignment.c new file mode 100644 index 00000000000..05602302a8f --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zcmp_stack_alignment.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options " -O0 -march=rv32e_zca_zcb_zcmp -mabi=ilp32e -mcmodel=medlow -fomit-frame-pointer" } */ +/* { 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 a5,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; +}
Zcmp can share the same logic as save-restore in stack allocation: pre-allocation by cm.push, step 1 and step 2. 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. Signed-off-by: Fei Gao <gaofei@eswincomputing.com> 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_adjust_multi_push_cfi_prologue): adjust cfi for cm.push (riscv_gen_multi_push_pop_insn): gen function for multi push and pop (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 * 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_stack_alignment.c: New test. --- gcc/config/riscv/iterators.md | 15 + gcc/config/riscv/predicates.md | 96 ++ gcc/config/riscv/riscv-protos.h | 1 + gcc/config/riscv/riscv.cc | 360 +++++- gcc/config/riscv/riscv.h | 23 + gcc/config/riscv/riscv.md | 2 + gcc/config/riscv/zc.md | 1042 +++++++++++++++++ gcc/testsuite/gcc.target/riscv/rv32e_zcmp.c | 239 ++++ gcc/testsuite/gcc.target/riscv/rv32i_zcmp.c | 239 ++++ .../gcc.target/riscv/zcmp_stack_alignment.c | 23 + 10 files changed, 2000 insertions(+), 40 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_stack_alignment.c