Commit b427dd7a by Alan Modra Committed by Alan Modra

rs6000 (SAVE_INLINE_VRS, [...]): Define.

gcc/
	* config/rs6000/rs6000 (SAVE_INLINE_VRS, REST_INLINE_VRS,
	V_SAVE_INLINE, SAVRES_LR, SAVRES_SAVE, SAVRES_REG,
	SAVRES_GPR, SAVRES_FPR, SAVRES_VR): Define.
	(no_global_regs_above): Delete.
	(no_global_regs): New function.
	(rs6000_savres_strategy): Handle vector regs.  Use proper lr_save_p
	value for load multiple test.
	(savres_routine_syms): Increase size.
	(rs6000_savres_routine_name, rs6000_savres_routine_sym,
	ptr_regno_for_savres, rs6000_emit_savres_rtx): Pass in int selector
	rather than a number of boolean flags.  Update all callers.
	(rs6000_savres_routine_name): Generate vector save/restore names.
	(rs6000_savres_routine_sym): Handle vector regs.  Delete forward decl.
	(ptr_regno_for_savres, rs6000_emit_savres_rtx): Likewise.
	(rs6000_emit_prologue): Delete saving_FPRs_inline, saving_GPRs_inline
	and using_store_multiple.  Expand uses.  Don't always use r11 as
	frame reg when needed for out-of-line saves.  Set up initial offset
	for out-of-line vector saves when buying stack frame.  Handle pointer
	reg setup for out-of-line fp save.  Emit call to out-of-line vector
	save function.  Choose r11 or r12 for vrsave reg when available for
	better scheduling.
	(rs6000_output_function_prologue): Don't emit .extern for ELF.
	(rs6000_emit_epilogue): Choose a better frame reg when restoring
	from back-chain to suit out-of-line vector restore functions.  Emit
	call to out-of-line vector restore function.  Adjust register used
	for cr restore.  Tweak pointer register setup for gpr restore.
	* config/rs6000/rs6000.h (FIRST_SAVED_GP_REGNO): Take into account
	FIXED_R13.
	* config/rs6000/sysv4.h (FP_SAVE_INLINE, GP_SAVE_INLINE): Simplify.
	(V_SAVE_INLINE): Define.
	* config/rs6000/altivec.md (save_vregs_*, restore_vregs_*): New insns.
libgcc/
	* config/rs6000/crtsavevr.S: New file.
	* config/rs6000/crtrestvr.S: New file.
	* config/rs6000/t-savresfgpr: Build the above.
	* config/rs6000/t-netbsd: Likewise.

