c-common.c (vector_types_convertible_p): Treat opaque types as always convertible...
[gcc.git] / gcc / ipa.c
1 /* Basic IPA optimizations and utilities.
2 Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
3
4 This file is part of GCC.
5
6 GCC is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 2, or (at your option) any later
9 version.
10
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING. If not, write to the Free
18 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301, USA. */
20
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "tm.h"
25 #include "cgraph.h"
26 #include "tree-pass.h"
27 #include "timevar.h"
28
29 /* Fill array order with all nodes with output flag set in the reverse
30 topological order. */
31
32 int
33 cgraph_postorder (struct cgraph_node **order)
34 {
35 struct cgraph_node *node, *node2;
36 int stack_size = 0;
37 int order_pos = 0;
38 struct cgraph_edge *edge, last;
39
40 struct cgraph_node **stack =
41 XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
42
43 /* We have to deal with cycles nicely, so use a depth first traversal
44 output algorithm. Ignore the fact that some functions won't need
45 to be output and put them into order as well, so we get dependencies
46 right through intline functions. */
47 for (node = cgraph_nodes; node; node = node->next)
48 node->aux = NULL;
49 for (node = cgraph_nodes; node; node = node->next)
50 if (!node->aux)
51 {
52 node2 = node;
53 if (!node->callers)
54 node->aux = &last;
55 else
56 node->aux = node->callers;
57 while (node2)
58 {
59 while (node2->aux != &last)
60 {
61 edge = node2->aux;
62 if (edge->next_caller)
63 node2->aux = edge->next_caller;
64 else
65 node2->aux = &last;
66 if (!edge->caller->aux)
67 {
68 if (!edge->caller->callers)
69 edge->caller->aux = &last;
70 else
71 edge->caller->aux = edge->caller->callers;
72 stack[stack_size++] = node2;
73 node2 = edge->caller;
74 break;
75 }
76 }
77 if (node2->aux == &last)
78 {
79 order[order_pos++] = node2;
80 if (stack_size)
81 node2 = stack[--stack_size];
82 else
83 node2 = NULL;
84 }
85 }
86 }
87 free (stack);
88 for (node = cgraph_nodes; node; node = node->next)
89 node->aux = NULL;
90 return order_pos;
91 }
92
93 /* Perform reachability analysis and reclaim all unreachable nodes.
94 If BEFORE_INLINING_P is true this function is called before inlining
95 decisions has been made. If BEFORE_INLINING_P is false this function also
96 removes unneeded bodies of extern inline functions. */
97
98 bool
99 cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
100 {
101 struct cgraph_node *first = (void *) 1;
102 struct cgraph_node *node, *next;
103 bool changed = false;
104 int insns = 0;
105
106 #ifdef ENABLE_CHECKING
107 verify_cgraph ();
108 #endif
109 if (file)
110 fprintf (file, "\nReclaiming functions:");
111 #ifdef ENABLE_CHECKING
112 for (node = cgraph_nodes; node; node = node->next)
113 gcc_assert (!node->aux);
114 #endif
115 for (node = cgraph_nodes; node; node = node->next)
116 if (node->needed && !node->global.inlined_to
117 && ((!DECL_EXTERNAL (node->decl))
118 || !node->analyzed
119 || before_inlining_p))
120 {
121 node->aux = first;
122 first = node;
123 }
124 else
125 gcc_assert (!node->aux);
126
127 /* Perform reachability analysis. As a special case do not consider
128 extern inline functions not inlined as live because we won't output
129 them at all. */
130 while (first != (void *) 1)
131 {
132 struct cgraph_edge *e;
133 node = first;
134 first = first->aux;
135
136 for (e = node->callees; e; e = e->next_callee)
137 if (!e->callee->aux
138 && node->analyzed
139 && (!e->inline_failed || !e->callee->analyzed
140 || (!DECL_EXTERNAL (e->callee->decl))
141 || before_inlining_p))
142 {
143 e->callee->aux = first;
144 first = e->callee;
145 }
146 }
147
148 /* Remove unreachable nodes. Extern inline functions need special care;
149 Unreachable extern inline functions shall be removed.
150 Reachable extern inline functions we never inlined shall get their bodies
151 eliminated.
152 Reachable extern inline functions we sometimes inlined will be turned into
153 unanalyzed nodes so they look like for true extern functions to the rest
154 of code. Body of such functions is released via remove_node once the
155 inline clones are eliminated. */
156 for (node = cgraph_nodes; node; node = next)
157 {
158 next = node->next;
159 if (!node->aux)
160 {
161 int local_insns;
162 tree decl = node->decl;
163
164 node->global.inlined_to = NULL;
165 if (DECL_STRUCT_FUNCTION (decl))
166 local_insns = node->local.self_insns;
167 else
168 local_insns = 0;
169 if (file)
170 fprintf (file, " %s", cgraph_node_name (node));
171 if (!node->analyzed || !DECL_EXTERNAL (node->decl)
172 || before_inlining_p)
173 cgraph_remove_node (node);
174 else
175 {
176 struct cgraph_edge *e;
177
178 for (e = node->callers; e; e = e->next_caller)
179 if (e->caller->aux)
180 break;
181 if (e || node->needed)
182 {
183 struct cgraph_node *clone;
184
185 for (clone = node->next_clone; clone;
186 clone = clone->next_clone)
187 if (clone->aux)
188 break;
189 if (!clone)
190 {
191 cgraph_release_function_body (node);
192 node->analyzed = false;
193 }
194 cgraph_node_remove_callees (node);
195 node->analyzed = false;
196 }
197 else
198 cgraph_remove_node (node);
199 }
200 if (!DECL_SAVED_TREE (decl))
201 insns += local_insns;
202 changed = true;
203 }
204 }
205 for (node = cgraph_nodes; node; node = node->next)
206 node->aux = NULL;
207 if (file)
208 fprintf (file, "\nReclaimed %i insns", insns);
209 return changed;
210 }
211
212 /* Mark visibility of all functions.
213
214 A local function is one whose calls can occur only in the current
215 compilation unit and all its calls are explicit, so we can change
216 its calling convention. We simply mark all static functions whose
217 address is not taken as local.
218
219 We also change the TREE_PUBLIC flag of all declarations that are public
220 in language point of view but we want to overwrite this default
221 via visibilities for the backend point of view. */
222
223 static unsigned int
224 function_and_variable_visibility (void)
225 {
226 struct cgraph_node *node;
227 struct varpool_node *vnode;
228
229 for (node = cgraph_nodes; node; node = node->next)
230 {
231 if (node->reachable
232 && (DECL_COMDAT (node->decl)
233 || (!flag_whole_program
234 && TREE_PUBLIC (node->decl) && !DECL_EXTERNAL (node->decl))))
235 node->local.externally_visible = true;
236 if (!node->local.externally_visible && node->analyzed
237 && !DECL_EXTERNAL (node->decl))
238 {
239 gcc_assert (flag_whole_program || !TREE_PUBLIC (node->decl));
240 TREE_PUBLIC (node->decl) = 0;
241 }
242 node->local.local = (!node->needed
243 && node->analyzed
244 && !DECL_EXTERNAL (node->decl)
245 && !node->local.externally_visible);
246 }
247 for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
248 {
249 if (vnode->needed
250 && !flag_whole_program
251 && (DECL_COMDAT (vnode->decl) || TREE_PUBLIC (vnode->decl)))
252 vnode->externally_visible = 1;
253 if (!vnode->externally_visible)
254 {
255 gcc_assert (flag_whole_program || !TREE_PUBLIC (vnode->decl));
256 TREE_PUBLIC (vnode->decl) = 0;
257 }
258 gcc_assert (TREE_STATIC (vnode->decl));
259 }
260
261 if (dump_file)
262 {
263 fprintf (dump_file, "\nMarking local functions:");
264 for (node = cgraph_nodes; node; node = node->next)
265 if (node->local.local)
266 fprintf (dump_file, " %s", cgraph_node_name (node));
267 fprintf (dump_file, "\n\n");
268 fprintf (dump_file, "\nMarking externally visible functions:");
269 for (node = cgraph_nodes; node; node = node->next)
270 if (node->local.externally_visible)
271 fprintf (dump_file, " %s", cgraph_node_name (node));
272 fprintf (dump_file, "\n\n");
273 }
274 cgraph_function_flags_ready = true;
275 return 0;
276 }
277
278 struct tree_opt_pass pass_ipa_function_and_variable_visibility =
279 {
280 "visibility", /* name */
281 NULL, /* gate */
282 function_and_variable_visibility, /* execute */
283 NULL, /* sub */
284 NULL, /* next */
285 0, /* static_pass_number */
286 TV_CGRAPHOPT, /* tv_id */
287 0, /* properties_required */
288 0, /* properties_provided */
289 0, /* properties_destroyed */
290 0, /* todo_flags_start */
291 TODO_remove_functions | TODO_dump_cgraph,/* todo_flags_finish */
292 0 /* letter */
293 };