Jakub Jelinek <jakub@redhat.com>

* config/sparc/sparc.h (FIXED_REGISTERS, CONDITIONAL_REGISTER_USAGE):
        Allow the user to override call-used/fixed state of %g2-5
        registers from the command line (with the exception of %g4 for
        embedded model).
        (REG_LEAF_ALLOC_ORDER): Move %g1 and %g4-7 registers to front, so that
        there is a higher chance of having a leaf function.
        (MACHINE_STATE_SAVE, MACHINE_STATE_RESTORE): Provide separate macros
        for ARCH64 which has %ccr register.
        * config/sparc/sparc.md (return_losum_si, return_losum_di): New
        patterns.
        * config/sparc/sparc.c (eligible_for_epilogue_delay): For the return
        insn accept into delay slot any insn which does not use %[ol]
        registers.  Accept some LO_SUM and shift left by 1 for the normal
        restore case.
        (output_function_epilogue): Likewise.
        (epilogue_renumber): Added argument which inhibits any renumbering
        and just tests if the rtx does not use any %[ol] registers.
        (output_return): Reflect above change.

From-SVN: r30727
This commit is contained in:
Jakub Jelinek 1999-11-30 23:18:21 +01:00 committed by Richard Henderson
parent f34e52f774
commit e48addeebc
4 changed files with 222 additions and 77 deletions

View File

@ -1,3 +1,24 @@
1999-11-30 Jakub Jelinek <jakub@redhat.com>
* config/sparc/sparc.h (FIXED_REGISTERS, CONDITIONAL_REGISTER_USAGE):
Allow the user to override call-used/fixed state of %g2-5
registers from the command line (with the exception of %g4 for
embedded model).
(REG_LEAF_ALLOC_ORDER): Move %g1 and %g4-7 registers to front, so that
there is a higher chance of having a leaf function.
(MACHINE_STATE_SAVE, MACHINE_STATE_RESTORE): Provide separate macros
for ARCH64 which has %ccr register.
* config/sparc/sparc.md (return_losum_si, return_losum_di): New
patterns.
* config/sparc/sparc.c (eligible_for_epilogue_delay): For the return
insn accept into delay slot any insn which does not use %[ol]
registers. Accept some LO_SUM and shift left by 1 for the normal
restore case.
(output_function_epilogue): Likewise.
(epilogue_renumber): Added argument which inhibits any renumbering
and just tests if the rtx does not use any %[ol] registers.
(output_return): Reflect above change.
1999-11-30 Jakub Jelinek <jakub@redhat.com>
* config/sparc/sparc.c (sparc_va_arg): Fix sparc64 va_arg

View File

