]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/mips/frame-header-opt.c
config.gcc (mips*-*-*): Add frame-header-opt.o to extra_objs.
[thirdparty/gcc.git] / gcc / config / mips / frame-header-opt.c
CommitLineData
d41c8b4c
SE
1/* Analyze functions to determine if callers need to allocate a frame header
2 on the stack. The frame header is used by callees to save their arguments.
3 This optimization is specific to TARGET_OLDABI targets. For TARGET_NEWABI
4 targets, if a frame header is required, it is allocated by the callee.
5
6
7 Copyright (C) 2015 Free Software Foundation, Inc.
8
9This file is part of GCC.
10
11GCC is free software; you can redistribute it and/or modify it
12under the terms of the GNU General Public License as published by the
13Free Software Foundation; either version 3, or (at your option) any
14later version.
15
16GCC is distributed in the hope that it will be useful, but WITHOUT
17ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19for more details.
20
21You should have received a copy of the GNU General Public License
22along with GCC; see the file COPYING3. If not see
23<http://www.gnu.org/licenses/>. */
24
25
26#include "config.h"
27#include "system.h"
28#include "context.h"
29#include "coretypes.h"
30#include "tree.h"
31#include "tree-core.h"
32#include "tree-pass.h"
33#include "target.h"
34#include "target-globals.h"
35#include "cfg.h"
36#include "cgraph.h"
37#include "function.h"
38#include "basic-block.h"
39#include "gimple.h"
40#include "gimple-iterator.h"
41#include "gimple-walk.h"
42
43static unsigned int frame_header_opt (void);
44
45namespace {
46
47const pass_data pass_data_ipa_frame_header_opt =
48{
49 IPA_PASS, /* type */
50 "frame-header-opt", /* name */
51 OPTGROUP_NONE, /* optinfo_flags */
52 TV_CGRAPHOPT, /* tv_id */
53 0, /* properties_required */
54 0, /* properties_provided */
55 0, /* properties_destroyed */
56 0, /* todo_flags_start */
57 0, /* todo_flags_finish */
58};
59
60class pass_ipa_frame_header_opt : public ipa_opt_pass_d
61{
62public:
63 pass_ipa_frame_header_opt (gcc::context *ctxt)
64 : ipa_opt_pass_d (pass_data_ipa_frame_header_opt, ctxt,
65 NULL, /* generate_summary */
66 NULL, /* write_summary */
67 NULL, /* read_summary */
68 NULL, /* write_optimization_summary */
69 NULL, /* read_optimization_summary */
70 NULL, /* stmt_fixup */
71 0, /* function_transform_todo_flags_start */
72 NULL, /* function_transform */
73 NULL) /* variable_transform */
74 {}
75
76 /* opt_pass methods: */
77 virtual bool gate (function *)
78 {
79 /* This optimization has no affect if TARGET_NEWABI. If optimize
80 is not at least 1 then the data needed for the optimization is
81 not available and nothing will be done anyway. */
82 return TARGET_OLDABI && flag_frame_header_optimization;
83 }
84
85 virtual unsigned int execute (function *) { return frame_header_opt (); }
86
87}; // class pass_ipa_frame_header_opt
88
89} // anon namespace
90
91static ipa_opt_pass_d *
92make_pass_ipa_frame_header_opt (gcc::context *ctxt)
93{
94 return new pass_ipa_frame_header_opt (ctxt);
95}
96
97void
98mips_register_frame_header_opt (void)
99{
100 opt_pass *p = make_pass_ipa_frame_header_opt (g);
101 static struct register_pass_info f =
102 {p, "comdats", 1, PASS_POS_INSERT_AFTER };
103 register_pass (&f);
104}
105
106
107/* Return true if it is certain that this is a leaf function. False if it is
108 not a leaf function or if it is impossible to tell. */
109
110static bool
111is_leaf_function (function *fn)
112{
113 basic_block bb;
114 gimple_stmt_iterator gsi;
115
116 /* If we do not have a cfg for this function be conservative and assume
117 it is not a leaf function. */
118 if (fn->cfg == NULL)
119 return false;
120
121 FOR_EACH_BB_FN (bb, fn)
122 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
123 if (is_gimple_call (gsi_stmt (gsi)))
124 return false;
125 return true;
126}
127
128/* Return true if this function will use the stack space allocated by its
129 caller or if we cannot determine for certain that it does not. */
130
131static bool
132needs_frame_header_p (function *fn)
133{
134 tree t;
135
136 if (fn->decl == NULL)
137 return true;
138
139 if (fn->stdarg || !is_leaf_function (fn))
140 return true;
141
142 for (t = DECL_ARGUMENTS (fn->decl); t; t = TREE_CHAIN (t))
143 {
144 if (!use_register_for_decl (t))
145 return true;
146 }
147
148 return false;
149}
150
151/* Returns TRUE if the argument stack space allocated by function FN is used.
152 Returns FALSE if the space is needed or if the need for the space cannot
153 be determined. */
154
155static bool
156callees_functions_use_frame_header (function *fn)
157{
158 basic_block bb;
159 gimple_stmt_iterator gsi;
160 gimple *stmt;
161 tree called_fn_tree;
162 function *called_fn;
163
164 if (fn->cfg == NULL)
165 return true;
166
167 FOR_EACH_BB_FN (bb, fn)
168 {
169 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
170 {
171 stmt = gsi_stmt (gsi);
172 if (is_gimple_call (stmt))
173 {
174 called_fn_tree = gimple_call_fndecl (stmt);
175 if (called_fn_tree != NULL)
176 {
177 called_fn = DECL_STRUCT_FUNCTION (called_fn_tree);
178 if (called_fn == NULL
179 || DECL_WEAK (called_fn_tree)
180 || !called_fn->machine->does_not_use_frame_header)
181 return true;
182 }
183 else
184 return true;
185 }
186 }
187 }
188 return false;
189}
190
191/* Scan each function to determine those that need its frame headers. Perform
192 a second scan to determine if the allocation can be skipped because none of
193 their callees require the frame header. */
194
195static unsigned int
196frame_header_opt ()
197{
198 struct cgraph_node *node;
199 function *fn;
200
201 FOR_EACH_DEFINED_FUNCTION (node)
202 {
203 fn = node->get_fun ();
204 if (fn != NULL)
205 fn->machine->does_not_use_frame_header = !needs_frame_header_p (fn);
206 }
207
208 FOR_EACH_DEFINED_FUNCTION (node)
209 {
210 fn = node->get_fun ();
211 if (fn != NULL)
212 fn->machine->optimize_call_stack
213 = !callees_functions_use_frame_header (fn);
214 }
215 return 0;
216}