Commit 56ca756c by Alan Modra Committed by Alan Modra

re PR target/53038 (cfi_restore for cr before cr is actually restored)

	PR target/53038
	* config/rs6000/rs6000.c (load_lr_save, restore_saved_lr,
	load_cr_save, add_crlr_cfa_restore): New functions.
	(rs6000_restore_saved_cr): Rename to..
	(restore_saved_cr): ..this.  Add cfa_restore notes for cr.
	(rs6000_emit_epilogue): Use new functions.  Adjust condition
	for emitting lr and cr cfa_restore.  Emit cfa_restores for fp
	regs when using out-of-line restore only when shrink wrapping.

From-SVN: r187010
parent f8e4c7e6
2012-05-01 Alan Modra <amodra@gmail.com>
PR target/53038
* config/rs6000/rs6000.c (load_lr_save, restore_saved_lr,
load_cr_save, add_crlr_cfa_restore): New functions.
(rs6000_restore_saved_cr): Rename to..
(restore_saved_cr): ..this. Add cfa_restore notes for cr.
(rs6000_emit_epilogue): Use new functions. Adjust condition
for emitting lr and cr cfa_restore. Emit cfa_restores for fp
regs when using out-of-line restore only when shrink wrapping.
2012-04-30 Uros Bizjak <ubizjak@gmail.com> 2012-04-30 Uros Bizjak <ubizjak@gmail.com>
PR middle-end/53136 PR middle-end/53136
......
...@@ -952,7 +952,6 @@ static void rs6000_set_default_type_attributes (tree); ...@@ -952,7 +952,6 @@ static void rs6000_set_default_type_attributes (tree);
static bool rs6000_reg_live_or_pic_offset_p (int); static bool rs6000_reg_live_or_pic_offset_p (int);
static tree rs6000_builtin_vectorized_libmass (tree, tree, tree); static tree rs6000_builtin_vectorized_libmass (tree, tree, tree);
static tree rs6000_builtin_vectorized_function (tree, tree, tree); static tree rs6000_builtin_vectorized_function (tree, tree, tree);
static void rs6000_restore_saved_cr (rtx, int);
static bool rs6000_output_addr_const_extra (FILE *, rtx); static bool rs6000_output_addr_const_extra (FILE *, rtx);
static void rs6000_output_function_prologue (FILE *, HOST_WIDE_INT); static void rs6000_output_function_prologue (FILE *, HOST_WIDE_INT);
static void rs6000_output_function_epilogue (FILE *, HOST_WIDE_INT); static void rs6000_output_function_epilogue (FILE *, HOST_WIDE_INT);
...@@ -20276,10 +20275,37 @@ rs6000_output_function_prologue (FILE *file, ...@@ -20276,10 +20275,37 @@ rs6000_output_function_prologue (FILE *file,
we restore after the pop when possible. */ we restore after the pop when possible. */
#define ALWAYS_RESTORE_ALTIVEC_BEFORE_POP 0 #define ALWAYS_RESTORE_ALTIVEC_BEFORE_POP 0
/* Restoring cr is a two step process: loading a reg from the frame
save, then moving the reg to cr. For ABI_V4 we must let the
unwinder know that the stack location is no longer valid at or
before the stack deallocation, but we can't emit a cfa_restore for
cr at the stack deallocation like we do for other registers.
The trouble is that it is possible for the move to cr to be
scheduled after the stack deallocation. So say exactly where cr
is located on each of the two insns. */
static rtx
load_cr_save (int regno, rtx frame_reg_rtx, int offset, bool exit_func)
{
rtx mem = gen_frame_mem_offset (SImode, frame_reg_rtx, offset);
rtx reg = gen_rtx_REG (SImode, regno);
rtx insn = emit_move_insn (reg, mem);
if (!exit_func && DEFAULT_ABI == ABI_V4)
{
rtx cr = gen_rtx_REG (SImode, CR2_REGNO);
rtx set = gen_rtx_SET (VOIDmode, reg, cr);
add_reg_note (insn, REG_CFA_REGISTER, set);
RTX_FRAME_RELATED_P (insn) = 1;
}
return reg;
}
/* Reload CR from REG. */ /* Reload CR from REG. */
static void static void
rs6000_restore_saved_cr (rtx reg, int using_mfcr_multiple) restore_saved_cr (rtx reg, int using_mfcr_multiple, bool exit_func)
{ {
int count = 0; int count = 0;
int i; int i;
...@@ -20317,13 +20343,61 @@ rs6000_restore_saved_cr (rtx reg, int using_mfcr_multiple) ...@@ -20317,13 +20343,61 @@ rs6000_restore_saved_cr (rtx reg, int using_mfcr_multiple)
else else
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
if (df_regs_ever_live_p (CR0_REGNO+i) && ! call_used_regs[CR0_REGNO+i]) if (df_regs_ever_live_p (CR0_REGNO+i) && ! call_used_regs[CR0_REGNO+i])
{ emit_insn (gen_movsi_to_cr_one (gen_rtx_REG (CCmode, CR0_REGNO+i),
emit_insn (gen_movsi_to_cr_one (gen_rtx_REG (CCmode,
CR0_REGNO+i),
reg)); reg));
if (!exit_func && (DEFAULT_ABI == ABI_V4 || flag_shrink_wrap))
{
rtx insn = get_last_insn ();
rtx cr = gen_rtx_REG (SImode, CR2_REGNO);
add_reg_note (insn, REG_CFA_RESTORE, cr);
RTX_FRAME_RELATED_P (insn) = 1;
}
}
/* Like cr, the move to lr instruction can be scheduled after the
stack deallocation, but unlike cr, its stack frame save is still
valid. So we only need to emit the cfa_restore on the correct
instruction. */
static void
load_lr_save (int regno, rtx frame_reg_rtx, int offset)
{
rtx mem = gen_frame_mem_offset (Pmode, frame_reg_rtx, offset);
rtx reg = gen_rtx_REG (Pmode, regno);
emit_move_insn (reg, mem);
}
static void
restore_saved_lr (int regno, bool exit_func)
{
rtx reg = gen_rtx_REG (Pmode, regno);
rtx lr = gen_rtx_REG (Pmode, LR_REGNO);
rtx insn = emit_move_insn (lr, reg);
if (!exit_func && flag_shrink_wrap)
{
add_reg_note (insn, REG_CFA_RESTORE, lr);
RTX_FRAME_RELATED_P (insn) = 1;
} }
} }
static rtx
add_crlr_cfa_restore (const rs6000_stack_t *info, rtx cfa_restores)
{
if (info->cr_save_p)
cfa_restores = alloc_reg_note (REG_CFA_RESTORE,
gen_rtx_REG (SImode, CR2_REGNO),
cfa_restores);
if (info->lr_save_p)
cfa_restores = alloc_reg_note (REG_CFA_RESTORE,
gen_rtx_REG (Pmode, LR_REGNO),
cfa_restores);
return cfa_restores;
}
/* Return true if OFFSET from stack pointer can be clobbered by signals. /* Return true if OFFSET from stack pointer can be clobbered by signals.
V.4 doesn't have any stack cushion, AIX ABIs have 220 or 288 bytes V.4 doesn't have any stack cushion, AIX ABIs have 220 or 288 bytes
below stack pointer not cloberred by signals. */ below stack pointer not cloberred by signals. */
...@@ -20372,6 +20446,7 @@ rs6000_emit_epilogue (int sibcall) ...@@ -20372,6 +20446,7 @@ rs6000_emit_epilogue (int sibcall)
enum machine_mode reg_mode = Pmode; enum machine_mode reg_mode = Pmode;
int reg_size = TARGET_32BIT ? 4 : 8; int reg_size = TARGET_32BIT ? 4 : 8;
int i; int i;
bool exit_func;
unsigned ptr_regno; unsigned ptr_regno;
info = rs6000_stack_info (); info = rs6000_stack_info ();
...@@ -20824,22 +20899,22 @@ rs6000_emit_epilogue (int sibcall) ...@@ -20824,22 +20899,22 @@ rs6000_emit_epilogue (int sibcall)
emit_insn (generate_set_vrsave (reg, info, 1)); emit_insn (generate_set_vrsave (reg, info, 1));
} }
/* If we exit by an out-of-line restore function on ABI_V4 then that
function will deallocate the stack, so we don't need to worry
about the unwinder restoring cr from an invalid stack frame
location. */
exit_func = (!restoring_FPRs_inline
|| (!restoring_GPRs_inline
&& info->first_fp_reg_save == 64));
/* Get the old lr if we saved it. If we are restoring registers /* Get the old lr if we saved it. If we are restoring registers
out-of-line, then the out-of-line routines can do this for us. */ out-of-line, then the out-of-line routines can do this for us. */
if (restore_lr && restoring_GPRs_inline) if (restore_lr && restoring_GPRs_inline)
{ load_lr_save (0, frame_reg_rtx, info->lr_save_offset + frame_off);
rtx mem = gen_frame_mem_offset (Pmode, frame_reg_rtx,
info->lr_save_offset + frame_off);
emit_move_insn (gen_rtx_REG (Pmode, 0), mem);
}
/* Get the old cr if we saved it. */ /* Get the old cr if we saved it. */
if (info->cr_save_p) if (info->cr_save_p)
{ {
rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
GEN_INT (info->cr_save_offset + frame_off));
rtx mem = gen_frame_mem (SImode, addr);
unsigned cr_save_regno = 12; unsigned cr_save_regno = 12;
if (!restoring_GPRs_inline) if (!restoring_GPRs_inline)
...@@ -20857,14 +20932,14 @@ rs6000_emit_epilogue (int sibcall) ...@@ -20857,14 +20932,14 @@ rs6000_emit_epilogue (int sibcall)
else if (REGNO (frame_reg_rtx) == 12) else if (REGNO (frame_reg_rtx) == 12)
cr_save_regno = 11; cr_save_regno = 11;
cr_save_reg = gen_rtx_REG (SImode, cr_save_regno); cr_save_reg = load_cr_save (cr_save_regno, frame_reg_rtx,
emit_move_insn (cr_save_reg, mem); info->cr_save_offset + frame_off,
exit_func);
} }
/* Set LR here to try to overlap restores below. */ /* Set LR here to try to overlap restores below. */
if (restore_lr && restoring_GPRs_inline) if (restore_lr && restoring_GPRs_inline)
emit_move_insn (gen_rtx_REG (Pmode, LR_REGNO), restore_saved_lr (0, exit_func);
gen_rtx_REG (Pmode, 0));
/* Load exception handler data registers, if needed. */ /* Load exception handler data registers, if needed. */
if (crtl->calls_eh_return) if (crtl->calls_eh_return)
...@@ -20983,7 +21058,7 @@ rs6000_emit_epilogue (int sibcall) ...@@ -20983,7 +21058,7 @@ rs6000_emit_epilogue (int sibcall)
frame_off = -end_save; frame_off = -end_save;
if (can_use_exit && info->cr_save_p) if (can_use_exit && info->cr_save_p)
rs6000_restore_saved_cr (cr_save_reg, using_mtcr_multiple); restore_saved_cr (cr_save_reg, using_mtcr_multiple, true);
ptr_off = -end_save; ptr_off = -end_save;
rs6000_emit_savres_rtx (info, ptr_reg, rs6000_emit_savres_rtx (info, ptr_reg,
...@@ -21046,23 +21121,14 @@ rs6000_emit_epilogue (int sibcall) ...@@ -21046,23 +21121,14 @@ rs6000_emit_epilogue (int sibcall)
The cfa_restores must be emitted on or before the insn that The cfa_restores must be emitted on or before the insn that
invalidates the stack, and of course must not be emitted invalidates the stack, and of course must not be emitted
before the insn that actually does the restore. The latter before the insn that actually does the restore. The latter
is why the LR cfa_restore condition below is a little is why it is a bad idea to emit the cfa_restores as a group
complicated. It's also why it is a bad idea to emit the on the last instruction here that actually does a restore:
cfa_restores as a group on the last instruction here that That insn may be reordered with respect to others doing
actually does a restore: That insn may be reordered with restores. */
respect to others doing restores. */
if (info->cr_save_p)
cfa_restores = alloc_reg_note (REG_CFA_RESTORE,
gen_rtx_REG (SImode, CR2_REGNO),
cfa_restores);
if (flag_shrink_wrap if (flag_shrink_wrap
&& (restore_lr
|| (info->lr_save_p
&& !restoring_GPRs_inline && !restoring_GPRs_inline
&& info->first_fp_reg_save == 64))) && info->first_fp_reg_save == 64)
cfa_restores = alloc_reg_note (REG_CFA_RESTORE, cfa_restores = add_crlr_cfa_restore (info, cfa_restores);
gen_rtx_REG (Pmode, LR_REGNO),
cfa_restores);
for (i = info->first_gp_reg_save; i < 32; i++) for (i = info->first_gp_reg_save; i < 32; i++)
if (!restoring_GPRs_inline if (!restoring_GPRs_inline
...@@ -21086,12 +21152,8 @@ rs6000_emit_epilogue (int sibcall) ...@@ -21086,12 +21152,8 @@ rs6000_emit_epilogue (int sibcall)
if (restore_lr && !restoring_GPRs_inline) if (restore_lr && !restoring_GPRs_inline)
{ {
rtx mem = gen_frame_mem_offset (Pmode, frame_reg_rtx, load_lr_save (0, frame_reg_rtx, info->lr_save_offset + frame_off);
info->lr_save_offset + frame_off); restore_saved_lr (0, exit_func);
emit_move_insn (gen_rtx_REG (Pmode, 0), mem);
emit_move_insn (gen_rtx_REG (Pmode, LR_REGNO),
gen_rtx_REG (Pmode, 0));
} }
/* Restore fpr's if we need to do it without calling a function. */ /* Restore fpr's if we need to do it without calling a function. */
...@@ -21118,7 +21180,7 @@ rs6000_emit_epilogue (int sibcall) ...@@ -21118,7 +21180,7 @@ rs6000_emit_epilogue (int sibcall)
/* If we saved cr, restore it here. Just those that were used. */ /* If we saved cr, restore it here. Just those that were used. */
if (info->cr_save_p) if (info->cr_save_p)
rs6000_restore_saved_cr (cr_save_reg, using_mtcr_multiple); restore_saved_cr (cr_save_reg, using_mtcr_multiple, exit_func);
/* If this is V.4, unwind the stack pointer after all of the loads /* If this is V.4, unwind the stack pointer after all of the loads
have been done, or set up r11 if we are restoring fp out of line. */ have been done, or set up r11 if we are restoring fp out of line. */
...@@ -21198,11 +21260,8 @@ rs6000_emit_epilogue (int sibcall) ...@@ -21198,11 +21260,8 @@ rs6000_emit_epilogue (int sibcall)
int i; int i;
rtx sym; rtx sym;
if ((DEFAULT_ABI == ABI_V4 || flag_shrink_wrap) if (flag_shrink_wrap)
&& lr) cfa_restores = add_crlr_cfa_restore (info, cfa_restores);
cfa_restores = alloc_reg_note (REG_CFA_RESTORE,
gen_rtx_REG (Pmode, LR_REGNO),
cfa_restores);
sym = rs6000_savres_routine_sym (info, sym = rs6000_savres_routine_sym (info,
SAVRES_FPR | (lr ? SAVRES_LR : 0)); SAVRES_FPR | (lr ? SAVRES_LR : 0));
...@@ -21221,7 +21280,7 @@ rs6000_emit_epilogue (int sibcall) ...@@ -21221,7 +21280,7 @@ rs6000_emit_epilogue (int sibcall)
reg = gen_rtx_REG (DFmode, info->first_fp_reg_save + i); reg = gen_rtx_REG (DFmode, info->first_fp_reg_save + i);
RTVEC_ELT (p, i + 4) = gen_rtx_SET (VOIDmode, reg, mem); RTVEC_ELT (p, i + 4) = gen_rtx_SET (VOIDmode, reg, mem);
if (DEFAULT_ABI == ABI_V4 || flag_shrink_wrap) if (flag_shrink_wrap)
cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg,
cfa_restores); cfa_restores);
} }
......
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