11debfc3dSmrg /* Analyze functions to determine if callers need to allocate a frame header
21debfc3dSmrg on the stack. The frame header is used by callees to save their arguments.
31debfc3dSmrg This optimization is specific to TARGET_OLDABI targets. For TARGET_NEWABI
41debfc3dSmrg targets, if a frame header is required, it is allocated by the callee.
51debfc3dSmrg
61debfc3dSmrg
7*8feb0f0bSmrg Copyright (C) 2015-2020 Free Software Foundation, Inc.
81debfc3dSmrg
91debfc3dSmrg This file is part of GCC.
101debfc3dSmrg
111debfc3dSmrg GCC is free software; you can redistribute it and/or modify it
121debfc3dSmrg under the terms of the GNU General Public License as published by the
131debfc3dSmrg Free Software Foundation; either version 3, or (at your option) any
141debfc3dSmrg later version.
151debfc3dSmrg
161debfc3dSmrg GCC is distributed in the hope that it will be useful, but WITHOUT
171debfc3dSmrg ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
181debfc3dSmrg FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
191debfc3dSmrg for more details.
201debfc3dSmrg
211debfc3dSmrg You should have received a copy of the GNU General Public License
221debfc3dSmrg along with GCC; see the file COPYING3. If not see
231debfc3dSmrg <http://www.gnu.org/licenses/>. */
241debfc3dSmrg
251debfc3dSmrg
26a2dc1f3fSmrg #define IN_TARGET_CODE 1
27a2dc1f3fSmrg
281debfc3dSmrg #include "config.h"
291debfc3dSmrg #include "system.h"
301debfc3dSmrg #include "context.h"
311debfc3dSmrg #include "coretypes.h"
32c0a68be4Smrg #include "backend.h"
331debfc3dSmrg #include "tree.h"
341debfc3dSmrg #include "tree-core.h"
351debfc3dSmrg #include "tree-pass.h"
361debfc3dSmrg #include "target.h"
371debfc3dSmrg #include "target-globals.h"
38a2dc1f3fSmrg #include "profile-count.h"
391debfc3dSmrg #include "cgraph.h"
401debfc3dSmrg #include "function.h"
411debfc3dSmrg #include "basic-block.h"
421debfc3dSmrg #include "gimple.h"
431debfc3dSmrg #include "gimple-iterator.h"
441debfc3dSmrg #include "gimple-walk.h"
451debfc3dSmrg
461debfc3dSmrg static unsigned int frame_header_opt (void);
471debfc3dSmrg
481debfc3dSmrg namespace {
491debfc3dSmrg
501debfc3dSmrg const pass_data pass_data_ipa_frame_header_opt =
511debfc3dSmrg {
521debfc3dSmrg IPA_PASS, /* type */
531debfc3dSmrg "frame-header-opt", /* name */
541debfc3dSmrg OPTGROUP_NONE, /* optinfo_flags */
551debfc3dSmrg TV_CGRAPHOPT, /* tv_id */
561debfc3dSmrg 0, /* properties_required */
571debfc3dSmrg 0, /* properties_provided */
581debfc3dSmrg 0, /* properties_destroyed */
591debfc3dSmrg 0, /* todo_flags_start */
601debfc3dSmrg 0, /* todo_flags_finish */
611debfc3dSmrg };
621debfc3dSmrg
631debfc3dSmrg class pass_ipa_frame_header_opt : public ipa_opt_pass_d
641debfc3dSmrg {
651debfc3dSmrg public:
pass_ipa_frame_header_opt(gcc::context * ctxt)661debfc3dSmrg pass_ipa_frame_header_opt (gcc::context *ctxt)
671debfc3dSmrg : ipa_opt_pass_d (pass_data_ipa_frame_header_opt, ctxt,
681debfc3dSmrg NULL, /* generate_summary */
691debfc3dSmrg NULL, /* write_summary */
701debfc3dSmrg NULL, /* read_summary */
711debfc3dSmrg NULL, /* write_optimization_summary */
721debfc3dSmrg NULL, /* read_optimization_summary */
731debfc3dSmrg NULL, /* stmt_fixup */
741debfc3dSmrg 0, /* function_transform_todo_flags_start */
751debfc3dSmrg NULL, /* function_transform */
761debfc3dSmrg NULL) /* variable_transform */
771debfc3dSmrg {}
781debfc3dSmrg
791debfc3dSmrg /* opt_pass methods: */
gate(function *)801debfc3dSmrg virtual bool gate (function *)
811debfc3dSmrg {
821debfc3dSmrg /* This optimization has no affect if TARGET_NEWABI. If optimize
831debfc3dSmrg is not at least 1 then the data needed for the optimization is
841debfc3dSmrg not available and nothing will be done anyway. */
851debfc3dSmrg return TARGET_OLDABI && flag_frame_header_optimization && optimize > 0;
861debfc3dSmrg }
871debfc3dSmrg
execute(function *)881debfc3dSmrg virtual unsigned int execute (function *) { return frame_header_opt (); }
891debfc3dSmrg
901debfc3dSmrg }; // class pass_ipa_frame_header_opt
911debfc3dSmrg
921debfc3dSmrg } // anon namespace
931debfc3dSmrg
941debfc3dSmrg static ipa_opt_pass_d *
make_pass_ipa_frame_header_opt(gcc::context * ctxt)951debfc3dSmrg make_pass_ipa_frame_header_opt (gcc::context *ctxt)
961debfc3dSmrg {
971debfc3dSmrg return new pass_ipa_frame_header_opt (ctxt);
981debfc3dSmrg }
991debfc3dSmrg
1001debfc3dSmrg void
mips_register_frame_header_opt(void)1011debfc3dSmrg mips_register_frame_header_opt (void)
1021debfc3dSmrg {
1031debfc3dSmrg opt_pass *p = make_pass_ipa_frame_header_opt (g);
1041debfc3dSmrg struct register_pass_info f = { p, "comdats", 1, PASS_POS_INSERT_AFTER };
1051debfc3dSmrg register_pass (&f);
1061debfc3dSmrg }
1071debfc3dSmrg
1081debfc3dSmrg
1091debfc3dSmrg /* Return true if it is certain that this is a leaf function. False if it is
1101debfc3dSmrg not a leaf function or if it is impossible to tell. */
1111debfc3dSmrg
1121debfc3dSmrg static bool
is_leaf_function(function * fn)1131debfc3dSmrg is_leaf_function (function *fn)
1141debfc3dSmrg {
1151debfc3dSmrg basic_block bb;
1161debfc3dSmrg gimple_stmt_iterator gsi;
1171debfc3dSmrg
1181debfc3dSmrg /* If we do not have a cfg for this function be conservative and assume
1191debfc3dSmrg it is not a leaf function. */
1201debfc3dSmrg if (fn->cfg == NULL)
1211debfc3dSmrg return false;
1221debfc3dSmrg
1231debfc3dSmrg FOR_EACH_BB_FN (bb, fn)
1241debfc3dSmrg for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
1251debfc3dSmrg if (is_gimple_call (gsi_stmt (gsi)))
1261debfc3dSmrg return false;
1271debfc3dSmrg return true;
1281debfc3dSmrg }
1291debfc3dSmrg
1301debfc3dSmrg /* Return true if this function has inline assembly code or if we cannot
1311debfc3dSmrg be certain that it does not. False if we know that there is no inline
1321debfc3dSmrg assembly. */
1331debfc3dSmrg
1341debfc3dSmrg static bool
has_inlined_assembly(function * fn)1351debfc3dSmrg has_inlined_assembly (function *fn)
1361debfc3dSmrg {
1371debfc3dSmrg basic_block bb;
1381debfc3dSmrg gimple_stmt_iterator gsi;
1391debfc3dSmrg
1401debfc3dSmrg /* If we do not have a cfg for this function be conservative and assume
1411debfc3dSmrg it is may have inline assembly. */
1421debfc3dSmrg if (fn->cfg == NULL)
1431debfc3dSmrg return true;
1441debfc3dSmrg
1451debfc3dSmrg FOR_EACH_BB_FN (bb, fn)
1461debfc3dSmrg for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
1471debfc3dSmrg if (gimple_code (gsi_stmt (gsi)) == GIMPLE_ASM)
1481debfc3dSmrg return true;
1491debfc3dSmrg
1501debfc3dSmrg return false;
1511debfc3dSmrg }
1521debfc3dSmrg
1531debfc3dSmrg /* Return true if this function will use the stack space allocated by its
1541debfc3dSmrg caller or if we cannot determine for certain that it does not. */
1551debfc3dSmrg
1561debfc3dSmrg static bool
needs_frame_header_p(function * fn)1571debfc3dSmrg needs_frame_header_p (function *fn)
1581debfc3dSmrg {
1591debfc3dSmrg tree t;
1601debfc3dSmrg
1611debfc3dSmrg if (fn->decl == NULL)
1621debfc3dSmrg return true;
1631debfc3dSmrg
1641debfc3dSmrg if (fn->stdarg)
1651debfc3dSmrg return true;
1661debfc3dSmrg
1671debfc3dSmrg for (t = DECL_ARGUMENTS (fn->decl); t; t = TREE_CHAIN (t))
1681debfc3dSmrg {
1691debfc3dSmrg if (!use_register_for_decl (t))
1701debfc3dSmrg return true;
1711debfc3dSmrg
1721debfc3dSmrg /* Some 64-bit types may get copied to general registers using the frame
1731debfc3dSmrg header, see mips_output_64bit_xfer. Checking for SImode only may be
1741debfc3dSmrg overly restrictive but it is guaranteed to be safe. */
1751debfc3dSmrg if (DECL_MODE (t) != SImode)
1761debfc3dSmrg return true;
1771debfc3dSmrg }
1781debfc3dSmrg
1791debfc3dSmrg return false;
1801debfc3dSmrg }
1811debfc3dSmrg
1821debfc3dSmrg /* Return true if the argument stack space allocated by function FN is used.
1831debfc3dSmrg Return false if the space is needed or if the need for the space cannot
1841debfc3dSmrg be determined. */
1851debfc3dSmrg
1861debfc3dSmrg static bool
callees_functions_use_frame_header(function * fn)1871debfc3dSmrg callees_functions_use_frame_header (function *fn)
1881debfc3dSmrg {
1891debfc3dSmrg basic_block bb;
1901debfc3dSmrg gimple_stmt_iterator gsi;
1911debfc3dSmrg gimple *stmt;
1921debfc3dSmrg tree called_fn_tree;
1931debfc3dSmrg function *called_fn;
1941debfc3dSmrg
1951debfc3dSmrg if (fn->cfg == NULL)
1961debfc3dSmrg return true;
1971debfc3dSmrg
1981debfc3dSmrg FOR_EACH_BB_FN (bb, fn)
1991debfc3dSmrg {
2001debfc3dSmrg for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
2011debfc3dSmrg {
2021debfc3dSmrg stmt = gsi_stmt (gsi);
2031debfc3dSmrg if (is_gimple_call (stmt))
2041debfc3dSmrg {
2051debfc3dSmrg called_fn_tree = gimple_call_fndecl (stmt);
2061debfc3dSmrg if (called_fn_tree != NULL)
2071debfc3dSmrg {
2081debfc3dSmrg called_fn = DECL_STRUCT_FUNCTION (called_fn_tree);
2091debfc3dSmrg if (called_fn == NULL
2101debfc3dSmrg || DECL_WEAK (called_fn_tree)
2111debfc3dSmrg || has_inlined_assembly (called_fn)
2121debfc3dSmrg || !is_leaf_function (called_fn)
2131debfc3dSmrg || !called_fn->machine->does_not_use_frame_header)
2141debfc3dSmrg return true;
2151debfc3dSmrg }
2161debfc3dSmrg else
2171debfc3dSmrg return true;
2181debfc3dSmrg }
2191debfc3dSmrg }
2201debfc3dSmrg }
2211debfc3dSmrg return false;
2221debfc3dSmrg }
2231debfc3dSmrg
2241debfc3dSmrg /* Set the callers_may_not_allocate_frame flag for any function which
2251debfc3dSmrg function FN calls because FN may not allocate a frame header. */
2261debfc3dSmrg
2271debfc3dSmrg static void
set_callers_may_not_allocate_frame(function * fn)2281debfc3dSmrg set_callers_may_not_allocate_frame (function *fn)
2291debfc3dSmrg {
2301debfc3dSmrg basic_block bb;
2311debfc3dSmrg gimple_stmt_iterator gsi;
2321debfc3dSmrg gimple *stmt;
2331debfc3dSmrg tree called_fn_tree;
2341debfc3dSmrg function *called_fn;
2351debfc3dSmrg
2361debfc3dSmrg if (fn->cfg == NULL)
2371debfc3dSmrg return;
2381debfc3dSmrg
2391debfc3dSmrg FOR_EACH_BB_FN (bb, fn)
2401debfc3dSmrg {
2411debfc3dSmrg for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
2421debfc3dSmrg {
2431debfc3dSmrg stmt = gsi_stmt (gsi);
2441debfc3dSmrg if (is_gimple_call (stmt))
2451debfc3dSmrg {
2461debfc3dSmrg called_fn_tree = gimple_call_fndecl (stmt);
2471debfc3dSmrg if (called_fn_tree != NULL)
2481debfc3dSmrg {
2491debfc3dSmrg called_fn = DECL_STRUCT_FUNCTION (called_fn_tree);
2501debfc3dSmrg if (called_fn != NULL)
2511debfc3dSmrg called_fn->machine->callers_may_not_allocate_frame = true;
2521debfc3dSmrg }
2531debfc3dSmrg }
2541debfc3dSmrg }
2551debfc3dSmrg }
2561debfc3dSmrg return;
2571debfc3dSmrg }
2581debfc3dSmrg
2591debfc3dSmrg /* Scan each function to determine those that need its frame headers. Perform
2601debfc3dSmrg a second scan to determine if the allocation can be skipped because none of
2611debfc3dSmrg their callees require the frame header. */
2621debfc3dSmrg
2631debfc3dSmrg static unsigned int
frame_header_opt()2641debfc3dSmrg frame_header_opt ()
2651debfc3dSmrg {
2661debfc3dSmrg struct cgraph_node *node;
2671debfc3dSmrg function *fn;
2681debfc3dSmrg
2691debfc3dSmrg FOR_EACH_DEFINED_FUNCTION (node)
2701debfc3dSmrg {
2711debfc3dSmrg fn = node->get_fun ();
2721debfc3dSmrg if (fn != NULL)
2731debfc3dSmrg fn->machine->does_not_use_frame_header = !needs_frame_header_p (fn);
2741debfc3dSmrg }
2751debfc3dSmrg
2761debfc3dSmrg FOR_EACH_DEFINED_FUNCTION (node)
2771debfc3dSmrg {
2781debfc3dSmrg fn = node->get_fun ();
2791debfc3dSmrg if (fn != NULL)
2801debfc3dSmrg fn->machine->optimize_call_stack
2811debfc3dSmrg = !callees_functions_use_frame_header (fn) && !is_leaf_function (fn);
2821debfc3dSmrg }
2831debfc3dSmrg
2841debfc3dSmrg FOR_EACH_DEFINED_FUNCTION (node)
2851debfc3dSmrg {
2861debfc3dSmrg fn = node->get_fun ();
2871debfc3dSmrg if (fn != NULL && fn->machine->optimize_call_stack)
2881debfc3dSmrg set_callers_may_not_allocate_frame (fn);
2891debfc3dSmrg }
2901debfc3dSmrg
2911debfc3dSmrg return 0;
2921debfc3dSmrg }
293