diff options
author | uweigand <uweigand@138bc75d-0d04-0410-961f-82ee72b054a4> | 2004-09-30 21:23:29 +0000 |
---|---|---|
committer | uweigand <uweigand@138bc75d-0d04-0410-961f-82ee72b054a4> | 2004-09-30 21:23:29 +0000 |
commit | 4fed3f99b034309e255c9f820b40788458d2da70 (patch) | |
tree | 81a32418ffd1c56b733fb0bb0b171fbf1dea4bed /gcc/config | |
parent | 772b9a4fbb783e82ff9ee2d0b67f9e33ed441f89 (diff) | |
download | gcc-4fed3f99b034309e255c9f820b40788458d2da70.tar.gz |
* config/s390/s390-protos.h (s390_arg_frame_offset): Remove.
(s390_return_address_offset): Remove.
(s390_can_eliminate): Add prototype.
(s390_initial_elimination_offset): Add prototype.
* config/s390/s390.h (CAN_ELIMINATE): Call s390_can_eliminate.
(INITIAL_ELIMINATION_OFFSET): Call s390_initial_elimination_offset.
* config/s390/s390.c (s390_arg_frame_offset): Remove.
(s390_return_address_offset): Remove.
(s390_can_eliminate, s390_initial_elimination_offset): New functions.
(struct machine_function): New member split_branches_pending_p.
(s390_mainpool_start): Allow nonexistant pool insn for empty pool.
(s390_mainpool_finish): Likewise. Clear base_reg if pool empty.
(s390_optimize_prologue): Remove base_used argument. Call
s390_update_frame_layout instead of s390_register_info. Handle
prologue/epilogue insns that touch only RETURN_REGNUM.
(s390_reorg): Remove base_used. Clear split_branches_pending_p.
(s390_register_info): Remove base_used and return_addr_used
arguments, compute special register usage inline. Return live
register data to caller.
(s390_frame_info): Remove arguments, do not call s390_register_info.
(s390_init_frame_layout): New function.
(s390_update_frame_layout): Likewise.
(s390_emit_prologue): Call s390_update_frame_layout; some code
move to there. Do not emit pool placeholder insn if unnecessary.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@88357 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config')
-rw-r--r-- | gcc/config/s390/s390-protos.h | 4 | ||||
-rw-r--r-- | gcc/config/s390/s390.c | 278 | ||||
-rw-r--r-- | gcc/config/s390/s390.h | 25 |
3 files changed, 184 insertions, 123 deletions
diff --git a/gcc/config/s390/s390-protos.h b/gcc/config/s390/s390-protos.h index 359e20cd87b..d1407c19c5a 100644 --- a/gcc/config/s390/s390-protos.h +++ b/gcc/config/s390/s390-protos.h @@ -23,8 +23,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA extern void optimization_options (int, int); extern void override_options (void); -extern HOST_WIDE_INT s390_arg_frame_offset (void); -extern HOST_WIDE_INT s390_return_address_offset (void); +extern bool s390_can_eliminate (int, int); +extern HOST_WIDE_INT s390_initial_elimination_offset (int, int); extern void s390_emit_prologue (void); extern void s390_emit_epilogue (bool); extern void s390_function_profiler (FILE *, int); diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c index bb468fe510f..073d9dfedf0 100644 --- a/gcc/config/s390/s390.c +++ b/gcc/config/s390/s390.c @@ -254,6 +254,9 @@ struct machine_function GTY(()) /* Literal pool base register. */ rtx base_reg; + /* True if we may need to perform branch splitting. */ + bool split_branches_pending_p; + /* Some local-dynamic TLS symbol name. */ const char *some_ld_name; }; @@ -289,11 +292,13 @@ static void find_constant_pool_ref (rtx, rtx *); static void replace_constant_pool_ref (rtx *, rtx, rtx); static rtx find_ltrel_base (rtx); static void replace_ltrel_base (rtx *); -static void s390_optimize_prologue (bool); +static void s390_optimize_prologue (void); static int find_unused_clobbered_reg (void); static void s390_frame_area (int *, int *); -static void s390_register_info (int, int); -static void s390_frame_info (int, int); +static void s390_register_info (int []); +static void s390_frame_info (void); +static void s390_init_frame_layout (void); +static void s390_update_frame_layout (void); static rtx save_fpr (rtx, int, int); static rtx restore_fpr (rtx, int, int); static rtx save_gprs (rtx, int, int, int); @@ -4895,7 +4900,7 @@ s390_mainpool_start (void) } } - if (!pool->pool_insn) + if (!pool->pool_insn && pool->size > 0) abort (); if (pool->size >= 4096) @@ -4918,13 +4923,17 @@ s390_mainpool_start (void) static void s390_mainpool_finish (struct constant_pool *pool) { - rtx base_reg = SET_DEST (PATTERN (pool->pool_insn)); + rtx base_reg = cfun->machine->base_reg; rtx insn; /* If the pool is empty, we're done. */ if (pool->size == 0) { - remove_insn (pool->pool_insn); + /* We don't actually need a base register after all. */ + cfun->machine->base_reg = NULL_RTX; + + if (pool->pool_insn) + remove_insn (pool->pool_insn); s390_free_pool (pool); return; } @@ -5437,20 +5446,16 @@ s390_output_pool_entry (rtx exp, enum machine_mode mode, unsigned int align) /* Rework the prologue/epilogue to avoid saving/restoring - registers unnecessarily. BASE_USED specifies whether - the literal pool base register needs to be saved. */ + registers unnecessarily. */ static void -s390_optimize_prologue (bool base_used) +s390_optimize_prologue (void) { rtx insn, new_insn, next_insn; /* Do a final recompute of the frame-related data. */ - s390_register_info (base_used, cfun_frame_layout.save_return_addr_p); - regs_ever_live[BASE_REGNUM] = base_used; - regs_ever_live[RETURN_REGNUM] = cfun_frame_layout.save_return_addr_p; - regs_ever_live[STACK_POINTER_REGNUM] = cfun_frame_layout.frame_size > 0; + s390_update_frame_layout (); /* If all special registers are in fact used, there's nothing we can do, so no point in walking the insn list. */ @@ -5509,10 +5514,13 @@ s390_optimize_prologue (bool base_used) if (GET_CODE (PATTERN (insn)) == SET && GET_CODE (SET_SRC (PATTERN (insn))) == REG - && REGNO (SET_SRC (PATTERN (insn))) == BASE_REGNUM + && (REGNO (SET_SRC (PATTERN (insn))) == BASE_REGNUM + || (!TARGET_CPU_ZARCH + && REGNO (SET_SRC (PATTERN (insn))) == RETURN_REGNUM)) && GET_CODE (SET_DEST (PATTERN (insn))) == MEM) { set = PATTERN (insn); + first = REGNO (SET_SRC (set)); offset = const0_rtx; base = eliminate_constant_term (XEXP (SET_DEST (set), 0), &offset); off = INTVAL (offset); @@ -5526,7 +5534,7 @@ s390_optimize_prologue (bool base_used) { new_insn = save_gprs (base, off + (cfun_frame_layout.first_save_gpr - - BASE_REGNUM) * UNITS_PER_WORD, + - first) * UNITS_PER_WORD, cfun_frame_layout.first_save_gpr, cfun_frame_layout.last_save_gpr); new_insn = emit_insn_before (new_insn, insn); @@ -5572,10 +5580,13 @@ s390_optimize_prologue (bool base_used) if (GET_CODE (PATTERN (insn)) == SET && GET_CODE (SET_DEST (PATTERN (insn))) == REG - && REGNO (SET_DEST (PATTERN (insn))) == BASE_REGNUM + && (REGNO (SET_DEST (PATTERN (insn))) == BASE_REGNUM + || (!TARGET_CPU_ZARCH + && REGNO (SET_DEST (PATTERN (insn))) == RETURN_REGNUM)) && GET_CODE (SET_SRC (PATTERN (insn))) == MEM) { set = PATTERN (insn); + first = REGNO (SET_DEST (set)); offset = const0_rtx; base = eliminate_constant_term (XEXP (SET_SRC (set), 0), &offset); off = INTVAL (offset); @@ -5589,7 +5600,7 @@ s390_optimize_prologue (bool base_used) { new_insn = restore_gprs (base, off + (cfun_frame_layout.first_restore_gpr - - BASE_REGNUM) * UNITS_PER_WORD, + - first) * UNITS_PER_WORD, cfun_frame_layout.first_restore_gpr, cfun_frame_layout.last_restore_gpr); new_insn = emit_insn_before (new_insn, insn); @@ -5607,7 +5618,6 @@ s390_optimize_prologue (bool base_used) static void s390_reorg (void) { - bool base_used = false; bool pool_overflow = false; /* Make sure all splits have been performed; splits after @@ -5680,19 +5690,17 @@ s390_reorg (void) /* If we made it up to here, both conditions are satisfied. Finish up literal pool related changes. */ - if ((pool_overflow || pool->size > 0) - && REGNO (cfun->machine->base_reg) == BASE_REGNUM) - base_used = true; - if (pool_overflow) s390_chunkify_finish (pool); else s390_mainpool_finish (pool); + /* We're done splitting branches. */ + cfun->machine->split_branches_pending_p = false; break; } - s390_optimize_prologue (base_used); + s390_optimize_prologue (); } @@ -5806,14 +5814,12 @@ s390_frame_area (int *area_bottom, int *area_top) *area_top = t; } -/* Fill cfun->machine with info about register usage of current - function. BASE_USED and RETURN_ADDR_USED specify whether we assume the - base and return address register will need to be saved. */ +/* Fill cfun->machine with info about register usage of current function. + Return in LIVE_REGS which GPRs are currently considered live. */ static void -s390_register_info (int base_used, int return_addr_used) +s390_register_info (int live_regs[]) { - int live_regs[16]; int i, j; /* fprs 8 - 15 are call saved for 64 Bit ABI. */ @@ -5837,17 +5843,24 @@ s390_register_info (int base_used, int return_addr_used) live_regs[i] = regs_ever_live[i] && !global_regs[i]; if (flag_pic) - live_regs[PIC_OFFSET_TABLE_REGNUM] = - regs_ever_live[PIC_OFFSET_TABLE_REGNUM]; - - live_regs[BASE_REGNUM] = base_used; - live_regs[RETURN_REGNUM] = return_addr_used; - live_regs[STACK_POINTER_REGNUM] = (!current_function_is_leaf - || TARGET_TPF_PROFILING - || cfun_save_high_fprs_p - || get_frame_size () > 0 - || current_function_calls_alloca - || current_function_stdarg); + live_regs[PIC_OFFSET_TABLE_REGNUM] + = regs_ever_live[PIC_OFFSET_TABLE_REGNUM]; + + live_regs[BASE_REGNUM] + = cfun->machine->base_reg + && REGNO (cfun->machine->base_reg) == BASE_REGNUM; + + live_regs[RETURN_REGNUM] + = cfun->machine->split_branches_pending_p + || cfun_frame_layout.save_return_addr_p; + + live_regs[STACK_POINTER_REGNUM] + = !current_function_is_leaf + || TARGET_TPF_PROFILING + || cfun_save_high_fprs_p + || get_frame_size () > 0 + || current_function_calls_alloca + || current_function_stdarg; for (i = 6; i < 16; i++) if (live_regs[i]) @@ -5895,19 +5908,14 @@ s390_register_info (int base_used, int return_addr_used) cfun_set_fpr_bit (i); } -/* 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. */ +/* Fill cfun->machine with info about frame of current function. */ static void -s390_frame_info (int base_used, int return_addr_used) +s390_frame_info (void) { int i; cfun_frame_layout.frame_size = get_frame_size (); - - s390_register_info (base_used, return_addr_used); - if (!TARGET_64BIT && cfun_frame_layout.frame_size > 0x7fff0000) fatal_error ("Total size of local variables exceeds architecture limit."); @@ -6011,37 +6019,136 @@ s390_frame_info (int base_used, int return_addr_used) } } -/* Return offset between argument pointer and frame pointer - initially after prologue. */ +/* Generate frame layout. Fills in register and frame data for the current + function in cfun->machine. This routine can be called multiple times; + it will re-do the complete frame layout every time. */ -HOST_WIDE_INT -s390_arg_frame_offset (void) +static void +s390_init_frame_layout (void) +{ + HOST_WIDE_INT frame_size; + int base_used; + int live_regs[16]; + + /* If return address register is explicitly used, we need to save it. */ + if (regs_ever_live[RETURN_REGNUM] + || !current_function_is_leaf + || TARGET_TPF_PROFILING + || current_function_stdarg + || current_function_calls_eh_return) + cfun_frame_layout.save_return_addr_p = true; + + /* On S/390 machines, we may need to perform branch splitting, which + will require both base and return address register. We have no + choice but to assume we're going to need them until right at the + end of the machine dependent reorg phase. */ + if (!TARGET_CPU_ZARCH) + cfun->machine->split_branches_pending_p = true; + + do + { + frame_size = cfun_frame_layout.frame_size; + + /* Try to predict whether we'll need the base register. */ + base_used = cfun->machine->split_branches_pending_p + || current_function_uses_const_pool + || (!DISP_IN_RANGE (-frame_size) + && !CONST_OK_FOR_CONSTRAINT_P (-frame_size, 'K', "K")); + + /* Decide which register to use as literal pool base. In small + leaf functions, try to use an unused call-clobbered register + as base register to avoid save/restore overhead. */ + if (!base_used) + cfun->machine->base_reg = NULL_RTX; + else if (current_function_is_leaf && !regs_ever_live[5]) + cfun->machine->base_reg = gen_rtx_REG (Pmode, 5); + else + cfun->machine->base_reg = gen_rtx_REG (Pmode, BASE_REGNUM); + + s390_register_info (live_regs); + s390_frame_info (); + } + while (frame_size != cfun_frame_layout.frame_size); +} + +/* Update frame layout. Recompute actual register save data based on + current info and update regs_ever_live for the special registers. + May be called multiple times, but may never cause *more* registers + to be saved than s390_init_frame_layout allocated room for. */ + +static void +s390_update_frame_layout (void) +{ + int live_regs[16]; + + s390_register_info (live_regs); + + regs_ever_live[BASE_REGNUM] = live_regs[BASE_REGNUM]; + regs_ever_live[RETURN_REGNUM] = live_regs[RETURN_REGNUM]; + regs_ever_live[STACK_POINTER_REGNUM] = live_regs[STACK_POINTER_REGNUM]; + + if (cfun->machine->base_reg) + regs_ever_live[REGNO (cfun->machine->base_reg)] = 1; +} + +/* Return true if register FROM can be eliminated via register TO. */ + +bool +s390_can_eliminate (int from, int to) { - /* 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_frame_layout.save_return_addr_p; + gcc_assert (to == STACK_POINTER_REGNUM + || to == HARD_FRAME_POINTER_REGNUM); + + gcc_assert (from == FRAME_POINTER_REGNUM + || from == ARG_POINTER_REGNUM + || from == RETURN_ADDRESS_POINTER_REGNUM); - s390_frame_info (1, !TARGET_CPU_ZARCH || return_addr_used); + /* Make sure we actually saved the return address. */ + if (from == RETURN_ADDRESS_POINTER_REGNUM) + if (!current_function_calls_eh_return + && !current_function_stdarg + && !cfun_frame_layout.save_return_addr_p) + return false; - return cfun_frame_layout.frame_size + STACK_POINTER_OFFSET; + return true; } -/* Return offset between return address pointer (location of r14 - on the stack) and frame pointer initially after prologue. */ +/* Return offset between register FROM and TO initially after prolog. */ HOST_WIDE_INT -s390_return_address_offset (void) +s390_initial_elimination_offset (int from, int to) { - s390_frame_info (1, 1); + HOST_WIDE_INT offset; + int index; - if (cfun_frame_layout.last_save_gpr < RETURN_REGNUM) - abort (); + /* ??? Why are we called for non-eliminable pairs? */ + if (!s390_can_eliminate (from, to)) + return 0; + + switch (from) + { + case FRAME_POINTER_REGNUM: + offset = 0; + break; + + case ARG_POINTER_REGNUM: + s390_init_frame_layout (); + offset = cfun_frame_layout.frame_size + STACK_POINTER_OFFSET; + break; - return (cfun_frame_layout.frame_size + cfun_frame_layout.gprs_offset - + (RETURN_REGNUM - cfun_frame_layout.first_save_gpr) * UNITS_PER_WORD); + case RETURN_ADDRESS_POINTER_REGNUM: + s390_init_frame_layout (); + index = RETURN_REGNUM - cfun_frame_layout.first_save_gpr; + gcc_assert (index >= 0); + offset = cfun_frame_layout.frame_size + cfun_frame_layout.gprs_offset; + offset += index * UNITS_PER_WORD; + break; + + default: + gcc_unreachable (); + } + + return offset; } /* Emit insn to save fpr REGNUM at offset OFFSET relative @@ -6230,41 +6337,9 @@ s390_emit_prologue (void) int offset; int next_fpr = 0; - /* 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_frame_layout.save_return_addr_p = 1; - - /* Decide which register to use as literal pool base. In small leaf - functions, try to use an unused call-clobbered register as base - register to avoid save/restore overhead. */ - - if (current_function_is_leaf && !regs_ever_live[5]) - cfun->machine->base_reg = gen_rtx_REG (Pmode, 5); - else - cfun->machine->base_reg = gen_rtx_REG (Pmode, BASE_REGNUM); - - regs_ever_live[REGNO (cfun->machine->base_reg)] = 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 prologue was emitted. If it turns out later that we really - don't need them, the prologue/epilogue code is modified again. */ - - s390_frame_info (1, !TARGET_CPU_ZARCH - || cfun_frame_layout.save_return_addr_p); - - /* We need to update regs_ever_live to avoid data-flow problems. */ + /* Complete frame layout. */ - regs_ever_live[BASE_REGNUM] = 1; - regs_ever_live[RETURN_REGNUM] = (!TARGET_CPU_ZARCH - || cfun_frame_layout.save_return_addr_p); - regs_ever_live[STACK_POINTER_REGNUM] = cfun_frame_layout.frame_size > 0; + s390_update_frame_layout (); /* Annotate all constant pool references to let the scheduler know they implicitly use the base register. */ @@ -6297,7 +6372,8 @@ s390_emit_prologue (void) /* Dummy insn to mark literal pool slot. */ - emit_insn (gen_main_pool (cfun->machine->base_reg)); + if (cfun->machine->base_reg) + emit_insn (gen_main_pool (cfun->machine->base_reg)); offset = cfun_frame_layout.f0_offset; diff --git a/gcc/config/s390/s390.h b/gcc/config/s390/s390.h index 5b083aadbe6..9814561e052 100644 --- a/gcc/config/s390/s390.h +++ b/gcc/config/s390/s390.h @@ -652,26 +652,11 @@ extern int current_function_outgoing_args_size; { RETURN_ADDRESS_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ { RETURN_ADDRESS_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}} -#define CAN_ELIMINATE(FROM, TO) (1) - -#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ -{ if ((FROM) == FRAME_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM) \ - { (OFFSET) = 0; } \ - else if ((FROM) == FRAME_POINTER_REGNUM \ - && (TO) == HARD_FRAME_POINTER_REGNUM) \ - { (OFFSET) = 0; } \ - else if ((FROM) == ARG_POINTER_REGNUM \ - && (TO) == HARD_FRAME_POINTER_REGNUM) \ - { (OFFSET) = s390_arg_frame_offset (); } \ - else if ((FROM) == ARG_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM) \ - { (OFFSET) = s390_arg_frame_offset (); } \ - else if ((FROM) == RETURN_ADDRESS_POINTER_REGNUM \ - && ((TO) == STACK_POINTER_REGNUM \ - || (TO) == HARD_FRAME_POINTER_REGNUM)) \ - { (OFFSET) = s390_return_address_offset (); } \ - else \ - abort(); \ -} +#define CAN_ELIMINATE(FROM, TO) \ + s390_can_eliminate ((FROM), (TO)) + +#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ + (OFFSET) = s390_initial_elimination_offset ((FROM), (TO)) /* Stack arguments. */ |