s390.c (struct machine_function): Use save_return_addr_p as a general flag that the return address register needs...

* config/s390/s390.c (struct machine_function): Use save_return_addr_p
	as a general flag that the return address register needs to be saved,
	not necessarily because of __builtin_return_addr (0).
	(s390_split_branches): Remove TEMP_REG and TEMP_USED arguments,
	remove special handling of zSeries machines.
	(s390_optimize_prolog): Remove TEMP_USED argument, treat the return
	register as a regular register on zSeries machines.
	(s390_reorg): Adjust calls to s390_split_branches and
	s390_optimize_prolog.
	(s390_frame_info): On zSeries machines, do not assume the return
	register is always used.  Update regs_ever_live with current data
	for the special registers.
	(s390_emit_epilogue): Use save_return_addr_p to determine whether
	the return register was saved.
	* config/s390/s390.h (CONDITIONAL_REGISTER_USAGE): Do not mark
	RETURN_REGNUM fixed on zSeries machines.
	(REG_ALLOC_ORDER): Use RETURN_REGNUM last.
	* config/s390/s390.md ("*doloop_si"): Handle branch overflow
	via ahi-jgne pair on zSeries machines.
	("*doloop_di"): Likewise.
	("*doloop_di_long"): Remove.

From-SVN: r73084
This commit is contained in:
Ulrich Weigand 2003-10-30 14:11:34 +00:00 committed by Ulrich Weigand
parent bde58e3208
commit 545d16ffb6
4 changed files with 138 additions and 95 deletions

View file

@ -1,3 +1,27 @@
2003-10-30 Ulrich Weigand <uweigand@de.ibm.com>
* config/s390/s390.c (struct machine_function): Use save_return_addr_p
as a general flag that the return address register needs to be saved,
not necessarily because of __builtin_return_addr (0).
(s390_split_branches): Remove TEMP_REG and TEMP_USED arguments,
remove special handling of zSeries machines.
(s390_optimize_prolog): Remove TEMP_USED argument, treat the return
register as a regular register on zSeries machines.
(s390_reorg): Adjust calls to s390_split_branches and
s390_optimize_prolog.
(s390_frame_info): On zSeries machines, do not assume the return
register is always used. Update regs_ever_live with current data
for the special registers.
(s390_emit_epilogue): Use save_return_addr_p to determine whether
the return register was saved.
* config/s390/s390.h (CONDITIONAL_REGISTER_USAGE): Do not mark
RETURN_REGNUM fixed on zSeries machines.
(REG_ALLOC_ORDER): Use RETURN_REGNUM last.
* config/s390/s390.md ("*doloop_si"): Handle branch overflow
via ahi-jgne pair on zSeries machines.
("*doloop_di"): Likewise.
("*doloop_di_long"): Remove.
2003-10-30 Richard Earnshaw <rearnsha@arm.com>
* arm.c (arm_override_options): Revert change of arm_constant_limit

View file

