+2015-10-09 Steve Ellcey <sellcey@imgtec.com>
+
+ * 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 <ubizjak@gmail.com>
* config/i386/i386.c
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*)
--- /dev/null
+/* 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
+<http://www.gnu.org/licenses/>. */
+
+
+#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;
+}
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 */
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
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
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
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. */
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
$(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)
-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
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