@ -63,6 +63,10 @@ Boston, MA 02111-1307, USA. */
static int apparent_fsize;
static int actual_fsize;
/* Number of live general or floating point registers needed to be saved
(as 4-byte quantities). This is only done if TARGET_EPILOGUE. */
static int num_gfregs;
/* Save the operands last given to a compare for use when we
generate a scc or bcc insn. */
@ -124,7 +128,7 @@ static void sparc_output_deferred_case_vectors PROTO((void));
static void sparc_add_gc_roots PROTO ((void));
static void mark_ultrasparc_pipeline_state PROTO ((void *));
static int check_return_regs PROTO ((rtx));
static void epilogue_renumber PROTO ((rtx *));
static int epilogue_renumber PROTO ((rtx *, int));
static int ultra_cmove_results_ready_p PROTO ((rtx));
static int ultra_fpmode_conflict_exists PROTO ((enum machine_mode));
static rtx *ultra_find_type PROTO ((int, rtx *, int));
@ -2208,6 +2212,11 @@ eligible_for_epilogue_delay (trial, slot)
optimize things as necessary. */
if (TARGET_LIVE_G0)
return 0;
/* If there are any call-saved registers, we should scan TRIAL if it
does not reference them. For now just make it easy. */
if (num_gfregs)
return 0;
/* In the case of a true leaf function, anything can go into the delay slot.
A delay slot only exists however if the frame size is zero, otherwise
@ -2228,7 +2237,7 @@ eligible_for_epilogue_delay (trial, slot)
pat = PATTERN (trial);
/* Otherwise, only operations which can be done in tandem with
a `restore' insn can go into the delay slot. */
a `restore' or `return' insn can go into the delay slot. */
if (GET_CODE (SET_DEST (pat)) != REG
|| REGNO (SET_DEST (pat)) >= 32
|| REGNO (SET_DEST (pat)) < 24)
@ -2247,7 +2256,7 @@ eligible_for_epilogue_delay (trial, slot)
else
return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (SImode);
}
/* This matches "*return_di". */
else if (arith_double_operand (src, GET_MODE (src)))
return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode);
@ -2257,6 +2266,12 @@ eligible_for_epilogue_delay (trial, slot)
&& register_operand (src, SFmode))
return 1;
/* If we have return instruction, anything that does not use
local or output registers and can go into a delay slot wins. */
else if (TARGET_V9 && ! epilogue_renumber (&pat, 1)
&& (get_attr_in_uncond_branch_delay (trial) == IN_BRANCH_DELAY_TRUE))
return 1;
/* This matches "*return_addsi". */
else if (GET_CODE (src) == PLUS
&& arith_operand (XEXP (src, 0), SImode)
@ -2273,6 +2288,25 @@ eligible_for_epilogue_delay (trial, slot)
|| register_operand (XEXP (src, 1), DImode)))
return 1;
/* This can match "*return_losum_[sd]i".
Catch only some cases, so that return_losum* don't have
to be too big. */
else if (GET_CODE (src) == LO_SUM
&& ! TARGET_CM_MEDMID
&& ((register_operand (XEXP (src, 0), SImode)
&& immediate_operand (XEXP (src, 1), SImode))
|| (TARGET_ARCH64
&& register_operand (XEXP (src, 0), DImode)
&& immediate_operand (XEXP (src, 1), DImode))))
return 1;
/* sll{,x} reg,1,reg2 is add reg,reg,reg2 as well. */
else if (GET_CODE (src) == ASHIFT
&& (register_operand (XEXP (src, 0), SImode)
|| register_operand (XEXP (src, 0), DImode))
&& XEXP (src, 1) == const1_rtx)
return 1;
return 0;
}
@ -2979,12 +3013,6 @@ restore_regs (file, low, high, base, offset, n_regs)
return n_regs;
}
/* Static variables we want to share between prologue and epilogue. */
/* Number of live general or floating point registers needed to be saved
(as 4-byte quantities). This is only done if TARGET_EPILOGUE. */
static int num_gfregs;
/* Compute the frame size required by the function. This function is called
during the reload pass and also by output_function_prologue(). */
@ -3283,7 +3311,7 @@ output_function_epilogue (file, size, leaf_function)
#endif
else if (current_function_epilogue_delay_list == 0)
{
{
/* If code does not drop into the epilogue, we need
do nothing except output pending case vectors. */
rtx insn = get_last_insn ();
@ -3339,13 +3367,38 @@ output_function_epilogue (file, size, leaf_function)
/* If we wound up with things in our delay slot, flush them here. */
if (current_function_epilogue_delay_list)
{
rtx insn = emit_jump_insn_after (gen_rtx_RETURN (VOIDmode),
get_last_insn ());
PATTERN (insn) = gen_rtx_PARALLEL (VOIDmode,
gen_rtvec (2,
PATTERN (XEXP (current_function_epilogue_delay_list, 0)),
PATTERN (insn)));
final_scan_insn (insn, file, 1, 0, 1);
rtx delay = PATTERN (XEXP (current_function_epilogue_delay_list, 0));
if (TARGET_V9 && ! epilogue_renumber (&delay, 1))
{
epilogue_renumber (&delay, 0);
fputs (SKIP_CALLERS_UNIMP_P
? "\treturn\t%i7+12\n"
: "\treturn\t%i7+8\n", file);
final_scan_insn (XEXP (current_function_epilogue_delay_list, 0), file, 1, 0, 0);
}
else
{
rtx insn = emit_jump_insn_after (gen_rtx_RETURN (VOIDmode),
get_last_insn ());
rtx src;
if (GET_CODE (delay) != SET)
abort();
src = SET_SRC (delay);
if (GET_CODE (src) == ASHIFT)
{
if (XEXP (src, 1) != const1_rtx)
abort();
SET_SRC (delay) = gen_rtx_PLUS (GET_MODE (src), XEXP (src, 0),
XEXP (src, 0));
}
PATTERN (insn) = gen_rtx_PARALLEL (VOIDmode,
gen_rtvec (2, delay, PATTERN (insn)));
final_scan_insn (insn, file, 1, 0, 1);
}
}
else if (TARGET_V9 && ! SKIP_CALLERS_UNIMP_P)
fputs ("\treturn\t%i7+8\n\tnop\n", file);
@ -4726,56 +4779,56 @@ output_v9branch (op, reg, label, reversed, annul, noop, insn)
return string;
}
/* Renumber registers in delay slot. Replace registers instead of
renumbering because they may be shared.
/* Return 1, if any of the registers of the instruction are %l[0-7] or %o[0-7].
Such instructions cannot be used in the delay slot of return insn on v9.
If TEST is 0, also rename all %i[0-7] registers to their %o[0-7] counterparts.
*/
This does not handle instructions other than move. */
static void
epilogue_renumber (where)
rtx *where;
static int
epilogue_renumber (where, test)
register rtx *where;
int test;
{
rtx x = *where;
enum rtx_code code = GET_CODE (x);
register const char *fmt;
register int i;
register enum rtx_code code;
if (*where == 0)
return 0;
code = GET_CODE (*where);
switch (code)
{
case MEM:
*where = x = copy_rtx (x);
epilogue_renumber (&XEXP (x, 0));
return;
case REG:
{
int regno = REGNO (x);
if (regno > 8 && regno < 24)
abort ();
if (regno >= 24 && regno < 32)
*where = gen_rtx_REG (GET_MODE (x), regno - 16);
return;
}
if (REGNO (*where) >= 8 && REGNO (*where) < 24) /* oX or lX */
return 1;
if (! test && REGNO (*where) >= 24 && REGNO (*where) < 32)
*where = gen_rtx (REG, GET_MODE (*where), OUTGOING_REGNO (REGNO(*where)));
case SCRATCH:
case CC0:
case PC:
case CONST_INT:
case CONST_DOUBLE:
case CONST:
case SYMBOL_REF:
case LABEL_REF:
return;
case IOR:
case AND:
case XOR:
case PLUS:
case MINUS:
epilogue_renumber (&XEXP (x, 1));
case NEG:
case NOT:
epilogue_renumber (&XEXP (x, 0));
return;
default:
debug_rtx (*where);
abort ();
return 0;
}
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'E')
{
register int j;
for (j = XVECLEN (*where, i) - 1; j >= 0; j--)
if (epilogue_renumber (&(XVECEXP (*where, i, j)), test))
return 1;
}
else if (fmt[i] == 'e'
&& epilogue_renumber (&(XEXP (*where, i)), test))
return 1;
}
return 0;
}
/* Output assembler code to return from a function. */
@ -4840,8 +4893,8 @@ output_return (operands)
{
if (delay)
{
epilogue_renumber (&SET_DEST (PATTERN (delay)));
epilogue_renumber (&SET_SRC (PATTERN (delay)));
epilogue_renumber (&SET_DEST (PATTERN (delay)), 0);
epilogue_renumber (&SET_SRC (PATTERN (delay)), 0);
}
if (SKIP_CALLERS_UNIMP_P)
return "return\t%%i7+12%#";

View File

@ -962,7 +962,7 @@ if (TARGET_ARCH64 \
*/
#define FIXED_REGISTERS \
{1, 0, 0, 0, 0, 0, 1, 1, \
{1, 0, 2, 2, 2, 2, 1, 1, \
0, 0, 0, 0, 0, 0, 1, 0, \
0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 1, 1, \
@ -1015,10 +1015,12 @@ do \
fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \
call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \
} \
if (TARGET_ARCH32) \
{ \
fixed_regs[5] = 1; \
} \
/* If the user has passed -f{fixed,call-{used,saved}}-g5 */ \
/* then honour it. */ \
if (TARGET_ARCH32 && fixed_regs[5]) \
fixed_regs[5] = 1; \
else if (TARGET_ARCH64 && fixed_regs[5] == 2) \
fixed_regs[5] = 0; \
if (TARGET_LIVE_G0) \
fixed_regs[0] = 0; \
if (! TARGET_V9) \
@ -1040,10 +1042,18 @@ do \
for (regno = 32; regno < SPARC_LAST_V9_FCC_REG; regno++) \
fixed_regs[regno] = 1; \
} \
/* Don't unfix g2-g4 if they were fixed with -ffixed-. */ \
fixed_regs[2] |= ! TARGET_APP_REGS; \
fixed_regs[3] |= ! TARGET_APP_REGS; \
fixed_regs[4] |= ! TARGET_APP_REGS || TARGET_CM_EMBMEDANY; \
/* If the user has passed -f{fixed,call-{used,saved}}-g2 */ \
/* then honour it. Likewise with g3 and g4. */ \
if (fixed_regs[2] == 2) \
fixed_regs[2] = ! TARGET_APP_REGS; \
if (fixed_regs[3] == 2) \
fixed_regs[3] = ! TARGET_APP_REGS; \
if (TARGET_ARCH32 && fixed_regs[4] == 2) \
fixed_regs[4] = ! TARGET_APP_REGS; \
else if (TARGET_CM_EMBMEDANY) \
fixed_regs[4] = 1; \
else if (fixed_regs[4] == 2) \
fixed_regs[4] = 0; \
if (TARGET_FLAT) \
{ \
/* Let the compiler believe the frame pointer is still \
@ -1335,11 +1345,12 @@ extern enum reg_class sparc_regno_reg_class[];
1, 4, 5, 6, 7, 0, 14, 30}
/* This is the order in which to allocate registers for
leaf functions. If all registers can fit in the "i" registers,
leaf functions. If all registers can fit in the "gi" registers,
then we have the possibility of having a leaf function. */
#define REG_LEAF_ALLOC_ORDER \
{ 2, 3, 24, 25, 26, 27, 28, 29, \
4, 5, 6, 7, 1, \
15, 8, 9, 10, 11, 12, 13, \
16, 17, 18, 19, 20, 21, 22, 23, \
34, 35, 36, 37, 38, 39, \
@ -1352,8 +1363,8 @@ extern enum reg_class sparc_regno_reg_class[];
88, 89, 90, 91, 92, 93, 94, 95, \
32, 33, \
96, 97, 98, 99, 100, \
1, 4, 5, 6, 7, 0, 14, 30, 31}
0, 14, 30, 31}
#define ORDER_REGS_FOR_LOCAL_ALLOC order_regs_for_local_alloc ()
/* ??? %g7 is not a leaf register to effectively #undef LEAF_REGISTERS when
@ -1889,6 +1900,8 @@ do { \
#define FUNCTION_BLOCK_PROFILER_EXIT(FILE) \
sparc_function_block_profiler_exit(FILE)
#ifdef IN_LIBGCC2
/* The function `__bb_trace_func' is called in every basic block
and is not allowed to change the machine state. Saving (restoring)
the state can either be done in the BLOCK_PROFILER macro,
@ -1908,12 +1921,18 @@ do { \
On sparc it is sufficient to save the psw register to memory.
Unfortunately the psw register can be read in supervisor mode only,
so we read only the condition codes by using branch instructions
and hope that this is enough. */
and hope that this is enough.
On V9, life is much sweater: there is a user accessible %ccr
register, but we use it for 64bit libraries only. */
#if TARGET_ARCH32
#define MACHINE_STATE_SAVE(ID) \
int ms_flags, ms_saveret; \
asm volatile( \
"mov %%g0,%0\n\
"mov %%g2,%1\n\
mov %%g0,%0\n\
be,a LFLGNZ"ID"\n\
or %0,4,%0\n\
LFLGNZ"ID":\n\
@ -1925,10 +1944,20 @@ LFLGNC"ID":\n\
LFLGNV"ID":\n\
bneg,a LFLGNN"ID"\n\
or %0,8,%0\n\
LFLGNN"ID":\n\
mov %%g2,%1" \
LFLGNN"ID":" \
: "=r"(ms_flags), "=r"(ms_saveret));
#else
#define MACHINE_STATE_SAVE(ID) \
unsigned long ms_flags, ms_saveret; \
asm volatile( \
"mov %%g2,%1\n\ \
rd %%ccr,%0" \
: "=r"(ms_flags), "=r"(ms_saveret));
#endif
/* On sparc MACHINE_STATE_RESTORE restores the psw register from memory.
The psw register can be written in supervisor mode only,
which is true even for simple condition codes.
@ -1937,6 +1966,8 @@ LFLGNN"ID":\n\
be generated in this way. If this happens an unimplemented
instruction will be executed to abort the program. */
#if TARGET_ARCH32
#define MACHINE_STATE_RESTORE(ID) \
{ extern char flgtab[] __asm__("LFLGTAB"ID); \
int scratch; \
@ -1995,7 +2026,20 @@ LFLGRET"ID":\n\
: "=r"(scratch) \
: "r"(ms_flags*8), "r"(flgtab), "r"(-1), \
"r"(0x80000000), "r"(ms_saveret) \
: "cc", "%g2"); }
: "cc", "g2"); }
#else
#define MACHINE_STATE_RESTORE(ID) \
asm volatile ( \
"wr %0,0,%%ccr\n\
mov %1,%%g2" \
: : "r"(ms_flags), "r"(ms_saveret) \
: "cc", "g2");
#endif
#endif /* IN_LIBGCC2 */
/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function,
the stack pointer does not matter. The value is tested only in

