aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2016-04-30 10:05:39 +0930
committerAlan Modra <amodra@gcc.gnu.org>2016-04-30 10:05:39 +0930
commitcc5f7354319b23401cec9a800fb4f784ec506f21 (patch)
tree9bb07d742197b0598fadbc998abb013b7307d453 /gcc
parent8cd5d1f46ced83c462e6ababeff4b139da889fab (diff)
downloadgcc-cc5f7354319b23401cec9a800fb4f784ec506f21.zip
gcc-cc5f7354319b23401cec9a800fb4f784ec506f21.tar.gz
gcc-cc5f7354319b23401cec9a800fb4f784ec506f21.tar.bz2
[RS6000] Allow saving of fixed regs.
As I noted a long time ago in the comment on fixed_reg_p, the real problem with saving fixed/global regs is that exception frame unwinding might restore them. So don't emit eh_frame info for any such reg, and the unwinder won't restore them. Also, tidy rs6000_savres_strategy. Delaying some checks means we won't iterate over regs quite so often. * config/rs6000/rs6000.c (rs6000_savres_strategy): Force inline restoring when fixed_reg_p, but allow out-of-line or stmw save. Check for user regs later to avoid unnecessary looping over regs. Merge user reg check with non-saved reg check. Don't force inline VR restore when static chain used. (rs6000_frame_related): Omit eh_frame info for user regs when saving. (fixed_regs_p): Delete. From-SVN: r235672
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog11
-rw-r--r--gcc/config/rs6000/rs6000.c167
2 files changed, 98 insertions, 80 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 451ea71..65c5d3f 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,16 @@
2016-04-30 Alan Modra <amodra@gmail.com>
+ * config/rs6000/rs6000.c (rs6000_savres_strategy): Force inline
+ restoring when fixed_reg_p, but allow out-of-line or stmw save.
+ Check for user regs later to avoid unnecessary looping over regs.
+ Merge user reg check with non-saved reg check. Don't force
+ inline VR restore when static chain used.
+ (rs6000_frame_related): Omit eh_frame info for user regs when
+ saving.
+ (fixed_regs_p): Delete.
+
+2016-04-30 Alan Modra <amodra@gmail.com>
+
* config/rs6000/rs6000.c (SAVRES_MULTIPLE): Replace with..
(SAVE_STRATEGY, REST_STRATEGY): ..this. Renumber and sort enum.
Update all uses.
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 7a1d516..0ddb31d 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -23231,7 +23231,10 @@ is_altivec_return_reg (rtx reg, void *xyes)
/* Return whether REG is a global user reg or has been specifed by
- -ffixed-REG. */
+ -ffixed-REG. We should not restore these, and so cannot use
+ lmw or out-of-line restore functions if there are any. We also
+ can't save them (well, emit frame notes for them), because frame
+ unwinding during exception handling will restore saved registers. */
static bool
fixed_reg_p (int reg)
@@ -23247,21 +23250,6 @@ fixed_reg_p (int reg)
return fixed_regs[reg];
}
-/* Look for user-defined global regs or -ffixed-<reg> in the range
- FIRST to LAST-1. We should not restore these, and so cannot use
- lmw or out-of-line restore functions if there are any. We also
- can't save them (well, emit frame notes for them), because frame
- unwinding during exception handling will restore saved registers. */
-
-static bool
-fixed_regs_p (unsigned first, unsigned last)
-{
- while (first < last)
- if (fixed_reg_p (first++))
- return true;
- return false;
-}
-
/* Determine the strategy for savings/restoring registers. */
enum {
@@ -23283,35 +23271,25 @@ rs6000_savres_strategy (rs6000_stack_t *info,
bool using_static_chain_p)
{
int strategy = 0;
- bool lr_save_p;
-
- if (TARGET_MULTIPLE
- && !TARGET_POWERPC64
- && !(TARGET_SPE_ABI && info->spe_64bit_regs_used)
- && info->first_gp_reg_save < 31
- && !fixed_regs_p (info->first_gp_reg_save, 32))
- strategy |= SAVE_MULTIPLE | REST_MULTIPLE;
+ /* Select between in-line and out-of-line save and restore of regs.
+ First, all the obvious cases where we don't use out-of-line. */
if (crtl->calls_eh_return
|| cfun->machine->ra_need_lr)
strategy |= (SAVE_INLINE_FPRS | REST_INLINE_FPRS
| SAVE_INLINE_GPRS | REST_INLINE_GPRS
| SAVE_INLINE_VRS | REST_INLINE_VRS);
+ if (info->first_gp_reg_save == 32)
+ strategy |= SAVE_INLINE_GPRS | REST_INLINE_GPRS;
+
if (info->first_fp_reg_save == 64
/* The out-of-line FP routines use double-precision stores;
we can't use those routines if we don't have such stores. */
- || (TARGET_HARD_FLOAT && !TARGET_DOUBLE_FLOAT)
- || fixed_regs_p (info->first_fp_reg_save, 64))
+ || (TARGET_HARD_FLOAT && !TARGET_DOUBLE_FLOAT))
strategy |= SAVE_INLINE_FPRS | REST_INLINE_FPRS;
- if (info->first_gp_reg_save == 32
- || (!(strategy & (SAVE_MULTIPLE | REST_MULTIPLE))
- && fixed_regs_p (info->first_gp_reg_save, 32)))
- strategy |= SAVE_INLINE_GPRS | REST_INLINE_GPRS;
-
- if (info->first_altivec_reg_save == LAST_ALTIVEC_REGNO + 1
- || fixed_regs_p (info->first_altivec_reg_save, LAST_ALTIVEC_REGNO + 1))
+ if (info->first_altivec_reg_save == LAST_ALTIVEC_REGNO + 1)
strategy |= SAVE_INLINE_VRS | REST_INLINE_VRS;
/* Define cutoff for using out-of-line functions to save registers. */
@@ -23364,72 +23342,91 @@ rs6000_savres_strategy (rs6000_stack_t *info,
&& (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_DARWIN))
strategy |= ((DEFAULT_ABI == ABI_DARWIN ? 0 : SAVE_INLINE_FPRS)
| SAVE_INLINE_GPRS
- | SAVE_INLINE_VRS | REST_INLINE_VRS);
+ | SAVE_INLINE_VRS);
- /* We can only use the out-of-line routines to restore if we've
+ /* Saving CR interferes with the exit routines used on the SPE, so
+ just punt here. */
+ if (TARGET_SPE_ABI
+ && info->spe_64bit_regs_used
+ && info->cr_save_p)
+ strategy |= REST_INLINE_GPRS;
+
+ /* We can only use the out-of-line routines to restore fprs if we've
saved all the registers from first_fp_reg_save in the prologue.
- Otherwise, we risk loading garbage. */
- if ((strategy & (SAVE_INLINE_FPRS | REST_INLINE_FPRS)) == SAVE_INLINE_FPRS)
+ Otherwise, we risk loading garbage. Of course, if we have saved
+ out-of-line then we know we haven't skipped any fprs. */
+ if ((strategy & SAVE_INLINE_FPRS)
+ && !(strategy & REST_INLINE_FPRS))
{
int i;
for (i = info->first_fp_reg_save; i < 64; i++)
- if (!save_reg_p (i))
+ if (fixed_regs[i] || !save_reg_p (i))
{
strategy |= REST_INLINE_FPRS;
break;
}
}
- /* If we are going to use store multiple, then don't even bother
- with the out-of-line routines, since the store-multiple
- instruction will always be smaller. */
- if ((strategy & (SAVE_MULTIPLE | REST_MULTIPLE)))
- strategy |= SAVE_INLINE_GPRS;
-
- /* info->lr_save_p isn't yet set if the only reason lr needs to be
- saved is an out-of-line save or restore. Set up the value for
- the next test (excluding out-of-line gpr restore). */
- lr_save_p = (info->lr_save_p
- || !(strategy & SAVE_INLINE_GPRS)
- || !(strategy & SAVE_INLINE_FPRS)
- || !(strategy & SAVE_INLINE_VRS)
- || !(strategy & REST_INLINE_FPRS)
- || !(strategy & REST_INLINE_VRS));
-
- /* The situation is more complicated with load multiple. We'd
- prefer to use the out-of-line routines for restores, since the
- "exit" out-of-line routines can handle the restore of LR and the
- frame teardown. However if doesn't make sense to use the
- out-of-line routine if that is the only reason we'd need to save
- LR, and we can't use the "exit" out-of-line gpr restore if we
- have saved some fprs; In those cases it is advantageous to use
- load multiple when available. */
- if ((strategy & (SAVE_MULTIPLE | REST_MULTIPLE))
- && (!lr_save_p
- || info->first_fp_reg_save != 64))
- strategy |= REST_INLINE_GPRS;
+ /* Similarly, for altivec regs. */
+ if ((strategy & SAVE_INLINE_VRS)
+ && !(strategy & REST_INLINE_VRS))
+ {
+ int i;
- /* Saving CR interferes with the exit routines used on the SPE, so
- just punt here. */
- if (TARGET_SPE_ABI
- && info->spe_64bit_regs_used
- && info->cr_save_p)
- strategy |= REST_INLINE_GPRS;
+ for (i = info->first_altivec_reg_save; i < LAST_ALTIVEC_REGNO + 1; i++)
+ if (fixed_regs[i] || !save_reg_p (i))
+ {
+ strategy |= REST_INLINE_VRS;
+ break;
+ }
+ }
+
+ if (TARGET_MULTIPLE
+ && !TARGET_POWERPC64
+ && !(TARGET_SPE_ABI && info->spe_64bit_regs_used)
+ && info->first_gp_reg_save != 32)
+ {
+ /* Prefer store multiple for saves over out-of-line routines,
+ since the store-multiple instruction will always be smaller. */
+ strategy |= SAVE_INLINE_GPRS | SAVE_MULTIPLE;
+
+ /* info->lr_save_p isn't yet set if the only reason lr needs to be
+ saved is an out-of-line save or restore. Set up the value for
+ the next test (excluding out-of-line gprs). */
+ bool lr_save_p = (info->lr_save_p
+ || !(strategy & SAVE_INLINE_FPRS)
+ || !(strategy & SAVE_INLINE_VRS)
+ || !(strategy & REST_INLINE_FPRS)
+ || !(strategy & REST_INLINE_VRS));
+
+ /* The situation is more complicated with load multiple. We'd
+ prefer to use the out-of-line routines for restores, since the
+ "exit" out-of-line routines can handle the restore of LR and the
+ frame teardown. However if doesn't make sense to use the
+ out-of-line routine if that is the only reason we'd need to save
+ LR, and we can't use the "exit" out-of-line gpr restore if we
+ have saved some fprs; In those cases it is advantageous to use
+ load multiple when available. */
+ if (info->first_fp_reg_save != 64 || !lr_save_p)
+ strategy |= REST_INLINE_GPRS | REST_MULTIPLE;
+ }
/* We can only use load multiple or the out-of-line routines to
- restore if we've used store multiple or out-of-line routines
- in the prologue, i.e. if we've saved all the registers from
- first_gp_reg_save. Otherwise, we risk loading garbage. */
- if ((strategy & (SAVE_INLINE_GPRS | REST_INLINE_GPRS | SAVE_MULTIPLE | REST_MULTIPLE))
- == SAVE_INLINE_GPRS)
+ restore gprs if we've saved all the registers from
+ first_gp_reg_save. Otherwise, we risk loading garbage.
+ Of course, if we have saved out-of-line or used stmw then we know
+ we haven't skipped any gprs. */
+ if ((strategy & (SAVE_INLINE_GPRS | SAVE_MULTIPLE)) == SAVE_INLINE_GPRS
+ && (strategy & (REST_INLINE_GPRS | REST_MULTIPLE)) != REST_INLINE_GPRS)
{
int i;
for (i = info->first_gp_reg_save; i < 32; i++)
- if (!save_reg_p (i))
+ if (fixed_reg_p (i) || !save_reg_p (i))
{
strategy |= REST_INLINE_GPRS;
+ strategy &= ~REST_MULTIPLE;
break;
}
}
@@ -24702,7 +24699,14 @@ rs6000_frame_related (rtx insn, rtx reg, HOST_WIDE_INT val,
{
rtx set = XVECEXP (real, 0, i);
- RTX_FRAME_RELATED_P (set) = 1;
+ /* If this PARALLEL has been emitted for out-of-line
+ register save functions, or store multiple, then omit
+ eh_frame info for any user-defined global regs. If
+ eh_frame info is supplied, frame unwinding will
+ restore a user reg. */
+ if (!REG_P (SET_SRC (set))
+ || !fixed_reg_p (REGNO (SET_SRC (set))))
+ RTX_FRAME_RELATED_P (set) = 1;
}
RTX_FRAME_RELATED_P (insn) = 1;
return insn;
@@ -24772,7 +24776,10 @@ rs6000_frame_related (rtx insn, rtx reg, HOST_WIDE_INT val,
if (temp)
XEXP (SET_DEST (set), 0) = temp;
}
- RTX_FRAME_RELATED_P (set) = 1;
+ /* Omit eh_frame info for any user-defined global regs. */
+ if (!REG_P (SET_SRC (set))
+ || !fixed_reg_p (REGNO (SET_SRC (set))))
+ RTX_FRAME_RELATED_P (set) = 1;
}
}