From 0bfbc1662bc4aa9bcdc00b6a20e3cb9d23be0efe Mon Sep 17 00:00:00 2001 From: Steve Ellcey Date: Tue, 24 Nov 2015 22:09:17 +0000 Subject: [PATCH] frame-header-opt.c (gate): Check for optimize > 0. 2015-11-24 Steve Ellcey * 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 --- gcc/ChangeLog | 21 +++++++ gcc/config/mips/frame-header-opt.c | 88 +++++++++++++++++++++++++++--- gcc/config/mips/mips.c | 53 +++++++++++++++--- gcc/config/mips/mips.h | 7 +++ 4 files changed, 153 insertions(+), 16 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6333faa94f3..30ff440cd05 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,24 @@ +2015-11-24 Steve Ellcey + + * 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 PR rtl-optimization/68520 diff --git a/gcc/config/mips/frame-header-opt.c b/gcc/config/mips/frame-header-opt.c index 7c7b1f2209e..b80aa4db032 100644 --- a/gcc/config/mips/frame-header-opt.c +++ b/gcc/config/mips/frame-header-opt.c @@ -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; + 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. */ @@ -209,8 +275,16 @@ frame_header_opt () { fn = node->get_fun (); if (fn != NULL) - fn->machine->optimize_call_stack - = !callees_functions_use_frame_header (fn); + fn->machine->optimize_call_stack + = !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; } diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index d3b7730486d..eeb80eb1abb 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -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; @@ -11592,12 +11621,15 @@ mips_expand_prologue (void) } else { - rtx insn = gen_add3_insn (stack_pointer_rtx, - stack_pointer_rtx, - GEN_INT (-step1)); - RTX_FRAME_RELATED_P (emit_insn (insn)) = 1; - mips_frame_barrier (); - size -= step1; + if (step1 != 0) + { + rtx insn = gen_add3_insn (stack_pointer_rtx, + stack_pointer_rtx, + GEN_INT (-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_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. diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h index 501d283845b..7a4a0ba59a0 100644 --- a/gcc/config/mips/mips.h +++ b/gcc/config/mips/mips.h @@ -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 -- 2.30.2