Commit 0bfbc166 by Steve Ellcey Committed by Steve Ellcey

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
parent 82ad5144
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> 2015-11-24 Segher Boessenkool <segher@kernel.crashing.org>
PR rtl-optimization/68520 PR rtl-optimization/68520
...@@ -79,7 +79,7 @@ public: ...@@ -79,7 +79,7 @@ public:
/* This optimization has no affect if TARGET_NEWABI. If optimize /* This optimization has no affect if TARGET_NEWABI. If optimize
is not at least 1 then the data needed for the optimization is is not at least 1 then the data needed for the optimization is
not available and nothing will be done anyway. */ 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 (); } virtual unsigned int execute (function *) { return frame_header_opt (); }
...@@ -125,6 +125,29 @@ is_leaf_function (function *fn) ...@@ -125,6 +125,29 @@ is_leaf_function (function *fn)
return true; 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 /* 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. */ caller or if we cannot determine for certain that it does not. */
...@@ -136,20 +159,26 @@ needs_frame_header_p (function *fn) ...@@ -136,20 +159,26 @@ needs_frame_header_p (function *fn)
if (fn->decl == NULL) if (fn->decl == NULL)
return true; return true;
if (fn->stdarg || !is_leaf_function (fn)) if (fn->stdarg)
return true; return true;
for (t = DECL_ARGUMENTS (fn->decl); t; t = TREE_CHAIN (t)) for (t = DECL_ARGUMENTS (fn->decl); t; t = TREE_CHAIN (t))
{ {
if (!use_register_for_decl (t)) if (!use_register_for_decl (t))
return true; 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; return false;
} }
/* Returns TRUE if the argument stack space allocated by function FN is used. /* Return 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 false if the space is needed or if the need for the space cannot
be determined. */ be determined. */
static bool static bool
...@@ -177,6 +206,8 @@ callees_functions_use_frame_header (function *fn) ...@@ -177,6 +206,8 @@ callees_functions_use_frame_header (function *fn)
called_fn = DECL_STRUCT_FUNCTION (called_fn_tree); called_fn = DECL_STRUCT_FUNCTION (called_fn_tree);
if (called_fn == NULL if (called_fn == NULL
|| DECL_WEAK (called_fn_tree) || DECL_WEAK (called_fn_tree)
|| has_inlined_assembly (called_fn)
|| !is_leaf_function (called_fn)
|| !called_fn->machine->does_not_use_frame_header) || !called_fn->machine->does_not_use_frame_header)
return true; return true;
} }
...@@ -188,6 +219,41 @@ callees_functions_use_frame_header (function *fn) ...@@ -188,6 +219,41 @@ callees_functions_use_frame_header (function *fn)
return false; 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 /* 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 a second scan to determine if the allocation can be skipped because none of
their callees require the frame header. */ their callees require the frame header. */
...@@ -209,8 +275,16 @@ frame_header_opt () ...@@ -209,8 +275,16 @@ frame_header_opt ()
{ {
fn = node->get_fun (); fn = node->get_fun ();
if (fn != NULL) if (fn != NULL)
fn->machine->optimize_call_stack 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; return 0;
} }
...@@ -10474,6 +10474,35 @@ mips_compute_frame_info (void) ...@@ -10474,6 +10474,35 @@ mips_compute_frame_info (void)
frame->cop0_sp_offset = offset - UNITS_PER_WORD; 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. */ /* Move above the callee-allocated varargs save area. */
offset += MIPS_STACK_ALIGN (cfun->machine->varargs_size); offset += MIPS_STACK_ALIGN (cfun->machine->varargs_size);
frame->arg_pointer_offset = offset; frame->arg_pointer_offset = offset;
...@@ -11592,12 +11621,15 @@ mips_expand_prologue (void) ...@@ -11592,12 +11621,15 @@ mips_expand_prologue (void)
} }
else else
{ {
rtx insn = gen_add3_insn (stack_pointer_rtx, if (step1 != 0)
stack_pointer_rtx, {
GEN_INT (-step1)); rtx insn = gen_add3_insn (stack_pointer_rtx,
RTX_FRAME_RELATED_P (emit_insn (insn)) = 1; stack_pointer_rtx,
mips_frame_barrier (); GEN_INT (-step1));
size -= step1; RTX_FRAME_RELATED_P (emit_insn (insn)) = 1;
mips_frame_barrier ();
size -= step1;
}
} }
mips_for_each_saved_acc (size, mips_save_reg); mips_for_each_saved_acc (size, mips_save_reg);
mips_for_each_saved_gpr_and_fpr (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) ...@@ -11722,9 +11754,9 @@ mips_epilogue_emit_cfa_restores (void)
rtx_insn *insn; rtx_insn *insn;
insn = get_last_insn (); insn = get_last_insn ();
gcc_assert (insn && !REG_NOTES (insn));
if (mips_epilogue.cfa_restores) if (mips_epilogue.cfa_restores)
{ {
gcc_assert (insn && !REG_NOTES (insn));
RTX_FRAME_RELATED_P (insn) = 1; RTX_FRAME_RELATED_P (insn) = 1;
REG_NOTES (insn) = mips_epilogue.cfa_restores; REG_NOTES (insn) = mips_epilogue.cfa_restores;
mips_epilogue.cfa_restores = 0; mips_epilogue.cfa_restores = 0;
...@@ -11975,7 +12007,9 @@ mips_expand_epilogue (bool sibcall_p) ...@@ -11975,7 +12007,9 @@ mips_expand_epilogue (bool sibcall_p)
mips_deallocate_stack (stack_pointer_rtx, GEN_INT (step2), 0); 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); gcc_assert (!mips_epilogue.cfa_restores);
/* Add in the __builtin_eh_return stack adjustment. We need to /* Add in the __builtin_eh_return stack adjustment. We need to
...@@ -12077,7 +12111,8 @@ mips_can_use_return_insn (void) ...@@ -12077,7 +12111,8 @@ mips_can_use_return_insn (void)
if (mips16_cfun_returns_in_fpr_p ()) if (mips16_cfun_returns_in_fpr_p ())
return false; 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. /* Return true if register REGNO can store a value of mode MODE.
......
...@@ -3273,6 +3273,13 @@ struct GTY(()) machine_function { ...@@ -3273,6 +3273,13 @@ struct GTY(()) machine_function {
/* True if none of the functions that are called by this function need /* True if none of the functions that are called by this function need
stack space allocated for their arguments. */ stack space allocated for their arguments. */
bool optimize_call_stack; 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 #endif
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment