From: Ulrich Weigand Date: Wed, 16 Jun 2004 23:11:33 +0000 (+0000) Subject: s390.c (struct machine_function): New member last_restore_gpr. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=b767fc11d8fc76782a969535772caf9f6df95d68;p=gcc.git s390.c (struct machine_function): New member last_restore_gpr. * config/s390/s390.c (struct machine_function): New member last_restore_gpr. (s390_frame_info): Add BASE_USED and RETURN_ADDR_USED parameters. Do not modify machine->save_return_addr_p or regs_ever_live. Fill in machine->last_restore_gpr. (s390_optimize_prolog): Use s390_frame_info to compute registers to save/restore, remove duplicated code. (s390_arg_frame_offset): Use s390_frame_info to compute frame size, remove duplicated code. (s390_emit_prologue): Adapt s390_frame_info call. Update machine->save_return_addr_p and regs_ever_live. (s390_emit_epilogue): Use machine->last_restore_gpr instead of machine->last_save_gpr. From-SVN: r83275 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 50bfa931162..0813d9260ef 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,19 @@ +2004-06-16 Ulrich Weigand + + * config/s390/s390.c (struct machine_function): New member + last_restore_gpr. + (s390_frame_info): Add BASE_USED and RETURN_ADDR_USED parameters. + Do not modify machine->save_return_addr_p or regs_ever_live. + Fill in machine->last_restore_gpr. + (s390_optimize_prolog): Use s390_frame_info to compute registers + to save/restore, remove duplicated code. + (s390_arg_frame_offset): Use s390_frame_info to compute frame + size, remove duplicated code. + (s390_emit_prologue): Adapt s390_frame_info call. Update + machine->save_return_addr_p and regs_ever_live. + (s390_emit_epilogue): Use machine->last_restore_gpr instead of + machine->last_save_gpr. + 2004-06-16 Richard Henderson * c-parse.in (if_stmt_locus): Remove. diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c index 2e6b2ca5707..ed1eb50f830 100644 --- a/gcc/config/s390/s390.c +++ b/gcc/config/s390/s390.c @@ -213,6 +213,7 @@ struct machine_function GTY(()) int first_save_gpr; int first_restore_gpr; int last_save_gpr; + int last_restore_gpr; /* Size of stack frame. */ HOST_WIDE_INT frame_size; @@ -242,7 +243,7 @@ static rtx find_ltrel_base (rtx); static void replace_ltrel_base (rtx *, rtx); static void s390_optimize_prolog (bool); static int find_unused_clobbered_reg (void); -static void s390_frame_info (void); +static void s390_frame_info (int, int); static rtx save_fpr (rtx, int, int); static rtx restore_fpr (rtx, int, int); static rtx save_gprs (rtx, int, int, int); @@ -4942,64 +4943,24 @@ s390_output_pool_entry (rtx exp, enum machine_mode mode, unsigned int align) static void s390_optimize_prolog (bool base_used) { - int save_first, save_last, restore_first, restore_last; - int i, j; rtx insn, new_insn, next_insn; - /* Recompute regs_ever_live data for special registers. */ + /* Do a final recompute of the frame-related data. */ + + s390_frame_info (base_used, cfun->machine->save_return_addr_p); regs_ever_live[BASE_REGISTER] = base_used; regs_ever_live[RETURN_REGNUM] = cfun->machine->save_return_addr_p; regs_ever_live[STACK_POINTER_REGNUM] = cfun->machine->frame_size > 0; - - /* Find first and last gpr to be saved. */ - - for (i = 6; i < 16; i++) - if (regs_ever_live[i]) - if (!global_regs[i] - || i == STACK_POINTER_REGNUM - || i == RETURN_REGNUM - || i == BASE_REGISTER - || (flag_pic && i == (int)PIC_OFFSET_TABLE_REGNUM)) - break; - - for (j = 15; j > i; j--) - if (regs_ever_live[j]) - if (!global_regs[j] - || j == STACK_POINTER_REGNUM - || j == RETURN_REGNUM - || j == BASE_REGISTER - || (flag_pic && j == (int)PIC_OFFSET_TABLE_REGNUM)) - break; - - if (i == 16) - { - /* Nothing to save/restore. */ - save_first = restore_first = -1; - save_last = restore_last = -1; - } - else - { - /* Save/restore from i to j. */ - save_first = restore_first = i; - save_last = restore_last = j; - } - - /* Varargs functions need to save gprs 2 to 6. */ - if (current_function_stdarg) - { - save_first = 2; - if (save_last < 6) - save_last = 6; - } - - /* If all special registers are in fact used, there's nothing we can do, so no point in walking the insn list. */ - if (i <= BASE_REGISTER && j >= BASE_REGISTER - && (TARGET_CPU_ZARCH || (i <= RETURN_REGNUM && j >= RETURN_REGNUM))) - return; + if (cfun->machine->first_save_gpr <= BASE_REGISTER + && cfun->machine->last_save_gpr >= BASE_REGISTER + && (TARGET_CPU_ZARCH + || (cfun->machine->first_save_gpr <= RETURN_REGNUM + && cfun->machine->last_save_gpr >= RETURN_REGNUM))) + return; /* Search for prolog/epilog insns and replace them. */ @@ -5028,9 +4989,10 @@ s390_optimize_prolog (bool base_used) if (first > BASE_REGISTER || last < BASE_REGISTER) continue; - if (save_first != -1) + if (cfun->machine->first_save_gpr != -1) { - new_insn = save_gprs (base, off, save_first, save_last); + new_insn = save_gprs (base, off, cfun->machine->first_save_gpr, + cfun->machine->last_save_gpr); new_insn = emit_insn_before (new_insn, insn); INSN_ADDRESSES_NEW (new_insn, -1); } @@ -5052,9 +5014,10 @@ s390_optimize_prolog (bool base_used) if (GET_CODE (base) != REG || off < 0) continue; - if (save_first != -1) + if (cfun->machine->first_save_gpr != -1) { - new_insn = save_gprs (base, off, save_first, save_last); + new_insn = save_gprs (base, off, cfun->machine->first_save_gpr, + cfun->machine->last_save_gpr); new_insn = emit_insn_before (new_insn, insn); INSN_ADDRESSES_NEW (new_insn, -1); } @@ -5078,9 +5041,10 @@ s390_optimize_prolog (bool base_used) if (first > BASE_REGISTER || last < BASE_REGISTER) continue; - if (restore_first != -1) + if (cfun->machine->first_restore_gpr != -1) { - new_insn = restore_gprs (base, off, restore_first, restore_last); + new_insn = restore_gprs (base, off, cfun->machine->first_restore_gpr, + cfun->machine->last_restore_gpr); new_insn = emit_insn_before (new_insn, insn); INSN_ADDRESSES_NEW (new_insn, -1); } @@ -5102,9 +5066,10 @@ s390_optimize_prolog (bool base_used) if (GET_CODE (base) != REG || off < 0) continue; - if (restore_first != -1) + if (cfun->machine->first_restore_gpr != -1) { - new_insn = restore_gprs (base, off, restore_first, restore_last); + new_insn = restore_gprs (base, off, cfun->machine->first_restore_gpr, + cfun->machine->last_restore_gpr); new_insn = emit_insn_before (new_insn, insn); INSN_ADDRESSES_NEW (new_insn, -1); } @@ -5258,11 +5223,14 @@ find_unused_clobbered_reg (void) return 0; } -/* Fill FRAME with info about frame of current function. */ +/* Fill cfun->machine with info about frame of current function. + BASE_USED and RETURN_ADDR_USED specify whether we assume the + base and return address register will need to be saved. */ static void -s390_frame_info (void) +s390_frame_info (int base_used, int return_addr_used) { + int live_regs[16]; int i, j; HOST_WIDE_INT fsize = get_frame_size (); @@ -5283,59 +5251,65 @@ s390_frame_info (void) /* Does function need to setup frame and save area. */ - if (! current_function_is_leaf + if (!current_function_is_leaf || TARGET_TPF_PROFILING || cfun->machine->frame_size > 0 || current_function_calls_alloca || current_function_stdarg) cfun->machine->frame_size += STARTING_FRAME_OFFSET; - /* If we use the return register, we'll need to make sure - it is going to be saved/restored. */ + /* Find first and last gpr to be saved. We trust regs_ever_live + data, except that we don't save and restore global registers. - if (!current_function_is_leaf - || TARGET_TPF_PROFILING - || regs_ever_live[RETURN_REGNUM]) - cfun->machine->save_return_addr_p = 1; + Also, all registers with special meaning to the compiler need + to be handled extra. */ - /* Find first and last gpr to be saved. Note that at this point, - we assume the base register and -on S/390- the return register - always need to be saved. This is done because the usage of these - register might change even after the prolog was emitted. - If it turns out later that we really don't need them, the - prolog/epilog code is modified again. */ + for (i = 0; i < 16; i++) + live_regs[i] = regs_ever_live[i] && !global_regs[i]; - regs_ever_live[BASE_REGISTER] = 1; - if (!TARGET_CPU_ZARCH || cfun->machine->save_return_addr_p) - regs_ever_live[RETURN_REGNUM] = 1; - regs_ever_live[STACK_POINTER_REGNUM] = cfun->machine->frame_size > 0; + if (flag_pic) + live_regs[PIC_OFFSET_TABLE_REGNUM] = + regs_ever_live[PIC_OFFSET_TABLE_REGNUM]; - for (i = 6; i < 16; i++) - if (regs_ever_live[i]) - if (!global_regs[i] - || i == STACK_POINTER_REGNUM - || i == RETURN_REGNUM - || i == BASE_REGISTER - || (flag_pic && i == (int)PIC_OFFSET_TABLE_REGNUM)) - break; + live_regs[BASE_REGISTER] = base_used; + live_regs[RETURN_REGNUM] = return_addr_used; + live_regs[STACK_POINTER_REGNUM] = cfun->machine->frame_size > 0; + for (i = 6; i < 16; i++) + if (live_regs[i]) + break; for (j = 15; j > i; j--) - if (regs_ever_live[j]) - if (!global_regs[j] - || j == STACK_POINTER_REGNUM - || j == RETURN_REGNUM - || j == BASE_REGISTER - || (flag_pic && j == (int)PIC_OFFSET_TABLE_REGNUM)) - break; + if (live_regs[j]) + break; - /* Save / Restore from gpr i to j. */ - cfun->machine->first_save_gpr = i; - cfun->machine->first_restore_gpr = i; - cfun->machine->last_save_gpr = j; + if (i == 16) + { + /* Nothing to save/restore. */ + cfun->machine->first_save_gpr = -1; + cfun->machine->first_restore_gpr = -1; + cfun->machine->last_save_gpr = -1; + cfun->machine->last_restore_gpr = -1; + } + else + { + /* Save / Restore from gpr i to j. */ + cfun->machine->first_save_gpr = i; + cfun->machine->first_restore_gpr = i; + cfun->machine->last_save_gpr = j; + cfun->machine->last_restore_gpr = j; + } /* Varargs functions need to save gprs 2 to 6. */ if (current_function_stdarg) - cfun->machine->first_save_gpr = 2; + { + if (cfun->machine->first_save_gpr == -1 + || cfun->machine->first_save_gpr > 2) + cfun->machine->first_save_gpr = 2; + + if (cfun->machine->last_save_gpr == -1 + || cfun->machine->last_save_gpr < 6) + cfun->machine->last_save_gpr = 6; + } } /* Return offset between argument pointer and frame pointer @@ -5344,30 +5318,15 @@ s390_frame_info (void) HOST_WIDE_INT s390_arg_frame_offset (void) { - HOST_WIDE_INT fsize = get_frame_size (); - int save_fprs_p, i; + /* See the comment in s390_emit_prologue about the assumptions we make + whether or not the base and return address register need to be saved. */ + int return_addr_used = !current_function_is_leaf + || TARGET_TPF_PROFILING + || regs_ever_live[RETURN_REGNUM] + || cfun->machine->save_return_addr_p; - /* fprs 8 - 15 are caller saved for 64 Bit ABI. */ - save_fprs_p = 0; - if (TARGET_64BIT) - for (i = 24; i < 32; i++) - if (regs_ever_live[i] && !global_regs[i]) - { - save_fprs_p = 1; - break; - } - - fsize = fsize + save_fprs_p * 64; - - /* Does function need to setup frame and save area. */ - - if (! current_function_is_leaf - || TARGET_TPF_PROFILING - || fsize > 0 - || current_function_calls_alloca - || current_function_stdarg) - fsize += STARTING_FRAME_OFFSET; - return fsize + STACK_POINTER_OFFSET; + s390_frame_info (1, !TARGET_CPU_ZARCH || return_addr_used); + return cfun->machine->frame_size + STACK_POINTER_OFFSET; } /* Emit insn to save fpr REGNUM at offset OFFSET relative @@ -5556,9 +5515,29 @@ s390_emit_prologue (void) rtx temp_reg; int i; - /* Compute frame_info. */ + /* At this point, we decide whether we'll need to save/restore the + return address register. This decision is final on zSeries machines; + on S/390 it can still be overridden in s390_split_branches. */ + + if (!current_function_is_leaf + || TARGET_TPF_PROFILING + || regs_ever_live[RETURN_REGNUM]) + cfun->machine->save_return_addr_p = 1; + + /* Compute frame info. Note that at this point, we assume the base + register and -on S/390- the return register always need to be saved. + This is done because the usage of these registers might change even + after the prolog was emitted. If it turns out later that we really + don't need them, the prolog/epilog code is modified again. */ - s390_frame_info (); + s390_frame_info (1, !TARGET_CPU_ZARCH || cfun->machine->save_return_addr_p); + + /* We need to update regs_ever_live to avoid data-flow problems. */ + + regs_ever_live[BASE_REGISTER] = 1; + regs_ever_live[RETURN_REGNUM] = !TARGET_CPU_ZARCH + || cfun->machine->save_return_addr_p; + regs_ever_live[STACK_POINTER_REGNUM] = cfun->machine->frame_size > 0; /* Choose best register to use for temp use within prologue. See below for why TPF must use the register 1. */ @@ -5736,7 +5715,7 @@ s390_emit_epilogue (bool sibcall) if (cfun->machine->first_restore_gpr != -1) { area_bottom = cfun->machine->first_restore_gpr * UNITS_PER_WORD; - area_top = (cfun->machine->last_save_gpr + 1) * UNITS_PER_WORD; + area_top = (cfun->machine->last_restore_gpr + 1) * UNITS_PER_WORD; } else { @@ -5834,7 +5813,7 @@ s390_emit_epilogue (bool sibcall) to stack location from where they get restored. */ for (i = cfun->machine->first_restore_gpr; - i <= cfun->machine->last_save_gpr; + i <= cfun->machine->last_restore_gpr; i++) { /* These registers are special and need to be @@ -5862,7 +5841,7 @@ s390_emit_epilogue (bool sibcall) if (cfun->machine->save_return_addr_p || (cfun->machine->first_restore_gpr < BASE_REGISTER - && cfun->machine->last_save_gpr > RETURN_REGNUM)) + && cfun->machine->last_restore_gpr > RETURN_REGNUM)) { int return_regnum = find_unused_clobbered_reg(); if (!return_regnum) @@ -5885,7 +5864,7 @@ s390_emit_epilogue (bool sibcall) insn = restore_gprs (frame_pointer, offset, cfun->machine->first_restore_gpr, - cfun->machine->last_save_gpr); + cfun->machine->last_restore_gpr); emit_insn (insn); }