diff options
Diffstat (limited to 'gcc/config/sparc/sparc.c')
| -rw-r--r-- | gcc/config/sparc/sparc.c | 86 |
1 files changed, 65 insertions, 21 deletions
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); + + /* Advertise that the data calculated just above are now valid. */ + sparc_prologue_data_valid_p = true; - if (leaf_function_p) + 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; |

