{
/* 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
#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
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)
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;
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)
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. */
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;
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));
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);
/* 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
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));
}
}
}
+
+/* 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. */
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
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
{
/* 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. */
{
/* 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;