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>
PR debug/58150
......
......@@ -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;
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);
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,21 +998,15 @@ 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,
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)
......@@ -987,27 +1017,24 @@ nds32_force_addi_stack_int (int full_value)
rtx plus_rtx;
rtx set_rtx;
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_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,
nds32_emit_adjust_frame (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;
}
-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,
nds32_emit_adjust_frame (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);
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,
nds32_emit_adjust_frame (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);
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,
nds32_emit_adjust_frame (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;
}
-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,
nds32_emit_adjust_frame (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);
-1 * sp_adjust);
}
else
{
......@@ -3469,25 +3399,16 @@ nds32_expand_epilogue_v3pop (bool sibcall_p)
+ 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,
using POSITIVE value to tell that we are increasing
address. */
nds32_emit_adjust_frame (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);
}
/* 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. */
......
......@@ -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.
......
......@@ -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,9 +2119,6 @@ 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);
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