From: Steve Ellcey Date: Fri, 9 Oct 2015 17:10:42 +0000 (+0000) Subject: config.gcc (mips*-*-*): Add frame-header-opt.o to extra_objs. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=d41c8b4c43d7050f05668f23ad4563ed6e9b41d0;p=gcc.git config.gcc (mips*-*-*): Add frame-header-opt.o to extra_objs. 2015-10-05 Steve Ellcey * config.gcc (mips*-*-*): Add frame-header-opt.o to extra_objs. * frame-header-opt.c: New file. * config/mips/mips-proto.h (mips_register_frame_header_opt): Add prototype. * config/mips/mips.c (mips_compute_frame_info): Check optimize_call_stack flag. (mips_option_override): Register new frame_header_opt pass. (mips_frame_info, mips_int_mask, mips_shadow_set, machine_function): Move these types to... * config/mips/mips.h: here. (machine_function): Add does_not_use_frame_header and optimize_call_stack fields. * config/mips/t-mips (frame-header-opt.o): Add new make rule. * doc/invoke.texi (-mframe-header-opt, -mno-frame-header-opt): Document new flags. * config/mips/mips.opt (mframe-header-opt): Add new option. From-SVN: r228666 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f7b9e9f5c39..69743c318fb 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,22 @@ +2015-10-09 Steve Ellcey + + * config.gcc (mips*-*-*): Add frame-header-opt.o to extra_objs. + * frame-header-opt.c: New file. + * config/mips/mips-proto.h (mips_register_frame_header_opt): + Add prototype. + * config/mips/mips.c (mips_compute_frame_info): Check + optimize_call_stack flag. + (mips_option_override): Register new frame_header_opt pass. + (mips_frame_info, mips_int_mask, mips_shadow_set, + machine_function): Move these types to... + * config/mips/mips.h: here. + (machine_function): Add does_not_use_frame_header and + optimize_call_stack fields. + * config/mips/t-mips (frame-header-opt.o): Add new make rule. + * doc/invoke.texi (-mframe-header-opt, -mno-frame-header-opt): + Document new flags. + * config/mips/mips.opt (mframe-header-opt): Add new option. + 2015-10-09 Uros Bizjak * config/i386/i386.c diff --git a/gcc/config.gcc b/gcc/config.gcc index 58186634532..1962b0fa923 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -420,6 +420,7 @@ microblaze*-*-*) mips*-*-*) cpu_type=mips extra_headers="loongson.h" + extra_objs="frame-header-opt.o" extra_options="${extra_options} g.opt fused-madd.opt mips/mips-tables.opt" ;; nds32*) diff --git a/gcc/config/mips/frame-header-opt.c b/gcc/config/mips/frame-header-opt.c new file mode 100644 index 00000000000..7c7b1f2209e --- /dev/null +++ b/gcc/config/mips/frame-header-opt.c @@ -0,0 +1,216 @@ +/* Analyze functions to determine if callers need to allocate a frame header + on the stack. The frame header is used by callees to save their arguments. + This optimization is specific to TARGET_OLDABI targets. For TARGET_NEWABI + targets, if a frame header is required, it is allocated by the callee. + + + Copyright (C) 2015 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3, or (at your option) any +later version. + +GCC is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + + +#include "config.h" +#include "system.h" +#include "context.h" +#include "coretypes.h" +#include "tree.h" +#include "tree-core.h" +#include "tree-pass.h" +#include "target.h" +#include "target-globals.h" +#include "cfg.h" +#include "cgraph.h" +#include "function.h" +#include "basic-block.h" +#include "gimple.h" +#include "gimple-iterator.h" +#include "gimple-walk.h" + +static unsigned int frame_header_opt (void); + +namespace { + +const pass_data pass_data_ipa_frame_header_opt = +{ + IPA_PASS, /* type */ + "frame-header-opt", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + TV_CGRAPHOPT, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ +}; + +class pass_ipa_frame_header_opt : public ipa_opt_pass_d +{ +public: + pass_ipa_frame_header_opt (gcc::context *ctxt) + : ipa_opt_pass_d (pass_data_ipa_frame_header_opt, ctxt, + NULL, /* generate_summary */ + NULL, /* write_summary */ + NULL, /* read_summary */ + NULL, /* write_optimization_summary */ + NULL, /* read_optimization_summary */ + NULL, /* stmt_fixup */ + 0, /* function_transform_todo_flags_start */ + NULL, /* function_transform */ + NULL) /* variable_transform */ + {} + + /* opt_pass methods: */ + virtual bool gate (function *) + { + /* 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; + } + + virtual unsigned int execute (function *) { return frame_header_opt (); } + +}; // class pass_ipa_frame_header_opt + +} // anon namespace + +static ipa_opt_pass_d * +make_pass_ipa_frame_header_opt (gcc::context *ctxt) +{ + return new pass_ipa_frame_header_opt (ctxt); +} + +void +mips_register_frame_header_opt (void) +{ + opt_pass *p = make_pass_ipa_frame_header_opt (g); + static struct register_pass_info f = + {p, "comdats", 1, PASS_POS_INSERT_AFTER }; + register_pass (&f); +} + + +/* Return true if it is certain that this is a leaf function. False if it is + not a leaf function or if it is impossible to tell. */ + +static bool +is_leaf_function (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 not a leaf function. */ + if (fn->cfg == NULL) + return false; + + FOR_EACH_BB_FN (bb, fn) + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + if (is_gimple_call (gsi_stmt (gsi))) + return false; + return true; +} + +/* 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. */ + +static bool +needs_frame_header_p (function *fn) +{ + tree t; + + if (fn->decl == NULL) + return true; + + if (fn->stdarg || !is_leaf_function (fn)) + return true; + + for (t = DECL_ARGUMENTS (fn->decl); t; t = TREE_CHAIN (t)) + { + if (!use_register_for_decl (t)) + 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 + be determined. */ + +static bool +callees_functions_use_frame_header (function *fn) +{ + basic_block bb; + gimple_stmt_iterator gsi; + gimple *stmt; + tree called_fn_tree; + function *called_fn; + + 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)) + { + 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 + || DECL_WEAK (called_fn_tree) + || !called_fn->machine->does_not_use_frame_header) + return true; + } + else + return true; + } + } + } + return false; +} + +/* 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. */ + +static unsigned int +frame_header_opt () +{ + struct cgraph_node *node; + function *fn; + + FOR_EACH_DEFINED_FUNCTION (node) + { + fn = node->get_fun (); + if (fn != NULL) + fn->machine->does_not_use_frame_header = !needs_frame_header_p (fn); + } + + FOR_EACH_DEFINED_FUNCTION (node) + { + fn = node->get_fun (); + if (fn != NULL) + fn->machine->optimize_call_stack + = !callees_functions_use_frame_header (fn); + } + return 0; +} diff --git a/gcc/config/mips/mips-protos.h b/gcc/config/mips/mips-protos.h index 8a9ae0147ed..43774facdbe 100644 --- a/gcc/config/mips/mips-protos.h +++ b/gcc/config/mips/mips-protos.h @@ -371,4 +371,6 @@ typedef rtx (*mulsidi3_gen_fn) (rtx, rtx, rtx); extern mulsidi3_gen_fn mips_mulsidi3_gen_fn (enum rtx_code); #endif +extern void mips_register_frame_header_opt (void); + #endif /* ! GCC_MIPS_PROTOS_H */ diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 456db08d5f0..a4bb454bee9 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -328,153 +328,6 @@ static struct { bool fast_mult_zero_zero_p; } mips_tuning_info; -/* Information about a function's frame layout. */ -struct GTY(()) mips_frame_info { - /* The size of the frame in bytes. */ - HOST_WIDE_INT total_size; - - /* The number of bytes allocated to variables. */ - HOST_WIDE_INT var_size; - - /* The number of bytes allocated to outgoing function arguments. */ - HOST_WIDE_INT args_size; - - /* The number of bytes allocated to the .cprestore slot, or 0 if there - is no such slot. */ - HOST_WIDE_INT cprestore_size; - - /* Bit X is set if the function saves or restores GPR X. */ - unsigned int mask; - - /* Likewise FPR X. */ - unsigned int fmask; - - /* Likewise doubleword accumulator X ($acX). */ - unsigned int acc_mask; - - /* The number of GPRs, FPRs, doubleword accumulators and COP0 - registers saved. */ - unsigned int num_gp; - unsigned int num_fp; - unsigned int num_acc; - unsigned int num_cop0_regs; - - /* The offset of the topmost GPR, FPR, accumulator and COP0-register - save slots from the top of the frame, or zero if no such slots are - needed. */ - HOST_WIDE_INT gp_save_offset; - HOST_WIDE_INT fp_save_offset; - HOST_WIDE_INT acc_save_offset; - HOST_WIDE_INT cop0_save_offset; - - /* Likewise, but giving offsets from the bottom of the frame. */ - HOST_WIDE_INT gp_sp_offset; - HOST_WIDE_INT fp_sp_offset; - HOST_WIDE_INT acc_sp_offset; - HOST_WIDE_INT cop0_sp_offset; - - /* Similar, but the value passed to _mcount. */ - HOST_WIDE_INT ra_fp_offset; - - /* The offset of arg_pointer_rtx from the bottom of the frame. */ - HOST_WIDE_INT arg_pointer_offset; - - /* The offset of hard_frame_pointer_rtx from the bottom of the frame. */ - HOST_WIDE_INT hard_frame_pointer_offset; -}; - -/* Enumeration for masked vectored (VI) and non-masked (EIC) interrupts. */ -enum mips_int_mask -{ - INT_MASK_EIC = -1, - INT_MASK_SW0 = 0, - INT_MASK_SW1 = 1, - INT_MASK_HW0 = 2, - INT_MASK_HW1 = 3, - INT_MASK_HW2 = 4, - INT_MASK_HW3 = 5, - INT_MASK_HW4 = 6, - INT_MASK_HW5 = 7 -}; - -/* Enumeration to mark the existence of the shadow register set. - SHADOW_SET_INTSTACK indicates a shadow register set with a valid stack - pointer. */ -enum mips_shadow_set -{ - SHADOW_SET_NO, - SHADOW_SET_YES, - SHADOW_SET_INTSTACK -}; - -struct GTY(()) machine_function { - /* The next floating-point condition-code register to allocate - for ISA_HAS_8CC targets, relative to ST_REG_FIRST. */ - unsigned int next_fcc; - - /* The register returned by mips16_gp_pseudo_reg; see there for details. */ - rtx mips16_gp_pseudo_rtx; - - /* The number of extra stack bytes taken up by register varargs. - This area is allocated by the callee at the very top of the frame. */ - int varargs_size; - - /* The current frame information, calculated by mips_compute_frame_info. */ - struct mips_frame_info frame; - - /* The register to use as the function's global pointer, or INVALID_REGNUM - if the function doesn't need one. */ - unsigned int global_pointer; - - /* How many instructions it takes to load a label into $AT, or 0 if - this property hasn't yet been calculated. */ - unsigned int load_label_num_insns; - - /* True if mips_adjust_insn_length should ignore an instruction's - hazard attribute. */ - bool ignore_hazard_length_p; - - /* True if the whole function is suitable for .set noreorder and - .set nomacro. */ - bool all_noreorder_p; - - /* True if the function has "inflexible" and "flexible" references - to the global pointer. See mips_cfun_has_inflexible_gp_ref_p - and mips_cfun_has_flexible_gp_ref_p for details. */ - bool has_inflexible_gp_insn_p; - bool has_flexible_gp_insn_p; - - /* True if the function's prologue must load the global pointer - value into pic_offset_table_rtx and store the same value in - the function's cprestore slot (if any). Even if this value - is currently false, we may decide to set it to true later; - see mips_must_initialize_gp_p () for details. */ - bool must_initialize_gp_p; - - /* True if the current function must restore $gp after any potential - clobber. This value is only meaningful during the first post-epilogue - split_insns pass; see mips_must_initialize_gp_p () for details. */ - bool must_restore_gp_when_clobbered_p; - - /* True if this is an interrupt handler. */ - bool interrupt_handler_p; - - /* Records the way in which interrupts should be masked. Only used if - interrupts are not kept masked. */ - enum mips_int_mask int_mask; - - /* Records if this is an interrupt handler that uses shadow registers. */ - enum mips_shadow_set use_shadow_register_set; - - /* True if this is an interrupt handler that should keep interrupts - masked. */ - bool keep_interrupts_masked_p; - - /* True if this is an interrupt handler that should use DERET - instead of ERET. */ - bool use_debug_exception_return_p; -}; - /* Information about a single argument. */ struct mips_arg_info { /* True if the argument is passed in a floating-point register, or @@ -10504,10 +10357,15 @@ mips_compute_frame_info (void) cfun->machine->global_pointer = mips_global_pointer (); /* The first two blocks contain the outgoing argument area and the $gp save - slot. This area isn't needed in leaf functions, but if the - target-independent frame size is nonzero, we have already committed to - allocating these in STARTING_FRAME_OFFSET for !FRAME_GROWS_DOWNWARD. */ - if ((size == 0 || FRAME_GROWS_DOWNWARD) && crtl->is_leaf) + slot. This area isn't needed in leaf functions. We can also skip it + if we know that none of the called functions will use this space. + + But if the target-independent frame size is nonzero, we have already + committed to allocating these in STARTING_FRAME_OFFSET for + !FRAME_GROWS_DOWNWARD. */ + + if ((size == 0 || FRAME_GROWS_DOWNWARD) + && (crtl->is_leaf || (cfun->machine->optimize_call_stack && !flag_pic))) { /* The MIPS 3.0 linker does not like functions that dynamically allocate the stack and have 0 for STACK_DYNAMIC_OFFSET, since it @@ -18269,6 +18127,8 @@ mips_option_override (void) if (TARGET_HARD_FLOAT_ABI && TARGET_MIPS5900) REAL_MODE_FORMAT (SFmode) = &spu_single_format; + + mips_register_frame_header_opt (); } /* Swap the register information for registers I and I + 1, which diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h index 25a1e0622cd..be86c109b6c 100644 --- a/gcc/config/mips/mips.h +++ b/gcc/config/mips/mips.h @@ -3119,6 +3119,161 @@ extern const struct mips_cpu_info *mips_tune_info; extern unsigned int mips_base_compression_flags; extern GTY(()) struct target_globals *mips16_globals; extern GTY(()) struct target_globals *micromips_globals; + +/* Information about a function's frame layout. */ +struct GTY(()) mips_frame_info { + /* The size of the frame in bytes. */ + HOST_WIDE_INT total_size; + + /* The number of bytes allocated to variables. */ + HOST_WIDE_INT var_size; + + /* The number of bytes allocated to outgoing function arguments. */ + HOST_WIDE_INT args_size; + + /* The number of bytes allocated to the .cprestore slot, or 0 if there + is no such slot. */ + HOST_WIDE_INT cprestore_size; + + /* Bit X is set if the function saves or restores GPR X. */ + unsigned int mask; + + /* Likewise FPR X. */ + unsigned int fmask; + + /* Likewise doubleword accumulator X ($acX). */ + unsigned int acc_mask; + + /* The number of GPRs, FPRs, doubleword accumulators and COP0 + registers saved. */ + unsigned int num_gp; + unsigned int num_fp; + unsigned int num_acc; + unsigned int num_cop0_regs; + + /* The offset of the topmost GPR, FPR, accumulator and COP0-register + save slots from the top of the frame, or zero if no such slots are + needed. */ + HOST_WIDE_INT gp_save_offset; + HOST_WIDE_INT fp_save_offset; + HOST_WIDE_INT acc_save_offset; + HOST_WIDE_INT cop0_save_offset; + + /* Likewise, but giving offsets from the bottom of the frame. */ + HOST_WIDE_INT gp_sp_offset; + HOST_WIDE_INT fp_sp_offset; + HOST_WIDE_INT acc_sp_offset; + HOST_WIDE_INT cop0_sp_offset; + + /* Similar, but the value passed to _mcount. */ + HOST_WIDE_INT ra_fp_offset; + + /* The offset of arg_pointer_rtx from the bottom of the frame. */ + HOST_WIDE_INT arg_pointer_offset; + + /* The offset of hard_frame_pointer_rtx from the bottom of the frame. */ + HOST_WIDE_INT hard_frame_pointer_offset; +}; + +/* Enumeration for masked vectored (VI) and non-masked (EIC) interrupts. */ +enum mips_int_mask +{ + INT_MASK_EIC = -1, + INT_MASK_SW0 = 0, + INT_MASK_SW1 = 1, + INT_MASK_HW0 = 2, + INT_MASK_HW1 = 3, + INT_MASK_HW2 = 4, + INT_MASK_HW3 = 5, + INT_MASK_HW4 = 6, + INT_MASK_HW5 = 7 +}; + +/* Enumeration to mark the existence of the shadow register set. + SHADOW_SET_INTSTACK indicates a shadow register set with a valid stack + pointer. */ +enum mips_shadow_set +{ + SHADOW_SET_NO, + SHADOW_SET_YES, + SHADOW_SET_INTSTACK +}; + +struct GTY(()) machine_function { + /* The next floating-point condition-code register to allocate + for ISA_HAS_8CC targets, relative to ST_REG_FIRST. */ + unsigned int next_fcc; + + /* The register returned by mips16_gp_pseudo_reg; see there for details. */ + rtx mips16_gp_pseudo_rtx; + + /* The number of extra stack bytes taken up by register varargs. + This area is allocated by the callee at the very top of the frame. */ + int varargs_size; + + /* The current frame information, calculated by mips_compute_frame_info. */ + struct mips_frame_info frame; + + /* The register to use as the function's global pointer, or INVALID_REGNUM + if the function doesn't need one. */ + unsigned int global_pointer; + + /* How many instructions it takes to load a label into $AT, or 0 if + this property hasn't yet been calculated. */ + unsigned int load_label_num_insns; + + /* True if mips_adjust_insn_length should ignore an instruction's + hazard attribute. */ + bool ignore_hazard_length_p; + + /* True if the whole function is suitable for .set noreorder and + .set nomacro. */ + bool all_noreorder_p; + + /* True if the function has "inflexible" and "flexible" references + to the global pointer. See mips_cfun_has_inflexible_gp_ref_p + and mips_cfun_has_flexible_gp_ref_p for details. */ + bool has_inflexible_gp_insn_p; + bool has_flexible_gp_insn_p; + + /* True if the function's prologue must load the global pointer + value into pic_offset_table_rtx and store the same value in + the function's cprestore slot (if any). Even if this value + is currently false, we may decide to set it to true later; + see mips_must_initialize_gp_p () for details. */ + bool must_initialize_gp_p; + + /* True if the current function must restore $gp after any potential + clobber. This value is only meaningful during the first post-epilogue + split_insns pass; see mips_must_initialize_gp_p () for details. */ + bool must_restore_gp_when_clobbered_p; + + /* True if this is an interrupt handler. */ + bool interrupt_handler_p; + + /* Records the way in which interrupts should be masked. Only used if + interrupts are not kept masked. */ + enum mips_int_mask int_mask; + + /* Records if this is an interrupt handler that uses shadow registers. */ + enum mips_shadow_set use_shadow_register_set; + + /* True if this is an interrupt handler that should keep interrupts + masked. */ + bool keep_interrupts_masked_p; + + /* True if this is an interrupt handler that should use DERET + instead of ERET. */ + bool use_debug_exception_return_p; + + /* True if at least one of the formal parameters to a function must be + written to the frame header (probably so its address can be taken). */ + bool does_not_use_frame_header; + + /* True if none of the functions that are called by this function need + stack space allocated for their arguments. */ + bool optimize_call_stack; +}; #endif /* Enable querying of DFA units. */ diff --git a/gcc/config/mips/mips.opt b/gcc/config/mips/mips.opt index 84887d11623..b979eb51c59 100644 --- a/gcc/config/mips/mips.opt +++ b/gcc/config/mips/mips.opt @@ -412,6 +412,10 @@ modd-spreg Target Report Mask(ODD_SPREG) Enable use of odd-numbered single-precision registers +mframe-header-opt +Target Report Var(flag_frame_header_optimization) Optimization +Optimize frame header + noasmopt Driver diff --git a/gcc/config/mips/t-mips b/gcc/config/mips/t-mips index 01df1ad76a4..a8938411420 100644 --- a/gcc/config/mips/t-mips +++ b/gcc/config/mips/t-mips @@ -20,3 +20,7 @@ $(srcdir)/config/mips/mips-tables.opt: $(srcdir)/config/mips/genopt.sh \ $(srcdir)/config/mips/mips-cpus.def $(SHELL) $(srcdir)/config/mips/genopt.sh $(srcdir)/config/mips > \ $(srcdir)/config/mips/mips-tables.opt + +frame-header-opt.o: $(srcdir)/config/mips/frame-header-opt.c + $(COMPILE) $< + $(POSTCOMPILE) diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 1b44b444cbe..f10d7496c79 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -818,7 +818,8 @@ Objective-C and Objective-C++ Dialects}. -mbranch-cost=@var{num} -mbranch-likely -mno-branch-likely @gol -mfp-exceptions -mno-fp-exceptions @gol -mvr4130-align -mno-vr4130-align -msynci -mno-synci @gol --mrelax-pic-calls -mno-relax-pic-calls -mmcount-ra-address} +-mrelax-pic-calls -mno-relax-pic-calls -mmcount-ra-address @gol +-mframe-header-opt -mno-frame-header-opt} @emph{MMIX Options} @gccoptlist{-mlibfuncs -mno-libfuncs -mepsilon -mno-epsilon -mabi=gnu @gol @@ -18108,6 +18109,17 @@ if @var{ra-address} is nonnull. The default is @option{-mno-mcount-ra-address}. +@item -mframe-header-opt +@itemx -mno-frame-header-opt +@opindex mframe-header-opt +Enable (disable) frame header optimization in the o32 ABI. When using the +o32 ABI, calling functions will allocate 16 bytes on the stack for the called +function to write out register arguments. When enabled, this optimization +will suppress the allocation of the frame header if it can be determined that +it is unused. + +This optimization is off by default at all optimization levels. + @end table @node MMIX Options