View File

@ -8191,6 +8191,24 @@
}"
[(set_attr "type" "multi")])
(define_insn "*return_losum_si"
[(set (match_operand:SI 0 "restore_operand" "")
(lo_sum:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "immediate_operand" "in")))
(return)]
"! TARGET_EPILOGUE && ! TARGET_LIVE_G0 && ! TARGET_CM_MEDMID"
"*
{
if (! TARGET_ARCH64 && current_function_returns_struct)
return \"jmp\\t%%i7+12\\n\\trestore %r1, %%lo(%a2), %Y0\";
/* If operands are global or in registers, can use return */
else if (TARGET_V9 && IN_OR_GLOBAL_P (operands[1]))
return \"return\\t%%i7+8\\n\\tor\\t%Y1, %%lo(%a2), %Y0\";
else
return \"ret\;restore %r1, %%lo(%a2), %Y0\";
}"
[(set_attr "type" "multi")])
(define_insn "*return_di"
[(set (match_operand:DI 0 "restore_operand" "")
(match_operand:DI 1 "arith_double_operand" "rHI"))
@ -8208,6 +8226,15 @@
"ret\;restore %r1, %2, %Y0"
[(set_attr "type" "multi")])
(define_insn "*return_losum_di"
[(set (match_operand:DI 0 "restore_operand" "")
(lo_sum:DI (match_operand:DI 1 "arith_operand" "%r")
(match_operand:DI 2 "immediate_operand" "in")))
(return)]
"TARGET_ARCH64 && ! TARGET_EPILOGUE && ! TARGET_CM_MEDMID"
"ret\;restore %r1, %%lo(a2), %Y0"
[(set_attr "type" "multi")])
;; The following pattern is only generated by delayed-branch scheduling,
;; when the insn winds up in the epilogue.
(define_insn "*return_sf"