From 5be9b7a1750e019b85286348a325f00819daca52 Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Tue, 28 Sep 2004 08:26:08 +0200 Subject: [PATCH] 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 --- gcc/ChangeLog | 25 ++++++++++ gcc/config/sparc/sparc-protos.h | 1 + gcc/config/sparc/sparc.c | 86 +++++++++++++++++++++++++-------- gcc/config/sparc/sparc.h | 6 +-- gcc/config/sparc/sparc.md | 5 ++ 5 files changed, 99 insertions(+), 24 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d7fb97a35ac..678c005e25a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,28 @@ +2004-09-28 Eric Botcazou + + 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 PR c++/17642 diff --git a/gcc/config/sparc/sparc-protos.h b/gcc/config/sparc/sparc-protos.h index 71599c96223..e181f8f73bb 100644 --- a/gcc/config/sparc/sparc-protos.h +++ b/gcc/config/sparc/sparc-protos.h @@ -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); diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index 63d3f01cdca..aa1fa0905b1 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -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; diff --git a/gcc/config/sparc/sparc.h b/gcc/config/sparc/sparc.h index 5cf5201e0ef..d1b93ec1ab7 100644 --- a/gcc/config/sparc/sparc.h +++ b/gcc/config/sparc/sparc.h @@ -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) diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md index a077f8c881e..d91e51d5656 100644 --- a/gcc/config/sparc/sparc.md +++ b/gcc/config/sparc/sparc.md @@ -7684,6 +7684,11 @@ sparc_expand_epilogue (); }) +(define_expand "return" + [(return)] + "sparc_can_use_return_insn_p ()" + "") + (define_insn "*return_internal" [(return)] ""