frame-header-opt.c (gate): Check for optimize > 0.
2015-11-24 Steve Ellcey <sellcey@imgtec.com> * frame-header-opt.c (gate): Check for optimize > 0. (has_inlined_assembly): New function. (needs_frame_header_p): Remove is_leaf_function check, add argument type check. (callees_functions_use_frame_header): Add is_leaf_function and has_inlined_assembly calls.. (set_callers_may_not_allocate_frame): New function. (frame_header_opt): Add is_leaf_function call, add set_callers_may_not_allocate_frame call. * config/mips/mips.c (mips_compute_frame_info): Add check to see if callee saved regs can be put in frame header. (mips_expand_prologue): Add check to see if step1 is zero, fix cfa restores when using frame header to store regs. (mips_can_use_return_insn): Check to see if registers are stored in frame header. * config/mips/mips.h (machine_function): Add callers_may_not_allocate_frame and use_frame_header_for_callee_saved_regs fields. From-SVN: r230845
This commit is contained in:
parent
82ad51444f
commit
0bfbc1662b
|
@ -1,3 +1,24 @@
|
|||
2015-11-24 Steve Ellcey <sellcey@imgtec.com>
|
||||
|
||||
* frame-header-opt.c (gate): Check for optimize > 0.
|
||||
(has_inlined_assembly): New function.
|
||||
(needs_frame_header_p): Remove is_leaf_function check,
|
||||
add argument type check.
|
||||
(callees_functions_use_frame_header): Add is_leaf_function
|
||||
and has_inlined_assembly calls..
|
||||
(set_callers_may_not_allocate_frame): New function.
|
||||
(frame_header_opt): Add is_leaf_function call, add
|
||||
set_callers_may_not_allocate_frame call.
|
||||
* config/mips/mips.c (mips_compute_frame_info): Add check
|
||||
to see if callee saved regs can be put in frame header.
|
||||
(mips_expand_prologue): Add check to see if step1 is zero,
|
||||
fix cfa restores when using frame header to store regs.
|
||||
(mips_can_use_return_insn): Check to see if registers are
|
||||
stored in frame header.
|
||||
* config/mips/mips.h (machine_function): Add
|
||||
callers_may_not_allocate_frame and
|
||||
use_frame_header_for_callee_saved_regs fields.
|
||||
|
||||
2015-11-24 Segher Boessenkool <segher@kernel.crashing.org>
|
||||
|
||||
PR rtl-optimization/68520
|
||||
|
|
|
@ -79,7 +79,7 @@ public:
|
|||
/* This optimization has no affect if TARGET_NEWABI. If optimize
|
||||
is not at least 1 then the data needed for the optimization is
|
||||
not available and nothing will be done anyway. */
|
||||
return TARGET_OLDABI && flag_frame_header_optimization;
|
||||
return TARGET_OLDABI && flag_frame_header_optimization && optimize > 0;
|
||||
}
|
||||
|
||||
virtual unsigned int execute (function *) { return frame_header_opt (); }
|
||||
|
@ -125,6 +125,29 @@ is_leaf_function (function *fn)
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Return true if this function has inline assembly code or if we cannot
|
||||
be certain that it does not. False if we know that there is no inline
|
||||
assembly. */
|
||||
|
||||
static bool
|
||||
has_inlined_assembly (function *fn)
|
||||
{
|
||||
basic_block bb;
|
||||
gimple_stmt_iterator gsi;
|
||||
|
||||
/* If we do not have a cfg for this function be conservative and assume
|
||||
it is may have inline assembly. */
|
||||
if (fn->cfg == NULL)
|
||||
return true;
|
||||
|
||||
FOR_EACH_BB_FN (bb, fn)
|
||||
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
|
||||
if (gimple_code (gsi_stmt (gsi)) == GIMPLE_ASM)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Return true if this function will use the stack space allocated by its
|
||||
caller or if we cannot determine for certain that it does not. */
|
||||
|
||||
|
@ -136,20 +159,26 @@ needs_frame_header_p (function *fn)
|
|||
if (fn->decl == NULL)
|
||||
return true;
|
||||
|
||||
if (fn->stdarg || !is_leaf_function (fn))
|
||||
if (fn->stdarg)
|
||||
return true;
|
||||
|
||||
for (t = DECL_ARGUMENTS (fn->decl); t; t = TREE_CHAIN (t))
|
||||
{
|
||||
if (!use_register_for_decl (t))
|
||||
return true;
|
||||
|
||||
/* Some 64-bit types may get copied to general registers using the frame
|
||||
header, see mips_output_64bit_xfer. Checking for SImode only may be
|
||||
overly restrictive but it is guaranteed to be safe. */
|
||||
if (DECL_MODE (t) != SImode)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Returns TRUE if the argument stack space allocated by function FN is used.
|
||||
Returns FALSE if the space is needed or if the need for the space cannot
|
||||
/* Return true if the argument stack space allocated by function FN is used.
|
||||
Return false if the space is needed or if the need for the space cannot
|
||||
be determined. */
|
||||
|
||||
static bool
|
||||
|
@ -177,6 +206,8 @@ callees_functions_use_frame_header (function *fn)
|
|||
called_fn = DECL_STRUCT_FUNCTION (called_fn_tree);
|
||||
if (called_fn == NULL
|
||||
|| DECL_WEAK (called_fn_tree)
|
||||
|| has_inlined_assembly (called_fn)
|
||||
|| !is_leaf_function (called_fn)
|
||||
|| !called_fn->machine->does_not_use_frame_header)
|
||||
return true;
|
||||
}
|
||||
|
@ -188,6 +219,41 @@ callees_functions_use_frame_header (function *fn)
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Set the callers_may_not_allocate_frame flag for any function which
|
||||
function FN calls because FN may not allocate a frame header. */
|
||||
|
||||
static void
|
||||
set_callers_may_not_allocate_frame (function *fn)
|
||||
{
|
||||
basic_block bb;
|
||||
gimple_stmt_iterator gsi;
|
||||
gimple *stmt;
|
||||
tree called_fn_tree;
|
||||
function *called_fn;
|
||||
|
||||
if (fn->cfg == NULL)
|
||||
return;
|
||||
|
||||
FOR_EACH_BB_FN (bb, fn)
|
||||
{
|
||||
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
|
||||
{
|
||||
stmt = gsi_stmt (gsi);
|
||||
if (is_gimple_call (stmt))
|
||||
{
|
||||
called_fn_tree = gimple_call_fndecl (stmt);
|
||||
if (called_fn_tree != NULL)
|
||||
{
|
||||
called_fn = DECL_STRUCT_FUNCTION (called_fn_tree);
|
||||
if (called_fn != NULL)
|
||||
called_fn->machine->callers_may_not_allocate_frame = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Scan each function to determine those that need its frame headers. Perform
|
||||
a second scan to determine if the allocation can be skipped because none of
|
||||
their callees require the frame header. */
|
||||
|
@ -210,7 +276,15 @@ frame_header_opt ()
|
|||
fn = node->get_fun ();
|
||||
if (fn != NULL)
|
||||
fn->machine->optimize_call_stack
|
||||
= !callees_functions_use_frame_header (fn);
|
||||
= !callees_functions_use_frame_header (fn) && !is_leaf_function (fn);
|
||||
}
|
||||
|
||||
FOR_EACH_DEFINED_FUNCTION (node)
|
||||
{
|
||||
fn = node->get_fun ();
|
||||
if (fn != NULL && fn->machine->optimize_call_stack)
|
||||
set_callers_may_not_allocate_frame (fn);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -10474,6 +10474,35 @@ mips_compute_frame_info (void)
|
|||
frame->cop0_sp_offset = offset - UNITS_PER_WORD;
|
||||
}
|
||||
|
||||
/* Determine if we can save the callee-saved registers in the frame
|
||||
header. Restrict this to functions where there is no other reason
|
||||
to allocate stack space so that we can eliminate the instructions
|
||||
that modify the stack pointer. */
|
||||
|
||||
if (TARGET_OLDABI
|
||||
&& optimize > 0
|
||||
&& flag_frame_header_optimization
|
||||
&& !MAIN_NAME_P (DECL_NAME (current_function_decl))
|
||||
&& cfun->machine->varargs_size == 0
|
||||
&& crtl->args.pretend_args_size == 0
|
||||
&& frame->var_size == 0
|
||||
&& frame->num_acc == 0
|
||||
&& frame->num_cop0_regs == 0
|
||||
&& frame->num_fp == 0
|
||||
&& frame->num_gp > 0
|
||||
&& frame->num_gp <= MAX_ARGS_IN_REGISTERS
|
||||
&& !GENERATE_MIPS16E_SAVE_RESTORE
|
||||
&& !cfun->machine->interrupt_handler_p
|
||||
&& cfun->machine->does_not_use_frame_header
|
||||
&& cfun->machine->optimize_call_stack
|
||||
&& !cfun->machine->callers_may_not_allocate_frame
|
||||
&& !mips_cfun_has_cprestore_slot_p ())
|
||||
{
|
||||
offset = 0;
|
||||
frame->gp_sp_offset = REG_PARM_STACK_SPACE(cfun) - UNITS_PER_WORD;
|
||||
cfun->machine->use_frame_header_for_callee_saved_regs = true;
|
||||
}
|
||||
|
||||
/* Move above the callee-allocated varargs save area. */
|
||||
offset += MIPS_STACK_ALIGN (cfun->machine->varargs_size);
|
||||
frame->arg_pointer_offset = offset;
|
||||
|
@ -11591,6 +11620,8 @@ mips_expand_prologue (void)
|
|||
gen_rtx_REG (SImode, GP_REG_FIRST)));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (step1 != 0)
|
||||
{
|
||||
rtx insn = gen_add3_insn (stack_pointer_rtx,
|
||||
stack_pointer_rtx,
|
||||
|
@ -11599,6 +11630,7 @@ mips_expand_prologue (void)
|
|||
mips_frame_barrier ();
|
||||
size -= step1;
|
||||
}
|
||||
}
|
||||
mips_for_each_saved_acc (size, mips_save_reg);
|
||||
mips_for_each_saved_gpr_and_fpr (size, mips_save_reg);
|
||||
}
|
||||
|
@ -11722,9 +11754,9 @@ mips_epilogue_emit_cfa_restores (void)
|
|||
rtx_insn *insn;
|
||||
|
||||
insn = get_last_insn ();
|
||||
gcc_assert (insn && !REG_NOTES (insn));
|
||||
if (mips_epilogue.cfa_restores)
|
||||
{
|
||||
gcc_assert (insn && !REG_NOTES (insn));
|
||||
RTX_FRAME_RELATED_P (insn) = 1;
|
||||
REG_NOTES (insn) = mips_epilogue.cfa_restores;
|
||||
mips_epilogue.cfa_restores = 0;
|
||||
|
@ -11975,7 +12007,9 @@ mips_expand_epilogue (bool sibcall_p)
|
|||
mips_deallocate_stack (stack_pointer_rtx, GEN_INT (step2), 0);
|
||||
}
|
||||
|
||||
if (!use_jraddiusp_p)
|
||||
if (cfun->machine->use_frame_header_for_callee_saved_regs)
|
||||
mips_epilogue_emit_cfa_restores ();
|
||||
else if (!use_jraddiusp_p)
|
||||
gcc_assert (!mips_epilogue.cfa_restores);
|
||||
|
||||
/* Add in the __builtin_eh_return stack adjustment. We need to
|
||||
|
@ -12077,7 +12111,8 @@ mips_can_use_return_insn (void)
|
|||
if (mips16_cfun_returns_in_fpr_p ())
|
||||
return false;
|
||||
|
||||
return cfun->machine->frame.total_size == 0;
|
||||
return (cfun->machine->frame.total_size == 0
|
||||
&& !cfun->machine->use_frame_header_for_callee_saved_regs);
|
||||
}
|
||||
|
||||
/* Return true if register REGNO can store a value of mode MODE.
|
||||
|
|
|
@ -3273,6 +3273,13 @@ struct GTY(()) machine_function {
|
|||
/* True if none of the functions that are called by this function need
|
||||
stack space allocated for their arguments. */
|
||||
bool optimize_call_stack;
|
||||
|
||||
/* True if one of the functions calling this function may not allocate
|
||||
a frame header. */
|
||||
bool callers_may_not_allocate_frame;
|
||||
|
||||
/* True if GCC stored callee saved registers in the frame header. */
|
||||
bool use_frame_header_for_callee_saved_regs;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in New Issue