From-SVN: r186800
parent 1bf7c2a7
2012-04-25 Alan Modra <amodra@gmail.com> 2012-04-25 Alan Modra <amodra@gmail.com>
* config/rs6000/rs6000 (SAVE_INLINE_VRS, REST_INLINE_VRS,
V_SAVE_INLINE, SAVRES_LR, SAVRES_SAVE, SAVRES_REG,
SAVRES_GPR, SAVRES_FPR, SAVRES_VR): Define.
(no_global_regs_above): Delete.
(no_global_regs): New function.
(rs6000_savres_strategy): Handle vector regs. Use proper lr_save_p
value for load multiple test.
(savres_routine_syms): Increase size.
(rs6000_savres_routine_name, rs6000_savres_routine_sym,
ptr_regno_for_savres, rs6000_emit_savres_rtx): Pass in int selector
rather than a number of boolean flags. Update all callers.
(rs6000_savres_routine_name): Generate vector save/restore names.
(rs6000_savres_routine_sym): Handle vector regs. Delete forward decl.
(ptr_regno_for_savres, rs6000_emit_savres_rtx): Likewise.
(rs6000_emit_prologue): Delete saving_FPRs_inline, saving_GPRs_inline
and using_store_multiple. Expand uses. Don't always use r11 as
frame reg when needed for out-of-line saves. Set up initial offset
for out-of-line vector saves when buying stack frame. Handle pointer
reg setup for out-of-line fp save. Emit call to out-of-line vector
save function. Choose r11 or r12 for vrsave reg when available for
better scheduling.
(rs6000_output_function_prologue): Don't emit .extern for ELF.
(rs6000_emit_epilogue): Choose a better frame reg when restoring
from back-chain to suit out-of-line vector restore functions. Emit
call to out-of-line vector restore function. Adjust register used
for cr restore. Tweak pointer register setup for gpr restore.
* config/rs6000/rs6000.h (FIRST_SAVED_GP_REGNO): Take into account
FIXED_R13.
* config/rs6000/sysv4.h (FP_SAVE_INLINE, GP_SAVE_INLINE): Simplify.
(V_SAVE_INLINE): Define.
* config/rs6000/altivec.md (save_vregs_*, restore_vregs_*): New insns.
2012-04-25 Alan Modra <amodra@gmail.com>
* config/rs6000/rs6000.c (rs6000_savres_strategy): Allow * config/rs6000/rs6000.c (rs6000_savres_strategy): Allow
out-of-line save/restore for large frames. Don't disable out-of-line save/restore for large frames. Don't disable
out-of-line saves on ABI_AIX when using static chain reg. out-of-line saves on ABI_AIX when using static chain reg.
......
...@@ -313,6 +313,68 @@ ...@@ -313,6 +313,68 @@
"TARGET_MACHO && (DEFAULT_ABI == ABI_DARWIN) && TARGET_32BIT" "TARGET_MACHO && (DEFAULT_ABI == ABI_DARWIN) && TARGET_32BIT"
"b %z1") "b %z1")
;; The save_vregs and restore_vregs patterns don't use memory_operand
;; because (plus (reg) (const_int)) is not a valid vector address.
;; This way is more compact than describing exactly what happens in
;; the out-of-line functions, ie. loading the constant into r11/r12
;; then using indexed addressing, and requires less editing of rtl
;; to describe the operation to dwarf2out_frame_debug_expr.
(define_insn "*save_vregs_<mode>_r11"
[(match_parallel 0 "any_parallel_operand"
[(clobber (reg:P 65))
(use (match_operand:P 1 "symbol_ref_operand" "s"))
(clobber (reg:P 11))
(use (reg:P 0))
(set (mem:V4SI (plus:P (match_operand:P 2 "gpc_reg_operand" "b")
(match_operand:P 3 "short_cint_operand" "I")))
(match_operand:V4SI 4 "gpc_reg_operand" "v"))])]
""
"bl %1"
[(set_attr "type" "branch")
(set_attr "length" "4")])
(define_insn "*save_vregs_<mode>_r12"
[(match_parallel 0 "any_parallel_operand"
[(clobber (reg:P 65))
(use (match_operand:P 1 "symbol_ref_operand" "s"))
(clobber (reg:P 12))
(use (reg:P 0))
(set (mem:V4SI (plus:P (match_operand:P 2 "gpc_reg_operand" "b")
(match_operand:P 3 "short_cint_operand" "I")))
(match_operand:V4SI 4 "gpc_reg_operand" "v"))])]
""
"bl %1"
[(set_attr "type" "branch")
(set_attr "length" "4")])
(define_insn "*restore_vregs_<mode>_r11"
[(match_parallel 0 "any_parallel_operand"
[(clobber (reg:P 65))
(use (match_operand:P 1 "symbol_ref_operand" "s"))
(clobber (reg:P 11))
(use (reg:P 0))
(set (match_operand:V4SI 2 "gpc_reg_operand" "=v")
(mem:V4SI (plus:P (match_operand:P 3 "gpc_reg_operand" "b")
(match_operand:P 4 "short_cint_operand" "I"))))])]
""
"bl %1"
[(set_attr "type" "branch")
(set_attr "length" "4")])
(define_insn "*restore_vregs_<mode>_r12"
[(match_parallel 0 "any_parallel_operand"
[(clobber (reg:P 65))
(use (match_operand:P 1 "symbol_ref_operand" "s"))
(clobber (reg:P 12))
(use (reg:P 0))
(set (match_operand:V4SI 2 "gpc_reg_operand" "=v")
(mem:V4SI (plus:P (match_operand:P 3 "gpc_reg_operand" "b")
(match_operand:P 4 "short_cint_operand" "I"))))])]
""
"bl %1"
[(set_attr "type" "branch")
(set_attr "length" "4")])
;; Simple binary operations. ;; Simple binary operations.
;; add ;; add
......
...@@ -937,7 +937,6 @@ static bool legitimate_small_data_p (enum machine_mode, rtx); ...@@ -937,7 +937,6 @@ static bool legitimate_small_data_p (enum machine_mode, rtx);
static bool legitimate_lo_sum_address_p (enum machine_mode, rtx, int); static bool legitimate_lo_sum_address_p (enum machine_mode, rtx, int);
static struct machine_function * rs6000_init_machine_status (void); static struct machine_function * rs6000_init_machine_status (void);
static bool rs6000_assemble_integer (rtx, unsigned int, int); static bool rs6000_assemble_integer (rtx, unsigned int, int);
static bool no_global_regs_above (int, bool);
#if defined (HAVE_GAS_HIDDEN) && !TARGET_MACHO #if defined (HAVE_GAS_HIDDEN) && !TARGET_MACHO
static void rs6000_assemble_visibility (tree, int); static void rs6000_assemble_visibility (tree, int);
#endif #endif
...@@ -950,7 +949,6 @@ static tree rs6000_handle_struct_attribute (tree *, tree, tree, int, bool *); ...@@ -950,7 +949,6 @@ static tree rs6000_handle_struct_attribute (tree *, tree, tree, int, bool *);
static void rs6000_eliminate_indexed_memrefs (rtx operands[2]); static void rs6000_eliminate_indexed_memrefs (rtx operands[2]);
static const char *rs6000_mangle_type (const_tree); static const char *rs6000_mangle_type (const_tree);
static void rs6000_set_default_type_attributes (tree); static void rs6000_set_default_type_attributes (tree);
static rtx rs6000_savres_routine_sym (rs6000_stack_t *, bool, bool, bool);
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);
...@@ -17405,6 +17403,21 @@ is_altivec_return_reg (rtx reg, void *xyes) ...@@ -17405,6 +17403,21 @@ is_altivec_return_reg (rtx reg, void *xyes)
} }
/* Look for user-defined global regs 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
global_regs_p (unsigned first, unsigned last)
{
while (first < last)
if (global_regs[first++])
return true;
return false;
}
/* Determine the strategy for savings/restoring registers. */ /* Determine the strategy for savings/restoring registers. */
enum { enum {
...@@ -17415,41 +17428,54 @@ enum { ...@@ -17415,41 +17428,54 @@ enum {
REST_INLINE_GPRS = 0x10, REST_INLINE_GPRS = 0x10,
SAVE_NOINLINE_GPRS_SAVES_LR = 0x20, SAVE_NOINLINE_GPRS_SAVES_LR = 0x20,
SAVE_NOINLINE_FPRS_SAVES_LR = 0x40, SAVE_NOINLINE_FPRS_SAVES_LR = 0x40,
REST_NOINLINE_FPRS_DOESNT_RESTORE_LR = 0x80 REST_NOINLINE_FPRS_DOESNT_RESTORE_LR = 0x80,
SAVE_INLINE_VRS = 0x100,
REST_INLINE_VRS = 0x200
}; };
#ifndef V_SAVE_INLINE
#define V_SAVE_INLINE(FIRST_REG) 1
#endif
static int static int
rs6000_savres_strategy (rs6000_stack_t *info, rs6000_savres_strategy (rs6000_stack_t *info,
bool using_static_chain_p) bool using_static_chain_p)
{ {
int strategy = 0; int strategy = 0;
bool lr_save_p;
if (TARGET_MULTIPLE if (TARGET_MULTIPLE
&& !TARGET_POWERPC64 && !TARGET_POWERPC64
&& !(TARGET_SPE_ABI && info->spe_64bit_regs_used) && !(TARGET_SPE_ABI && info->spe_64bit_regs_used)
&& info->first_gp_reg_save < 31 && info->first_gp_reg_save < 31
&& no_global_regs_above (info->first_gp_reg_save, /*gpr=*/true)) && !global_regs_p (info->first_gp_reg_save, 32))
strategy |= SAVRES_MULTIPLE; strategy |= SAVRES_MULTIPLE;
if (crtl->calls_eh_return if (crtl->calls_eh_return
|| cfun->machine->ra_need_lr) || cfun->machine->ra_need_lr)
strategy |= (SAVE_INLINE_FPRS | REST_INLINE_FPRS strategy |= (SAVE_INLINE_FPRS | REST_INLINE_FPRS
| SAVE_INLINE_GPRS | REST_INLINE_GPRS); | SAVE_INLINE_GPRS | REST_INLINE_GPRS
| SAVE_INLINE_VRS | REST_INLINE_VRS);
if (info->first_fp_reg_save == 64 if (info->first_fp_reg_save == 64
|| FP_SAVE_INLINE (info->first_fp_reg_save) || FP_SAVE_INLINE (info->first_fp_reg_save)
/* The out-of-line FP routines use double-precision stores; /* The out-of-line FP routines use double-precision stores;
we can't use those routines if we don't have such stores. */ we can't use those routines if we don't have such stores. */
|| (TARGET_HARD_FLOAT && !TARGET_DOUBLE_FLOAT) || (TARGET_HARD_FLOAT && !TARGET_DOUBLE_FLOAT)
|| !no_global_regs_above (info->first_fp_reg_save, /*gpr=*/false)) || global_regs_p (info->first_fp_reg_save, 64))
strategy |= SAVE_INLINE_FPRS | REST_INLINE_FPRS; strategy |= SAVE_INLINE_FPRS | REST_INLINE_FPRS;
if (info->first_gp_reg_save == 32 if (info->first_gp_reg_save == 32
|| GP_SAVE_INLINE (info->first_gp_reg_save) || GP_SAVE_INLINE (info->first_gp_reg_save)
|| !((strategy & SAVRES_MULTIPLE) || (!(strategy & SAVRES_MULTIPLE)
|| no_global_regs_above (info->first_gp_reg_save, /*gpr=*/true))) && global_regs_p (info->first_gp_reg_save, 32)))
strategy |= SAVE_INLINE_GPRS | REST_INLINE_GPRS; strategy |= SAVE_INLINE_GPRS | REST_INLINE_GPRS;
if (info->first_altivec_reg_save == LAST_ALTIVEC_REGNO + 1
|| V_SAVE_INLINE (info->first_altivec_reg_save)
|| global_regs_p (info->first_altivec_reg_save, LAST_ALTIVEC_REGNO + 1))
strategy |= SAVE_INLINE_VRS | REST_INLINE_VRS;
/* Don't bother to try to save things out-of-line if r11 is occupied /* Don't bother to try to save things out-of-line if r11 is occupied
by the static chain. It would require too much fiddling and the by the static chain. It would require too much fiddling and the
static chain is rarely used anyway. FPRs are saved w.r.t the stack static chain is rarely used anyway. FPRs are saved w.r.t the stack
...@@ -17457,7 +17483,8 @@ rs6000_savres_strategy (rs6000_stack_t *info, ...@@ -17457,7 +17483,8 @@ rs6000_savres_strategy (rs6000_stack_t *info,
if (using_static_chain_p && DEFAULT_ABI != ABI_AIX) if (using_static_chain_p && DEFAULT_ABI != ABI_AIX)
strategy |= ((DEFAULT_ABI == ABI_DARWIN strategy |= ((DEFAULT_ABI == ABI_DARWIN
? 0 : SAVE_INLINE_FPRS | REST_INLINE_FPRS) ? 0 : SAVE_INLINE_FPRS | REST_INLINE_FPRS)
| SAVE_INLINE_GPRS); | SAVE_INLINE_GPRS
| SAVE_INLINE_VRS | REST_INLINE_VRS);
/* If we are going to use store multiple, then don't even bother /* If we are going to use store multiple, then don't even bother
with the out-of-line routines, since the store-multiple with the out-of-line routines, since the store-multiple
...@@ -17465,6 +17492,16 @@ rs6000_savres_strategy (rs6000_stack_t *info, ...@@ -17465,6 +17492,16 @@ rs6000_savres_strategy (rs6000_stack_t *info,
if ((strategy & SAVRES_MULTIPLE)) if ((strategy & SAVRES_MULTIPLE))
strategy |= SAVE_INLINE_GPRS; 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 /* The situation is more complicated with load multiple. We'd
prefer to use the out-of-line routines for restores, since the 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 "exit" out-of-line routines can handle the restore of LR and the
...@@ -17474,7 +17511,7 @@ rs6000_savres_strategy (rs6000_stack_t *info, ...@@ -17474,7 +17511,7 @@ rs6000_savres_strategy (rs6000_stack_t *info,
have saved some fprs; In those cases it is advantageous to use have saved some fprs; In those cases it is advantageous to use
load multiple when available. */ load multiple when available. */
if ((strategy & SAVRES_MULTIPLE) if ((strategy & SAVRES_MULTIPLE)
&& (!info->lr_save_p && (!lr_save_p
|| info->first_fp_reg_save != 64)) || info->first_fp_reg_save != 64))
strategy |= REST_INLINE_GPRS; strategy |= REST_INLINE_GPRS;
...@@ -17868,8 +17905,10 @@ rs6000_stack_info (void) ...@@ -17868,8 +17905,10 @@ rs6000_stack_info (void)
if (!(info_ptr->savres_strategy & SAVE_INLINE_GPRS) if (!(info_ptr->savres_strategy & SAVE_INLINE_GPRS)
|| !(info_ptr->savres_strategy & SAVE_INLINE_FPRS) || !(info_ptr->savres_strategy & SAVE_INLINE_FPRS)
|| !(info_ptr->savres_strategy & SAVE_INLINE_VRS)
|| !(info_ptr->savres_strategy & REST_INLINE_GPRS) || !(info_ptr->savres_strategy & REST_INLINE_GPRS)
|| !(info_ptr->savres_strategy & REST_INLINE_FPRS)) || !(info_ptr->savres_strategy & REST_INLINE_FPRS)
|| !(info_ptr->savres_strategy & REST_INLINE_VRS))
info_ptr->lr_save_p = 1; info_ptr->lr_save_p = 1;
if (info_ptr->lr_save_p) if (info_ptr->lr_save_p)
...@@ -18965,30 +19004,25 @@ gen_frame_mem_offset (enum machine_mode mode, rtx reg, int offset) ...@@ -18965,30 +19004,25 @@ gen_frame_mem_offset (enum machine_mode mode, rtx reg, int offset)
return gen_frame_mem (mode, gen_rtx_PLUS (Pmode, reg, offset_rtx)); return gen_frame_mem (mode, gen_rtx_PLUS (Pmode, reg, offset_rtx));
} }
/* Look for user-defined global regs. We should not save and restore these,
and cannot use stmw/lmw if there are any in its range. */
static bool
no_global_regs_above (int first, bool gpr)
{
int i;
int last = gpr ? 32 : 64;
for (i = first; i < last; i++)
if (global_regs[i])
return false;
return true;
}
#ifndef TARGET_FIX_AND_CONTINUE #ifndef TARGET_FIX_AND_CONTINUE
#define TARGET_FIX_AND_CONTINUE 0 #define TARGET_FIX_AND_CONTINUE 0
#endif #endif
/* It's really GPR 13 and FPR 14, but we need the smaller of the two. */ /* It's really GPR 13 or 14, FPR 14 and VR 20. We need the smallest. */
#define FIRST_SAVRES_REGISTER FIRST_SAVED_GP_REGNO #define FIRST_SAVRES_REGISTER FIRST_SAVED_GP_REGNO
#define LAST_SAVRES_REGISTER 31 #define LAST_SAVRES_REGISTER 31
#define N_SAVRES_REGISTERS (LAST_SAVRES_REGISTER - FIRST_SAVRES_REGISTER + 1) #define N_SAVRES_REGISTERS (LAST_SAVRES_REGISTER - FIRST_SAVRES_REGISTER + 1)
static GTY(()) rtx savres_routine_syms[N_SAVRES_REGISTERS][8]; enum {
SAVRES_LR = 0x1,
SAVRES_SAVE = 0x2,
SAVRES_REG = 0x0c,
SAVRES_GPR = 0,
SAVRES_FPR = 4,
SAVRES_VR = 8
};
static GTY(()) rtx savres_routine_syms[N_SAVRES_REGISTERS][12];
/* Temporary holding space for an out-of-line register save/restore /* Temporary holding space for an out-of-line register save/restore
routine name. */ routine name. */
...@@ -18998,8 +19032,7 @@ static char savres_routine_name[30]; ...@@ -18998,8 +19032,7 @@ static char savres_routine_name[30];
We are saving/restoring GPRs if GPR is true. */ We are saving/restoring GPRs if GPR is true. */
static char * static char *
rs6000_savres_routine_name (rs6000_stack_t *info, int regno, rs6000_savres_routine_name (rs6000_stack_t *info, int regno, int sel)
bool savep, bool gpr, bool lr)
{ {
const char *prefix = ""; const char *prefix = "";
const char *suffix = ""; const char *suffix = "";
...@@ -19035,14 +19068,14 @@ rs6000_savres_routine_name (rs6000_stack_t *info, int regno, ...@@ -19035,14 +19068,14 @@ rs6000_savres_routine_name (rs6000_stack_t *info, int regno,
if (TARGET_SPE) if (TARGET_SPE)
{ {
/* No floating point saves on the SPE. */ /* No floating point saves on the SPE. */
gcc_assert (gpr); gcc_assert ((sel & SAVRES_REG) == SAVRES_GPR);
if (savep) if ((sel & SAVRES_SAVE))
prefix = info->spe_64bit_regs_used ? "_save64gpr_" : "_save32gpr_"; prefix = info->spe_64bit_regs_used ? "_save64gpr_" : "_save32gpr_";
else else
prefix = info->spe_64bit_regs_used ? "_rest64gpr_" : "_rest32gpr_"; prefix = info->spe_64bit_regs_used ? "_rest64gpr_" : "_rest32gpr_";
if (lr) if ((sel & SAVRES_LR))
suffix = "_x"; suffix = "_x";
} }
else if (DEFAULT_ABI == ABI_V4) else if (DEFAULT_ABI == ABI_V4)
...@@ -19050,35 +19083,46 @@ rs6000_savres_routine_name (rs6000_stack_t *info, int regno, ...@@ -19050,35 +19083,46 @@ rs6000_savres_routine_name (rs6000_stack_t *info, int regno,
if (TARGET_64BIT) if (TARGET_64BIT)
goto aix_names; goto aix_names;
if (gpr) if ((sel & SAVRES_REG) == SAVRES_GPR)
prefix = savep ? "_savegpr_" : "_restgpr_"; prefix = (sel & SAVRES_SAVE) ? "_savegpr_" : "_restgpr_";
else if ((sel & SAVRES_REG) == SAVRES_FPR)
prefix = (sel & SAVRES_SAVE) ? "_savefpr_" : "_restfpr_";
else if ((sel & SAVRES_REG) == SAVRES_VR)
prefix = (sel & SAVRES_SAVE) ? "_savevr_" : "_restvr_";
else else
prefix = savep ? "_savefpr_" : "_restfpr_"; abort ();
if (lr) if ((sel & SAVRES_LR))
suffix = "_x"; suffix = "_x";
} }
else if (DEFAULT_ABI == ABI_AIX) else if (DEFAULT_ABI == ABI_AIX)
{ {
#if !defined (POWERPC_LINUX) && !defined (POWERPC_FREEBSD) #if !defined (POWERPC_LINUX) && !defined (POWERPC_FREEBSD)
/* No out-of-line save/restore routines for GPRs on AIX. */ /* No out-of-line save/restore routines for GPRs on AIX. */
gcc_assert (!TARGET_AIX || !gpr); gcc_assert (!TARGET_AIX || (sel & SAVRES_REG) != SAVRES_GPR);
#endif #endif
aix_names: aix_names:
if (gpr) if ((sel & SAVRES_REG) == SAVRES_GPR)
prefix = (savep prefix = ((sel & SAVRES_SAVE)
? (lr ? "_savegpr0_" : "_savegpr1_") ? ((sel & SAVRES_LR) ? "_savegpr0_" : "_savegpr1_")
: (lr ? "_restgpr0_" : "_restgpr1_")); : ((sel & SAVRES_LR) ? "_restgpr0_" : "_restgpr1_"));
else if ((sel & SAVRES_REG) == SAVRES_FPR)
{
#if defined (POWERPC_LINUX) || defined (POWERPC_FREEBSD) #if defined (POWERPC_LINUX) || defined (POWERPC_FREEBSD)
else if (lr) if ((sel & SAVRES_LR))
prefix = (savep ? "_savefpr_" : "_restfpr_"); prefix = ((sel & SAVRES_SAVE) ? "_savefpr_" : "_restfpr_");
else
#endif #endif
else {
{ prefix = (sel & SAVRES_SAVE) ? SAVE_FP_PREFIX : RESTORE_FP_PREFIX;
prefix = savep ? SAVE_FP_PREFIX : RESTORE_FP_PREFIX; suffix = (sel & SAVRES_SAVE) ? SAVE_FP_SUFFIX : RESTORE_FP_SUFFIX;
suffix = savep ? SAVE_FP_SUFFIX : RESTORE_FP_SUFFIX; }
} }
else if ((sel & SAVRES_REG) == SAVRES_VR)
prefix = (sel & SAVRES_SAVE) ? "_savevr_" : "_restvr_";
else
abort ();
} }
if (DEFAULT_ABI == ABI_DARWIN) if (DEFAULT_ABI == ABI_DARWIN)
...@@ -19088,14 +19132,19 @@ rs6000_savres_routine_name (rs6000_stack_t *info, int regno, ...@@ -19088,14 +19132,19 @@ rs6000_savres_routine_name (rs6000_stack_t *info, int regno,
single symbol for the start of save sequence, and the code here single symbol for the start of save sequence, and the code here
embeds an offset into that code on the basis of the first register embeds an offset into that code on the basis of the first register
to be saved. */ to be saved. */
prefix = savep ? "save" : "rest" ; prefix = (sel & SAVRES_SAVE) ? "save" : "rest" ;
if (gpr) if ((sel & SAVRES_REG) == SAVRES_GPR)
sprintf (savres_routine_name, "*%sGPR%s%s%.0d ; %s r%d-r31", sprintf (savres_routine_name, "*%sGPR%s%s%.0d ; %s r%d-r31", prefix,
prefix, (lr ? "x" : ""), (regno == 13 ? "" : "+"), ((sel & SAVRES_LR) ? "x" : ""), (regno == 13 ? "" : "+"),
(regno-13) * 4, prefix, regno); (regno - 13) * 4, prefix, regno);
else if ((sel & SAVRES_REG) == SAVRES_FPR)
sprintf (savres_routine_name, "*%sFP%s%.0d ; %s f%d-f31", prefix,
(regno == 14 ? "" : "+"), (regno - 14) * 4, prefix, regno);
else if ((sel & SAVRES_REG) == SAVRES_VR)
sprintf (savres_routine_name, "*%sVEC%s%.0d ; %s v%d-v31", prefix,
(regno == 20 ? "" : "+"), (regno - 20) * 8, prefix, regno);
else else
sprintf (savres_routine_name, "*%sFP%s%.0d ; %s f%d-f31", abort ();
prefix, (regno == 14 ? "" : "+"), (regno-14) * 4, prefix, regno);
} }
else else
sprintf (savres_routine_name, "%s%d%s", prefix, regno, suffix); sprintf (savres_routine_name, "%s%d%s", prefix, regno, suffix);
...@@ -19107,22 +19156,28 @@ rs6000_savres_routine_name (rs6000_stack_t *info, int regno, ...@@ -19107,22 +19156,28 @@ rs6000_savres_routine_name (rs6000_stack_t *info, int regno,
We are saving/restoring GPRs if GPR is true. */ We are saving/restoring GPRs if GPR is true. */
static rtx static rtx
rs6000_savres_routine_sym (rs6000_stack_t *info, bool savep, rs6000_savres_routine_sym (rs6000_stack_t *info, int sel)
bool gpr, bool lr)
{ {
int regno = gpr ? info->first_gp_reg_save : (info->first_fp_reg_save - 32); int regno = ((sel & SAVRES_REG) == SAVRES_GPR
? info->first_gp_reg_save
: (sel & SAVRES_REG) == SAVRES_FPR
? info->first_fp_reg_save - 32
: (sel & SAVRES_REG) == SAVRES_VR
? info->first_altivec_reg_save - FIRST_ALTIVEC_REGNO
: -1);
rtx sym; rtx sym;
int select = ((savep ? 1 : 0) << 2 int select = sel;
| ((TARGET_SPE_ABI
/* On the SPE, we never have any FPRs, but we do have /* On the SPE, we never have any FPRs, but we do have 32/64-bit
32/64-bit versions of the routines. */ versions of the gpr routines. */
? (info->spe_64bit_regs_used ? 1 : 0) if (TARGET_SPE_ABI && (sel & SAVRES_REG) == SAVRES_GPR
: (gpr ? 1 : 0)) << 1) && info->spe_64bit_regs_used)
| (lr ? 1: 0)); select ^= SAVRES_FPR ^ SAVRES_GPR;
/* Don't generate bogus routine names. */ /* Don't generate bogus routine names. */
gcc_assert (FIRST_SAVRES_REGISTER <= regno gcc_assert (FIRST_SAVRES_REGISTER <= regno
&& regno <= LAST_SAVRES_REGISTER); && regno <= LAST_SAVRES_REGISTER
&& select >= 0 && select <= 12);
sym = savres_routine_syms[regno-FIRST_SAVRES_REGISTER][select]; sym = savres_routine_syms[regno-FIRST_SAVRES_REGISTER][select];
...@@ -19130,7 +19185,7 @@ rs6000_savres_routine_sym (rs6000_stack_t *info, bool savep, ...@@ -19130,7 +19185,7 @@ rs6000_savres_routine_sym (rs6000_stack_t *info, bool savep,
{ {
char *name; char *name;
name = rs6000_savres_routine_name (info, regno, savep, gpr, lr); name = rs6000_savres_routine_name (info, regno, sel);
sym = savres_routine_syms[regno-FIRST_SAVRES_REGISTER][select] sym = savres_routine_syms[regno-FIRST_SAVRES_REGISTER][select]
= gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (name)); = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (name));
...@@ -19176,11 +19231,11 @@ rs6000_emit_stack_reset (rs6000_stack_t *info, ...@@ -19176,11 +19231,11 @@ rs6000_emit_stack_reset (rs6000_stack_t *info,
} }
static inline unsigned static inline unsigned
ptr_regno_for_savres (bool gpr, bool lr) ptr_regno_for_savres (int sel)
{ {
if (DEFAULT_ABI == ABI_AIX) if (DEFAULT_ABI == ABI_AIX)
return !gpr || lr ? 1 : 12; return (sel & SAVRES_REG) == SAVRES_FPR || (sel & SAVRES_LR) ? 1 : 12;
return DEFAULT_ABI == ABI_DARWIN && !gpr ? 1 : 11; return DEFAULT_ABI == ABI_DARWIN && (sel & SAVRES_REG) == SAVRES_FPR ? 1 : 11;
} }
/* Construct a parallel rtx describing the effect of a call to an /* Construct a parallel rtx describing the effect of a call to an
...@@ -19190,8 +19245,7 @@ ptr_regno_for_savres (bool gpr, bool lr) ...@@ -19190,8 +19245,7 @@ ptr_regno_for_savres (bool gpr, bool lr)
static rtx static rtx
rs6000_emit_savres_rtx (rs6000_stack_t *info, rs6000_emit_savres_rtx (rs6000_stack_t *info,
rtx frame_reg_rtx, int save_area_offset, int lr_offset, rtx frame_reg_rtx, int save_area_offset, int lr_offset,
enum machine_mode reg_mode, enum machine_mode reg_mode, int sel)
bool savep, bool gpr, bool lr)
{ {
int i; int i;
int offset, start_reg, end_reg, n_regs, use_reg; int offset, start_reg, end_reg, n_regs, use_reg;
...@@ -19201,25 +19255,46 @@ rs6000_emit_savres_rtx (rs6000_stack_t *info, ...@@ -19201,25 +19255,46 @@ rs6000_emit_savres_rtx (rs6000_stack_t *info,
rtx par, insn; rtx par, insn;
offset = 0; offset = 0;
start_reg = (gpr start_reg = ((sel & SAVRES_REG) == SAVRES_GPR
? info->first_gp_reg_save ? info->first_gp_reg_save
: info->first_fp_reg_save); : (sel & SAVRES_REG) == SAVRES_FPR
end_reg = gpr ? 32 : 64; ? info->first_fp_reg_save
: (sel & SAVRES_REG) == SAVRES_VR
? info->first_altivec_reg_save
: -1);
end_reg = ((sel & SAVRES_REG) == SAVRES_GPR
? 32
: (sel & SAVRES_REG) == SAVRES_FPR
? 64
: (sel & SAVRES_REG) == SAVRES_VR
? LAST_ALTIVEC_REGNO + 1
: -1);
n_regs = end_reg - start_reg; n_regs = end_reg - start_reg;
p = rtvec_alloc ((lr ? 4 : 3) + n_regs); p = rtvec_alloc (3 + ((sel & SAVRES_LR) ? 1 : 0)
+ ((sel & SAVRES_REG) == SAVRES_VR ? 1 : 0)
+ n_regs);
if (!savep && lr) if (!(sel & SAVRES_SAVE) && (sel & SAVRES_LR))
RTVEC_ELT (p, offset++) = ret_rtx; RTVEC_ELT (p, offset++) = ret_rtx;
RTVEC_ELT (p, offset++) RTVEC_ELT (p, offset++)
= gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, LR_REGNO)); = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, LR_REGNO));
sym = rs6000_savres_routine_sym (info, savep, gpr, lr); sym = rs6000_savres_routine_sym (info, sel);
RTVEC_ELT (p, offset++) = gen_rtx_USE (VOIDmode, sym); RTVEC_ELT (p, offset++) = gen_rtx_USE (VOIDmode, sym);
use_reg = ptr_regno_for_savres (gpr, lr);
RTVEC_ELT (p, offset++) use_reg = ptr_regno_for_savres (sel);
= gen_rtx_USE (VOIDmode, if ((sel & SAVRES_REG) == SAVRES_VR)
gen_rtx_REG (Pmode, use_reg)); {
/* Vector regs are saved/restored using [reg+reg] addressing. */
RTVEC_ELT (p, offset++)
= gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, use_reg));
RTVEC_ELT (p, offset++)
= gen_rtx_USE (VOIDmode, gen_rtx_REG (Pmode, 0));
}
else
RTVEC_ELT (p, offset++)
= gen_rtx_USE (VOIDmode, gen_rtx_REG (Pmode, use_reg));
for (i = 0; i < end_reg - start_reg; i++) for (i = 0; i < end_reg - start_reg; i++)
{ {
...@@ -19230,11 +19305,11 @@ rs6000_emit_savres_rtx (rs6000_stack_t *info, ...@@ -19230,11 +19305,11 @@ rs6000_emit_savres_rtx (rs6000_stack_t *info,
mem = gen_frame_mem (reg_mode, addr); mem = gen_frame_mem (reg_mode, addr);
RTVEC_ELT (p, i + offset) = gen_rtx_SET (VOIDmode, RTVEC_ELT (p, i + offset) = gen_rtx_SET (VOIDmode,
savep ? mem : reg, (sel & SAVRES_SAVE) ? mem : reg,
savep ? reg : mem); (sel & SAVRES_SAVE) ? reg : mem);
} }
if (savep && lr) if ((sel & SAVRES_SAVE) && (sel & SAVRES_LR))
{ {
rtx addr, reg, mem; rtx addr, reg, mem;
reg = gen_rtx_REG (Pmode, 0); reg = gen_rtx_REG (Pmode, 0);
...@@ -19246,7 +19321,7 @@ rs6000_emit_savres_rtx (rs6000_stack_t *info, ...@@ -19246,7 +19321,7 @@ rs6000_emit_savres_rtx (rs6000_stack_t *info,
par = gen_rtx_PARALLEL (VOIDmode, p); par = gen_rtx_PARALLEL (VOIDmode, p);
if (!savep && lr) if (!(sel & SAVRES_SAVE) && (sel & SAVRES_LR))
{ {
insn = emit_jump_insn (par); insn = emit_jump_insn (par);
JUMP_LABEL (insn) = ret_rtx; JUMP_LABEL (insn) = ret_rtx;
...@@ -19291,9 +19366,6 @@ rs6000_emit_prologue (void) ...@@ -19291,9 +19366,6 @@ rs6000_emit_prologue (void)
rtx cr_save_rtx = NULL_RTX; rtx cr_save_rtx = NULL_RTX;
rtx insn; rtx insn;
int strategy; int strategy;
int saving_FPRs_inline;
int saving_GPRs_inline;
int using_store_multiple;
int using_static_chain_p = (cfun->static_chain_decl != NULL_TREE int using_static_chain_p = (cfun->static_chain_decl != NULL_TREE
&& df_regs_ever_live_p (STATIC_CHAIN_REGNUM) && df_regs_ever_live_p (STATIC_CHAIN_REGNUM)
&& call_used_regs[STATIC_CHAIN_REGNUM]); && call_used_regs[STATIC_CHAIN_REGNUM]);
...@@ -19469,9 +19541,6 @@ rs6000_emit_prologue (void) ...@@ -19469,9 +19541,6 @@ rs6000_emit_prologue (void)
} }
strategy = info->savres_strategy; strategy = info->savres_strategy;
using_store_multiple = strategy & SAVRES_MULTIPLE;
saving_FPRs_inline = strategy & SAVE_INLINE_FPRS;
saving_GPRs_inline = strategy & SAVE_INLINE_GPRS;
/* For V.4, update stack before we do any saving and set back pointer. */ /* For V.4, update stack before we do any saving and set back pointer. */
if (! WORLD_SAVE_P (info) if (! WORLD_SAVE_P (info)
...@@ -19480,18 +19549,19 @@ rs6000_emit_prologue (void) ...@@ -19480,18 +19549,19 @@ rs6000_emit_prologue (void)
|| crtl->calls_eh_return)) || crtl->calls_eh_return))
{ {
bool need_r11 = (TARGET_SPE bool need_r11 = (TARGET_SPE
? (!saving_GPRs_inline ? (!(strategy & SAVE_INLINE_GPRS)
&& info->spe_64bit_regs_used == 0) && info->spe_64bit_regs_used == 0)
: (!saving_FPRs_inline || !saving_GPRs_inline)); : (!(strategy & SAVE_INLINE_FPRS)
|| !(strategy & SAVE_INLINE_GPRS)
|| !(strategy & SAVE_INLINE_VRS)));
int ptr_regno = -1;
rtx ptr_reg = NULL_RTX; rtx ptr_reg = NULL_RTX;
int ptr_off = 0;
if (need_r11) if (info->total_size < 32767)
{
ptr_reg = gen_rtx_REG (Pmode, 11);
START_USE (11);
}
else if (info->total_size < 32767)
frame_off = info->total_size; frame_off = info->total_size;
else if (need_r11)
ptr_regno = 11;
else if (info->cr_save_p else if (info->cr_save_p
|| info->lr_save_p || info->lr_save_p
|| info->first_fp_reg_save < 64 || info->first_fp_reg_save < 64
...@@ -19499,10 +19569,7 @@ rs6000_emit_prologue (void) ...@@ -19499,10 +19569,7 @@ rs6000_emit_prologue (void)
|| info->altivec_size != 0 || info->altivec_size != 0
|| info->vrsave_mask != 0 || info->vrsave_mask != 0
|| crtl->calls_eh_return) || crtl->calls_eh_return)
{ ptr_regno = 12;
ptr_reg = gen_rtx_REG (Pmode, 12);
START_USE (12);
}
else else
{ {
/* The prologue won't be saving any regs so there is no need /* The prologue won't be saving any regs so there is no need
...@@ -19512,17 +19579,22 @@ rs6000_emit_prologue (void) ...@@ -19512,17 +19579,22 @@ rs6000_emit_prologue (void)
changes to this function. */ changes to this function. */
frame_off = info->total_size; frame_off = info->total_size;
} }
if (ptr_reg != NULL_RTX) if (ptr_regno != -1)
{ {
/* Set up the frame offset to that needed by the first /* Set up the frame offset to that needed by the first
out-of-line save function. */ out-of-line save function. */
START_USE (ptr_regno);
ptr_reg = gen_rtx_REG (Pmode, ptr_regno);
frame_reg_rtx = ptr_reg; frame_reg_rtx = ptr_reg;
if (!saving_FPRs_inline && info->first_fp_reg_save < 64) if (!(strategy & SAVE_INLINE_FPRS) && info->fp_size != 0)
gcc_checking_assert (info->fp_save_offset + info->fp_size == 0); gcc_checking_assert (info->fp_save_offset + info->fp_size == 0);
else if (!saving_GPRs_inline && info->first_gp_reg_save < 32) else if (!(strategy & SAVE_INLINE_GPRS) && info->first_gp_reg_save < 32)
frame_off = -(info->gp_save_offset + info->gp_size); ptr_off = info->gp_save_offset + info->gp_size;
else if (!(strategy & SAVE_INLINE_VRS) && info->altivec_size != 0)
ptr_off = info->altivec_save_offset + info->altivec_size;
frame_off = -ptr_off;
} }
rs6000_emit_allocate_stack (info->total_size, ptr_reg, -frame_off); rs6000_emit_allocate_stack (info->total_size, ptr_reg, ptr_off);
sp_off = info->total_size; sp_off = info->total_size;
if (frame_reg_rtx != sp_reg_rtx) if (frame_reg_rtx != sp_reg_rtx)
rs6000_emit_stack_tie (frame_reg_rtx, false); rs6000_emit_stack_tie (frame_reg_rtx, false);
...@@ -19560,7 +19632,6 @@ rs6000_emit_prologue (void) ...@@ -19560,7 +19632,6 @@ rs6000_emit_prologue (void)
&& !(strategy & (SAVE_INLINE_GPRS && !(strategy & (SAVE_INLINE_GPRS
| SAVE_NOINLINE_GPRS_SAVES_LR)) | SAVE_NOINLINE_GPRS_SAVES_LR))
? 11 : 12); ? 11 : 12);
cr_save_regno = DEFAULT_ABI == ABI_AIX && !saving_GPRs_inline ? 11 : 12;
if (!WORLD_SAVE_P (info) if (!WORLD_SAVE_P (info)
&& info->cr_save_p && info->cr_save_p
&& REGNO (frame_reg_rtx) != cr_save_regno && REGNO (frame_reg_rtx) != cr_save_regno
...@@ -19585,7 +19656,7 @@ rs6000_emit_prologue (void) ...@@ -19585,7 +19656,7 @@ rs6000_emit_prologue (void)
/* Do any required saving of fpr's. If only one or two to save, do /* Do any required saving of fpr's. If only one or two to save, do
it ourselves. Otherwise, call function. */ it ourselves. Otherwise, call function. */
if (!WORLD_SAVE_P (info) && saving_FPRs_inline) if (!WORLD_SAVE_P (info) && (strategy & SAVE_INLINE_FPRS))
{ {
int i; int i;
for (i = 0; i < 64 - info->first_fp_reg_save; i++) for (i = 0; i < 64 - info->first_fp_reg_save; i++)
...@@ -19601,17 +19672,24 @@ rs6000_emit_prologue (void) ...@@ -19601,17 +19672,24 @@ rs6000_emit_prologue (void)
else if (!WORLD_SAVE_P (info) && info->first_fp_reg_save != 64) else if (!WORLD_SAVE_P (info) && info->first_fp_reg_save != 64)
{ {
bool lr = (strategy & SAVE_NOINLINE_FPRS_SAVES_LR) != 0; bool lr = (strategy & SAVE_NOINLINE_FPRS_SAVES_LR) != 0;
unsigned ptr_regno = ptr_regno_for_savres (/*gpr=*/false, lr); int sel = SAVRES_SAVE | SAVRES_FPR | (lr ? SAVRES_LR : 0);
unsigned ptr_regno = ptr_regno_for_savres (sel);
rtx ptr_reg = frame_reg_rtx;
gcc_checking_assert (ptr_regno == REGNO (frame_reg_rtx) if (REGNO (frame_reg_rtx) == ptr_regno)
&& info->fp_save_offset + info->fp_size == 0 gcc_checking_assert (frame_off == 0);
&& frame_off == 0); else
insn = rs6000_emit_savres_rtx (info, frame_reg_rtx, {
ptr_reg = gen_rtx_REG (Pmode, ptr_regno);
NOT_INUSE (ptr_regno);
emit_insn (gen_add3_insn (ptr_reg,
frame_reg_rtx, GEN_INT (frame_off)));
}
insn = rs6000_emit_savres_rtx (info, ptr_reg,
info->fp_save_offset, info->fp_save_offset,
info->lr_save_offset, info->lr_save_offset,
DFmode, DFmode, sel);
/*savep=*/true, /*gpr=*/false, lr); rs6000_frame_related (insn, ptr_reg, sp_off,
rs6000_frame_related (insn, frame_reg_rtx, sp_off,
NULL_RTX, NULL_RTX); NULL_RTX, NULL_RTX);
if (lr) if (lr)
END_USE (0); END_USE (0);
...@@ -19635,7 +19713,7 @@ rs6000_emit_prologue (void) ...@@ -19635,7 +19713,7 @@ rs6000_emit_prologue (void)
int spe_regs_addressable int spe_regs_addressable
= (SPE_CONST_OFFSET_OK (info->spe_gp_save_offset + frame_off = (SPE_CONST_OFFSET_OK (info->spe_gp_save_offset + frame_off
+ reg_size * (32 - info->first_gp_reg_save - 1)) + reg_size * (32 - info->first_gp_reg_save - 1))
&& saving_GPRs_inline); && (strategy & SAVE_INLINE_GPRS));
if (spe_regs_addressable) if (spe_regs_addressable)
{ {
...@@ -19649,7 +19727,7 @@ rs6000_emit_prologue (void) ...@@ -19649,7 +19727,7 @@ rs6000_emit_prologue (void)
it is, then temporarily save it in r0. */ it is, then temporarily save it in r0. */
HOST_WIDE_INT offset; HOST_WIDE_INT offset;
if (!saving_GPRs_inline) if (!(strategy & SAVE_INLINE_GPRS))
ool_adjust = 8 * (info->first_gp_reg_save ool_adjust = 8 * (info->first_gp_reg_save
- (FIRST_SAVRES_REGISTER + 1)); - (FIRST_SAVRES_REGISTER + 1));
offset = info->spe_gp_save_offset + frame_off - ool_adjust; offset = info->spe_gp_save_offset + frame_off - ool_adjust;
...@@ -19674,7 +19752,7 @@ rs6000_emit_prologue (void) ...@@ -19674,7 +19752,7 @@ rs6000_emit_prologue (void)
frame_off = -info->spe_gp_save_offset + ool_adjust; frame_off = -info->spe_gp_save_offset + ool_adjust;
} }
if (saving_GPRs_inline) if ((strategy & SAVE_INLINE_GPRS))
{ {
for (i = 0; i < 32 - info->first_gp_reg_save; i++) for (i = 0; i < 32 - info->first_gp_reg_save; i++)
if (rs6000_reg_live_or_pic_offset_p (info->first_gp_reg_save + i)) if (rs6000_reg_live_or_pic_offset_p (info->first_gp_reg_save + i))
...@@ -19688,10 +19766,8 @@ rs6000_emit_prologue (void) ...@@ -19688,10 +19766,8 @@ rs6000_emit_prologue (void)
{ {
insn = rs6000_emit_savres_rtx (info, spe_save_area_ptr, insn = rs6000_emit_savres_rtx (info, spe_save_area_ptr,
info->spe_gp_save_offset + save_off, info->spe_gp_save_offset + save_off,
info->lr_save_offset + save_off, 0, reg_mode,
reg_mode, SAVRES_SAVE | SAVRES_GPR);
/*savep=*/true, /*gpr=*/true,
/*lr=*/false);
rs6000_frame_related (insn, spe_save_area_ptr, sp_off - save_off, rs6000_frame_related (insn, spe_save_area_ptr, sp_off - save_off,
NULL_RTX, NULL_RTX); NULL_RTX, NULL_RTX);
...@@ -19709,10 +19785,11 @@ rs6000_emit_prologue (void) ...@@ -19709,10 +19785,11 @@ rs6000_emit_prologue (void)
END_USE (11); END_USE (11);
} }
} }
else if (!WORLD_SAVE_P (info) && !saving_GPRs_inline) else if (!WORLD_SAVE_P (info) && !(strategy & SAVE_INLINE_GPRS))
{ {
bool lr = (strategy & SAVE_NOINLINE_GPRS_SAVES_LR) != 0; bool lr = (strategy & SAVE_NOINLINE_GPRS_SAVES_LR) != 0;
unsigned ptr_regno = ptr_regno_for_savres (/*gpr=*/true, lr); int sel = SAVRES_SAVE | SAVRES_GPR | (lr ? SAVRES_LR : 0);
unsigned ptr_regno = ptr_regno_for_savres (sel);
rtx ptr_reg = frame_reg_rtx; rtx ptr_reg = frame_reg_rtx;
bool ptr_set_up = REGNO (ptr_reg) == ptr_regno; bool ptr_set_up = REGNO (ptr_reg) == ptr_regno;
int end_save = info->gp_save_offset + info->gp_size; int end_save = info->gp_save_offset + info->gp_size;
...@@ -19741,14 +19818,13 @@ rs6000_emit_prologue (void) ...@@ -19741,14 +19818,13 @@ rs6000_emit_prologue (void)
insn = rs6000_emit_savres_rtx (info, ptr_reg, insn = rs6000_emit_savres_rtx (info, ptr_reg,
info->gp_save_offset + ptr_off, info->gp_save_offset + ptr_off,
info->lr_save_offset + ptr_off, info->lr_save_offset + ptr_off,
reg_mode, reg_mode, sel);
/*savep=*/true, /*gpr=*/true, lr);
rs6000_frame_related (insn, ptr_reg, sp_off - ptr_off, rs6000_frame_related (insn, ptr_reg, sp_off - ptr_off,
NULL_RTX, NULL_RTX); NULL_RTX, NULL_RTX);
if (lr) if (lr)
END_USE (0); END_USE (0);
} }
else if (!WORLD_SAVE_P (info) && using_store_multiple) else if (!WORLD_SAVE_P (info) && (strategy & SAVRES_MULTIPLE))
{ {
rtvec p; rtvec p;
int i; int i;
...@@ -19908,24 +19984,31 @@ rs6000_emit_prologue (void) ...@@ -19908,24 +19984,31 @@ rs6000_emit_prologue (void)
&& !(DEFAULT_ABI == ABI_V4 || crtl->calls_eh_return)) && !(DEFAULT_ABI == ABI_V4 || crtl->calls_eh_return))
{ {
rtx ptr_reg = NULL; rtx ptr_reg = NULL;
int ptr_off = 0;
/* If saving altivec regs we need to be able to address all save /* If saving altivec regs we need to be able to address all save
locations using a 16-bit offset. */ locations using a 16-bit offset. */
if ((info->altivec_size != 0 if ((strategy & SAVE_INLINE_VRS) == 0
&& (info->altivec_save_offset + info->altivec_size - 16 || (info->altivec_size != 0
+ info->total_size - frame_off) > 32767) && (info->altivec_save_offset + info->altivec_size - 16
+ info->total_size - frame_off) > 32767)
|| (info->vrsave_mask != 0 || (info->vrsave_mask != 0
&& (info->vrsave_save_offset && (info->vrsave_save_offset
+ info->total_size - frame_off) > 32767)) + info->total_size - frame_off) > 32767))
{ {
START_USE (12); int sel = SAVRES_SAVE | SAVRES_VR;
ptr_reg = gen_rtx_REG (Pmode, 12); unsigned ptr_regno = ptr_regno_for_savres (sel);
if (REGNO (frame_reg_rtx) != ptr_regno)
START_USE (ptr_regno);
ptr_reg = gen_rtx_REG (Pmode, ptr_regno);
frame_reg_rtx = ptr_reg; frame_reg_rtx = ptr_reg;
frame_off = -(info->altivec_save_offset + info->altivec_size); ptr_off = info->altivec_save_offset + info->altivec_size;
frame_off = -ptr_off;
} }
else if (REGNO (frame_reg_rtx) == 1) else if (REGNO (frame_reg_rtx) == 1)
frame_off = info->total_size; frame_off = info->total_size;
rs6000_emit_allocate_stack (info->total_size, ptr_reg, -frame_off); rs6000_emit_allocate_stack (info->total_size, ptr_reg, ptr_off);
sp_off = info->total_size; sp_off = info->total_size;
if (frame_reg_rtx != sp_reg_rtx) if (frame_reg_rtx != sp_reg_rtx)
rs6000_emit_stack_tie (frame_reg_rtx, false); rs6000_emit_stack_tie (frame_reg_rtx, false);
...@@ -19940,13 +20023,48 @@ rs6000_emit_prologue (void) ...@@ -19940,13 +20023,48 @@ rs6000_emit_prologue (void)
} }
/* Save AltiVec registers if needed. Save here because the red zone does /* Save AltiVec registers if needed. Save here because the red zone does
not include AltiVec registers. */ not always include AltiVec registers. */
if (!WORLD_SAVE_P (info) && TARGET_ALTIVEC_ABI && info->altivec_size != 0) if (!WORLD_SAVE_P (info) && TARGET_ALTIVEC_ABI
&& info->altivec_size != 0 && (strategy & SAVE_INLINE_VRS) == 0)
{
int end_save = info->altivec_save_offset + info->altivec_size;
int ptr_off;
/* Oddly, the vector save/restore functions point r0 at the end
of the save area, then use r11 or r12 to load offsets for
[reg+reg] addressing. */
rtx ptr_reg = gen_rtx_REG (Pmode, 0);
int scratch_regno = ptr_regno_for_savres (SAVRES_SAVE | SAVRES_VR);
rtx scratch_reg = gen_rtx_REG (Pmode, scratch_regno);
gcc_checking_assert (scratch_regno == 11 || scratch_regno == 12);
NOT_INUSE (0);
if (end_save + frame_off != 0)
{
rtx offset = GEN_INT (end_save + frame_off);
emit_insn (gen_add3_insn (ptr_reg, frame_reg_rtx, offset));
}
else
emit_move_insn (ptr_reg, frame_reg_rtx);
ptr_off = -end_save;
insn = rs6000_emit_savres_rtx (info, scratch_reg,
info->altivec_save_offset + ptr_off,
0, V4SImode, SAVRES_SAVE | SAVRES_VR);
rs6000_frame_related (insn, scratch_reg, sp_off - ptr_off,
NULL_RTX, NULL_RTX);
if (REGNO (frame_reg_rtx) == REGNO (scratch_reg))
{
/* The oddity mentioned above clobbered our frame reg. */
emit_move_insn (frame_reg_rtx, ptr_reg);
frame_off = ptr_off;
}
}
else if (!WORLD_SAVE_P (info) && TARGET_ALTIVEC_ABI
&& info->altivec_size != 0)
{ {
int i; int i;
/* There should be a non inline version of this, for when we
are saving lots of vector registers. */
for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i) for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
if (info->vrsave_mask & ALTIVEC_REG_BIT (i)) if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
{ {
...@@ -19987,12 +20105,23 @@ rs6000_emit_prologue (void) ...@@ -19987,12 +20105,23 @@ rs6000_emit_prologue (void)
{ {
rtx reg, mem, vrsave; rtx reg, mem, vrsave;
int offset; int offset;
int save_regno;
/* Get VRSAVE onto a GPR. Note that ABI_V4 might be using r12 /* Get VRSAVE onto a GPR. Note that ABI_V4 might be using r12
as frame_reg_rtx and r11 as the static chain pointer for as frame_reg_rtx and r11 as the static chain pointer for
nested functions. */ nested functions. */
NOT_INUSE (0); save_regno = 12;
reg = gen_rtx_REG (SImode, 0); if (DEFAULT_ABI == ABI_AIX && !using_static_chain_p)
save_regno = 11;
else if (REGNO (frame_reg_rtx) == 12)
{
save_regno = 11;
if (using_static_chain_p)
save_regno = 0;
}
NOT_INUSE (save_regno);
reg = gen_rtx_REG (SImode, save_regno);
vrsave = gen_rtx_REG (SImode, VRSAVE_REGNO); vrsave = gen_rtx_REG (SImode, VRSAVE_REGNO);
if (TARGET_MACHO) if (TARGET_MACHO)
emit_insn (gen_get_vrsave_internal (reg)); emit_insn (gen_get_vrsave_internal (reg));
...@@ -20105,21 +20234,25 @@ rs6000_output_function_prologue (FILE *file, ...@@ -20105,21 +20234,25 @@ rs6000_output_function_prologue (FILE *file,
/* Write .extern for any function we will call to save and restore /* Write .extern for any function we will call to save and restore
fp values. */ fp values. */
if (info->first_fp_reg_save < 64 if (info->first_fp_reg_save < 64
&& !TARGET_MACHO) && !TARGET_MACHO
&& !TARGET_ELF)
{ {
char *name; char *name;
int regno = info->first_fp_reg_save - 32; int regno = info->first_fp_reg_save - 32;
if ((info->savres_strategy & SAVE_INLINE_FPRS) == 0) if ((info->savres_strategy & SAVE_INLINE_FPRS) == 0)
{ {
name = rs6000_savres_routine_name (info, regno, /*savep=*/true, bool lr = (info->savres_strategy & SAVE_NOINLINE_FPRS_SAVES_LR) != 0;
/*gpr=*/false, /*lr=*/false); int sel = SAVRES_SAVE | SAVRES_FPR | (lr ? SAVRES_LR : 0);
name = rs6000_savres_routine_name (info, regno, sel);
fprintf (file, "\t.extern %s\n", name); fprintf (file, "\t.extern %s\n", name);
} }
if ((info->savres_strategy & REST_INLINE_FPRS) == 0) if ((info->savres_strategy & REST_INLINE_FPRS) == 0)
{ {
name = rs6000_savres_routine_name (info, regno, /*savep=*/false, bool lr = (info->savres_strategy
/*gpr=*/false, /*lr=*/true); & REST_NOINLINE_FPRS_DOESNT_RESTORE_LR) == 0;
int sel = SAVRES_FPR | (lr ? SAVRES_LR : 0);
name = rs6000_savres_routine_name (info, regno, sel);
fprintf (file, "\t.extern %s\n", name); fprintf (file, "\t.extern %s\n", name);
} }
} }
...@@ -20398,10 +20531,20 @@ rs6000_emit_epilogue (int sibcall) ...@@ -20398,10 +20531,20 @@ rs6000_emit_epilogue (int sibcall)
&& offset_below_red_zone_p (info->altivec_save_offset)))) && offset_below_red_zone_p (info->altivec_save_offset))))
{ {
int i; int i;
int scratch_regno = ptr_regno_for_savres (SAVRES_VR);
gcc_checking_assert (scratch_regno == 11 || scratch_regno == 12);
if (use_backchain_to_restore_sp) if (use_backchain_to_restore_sp)
{ {
frame_reg_rtx = gen_rtx_REG (Pmode, 11); int frame_regno = 11;
if ((strategy & REST_INLINE_VRS) == 0)
{
/* Of r11 and r12, select the one not clobbered by an
out-of-line restore function for the frame register. */
frame_regno = 11 + 12 - scratch_regno;
}
frame_reg_rtx = gen_rtx_REG (Pmode, frame_regno);
emit_move_insn (frame_reg_rtx, emit_move_insn (frame_reg_rtx,
gen_rtx_MEM (Pmode, sp_reg_rtx)); gen_rtx_MEM (Pmode, sp_reg_rtx));
frame_off = 0; frame_off = 0;
...@@ -20409,29 +20552,59 @@ rs6000_emit_epilogue (int sibcall) ...@@ -20409,29 +20552,59 @@ rs6000_emit_epilogue (int sibcall)
else if (frame_pointer_needed) else if (frame_pointer_needed)
frame_reg_rtx = hard_frame_pointer_rtx; frame_reg_rtx = hard_frame_pointer_rtx;
for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i) if ((strategy & REST_INLINE_VRS) == 0)
if (info->vrsave_mask & ALTIVEC_REG_BIT (i)) {
{ int end_save = info->altivec_save_offset + info->altivec_size;
rtx addr, areg, mem, reg; int ptr_off;
rtx ptr_reg = gen_rtx_REG (Pmode, 0);
rtx scratch_reg = gen_rtx_REG (Pmode, scratch_regno);
areg = gen_rtx_REG (Pmode, 0); if (end_save + frame_off != 0)
emit_move_insn {
(areg, GEN_INT (info->altivec_save_offset rtx offset = GEN_INT (end_save + frame_off);
+ frame_off
+ 16 * (i - info->first_altivec_reg_save)));
/* AltiVec addressing mode is [reg+reg]. */ emit_insn (gen_add3_insn (ptr_reg, frame_reg_rtx, offset));
addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, areg); }
mem = gen_frame_mem (V4SImode, addr); else
emit_move_insn (ptr_reg, frame_reg_rtx);
reg = gen_rtx_REG (V4SImode, i); ptr_off = -end_save;
emit_move_insn (reg, mem); insn = rs6000_emit_savres_rtx (info, scratch_reg,
if (flag_shrink_wrap info->altivec_save_offset + ptr_off,
|| offset_below_red_zone_p (info->altivec_save_offset 0, V4SImode, SAVRES_VR);
+ (i - info->first_altivec_reg_save) }
* 16)) else
cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, {
cfa_restores); for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
{
rtx addr, areg, mem, reg;
areg = gen_rtx_REG (Pmode, 0);
emit_move_insn
(areg, GEN_INT (info->altivec_save_offset
+ frame_off
+ 16 * (i - info->first_altivec_reg_save)));
/* AltiVec addressing mode is [reg+reg]. */
addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, areg);
mem = gen_frame_mem (V4SImode, addr);
reg = gen_rtx_REG (V4SImode, i);
emit_move_insn (reg, mem);
}
}
for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
if (((strategy & REST_INLINE_VRS) == 0
|| (info->vrsave_mask & ALTIVEC_REG_BIT (i)) != 0)
&& (flag_shrink_wrap
|| (offset_below_red_zone_p
(info->altivec_save_offset
+ 16 * (i - info->first_altivec_reg_save)))))
{
rtx reg = gen_rtx_REG (V4SImode, i);
cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores);
} }
} }
...@@ -20541,26 +20714,94 @@ rs6000_emit_epilogue (int sibcall) ...@@ -20541,26 +20714,94 @@ rs6000_emit_epilogue (int sibcall)
{ {
int i; int i;
for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i) if ((strategy & REST_INLINE_VRS) == 0)
if (info->vrsave_mask & ALTIVEC_REG_BIT (i)) {
{ int end_save = info->altivec_save_offset + info->altivec_size;
rtx addr, areg, mem, reg; int ptr_off;
rtx ptr_reg = gen_rtx_REG (Pmode, 0);
int scratch_regno = ptr_regno_for_savres (SAVRES_VR);
rtx scratch_reg = gen_rtx_REG (Pmode, scratch_regno);
areg = gen_rtx_REG (Pmode, 0); if (end_save + frame_off != 0)
emit_move_insn {
(areg, GEN_INT (info->altivec_save_offset rtx offset = GEN_INT (end_save + frame_off);
+ frame_off
+ 16 * (i - info->first_altivec_reg_save)));
/* AltiVec addressing mode is [reg+reg]. */ emit_insn (gen_add3_insn (ptr_reg, frame_reg_rtx, offset));
addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, areg); }
mem = gen_frame_mem (V4SImode, addr); else
emit_move_insn (ptr_reg, frame_reg_rtx);
reg = gen_rtx_REG (V4SImode, i); ptr_off = -end_save;
emit_move_insn (reg, mem); insn = rs6000_emit_savres_rtx (info, scratch_reg,
if (DEFAULT_ABI == ABI_V4 || flag_shrink_wrap) info->altivec_save_offset + ptr_off,
cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, 0, V4SImode, SAVRES_VR);
cfa_restores); if (REGNO (frame_reg_rtx) == REGNO (scratch_reg))
{
/* Frame reg was clobbered by out-of-line save. Restore it
from ptr_reg, and if we are calling out-of-line gpr or
fpr restore set up the correct pointer and offset. */
unsigned newptr_regno = 1;
if (!restoring_GPRs_inline)
{
bool lr = info->gp_save_offset + info->gp_size == 0;
int sel = SAVRES_GPR | (lr ? SAVRES_LR : 0);
newptr_regno = ptr_regno_for_savres (sel);
end_save = info->gp_save_offset + info->gp_size;
}
else if (!restoring_FPRs_inline)
{
bool lr = !(strategy & REST_NOINLINE_FPRS_DOESNT_RESTORE_LR);
int sel = SAVRES_FPR | (lr ? SAVRES_LR : 0);
newptr_regno = ptr_regno_for_savres (sel);
end_save = info->gp_save_offset + info->gp_size;
}
if (newptr_regno != 1 && REGNO (frame_reg_rtx) != newptr_regno)
frame_reg_rtx = gen_rtx_REG (Pmode, newptr_regno);
if (end_save + ptr_off != 0)
{
rtx offset = GEN_INT (end_save + ptr_off);
frame_off = -end_save;
emit_insn (gen_add3_insn (frame_reg_rtx, ptr_reg, offset));
}
else
{
frame_off = ptr_off;
emit_move_insn (frame_reg_rtx, ptr_reg);
}
}
}
else
{
for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
{
rtx addr, areg, mem, reg;
areg = gen_rtx_REG (Pmode, 0);
emit_move_insn
(areg, GEN_INT (info->altivec_save_offset
+ frame_off
+ 16 * (i - info->first_altivec_reg_save)));
/* AltiVec addressing mode is [reg+reg]. */
addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, areg);
mem = gen_frame_mem (V4SImode, addr);
reg = gen_rtx_REG (V4SImode, i);
emit_move_insn (reg, mem);
}
}
for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
if (((strategy & REST_INLINE_VRS) == 0
|| (info->vrsave_mask & ALTIVEC_REG_BIT (i)) != 0)
&& (DEFAULT_ABI == ABI_V4 || flag_shrink_wrap))
{
rtx reg = gen_rtx_REG (V4SImode, i);
cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores);
} }
} }
...@@ -20599,12 +20840,24 @@ rs6000_emit_epilogue (int sibcall) ...@@ -20599,12 +20840,24 @@ rs6000_emit_epilogue (int sibcall)
rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
GEN_INT (info->cr_save_offset + frame_off)); GEN_INT (info->cr_save_offset + frame_off));
rtx mem = gen_frame_mem (SImode, addr); rtx mem = gen_frame_mem (SImode, addr);
unsigned cr_save_regno = 12;
if (!restoring_GPRs_inline)
{
/* Ensure we don't use the register used by the out-of-line
gpr register restore below. */
bool lr = info->gp_save_offset + info->gp_size == 0;
int sel = SAVRES_GPR | (lr ? SAVRES_LR : 0);
int gpr_ptr_regno = ptr_regno_for_savres (sel);
if (gpr_ptr_regno == 12)
cr_save_regno = 11;
gcc_checking_assert (REGNO (frame_reg_rtx) != cr_save_regno);
}
else if (REGNO (frame_reg_rtx) == 12)
cr_save_regno = 11;
cr_save_reg = gen_rtx_REG (SImode, cr_save_reg = gen_rtx_REG (SImode, cr_save_regno);
DEFAULT_ABI == ABI_AIX
&& !restoring_GPRs_inline
&& info->first_fp_reg_save < 64
? 11 : 12);
emit_move_insn (cr_save_reg, mem); emit_move_insn (cr_save_reg, mem);
} }
...@@ -20705,8 +20958,7 @@ rs6000_emit_epilogue (int sibcall) ...@@ -20705,8 +20958,7 @@ rs6000_emit_epilogue (int sibcall)
info->spe_gp_save_offset + frame_off, info->spe_gp_save_offset + frame_off,
info->lr_save_offset + frame_off, info->lr_save_offset + frame_off,
reg_mode, reg_mode,
/*savep=*/false, /*gpr=*/true, SAVRES_GPR | SAVRES_LR);
/*lr=*/true);
} }
else if (!restoring_GPRs_inline) else if (!restoring_GPRs_inline)
{ {
...@@ -20714,16 +20966,19 @@ rs6000_emit_epilogue (int sibcall) ...@@ -20714,16 +20966,19 @@ rs6000_emit_epilogue (int sibcall)
rtx ptr_reg; rtx ptr_reg;
int end_save = info->gp_save_offset + info->gp_size; int end_save = info->gp_save_offset + info->gp_size;
bool can_use_exit = end_save == 0; bool can_use_exit = end_save == 0;
int sel = SAVRES_GPR | (can_use_exit ? SAVRES_LR : 0);
int ptr_off; int ptr_off;
/* Emit stack reset code if we need it. */ /* Emit stack reset code if we need it. */
ptr_regno = ptr_regno_for_savres (/*gpr=*/true, can_use_exit); ptr_regno = ptr_regno_for_savres (sel);
ptr_reg = gen_rtx_REG (Pmode, ptr_regno); ptr_reg = gen_rtx_REG (Pmode, ptr_regno);
if (can_use_exit) if (can_use_exit)
rs6000_emit_stack_reset (info, frame_reg_rtx, frame_off, ptr_regno); rs6000_emit_stack_reset (info, frame_reg_rtx, frame_off, ptr_regno);
else else if (end_save + frame_off != 0)
emit_insn (gen_add3_insn (ptr_reg, frame_reg_rtx, emit_insn (gen_add3_insn (ptr_reg, frame_reg_rtx,
GEN_INT (end_save + frame_off))); GEN_INT (end_save + frame_off)));
else if (REGNO (frame_reg_rtx) != ptr_regno)
emit_move_insn (ptr_reg, frame_reg_rtx);
if (REGNO (frame_reg_rtx) == ptr_regno) if (REGNO (frame_reg_rtx) == ptr_regno)
frame_off = -end_save; frame_off = -end_save;
...@@ -20734,9 +20989,7 @@ rs6000_emit_epilogue (int sibcall) ...@@ -20734,9 +20989,7 @@ rs6000_emit_epilogue (int sibcall)
rs6000_emit_savres_rtx (info, ptr_reg, rs6000_emit_savres_rtx (info, ptr_reg,
info->gp_save_offset + ptr_off, info->gp_save_offset + ptr_off,
info->lr_save_offset + ptr_off, info->lr_save_offset + ptr_off,
reg_mode, reg_mode, sel);
/*savep=*/false, /*gpr=*/true,
/*lr=*/can_use_exit);
} }
else if (using_load_multiple) else if (using_load_multiple)
{ {
...@@ -20873,7 +21126,8 @@ rs6000_emit_epilogue (int sibcall) ...@@ -20873,7 +21126,8 @@ rs6000_emit_epilogue (int sibcall)
if (!restoring_FPRs_inline) if (!restoring_FPRs_inline)
{ {
bool lr = (strategy & REST_NOINLINE_FPRS_DOESNT_RESTORE_LR) == 0; bool lr = (strategy & REST_NOINLINE_FPRS_DOESNT_RESTORE_LR) == 0;
ptr_regno = ptr_regno_for_savres (/*gpr=*/false, lr); int sel = SAVRES_FPR | (lr ? SAVRES_LR : 0);
ptr_regno = ptr_regno_for_savres (sel);
} }
insn = rs6000_emit_stack_reset (info, frame_reg_rtx, frame_off, ptr_regno); insn = rs6000_emit_stack_reset (info, frame_reg_rtx, frame_off, ptr_regno);
...@@ -20951,9 +21205,7 @@ rs6000_emit_epilogue (int sibcall) ...@@ -20951,9 +21205,7 @@ rs6000_emit_epilogue (int sibcall)
cfa_restores); cfa_restores);
sym = rs6000_savres_routine_sym (info, sym = rs6000_savres_routine_sym (info,
/*savep=*/false, SAVRES_FPR | (lr ? SAVRES_LR : 0));
/*gpr=*/false,
/*lr=*/lr);
RTVEC_ELT (p, 2) = gen_rtx_USE (VOIDmode, sym); RTVEC_ELT (p, 2) = gen_rtx_USE (VOIDmode, sym);
RTVEC_ELT (p, 3) = gen_rtx_USE (VOIDmode, RTVEC_ELT (p, 3) = gen_rtx_USE (VOIDmode,
gen_rtx_REG (Pmode, gen_rtx_REG (Pmode,
......
...@@ -909,8 +909,8 @@ extern unsigned rs6000_pointer_size; ...@@ -909,8 +909,8 @@ extern unsigned rs6000_pointer_size;
#define TOTAL_ALTIVEC_REGS (LAST_ALTIVEC_REGNO - FIRST_ALTIVEC_REGNO + 1) #define TOTAL_ALTIVEC_REGS (LAST_ALTIVEC_REGNO - FIRST_ALTIVEC_REGNO + 1)
#define FIRST_SAVED_ALTIVEC_REGNO (FIRST_ALTIVEC_REGNO+20) #define FIRST_SAVED_ALTIVEC_REGNO (FIRST_ALTIVEC_REGNO+20)
#define FIRST_SAVED_FP_REGNO (14+32) #define FIRST_SAVED_FP_REGNO (14+32)
#define FIRST_SAVED_GP_REGNO 13 #define FIRST_SAVED_GP_REGNO (FIXED_R13 ? 14 : 13)
/* List the order in which to allocate registers. Each register must be /* List the order in which to allocate registers. Each register must be
listed once, even those in FIXED_REGISTERS. listed once, even those in FIXED_REGISTERS.
......
...@@ -245,13 +245,16 @@ do { \ ...@@ -245,13 +245,16 @@ do { \
/* Define cutoff for using external functions to save floating point. /* Define cutoff for using external functions to save floating point.
When optimizing for size, use external functions when profitable. */ When optimizing for size, use external functions when profitable. */
#define FP_SAVE_INLINE(FIRST_REG) (optimize_size \ #define FP_SAVE_INLINE(FIRST_REG) ((FIRST_REG) == 62 \
? ((FIRST_REG) == 62 \ || (FIRST_REG) == 63 \
|| (FIRST_REG) == 63) \ || !optimize_size)
: (FIRST_REG) < 64)
/* And similarly for general purpose registers. */ /* And similarly for general purpose registers. */
#define GP_SAVE_INLINE(FIRST_REG) ((FIRST_REG) < 32 \ #define GP_SAVE_INLINE(FIRST_REG) (!optimize_size)
&& !optimize_size)
/* And vector registers. */
#define V_SAVE_INLINE(FIRST_REG) ((FIRST_REG) == LAST_ALTIVEC_REGNO \
|| !optimize_size)
/* Put jump tables in read-only memory, rather than in .text. */ /* Put jump tables in read-only memory, rather than in .text. */
#define JUMP_TABLES_IN_TEXT_SECTION 0 #define JUMP_TABLES_IN_TEXT_SECTION 0
......
2012-04-25 Alan Modra <amodra@gmail.com>
* config/rs6000/crtsavevr.S: New file.
* config/rs6000/crtrestvr.S: New file.
* config/rs6000/t-savresfgpr: Build the above.
* config/rs6000/t-netbsd: Likewise.
2012-04-24 Sriraman Tallam <tmsriram@google.com> 2012-04-24 Sriraman Tallam <tmsriram@google.com>
* libgcc/config/i386/i386-cpuinfo.c: Set __cpu_vendor always. * libgcc/config/i386/i386-cpuinfo.c: Set __cpu_vendor always.
......
/* Routines for restoring vector registers.
Copyright (C) 2012
Free Software Foundation, Inc.
Written by Alan Modra, IBM
This file is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
later version.
This file is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
Under Section 7 of GPL version 3, you are granted additional
permissions described in the GCC Runtime Library Exception, version
3.1, as published by the Free Software Foundation.
You should have received a copy of the GNU General Public License and
a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */
/* On PowerPC64 Linux, these functions are provided by the linker. */
#ifndef __powerpc64__
#undef __ALTIVEC__
#define __ALTIVEC__ 1
#include "ppc-asm.h"
/* Called with r0 pointing just beyond the end of the vector save area. */
.section ".text"
CFI_STARTPROC
HIDDEN_FUNC(_restvr_20)
li r11,-192
lvx v20,r11,r0
HIDDEN_FUNC(_restvr_21)
li r11,-176
lvx v21,r11,r0
HIDDEN_FUNC(_restvr_22)
li r11,-160
lvx v22,r11,r0
HIDDEN_FUNC(_restvr_23)
li r11,-144
lvx v23,r11,r0
HIDDEN_FUNC(_restvr_24)
li r11,-128
lvx v24,r11,r0
HIDDEN_FUNC(_restvr_25)
li r11,-112
lvx v25,r11,r0
HIDDEN_FUNC(_restvr_26)
li r11,-96
lvx v26,r11,r0
HIDDEN_FUNC(_restvr_27)
li r11,-80
lvx v27,r11,r0
HIDDEN_FUNC(_restvr_28)
li r11,-64
lvx v28,r11,r0
HIDDEN_FUNC(_restvr_29)
li r11,-48
lvx v29,r11,r0
HIDDEN_FUNC(_restvr_30)
li r11,-32
lvx v30,r11,r0
HIDDEN_FUNC(_restvr_31)
li r11,-16
lvx v31,r11,r0
blr
FUNC_END(_restvr_31)
FUNC_END(_restvr_30)
FUNC_END(_restvr_29)
FUNC_END(_restvr_28)
FUNC_END(_restvr_27)
FUNC_END(_restvr_26)
FUNC_END(_restvr_25)
FUNC_END(_restvr_24)
FUNC_END(_restvr_23)
FUNC_END(_restvr_22)
FUNC_END(_restvr_21)
FUNC_END(_restvr_20)
CFI_ENDPROC
#endif
/* Routines for saving vector registers.
Copyright (C) 2012
Free Software Foundation, Inc.
Written by Alan Modra, IBM
This file is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
later version.
This file is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
Under Section 7 of GPL version 3, you are granted additional
permissions described in the GCC Runtime Library Exception, version
3.1, as published by the Free Software Foundation.
You should have received a copy of the GNU General Public License and
a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */
/* On PowerPC64 Linux, these functions are provided by the linker. */
#ifndef __powerpc64__
#undef __ALTIVEC__
#define __ALTIVEC__ 1
#include "ppc-asm.h"
/* Called with r0 pointing just beyond the end of the vector save area. */
.section ".text"
CFI_STARTPROC
HIDDEN_FUNC(_savevr_20)
li r11,-192
stvx v20,r11,r0
HIDDEN_FUNC(_savevr_21)
li r11,-176
stvx v21,r11,r0
HIDDEN_FUNC(_savevr_22)
li r11,-160
stvx v22,r11,r0
HIDDEN_FUNC(_savevr_23)
li r11,-144
stvx v23,r11,r0
HIDDEN_FUNC(_savevr_24)
li r11,-128
stvx v24,r11,r0
HIDDEN_FUNC(_savevr_25)
li r11,-112
stvx v25,r11,r0
HIDDEN_FUNC(_savevr_26)
li r11,-96
stvx v26,r11,r0
HIDDEN_FUNC(_savevr_27)
li r11,-80
stvx v27,r11,r0
HIDDEN_FUNC(_savevr_28)
li r11,-64
stvx v28,r11,r0
HIDDEN_FUNC(_savevr_29)
li r11,-48
stvx v29,r11,r0
HIDDEN_FUNC(_savevr_30)
li r11,-32
stvx v30,r11,r0
HIDDEN_FUNC(_savevr_31)
li r11,-16
stvx v31,r11,r0
blr
FUNC_END(_savevr_31)
FUNC_END(_savevr_30)
FUNC_END(_savevr_29)
FUNC_END(_savevr_28)
FUNC_END(_savevr_27)
FUNC_END(_savevr_26)
FUNC_END(_savevr_25)
FUNC_END(_savevr_24)
FUNC_END(_savevr_23)
FUNC_END(_savevr_22)
FUNC_END(_savevr_21)
FUNC_END(_savevr_20)
CFI_ENDPROC
#endif
...@@ -6,4 +6,6 @@ LIB2ADD_ST = \ ...@@ -6,4 +6,6 @@ LIB2ADD_ST = \
$(srcdir)/config/rs6000/crtsavgpr.S \ $(srcdir)/config/rs6000/crtsavgpr.S \
$(srcdir)/config/rs6000/crtresgpr.S \ $(srcdir)/config/rs6000/crtresgpr.S \
$(srcdir)/config/rs6000/crtresxfpr.S \ $(srcdir)/config/rs6000/crtresxfpr.S \
$(srcdir)/config/rs6000/crtresxgpr.S $(srcdir)/config/rs6000/crtresxgpr.S \
$(srcdir)/config/rs6000/crtsavevr.S \
$(srcdir)/config/rs6000/crtrestvr.S
...@@ -6,6 +6,8 @@ LIB2ADD_ST += \ ...@@ -6,6 +6,8 @@ LIB2ADD_ST += \
$(srcdir)/config/rs6000/crtresgpr.S \ $(srcdir)/config/rs6000/crtresgpr.S \
$(srcdir)/config/rs6000/crtresxfpr.S \ $(srcdir)/config/rs6000/crtresxfpr.S \
$(srcdir)/config/rs6000/crtresxgpr.S \ $(srcdir)/config/rs6000/crtresxgpr.S \
$(srcdir)/config/rs6000/crtsavevr.S \
$(srcdir)/config/rs6000/crtrestvr.S \
$(srcdir)/config/rs6000/e500crtres32gpr.S \ $(srcdir)/config/rs6000/e500crtres32gpr.S \
$(srcdir)/config/rs6000/e500crtres64gpr.S \ $(srcdir)/config/rs6000/e500crtres64gpr.S \
$(srcdir)/config/rs6000/e500crtres64gprctr.S \ $(srcdir)/config/rs6000/e500crtres64gprctr.S \
......
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