re PR target/16532 (Inefficient jump to epilogue)

PR target/16532
	* config/sparc/sparc.c (struct machine_function): New field
	'leaf_function_p' and 'prologue_data_valid_p'.
	(sparc_leaf_function_p, sparc_prologue_data_valid_p): New macro
	to conveniently access the above fields.
	(TARGET_LATE_RTL_PROLOGUE_EPILOGUE): Delete.
	(eligible_for_return_delay): Use 'sparc_leaf_function_p' instead
	of the generic flavor 'current_function_uses_only_leaf_regs'.
	(eligible_for_sibcall_delay): Likewise.
	(sparc_expand_prologue): Compute 'sparc_leaf_function_p' and set
	'sparc_prologue_data_valid_p'.  Use 'sparc_leaf_function_p'.
	(sparc_asm_function_prologue): Add sanity check for the assumption
	made in 'sparc_expand_prologue'.  Use 'sparc_leaf_function_p'.
	(sparc_can_use_return_insn_p): New function.
	(sparc_expand_epilogue): Use 'sparc_leaf_function_p'.
	(output_restore): Likewise.
	(output_sibcall): Likewise.
	(sparc_output_mi_thunk): Likewise.
	* config/sparc/sparc-protos.h (sparc_can_use_return_insn_p): Declare.
	* config/sparc/sparc.md (return): New expander.

	* config/sparc/sparc.h (INITIAL_ELIMINATION_OFFSET): Minor tweak.

From-SVN: r88220
This commit is contained in:
Eric Botcazou 2004-09-28 08:26:08 +02:00 committed by Eric Botcazou
parent 4badaa417d
commit 5be9b7a175
5 changed files with 99 additions and 24 deletions

View File

@ -1,3 +1,28 @@
2004-09-28 Eric Botcazou <ebotcazou@libertysurf.fr>
PR target/16532
* config/sparc/sparc.c (struct machine_function): New field
'leaf_function_p' and 'prologue_data_valid_p'.
(sparc_leaf_function_p, sparc_prologue_data_valid_p): New macro
to conveniently access the above fields.
(TARGET_LATE_RTL_PROLOGUE_EPILOGUE): Delete.
(eligible_for_return_delay): Use 'sparc_leaf_function_p' instead
of the generic flavor 'current_function_uses_only_leaf_regs'.
(eligible_for_sibcall_delay): Likewise.
(sparc_expand_prologue): Compute 'sparc_leaf_function_p' and set
'sparc_prologue_data_valid_p'. Use 'sparc_leaf_function_p'.
(sparc_asm_function_prologue): Add sanity check for the assumption
made in 'sparc_expand_prologue'. Use 'sparc_leaf_function_p'.
(sparc_can_use_return_insn_p): New function.
(sparc_expand_epilogue): Use 'sparc_leaf_function_p'.
(output_restore): Likewise.
(output_sibcall): Likewise.
(sparc_output_mi_thunk): Likewise.
* config/sparc/sparc-protos.h (sparc_can_use_return_insn_p): Declare.
* config/sparc/sparc.md (return): New expander.
* config/sparc/sparc.h (INITIAL_ELIMINATION_OFFSET): Minor tweak.
2004-09-27 Mark Mitchell <mark@codesourcery.com>
PR c++/17642

View File

@ -47,6 +47,7 @@ extern void order_regs_for_local_alloc (void);
extern HOST_WIDE_INT sparc_compute_frame_size (HOST_WIDE_INT, int);
extern void sparc_expand_prologue (void);
extern void sparc_expand_epilogue (void);
extern bool sparc_can_use_return_insn_p (void);
extern int check_pic (int);
extern int short_branch (int, int);
extern void sparc_profile_hook (int);

View File

