diff options
Diffstat (limited to 'gcc/config/rs6000')
-rw-r--r-- | gcc/config/rs6000/rs6000.c | 321 | ||||
-rw-r--r-- | gcc/config/rs6000/sysv4.h | 7 |
2 files changed, 176 insertions, 152 deletions
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index f265dce42fe..6f7636bb298 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -73,6 +73,7 @@ /* Structure used to define the rs6000 stack */ typedef struct rs6000_stack { + int reload_completed; /* stack info won't change from here on */ int first_gp_reg_save; /* first callee saved GP register used */ int first_fp_reg_save; /* first callee saved FP register used */ int first_altivec_reg_save; /* first callee saved AltiVec register used */ @@ -109,6 +110,7 @@ typedef struct rs6000_stack { int spe_padding_size; HOST_WIDE_INT total_size; /* total bytes allocated for stack */ int spe_64bit_regs_used; + int savres_strategy; } rs6000_stack_t; /* A C structure for machine-specific, per-function data. @@ -994,7 +996,6 @@ static rtx rs6000_make_savres_rtx (rs6000_stack_t *, rtx, 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_function (tree, tree, tree); -static int rs6000_savres_strategy (rs6000_stack_t *, bool, int, int); static void rs6000_restore_saved_cr (rtx, int); static bool rs6000_output_addr_const_extra (FILE *, rtx); static void rs6000_output_function_prologue (FILE *, HOST_WIDE_INT); @@ -15161,6 +15162,8 @@ rs6000_got_register (rtx value ATTRIBUTE_UNUSED) return pic_offset_table_rtx; } +static rs6000_stack_t stack_info; + /* Function to init struct machine_function. This will be called, via a pointer variable, from push_function_context. */ @@ -15168,6 +15171,7 @@ rs6000_got_register (rtx value ATTRIBUTE_UNUSED) static struct machine_function * rs6000_init_machine_status (void) { + stack_info.reload_completed = 0; return ggc_alloc_cleared_machine_function (); } @@ -18050,6 +18054,107 @@ is_altivec_return_reg (rtx reg, void *xyes) } +/* Determine the strategy for savings/restoring registers. */ + +enum { + SAVRES_MULTIPLE = 0x1, + SAVE_INLINE_FPRS = 0x2, + SAVE_INLINE_GPRS = 0x4, + REST_INLINE_FPRS = 0x8, + REST_INLINE_GPRS = 0x10, + SAVE_NOINLINE_GPRS_SAVES_LR = 0x20, + SAVE_NOINLINE_FPRS_SAVES_LR = 0x40, + REST_NOINLINE_FPRS_DOESNT_RESTORE_LR = 0x80 +}; + +static int +rs6000_savres_strategy (rs6000_stack_t *info, + bool using_static_chain_p) +{ + int strategy = 0; + + if (TARGET_MULTIPLE + && !TARGET_POWERPC64 + && !(TARGET_SPE_ABI && info->spe_64bit_regs_used) + && info->first_gp_reg_save < 31 + && no_global_regs_above (info->first_gp_reg_save, /*gpr=*/true)) + strategy |= SAVRES_MULTIPLE; + + if (crtl->calls_eh_return + || cfun->machine->ra_need_lr + || info->total_size > 32767) + strategy |= (SAVE_INLINE_FPRS | REST_INLINE_FPRS + | SAVE_INLINE_GPRS | REST_INLINE_GPRS); + + if (info->first_fp_reg_save == 64 + || FP_SAVE_INLINE (info->first_fp_reg_save) + /* 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) + || !no_global_regs_above (info->first_fp_reg_save, /*gpr=*/false)) + strategy |= SAVE_INLINE_FPRS | REST_INLINE_FPRS; + + if (info->first_gp_reg_save == 32 + || GP_SAVE_INLINE (info->first_gp_reg_save) + || !((strategy & SAVRES_MULTIPLE) + || no_global_regs_above (info->first_gp_reg_save, /*gpr=*/true))) + strategy |= SAVE_INLINE_GPRS | REST_INLINE_GPRS; + + /* 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 + static chain is rarely used anyway. */ + if (using_static_chain_p) + strategy |= SAVE_INLINE_FPRS | SAVE_INLINE_GPRS; + + /* 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 & SAVRES_MULTIPLE)) + strategy |= SAVE_INLINE_GPRS; + + /* 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 & SAVRES_MULTIPLE) + && (!info->lr_save_p + || info->first_fp_reg_save != 64)) + strategy |= REST_INLINE_GPRS; + + /* 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 | SAVRES_MULTIPLE)) == SAVE_INLINE_GPRS) + strategy |= REST_INLINE_GPRS; + + /* 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; + +#ifdef POWERPC_LINUX + if (TARGET_64BIT) + { + if (!(strategy & SAVE_INLINE_FPRS)) + strategy |= SAVE_NOINLINE_FPRS_SAVES_LR; + else if (!(strategy & SAVE_INLINE_GPRS) + && info->first_fp_reg_save == 64) + strategy |= SAVE_NOINLINE_GPRS_SAVES_LR; + } +#else + if (TARGET_AIX && !(strategy & REST_INLINE_FPRS)) + strategy |= REST_NOINLINE_FPRS_DOESNT_RESTORE_LR; +#endif + return strategy; +} + /* Calculate the stack information for the current function. This is complicated by having two separate calling sequences, the AIX calling sequence and the V.4 calling sequence. @@ -18150,15 +18255,26 @@ is_altivec_return_reg (rtx reg, void *xyes) static rs6000_stack_t * rs6000_stack_info (void) { - static rs6000_stack_t info; - rs6000_stack_t *info_ptr = &info; +#ifdef ENABLE_CHECKING + static rs6000_stack_t info_save; +#endif + rs6000_stack_t *info_ptr = &stack_info; int reg_size = TARGET_32BIT ? 4 : 8; int ehrd_size; int save_align; int first_gp; HOST_WIDE_INT non_fixed_size; + bool using_static_chain_p; + +#ifdef ENABLE_CHECKING + memcpy (&info_save, &stack_info, sizeof stack_info); +#else + if (reload_completed && info_ptr->reload_completed) + return info_ptr; +#endif - memset (&info, 0, sizeof (info)); + memset (&stack_info, 0, sizeof (stack_info)); + info_ptr->reload_completed = reload_completed; if (TARGET_SPE) { @@ -18215,23 +18331,6 @@ rs6000_stack_info (void) info_ptr->calls_p = (! current_function_is_leaf || cfun->machine->ra_needs_full_frame); - /* Determine if we need to save the link register. */ - if ((DEFAULT_ABI == ABI_AIX - && crtl->profile - && !TARGET_PROFILE_KERNEL) -#ifdef TARGET_RELOCATABLE - || (TARGET_RELOCATABLE && (get_pool_size () != 0)) -#endif - || (info_ptr->first_fp_reg_save != 64 - && !FP_SAVE_INLINE (info_ptr->first_fp_reg_save)) - || (DEFAULT_ABI == ABI_V4 && cfun->calls_alloca) - || info_ptr->calls_p - || rs6000_ra_ever_killed ()) - { - info_ptr->lr_save_p = 1; - df_set_regs_ever_live (LR_REGNO, true); - } - /* Determine if we need to save the condition code registers. */ if (df_regs_ever_live_p (CR2_REGNO) || df_regs_ever_live_p (CR3_REGNO) @@ -18400,6 +18499,33 @@ rs6000_stack_info (void) info_ptr->total_size = RS6000_ALIGN (non_fixed_size + info_ptr->fixed_size, ABI_STACK_BOUNDARY / BITS_PER_UNIT); + /* Determine if we need to save the link register. */ + if (info_ptr->calls_p + || (DEFAULT_ABI == ABI_AIX + && crtl->profile + && !TARGET_PROFILE_KERNEL) + || (DEFAULT_ABI == ABI_V4 && cfun->calls_alloca) +#ifdef TARGET_RELOCATABLE + || (TARGET_RELOCATABLE && (get_pool_size () != 0)) +#endif + || rs6000_ra_ever_killed ()) + info_ptr->lr_save_p = 1; + + using_static_chain_p = (cfun->static_chain_decl != NULL_TREE + && df_regs_ever_live_p (STATIC_CHAIN_REGNUM) + && call_used_regs[STATIC_CHAIN_REGNUM]); + info_ptr->savres_strategy = rs6000_savres_strategy (info_ptr, + using_static_chain_p); + + if (!(info_ptr->savres_strategy & SAVE_INLINE_GPRS) + || !(info_ptr->savres_strategy & SAVE_INLINE_FPRS) + || !(info_ptr->savres_strategy & REST_INLINE_GPRS) + || !(info_ptr->savres_strategy & REST_INLINE_FPRS)) + info_ptr->lr_save_p = 1; + + if (info_ptr->lr_save_p) + df_set_regs_ever_live (LR_REGNO, true); + /* Determine if we need to allocate any stack frame: For AIX we need to push the stack if a frame pointer is needed @@ -18451,6 +18577,10 @@ rs6000_stack_info (void) if (! info_ptr->cr_save_p) info_ptr->cr_save_offset = 0; +#ifdef ENABLE_CHECKING + gcc_assert (!(reload_completed && info_save.reload_completed) + || memcmp (&info_save, &stack_info, sizeof stack_info) == 0); +#endif return info_ptr; } @@ -19714,106 +19844,6 @@ rs6000_reg_live_or_pic_offset_p (int reg) || (DEFAULT_ABI == ABI_DARWIN && flag_pic)))); } -enum { - SAVRES_MULTIPLE = 0x1, - SAVRES_INLINE_FPRS = 0x2, - SAVRES_INLINE_GPRS = 0x4, - SAVRES_NOINLINE_GPRS_SAVES_LR = 0x8, - SAVRES_NOINLINE_FPRS_SAVES_LR = 0x10, - SAVRES_NOINLINE_FPRS_DOESNT_RESTORE_LR = 0x20 -}; - -/* Determine the strategy for savings/restoring registers. */ - -static int -rs6000_savres_strategy (rs6000_stack_t *info, bool savep, - int using_static_chain_p, int sibcall) -{ - bool using_multiple_p; - bool common; - bool savres_fprs_inline; - bool savres_gprs_inline; - bool noclobber_global_gprs - = no_global_regs_above (info->first_gp_reg_save, /*gpr=*/true); - int strategy; - - using_multiple_p = (TARGET_MULTIPLE && ! TARGET_POWERPC64 - && (!TARGET_SPE_ABI - || info->spe_64bit_regs_used == 0) - && info->first_gp_reg_save < 31 - && noclobber_global_gprs); - /* 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 - static chain is rarely used anyway. */ - common = (using_static_chain_p - || sibcall - || crtl->calls_eh_return - || !info->lr_save_p - || cfun->machine->ra_need_lr - || info->total_size > 32767); - savres_fprs_inline = (common - || info->first_fp_reg_save == 64 - || !no_global_regs_above (info->first_fp_reg_save, - /*gpr=*/false) - /* 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) - || FP_SAVE_INLINE (info->first_fp_reg_save)); - savres_gprs_inline = (common - /* Saving CR interferes with the exit routines - used on the SPE, so just punt here. */ - || (!savep - && TARGET_SPE_ABI - && info->spe_64bit_regs_used != 0 - && info->cr_save_p != 0) - || info->first_gp_reg_save == 32 - || !noclobber_global_gprs - || GP_SAVE_INLINE (info->first_gp_reg_save)); - - if (savep) - /* 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. */ - savres_gprs_inline = savres_gprs_inline || using_multiple_p; - else - { - /* 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. But we can only use the out-of-line - routines if we know that 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 from the stack. Furthermore, we can only use - the "exit" out-of-line gpr restore if we haven't saved any - fprs. */ - bool saved_all = !savres_gprs_inline || using_multiple_p; - - if (saved_all && info->first_fp_reg_save != 64) - /* We can't use the exit routine; use load multiple if it's - available. */ - savres_gprs_inline = savres_gprs_inline || using_multiple_p; - } - - strategy = (using_multiple_p - | (savres_fprs_inline << 1) - | (savres_gprs_inline << 2)); -#ifdef POWERPC_LINUX - if (TARGET_64BIT) - { - if (!savres_fprs_inline) - strategy |= SAVRES_NOINLINE_FPRS_SAVES_LR; - else if (!savres_gprs_inline && info->first_fp_reg_save == 64) - strategy |= SAVRES_NOINLINE_GPRS_SAVES_LR; - } -#else - if (TARGET_AIX && !savres_fprs_inline) - strategy |= SAVRES_NOINLINE_FPRS_DOESNT_RESTORE_LR; -#endif - return strategy; -} - /* Emit function prologue as insns. */ void @@ -19862,12 +19892,10 @@ rs6000_emit_prologue (void) reg_size = 8; } - strategy = rs6000_savres_strategy (info, /*savep=*/true, - /*static_chain_p=*/using_static_chain_p, - /*sibcall=*/0); + strategy = info->savres_strategy; using_store_multiple = strategy & SAVRES_MULTIPLE; - saving_FPRs_inline = strategy & SAVRES_INLINE_FPRS; - saving_GPRs_inline = strategy & SAVRES_INLINE_GPRS; + 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. */ if (! WORLD_SAVE_P (info) @@ -20037,8 +20065,8 @@ rs6000_emit_prologue (void) gen_rtx_REG (Pmode, LR_REGNO)); RTX_FRAME_RELATED_P (insn) = 1; - if (!(strategy & (SAVRES_NOINLINE_GPRS_SAVES_LR - | SAVRES_NOINLINE_FPRS_SAVES_LR))) + if (!(strategy & (SAVE_NOINLINE_GPRS_SAVES_LR + | SAVE_NOINLINE_FPRS_SAVES_LR))) { addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (info->lr_save_offset + sp_offset)); @@ -20098,7 +20126,7 @@ rs6000_emit_prologue (void) DFmode, /*savep=*/true, /*gpr=*/false, /*lr=*/(strategy - & SAVRES_NOINLINE_FPRS_SAVES_LR) + & SAVE_NOINLINE_FPRS_SAVES_LR) != 0); insn = emit_insn (par); rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, @@ -20225,7 +20253,7 @@ rs6000_emit_prologue (void) reg_mode, /*savep=*/true, /*gpr=*/true, /*lr=*/(strategy - & SAVRES_NOINLINE_GPRS_SAVES_LR) + & SAVE_NOINLINE_GPRS_SAVES_LR) != 0); insn = emit_insn (par); rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, @@ -20533,19 +20561,23 @@ rs6000_output_function_prologue (FILE *file, /* Write .extern for any function we will call to save and restore fp values. */ - if (info->first_fp_reg_save < 64 - && !FP_SAVE_INLINE (info->first_fp_reg_save)) + if (info->first_fp_reg_save < 64) { char *name; int regno = info->first_fp_reg_save - 32; - name = rs6000_savres_routine_name (info, regno, /*savep=*/true, - /*gpr=*/false, /*lr=*/false); - fprintf (file, "\t.extern %s\n", name); - - name = rs6000_savres_routine_name (info, regno, /*savep=*/false, - /*gpr=*/false, /*lr=*/true); - fprintf (file, "\t.extern %s\n", name); + if ((info->savres_strategy & SAVE_INLINE_FPRS) == 0) + { + name = rs6000_savres_routine_name (info, regno, /*savep=*/true, + /*gpr=*/false, /*lr=*/false); + fprintf (file, "\t.extern %s\n", name); + } + if ((info->savres_strategy & REST_INLINE_FPRS) == 0) + { + name = rs6000_savres_routine_name (info, regno, /*savep=*/false, + /*gpr=*/false, /*lr=*/true); + fprintf (file, "\t.extern %s\n", name); + } } /* Write .extern for AIX common mode routines, if needed. */ @@ -20691,11 +20723,10 @@ rs6000_emit_epilogue (int sibcall) reg_size = 8; } - strategy = rs6000_savres_strategy (info, /*savep=*/false, - /*static_chain_p=*/0, sibcall); + strategy = info->savres_strategy; using_load_multiple = strategy & SAVRES_MULTIPLE; - restoring_FPRs_inline = strategy & SAVRES_INLINE_FPRS; - restoring_GPRs_inline = strategy & SAVRES_INLINE_GPRS; + restoring_FPRs_inline = sibcall || (strategy & REST_INLINE_FPRS); + restoring_GPRs_inline = sibcall || (strategy & REST_INLINE_GPRS); using_mtcr_multiple = (rs6000_cpu == PROCESSOR_PPC601 || rs6000_cpu == PROCESSOR_PPC603 || rs6000_cpu == PROCESSOR_PPC750 @@ -20713,7 +20744,7 @@ rs6000_emit_epilogue (int sibcall) && !frame_pointer_needed)); restore_lr = (info->lr_save_p && (restoring_FPRs_inline - || (strategy & SAVRES_NOINLINE_FPRS_DOESNT_RESTORE_LR)) + || (strategy & REST_NOINLINE_FPRS_DOESNT_RESTORE_LR)) && (restoring_GPRs_inline || info->first_fp_reg_save < 64)); @@ -21352,7 +21383,7 @@ rs6000_emit_epilogue (int sibcall) if (!sibcall) { rtvec p; - bool lr = (strategy & SAVRES_NOINLINE_FPRS_DOESNT_RESTORE_LR) == 0; + bool lr = (strategy & REST_NOINLINE_FPRS_DOESNT_RESTORE_LR) == 0; if (! restoring_FPRs_inline) p = rtvec_alloc (4 + 64 - info->first_fp_reg_save); else diff --git a/gcc/config/rs6000/sysv4.h b/gcc/config/rs6000/sysv4.h index 6d88e324e88..04cc70e3adf 100644 --- a/gcc/config/rs6000/sysv4.h +++ b/gcc/config/rs6000/sysv4.h @@ -502,13 +502,6 @@ do { \ reg_names[1]); \ } while (0) -/* Switch Recognition by gcc.c. Add -G xx support. */ - -/* Override svr4.h definition. */ -#undef SWITCH_TAKES_ARG -#define SWITCH_TAKES_ARG(CHAR) \ - (DEFAULT_SWITCH_TAKES_ARG (CHAR) || (CHAR) == 'G') - extern int fixuplabelno; /* Handle constructors specially for -mrelocatable. */ |