diff options
author | Steve Ellcey <sellcey@imgtec.com> | 2015-10-09 17:10:42 +0000 |
---|---|---|
committer | Steve Ellcey <sje@gcc.gnu.org> | 2015-10-09 17:10:42 +0000 |
commit | d41c8b4c43d7050f05668f23ad4563ed6e9b41d0 (patch) | |
tree | ec2b873ea269f855d61f77eb73a55bc41a5d0dc5 /gcc/config/mips/frame-header-opt.c | |
parent | b867c7ca88776d062e3e62c212fb0a59b6d688c9 (diff) | |
download | gcc-d41c8b4c43d7050f05668f23ad4563ed6e9b41d0.zip gcc-d41c8b4c43d7050f05668f23ad4563ed6e9b41d0.tar.gz gcc-d41c8b4c43d7050f05668f23ad4563ed6e9b41d0.tar.bz2 |
config.gcc (mips*-*-*): Add frame-header-opt.o to extra_objs.
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.
From-SVN: r228666
Diffstat (limited to 'gcc/config/mips/frame-header-opt.c')
-rw-r--r-- | gcc/config/mips/frame-header-opt.c | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/gcc/config/mips/frame-header-opt.c b/gcc/config/mips/frame-header-opt.c new file mode 100644 index 0000000..7c7b1f2 --- /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; +} |