@ -270,8 +270,20 @@ struct machine_function GTY(())
{
/* Some local-dynamic TLS symbol name. */
const char *some_ld_name;
/* True if the current function is leaf and uses only leaf regs,
so that the SPARC leaf function optimization can be applied.
Private version of current_function_uses_only_leaf_regs, see
sparc_expand_prologue for the rationale. */
int leaf_function_p;
/* True if the data calculated by sparc_expand_prologue are valid. */
bool prologue_data_valid_p;
};
#define sparc_leaf_function_p cfun->machine->leaf_function_p
#define sparc_prologue_data_valid_p cfun->machine->prologue_data_valid_p
/* Register we pretend to think the frame pointer is allocated to.
Normally, this is %fp, but if we are in a leaf procedure, this
is %sp+"something". We record "something" separately as it may
@ -452,9 +464,6 @@ enum processor_type sparc_cpu;
#undef TARGET_GIMPLIFY_VA_ARG_EXPR
#define TARGET_GIMPLIFY_VA_ARG_EXPR sparc_gimplify_va_arg
#undef TARGET_LATE_RTL_PROLOGUE_EPILOGUE
#define TARGET_LATE_RTL_PROLOGUE_EPILOGUE true
#ifdef SUBTARGET_INSERT_ATTRIBUTES
#undef TARGET_INSERT_ATTRIBUTES
#define TARGET_INSERT_ATTRIBUTES SUBTARGET_INSERT_ATTRIBUTES
@ -3154,7 +3163,6 @@ eligible_for_restore_insn (rtx trial, bool return_p)
int
eligible_for_return_delay (rtx trial)
{
int leaf_function_p = current_function_uses_only_leaf_regs;
rtx pat;
if (GET_CODE (trial) != INSN || GET_CODE (PATTERN (trial)) != SET)
@ -3174,7 +3182,7 @@ eligible_for_return_delay (rtx trial)
return 0;
/* In the case of a true leaf function, anything can go into the slot. */
if (leaf_function_p)
if (sparc_leaf_function_p)
return get_attr_in_uncond_branch_delay (trial)
== IN_UNCOND_BRANCH_DELAY_TRUE;
@ -3204,7 +3212,6 @@ eligible_for_return_delay (rtx trial)
int
eligible_for_sibcall_delay (rtx trial)
{
int leaf_function_p = current_function_uses_only_leaf_regs;
rtx pat;
if (GET_CODE (trial) != INSN || GET_CODE (PATTERN (trial)) != SET)
@ -3215,7 +3222,7 @@ eligible_for_sibcall_delay (rtx trial)
pat = PATTERN (trial);
if (leaf_function_p)
if (sparc_leaf_function_p)
{
/* If the tail call is done using the call instruction,
we have to restore %o7 in the delay slot. */
@ -4469,13 +4476,40 @@ emit_stack_pointer_decrement (rtx decrement)
void
sparc_expand_prologue (void)
{
int leaf_function_p = current_function_uses_only_leaf_regs;
/* Compute a snapshot of current_function_uses_only_leaf_regs. Relying
on the final value of the flag means deferring the prologue/epilogue
expansion until just before the second scheduling pass, which is too
late to emit multiple epilogues or return insns.
Of course we are making the assumption that the value of the flag
will not change between now and its final value. Of the three parts
of the formula, only the last one can reasonably vary. Let's take a
closer look, after assuming that the first two ones are set to true
(otherwise the last value is effectively silenced).
If only_leaf_regs_used returns false, the global predicate will also
be false so the actual frame size calculated below will be positive.
As a consequence, the save_register_window insn will be emitted in
the instruction stream; now this insn explicitly references %fp
which is not a leaf register so only_leaf_regs_used will always
return false subsequently.
If only_leaf_regs_used returns true, we hope that the subsequent
optimization passes won't cause non-leaf registers to pop up. For
example, the regrename pass has special provisions to not rename to
non-leaf registers in a leaf function. */
sparc_leaf_function_p
= optimize > 0 && leaf_function_p () && only_leaf_regs_used ();
/* Need to use actual_fsize, since we are also allocating
space for our callee (and our own register save area). */
actual_fsize = sparc_compute_frame_size (get_frame_size(), leaf_function_p);
actual_fsize
= sparc_compute_frame_size (get_frame_size(), sparc_leaf_function_p);
if (leaf_function_p)
/* Advertise that the data calculated just above are now valid. */
sparc_prologue_data_valid_p = true;
if (sparc_leaf_function_p)
{
frame_base_reg = stack_pointer_rtx;
frame_base_offset = actual_fsize + SPARC_STACK_BIAS;
@ -4488,7 +4522,7 @@ sparc_expand_prologue (void)
if (actual_fsize == 0)
/* do nothing. */ ;
else if (leaf_function_p)
else if (sparc_leaf_function_p)
{
if (actual_fsize <= 4096)
emit_stack_pointer_increment (GEN_INT (- actual_fsize));
@ -4542,7 +4576,9 @@ sparc_expand_prologue (void)
static void
sparc_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
{
int leaf_function_p = current_function_uses_only_leaf_regs;
/* Check that the assumption we made in sparc_expand_prologue is valid. */
if (sparc_leaf_function_p != current_function_uses_only_leaf_regs)
abort();
sparc_output_scratch_registers (file);
@ -4552,12 +4588,12 @@ sparc_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
/* The canonical frame address refers to the top of the frame. */
dwarf2out_def_cfa (label,
leaf_function_p
sparc_leaf_function_p
? STACK_POINTER_REGNUM
: HARD_FRAME_POINTER_REGNUM,
frame_base_offset);
if (! leaf_function_p)
if (! sparc_leaf_function_p)
{
/* Note the register window save. This tells the unwinder that
it needs to restore the window registers from the previous
@ -4576,14 +4612,12 @@ sparc_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
void
sparc_expand_epilogue (void)
{
int leaf_function_p = current_function_uses_only_leaf_regs;
if (num_gfregs)
emit_restore_regs ();
if (actual_fsize == 0)
/* do nothing. */ ;
else if (leaf_function_p)
else if (sparc_leaf_function_p)
{
if (actual_fsize <= 4096)
emit_stack_pointer_decrement (GEN_INT (- actual_fsize));
@ -4600,6 +4634,16 @@ sparc_expand_epilogue (void)
}
}
}
/* Return true if it is appropriate to emit `return' instructions in the
body of a function. */
bool
sparc_can_use_return_insn_p (void)
{
return sparc_prologue_data_valid_p
&& (actual_fsize == 0 || !sparc_leaf_function_p);
}
/* This function generates the assembly code for function exit. */
@ -4677,7 +4721,7 @@ output_restore (rtx pat)
const char *
output_return (rtx insn)
{
if (current_function_uses_only_leaf_regs)
if (sparc_leaf_function_p)
{
/* This is a leaf function so we don't have to bother restoring the
register window, which frees us from dealing with the convoluted
@ -4766,7 +4810,7 @@ output_sibcall (rtx insn, rtx call_operand)
operands[0] = call_operand;
if (current_function_uses_only_leaf_regs)
if (sparc_leaf_function_p)
{
/* This is a leaf function so we don't have to bother restoring the
register window. We simply output the jump to the function and
@ -8499,7 +8543,7 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
{
/* We will emit a regular sibcall below, so we need to instruct
output_sibcall that we are in a leaf function. */
current_function_uses_only_leaf_regs = 1;
sparc_leaf_function_p = 1;
/* This will cause final.c to invoke leaf_renumber_regs so we
must behave as if we were in a not-yet-leafified function. */
@ -8509,7 +8553,7 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
{
/* We will emit the sibcall manually below, so we will need to
manually spill non-leaf registers. */
current_function_uses_only_leaf_regs = 0;
sparc_leaf_function_p = 0;
/* We really are in a leaf function. */
int_arg_first = SPARC_OUTGOING_INT_ARG_FIRST;

View File

@ -1121,8 +1121,7 @@ extern int sparc_mode_class[];
/* Value should be nonzero if functions must have frame pointers.
Zero means the frame pointer need not be set up (and parms
may be accessed via the stack pointer) in functions that seem suitable.
This is computed in `reload', in reload1.c.
Used in flow.c, global.c, and reload1.c. */
Used in flow.c, global.c, ra.c and reload1.c. */
#define FRAME_POINTER_REQUIRED \
(! (leaf_function_p () && only_leaf_regs_used ()))
@ -1594,9 +1593,10 @@ extern char leaf_reg_remap[];
is a leaf function, we guessed right! */
#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
do { \
(OFFSET) = 0; \
if ((TO) == STACK_POINTER_REGNUM) \
(OFFSET) = sparc_compute_frame_size (get_frame_size (), 1); \
else \
(OFFSET) = 0; \
(OFFSET) += SPARC_STACK_BIAS; \
} while (0)

View File

@ -7684,6 +7684,11 @@
sparc_expand_epilogue ();
})
(define_expand "return"
[(return)]
"sparc_can_use_return_insn_p ()"
"")
(define_insn "*return_internal"
[(return)]
""