Commit a6c7e777 by Monk Chiang Committed by Chung-Ju Wu

[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 <jasonwucj@gmail.com>
Co-Authored-By: Kito Cheng <kito.cheng@gmail.com>

From-SVN: r258442
parent 1fdffa31
2018-03-11 Monk Chiang <sh.chiang04@gmail.com>
Kito Cheng <kito.cheng@gmail.com>
Chung-Ju Wu <jasonwucj@gmail.com>
* 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 <jakub@redhat.com> 2018-03-11 Jakub Jelinek <jakub@redhat.com>
PR debug/58150 PR debug/58150
......
...@@ -144,6 +144,7 @@ nds32_compute_stack_frame (void) ...@@ -144,6 +144,7 @@ nds32_compute_stack_frame (void)
{ {
int r; int r;
int block_size; int block_size;
bool v3pushpop_p;
/* Because nds32_compute_stack_frame() will be called from different place, /* Because nds32_compute_stack_frame() will be called from different place,
everytime we enter this function, we have to assume this function everytime we enter this function, we have to assume this function
...@@ -264,6 +265,8 @@ nds32_compute_stack_frame (void) ...@@ -264,6 +265,8 @@ nds32_compute_stack_frame (void)
return; return;
} }
v3pushpop_p = NDS32_V3PUSH_AVAILABLE_P;
/* Adjustment for v3push instructions: /* Adjustment for v3push instructions:
If we are using v3push (push25/pop25) instructions, If we are using v3push (push25/pop25) instructions,
we need to make sure Rb is $r6 and Re is we need to make sure Rb is $r6 and Re is
...@@ -271,9 +274,7 @@ nds32_compute_stack_frame (void) ...@@ -271,9 +274,7 @@ nds32_compute_stack_frame (void)
Some results above will be discarded and recomputed. Some results above will be discarded and recomputed.
Note that it is only available under V3/V3M ISA and we Note that it is only available under V3/V3M ISA and we
DO NOT setup following stuff for isr or variadic function. */ DO NOT setup following stuff for isr or variadic function. */
if (TARGET_V3PUSH if (v3pushpop_p)
&& !nds32_isr_function_p (current_function_decl)
&& (cfun->machine->va_args_size == 0))
{ {
/* Recompute: /* Recompute:
cfun->machine->fp_size cfun->machine->fp_size
...@@ -323,6 +324,39 @@ nds32_compute_stack_frame (void) ...@@ -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 /* We have correctly set callee_saved_first_gpr_regno
and callee_saved_last_gpr_regno. and callee_saved_last_gpr_regno.
Initially, the callee_saved_gpr_regs_size is supposed to be 0. Initially, the callee_saved_gpr_regs_size is supposed to be 0.
...@@ -368,14 +402,15 @@ nds32_compute_stack_frame (void) ...@@ -368,14 +402,15 @@ nds32_compute_stack_frame (void)
"push registers to memory", "push registers to memory",
"adjust stack pointer". */ "adjust stack pointer". */
static void 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 extra_count;
int num_use_regs; int num_use_regs;
int par_index; int par_index;
int offset; int offset;
int save_fp, save_gp, save_lp;
rtx reg; rtx reg;
rtx mem; rtx mem;
...@@ -403,24 +438,19 @@ nds32_emit_stack_push_multiple (rtx Rb, rtx Re, rtx En4, bool vaarg_p) ...@@ -403,24 +438,19 @@ nds32_emit_stack_push_multiple (rtx Rb, rtx Re, rtx En4, bool vaarg_p)
(set (reg:SI SP_REGNUM) (set (reg:SI SP_REGNUM)
(plus (reg:SI SP_REGNUM) (const_int -32)))]) */ (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. */ /* Calculate the number of registers that will be pushed. */
extra_count = 0; extra_count = 0;
if (save_fp) if (save_fp_p)
extra_count++; extra_count++;
if (save_gp) if (save_gp_p)
extra_count++; extra_count++;
if (save_lp) if (save_lp_p)
extra_count++; extra_count++;
/* Note that Rb and Re may be SP_REGNUM. DO NOT count it in. */ /* 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; num_use_regs = extra_count;
else else
num_use_regs = REGNO (Re) - REGNO (Rb) + 1 + extra_count; num_use_regs = Re - Rb + 1 + extra_count;
/* In addition to used registers, /* In addition to used registers,
we need one more space for (set sp sp-x) rtx. */ 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) ...@@ -432,7 +462,7 @@ nds32_emit_stack_push_multiple (rtx Rb, rtx Re, rtx En4, bool vaarg_p)
offset = -(num_use_regs * 4); offset = -(num_use_regs * 4);
/* Create (set mem regX) from Rb, Rb+1 up to Re. */ /* 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. /* Rb and Re may be SP_REGNUM.
We need to break this loop immediately. */ 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) ...@@ -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. */ /* 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); reg = gen_rtx_REG (SImode, FP_REGNUM);
mem = gen_frame_mem (SImode, plus_constant (Pmode, 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) ...@@ -463,7 +493,7 @@ nds32_emit_stack_push_multiple (rtx Rb, rtx Re, rtx En4, bool vaarg_p)
offset = offset + 4; offset = offset + 4;
par_index++; par_index++;
} }
if (save_gp) if (save_gp_p)
{ {
reg = gen_rtx_REG (SImode, GP_REGNUM); reg = gen_rtx_REG (SImode, GP_REGNUM);
mem = gen_frame_mem (SImode, plus_constant (Pmode, 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) ...@@ -475,7 +505,7 @@ nds32_emit_stack_push_multiple (rtx Rb, rtx Re, rtx En4, bool vaarg_p)
offset = offset + 4; offset = offset + 4;
par_index++; par_index++;
} }
if (save_lp) if (save_lp_p)
{ {
reg = gen_rtx_REG (SImode, LP_REGNUM); reg = gen_rtx_REG (SImode, LP_REGNUM);
mem = gen_frame_mem (SImode, plus_constant (Pmode, 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) ...@@ -521,14 +551,14 @@ nds32_emit_stack_push_multiple (rtx Rb, rtx Re, rtx En4, bool vaarg_p)
"pop registers from memory", "pop registers from memory",
"adjust stack pointer". */ "adjust stack pointer". */
static void 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 extra_count;
int num_use_regs; int num_use_regs;
int par_index; int par_index;
int offset; int offset;
int save_fp, save_gp, save_lp;
rtx reg; rtx reg;
rtx mem; rtx mem;
...@@ -556,24 +586,19 @@ nds32_emit_stack_pop_multiple (rtx Rb, rtx Re, rtx En4) ...@@ -556,24 +586,19 @@ nds32_emit_stack_pop_multiple (rtx Rb, rtx Re, rtx En4)
(set (reg:SI SP_REGNUM) (set (reg:SI SP_REGNUM)
(plus (reg:SI SP_REGNUM) (const_int 32)))]) */ (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. */ /* Calculate the number of registers that will be poped. */
extra_count = 0; extra_count = 0;
if (save_fp) if (save_fp_p)
extra_count++; extra_count++;
if (save_gp) if (save_gp_p)
extra_count++; extra_count++;
if (save_lp) if (save_lp_p)
extra_count++; extra_count++;
/* Note that Rb and Re may be SP_REGNUM. DO NOT count it in. */ /* 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; num_use_regs = extra_count;
else else
num_use_regs = REGNO (Re) - REGNO (Rb) + 1 + extra_count; num_use_regs = Re - Rb + 1 + extra_count;
/* In addition to used registers, /* In addition to used registers,
we need one more space for (set sp sp+x) rtx. */ 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) ...@@ -585,7 +610,7 @@ nds32_emit_stack_pop_multiple (rtx Rb, rtx Re, rtx En4)
offset = 0; offset = 0;
/* Create (set regX mem) from Rb, Rb+1 up to Re. */ /* 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. /* Rb and Re may be SP_REGNUM.
We need to break this loop immediately. */ We need to break this loop immediately. */
...@@ -606,7 +631,7 @@ nds32_emit_stack_pop_multiple (rtx Rb, rtx Re, rtx En4) ...@@ -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. */ /* 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); reg = gen_rtx_REG (SImode, FP_REGNUM);
mem = gen_frame_mem (SImode, plus_constant (Pmode, mem = gen_frame_mem (SImode, plus_constant (Pmode,
...@@ -620,7 +645,7 @@ nds32_emit_stack_pop_multiple (rtx Rb, rtx Re, rtx En4) ...@@ -620,7 +645,7 @@ nds32_emit_stack_pop_multiple (rtx Rb, rtx Re, rtx En4)
dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf); dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf);
} }
if (save_gp) if (save_gp_p)
{ {
reg = gen_rtx_REG (SImode, GP_REGNUM); reg = gen_rtx_REG (SImode, GP_REGNUM);
mem = gen_frame_mem (SImode, plus_constant (Pmode, mem = gen_frame_mem (SImode, plus_constant (Pmode,
...@@ -634,7 +659,7 @@ nds32_emit_stack_pop_multiple (rtx Rb, rtx Re, rtx En4) ...@@ -634,7 +659,7 @@ nds32_emit_stack_pop_multiple (rtx Rb, rtx Re, rtx En4)
dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf); dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf);
} }
if (save_lp) if (save_lp_p)
{ {
reg = gen_rtx_REG (SImode, LP_REGNUM); reg = gen_rtx_REG (SImode, LP_REGNUM);
mem = gen_frame_mem (SImode, plus_constant (Pmode, mem = gen_frame_mem (SImode, plus_constant (Pmode,
...@@ -677,12 +702,11 @@ nds32_emit_stack_pop_multiple (rtx Rb, rtx Re, rtx En4) ...@@ -677,12 +702,11 @@ nds32_emit_stack_pop_multiple (rtx Rb, rtx Re, rtx En4)
"push registers to memory", "push registers to memory",
"adjust stack pointer". */ "adjust stack pointer". */
static void static void
nds32_emit_stack_v3push (rtx Rb, nds32_emit_stack_v3push (unsigned Rb,
rtx Re, unsigned Re,
rtx En4 ATTRIBUTE_UNUSED, unsigned imm8u)
rtx imm8u)
{ {
int regno; unsigned regno;
int num_use_regs; int num_use_regs;
int par_index; int par_index;
int offset; int offset;
...@@ -717,7 +741,7 @@ nds32_emit_stack_v3push (rtx Rb, ...@@ -717,7 +741,7 @@ nds32_emit_stack_v3push (rtx Rb,
we need to count these three registers. we need to count these three registers.
Under v3push, Rb is $r6, while Re is $r6, $r8, $r10, or $r14. 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. */ 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, /* In addition to used registers,
we need one more space for (set sp sp-x-imm8u) rtx. */ we need one more space for (set sp sp-x-imm8u) rtx. */
...@@ -731,7 +755,7 @@ nds32_emit_stack_v3push (rtx Rb, ...@@ -731,7 +755,7 @@ nds32_emit_stack_v3push (rtx Rb,
/* Create (set mem regX) from Rb, Rb+1 up to Re. /* Create (set mem regX) from Rb, Rb+1 up to Re.
Under v3push, Rb is $r6, while Re is $r6, $r8, $r10, or $r14. 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. */ 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); reg = gen_rtx_REG (SImode, regno);
mem = gen_frame_mem (SImode, plus_constant (Pmode, mem = gen_frame_mem (SImode, plus_constant (Pmode,
...@@ -783,7 +807,7 @@ nds32_emit_stack_v3push (rtx Rb, ...@@ -783,7 +807,7 @@ nds32_emit_stack_v3push (rtx Rb,
= gen_rtx_SET (stack_pointer_rtx, = gen_rtx_SET (stack_pointer_rtx,
plus_constant (Pmode, plus_constant (Pmode,
stack_pointer_rtx, stack_pointer_rtx,
offset - INTVAL (imm8u))); offset - imm8u));
XVECEXP (parallel_insn, 0, par_index) = adjust_sp_rtx; XVECEXP (parallel_insn, 0, par_index) = adjust_sp_rtx;
RTX_FRAME_RELATED_P (adjust_sp_rtx) = 1; RTX_FRAME_RELATED_P (adjust_sp_rtx) = 1;
...@@ -801,12 +825,11 @@ nds32_emit_stack_v3push (rtx Rb, ...@@ -801,12 +825,11 @@ nds32_emit_stack_v3push (rtx Rb,
"pop registers from memory", "pop registers from memory",
"adjust stack pointer". */ "adjust stack pointer". */
static void static void
nds32_emit_stack_v3pop (rtx Rb, nds32_emit_stack_v3pop (unsigned Rb,
rtx Re, unsigned Re,
rtx En4 ATTRIBUTE_UNUSED, unsigned imm8u)
rtx imm8u)
{ {
int regno; unsigned regno;
int num_use_regs; int num_use_regs;
int par_index; int par_index;
int offset; int offset;
...@@ -842,7 +865,7 @@ nds32_emit_stack_v3pop (rtx Rb, ...@@ -842,7 +865,7 @@ nds32_emit_stack_v3pop (rtx Rb,
we need to count these three registers. we need to count these three registers.
Under v3push, Rb is $r6, while Re is $r6, $r8, $r10, or $r14. 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. */ 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, /* In addition to used registers,
we need one more space for (set sp sp+x+imm8u) rtx. */ we need one more space for (set sp sp+x+imm8u) rtx. */
...@@ -856,7 +879,7 @@ nds32_emit_stack_v3pop (rtx Rb, ...@@ -856,7 +879,7 @@ nds32_emit_stack_v3pop (rtx Rb,
/* Create (set regX mem) from Rb, Rb+1 up to Re. /* Create (set regX mem) from Rb, Rb+1 up to Re.
Under v3pop, Rb is $r6, while Re is $r6, $r8, $r10, or $r14. 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. */ 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); reg = gen_rtx_REG (SImode, regno);
mem = gen_frame_mem (SImode, plus_constant (Pmode, mem = gen_frame_mem (SImode, plus_constant (Pmode,
...@@ -914,11 +937,24 @@ nds32_emit_stack_v3pop (rtx Rb, ...@@ -914,11 +937,24 @@ nds32_emit_stack_v3pop (rtx Rb,
= gen_rtx_SET (stack_pointer_rtx, = gen_rtx_SET (stack_pointer_rtx,
plus_constant (Pmode, plus_constant (Pmode,
stack_pointer_rtx, stack_pointer_rtx,
offset + INTVAL (imm8u))); offset + imm8u));
XVECEXP (parallel_insn, 0, par_index) = adjust_sp_rtx; XVECEXP (parallel_insn, 0, par_index) = adjust_sp_rtx;
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. */ /* Tell gcc we adjust SP in this insn. */
dwarf = alloc_reg_note (REG_CFA_ADJUST_CFA, copy_rtx (adjust_sp_rtx), dwarf); dwarf = alloc_reg_note (REG_CFA_ADJUST_CFA,
copy_rtx (adjust_sp_rtx), dwarf);
}
parallel_insn = emit_insn (parallel_insn); parallel_insn = emit_insn (parallel_insn);
...@@ -940,18 +976,18 @@ nds32_emit_stack_v3pop (rtx Rb, ...@@ -940,18 +976,18 @@ nds32_emit_stack_v3pop (rtx Rb,
the adjustment value is not able to be fit in the 'addi' instruction. the adjustment value is not able to be fit in the 'addi' instruction.
One solution is to move value into a register One solution is to move value into a register
and then use 'add' instruction. and then use 'add' instruction.
In practice, we use TA_REGNUM ($r15) to accomplish this purpose. In practice, we use TA_REGNUM ($r15) to accomplish this purpose. */
Also, we need to return zero for sp adjustment so that static void
proglogue/epilogue knows there is no need to create 'addi' instruction. */ nds32_emit_adjust_frame (rtx to_reg, rtx from_reg, int adjust_value)
static int
nds32_force_addi_stack_int (int full_value)
{ {
int adjust_value;
rtx tmp_reg; 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. /* The value is not able to fit in single addi instruction.
Create more instructions of moving value into a register Create more instructions of moving value into a register
...@@ -962,21 +998,15 @@ nds32_force_addi_stack_int (int full_value) ...@@ -962,21 +998,15 @@ nds32_force_addi_stack_int (int full_value)
/* Create one more instruction to move value /* Create one more instruction to move value
into the temporary register. */ 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. */ /* Create new 'add' rtx. */
sp_adjust_insn = gen_addsi3 (stack_pointer_rtx, frame_adjust_insn = gen_addsi3 (to_reg,
stack_pointer_rtx, from_reg,
tmp_reg); tmp_reg);
/* Emit rtx into insn list and receive its transformed insn rtx. */ /* 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 /* Because (tmp_reg <- full_value) may be split into two
rtl patterns, we can not set its RTX_FRAME_RELATED_P. rtl patterns, we can not set its RTX_FRAME_RELATED_P.
We need to construct another (sp <- sp + full_value) We need to construct another (sp <- sp + full_value)
...@@ -987,27 +1017,24 @@ nds32_force_addi_stack_int (int full_value) ...@@ -987,27 +1017,24 @@ nds32_force_addi_stack_int (int full_value)
rtx plus_rtx; rtx plus_rtx;
rtx set_rtx; rtx set_rtx;
plus_rtx = plus_constant (Pmode, stack_pointer_rtx, full_value); plus_rtx = plus_constant (Pmode, from_reg, adjust_value);
set_rtx = gen_rtx_SET (stack_pointer_rtx, plus_rtx); set_rtx = gen_rtx_SET (to_reg, plus_rtx);
add_reg_note (sp_adjust_insn, REG_FRAME_RELATED_EXPR, set_rtx); add_reg_note (frame_adjust_insn, REG_FRAME_RELATED_EXPR, 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;
} }
else else
{ {
/* The value is able to fit in addi instruction. /* Generate sp adjustment instruction if and only if sp_adjust != 0. */
However, remember to make it to be positive value frame_adjust_insn = gen_addsi3 (to_reg,
because we want to return 'adjustment' result. */ from_reg,
adjust_value = (full_value < 0) ? (-full_value) : (full_value); adjust_value_rtx);
/* Emit rtx into instructions list and receive INSN rtx form. */
return adjust_value; 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. */ /* Return true if MODE/TYPE need double word alignment. */
...@@ -2965,10 +2992,7 @@ nds32_expand_prologue (void) ...@@ -2965,10 +2992,7 @@ nds32_expand_prologue (void)
{ {
int fp_adjust; int fp_adjust;
int sp_adjust; int sp_adjust;
int en4_const; unsigned Rb, Re;
rtx Rb, Re;
rtx fp_adjust_insn, sp_adjust_insn;
/* Compute and setup stack frame size. /* Compute and setup stack frame size.
The result will be in cfun->machine. */ The result will be in cfun->machine. */
...@@ -2978,10 +3002,10 @@ nds32_expand_prologue (void) ...@@ -2978,10 +3002,10 @@ nds32_expand_prologue (void)
registers that hold the unnamed argument value. */ registers that hold the unnamed argument value. */
if (cfun->machine->va_args_size != 0) if (cfun->machine->va_args_size != 0)
{ {
Rb = gen_rtx_REG (SImode, cfun->machine->va_args_first_regno); Rb = cfun->machine->va_args_first_regno;
Re = gen_rtx_REG (SImode, cfun->machine->va_args_last_regno); Re = cfun->machine->va_args_last_regno;
/* No need to push $fp, $gp, or $lp, so use GEN_INT(0). */ /* No need to push $fp, $gp, or $lp. */
nds32_emit_stack_push_multiple (Rb, Re, GEN_INT (0), true); nds32_emit_stack_push_multiple (Rb, Re, false, false, false, true);
/* We may also need to adjust stack pointer for padding bytes /* We may also need to adjust stack pointer for padding bytes
because varargs may cause $sp not 8-byte aligned. */ because varargs may cause $sp not 8-byte aligned. */
...@@ -2989,17 +3013,10 @@ nds32_expand_prologue (void) ...@@ -2989,17 +3013,10 @@ nds32_expand_prologue (void)
{ {
/* Generate sp adjustment instruction. */ /* Generate sp adjustment instruction. */
sp_adjust = cfun->machine->va_args_area_padding_bytes; 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. nds32_emit_adjust_frame (stack_pointer_rtx,
We need to use RTX_FRAME_RELATED_P so that GCC is able to stack_pointer_rtx,
generate CFI (Call Frame Information) stuff. */ -1 * sp_adjust);
RTX_FRAME_RELATED_P (sp_adjust_insn) = 1;
} }
} }
...@@ -3009,28 +3026,22 @@ nds32_expand_prologue (void) ...@@ -3009,28 +3026,22 @@ nds32_expand_prologue (void)
return; return;
/* Get callee_first_regno and callee_last_regno. */ /* Get callee_first_regno and callee_last_regno. */
Rb = gen_rtx_REG (SImode, cfun->machine->callee_saved_first_gpr_regno); Rb = cfun->machine->callee_saved_first_gpr_regno;
Re = gen_rtx_REG (SImode, cfun->machine->callee_saved_last_gpr_regno); Re = 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;
/* If $fp, $gp, $lp, and all callee-save registers are NOT required /* If $fp, $gp, $lp, and all callee-save registers are NOT required
to be saved, we don't have to create multiple push instruction. to be saved, we don't have to create multiple push instruction.
Otherwise, a multiple push instruction is needed. */ 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. */ /* 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 /* Check frame_pointer_needed to see
...@@ -3047,14 +3058,10 @@ nds32_expand_prologue (void) ...@@ -3047,14 +3058,10 @@ nds32_expand_prologue (void)
+ cfun->machine->gp_size + cfun->machine->gp_size
+ cfun->machine->lp_size + cfun->machine->lp_size
+ cfun->machine->callee_saved_gpr_regs_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. */ nds32_emit_adjust_frame (hard_frame_pointer_rtx,
RTX_FRAME_RELATED_P (fp_adjust_insn) = 1; stack_pointer_rtx,
fp_adjust);
} }
/* Adjust $sp = $sp - local_size - out_args_size /* Adjust $sp = $sp - local_size - out_args_size
...@@ -3065,21 +3072,9 @@ nds32_expand_prologue (void) ...@@ -3065,21 +3072,9 @@ nds32_expand_prologue (void)
/* sp_adjust value may be out of range of the addi instruction, /* sp_adjust value may be out of range of the addi instruction,
create alternative add behavior with TA_REGNUM if necessary, create alternative add behavior with TA_REGNUM if necessary,
using NEGATIVE value to tell that we are decreasing address. */ using NEGATIVE value to tell that we are decreasing address. */
sp_adjust = nds32_force_addi_stack_int ( (-1) * sp_adjust); nds32_emit_adjust_frame (stack_pointer_rtx,
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, stack_pointer_rtx,
GEN_INT (-1 * sp_adjust)); -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;
}
/* Prevent the instruction scheduler from /* Prevent the instruction scheduler from
moving instructions across the boundary. */ moving instructions across the boundary. */
...@@ -3091,10 +3086,7 @@ void ...@@ -3091,10 +3086,7 @@ void
nds32_expand_epilogue (bool sibcall_p) nds32_expand_epilogue (bool sibcall_p)
{ {
int sp_adjust; int sp_adjust;
int en4_const; unsigned Rb, Re;
rtx Rb, Re;
rtx sp_adjust_insn;
/* Compute and setup stack frame size. /* Compute and setup stack frame size.
The result will be in cfun->machine. */ The result will be in cfun->machine. */
...@@ -3119,16 +3111,10 @@ nds32_expand_epilogue (bool sibcall_p) ...@@ -3119,16 +3111,10 @@ nds32_expand_epilogue (bool sibcall_p)
We need to consider padding bytes here. */ We need to consider padding bytes here. */
sp_adjust = cfun->machine->va_args_size sp_adjust = cfun->machine->va_args_size
+ cfun->machine->va_args_area_padding_bytes; + 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. nds32_emit_adjust_frame (stack_pointer_rtx,
We need to use RTX_FRAME_RELATED_P so that GCC is able to stack_pointer_rtx,
generate CFI (Call Frame Information) stuff. */ sp_adjust);
RTX_FRAME_RELATED_P (sp_adjust_insn) = 1;
} }
/* Generate return instruction by using 'return_internal' pattern. /* Generate return instruction by using 'return_internal' pattern.
...@@ -3150,71 +3136,47 @@ nds32_expand_epilogue (bool sibcall_p) ...@@ -3150,71 +3136,47 @@ nds32_expand_epilogue (bool sibcall_p)
+ cfun->machine->gp_size + cfun->machine->gp_size
+ cfun->machine->lp_size + cfun->machine->lp_size
+ cfun->machine->callee_saved_gpr_regs_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. */ nds32_emit_adjust_frame (stack_pointer_rtx,
RTX_FRAME_RELATED_P (sp_adjust_insn) = 1; hard_frame_pointer_rtx,
-1 * sp_adjust);
} }
else else
{ {
/* If frame pointer is NOT needed, /* If frame pointer is NOT needed,
we cannot calculate the sp adjustment from frame pointer. we cannot calculate the sp adjustment from frame pointer.
Instead, we calculate the adjustment by local_size, 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, Notice that such sp adjustment value may be out of range,
so we have to deal with it as well. */ so we have to deal with it as well. */
/* Adjust $sp = $sp + local_size + out_args_size /* 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 sp_adjust = cfun->machine->local_size
+ cfun->machine->out_args_size + cfun->machine->out_args_size
+ cfun->machine->callee_saved_area_gpr_padding_bytes; + 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. */ nds32_emit_adjust_frame (stack_pointer_rtx,
RTX_FRAME_RELATED_P (sp_adjust_insn) = 1; stack_pointer_rtx,
} sp_adjust);
} }
/* Get callee_first_regno and callee_last_regno. */ /* Get callee_first_regno and callee_last_regno. */
Rb = gen_rtx_REG (SImode, cfun->machine->callee_saved_first_gpr_regno); Rb = cfun->machine->callee_saved_first_gpr_regno;
Re = gen_rtx_REG (SImode, cfun->machine->callee_saved_last_gpr_regno); Re = 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;
/* If $fp, $gp, $lp, and all callee-save registers are NOT required /* If $fp, $gp, $lp, and all callee-save registers are NOT required
to be saved, we don't have to create multiple pop instruction. to be saved, we don't have to create multiple pop instruction.
Otherwise, a multiple pop instruction is needed. */ 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. */ /* 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 /* If this is a variadic function, we do not have to restore argument
...@@ -3226,16 +3188,10 @@ nds32_expand_epilogue (bool sibcall_p) ...@@ -3226,16 +3188,10 @@ nds32_expand_epilogue (bool sibcall_p)
We need to consider padding bytes here. */ We need to consider padding bytes here. */
sp_adjust = cfun->machine->va_args_size sp_adjust = cfun->machine->va_args_size
+ cfun->machine->va_args_area_padding_bytes; + 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. nds32_emit_adjust_frame (stack_pointer_rtx,
We need to use RTX_FRAME_RELATED_P so that GCC is able to stack_pointer_rtx,
generate CFI (Call Frame Information) stuff. */ sp_adjust);
RTX_FRAME_RELATED_P (sp_adjust_insn) = 1;
} }
/* Generate return instruction. */ /* Generate return instruction. */
...@@ -3249,22 +3205,23 @@ nds32_expand_prologue_v3push (void) ...@@ -3249,22 +3205,23 @@ nds32_expand_prologue_v3push (void)
{ {
int fp_adjust; int fp_adjust;
int sp_adjust; int sp_adjust;
unsigned Rb, Re;
rtx Rb, Re;
rtx fp_adjust_insn, sp_adjust_insn;
/* Compute and setup stack frame size. /* Compute and setup stack frame size.
The result will be in cfun->machine. */ The result will be in cfun->machine. */
nds32_compute_stack_frame (); 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', /* If the function is 'naked',
we do not have to generate prologue code fragment. */ we do not have to generate prologue code fragment. */
if (cfun->machine->naked_p) if (cfun->machine->naked_p)
return; return;
/* Get callee_first_regno and callee_last_regno. */ /* Get callee_first_regno and callee_last_regno. */
Rb = gen_rtx_REG (SImode, cfun->machine->callee_saved_first_gpr_regno); Rb = cfun->machine->callee_saved_first_gpr_regno;
Re = gen_rtx_REG (SImode, cfun->machine->callee_saved_last_gpr_regno); Re = cfun->machine->callee_saved_last_gpr_regno;
/* Calculate sp_adjust first to test if 'push25 Re,imm8u' is available, /* Calculate sp_adjust first to test if 'push25 Re,imm8u' is available,
where imm8u has to be 8-byte alignment. */ where imm8u has to be 8-byte alignment. */
...@@ -3278,11 +3235,8 @@ nds32_expand_prologue_v3push (void) ...@@ -3278,11 +3235,8 @@ nds32_expand_prologue_v3push (void)
/* We can use 'push25 Re,imm8u'. */ /* We can use 'push25 Re,imm8u'. */
/* nds32_emit_stack_v3push(last_regno, sp_adjust), /* nds32_emit_stack_v3push(last_regno, sp_adjust),
the pattern 'stack_v3push' is implemented in nds32.md. 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, sp_adjust);
nds32_emit_stack_v3push (Rb, Re,
GEN_INT (14), GEN_INT (sp_adjust));
/* Check frame_pointer_needed to see /* Check frame_pointer_needed to see
if we shall emit fp adjustment instruction. */ if we shall emit fp adjustment instruction. */
if (frame_pointer_needed) if (frame_pointer_needed)
...@@ -3302,11 +3256,10 @@ nds32_expand_prologue_v3push (void) ...@@ -3302,11 +3256,10 @@ nds32_expand_prologue_v3push (void)
+ cfun->machine->lp_size + cfun->machine->lp_size
+ cfun->machine->callee_saved_gpr_regs_size + cfun->machine->callee_saved_gpr_regs_size
+ sp_adjust; + sp_adjust;
fp_adjust_insn = gen_addsi3 (hard_frame_pointer_rtx,
nds32_emit_adjust_frame (hard_frame_pointer_rtx,
stack_pointer_rtx, stack_pointer_rtx,
GEN_INT (fp_adjust)); fp_adjust);
/* Emit rtx into instructions list and receive INSN rtx form. */
fp_adjust_insn = emit_insn (fp_adjust_insn);
} }
} }
else else
...@@ -3315,10 +3268,8 @@ nds32_expand_prologue_v3push (void) ...@@ -3315,10 +3268,8 @@ nds32_expand_prologue_v3push (void)
expand one more instruction to adjust $sp later. */ expand one more instruction to adjust $sp later. */
/* nds32_emit_stack_v3push(last_regno, sp_adjust), /* nds32_emit_stack_v3push(last_regno, sp_adjust),
the pattern 'stack_v3push' is implemented in nds32.md. 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, 0);
nds32_emit_stack_v3push (Rb, Re,
GEN_INT (14), GEN_INT (0));
/* Check frame_pointer_needed to see /* Check frame_pointer_needed to see
if we shall emit fp adjustment instruction. */ if we shall emit fp adjustment instruction. */
...@@ -3336,34 +3287,18 @@ nds32_expand_prologue_v3push (void) ...@@ -3336,34 +3287,18 @@ nds32_expand_prologue_v3push (void)
+ cfun->machine->gp_size + cfun->machine->gp_size
+ cfun->machine->lp_size + cfun->machine->lp_size
+ cfun->machine->callee_saved_gpr_regs_size; + cfun->machine->callee_saved_gpr_regs_size;
fp_adjust_insn = gen_addsi3 (hard_frame_pointer_rtx,
nds32_emit_adjust_frame (hard_frame_pointer_rtx,
stack_pointer_rtx, stack_pointer_rtx,
GEN_INT (fp_adjust)); fp_adjust);
/* Emit rtx into instructions list and receive INSN rtx form. */
fp_adjust_insn = emit_insn (fp_adjust_insn);
} }
/* Because we use 'push25 Re,0', /* Because we use 'push25 Re,0',
we need to expand one more instruction to adjust $sp. 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. */ using NEGATIVE value to tell that we are decreasing address. */
sp_adjust = nds32_force_addi_stack_int ( (-1) * sp_adjust); nds32_emit_adjust_frame (stack_pointer_rtx,
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, stack_pointer_rtx,
GEN_INT (-1 * sp_adjust)); -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;
}
} }
/* Prevent the instruction scheduler from /* Prevent the instruction scheduler from
...@@ -3376,9 +3311,7 @@ void ...@@ -3376,9 +3311,7 @@ void
nds32_expand_epilogue_v3pop (bool sibcall_p) nds32_expand_epilogue_v3pop (bool sibcall_p)
{ {
int sp_adjust; int sp_adjust;
unsigned Rb, Re;
rtx Rb, Re;
rtx sp_adjust_insn;
/* Compute and setup stack frame size. /* Compute and setup stack frame size.
The result will be in cfun->machine. */ The result will be in cfun->machine. */
...@@ -3400,8 +3333,8 @@ nds32_expand_epilogue_v3pop (bool sibcall_p) ...@@ -3400,8 +3333,8 @@ nds32_expand_epilogue_v3pop (bool sibcall_p)
} }
/* Get callee_first_regno and callee_last_regno. */ /* Get callee_first_regno and callee_last_regno. */
Rb = gen_rtx_REG (SImode, cfun->machine->callee_saved_first_gpr_regno); Rb = cfun->machine->callee_saved_first_gpr_regno;
Re = gen_rtx_REG (SImode, cfun->machine->callee_saved_last_gpr_regno); Re = cfun->machine->callee_saved_last_gpr_regno;
/* Calculate sp_adjust first to test if 'pop25 Re,imm8u' is available, /* Calculate sp_adjust first to test if 'pop25 Re,imm8u' is available,
where imm8u has to be 8-byte alignment. */ where imm8u has to be 8-byte alignment. */
...@@ -3423,10 +3356,8 @@ nds32_expand_epilogue_v3pop (bool sibcall_p) ...@@ -3423,10 +3356,8 @@ nds32_expand_epilogue_v3pop (bool sibcall_p)
/* We can use 'pop25 Re,imm8u'. */ /* We can use 'pop25 Re,imm8u'. */
/* nds32_emit_stack_v3pop(last_regno, sp_adjust), /* nds32_emit_stack_v3pop(last_regno, sp_adjust),
the pattern 'stack_v3pop' is implementad in nds32.md. 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, sp_adjust);
nds32_emit_stack_v3pop (Rb, Re,
GEN_INT (14), GEN_INT (sp_adjust));
} }
else else
{ {
...@@ -3447,11 +3378,10 @@ nds32_expand_epilogue_v3pop (bool sibcall_p) ...@@ -3447,11 +3378,10 @@ nds32_expand_epilogue_v3pop (bool sibcall_p)
+ cfun->machine->gp_size + cfun->machine->gp_size
+ cfun->machine->lp_size + cfun->machine->lp_size
+ cfun->machine->callee_saved_gpr_regs_size; + cfun->machine->callee_saved_gpr_regs_size;
sp_adjust_insn = gen_addsi3 (stack_pointer_rtx,
nds32_emit_adjust_frame (stack_pointer_rtx,
hard_frame_pointer_rtx, hard_frame_pointer_rtx,
GEN_INT (-1 * sp_adjust)); -1 * sp_adjust);
/* Emit rtx into instructions list and receive INSN rtx form. */
sp_adjust_insn = emit_insn (sp_adjust_insn);
} }
else else
{ {
...@@ -3469,25 +3399,16 @@ nds32_expand_epilogue_v3pop (bool sibcall_p) ...@@ -3469,25 +3399,16 @@ nds32_expand_epilogue_v3pop (bool sibcall_p)
+ cfun->machine->callee_saved_area_gpr_padding_bytes; + cfun->machine->callee_saved_area_gpr_padding_bytes;
/* sp_adjust value may be out of range of the addi instruction, /* sp_adjust value may be out of range of the addi instruction,
create alternative add behavior with TA_REGNUM if necessary, create alternative add behavior with TA_REGNUM if necessary,
using POSITIVE value to tell that we are increasing address. */ using POSITIVE value to tell that we are increasing
sp_adjust = nds32_force_addi_stack_int (sp_adjust); address. */
if (sp_adjust) nds32_emit_adjust_frame (stack_pointer_rtx,
{
/* Generate sp adjustment instruction
if and only if sp_adjust != 0. */
sp_adjust_insn = gen_addsi3 (stack_pointer_rtx,
stack_pointer_rtx, stack_pointer_rtx,
GEN_INT (sp_adjust)); sp_adjust);
/* Emit rtx into instructions list and receive INSN rtx form. */
sp_adjust_insn = emit_insn (sp_adjust_insn);
}
} }
/* nds32_emit_stack_v3pop(last_regno, sp_adjust), /* nds32_emit_stack_v3pop(last_regno, sp_adjust),
the pattern 'stack_v3pop' is implementad in nds32.md. */ 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, 0);
nds32_emit_stack_v3pop (Rb, Re,
GEN_INT (14), GEN_INT (0));
} }
/* Generate return instruction. */ /* Generate return instruction. */
......
...@@ -130,6 +130,10 @@ enum nds32_16bit_address_type ...@@ -130,6 +130,10 @@ enum nds32_16bit_address_type
/* Define the last integer register number. */ /* Define the last integer register number. */
#define NDS32_LAST_GPR_REGNUM 31 #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 double word alignment bits. */
#define NDS32_DOUBLE_WORD_ALIGNMENT 64 #define NDS32_DOUBLE_WORD_ALIGNMENT 64
...@@ -196,6 +200,19 @@ enum nds32_16bit_address_type ...@@ -196,6 +200,19 @@ enum nds32_16bit_address_type
#define NDS32_REQUIRED_CALLEE_SAVED_P(regno) \ #define NDS32_REQUIRED_CALLEE_SAVED_P(regno) \
((!call_used_regs[regno]) && (df_regs_ever_live_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. /* A C structure for machine-specific, per-function data.
......
...@@ -2093,11 +2093,8 @@ create_template: ...@@ -2093,11 +2093,8 @@ create_template:
"" ""
{ {
/* Note that only under V3/V3M ISA, we could use v3push prologue. /* Note that only under V3/V3M ISA, we could use v3push prologue.
In addition, we do not want to use v3push for isr function In addition, we need to check if v3push is indeed available. */
and variadic function. */ if (NDS32_V3PUSH_AVAILABLE_P)
if (TARGET_V3PUSH
&& !nds32_isr_function_p (current_function_decl)
&& (cfun->machine->va_args_size == 0))
nds32_expand_prologue_v3push (); nds32_expand_prologue_v3push ();
else else
nds32_expand_prologue (); nds32_expand_prologue ();
...@@ -2108,11 +2105,8 @@ create_template: ...@@ -2108,11 +2105,8 @@ create_template:
"" ""
{ {
/* Note that only under V3/V3M ISA, we could use v3pop epilogue. /* Note that only under V3/V3M ISA, we could use v3pop epilogue.
In addition, we do not want to use v3pop for isr function In addition, we need to check if v3push is indeed available. */
and variadic function. */ if (NDS32_V3PUSH_AVAILABLE_P)
if (TARGET_V3PUSH
&& !nds32_isr_function_p (current_function_decl)
&& (cfun->machine->va_args_size == 0))
nds32_expand_epilogue_v3pop (false); nds32_expand_epilogue_v3pop (false);
else else
nds32_expand_epilogue (false); nds32_expand_epilogue (false);
...@@ -2125,9 +2119,6 @@ create_template: ...@@ -2125,9 +2119,6 @@ create_template:
/* Pass true to indicate that this is sibcall epilogue and /* Pass true to indicate that this is sibcall epilogue and
exit from a function without the final branch back to the exit from a function without the final branch back to the
calling function. */ 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; DONE;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment