aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMonk Chiang <sh.chiang04@gmail.com>2018-03-12 01:21:57 +0000
committerChung-Ju Wu <jasonwucj@gcc.gnu.org>2018-03-12 01:21:57 +0000
commita6c7e7779ad2330a0e14c87ba0e339367679ed9e (patch)
tree6b0eb6a8d947dd718adb5c3b41c4b4a914480296 /gcc
parent1fdffa310b8ec30ba048c9857316e7f54432d992 (diff)
downloadgcc-a6c7e7779ad2330a0e14c87ba0e339367679ed9e.zip
gcc-a6c7e7779ad2330a0e14c87ba0e339367679ed9e.tar.gz
gcc-a6c7e7779ad2330a0e14c87ba0e339367679ed9e.tar.bz2
[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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog14
-rw-r--r--gcc/config/nds32/nds32.c511
-rw-r--r--gcc/config/nds32/nds32.h17
-rw-r--r--gcc/config/nds32/nds32.md19
4 files changed, 252 insertions, 309 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 85062c06..aad7f0e 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,17 @@
+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
diff --git a/gcc/config/nds32/nds32.c b/gcc/config/nds32/nds32.c
index 3536411..2d644b7 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 6846aef..dc40735 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 71736f6..58a13c1 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;
})