@ -190,8 +190,7 @@ struct machine_function GTY(())
/* Set, if some of the fprs 8-15 need to be saved (64 bit abi). */
int save_fprs_p;
/* Set if return address needs to be saved because the current
function uses __builtin_return_addr (0). */
/* Set if return address needs to be saved. */
bool save_return_addr_p;
/* Number of first and last gpr to be saved, restored. */
@ -220,12 +219,12 @@ static const char *get_some_local_dynamic_name (void);
static int get_some_local_dynamic_name_1 (rtx *, void *);
static int reg_used_in_mem_p (int, rtx);
static int addr_generation_dependency_p (rtx, rtx);
static int s390_split_branches (rtx, bool *);
static int s390_split_branches (void);
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 *, rtx);
static void s390_optimize_prolog (bool, bool);
static void s390_optimize_prolog (bool);
static int find_unused_clobbered_reg (void);
static void s390_frame_info (void);
static rtx save_fpr (rtx, int, int);
@ -3882,15 +3881,12 @@ s390_sched_reorder2 (FILE *dump ATTRIBUTE_UNUSED,
/* Split all branches that exceed the maximum distance.
Returns true if this created a new literal pool entry.
Code generated by this routine is allowed to use
TEMP_REG as temporary scratch register. If this is
done, TEMP_USED is set to true. */
Returns true if this created a new literal pool entry. */
static int
s390_split_branches (rtx temp_reg, bool *temp_used)
s390_split_branches (void)
{
rtx temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
int new_literal = 0;
rtx insn, pat, tmp, target;
rtx *label;
@ -3928,19 +3924,14 @@ s390_split_branches (rtx temp_reg, bool *temp_used)
else
continue;
if (get_attr_length (insn) <= (TARGET_CPU_ZARCH ? 6 : 4))
if (get_attr_length (insn) <= 4)
continue;
*temp_used = 1;
/* We are going to use the return register as scratch register,
make sure it will be saved/restored by the prologue/epilogue. */
cfun->machine->save_return_addr_p = 1;
if (TARGET_CPU_ZARCH)
{
tmp = emit_insn_before (gen_rtx_SET (Pmode, temp_reg, *label), insn);
INSN_ADDRESSES_NEW (tmp, -1);
target = temp_reg;
}
else if (!flag_pic)
if (!flag_pic)
{
new_literal = 1;
tmp = force_const_mem (Pmode, *label);
@ -5023,12 +5014,10 @@ s390_output_pool_entry (FILE *file, rtx exp, enum machine_mode mode,
/* Rework the prolog/epilog to avoid saving/restoring
registers unnecessarily. BASE_USED specifies whether
the literal pool base register needs to be saved,
TEMP_USED specifies whether the return register needs
to be saved. */
the literal pool base register needs to be saved. */
static void
s390_optimize_prolog (bool base_used, bool temp_used)
s390_optimize_prolog (bool base_used)
{
int save_first, save_last, restore_first, restore_last;
int i, j;
@ -5036,17 +5025,9 @@ s390_optimize_prolog (bool base_used, bool temp_used)
/* Recompute regs_ever_live data for special registers. */
regs_ever_live[BASE_REGISTER] = base_used;
regs_ever_live[RETURN_REGNUM] = temp_used;
regs_ever_live[RETURN_REGNUM] = cfun->machine->save_return_addr_p;
regs_ever_live[STACK_POINTER_REGNUM] = cfun->machine->frame_size > 0;
/* In non-leaf functions, the prolog/epilog code relies
on RETURN_REGNUM being saved in any case. We also need
to save the return register if __builtin_return_address (0)
was used in the current function. */
if (!current_function_is_leaf
|| cfun->machine->save_return_addr_p)
regs_ever_live[RETURN_REGNUM] = 1;
/* Find first and last gpr to be saved. */
@ -5093,7 +5074,7 @@ s390_optimize_prolog (bool base_used, bool temp_used)
/* 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
&& i <= RETURN_REGNUM && j >= RETURN_REGNUM)
&& (TARGET_CPU_ZARCH || (i <= RETURN_REGNUM && j >= RETURN_REGNUM)))
return;
@ -5108,10 +5089,9 @@ s390_optimize_prolog (bool base_used, bool temp_used)
if (GET_CODE (insn) != INSN)
continue;
if (GET_CODE (PATTERN (insn)) != PARALLEL)
continue;
if (store_multiple_operation (PATTERN (insn), VOIDmode))
if (GET_CODE (PATTERN (insn)) == PARALLEL
&& store_multiple_operation (PATTERN (insn), VOIDmode))
{
set = XVECEXP (PATTERN (insn), 0, 0);
first = REGNO (SET_SRC (set));
@ -5122,9 +5102,7 @@ s390_optimize_prolog (bool base_used, bool temp_used)
if (GET_CODE (base) != REG || off < 0)
continue;
if (first > BASE_REGISTER && first > RETURN_REGNUM)
continue;
if (last < BASE_REGISTER && last < RETURN_REGNUM)
if (first > BASE_REGISTER || last < BASE_REGISTER)
continue;
if (save_first != -1)
@ -5135,9 +5113,35 @@ s390_optimize_prolog (bool base_used, bool temp_used)
}
remove_insn (insn);
continue;
}
if (load_multiple_operation (PATTERN (insn), VOIDmode))
if (GET_CODE (PATTERN (insn)) == SET
&& GET_CODE (SET_SRC (PATTERN (insn))) == REG
&& REGNO (SET_SRC (PATTERN (insn))) == BASE_REGISTER
&& GET_CODE (SET_DEST (PATTERN (insn))) == MEM)
{
set = PATTERN (insn);
offset = const0_rtx;
base = eliminate_constant_term (XEXP (SET_DEST (set), 0), &offset);
off = INTVAL (offset) - BASE_REGISTER * UNITS_PER_WORD;
if (GET_CODE (base) != REG || off < 0)
continue;
if (save_first != -1)
{
new_insn = save_gprs (base, off, save_first, save_last);
new_insn = emit_insn_before (new_insn, insn);
INSN_ADDRESSES_NEW (new_insn, -1);
}
remove_insn (insn);
continue;
}
if (GET_CODE (PATTERN (insn)) == PARALLEL
&& load_multiple_operation (PATTERN (insn), VOIDmode))
{
set = XVECEXP (PATTERN (insn), 0, 0);
first = REGNO (SET_DEST (set));
@ -5148,9 +5152,7 @@ s390_optimize_prolog (bool base_used, bool temp_used)
if (GET_CODE (base) != REG || off < 0)
continue;
if (first > BASE_REGISTER && first > RETURN_REGNUM)
continue;
if (last < BASE_REGISTER && last < RETURN_REGNUM)
if (first > BASE_REGISTER || last < BASE_REGISTER)
continue;
if (restore_first != -1)
@ -5161,6 +5163,31 @@ s390_optimize_prolog (bool base_used, bool temp_used)
}
remove_insn (insn);
continue;
}
if (GET_CODE (PATTERN (insn)) == SET
&& GET_CODE (SET_DEST (PATTERN (insn))) == REG
&& REGNO (SET_DEST (PATTERN (insn))) == BASE_REGISTER
&& GET_CODE (SET_SRC (PATTERN (insn))) == MEM)
{
set = PATTERN (insn);
offset = const0_rtx;
base = eliminate_constant_term (XEXP (SET_SRC (set), 0), &offset);
off = INTVAL (offset) - BASE_REGISTER * UNITS_PER_WORD;
if (GET_CODE (base) != REG || off < 0)
continue;
if (restore_first != -1)
{
new_insn = restore_gprs (base, off, restore_first, restore_last);
new_insn = emit_insn_before (new_insn, insn);
INSN_ADDRESSES_NEW (new_insn, -1);
}
remove_insn (insn);
continue;
}
}
}
@ -5170,9 +5197,7 @@ s390_optimize_prolog (bool base_used, bool temp_used)
static void
s390_reorg (void)
{
rtx temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
rtx base_reg = gen_rtx_REG (Pmode, BASE_REGISTER);
bool temp_used = false;
bool base_used = false;
bool pool_overflow = false;
@ -5238,8 +5263,9 @@ s390_reorg (void)
/* Split out-of-range branches. If this has created new
literal pool entries, cancel current chunk list and
recompute it. */
if (s390_split_branches (temp_reg, &temp_used))
recompute it. zSeries machines have large branch
instructions, so we never need to split a branch. */
if (!TARGET_CPU_ZARCH && s390_split_branches ())
{
if (pool_overflow)
s390_chunkify_cancel (pool);
@ -5263,7 +5289,7 @@ s390_reorg (void)
break;
}
s390_optimize_prolog (base_used, temp_used);
s390_optimize_prolog (base_used);
}
@ -5309,7 +5335,6 @@ find_unused_clobbered_reg (void)
static void
s390_frame_info (void)
{
char gprs_ever_live[16];
int i, j;
HOST_WIDE_INT fsize = get_frame_size ();
@ -5336,31 +5361,42 @@ s390_frame_info (void)
|| 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. */
if (!current_function_is_leaf
|| regs_ever_live[RETURN_REGNUM])
cfun->machine->save_return_addr_p = 1;
/* Find first and last gpr to be saved. Note that at this point,
we assume the return register and the base register always
need to be saved. This is done because the usage of these
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++)
gprs_ever_live[i] = regs_ever_live[i] && !global_regs[i];
if (flag_pic)
gprs_ever_live[PIC_OFFSET_TABLE_REGNUM] =
regs_ever_live[PIC_OFFSET_TABLE_REGNUM];
gprs_ever_live[BASE_REGISTER] = 1;
gprs_ever_live[RETURN_REGNUM] = 1;
gprs_ever_live[STACK_POINTER_REGNUM] = cfun->machine->frame_size > 0;
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;
for (i = 6; i < 16; i++)
if (gprs_ever_live[i])
break;
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 (gprs_ever_live[j])
break;
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;
/* Save / Restore from gpr i to j. */
cfun->machine->first_save_gpr = i;
@ -5911,7 +5947,7 @@ s390_emit_epilogue (void)
/* Fetch return address from stack before load multiple,
this will do good for scheduling. */
if (!current_function_is_leaf)
if (cfun->machine->save_return_addr_p)
{
int return_regnum = find_unused_clobbered_reg();
if (!return_regnum)

View file

@ -313,7 +313,7 @@ if (INTEGRAL_MODE_P (MODE) && \
GPRs 6-15 are always call-saved.
GPR 12 is fixed if used as GOT pointer.
GPR 13 is always fixed (as literal pool pointer).
GPR 14 is always fixed (as return address).
GPR 14 is always fixed on S/390 machines (as return address).
GPR 15 is always fixed (as stack pointer).
The 'fake' hard registers are call-clobbered and fixed.
@ -364,6 +364,11 @@ do \
fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \
call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \
} \
if (TARGET_CPU_ZARCH) \
{ \
fixed_regs[RETURN_REGNUM] = 0; \
call_used_regs[RETURN_REGNUM] = 0; \
} \
if (TARGET_64BIT) \
{ \
for (i = 24; i < 32; i++) \
@ -378,7 +383,7 @@ do \
/* Preferred register allocation order. */
#define REG_ALLOC_ORDER \
{ 1, 2, 3, 4, 5, 0, 14, 13, 12, 11, 10, 9, 8, 7, 6, \
{ 1, 2, 3, 4, 5, 0, 13, 12, 11, 10, 9, 8, 7, 6, 14, \
16, 17, 18, 19, 20, 21, 22, 23, \
24, 25, 26, 27, 28, 29, 30, 31, \
15, 32, 33, 34 }

View file

@ -6596,6 +6596,8 @@
return "#";
else if (get_attr_length (insn) == 4)
return "brct\t%1,%l0";
else if (TARGET_CPU_ZARCH)
return "ahi\t%1,-1\;jgne\t%l0";
else
abort ();
}
@ -6675,37 +6677,13 @@
else if (get_attr_length (insn) == 4)
return "brctg\t%1,%l0";
else
abort ();
return "aghi\t%1,-1\;jgne\t%l0";
}
[(set_attr "op_type" "RI")
(set_attr "type" "branch")
(set (attr "length")
(if_then_else (lt (abs (minus (pc) (match_dup 0))) (const_int 60000))
(const_int 4) (const_int 12)))])
(define_insn "*doloop_di_long"
[(set (pc)
(if_then_else
(ne (match_operand:DI 1 "register_operand" "d,d")
(const_int 1))
(match_operand 0 "address_operand" "U,U")
(pc)))
(set (match_operand:DI 2 "register_operand" "=1,?*m*d")
(plus:DI (match_dup 1) (const_int -1)))
(clobber (match_scratch:DI 3 "=X,&d"))
(clobber (reg:CC 33))]
""
{
if (get_attr_op_type (insn) == OP_TYPE_RRE)
return "bctgr\t%1,%0";
else
return "bctg\t%1,%a0";
}
[(set (attr "op_type")
(if_then_else (match_operand 0 "register_operand" "")
(const_string "RRE") (const_string "RXE")))
(set_attr "type" "branch")
(set_attr "atype" "agen")])
(const_int 4) (const_int 10)))])
(define_split
[(set (pc)