summaryrefslogtreecommitdiff
path: root/gcc/config/mips
diff options
context:
space:
mode:
authorsje <sje@138bc75d-0d04-0410-961f-82ee72b054a4>2015-10-09 17:10:42 +0000
committersje <sje@138bc75d-0d04-0410-961f-82ee72b054a4>2015-10-09 17:10:42 +0000
commit0c9081e858156261656fdde996bd24c91f3cf291 (patch)
treeec2b873ea269f855d61f77eb73a55bc41a5d0dc5 /gcc/config/mips
parent60cc243ec8f66f6a25a92d2d4e4a626c512d82c0 (diff)
downloadgcc-0c9081e858156261656fdde996bd24c91f3cf291.tar.gz
2015-10-05 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@228666 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/mips')
-rw-r--r--gcc/config/mips/frame-header-opt.c216
-rw-r--r--gcc/config/mips/mips-protos.h2
-rw-r--r--gcc/config/mips/mips.c162
-rw-r--r--gcc/config/mips/mips.h155
-rw-r--r--gcc/config/mips/mips.opt4
-rw-r--r--gcc/config/mips/t-mips4
6 files changed, 392 insertions, 151 deletions
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
+<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;
+}
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)