From: Monk Chiang Date: Mon, 12 Mar 2018 01:21:57 +0000 (+0000) Subject: [NDS32] Refine prologue and epilogue code generation. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=a6c7e7779ad2330a0e14c87ba0e339367679ed9e;p=gcc.git [NDS32] Refine prologue and epilogue code generation. gcc/ * config/nds32/nds32.c (nds32_compute_stack_frame, nds32_emit_stack_push_multiple, nds32_emit_stack_pop_multiple, nds32_emit_stack_v3push, nds32_emit_stack_v3pop, nds32_emit_adjust_frame, nds32_expand_prologue, nds32_expand_epilogue, nds32_expand_prologue_v3push, nds32_expand_epilogue_v3pop): Refine. * config/nds32/nds32.h (NDS32_FIRST_CALLEE_SAVE_GPR_REGNUM, NDS32_LAST_CALLEE_SAVE_GPR_REGNUM, NDS32_V3PUSH_AVAILABLE_P): New. * config/nds32/nds32.md (prologue, epilogue): Use macro NDS32_V3PUSH_AVAILABLE_P to do checking. Co-Authored-By: Chung-Ju Wu Co-Authored-By: Kito Cheng From-SVN: r258442 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 85062c06280..aad7f0e0697 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,17 @@ +2018-03-11 Monk Chiang + Kito Cheng + Chung-Ju Wu + + * config/nds32/nds32.c (nds32_compute_stack_frame, + nds32_emit_stack_push_multiple, nds32_emit_stack_pop_multiple, + nds32_emit_stack_v3push, nds32_emit_stack_v3pop, + nds32_emit_adjust_frame, nds32_expand_prologue, nds32_expand_epilogue, + nds32_expand_prologue_v3push, nds32_expand_epilogue_v3pop): Refine. + * config/nds32/nds32.h (NDS32_FIRST_CALLEE_SAVE_GPR_REGNUM, + NDS32_LAST_CALLEE_SAVE_GPR_REGNUM, NDS32_V3PUSH_AVAILABLE_P): New. + * config/nds32/nds32.md (prologue, epilogue): Use macro + NDS32_V3PUSH_AVAILABLE_P to do checking. + 2018-03-11 Jakub Jelinek PR debug/58150 diff --git a/gcc/config/nds32/nds32.c b/gcc/config/nds32/nds32.c index 353641129f6..2d644b77d15 100644 --- a/gcc/config/nds32/nds32.c +++ b/gcc/config/nds32/nds32.c @@ -144,6 +144,7 @@ nds32_compute_stack_frame (void) { int r; int block_size; + bool v3pushpop_p; /* Because nds32_compute_stack_frame() will be called from different place, everytime we enter this function, we have to assume this function @@ -264,6 +265,8 @@ nds32_compute_stack_frame (void) return; } + v3pushpop_p = NDS32_V3PUSH_AVAILABLE_P; + /* Adjustment for v3push instructions: If we are using v3push (push25/pop25) instructions, we need to make sure Rb is $r6 and Re is @@ -271,9 +274,7 @@ nds32_compute_stack_frame (void) Some results above will be discarded and recomputed. Note that it is only available under V3/V3M ISA and we DO NOT setup following stuff for isr or variadic function. */ - if (TARGET_V3PUSH - && !nds32_isr_function_p (current_function_decl) - && (cfun->machine->va_args_size == 0)) + if (v3pushpop_p) { /* Recompute: cfun->machine->fp_size @@ -323,6 +324,39 @@ nds32_compute_stack_frame (void) } } + int sp_adjust = cfun->machine->local_size + + cfun->machine->out_args_size + + cfun->machine->callee_saved_area_gpr_padding_bytes; + + if (!v3pushpop_p + && sp_adjust == 0 + && !frame_pointer_needed) + { + block_size = cfun->machine->fp_size + + cfun->machine->gp_size + + cfun->machine->lp_size + + (4 * (cfun->machine->callee_saved_last_gpr_regno + - cfun->machine->callee_saved_first_gpr_regno + + 1)); + + if (!NDS32_DOUBLE_WORD_ALIGN_P (block_size)) + { + /* $r14 is last callee save register. */ + if (cfun->machine->callee_saved_last_gpr_regno + < NDS32_LAST_CALLEE_SAVE_GPR_REGNUM) + { + cfun->machine->callee_saved_last_gpr_regno++; + } + else if (cfun->machine->callee_saved_first_gpr_regno == SP_REGNUM) + { + cfun->machine->callee_saved_first_gpr_regno + = NDS32_FIRST_CALLEE_SAVE_GPR_REGNUM; + cfun->machine->callee_saved_last_gpr_regno + = NDS32_FIRST_CALLEE_SAVE_GPR_REGNUM; + } + } + } + /* We have correctly set callee_saved_first_gpr_regno and callee_saved_last_gpr_regno. Initially, the callee_saved_gpr_regs_size is supposed to be 0. @@ -368,14 +402,15 @@ nds32_compute_stack_frame (void) "push registers to memory", "adjust stack pointer". */ static void -nds32_emit_stack_push_multiple (rtx Rb, rtx Re, rtx En4, bool vaarg_p) +nds32_emit_stack_push_multiple (unsigned Rb, unsigned Re, + bool save_fp_p, bool save_gp_p, bool save_lp_p, + bool vaarg_p) { - int regno; + unsigned regno; int extra_count; int num_use_regs; int par_index; int offset; - int save_fp, save_gp, save_lp; rtx reg; rtx mem; @@ -403,24 +438,19 @@ nds32_emit_stack_push_multiple (rtx Rb, rtx Re, rtx En4, bool vaarg_p) (set (reg:SI SP_REGNUM) (plus (reg:SI SP_REGNUM) (const_int -32)))]) */ - /* Determine whether we need to save $fp, $gp, or $lp. */ - save_fp = INTVAL (En4) & 0x8; - save_gp = INTVAL (En4) & 0x4; - save_lp = INTVAL (En4) & 0x2; - /* Calculate the number of registers that will be pushed. */ extra_count = 0; - if (save_fp) + if (save_fp_p) extra_count++; - if (save_gp) + if (save_gp_p) extra_count++; - if (save_lp) + if (save_lp_p) extra_count++; /* Note that Rb and Re may be SP_REGNUM. DO NOT count it in. */ - if (REGNO (Rb) == SP_REGNUM && REGNO (Re) == SP_REGNUM) + if (Rb == SP_REGNUM && Re == SP_REGNUM) num_use_regs = extra_count; else - num_use_regs = REGNO (Re) - REGNO (Rb) + 1 + extra_count; + num_use_regs = Re - Rb + 1 + extra_count; /* In addition to used registers, we need one more space for (set sp sp-x) rtx. */ @@ -432,7 +462,7 @@ nds32_emit_stack_push_multiple (rtx Rb, rtx Re, rtx En4, bool vaarg_p) offset = -(num_use_regs * 4); /* Create (set mem regX) from Rb, Rb+1 up to Re. */ - for (regno = REGNO (Rb); regno <= (int) REGNO (Re); regno++) + for (regno = Rb; regno <= Re; regno++) { /* Rb and Re may be SP_REGNUM. We need to break this loop immediately. */ @@ -451,7 +481,7 @@ nds32_emit_stack_push_multiple (rtx Rb, rtx Re, rtx En4, bool vaarg_p) } /* Create (set mem fp), (set mem gp), and (set mem lp) if necessary. */ - if (save_fp) + if (save_fp_p) { reg = gen_rtx_REG (SImode, FP_REGNUM); mem = gen_frame_mem (SImode, plus_constant (Pmode, @@ -463,7 +493,7 @@ nds32_emit_stack_push_multiple (rtx Rb, rtx Re, rtx En4, bool vaarg_p) offset = offset + 4; par_index++; } - if (save_gp) + if (save_gp_p) { reg = gen_rtx_REG (SImode, GP_REGNUM); mem = gen_frame_mem (SImode, plus_constant (Pmode, @@ -475,7 +505,7 @@ nds32_emit_stack_push_multiple (rtx Rb, rtx Re, rtx En4, bool vaarg_p) offset = offset + 4; par_index++; } - if (save_lp) + if (save_lp_p) { reg = gen_rtx_REG (SImode, LP_REGNUM); mem = gen_frame_mem (SImode, plus_constant (Pmode, @@ -521,14 +551,14 @@ nds32_emit_stack_push_multiple (rtx Rb, rtx Re, rtx En4, bool vaarg_p) "pop registers from memory", "adjust stack pointer". */ static void -nds32_emit_stack_pop_multiple (rtx Rb, rtx Re, rtx En4) +nds32_emit_stack_pop_multiple (unsigned Rb, unsigned Re, + bool save_fp_p, bool save_gp_p, bool save_lp_p) { - int regno; + unsigned regno; int extra_count; int num_use_regs; int par_index; int offset; - int save_fp, save_gp, save_lp; rtx reg; rtx mem; @@ -556,24 +586,19 @@ nds32_emit_stack_pop_multiple (rtx Rb, rtx Re, rtx En4) (set (reg:SI SP_REGNUM) (plus (reg:SI SP_REGNUM) (const_int 32)))]) */ - /* Determine whether we need to restore $fp, $gp, or $lp. */ - save_fp = INTVAL (En4) & 0x8; - save_gp = INTVAL (En4) & 0x4; - save_lp = INTVAL (En4) & 0x2; - /* Calculate the number of registers that will be poped. */ extra_count = 0; - if (save_fp) + if (save_fp_p) extra_count++; - if (save_gp) + if (save_gp_p) extra_count++; - if (save_lp) + if (save_lp_p) extra_count++; /* Note that Rb and Re may be SP_REGNUM. DO NOT count it in. */ - if (REGNO (Rb) == SP_REGNUM && REGNO (Re) == SP_REGNUM) + if (Rb == SP_REGNUM && Re == SP_REGNUM) num_use_regs = extra_count; else - num_use_regs = REGNO (Re) - REGNO (Rb) + 1 + extra_count; + num_use_regs = Re - Rb + 1 + extra_count; /* In addition to used registers, we need one more space for (set sp sp+x) rtx. */ @@ -585,7 +610,7 @@ nds32_emit_stack_pop_multiple (rtx Rb, rtx Re, rtx En4) offset = 0; /* Create (set regX mem) from Rb, Rb+1 up to Re. */ - for (regno = REGNO (Rb); regno <= (int) REGNO (Re); regno++) + for (regno = Rb; regno <= Re; regno++) { /* Rb and Re may be SP_REGNUM. We need to break this loop immediately. */ @@ -606,7 +631,7 @@ nds32_emit_stack_pop_multiple (rtx Rb, rtx Re, rtx En4) } /* Create (set fp mem), (set gp mem), and (set lp mem) if necessary. */ - if (save_fp) + if (save_fp_p) { reg = gen_rtx_REG (SImode, FP_REGNUM); mem = gen_frame_mem (SImode, plus_constant (Pmode, @@ -620,7 +645,7 @@ nds32_emit_stack_pop_multiple (rtx Rb, rtx Re, rtx En4) dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf); } - if (save_gp) + if (save_gp_p) { reg = gen_rtx_REG (SImode, GP_REGNUM); mem = gen_frame_mem (SImode, plus_constant (Pmode, @@ -634,7 +659,7 @@ nds32_emit_stack_pop_multiple (rtx Rb, rtx Re, rtx En4) dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf); } - if (save_lp) + if (save_lp_p) { reg = gen_rtx_REG (SImode, LP_REGNUM); mem = gen_frame_mem (SImode, plus_constant (Pmode, @@ -677,12 +702,11 @@ nds32_emit_stack_pop_multiple (rtx Rb, rtx Re, rtx En4) "push registers to memory", "adjust stack pointer". */ static void -nds32_emit_stack_v3push (rtx Rb, - rtx Re, - rtx En4 ATTRIBUTE_UNUSED, - rtx imm8u) +nds32_emit_stack_v3push (unsigned Rb, + unsigned Re, + unsigned imm8u) { - int regno; + unsigned regno; int num_use_regs; int par_index; int offset; @@ -717,7 +741,7 @@ nds32_emit_stack_v3push (rtx Rb, we need to count these three registers. Under v3push, Rb is $r6, while Re is $r6, $r8, $r10, or $r14. So there is no need to worry about Rb=Re=SP_REGNUM case. */ - num_use_regs = REGNO (Re) - REGNO (Rb) + 1 + 3; + num_use_regs = Re - Rb + 1 + 3; /* In addition to used registers, we need one more space for (set sp sp-x-imm8u) rtx. */ @@ -731,7 +755,7 @@ nds32_emit_stack_v3push (rtx Rb, /* Create (set mem regX) from Rb, Rb+1 up to Re. Under v3push, Rb is $r6, while Re is $r6, $r8, $r10, or $r14. So there is no need to worry about Rb=Re=SP_REGNUM case. */ - for (regno = REGNO (Rb); regno <= (int) REGNO (Re); regno++) + for (regno = Rb; regno <= Re; regno++) { reg = gen_rtx_REG (SImode, regno); mem = gen_frame_mem (SImode, plus_constant (Pmode, @@ -783,7 +807,7 @@ nds32_emit_stack_v3push (rtx Rb, = gen_rtx_SET (stack_pointer_rtx, plus_constant (Pmode, stack_pointer_rtx, - offset - INTVAL (imm8u))); + offset - imm8u)); XVECEXP (parallel_insn, 0, par_index) = adjust_sp_rtx; RTX_FRAME_RELATED_P (adjust_sp_rtx) = 1; @@ -801,12 +825,11 @@ nds32_emit_stack_v3push (rtx Rb, "pop registers from memory", "adjust stack pointer". */ static void -nds32_emit_stack_v3pop (rtx Rb, - rtx Re, - rtx En4 ATTRIBUTE_UNUSED, - rtx imm8u) +nds32_emit_stack_v3pop (unsigned Rb, + unsigned Re, + unsigned imm8u) { - int regno; + unsigned regno; int num_use_regs; int par_index; int offset; @@ -842,7 +865,7 @@ nds32_emit_stack_v3pop (rtx Rb, we need to count these three registers. Under v3push, Rb is $r6, while Re is $r6, $r8, $r10, or $r14. So there is no need to worry about Rb=Re=SP_REGNUM case. */ - num_use_regs = REGNO (Re) - REGNO (Rb) + 1 + 3; + num_use_regs = Re - Rb + 1 + 3; /* In addition to used registers, we need one more space for (set sp sp+x+imm8u) rtx. */ @@ -856,7 +879,7 @@ nds32_emit_stack_v3pop (rtx Rb, /* Create (set regX mem) from Rb, Rb+1 up to Re. Under v3pop, Rb is $r6, while Re is $r6, $r8, $r10, or $r14. So there is no need to worry about Rb=Re=SP_REGNUM case. */ - for (regno = REGNO (Rb); regno <= (int) REGNO (Re); regno++) + for (regno = Rb; regno <= Re; regno++) { reg = gen_rtx_REG (SImode, regno); mem = gen_frame_mem (SImode, plus_constant (Pmode, @@ -914,11 +937,24 @@ nds32_emit_stack_v3pop (rtx Rb, = gen_rtx_SET (stack_pointer_rtx, plus_constant (Pmode, stack_pointer_rtx, - offset + INTVAL (imm8u))); + offset + imm8u)); XVECEXP (parallel_insn, 0, par_index) = adjust_sp_rtx; - /* Tell gcc we adjust SP in this insn. */ - dwarf = alloc_reg_note (REG_CFA_ADJUST_CFA, copy_rtx (adjust_sp_rtx), dwarf); + if (frame_pointer_needed) + { + /* (expr_list:REG_CFA_DEF_CFA (plus:SI (reg/f:SI $sp) + (const_int 0)) + mean reset frame pointer to $sp and reset to offset 0. */ + rtx cfa_adjust_rtx = gen_rtx_PLUS (Pmode, stack_pointer_rtx, + const0_rtx); + dwarf = alloc_reg_note (REG_CFA_DEF_CFA, cfa_adjust_rtx, dwarf); + } + else + { + /* Tell gcc we adjust SP in this insn. */ + dwarf = alloc_reg_note (REG_CFA_ADJUST_CFA, + copy_rtx (adjust_sp_rtx), dwarf); + } parallel_insn = emit_insn (parallel_insn); @@ -940,18 +976,18 @@ nds32_emit_stack_v3pop (rtx Rb, the adjustment value is not able to be fit in the 'addi' instruction. One solution is to move value into a register and then use 'add' instruction. - In practice, we use TA_REGNUM ($r15) to accomplish this purpose. - Also, we need to return zero for sp adjustment so that - proglogue/epilogue knows there is no need to create 'addi' instruction. */ -static int -nds32_force_addi_stack_int (int full_value) + In practice, we use TA_REGNUM ($r15) to accomplish this purpose. */ +static void +nds32_emit_adjust_frame (rtx to_reg, rtx from_reg, int adjust_value) { - int adjust_value; - rtx tmp_reg; - rtx sp_adjust_insn; + rtx frame_adjust_insn; + rtx adjust_value_rtx = GEN_INT (adjust_value); - if (!satisfies_constraint_Is15 (GEN_INT (full_value))) + if (adjust_value == 0) + return; + + if (!satisfies_constraint_Is15 (adjust_value_rtx)) { /* The value is not able to fit in single addi instruction. Create more instructions of moving value into a register @@ -962,52 +998,43 @@ nds32_force_addi_stack_int (int full_value) /* Create one more instruction to move value into the temporary register. */ - emit_move_insn (tmp_reg, GEN_INT (full_value)); + emit_move_insn (tmp_reg, adjust_value_rtx); /* Create new 'add' rtx. */ - sp_adjust_insn = gen_addsi3 (stack_pointer_rtx, - stack_pointer_rtx, - tmp_reg); + frame_adjust_insn = gen_addsi3 (to_reg, + from_reg, + tmp_reg); /* Emit rtx into insn list and receive its transformed insn rtx. */ - sp_adjust_insn = emit_insn (sp_adjust_insn); + frame_adjust_insn = emit_insn (frame_adjust_insn); - /* At prologue, we need to tell GCC that this is frame related insn, - so that we can consider this instruction to output debug information. - If full_value is NEGATIVE, it means this function - is invoked by expand_prologue. */ - if (full_value < 0) - { - /* Because (tmp_reg <- full_value) may be split into two - rtl patterns, we can not set its RTX_FRAME_RELATED_P. - We need to construct another (sp <- sp + full_value) - and then insert it into sp_adjust_insn's reg note to - represent a frame related expression. - GCC knows how to refer it and output debug information. */ - - rtx plus_rtx; - rtx set_rtx; + /* Because (tmp_reg <- full_value) may be split into two + rtl patterns, we can not set its RTX_FRAME_RELATED_P. + We need to construct another (sp <- sp + full_value) + and then insert it into sp_adjust_insn's reg note to + represent a frame related expression. + GCC knows how to refer it and output debug information. */ - plus_rtx = plus_constant (Pmode, stack_pointer_rtx, full_value); - set_rtx = gen_rtx_SET (stack_pointer_rtx, plus_rtx); - add_reg_note (sp_adjust_insn, REG_FRAME_RELATED_EXPR, set_rtx); + rtx plus_rtx; + rtx set_rtx; - RTX_FRAME_RELATED_P (sp_adjust_insn) = 1; - } - - /* We have used alternative way to adjust stack pointer value. - Return zero so that prologue/epilogue - will not generate other instructions. */ - return 0; + plus_rtx = plus_constant (Pmode, from_reg, adjust_value); + set_rtx = gen_rtx_SET (to_reg, plus_rtx); + add_reg_note (frame_adjust_insn, REG_FRAME_RELATED_EXPR, set_rtx); } else { - /* The value is able to fit in addi instruction. - However, remember to make it to be positive value - because we want to return 'adjustment' result. */ - adjust_value = (full_value < 0) ? (-full_value) : (full_value); - - return adjust_value; + /* Generate sp adjustment instruction if and only if sp_adjust != 0. */ + frame_adjust_insn = gen_addsi3 (to_reg, + from_reg, + adjust_value_rtx); + /* Emit rtx into instructions list and receive INSN rtx form. */ + frame_adjust_insn = emit_insn (frame_adjust_insn); } + + /* The insn rtx 'sp_adjust_insn' will change frame layout. + We need to use RTX_FRAME_RELATED_P so that GCC is able to + generate CFI (Call Frame Information) stuff. */ + RTX_FRAME_RELATED_P (frame_adjust_insn) = 1; } /* Return true if MODE/TYPE need double word alignment. */ @@ -2965,10 +2992,7 @@ nds32_expand_prologue (void) { int fp_adjust; int sp_adjust; - int en4_const; - - rtx Rb, Re; - rtx fp_adjust_insn, sp_adjust_insn; + unsigned Rb, Re; /* Compute and setup stack frame size. The result will be in cfun->machine. */ @@ -2978,10 +3002,10 @@ nds32_expand_prologue (void) registers that hold the unnamed argument value. */ if (cfun->machine->va_args_size != 0) { - Rb = gen_rtx_REG (SImode, cfun->machine->va_args_first_regno); - Re = gen_rtx_REG (SImode, cfun->machine->va_args_last_regno); - /* No need to push $fp, $gp, or $lp, so use GEN_INT(0). */ - nds32_emit_stack_push_multiple (Rb, Re, GEN_INT (0), true); + Rb = cfun->machine->va_args_first_regno; + Re = cfun->machine->va_args_last_regno; + /* No need to push $fp, $gp, or $lp. */ + nds32_emit_stack_push_multiple (Rb, Re, false, false, false, true); /* We may also need to adjust stack pointer for padding bytes because varargs may cause $sp not 8-byte aligned. */ @@ -2989,17 +3013,10 @@ nds32_expand_prologue (void) { /* Generate sp adjustment instruction. */ sp_adjust = cfun->machine->va_args_area_padding_bytes; - sp_adjust_insn = gen_addsi3 (stack_pointer_rtx, - stack_pointer_rtx, - GEN_INT (-1 * sp_adjust)); - - /* Emit rtx into instructions list and receive INSN rtx form. */ - sp_adjust_insn = emit_insn (sp_adjust_insn); - /* The insn rtx 'sp_adjust_insn' will change frame layout. - We need to use RTX_FRAME_RELATED_P so that GCC is able to - generate CFI (Call Frame Information) stuff. */ - RTX_FRAME_RELATED_P (sp_adjust_insn) = 1; + nds32_emit_adjust_frame (stack_pointer_rtx, + stack_pointer_rtx, + -1 * sp_adjust); } } @@ -3009,28 +3026,22 @@ nds32_expand_prologue (void) return; /* Get callee_first_regno and callee_last_regno. */ - Rb = gen_rtx_REG (SImode, cfun->machine->callee_saved_first_gpr_regno); - Re = gen_rtx_REG (SImode, cfun->machine->callee_saved_last_gpr_regno); - - /* nds32_emit_stack_push_multiple(first_regno, last_regno), - the pattern 'stack_push_multiple' is implemented in nds32.md. - For En4 field, we have to calculate its constant value. - Refer to Andes ISA for more information. */ - en4_const = 0; - if (cfun->machine->fp_size) - en4_const += 8; - if (cfun->machine->gp_size) - en4_const += 4; - if (cfun->machine->lp_size) - en4_const += 2; + Rb = cfun->machine->callee_saved_first_gpr_regno; + Re = cfun->machine->callee_saved_last_gpr_regno; /* If $fp, $gp, $lp, and all callee-save registers are NOT required to be saved, we don't have to create multiple push instruction. Otherwise, a multiple push instruction is needed. */ - if (!(REGNO (Rb) == SP_REGNUM && REGNO (Re) == SP_REGNUM && en4_const == 0)) + if (!(Rb == SP_REGNUM && Re == SP_REGNUM + && cfun->machine->fp_size == 0 + && cfun->machine->gp_size == 0 + && cfun->machine->lp_size == 0)) { /* Create multiple push instruction rtx. */ - nds32_emit_stack_push_multiple (Rb, Re, GEN_INT (en4_const), false); + nds32_emit_stack_push_multiple ( + Rb, Re, + cfun->machine->fp_size, cfun->machine->gp_size, cfun->machine->lp_size, + false); } /* Check frame_pointer_needed to see @@ -3047,14 +3058,10 @@ nds32_expand_prologue (void) + cfun->machine->gp_size + cfun->machine->lp_size + cfun->machine->callee_saved_gpr_regs_size; - fp_adjust_insn = gen_addsi3 (hard_frame_pointer_rtx, - stack_pointer_rtx, - GEN_INT (fp_adjust)); - /* Emit rtx into instructions list and receive INSN rtx form. */ - fp_adjust_insn = emit_insn (fp_adjust_insn); - /* The insn rtx 'fp_adjust_insn' will change frame layout. */ - RTX_FRAME_RELATED_P (fp_adjust_insn) = 1; + nds32_emit_adjust_frame (hard_frame_pointer_rtx, + stack_pointer_rtx, + fp_adjust); } /* Adjust $sp = $sp - local_size - out_args_size @@ -3065,21 +3072,9 @@ nds32_expand_prologue (void) /* sp_adjust value may be out of range of the addi instruction, create alternative add behavior with TA_REGNUM if necessary, using NEGATIVE value to tell that we are decreasing address. */ - sp_adjust = nds32_force_addi_stack_int ( (-1) * sp_adjust); - if (sp_adjust) - { - /* Generate sp adjustment instruction if and only if sp_adjust != 0. */ - sp_adjust_insn = gen_addsi3 (stack_pointer_rtx, - stack_pointer_rtx, - GEN_INT (-1 * sp_adjust)); - /* Emit rtx into instructions list and receive INSN rtx form. */ - sp_adjust_insn = emit_insn (sp_adjust_insn); - - /* The insn rtx 'sp_adjust_insn' will change frame layout. - We need to use RTX_FRAME_RELATED_P so that GCC is able to - generate CFI (Call Frame Information) stuff. */ - RTX_FRAME_RELATED_P (sp_adjust_insn) = 1; - } + nds32_emit_adjust_frame (stack_pointer_rtx, + stack_pointer_rtx, + -1 * sp_adjust); /* Prevent the instruction scheduler from moving instructions across the boundary. */ @@ -3091,10 +3086,7 @@ void nds32_expand_epilogue (bool sibcall_p) { int sp_adjust; - int en4_const; - - rtx Rb, Re; - rtx sp_adjust_insn; + unsigned Rb, Re; /* Compute and setup stack frame size. The result will be in cfun->machine. */ @@ -3119,16 +3111,10 @@ nds32_expand_epilogue (bool sibcall_p) We need to consider padding bytes here. */ sp_adjust = cfun->machine->va_args_size + cfun->machine->va_args_area_padding_bytes; - sp_adjust_insn = gen_addsi3 (stack_pointer_rtx, - stack_pointer_rtx, - GEN_INT (sp_adjust)); - /* Emit rtx into instructions list and receive INSN rtx form. */ - sp_adjust_insn = emit_insn (sp_adjust_insn); - - /* The insn rtx 'sp_adjust_insn' will change frame layout. - We need to use RTX_FRAME_RELATED_P so that GCC is able to - generate CFI (Call Frame Information) stuff. */ - RTX_FRAME_RELATED_P (sp_adjust_insn) = 1; + + nds32_emit_adjust_frame (stack_pointer_rtx, + stack_pointer_rtx, + sp_adjust); } /* Generate return instruction by using 'return_internal' pattern. @@ -3150,71 +3136,47 @@ nds32_expand_epilogue (bool sibcall_p) + cfun->machine->gp_size + cfun->machine->lp_size + cfun->machine->callee_saved_gpr_regs_size; - sp_adjust_insn = gen_addsi3 (stack_pointer_rtx, - hard_frame_pointer_rtx, - GEN_INT (-1 * sp_adjust)); - /* Emit rtx into instructions list and receive INSN rtx form. */ - sp_adjust_insn = emit_insn (sp_adjust_insn); - /* The insn rtx 'sp_adjust_insn' will change frame layout. */ - RTX_FRAME_RELATED_P (sp_adjust_insn) = 1; + nds32_emit_adjust_frame (stack_pointer_rtx, + hard_frame_pointer_rtx, + -1 * sp_adjust); } else { /* If frame pointer is NOT needed, we cannot calculate the sp adjustment from frame pointer. Instead, we calculate the adjustment by local_size, - out_args_size, and callee_saved_area_padding_bytes. + out_args_size, and callee_saved_area_gpr_padding_bytes. Notice that such sp adjustment value may be out of range, so we have to deal with it as well. */ /* Adjust $sp = $sp + local_size + out_args_size - + callee_saved_area_padding_bytes. */ + + callee_saved_area_gpr_padding_bytes. */ sp_adjust = cfun->machine->local_size + cfun->machine->out_args_size + cfun->machine->callee_saved_area_gpr_padding_bytes; - /* sp_adjust value may be out of range of the addi instruction, - create alternative add behavior with TA_REGNUM if necessary, - using POSITIVE value to tell that we are increasing address. */ - sp_adjust = nds32_force_addi_stack_int (sp_adjust); - if (sp_adjust) - { - /* Generate sp adjustment instruction - if and only if sp_adjust != 0. */ - sp_adjust_insn = gen_addsi3 (stack_pointer_rtx, - stack_pointer_rtx, - GEN_INT (sp_adjust)); - /* Emit rtx into instructions list and receive INSN rtx form. */ - sp_adjust_insn = emit_insn (sp_adjust_insn); - - /* The insn rtx 'sp_adjust_insn' will change frame layout. */ - RTX_FRAME_RELATED_P (sp_adjust_insn) = 1; - } + + nds32_emit_adjust_frame (stack_pointer_rtx, + stack_pointer_rtx, + sp_adjust); } /* Get callee_first_regno and callee_last_regno. */ - Rb = gen_rtx_REG (SImode, cfun->machine->callee_saved_first_gpr_regno); - Re = gen_rtx_REG (SImode, cfun->machine->callee_saved_last_gpr_regno); - - /* nds32_emit_stack_pop_multiple(first_regno, last_regno), - the pattern 'stack_pop_multiple' is implementad in nds32.md. - For En4 field, we have to calculate its constant value. - Refer to Andes ISA for more information. */ - en4_const = 0; - if (cfun->machine->fp_size) - en4_const += 8; - if (cfun->machine->gp_size) - en4_const += 4; - if (cfun->machine->lp_size) - en4_const += 2; + Rb = cfun->machine->callee_saved_first_gpr_regno; + Re = cfun->machine->callee_saved_last_gpr_regno; /* If $fp, $gp, $lp, and all callee-save registers are NOT required to be saved, we don't have to create multiple pop instruction. Otherwise, a multiple pop instruction is needed. */ - if (!(REGNO (Rb) == SP_REGNUM && REGNO (Re) == SP_REGNUM && en4_const == 0)) + if (!(Rb == SP_REGNUM && Re == SP_REGNUM + && cfun->machine->fp_size == 0 + && cfun->machine->gp_size == 0 + && cfun->machine->lp_size == 0)) { /* Create multiple pop instruction rtx. */ - nds32_emit_stack_pop_multiple (Rb, Re, GEN_INT (en4_const)); + nds32_emit_stack_pop_multiple ( + Rb, Re, + cfun->machine->fp_size, cfun->machine->gp_size, cfun->machine->lp_size); } /* If this is a variadic function, we do not have to restore argument @@ -3226,16 +3188,10 @@ nds32_expand_epilogue (bool sibcall_p) We need to consider padding bytes here. */ sp_adjust = cfun->machine->va_args_size + cfun->machine->va_args_area_padding_bytes; - sp_adjust_insn = gen_addsi3 (stack_pointer_rtx, - stack_pointer_rtx, - GEN_INT (sp_adjust)); - /* Emit rtx into instructions list and receive INSN rtx form. */ - sp_adjust_insn = emit_insn (sp_adjust_insn); - /* The insn rtx 'sp_adjust_insn' will change frame layout. - We need to use RTX_FRAME_RELATED_P so that GCC is able to - generate CFI (Call Frame Information) stuff. */ - RTX_FRAME_RELATED_P (sp_adjust_insn) = 1; + nds32_emit_adjust_frame (stack_pointer_rtx, + stack_pointer_rtx, + sp_adjust); } /* Generate return instruction. */ @@ -3249,22 +3205,23 @@ nds32_expand_prologue_v3push (void) { int fp_adjust; int sp_adjust; - - rtx Rb, Re; - rtx fp_adjust_insn, sp_adjust_insn; + unsigned Rb, Re; /* Compute and setup stack frame size. The result will be in cfun->machine. */ nds32_compute_stack_frame (); + if (cfun->machine->callee_saved_gpr_regs_size > 0) + df_set_regs_ever_live (FP_REGNUM, 1); + /* If the function is 'naked', we do not have to generate prologue code fragment. */ if (cfun->machine->naked_p) return; /* Get callee_first_regno and callee_last_regno. */ - Rb = gen_rtx_REG (SImode, cfun->machine->callee_saved_first_gpr_regno); - Re = gen_rtx_REG (SImode, cfun->machine->callee_saved_last_gpr_regno); + Rb = cfun->machine->callee_saved_first_gpr_regno; + Re = cfun->machine->callee_saved_last_gpr_regno; /* Calculate sp_adjust first to test if 'push25 Re,imm8u' is available, where imm8u has to be 8-byte alignment. */ @@ -3278,11 +3235,8 @@ nds32_expand_prologue_v3push (void) /* We can use 'push25 Re,imm8u'. */ /* nds32_emit_stack_v3push(last_regno, sp_adjust), - the pattern 'stack_v3push' is implemented in nds32.md. - The (const_int 14) means v3push always push { $fp $gp $lp }. */ - nds32_emit_stack_v3push (Rb, Re, - GEN_INT (14), GEN_INT (sp_adjust)); - + the pattern 'stack_v3push' is implemented in nds32.md. */ + nds32_emit_stack_v3push (Rb, Re, sp_adjust); /* Check frame_pointer_needed to see if we shall emit fp adjustment instruction. */ if (frame_pointer_needed) @@ -3302,11 +3256,10 @@ nds32_expand_prologue_v3push (void) + cfun->machine->lp_size + cfun->machine->callee_saved_gpr_regs_size + sp_adjust; - fp_adjust_insn = gen_addsi3 (hard_frame_pointer_rtx, - stack_pointer_rtx, - GEN_INT (fp_adjust)); - /* Emit rtx into instructions list and receive INSN rtx form. */ - fp_adjust_insn = emit_insn (fp_adjust_insn); + + nds32_emit_adjust_frame (hard_frame_pointer_rtx, + stack_pointer_rtx, + fp_adjust); } } else @@ -3315,10 +3268,8 @@ nds32_expand_prologue_v3push (void) expand one more instruction to adjust $sp later. */ /* nds32_emit_stack_v3push(last_regno, sp_adjust), - the pattern 'stack_v3push' is implemented in nds32.md. - The (const_int 14) means v3push always push { $fp $gp $lp }. */ - nds32_emit_stack_v3push (Rb, Re, - GEN_INT (14), GEN_INT (0)); + the pattern 'stack_v3push' is implemented in nds32.md. */ + nds32_emit_stack_v3push (Rb, Re, 0); /* Check frame_pointer_needed to see if we shall emit fp adjustment instruction. */ @@ -3336,34 +3287,18 @@ nds32_expand_prologue_v3push (void) + cfun->machine->gp_size + cfun->machine->lp_size + cfun->machine->callee_saved_gpr_regs_size; - fp_adjust_insn = gen_addsi3 (hard_frame_pointer_rtx, - stack_pointer_rtx, - GEN_INT (fp_adjust)); - /* Emit rtx into instructions list and receive INSN rtx form. */ - fp_adjust_insn = emit_insn (fp_adjust_insn); + + nds32_emit_adjust_frame (hard_frame_pointer_rtx, + stack_pointer_rtx, + fp_adjust); } /* Because we use 'push25 Re,0', we need to expand one more instruction to adjust $sp. - However, sp_adjust value may be out of range of the addi instruction, - create alternative add behavior with TA_REGNUM if necessary, using NEGATIVE value to tell that we are decreasing address. */ - sp_adjust = nds32_force_addi_stack_int ( (-1) * sp_adjust); - if (sp_adjust) - { - /* Generate sp adjustment instruction - if and only if sp_adjust != 0. */ - sp_adjust_insn = gen_addsi3 (stack_pointer_rtx, - stack_pointer_rtx, - GEN_INT (-1 * sp_adjust)); - /* Emit rtx into instructions list and receive INSN rtx form. */ - sp_adjust_insn = emit_insn (sp_adjust_insn); - - /* The insn rtx 'sp_adjust_insn' will change frame layout. - We need to use RTX_FRAME_RELATED_P so that GCC is able to - generate CFI (Call Frame Information) stuff. */ - RTX_FRAME_RELATED_P (sp_adjust_insn) = 1; - } + nds32_emit_adjust_frame (stack_pointer_rtx, + stack_pointer_rtx, + -1 * sp_adjust); } /* Prevent the instruction scheduler from @@ -3376,9 +3311,7 @@ void nds32_expand_epilogue_v3pop (bool sibcall_p) { int sp_adjust; - - rtx Rb, Re; - rtx sp_adjust_insn; + unsigned Rb, Re; /* Compute and setup stack frame size. The result will be in cfun->machine. */ @@ -3400,8 +3333,8 @@ nds32_expand_epilogue_v3pop (bool sibcall_p) } /* Get callee_first_regno and callee_last_regno. */ - Rb = gen_rtx_REG (SImode, cfun->machine->callee_saved_first_gpr_regno); - Re = gen_rtx_REG (SImode, cfun->machine->callee_saved_last_gpr_regno); + Rb = cfun->machine->callee_saved_first_gpr_regno; + Re = cfun->machine->callee_saved_last_gpr_regno; /* Calculate sp_adjust first to test if 'pop25 Re,imm8u' is available, where imm8u has to be 8-byte alignment. */ @@ -3423,10 +3356,8 @@ nds32_expand_epilogue_v3pop (bool sibcall_p) /* We can use 'pop25 Re,imm8u'. */ /* nds32_emit_stack_v3pop(last_regno, sp_adjust), - the pattern 'stack_v3pop' is implementad in nds32.md. - The (const_int 14) means v3pop always pop { $fp $gp $lp }. */ - nds32_emit_stack_v3pop (Rb, Re, - GEN_INT (14), GEN_INT (sp_adjust)); + the pattern 'stack_v3pop' is implementad in nds32.md. */ + nds32_emit_stack_v3pop (Rb, Re, sp_adjust); } else { @@ -3447,11 +3378,10 @@ nds32_expand_epilogue_v3pop (bool sibcall_p) + cfun->machine->gp_size + cfun->machine->lp_size + cfun->machine->callee_saved_gpr_regs_size; - sp_adjust_insn = gen_addsi3 (stack_pointer_rtx, - hard_frame_pointer_rtx, - GEN_INT (-1 * sp_adjust)); - /* Emit rtx into instructions list and receive INSN rtx form. */ - sp_adjust_insn = emit_insn (sp_adjust_insn); + + nds32_emit_adjust_frame (stack_pointer_rtx, + hard_frame_pointer_rtx, + -1 * sp_adjust); } else { @@ -3463,31 +3393,22 @@ nds32_expand_epilogue_v3pop (bool sibcall_p) so we have to deal with it as well. */ /* Adjust $sp = $sp + local_size + out_args_size - + callee_saved_area_gpr_padding_bytes. */ + + callee_saved_area_gpr_padding_bytes. */ sp_adjust = cfun->machine->local_size + cfun->machine->out_args_size + cfun->machine->callee_saved_area_gpr_padding_bytes; - /* sp_adjust value may be out of range of the addi instruction, - create alternative add behavior with TA_REGNUM if necessary, - using POSITIVE value to tell that we are increasing address. */ - sp_adjust = nds32_force_addi_stack_int (sp_adjust); - if (sp_adjust) - { - /* Generate sp adjustment instruction - if and only if sp_adjust != 0. */ - sp_adjust_insn = gen_addsi3 (stack_pointer_rtx, - stack_pointer_rtx, - GEN_INT (sp_adjust)); - /* Emit rtx into instructions list and receive INSN rtx form. */ - sp_adjust_insn = emit_insn (sp_adjust_insn); - } + /* sp_adjust value may be out of range of the addi instruction, + create alternative add behavior with TA_REGNUM if necessary, + using POSITIVE value to tell that we are increasing + address. */ + nds32_emit_adjust_frame (stack_pointer_rtx, + stack_pointer_rtx, + sp_adjust); } /* nds32_emit_stack_v3pop(last_regno, sp_adjust), the pattern 'stack_v3pop' is implementad in nds32.md. */ - /* The (const_int 14) means v3pop always pop { $fp $gp $lp }. */ - nds32_emit_stack_v3pop (Rb, Re, - GEN_INT (14), GEN_INT (0)); + nds32_emit_stack_v3pop (Rb, Re, 0); } /* Generate return instruction. */ diff --git a/gcc/config/nds32/nds32.h b/gcc/config/nds32/nds32.h index 6846aef5f16..dc40735700a 100644 --- a/gcc/config/nds32/nds32.h +++ b/gcc/config/nds32/nds32.h @@ -130,6 +130,10 @@ enum nds32_16bit_address_type /* Define the last integer register number. */ #define NDS32_LAST_GPR_REGNUM 31 +#define NDS32_FIRST_CALLEE_SAVE_GPR_REGNUM 6 +#define NDS32_LAST_CALLEE_SAVE_GPR_REGNUM \ + (TARGET_REDUCED_REGS ? 10 : 14) + /* Define double word alignment bits. */ #define NDS32_DOUBLE_WORD_ALIGNMENT 64 @@ -196,6 +200,19 @@ enum nds32_16bit_address_type #define NDS32_REQUIRED_CALLEE_SAVED_P(regno) \ ((!call_used_regs[regno]) && (df_regs_ever_live_p (regno))) +/* This macro is to check if the push25/pop25 are available to be used + for code generation. Because pop25 also performs return behavior, + the instructions may not be available for some cases. + If we want to use push25/pop25, all the following conditions must + be satisfied: + 1. TARGET_V3PUSH is set. + 2. Current function is not an ISR function. + 3. Current function is not a variadic function.*/ +#define NDS32_V3PUSH_AVAILABLE_P \ + (TARGET_V3PUSH \ + && !nds32_isr_function_p (current_function_decl) \ + && (cfun->machine->va_args_size == 0)) + /* ------------------------------------------------------------------------ */ /* A C structure for machine-specific, per-function data. diff --git a/gcc/config/nds32/nds32.md b/gcc/config/nds32/nds32.md index 71736f69b06..58a13c1abfd 100644 --- a/gcc/config/nds32/nds32.md +++ b/gcc/config/nds32/nds32.md @@ -2093,11 +2093,8 @@ create_template: "" { /* Note that only under V3/V3M ISA, we could use v3push prologue. - In addition, we do not want to use v3push for isr function - and variadic function. */ - if (TARGET_V3PUSH - && !nds32_isr_function_p (current_function_decl) - && (cfun->machine->va_args_size == 0)) + In addition, we need to check if v3push is indeed available. */ + if (NDS32_V3PUSH_AVAILABLE_P) nds32_expand_prologue_v3push (); else nds32_expand_prologue (); @@ -2108,11 +2105,8 @@ create_template: "" { /* Note that only under V3/V3M ISA, we could use v3pop epilogue. - In addition, we do not want to use v3pop for isr function - and variadic function. */ - if (TARGET_V3PUSH - && !nds32_isr_function_p (current_function_decl) - && (cfun->machine->va_args_size == 0)) + In addition, we need to check if v3push is indeed available. */ + if (NDS32_V3PUSH_AVAILABLE_P) nds32_expand_epilogue_v3pop (false); else nds32_expand_epilogue (false); @@ -2125,10 +2119,7 @@ create_template: /* Pass true to indicate that this is sibcall epilogue and exit from a function without the final branch back to the calling function. */ - if (TARGET_V3PUSH && !nds32_isr_function_p (current_function_decl)) - nds32_expand_epilogue_v3pop (true); - else - nds32_expand_epilogue (true); + nds32_expand_epilogue (true); DONE; })