s390-protos.h (s390_arg_frame_offset): Remove.

* 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.

From-SVN: r88357
This commit is contained in:
Ulrich Weigand 2004-09-30 21:23:29 +00:00 committed by Ulrich Weigand
parent 13c025c186
commit 9108699053
4 changed files with 209 additions and 121 deletions

View File

@ -1,3 +1,30 @@
2004-09-30 Ulrich Weigand <uweigand@de.ibm.com>
* 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.
2004-09-30 Ulrich Weigand <uweigand@de.ibm.com>
* config/s390/s390.c (legitimate_reload_constant_p): Remove

View File

@ -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);

View File

@ -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[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[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)
{
/* 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;
HOST_WIDE_INT frame_size;
int base_used;
int live_regs[16];
s390_frame_info (1, !TARGET_CPU_ZARCH || return_addr_used);
/* 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;
return cfun_frame_layout.frame_size + STACK_POINTER_OFFSET;
/* 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);
}
/* Return offset between return address pointer (location of r14
on the stack) and frame pointer initially after prologue. */
/* 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)
{
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);
/* 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 true;
}
/* 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;
return (cfun_frame_layout.frame_size + cfun_frame_layout.gprs_offset
+ (RETURN_REGNUM - cfun_frame_layout.first_save_gpr) * UNITS_PER_WORD);
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;
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. */
/* Complete frame layout. */
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. */
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;

View File

@ -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 CAN_ELIMINATE(FROM, TO) \
s390_can_eliminate ((FROM), (TO))
#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 INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
(OFFSET) = s390_initial_elimination_offset ((FROM), (TO))
/* Stack arguments. */