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:
parent
bde58e3208
commit
545d16ffb6
4 changed files with 138 additions and 95 deletions
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Add table
Reference in a new issue