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:
parent
4badaa417d
commit
5be9b7a175
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
||||
|
@ -7684,6 +7684,11 @@
|
||||
sparc_expand_epilogue ();
|
||||
})
|
||||
|
||||
(define_expand "return"
|
||||
[(return)]
|
||||
"sparc_can_use_return_insn_p ()"
|
||||
"")
|
||||
|
||||
(define_insn "*return_internal"
|
||||
[(return)]
|
||||
""
|
||||
|
Loading…
Reference in New Issue
Block a user